diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/Plugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/Plugin.java index 192f587665..353e8eac07 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/Plugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/Plugin.java @@ -1,57 +1,56 @@ -/* - * Copyright (c) 2016-2017, Adam - * 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; - -import com.google.inject.Binder; -import com.google.inject.Injector; -import com.google.inject.Module; - -import java.io.File; - -public abstract class Plugin implements Module -{ - protected Injector injector; - - public File file; - public PluginClassLoader loader; - - @Override - public void configure(Binder binder) - { - } - - protected void startUp() throws Exception - { - } - - protected void shutDown() throws Exception - { - } - - public final Injector getInjector() - { - return injector; - } -} +/* + * Copyright (c) 2016-2017, Adam + * 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; + +import com.google.inject.Binder; +import com.google.inject.Injector; +import com.google.inject.Module; +import java.io.File; + +public abstract class Plugin implements Module +{ + protected Injector injector; + + public File file; + public PluginClassLoader loader; + + @Override + public void configure(Binder binder) + { + } + + protected void startUp() throws Exception + { + } + + protected void shutDown() throws Exception + { + } + + public final Injector getInjector() + { + return injector; + } +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/PluginDescriptor.java b/runelite-client/src/main/java/net/runelite/client/plugins/PluginDescriptor.java index fafcaebcbd..c505eac5bb 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/PluginDescriptor.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/PluginDescriptor.java @@ -1,63 +1,63 @@ -/* - * Copyright (c) 2017, Adam - * 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; - -import java.lang.annotation.Documented; -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -@Retention(RetentionPolicy.RUNTIME) -@Target(ElementType.TYPE) -@Documented -public @interface PluginDescriptor -{ - String name(); - - /** - * A short, one-line summary of the plugin. - */ - String description() default ""; - - /** - * A list of plugin keywords, used (together with the name) when searching for plugins. - * Each tag should not contain any spaces, and should be fully lowercase. - */ - String[] tags() default {}; - - boolean enabledByDefault() default true; - - /** - * Whether or not plugin is hidden from configuration panel - */ - boolean hidden() default false; - - boolean developerPlugin() default false; - - boolean loadWhenOutdated() default false; - - PluginType type() default PluginType.GENERAL_USE; -} +/* + * Copyright (c) 2017, Adam + * 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; + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.TYPE) +@Documented +public @interface PluginDescriptor +{ + String name(); + + /** + * A short, one-line summary of the plugin. + */ + String description() default ""; + + /** + * A list of plugin keywords, used (together with the name) when searching for plugins. + * Each tag should not contain any spaces, and should be fully lowercase. + */ + String[] tags() default {}; + + boolean enabledByDefault() default true; + + /** + * Whether or not plugin is hidden from configuration panel + */ + boolean hidden() default false; + + boolean developerPlugin() default false; + + boolean loadWhenOutdated() default false; + + PluginType type() default PluginType.GENERAL_USE; +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/PluginManager.java b/runelite-client/src/main/java/net/runelite/client/plugins/PluginManager.java index 62e8a22aa8..32eea3d5c9 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/PluginManager.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/PluginManager.java @@ -1,553 +1,554 @@ -/* - * Copyright (c) 2016-2017, Adam - * 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; - -import com.google.common.annotations.VisibleForTesting; -import com.google.common.collect.ImmutableSet; -import com.google.common.collect.Lists; -import com.google.common.graph.Graph; -import com.google.common.graph.GraphBuilder; -import com.google.common.graph.Graphs; -import com.google.common.graph.MutableGraph; -import com.google.common.reflect.ClassPath; -import com.google.common.reflect.ClassPath.ClassInfo; -import com.google.inject.Binder; -import com.google.inject.CreationException; -import com.google.inject.Injector; -import com.google.inject.Key; -import com.google.inject.Module; -import java.io.IOException; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Iterator; -import java.util.List; -import java.util.Optional; -import java.util.Set; -import java.util.concurrent.CopyOnWriteArrayList; -import java.util.concurrent.ScheduledExecutorService; -import java.util.stream.Collectors; -import javax.inject.Inject; -import javax.inject.Named; -import javax.inject.Provider; -import javax.inject.Singleton; -import javax.swing.SwingUtilities; -import lombok.Setter; -import lombok.extern.slf4j.Slf4j; -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; -import net.runelite.client.config.ConfigManager; -import net.runelite.client.config.RuneLiteConfig; -import net.runelite.client.eventbus.EventBus; -import net.runelite.client.eventbus.Subscribe; -import net.runelite.client.events.PluginChanged; -import net.runelite.client.task.Schedule; -import net.runelite.client.task.ScheduledMethod; -import net.runelite.client.task.Scheduler; -import net.runelite.client.util.GameEventManager; - -@Singleton -@Slf4j -public class PluginManager -{ - /** - * Base package where the core plugins are - */ - private static final String PLUGIN_PACKAGE = "net.runelite.client.plugins"; - - private final boolean developerMode; - private final EventBus eventBus; - private final Scheduler scheduler; - private final ConfigManager configManager; - private final ScheduledExecutorService executor; - private final Provider sceneTileManager; - private final List plugins = new CopyOnWriteArrayList<>(); - private final List activePlugins = new CopyOnWriteArrayList<>(); - private final String runeliteGroupName = RuneLiteConfig.class - .getAnnotation(ConfigGroup.class).value(); - - @Inject - PluginWatcher pluginWatcher; - - @Setter - boolean isOutdated; - - @Inject - @VisibleForTesting - PluginManager( - @Named("developerMode") final boolean developerMode, - final EventBus eventBus, - final Scheduler scheduler, - final ConfigManager configManager, - final ScheduledExecutorService executor, - final Provider sceneTileManager) - { - this.developerMode = developerMode; - this.eventBus = eventBus; - this.scheduler = scheduler; - this.configManager = configManager; - this.executor = executor; - this.sceneTileManager = sceneTileManager; - } - - public void watch() - { - pluginWatcher.start(); - } - - @Subscribe - public void onSessionOpen(SessionOpen event) - { - refreshPlugins(); - } - - @Subscribe - public void onSessionClose(SessionClose event) - { - refreshPlugins(); - } - - private void refreshPlugins() - { - loadDefaultPluginConfiguration(); - getPlugins() - .forEach(plugin -> executor.submit(() -> - { - try - { - if (!startPlugin(plugin)) - { - stopPlugin(plugin); - } - } - catch (PluginInstantiationException e) - { - log.warn("Error during starting/stopping plugin {}. {}", plugin.getClass().getSimpleName(), e); - } - })); - } - - public Config getPluginConfigProxy(Plugin plugin) - { - final Injector injector = plugin.getInjector(); - - for (Key key : injector.getAllBindings().keySet()) - { - Class type = key.getTypeLiteral().getRawType(); - if (Config.class.isAssignableFrom(type)) - { - return (Config) injector.getInstance(key); - } - } - - return null; - } - - public List getPluginConfigProxies() - { - List injectors = new ArrayList<>(); - injectors.add(RuneLite.getInjector()); - getPlugins().forEach(pl -> injectors.add(pl.getInjector())); - - List list = new ArrayList<>(); - for (Injector injector : injectors) - { - for (Key key : injector.getAllBindings().keySet()) - { - Class type = key.getTypeLiteral().getRawType(); - if (Config.class.isAssignableFrom(type)) - { - Config config = (Config) injector.getInstance(key); - list.add(config); - } - } - } - - return list; - } - - public void loadDefaultPluginConfiguration() - { - for (Object config : getPluginConfigProxies()) - { - configManager.setDefaultConfiguration(config, false); - } - } - - public void loadCorePlugins() throws IOException - { - plugins.addAll(scanAndInstantiate(getClass().getClassLoader(), PLUGIN_PACKAGE)); - } - - public void startCorePlugins() - { - List scannedPlugins = new ArrayList<>(plugins); - for (Plugin plugin : scannedPlugins) - { - try - { - startPlugin(plugin); - } - catch (PluginInstantiationException ex) - { - log.warn("Unable to start plugin {}. {}", plugin.getClass().getSimpleName(), ex); - plugins.remove(plugin); - } - } - } - - List scanAndInstantiate(ClassLoader classLoader, String packageName) throws IOException - { - MutableGraph> graph = GraphBuilder - .directed() - .build(); - - List scannedPlugins = new ArrayList<>(); - ClassPath classPath = ClassPath.from(classLoader); - - ImmutableSet classes = packageName == null ? classPath.getAllClasses() - : classPath.getTopLevelClassesRecursive(packageName); - for (ClassInfo classInfo : classes) - { - Class clazz = classInfo.load(); - PluginDescriptor pluginDescriptor = clazz.getAnnotation(PluginDescriptor.class); - - if (pluginDescriptor == null) - { - if (clazz.getSuperclass() == Plugin.class) - { - log.warn("Class {} is a plugin, but has no plugin descriptor", - clazz); - } - continue; - } - - if (clazz.getSuperclass() != Plugin.class) - { - log.warn("Class {} has plugin descriptor, but is not a plugin", - clazz); - continue; - } - - if (!pluginDescriptor.loadWhenOutdated() && isOutdated) - { - continue; - } - - if (pluginDescriptor.developerPlugin() && !developerMode) - { - continue; - } - - Class pluginClass = (Class) clazz; - graph.addNode(pluginClass); - } - - // Build plugin graph - for (Class pluginClazz : graph.nodes()) - { - PluginDependency[] pluginDependencies = pluginClazz.getAnnotationsByType(PluginDependency.class); - - for (PluginDependency pluginDependency : pluginDependencies) - { - graph.putEdge(pluginClazz, pluginDependency.value()); - } - } - - if (Graphs.hasCycle(graph)) - { - throw new RuntimeException("Plugin dependency graph contains a cycle!"); - } - - List> sortedPlugins = topologicalSort(graph); - sortedPlugins = Lists.reverse(sortedPlugins); - - for (Class pluginClazz : sortedPlugins) - { - Plugin plugin; - try - { - plugin = instantiate(scannedPlugins, (Class) pluginClazz); - } - catch (PluginInstantiationException ex) - { - log.warn("Error instantiating plugin!", ex); - continue; - } - - scannedPlugins.add(plugin); - } - - return scannedPlugins; - } - - public synchronized boolean startPlugin(Plugin plugin) throws PluginInstantiationException - { - if (activePlugins.contains(plugin) || !isPluginEnabled(plugin)) - { - return false; - } - - activePlugins.add(plugin); - - try - { - // plugins always start in the event thread - SwingUtilities.invokeAndWait(() -> - { - try - { - plugin.startUp(); - } - catch (Exception ex) - { - throw new RuntimeException(ex); - } - }); - - log.debug("Plugin {} is now running", plugin.getClass().getSimpleName()); - if (!isOutdated && sceneTileManager != null) - { - final GameEventManager gameEventManager = this.sceneTileManager.get(); - if (gameEventManager != null) - { - gameEventManager.simulateGameEvents(plugin); - } - } - - eventBus.register(plugin); - schedule(plugin); - eventBus.post(new PluginChanged(plugin, true)); - } - catch (InterruptedException | InvocationTargetException | IllegalArgumentException ex) - { - throw new PluginInstantiationException(ex); - } - - return true; - } - - public synchronized boolean stopPlugin(Plugin plugin) throws PluginInstantiationException - { - if (!activePlugins.contains(plugin) || isPluginEnabled(plugin)) - { - return false; - } - - activePlugins.remove(plugin); - - try - { - unschedule(plugin); - eventBus.unregister(plugin); - - // plugins always stop in the event thread - SwingUtilities.invokeAndWait(() -> - { - try - { - plugin.shutDown(); - } - catch (Exception ex) - { - throw new RuntimeException(ex); - } - }); - - log.debug("Plugin {} is now stopped", plugin.getClass().getSimpleName()); - eventBus.post(new PluginChanged(plugin, false)); - - } - catch (InterruptedException | InvocationTargetException ex) - { - throw new PluginInstantiationException(ex); - } - - return true; - } - - public void setPluginEnabled(Plugin plugin, boolean enabled) - { - final String keyName = plugin.getClass().getSimpleName().toLowerCase(); - configManager.setConfiguration(runeliteGroupName, keyName, String.valueOf(enabled)); - } - - public boolean isPluginEnabled(Plugin plugin) - { - final String keyName = plugin.getClass().getSimpleName().toLowerCase(); - final String value = configManager.getConfiguration(runeliteGroupName, keyName); - - if (value != null) - { - return Boolean.valueOf(value); - } - - final PluginDescriptor pluginDescriptor = plugin.getClass().getAnnotation(PluginDescriptor.class); - return pluginDescriptor == null || pluginDescriptor.enabledByDefault(); - } - - private Plugin instantiate(List scannedPlugins, Class clazz) throws PluginInstantiationException - { - PluginDependency[] pluginDependencies = clazz.getAnnotationsByType(PluginDependency.class); - List deps = new ArrayList<>(); - for (PluginDependency pluginDependency : pluginDependencies) - { - Optional dependency = scannedPlugins.stream().filter(p -> p.getClass() == pluginDependency.value()).findFirst(); - if (!dependency.isPresent()) - { - throw new PluginInstantiationException("Unmet dependency for " + clazz.getSimpleName() + ": " + pluginDependency.value().getSimpleName()); - } - deps.add(dependency.get()); - } - - Plugin plugin; - try - { - plugin = clazz.newInstance(); - } - catch (InstantiationException | IllegalAccessException ex) - { - throw new PluginInstantiationException(ex); - } - - try - { - Module pluginModule = (Binder binder) -> - { - binder.bind(clazz).toInstance(plugin); - binder.install(plugin); - for (Plugin p : deps) - { - Module p2 = (Binder binder2) -> - { - binder2.bind((Class) p.getClass()).toInstance(p); - binder2.install(p); - }; - binder.install(p2); - } - }; - Injector pluginInjector = RuneLite.getInjector().createChildInjector(pluginModule); - pluginInjector.injectMembers(plugin); - plugin.injector = pluginInjector; - } - catch (CreationException ex) - { - throw new PluginInstantiationException(ex); - } - - log.debug("Loaded plugin {}", clazz.getSimpleName()); - return plugin; - } - - void add(Plugin plugin) - { - plugins.add(plugin); - } - - void remove(Plugin plugin) - { - plugins.remove(plugin); - } - - public Collection getPlugins() - { - return plugins; - } - - private void schedule(Plugin plugin) - { - for (Method method : plugin.getClass().getMethods()) - { - Schedule schedule = method.getAnnotation(Schedule.class); - - if (schedule == null) - { - continue; - } - - ScheduledMethod scheduledMethod = new ScheduledMethod(schedule, method, plugin); - log.debug("Scheduled task {}", scheduledMethod); - - scheduler.addScheduledMethod(scheduledMethod); - } - } - - private void unschedule(Plugin plugin) - { - List methods = new ArrayList<>(scheduler.getScheduledMethods()); - - for (ScheduledMethod method : methods) - { - if (method.getObject() != plugin) - { - continue; - } - - log.debug("Removing scheduled task {}", method); - scheduler.removeScheduledMethod(method); - } - } - - /** - * Topologically sort a graph. Uses Kahn's algorithm. - * @param graph - * @param - * @return - */ - private List topologicalSort(Graph graph) - { - MutableGraph graphCopy = Graphs.copyOf(graph); - List l = new ArrayList<>(); - Set s = graphCopy.nodes().stream() - .filter(node -> graphCopy.inDegree(node) == 0) - .collect(Collectors.toSet()); - while (!s.isEmpty()) - { - Iterator it = s.iterator(); - T n = it.next(); - it.remove(); - - l.add(n); - - for (T m : graphCopy.successors(n)) - { - graphCopy.removeEdge(n, m); - if (graphCopy.inDegree(m) == 0) - { - s.add(m); - } - } - } - if (!graphCopy.edges().isEmpty()) - { - throw new RuntimeException("Graph has at least one cycle"); - } - return l; - } -} +/* + * Copyright (c) 2016-2017, Adam + * 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; + +import com.google.common.annotations.VisibleForTesting; +import com.google.common.collect.ImmutableSet; +import com.google.common.collect.Lists; +import com.google.common.graph.Graph; +import com.google.common.graph.GraphBuilder; +import com.google.common.graph.Graphs; +import com.google.common.graph.MutableGraph; +import com.google.common.reflect.ClassPath; +import com.google.common.reflect.ClassPath.ClassInfo; +import com.google.inject.Binder; +import com.google.inject.CreationException; +import com.google.inject.Injector; +import com.google.inject.Key; +import com.google.inject.Module; +import java.io.IOException; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Iterator; +import java.util.List; +import java.util.Optional; +import java.util.Set; +import java.util.concurrent.CopyOnWriteArrayList; +import java.util.concurrent.ScheduledExecutorService; +import java.util.stream.Collectors; +import javax.inject.Inject; +import javax.inject.Named; +import javax.inject.Provider; +import javax.inject.Singleton; +import javax.swing.SwingUtilities; +import lombok.Setter; +import lombok.extern.slf4j.Slf4j; +import net.runelite.client.RuneLite; +import net.runelite.client.config.Config; +import net.runelite.client.config.ConfigGroup; +import net.runelite.client.config.ConfigManager; +import net.runelite.client.config.RuneLiteConfig; +import net.runelite.client.eventbus.EventBus; +import net.runelite.client.eventbus.Subscribe; +import net.runelite.client.events.PluginChanged; +import net.runelite.client.events.SessionClose; +import net.runelite.client.events.SessionOpen; +import net.runelite.client.task.Schedule; +import net.runelite.client.task.ScheduledMethod; +import net.runelite.client.task.Scheduler; +import net.runelite.client.util.GameEventManager; + +@Singleton +@Slf4j +public class PluginManager +{ + /** + * Base package where the core plugins are + */ + private static final String PLUGIN_PACKAGE = "net.runelite.client.plugins"; + + private final boolean developerMode; + private final EventBus eventBus; + private final Scheduler scheduler; + private final ConfigManager configManager; + private final ScheduledExecutorService executor; + private final Provider sceneTileManager; + private final List plugins = new CopyOnWriteArrayList<>(); + private final List activePlugins = new CopyOnWriteArrayList<>(); + private final String runeliteGroupName = RuneLiteConfig.class + .getAnnotation(ConfigGroup.class).value(); + + @Inject + PluginWatcher pluginWatcher; + + @Setter + boolean isOutdated; + + @Inject + @VisibleForTesting + PluginManager( + @Named("developerMode") final boolean developerMode, + final EventBus eventBus, + final Scheduler scheduler, + final ConfigManager configManager, + final ScheduledExecutorService executor, + final Provider sceneTileManager) + { + this.developerMode = developerMode; + this.eventBus = eventBus; + this.scheduler = scheduler; + this.configManager = configManager; + this.executor = executor; + this.sceneTileManager = sceneTileManager; + } + + public void watch() + { + pluginWatcher.start(); + } + + @Subscribe + public void onSessionOpen(SessionOpen event) + { + refreshPlugins(); + } + + @Subscribe + public void onSessionClose(SessionClose event) + { + refreshPlugins(); + } + + private void refreshPlugins() + { + loadDefaultPluginConfiguration(); + getPlugins() + .forEach(plugin -> executor.submit(() -> + { + try + { + if (!startPlugin(plugin)) + { + stopPlugin(plugin); + } + } + catch (PluginInstantiationException e) + { + log.warn("Error during starting/stopping plugin {}. {}", plugin.getClass().getSimpleName(), e); + } + })); + } + + public Config getPluginConfigProxy(Plugin plugin) + { + final Injector injector = plugin.getInjector(); + + for (Key key : injector.getAllBindings().keySet()) + { + Class type = key.getTypeLiteral().getRawType(); + if (Config.class.isAssignableFrom(type)) + { + return (Config) injector.getInstance(key); + } + } + + return null; + } + + public List getPluginConfigProxies() + { + List injectors = new ArrayList<>(); + injectors.add(RuneLite.getInjector()); + getPlugins().forEach(pl -> injectors.add(pl.getInjector())); + + List list = new ArrayList<>(); + for (Injector injector : injectors) + { + for (Key key : injector.getAllBindings().keySet()) + { + Class type = key.getTypeLiteral().getRawType(); + if (Config.class.isAssignableFrom(type)) + { + Config config = (Config) injector.getInstance(key); + list.add(config); + } + } + } + + return list; + } + + public void loadDefaultPluginConfiguration() + { + for (Object config : getPluginConfigProxies()) + { + configManager.setDefaultConfiguration(config, false); + } + } + + public void loadCorePlugins() throws IOException + { + plugins.addAll(scanAndInstantiate(getClass().getClassLoader(), PLUGIN_PACKAGE)); + } + + public void startCorePlugins() + { + List scannedPlugins = new ArrayList<>(plugins); + for (Plugin plugin : scannedPlugins) + { + try + { + startPlugin(plugin); + } + catch (PluginInstantiationException ex) + { + log.warn("Unable to start plugin {}. {}", plugin.getClass().getSimpleName(), ex); + plugins.remove(plugin); + } + } + } + + List scanAndInstantiate(ClassLoader classLoader, String packageName) throws IOException + { + MutableGraph> graph = GraphBuilder + .directed() + .build(); + + List scannedPlugins = new ArrayList<>(); + ClassPath classPath = ClassPath.from(classLoader); + + ImmutableSet classes = packageName == null ? classPath.getAllClasses() + : classPath.getTopLevelClassesRecursive(packageName); + for (ClassInfo classInfo : classes) + { + Class clazz = classInfo.load(); + PluginDescriptor pluginDescriptor = clazz.getAnnotation(PluginDescriptor.class); + + if (pluginDescriptor == null) + { + if (clazz.getSuperclass() == Plugin.class) + { + log.warn("Class {} is a plugin, but has no plugin descriptor", + clazz); + } + continue; + } + + if (clazz.getSuperclass() != Plugin.class) + { + log.warn("Class {} has plugin descriptor, but is not a plugin", + clazz); + continue; + } + + if (!pluginDescriptor.loadWhenOutdated() && isOutdated) + { + continue; + } + + if (pluginDescriptor.developerPlugin() && !developerMode) + { + continue; + } + + Class pluginClass = (Class) clazz; + graph.addNode(pluginClass); + } + + // Build plugin graph + for (Class pluginClazz : graph.nodes()) + { + PluginDependency[] pluginDependencies = pluginClazz.getAnnotationsByType(PluginDependency.class); + + for (PluginDependency pluginDependency : pluginDependencies) + { + graph.putEdge(pluginClazz, pluginDependency.value()); + } + } + + if (Graphs.hasCycle(graph)) + { + throw new RuntimeException("Plugin dependency graph contains a cycle!"); + } + + List> sortedPlugins = topologicalSort(graph); + sortedPlugins = Lists.reverse(sortedPlugins); + + for (Class pluginClazz : sortedPlugins) + { + Plugin plugin; + try + { + plugin = instantiate(scannedPlugins, (Class) pluginClazz); + } + catch (PluginInstantiationException ex) + { + log.warn("Error instantiating plugin!", ex); + continue; + } + + scannedPlugins.add(plugin); + } + + return scannedPlugins; + } + + public synchronized boolean startPlugin(Plugin plugin) throws PluginInstantiationException + { + if (activePlugins.contains(plugin) || !isPluginEnabled(plugin)) + { + return false; + } + + activePlugins.add(plugin); + + try + { + // plugins always start in the event thread + SwingUtilities.invokeAndWait(() -> + { + try + { + plugin.startUp(); + } + catch (Exception ex) + { + throw new RuntimeException(ex); + } + }); + + log.debug("Plugin {} is now running", plugin.getClass().getSimpleName()); + if (!isOutdated && sceneTileManager != null) + { + final GameEventManager gameEventManager = this.sceneTileManager.get(); + if (gameEventManager != null) + { + gameEventManager.simulateGameEvents(plugin); + } + } + + eventBus.register(plugin); + schedule(plugin); + eventBus.post(new PluginChanged(plugin, true)); + } + catch (InterruptedException | InvocationTargetException | IllegalArgumentException ex) + { + throw new PluginInstantiationException(ex); + } + + return true; + } + + public synchronized boolean stopPlugin(Plugin plugin) throws PluginInstantiationException + { + if (!activePlugins.contains(plugin) || isPluginEnabled(plugin)) + { + return false; + } + + activePlugins.remove(plugin); + + try + { + unschedule(plugin); + eventBus.unregister(plugin); + + // plugins always stop in the event thread + SwingUtilities.invokeAndWait(() -> + { + try + { + plugin.shutDown(); + } + catch (Exception ex) + { + throw new RuntimeException(ex); + } + }); + + log.debug("Plugin {} is now stopped", plugin.getClass().getSimpleName()); + eventBus.post(new PluginChanged(plugin, false)); + + } + catch (InterruptedException | InvocationTargetException ex) + { + throw new PluginInstantiationException(ex); + } + + return true; + } + + public void setPluginEnabled(Plugin plugin, boolean enabled) + { + final String keyName = plugin.getClass().getSimpleName().toLowerCase(); + configManager.setConfiguration(runeliteGroupName, keyName, String.valueOf(enabled)); + } + + public boolean isPluginEnabled(Plugin plugin) + { + final String keyName = plugin.getClass().getSimpleName().toLowerCase(); + final String value = configManager.getConfiguration(runeliteGroupName, keyName); + + if (value != null) + { + return Boolean.valueOf(value); + } + + final PluginDescriptor pluginDescriptor = plugin.getClass().getAnnotation(PluginDescriptor.class); + return pluginDescriptor == null || pluginDescriptor.enabledByDefault(); + } + + private Plugin instantiate(List scannedPlugins, Class clazz) throws PluginInstantiationException + { + PluginDependency[] pluginDependencies = clazz.getAnnotationsByType(PluginDependency.class); + List deps = new ArrayList<>(); + for (PluginDependency pluginDependency : pluginDependencies) + { + Optional dependency = scannedPlugins.stream().filter(p -> p.getClass() == pluginDependency.value()).findFirst(); + if (!dependency.isPresent()) + { + throw new PluginInstantiationException("Unmet dependency for " + clazz.getSimpleName() + ": " + pluginDependency.value().getSimpleName()); + } + deps.add(dependency.get()); + } + + Plugin plugin; + try + { + plugin = clazz.newInstance(); + } + catch (InstantiationException | IllegalAccessException ex) + { + throw new PluginInstantiationException(ex); + } + + try + { + Module pluginModule = (Binder binder) -> + { + binder.bind(clazz).toInstance(plugin); + binder.install(plugin); + for (Plugin p : deps) + { + Module p2 = (Binder binder2) -> + { + binder2.bind((Class) p.getClass()).toInstance(p); + binder2.install(p); + }; + binder.install(p2); + } + }; + Injector pluginInjector = RuneLite.getInjector().createChildInjector(pluginModule); + pluginInjector.injectMembers(plugin); + plugin.injector = pluginInjector; + } + catch (CreationException ex) + { + throw new PluginInstantiationException(ex); + } + + log.debug("Loaded plugin {}", clazz.getSimpleName()); + return plugin; + } + + void add(Plugin plugin) + { + plugins.add(plugin); + } + + void remove(Plugin plugin) + { + plugins.remove(plugin); + } + + public Collection getPlugins() + { + return plugins; + } + + private void schedule(Plugin plugin) + { + for (Method method : plugin.getClass().getMethods()) + { + Schedule schedule = method.getAnnotation(Schedule.class); + + if (schedule == null) + { + continue; + } + + ScheduledMethod scheduledMethod = new ScheduledMethod(schedule, method, plugin); + log.debug("Scheduled task {}", scheduledMethod); + + scheduler.addScheduledMethod(scheduledMethod); + } + } + + private void unschedule(Plugin plugin) + { + List methods = new ArrayList<>(scheduler.getScheduledMethods()); + + for (ScheduledMethod method : methods) + { + if (method.getObject() != plugin) + { + continue; + } + + log.debug("Removing scheduled task {}", method); + scheduler.removeScheduledMethod(method); + } + } + + /** + * Topologically sort a graph. Uses Kahn's algorithm. + * + * @param graph + * @param + * @return + */ + private List topologicalSort(Graph graph) + { + MutableGraph graphCopy = Graphs.copyOf(graph); + List l = new ArrayList<>(); + Set s = graphCopy.nodes().stream() + .filter(node -> graphCopy.inDegree(node) == 0) + .collect(Collectors.toSet()); + while (!s.isEmpty()) + { + Iterator it = s.iterator(); + T n = it.next(); + it.remove(); + + l.add(n); + + for (T m : graphCopy.successors(n)) + { + graphCopy.removeEdge(n, m); + if (graphCopy.inDegree(m) == 0) + { + s.add(m); + } + } + } + if (!graphCopy.edges().isEmpty()) + { + throw new RuntimeException("Graph has at least one cycle"); + } + return l; + } +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/PluginType.java b/runelite-client/src/main/java/net/runelite/client/plugins/PluginType.java index 1ba59834cb..687b79e3d4 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/PluginType.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/PluginType.java @@ -1,15 +1,16 @@ -package net.runelite.client.plugins; - -public enum PluginType { - - PVM, - PVP, - - UTILITY, - GENERAL_USE, - - EXTERNAL, - - PLUGIN_ORGANIZER - -} +package net.runelite.client.plugins; + +public enum PluginType +{ + + PVM, + PVP, + + UTILITY, + GENERAL_USE, + + EXTERNAL, + + PLUGIN_ORGANIZER + +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/PluginWatcher.java b/runelite-client/src/main/java/net/runelite/client/plugins/PluginWatcher.java index 031d408c03..5505efbee5 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/PluginWatcher.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/PluginWatcher.java @@ -1,273 +1,273 @@ -/* - * Copyright (c) 2016-2017, Adam - * 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; - -import com.google.inject.Injector; -import com.google.inject.Key; -import java.io.File; -import java.io.IOException; -import java.net.MalformedURLException; -import java.net.URLClassLoader; -import java.nio.file.FileSystems; -import java.nio.file.Path; -import static java.nio.file.StandardWatchEventKinds.ENTRY_DELETE; -import static java.nio.file.StandardWatchEventKinds.ENTRY_MODIFY; -import java.nio.file.WatchEvent; -import java.nio.file.WatchEvent.Kind; -import java.nio.file.WatchKey; -import java.nio.file.WatchService; -import java.util.List; -import javax.inject.Inject; -import javax.inject.Singleton; -import lombok.extern.slf4j.Slf4j; -import net.runelite.client.RuneLite; -import net.runelite.client.config.Config; -import net.runelite.client.config.ConfigManager; -import net.runelite.client.config.RuneLiteConfig; - -@Singleton -@Slf4j -public class PluginWatcher extends Thread -{ - private static final File BASE = RuneLite.PLUGIN_DIR; - - private final RuneLiteConfig runeliteConfig; - private final PluginManager pluginManager; - private final WatchService watchService; - private final WatchKey watchKey; - - @Inject - private ConfigManager configManager; - - @Inject - public PluginWatcher(RuneLiteConfig runeliteConfig, PluginManager pluginManager) throws IOException - { - this.runeliteConfig = runeliteConfig; - this.pluginManager = pluginManager; - - setName("Plugin Watcher"); - setDaemon(true); - - watchService = FileSystems.getDefault().newWatchService(); - BASE.mkdirs(); - Path dir = BASE.toPath(); - watchKey = dir.register(watchService, ENTRY_MODIFY, ENTRY_DELETE); - } - - public void cancel() - { - watchKey.cancel(); - } - - @Override - public void run() - { - if (runeliteConfig.enablePlugins()) - { - scan(); - } - - for (;;) - { - try - { - WatchKey key = watchService.take(); - Thread.sleep(50); - - if (!runeliteConfig.enablePlugins()) - { - key.reset(); - continue; - } - - for (WatchEvent event : key.pollEvents()) - { - Kind kind = event.kind(); - Path path = (Path) event.context(); - File file = new File(BASE, path.toFile().getName()); - - log.debug("Event {} file {}", kind, file); - - if (kind == ENTRY_MODIFY) - { - Plugin existing = findPluginForFile(file); - if (existing != null) - { - log.info("Reloading plugin {}", file); - unload(existing); - } - else - { - log.info("Loading plugin {}", file); - } - - load(file); - } - else if (kind == ENTRY_DELETE) - { - Plugin existing = findPluginForFile(file); - if (existing != null) - { - log.info("Unloading plugin {}", file); - - unload(existing); - } - } - } - key.reset(); - - } - catch (InterruptedException ex) - { - log.warn("error polling for plugins", ex); - } - } - } - - private void scan() - { - for (File file : BASE.listFiles()) - { - if (!file.getName().endsWith(".jar")) - { - continue; - } - - log.info("Loading plugin from {}", file); - load(file); - } - } - - private Plugin findPluginForFile(File file) - { - for (Plugin plugin : pluginManager.getPlugins()) - { - if (plugin.file != null && plugin.file.equals(file)) - { - return plugin; - } - } - return null; - } - - private void load(File pluginFile) - { - PluginClassLoader loader; - try - { - loader = new PluginClassLoader(pluginFile, getClass().getClassLoader()); - } - catch (MalformedURLException ex) - { - log.warn("Error loading plugin", ex); - return; - } - - List loadedPlugins; - try - { - loadedPlugins = pluginManager.scanAndInstantiate(loader, null); - } - catch (IOException ex) - { - close(loader); - log.warn("Error loading plugin", ex); - return; - } - - if (loadedPlugins.isEmpty()) - { - close(loader); - log.warn("No plugin found in plugin {}", pluginFile); - return; - } - - if (loadedPlugins.size() != 1) - { - close(loader); - log.warn("You can not have more than one plugin per jar"); - return; - } - - Plugin plugin = loadedPlugins.get(0); - plugin.file = pluginFile; - plugin.loader = loader; - - // Initialize default configuration - Injector injector = plugin.getInjector(); - for (Key key : injector.getAllBindings().keySet()) - { - Class type = key.getTypeLiteral().getRawType(); - if (Config.class.isAssignableFrom(type)) - { - Config config = (Config) injector.getInstance(key); - configManager.setDefaultConfiguration(config, false); - } - } - - try - { - pluginManager.startPlugin(plugin); - } - catch (PluginInstantiationException ex) - { - close(loader); - log.warn("unable to start plugin", ex); - return; - } - - // Plugin is now running - pluginManager.add(plugin); - } - - private void unload(Plugin plugin) - { - try - { - pluginManager.stopPlugin(plugin); - } - catch (PluginInstantiationException ex) - { - log.warn("unable to stop plugin", ex); - } - - pluginManager.remove(plugin); // remove it regardless - - close(plugin.loader); - } - - private void close(URLClassLoader classLoader) - { - try - { - classLoader.close(); - } - catch (IOException ex1) - { - log.warn(null, ex1); - } - } - -} +/* + * Copyright (c) 2016-2017, Adam + * 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; + +import com.google.inject.Injector; +import com.google.inject.Key; +import java.io.File; +import java.io.IOException; +import java.net.MalformedURLException; +import java.net.URLClassLoader; +import java.nio.file.FileSystems; +import java.nio.file.Path; +import static java.nio.file.StandardWatchEventKinds.ENTRY_DELETE; +import static java.nio.file.StandardWatchEventKinds.ENTRY_MODIFY; +import java.nio.file.WatchEvent; +import java.nio.file.WatchEvent.Kind; +import java.nio.file.WatchKey; +import java.nio.file.WatchService; +import java.util.List; +import javax.inject.Inject; +import javax.inject.Singleton; +import lombok.extern.slf4j.Slf4j; +import net.runelite.client.RuneLite; +import net.runelite.client.config.Config; +import net.runelite.client.config.ConfigManager; +import net.runelite.client.config.RuneLiteConfig; + +@Singleton +@Slf4j +public class PluginWatcher extends Thread +{ + private static final File BASE = RuneLite.PLUGIN_DIR; + + private final RuneLiteConfig runeliteConfig; + private final PluginManager pluginManager; + private final WatchService watchService; + private final WatchKey watchKey; + + @Inject + private ConfigManager configManager; + + @Inject + public PluginWatcher(RuneLiteConfig runeliteConfig, PluginManager pluginManager) throws IOException + { + this.runeliteConfig = runeliteConfig; + this.pluginManager = pluginManager; + + setName("Plugin Watcher"); + setDaemon(true); + + watchService = FileSystems.getDefault().newWatchService(); + BASE.mkdirs(); + Path dir = BASE.toPath(); + watchKey = dir.register(watchService, ENTRY_MODIFY, ENTRY_DELETE); + } + + public void cancel() + { + watchKey.cancel(); + } + + @Override + public void run() + { + if (runeliteConfig.enablePlugins()) + { + scan(); + } + + for (; ; ) + { + try + { + WatchKey key = watchService.take(); + Thread.sleep(50); + + if (!runeliteConfig.enablePlugins()) + { + key.reset(); + continue; + } + + for (WatchEvent event : key.pollEvents()) + { + Kind kind = event.kind(); + Path path = (Path) event.context(); + File file = new File(BASE, path.toFile().getName()); + + log.debug("Event {} file {}", kind, file); + + if (kind == ENTRY_MODIFY) + { + Plugin existing = findPluginForFile(file); + if (existing != null) + { + log.info("Reloading plugin {}", file); + unload(existing); + } + else + { + log.info("Loading plugin {}", file); + } + + load(file); + } + else if (kind == ENTRY_DELETE) + { + Plugin existing = findPluginForFile(file); + if (existing != null) + { + log.info("Unloading plugin {}", file); + + unload(existing); + } + } + } + key.reset(); + + } + catch (InterruptedException ex) + { + log.warn("error polling for plugins", ex); + } + } + } + + private void scan() + { + for (File file : BASE.listFiles()) + { + if (!file.getName().endsWith(".jar")) + { + continue; + } + + log.info("Loading plugin from {}", file); + load(file); + } + } + + private Plugin findPluginForFile(File file) + { + for (Plugin plugin : pluginManager.getPlugins()) + { + if (plugin.file != null && plugin.file.equals(file)) + { + return plugin; + } + } + return null; + } + + private void load(File pluginFile) + { + PluginClassLoader loader; + try + { + loader = new PluginClassLoader(pluginFile, getClass().getClassLoader()); + } + catch (MalformedURLException ex) + { + log.warn("Error loading plugin", ex); + return; + } + + List loadedPlugins; + try + { + loadedPlugins = pluginManager.scanAndInstantiate(loader, null); + } + catch (IOException ex) + { + close(loader); + log.warn("Error loading plugin", ex); + return; + } + + if (loadedPlugins.isEmpty()) + { + close(loader); + log.warn("No plugin found in plugin {}", pluginFile); + return; + } + + if (loadedPlugins.size() != 1) + { + close(loader); + log.warn("You can not have more than one plugin per jar"); + return; + } + + Plugin plugin = loadedPlugins.get(0); + plugin.file = pluginFile; + plugin.loader = loader; + + // Initialize default configuration + Injector injector = plugin.getInjector(); + for (Key key : injector.getAllBindings().keySet()) + { + Class type = key.getTypeLiteral().getRawType(); + if (Config.class.isAssignableFrom(type)) + { + Config config = (Config) injector.getInstance(key); + configManager.setDefaultConfiguration(config, false); + } + } + + try + { + pluginManager.startPlugin(plugin); + } + catch (PluginInstantiationException ex) + { + close(loader); + log.warn("unable to start plugin", ex); + return; + } + + // Plugin is now running + pluginManager.add(plugin); + } + + private void unload(Plugin plugin) + { + try + { + pluginManager.stopPlugin(plugin); + } + catch (PluginInstantiationException ex) + { + log.warn("unable to stop plugin", ex); + } + + pluginManager.remove(plugin); // remove it regardless + + close(plugin.loader); + } + + private void close(URLClassLoader classLoader) + { + try + { + classLoader.close(); + } + catch (IOException ex1) + { + log.warn(null, ex1); + } + } + +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/achievementdiary/Requirement.java b/runelite-client/src/main/java/net/runelite/client/plugins/achievementdiary/Requirement.java index d7d0b32a13..9216d120c4 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/achievementdiary/Requirement.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/achievementdiary/Requirement.java @@ -1,28 +1,29 @@ -/* - * Copyright (c) 2019 Abex - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */package net.runelite.client.plugins.achievementdiary; - -public interface Requirement -{ -} +/* + * Copyright (c) 2019 Abex + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package net.runelite.client.plugins.achievementdiary; + +public interface Requirement +{ +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/achievementdiary/diaries/KourendDiaryRequirement.java b/runelite-client/src/main/java/net/runelite/client/plugins/achievementdiary/diaries/KourendDiaryRequirement.java index 182b288a3b..4fe0ea04c2 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/achievementdiary/diaries/KourendDiaryRequirement.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/achievementdiary/diaries/KourendDiaryRequirement.java @@ -1,136 +1,136 @@ -/* - * Copyright (c) 2019 William - * 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.achievementdiary.diaries; - -import net.runelite.api.Favour; -import net.runelite.api.Quest; -import net.runelite.api.Skill; -import net.runelite.client.plugins.achievementdiary.GenericDiaryRequirement; -import net.runelite.client.plugins.achievementdiary.SkillRequirement; -import net.runelite.client.plugins.achievementdiary.QuestRequirement; -import net.runelite.client.plugins.achievementdiary.FavourRequirement; - -public class KourendDiaryRequirement extends GenericDiaryRequirement -{ - public KourendDiaryRequirement() - { - //EASY - add("Mine some Iron at the Mount Karuulm mine.", - new SkillRequirement(Skill.MINING, 15)); - add("Steal from a Hosidius Food Stall.", - new SkillRequirement(Skill.THIEVING, 25), - new FavourRequirement(Favour.HOSIDIUS, 15)); - add("Browse the Warrens General Store.", - new QuestRequirement(Quest.THE_QUEEN_OF_THIEVES, true)); - add("Enter your Player Owned House from Hosidius.", - new SkillRequirement(Skill.CONSTRUCTION, 25)); - add("Create a Strength potion in the Lovakengj Pub.", - new SkillRequirement(Skill.HERBLORE, 12)); - add("Fish a Trout from the River Molch.", - new SkillRequirement(Skill.FISHING, 20)); - - //MEDIUM - add("Travel to the Fairy Ring south of Mount Karuulm.", - new QuestRequirement(Quest.FAIRYTALE_II__CURE_A_QUEEN, true)); - add("Use Kharedst's memoirs to teleport to all five cities in Great Kourend.", - new QuestRequirement(Quest.THE_DEPTHS_OF_DESPAIR), - new QuestRequirement(Quest.THE_QUEEN_OF_THIEVES), - new QuestRequirement(Quest.TALE_OF_THE_RIGHTEOUS), - new QuestRequirement(Quest.THE_FORSAKEN_TOWER), - new QuestRequirement(Quest.THE_ASCENT_OF_ARCEUUS)); - add("Mine some Volcanic sulphur.", - new SkillRequirement(Skill.MINING, 42)); - add("Enter the Farming Guild.", - new SkillRequirement(Skill.FARMING, 45)); - add("Switch to the Necromancy Spellbook at Tyss.", - new FavourRequirement(Favour.ARCEUUS, 60)); - add("Repair a Piscarilius crane.", - new SkillRequirement(Skill.CRAFTING, 30)); - add("Deliver some intelligence to Captain Ginea.", - new FavourRequirement(Favour.SHAYZIEN, 40)); - add("Catch a Bluegill on Molch Island.", - new SkillRequirement(Skill.FISHING, 43), - new SkillRequirement(Skill.HUNTER, 35)); - add("Use the boulder leap in the Arceuus essence mine.", - new SkillRequirement(Skill.AGILITY, 49)); - add("Subdue the Wintertodt.", - new SkillRequirement(Skill.FIREMAKING, 50)); - add("Catch a Chinchompa in the Kourend Woodland.", - new SkillRequirement(Skill.HUNTER, 53), - new QuestRequirement(Quest.EAGLES_PEAK)); - add("Chop some Mahogany logs north of the Farming Guild.", - new SkillRequirement(Skill.WOODCUTTING, 50)); - - //HARD - add("Enter the Woodcutting Guild.", - new SkillRequirement(Skill.WOODCUTTING, 60), - new FavourRequirement(Favour.HOSIDIUS, 75)); - add("Smelt an Adamantite bar in The Forsaken Tower.", - new SkillRequirement(Skill.SMITHING, 70), - new QuestRequirement(Quest.THE_FORSAKEN_TOWER, true)); - add("Kill a Lizardman Shaman in Molch.", - new FavourRequirement(Favour.SHAYZIEN, 100)); - add("Mine some Lovakite.", - new SkillRequirement(Skill.MINING, 65), - new FavourRequirement(Favour.LOVAKENGJ, 30)); - add("Plant some Logavano seeds at the Tithe Farm.", - new SkillRequirement(Skill.FARMING, 74), - new FavourRequirement(Favour.HOSIDIUS, 100)); - add("Teleport to Xeric's Heart using Xeric's Talisman.", - new QuestRequirement(Quest.ARCHITECTURAL_ALLIANCE)); - add("Deliver an artefact to Captain Khaled.", - new SkillRequirement(Skill.THIEVING, 49), - new FavourRequirement(Favour.PISCARILIUS, 75)); - add("Kill a Wyrm in the Karuulm Slayer Dungeon.", - new SkillRequirement(Skill.SLAYER, 62)); - add("Cast Monster Examine on a Troll south of Mount Quidamortem.", - new SkillRequirement(Skill.MAGIC, 66), - new QuestRequirement(Quest.DREAM_MENTOR)); - - //ELITE - add("Craft one or more Blood runes.", - new SkillRequirement(Skill.RUNECRAFT, 77), - new SkillRequirement(Skill.MINING, 38), - new SkillRequirement(Skill.CRAFTING, 38), - new FavourRequirement(Favour.ARCEUUS, 100)); - add("Chop some Redwood logs.", - new SkillRequirement(Skill.WOODCUTTING, 90), - new FavourRequirement(Favour.HOSIDIUS, 75)); - add("Catch an Anglerfish and cook it whilst in Great Kourend.", - new SkillRequirement(Skill.FISHING, 82), - new SkillRequirement(Skill.COOKING, 84), - new FavourRequirement(Favour.PISCARILIUS, 100)); - add("Kill a Hydra in the Karuulm Slayer Dungeon.", - new SkillRequirement(Skill.SLAYER, 95)); - add("Create an Ape Atoll teleport tablet.", - new SkillRequirement(Skill.MAGIC, 90), - new SkillRequirement(Skill.MINING, 38), - new SkillRequirement(Skill.CRAFTING, 38), - new FavourRequirement(Favour.ARCEUUS, 100)); - add("Create your own Battlestaff from scratch within the Farming Guild.", - new SkillRequirement(Skill.FARMING, 85), - new SkillRequirement(Skill.FLETCHING, 40)); - } -} +/* + * Copyright (c) 2019 William + * 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.achievementdiary.diaries; + +import net.runelite.api.Favour; +import net.runelite.api.Quest; +import net.runelite.api.Skill; +import net.runelite.client.plugins.achievementdiary.FavourRequirement; +import net.runelite.client.plugins.achievementdiary.GenericDiaryRequirement; +import net.runelite.client.plugins.achievementdiary.QuestRequirement; +import net.runelite.client.plugins.achievementdiary.SkillRequirement; + +public class KourendDiaryRequirement extends GenericDiaryRequirement +{ + public KourendDiaryRequirement() + { + //EASY + add("Mine some Iron at the Mount Karuulm mine.", + new SkillRequirement(Skill.MINING, 15)); + add("Steal from a Hosidius Food Stall.", + new SkillRequirement(Skill.THIEVING, 25), + new FavourRequirement(Favour.HOSIDIUS, 15)); + add("Browse the Warrens General Store.", + new QuestRequirement(Quest.THE_QUEEN_OF_THIEVES, true)); + add("Enter your Player Owned House from Hosidius.", + new SkillRequirement(Skill.CONSTRUCTION, 25)); + add("Create a Strength potion in the Lovakengj Pub.", + new SkillRequirement(Skill.HERBLORE, 12)); + add("Fish a Trout from the River Molch.", + new SkillRequirement(Skill.FISHING, 20)); + + //MEDIUM + add("Travel to the Fairy Ring south of Mount Karuulm.", + new QuestRequirement(Quest.FAIRYTALE_II__CURE_A_QUEEN, true)); + add("Use Kharedst's memoirs to teleport to all five cities in Great Kourend.", + new QuestRequirement(Quest.THE_DEPTHS_OF_DESPAIR), + new QuestRequirement(Quest.THE_QUEEN_OF_THIEVES), + new QuestRequirement(Quest.TALE_OF_THE_RIGHTEOUS), + new QuestRequirement(Quest.THE_FORSAKEN_TOWER), + new QuestRequirement(Quest.THE_ASCENT_OF_ARCEUUS)); + add("Mine some Volcanic sulphur.", + new SkillRequirement(Skill.MINING, 42)); + add("Enter the Farming Guild.", + new SkillRequirement(Skill.FARMING, 45)); + add("Switch to the Necromancy Spellbook at Tyss.", + new FavourRequirement(Favour.ARCEUUS, 60)); + add("Repair a Piscarilius crane.", + new SkillRequirement(Skill.CRAFTING, 30)); + add("Deliver some intelligence to Captain Ginea.", + new FavourRequirement(Favour.SHAYZIEN, 40)); + add("Catch a Bluegill on Molch Island.", + new SkillRequirement(Skill.FISHING, 43), + new SkillRequirement(Skill.HUNTER, 35)); + add("Use the boulder leap in the Arceuus essence mine.", + new SkillRequirement(Skill.AGILITY, 49)); + add("Subdue the Wintertodt.", + new SkillRequirement(Skill.FIREMAKING, 50)); + add("Catch a Chinchompa in the Kourend Woodland.", + new SkillRequirement(Skill.HUNTER, 53), + new QuestRequirement(Quest.EAGLES_PEAK)); + add("Chop some Mahogany logs north of the Farming Guild.", + new SkillRequirement(Skill.WOODCUTTING, 50)); + + //HARD + add("Enter the Woodcutting Guild.", + new SkillRequirement(Skill.WOODCUTTING, 60), + new FavourRequirement(Favour.HOSIDIUS, 75)); + add("Smelt an Adamantite bar in The Forsaken Tower.", + new SkillRequirement(Skill.SMITHING, 70), + new QuestRequirement(Quest.THE_FORSAKEN_TOWER, true)); + add("Kill a Lizardman Shaman in Molch.", + new FavourRequirement(Favour.SHAYZIEN, 100)); + add("Mine some Lovakite.", + new SkillRequirement(Skill.MINING, 65), + new FavourRequirement(Favour.LOVAKENGJ, 30)); + add("Plant some Logavano seeds at the Tithe Farm.", + new SkillRequirement(Skill.FARMING, 74), + new FavourRequirement(Favour.HOSIDIUS, 100)); + add("Teleport to Xeric's Heart using Xeric's Talisman.", + new QuestRequirement(Quest.ARCHITECTURAL_ALLIANCE)); + add("Deliver an artefact to Captain Khaled.", + new SkillRequirement(Skill.THIEVING, 49), + new FavourRequirement(Favour.PISCARILIUS, 75)); + add("Kill a Wyrm in the Karuulm Slayer Dungeon.", + new SkillRequirement(Skill.SLAYER, 62)); + add("Cast Monster Examine on a Troll south of Mount Quidamortem.", + new SkillRequirement(Skill.MAGIC, 66), + new QuestRequirement(Quest.DREAM_MENTOR)); + + //ELITE + add("Craft one or more Blood runes.", + new SkillRequirement(Skill.RUNECRAFT, 77), + new SkillRequirement(Skill.MINING, 38), + new SkillRequirement(Skill.CRAFTING, 38), + new FavourRequirement(Favour.ARCEUUS, 100)); + add("Chop some Redwood logs.", + new SkillRequirement(Skill.WOODCUTTING, 90), + new FavourRequirement(Favour.HOSIDIUS, 75)); + add("Catch an Anglerfish and cook it whilst in Great Kourend.", + new SkillRequirement(Skill.FISHING, 82), + new SkillRequirement(Skill.COOKING, 84), + new FavourRequirement(Favour.PISCARILIUS, 100)); + add("Kill a Hydra in the Karuulm Slayer Dungeon.", + new SkillRequirement(Skill.SLAYER, 95)); + add("Create an Ape Atoll teleport tablet.", + new SkillRequirement(Skill.MAGIC, 90), + new SkillRequirement(Skill.MINING, 38), + new SkillRequirement(Skill.CRAFTING, 38), + new FavourRequirement(Favour.ARCEUUS, 100)); + add("Create your own Battlestaff from scratch within the Farming Guild.", + new SkillRequirement(Skill.FARMING, 85), + new SkillRequirement(Skill.FLETCHING, 40)); + } +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/agility/AgilityOverlay.java b/runelite-client/src/main/java/net/runelite/client/plugins/agility/AgilityOverlay.java index e9c205f64f..5599fca791 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/agility/AgilityOverlay.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/agility/AgilityOverlay.java @@ -1,141 +1,141 @@ -/* - * Copyright (c) 2018, Adam - * Copyright (c) 2018, Cas - * 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.agility; - -import java.awt.Color; -import java.awt.Dimension; -import java.awt.Graphics2D; -import java.awt.Polygon; -import java.awt.geom.Area; -import java.util.List; -import javax.inject.Inject; -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; -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; - private final AgilityConfig config; - - @Inject - private AgilityOverlay(Client client, AgilityPlugin plugin, AgilityConfig config) - { - super(plugin); - setPosition(OverlayPosition.DYNAMIC); - setLayer(OverlayLayer.ABOVE_SCENE); - this.client = client; - this.plugin = plugin; - this.config = config; - } - - @Override - public Dimension render(Graphics2D graphics) - { - LocalPoint playerLocation = client.getLocalPlayer().getLocalLocation(); - Point mousePosition = client.getMouseCanvasPosition(); - final List marksOfGrace = plugin.getMarksOfGrace(); - plugin.getObstacles().forEach((object, obstacle) -> - { - 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) - { - // This assumes that the obstacle is not clickable. - if (Obstacles.TRAP_OBSTACLE_IDS.contains(object.getId())) - { - Polygon polygon = object.getCanvasTilePoly(); - if (polygon != null) - { - OverlayUtil.renderPolygon(graphics, polygon, config.getTrapColor()); - } - return; - } - Area objectClickbox = object.getClickbox(); - if (objectClickbox != null) - { - 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(); - } - - if (objectClickbox.contains(mousePosition.getX(), mousePosition.getY())) - { - graphics.setColor(configColor.darker()); - } - else - { - graphics.setColor(configColor); - } - - graphics.draw(objectClickbox); - graphics.setColor(new Color(configColor.getRed(), configColor.getGreen(), configColor.getBlue(), 50)); - graphics.fill(objectClickbox); - } - } - - }); - - if (config.highlightMarks() && !marksOfGrace.isEmpty()) - { - for (Tile markOfGraceTile : marksOfGrace) - { - if (markOfGraceTile.getPlane() == client.getPlane() && markOfGraceTile.getItemLayer() != null - && markOfGraceTile.getLocalLocation().distanceTo(playerLocation) < MAX_DISTANCE) - { - final Polygon poly = markOfGraceTile.getItemLayer().getCanvasTilePoly(); - - if (poly == null) - { - continue; - } - - OverlayUtil.renderPolygon(graphics, poly, config.getMarkColor()); - } - } - } - - return null; - } -} +/* + * Copyright (c) 2018, Adam + * Copyright (c) 2018, Cas + * 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.agility; + +import java.awt.Color; +import java.awt.Dimension; +import java.awt.Graphics2D; +import java.awt.Polygon; +import java.awt.geom.Area; +import java.util.List; +import javax.inject.Inject; +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; +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; + private final AgilityConfig config; + + @Inject + private AgilityOverlay(Client client, AgilityPlugin plugin, AgilityConfig config) + { + super(plugin); + setPosition(OverlayPosition.DYNAMIC); + setLayer(OverlayLayer.ABOVE_SCENE); + this.client = client; + this.plugin = plugin; + this.config = config; + } + + @Override + public Dimension render(Graphics2D graphics) + { + LocalPoint playerLocation = client.getLocalPlayer().getLocalLocation(); + Point mousePosition = client.getMouseCanvasPosition(); + final List marksOfGrace = plugin.getMarksOfGrace(); + plugin.getObstacles().forEach((object, obstacle) -> + { + 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) + { + // This assumes that the obstacle is not clickable. + if (Obstacles.TRAP_OBSTACLE_IDS.contains(object.getId())) + { + Polygon polygon = object.getCanvasTilePoly(); + if (polygon != null) + { + OverlayUtil.renderPolygon(graphics, polygon, config.getTrapColor()); + } + return; + } + Area objectClickbox = object.getClickbox(); + if (objectClickbox != null) + { + 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(); + } + + if (objectClickbox.contains(mousePosition.getX(), mousePosition.getY())) + { + graphics.setColor(configColor.darker()); + } + else + { + graphics.setColor(configColor); + } + + graphics.draw(objectClickbox); + graphics.setColor(new Color(configColor.getRed(), configColor.getGreen(), configColor.getBlue(), 50)); + graphics.fill(objectClickbox); + } + } + + }); + + if (config.highlightMarks() && !marksOfGrace.isEmpty()) + { + for (Tile markOfGraceTile : marksOfGrace) + { + if (markOfGraceTile.getPlane() == client.getPlane() && markOfGraceTile.getItemLayer() != null + && markOfGraceTile.getLocalLocation().distanceTo(playerLocation) < MAX_DISTANCE) + { + final Polygon poly = markOfGraceTile.getItemLayer().getCanvasTilePoly(); + + if (poly == null) + { + continue; + } + + OverlayUtil.renderPolygon(graphics, poly, config.getMarkColor()); + } + } + } + + return null; + } +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/agility/AgilityPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/agility/AgilityPlugin.java index 942fdd93b0..3074ab1eb5 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/agility/AgilityPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/agility/AgilityPlugin.java @@ -1,462 +1,463 @@ -/* - * Copyright (c) 2018, Adam - * 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.agility; - -import com.google.inject.Provides; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import javax.inject.Inject; -import lombok.Getter; -import lombok.extern.slf4j.Slf4j; -import net.runelite.api.Client; -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; -import net.runelite.api.events.DecorativeObjectSpawned; -import net.runelite.api.events.ExperienceChanged; -import net.runelite.api.events.GameObjectChanged; -import net.runelite.api.events.GameObjectDespawned; -import net.runelite.api.events.GameObjectSpawned; -import net.runelite.api.events.GameStateChanged; -import net.runelite.api.events.GameTick; -import net.runelite.api.events.GroundObjectChanged; -import net.runelite.api.events.GroundObjectDespawned; -import net.runelite.api.events.GroundObjectSpawned; -import net.runelite.api.events.ItemDespawned; -import net.runelite.api.events.ItemSpawned; -import net.runelite.api.events.MenuEntryAdded; -import net.runelite.api.events.WallObjectChanged; -import net.runelite.api.events.WallObjectDespawned; -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; -import net.runelite.client.ui.overlay.OverlayManager; -import net.runelite.client.ui.overlay.infobox.InfoBoxManager; -import net.runelite.api.MenuEntry; -import net.runelite.client.util.ColorUtil; -import net.runelite.api.MenuAction; -import java.awt.Color; - -@PluginDescriptor( - name = "Agility", - description = "Show helpful information about agility courses and obstacles", - tags = {"grace", "marks", "overlay", "shortcuts", "skilling", "traps"} -) -@Slf4j -public class AgilityPlugin extends Plugin -{ - private static final int AGILITY_ARENA_REGION_ID = 11157; - - @Getter - private final Map obstacles = new HashMap<>(); - - @Getter - private final List marksOfGrace = new ArrayList<>(); - - @Inject - private OverlayManager overlayManager; - - @Inject - private AgilityOverlay agilityOverlay; - - @Inject - private LapCounterOverlay lapCounterOverlay; - - @Inject - private Notifier notifier; - - @Inject - private Client client; - - @Inject - private InfoBoxManager infoBoxManager; - - @Inject - private AgilityConfig config; - - @Inject - private ItemManager itemManager; - - @Getter - private AgilitySession session; - - private int lastAgilityXp; - private WorldPoint lastArenaTicketPosition; - - @Getter - private int agilityLevel; - - @Provides - AgilityConfig getConfig(ConfigManager configManager) - { - return configManager.getConfig(AgilityConfig.class); - } - - @Override - protected void startUp() throws Exception - { - overlayManager.add(agilityOverlay); - overlayManager.add(lapCounterOverlay); - agilityLevel = client.getBoostedSkillLevel(Skill.AGILITY); - } - - @Override - protected void shutDown() throws Exception - { - overlayManager.remove(agilityOverlay); - overlayManager.remove(lapCounterOverlay); - marksOfGrace.clear(); - obstacles.clear(); - session = null; - agilityLevel = 0; - } - - @Subscribe - public void onGameStateChanged(GameStateChanged event) - { - switch (event.getGameState()) - { - case HOPPING: - case LOGIN_SCREEN: - session = null; - lastArenaTicketPosition = null; - removeAgilityArenaTimer(); - break; - case LOADING: - marksOfGrace.clear(); - obstacles.clear(); - break; - case LOGGED_IN: - if (!isInAgilityArena()) - { - lastArenaTicketPosition = null; - removeAgilityArenaTimer(); - } - break; - } - } - - @Subscribe - public void onConfigChanged(ConfigChanged event) - { - if (!config.showAgilityArenaTimer()) - { - removeAgilityArenaTimer(); - } - } - - @Subscribe - public void onExperienceChanged(ExperienceChanged event) - { - if (event.getSkill() != AGILITY || !config.showLapCount()) - { - return; - } - - // Determine how much EXP was actually gained - int agilityXp = client.getSkillExperience(AGILITY); - int skillGained = agilityXp - lastAgilityXp; - lastAgilityXp = agilityXp; - - // Get course - Courses course = Courses.getCourse(client.getLocalPlayer().getWorldLocation().getRegionID()); - if (course == null - || (course.getCourseEndWorldPoints().length == 0 - ? Math.abs(course.getLastObstacleXp() - skillGained) > 1 - : Arrays.stream(course.getCourseEndWorldPoints()).noneMatch(wp -> wp.equals(client.getLocalPlayer().getWorldLocation())))) - { - return; - } - - if (session != null && session.getCourse() == course) - { - session.incrementLapCount(client); - } - else - { - session = new AgilitySession(course); - // New course found, reset lap count and set new course - session.resetLapCount(); - session.incrementLapCount(client); - } - } - - - @Subscribe - public void onBoostedLevelChanged(BoostedLevelChanged boostedLevelChanged) - { - Skill skill = boostedLevelChanged.getSkill(); - if (skill == AGILITY) - { - agilityLevel = client.getBoostedSkillLevel(skill); - } - } - - @Subscribe - public void onItemSpawned(ItemSpawned itemSpawned) - { - if (obstacles.isEmpty()) - { - return; - } - - final Item item = itemSpawned.getItem(); - final Tile tile = itemSpawned.getTile(); - - if (item.getId() == ItemID.MARK_OF_GRACE) - { - marksOfGrace.add(tile); - } - } - - @Subscribe - public void onItemDespawned(ItemDespawned itemDespawned) - { - final Tile tile = itemDespawned.getTile(); - marksOfGrace.remove(tile); - } - - @Subscribe - public void onGameTick(GameTick tick) - { - if (isInAgilityArena()) - { - // Hint arrow has no plane, and always returns the current plane - WorldPoint newTicketPosition = client.getHintArrowPoint(); - WorldPoint oldTickPosition = lastArenaTicketPosition; - - lastArenaTicketPosition = newTicketPosition; - - if (oldTickPosition != null && newTicketPosition != null - && (oldTickPosition.getX() != newTicketPosition.getX() || oldTickPosition.getY() != newTicketPosition.getY())) - { - log.debug("Ticked position moved from {} to {}", oldTickPosition, newTicketPosition); - - if (config.notifyAgilityArena()) - { - notifier.notify("Ticket location changed"); - } - - if (config.showAgilityArenaTimer()) - { - showNewAgilityArenaTimer(); - } - } - } - } - - private boolean isInAgilityArena() - { - Player local = client.getLocalPlayer(); - if (local == null) - { - return false; - } - - WorldPoint location = local.getWorldLocation(); - return location.getRegionID() == AGILITY_ARENA_REGION_ID; - } - - private void removeAgilityArenaTimer() - { - infoBoxManager.removeIf(infoBox -> infoBox instanceof AgilityArenaTimer); - } - - private void showNewAgilityArenaTimer() - { - removeAgilityArenaTimer(); - infoBoxManager.addInfoBox(new AgilityArenaTimer(this, itemManager.getImage(AGILITY_ARENA_TICKET))); - } - - @Subscribe - public void onGameObjectSpawned(GameObjectSpawned event) - { - onTileObject(event.getTile(), null, event.getGameObject()); - } - - @Subscribe - public void onGameObjectChanged(GameObjectChanged event) - { - onTileObject(event.getTile(), event.getPrevious(), event.getGameObject()); - } - - @Subscribe - public void onGameObjectDespawned(GameObjectDespawned event) - { - onTileObject(event.getTile(), event.getGameObject(), null); - } - - @Subscribe - public void onGroundObjectSpawned(GroundObjectSpawned event) - { - onTileObject(event.getTile(), null, event.getGroundObject()); - } - - @Subscribe - public void onGroundObjectChanged(GroundObjectChanged event) - { - onTileObject(event.getTile(), event.getPrevious(), event.getGroundObject()); - } - - @Subscribe - public void onGroundObjectDespawned(GroundObjectDespawned event) - { - onTileObject(event.getTile(), event.getGroundObject(), null); - } - - @Subscribe - public void onWallObjectSpawned(WallObjectSpawned event) - { - onTileObject(event.getTile(), null, event.getWallObject()); - } - - @Subscribe - public void onWallObjectChanged(WallObjectChanged event) - { - onTileObject(event.getTile(), event.getPrevious(), event.getWallObject()); - } - - @Subscribe - public void onWallObjectDespawned(WallObjectDespawned event) - { - onTileObject(event.getTile(), event.getWallObject(), null); - } - - @Subscribe - public void onDecorativeObjectSpawned(DecorativeObjectSpawned event) - { - onTileObject(event.getTile(), null, event.getDecorativeObject()); - } - - @Subscribe - public void onDecorativeObjectChanged(DecorativeObjectChanged event) - { - onTileObject(event.getTile(), event.getPrevious(), event.getDecorativeObject()); - } - - @Subscribe - public void onDecorativeObjectDespawned(DecorativeObjectDespawned event) - { - onTileObject(event.getTile(), event.getDecorativeObject(), null); - } - - private void onTileObject(Tile tile, TileObject oldObject, TileObject newObject) - { - obstacles.remove(oldObject); - - if (newObject == null) - { - return; - } - - if (Obstacles.COURSE_OBSTACLE_IDS.contains(newObject.getId()) || - (Obstacles.TRAP_OBSTACLE_IDS.contains(newObject.getId()) - && Obstacles.TRAP_OBSTACLE_REGIONS.contains(newObject.getWorldLocation().getRegionID()))) - { - 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)); - } - } - } - - @Subscribe - public void onMenuEntryAdded(MenuEntryAdded event) - { - if (!config.showShortcutLevel()) - { - return; - } - - //Guarding against non-first option because agility shortcuts are always that type of event. - if (event.getType() != MenuAction.GAME_OBJECT_FIRST_OPTION.getId()) - { - return; - } - - final int entryId = event.getIdentifier(); - MenuEntry[] menuEntries = client.getMenuEntries(); - - for (Obstacle nearbyObstacle : getObstacles().values()) - { - AgilityShortcut shortcut = nearbyObstacle.getShortcut(); - if (shortcut != null && Arrays.stream(shortcut.getObstacleIds()).anyMatch(i -> i == entryId)) { - MenuEntry entry = menuEntries[menuEntries.length - 1]; - int level = shortcut.getLevel(); - Color color = level <= getAgilityLevel() ? Color.GREEN : Color.RED; - String requirementText = " (level-" + level + ")"; - - entry.setTarget(event.getTarget() + ColorUtil.prependColorTag(requirementText, color)); - client.setMenuEntries(menuEntries); - return; - } - } - } -} +/* + * Copyright (c) 2018, Adam + * 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.agility; + +import com.google.inject.Provides; +import java.awt.Color; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import javax.inject.Inject; +import lombok.Getter; +import lombok.extern.slf4j.Slf4j; +import net.runelite.api.Client; +import net.runelite.api.Item; +import net.runelite.api.ItemID; +import static net.runelite.api.ItemID.AGILITY_ARENA_TICKET; +import net.runelite.api.MenuAction; +import net.runelite.api.MenuEntry; +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; +import net.runelite.api.events.DecorativeObjectSpawned; +import net.runelite.api.events.ExperienceChanged; +import net.runelite.api.events.GameObjectChanged; +import net.runelite.api.events.GameObjectDespawned; +import net.runelite.api.events.GameObjectSpawned; +import net.runelite.api.events.GameStateChanged; +import net.runelite.api.events.GameTick; +import net.runelite.api.events.GroundObjectChanged; +import net.runelite.api.events.GroundObjectDespawned; +import net.runelite.api.events.GroundObjectSpawned; +import net.runelite.api.events.ItemDespawned; +import net.runelite.api.events.ItemSpawned; +import net.runelite.api.events.MenuEntryAdded; +import net.runelite.api.events.WallObjectChanged; +import net.runelite.api.events.WallObjectDespawned; +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; +import net.runelite.client.ui.overlay.OverlayManager; +import net.runelite.client.ui.overlay.infobox.InfoBoxManager; +import net.runelite.client.util.ColorUtil; + +@PluginDescriptor( + name = "Agility", + description = "Show helpful information about agility courses and obstacles", + tags = {"grace", "marks", "overlay", "shortcuts", "skilling", "traps"} +) +@Slf4j +public class AgilityPlugin extends Plugin +{ + private static final int AGILITY_ARENA_REGION_ID = 11157; + + @Getter + private final Map obstacles = new HashMap<>(); + + @Getter + private final List marksOfGrace = new ArrayList<>(); + + @Inject + private OverlayManager overlayManager; + + @Inject + private AgilityOverlay agilityOverlay; + + @Inject + private LapCounterOverlay lapCounterOverlay; + + @Inject + private Notifier notifier; + + @Inject + private Client client; + + @Inject + private InfoBoxManager infoBoxManager; + + @Inject + private AgilityConfig config; + + @Inject + private ItemManager itemManager; + + @Getter + private AgilitySession session; + + private int lastAgilityXp; + private WorldPoint lastArenaTicketPosition; + + @Getter + private int agilityLevel; + + @Provides + AgilityConfig getConfig(ConfigManager configManager) + { + return configManager.getConfig(AgilityConfig.class); + } + + @Override + protected void startUp() throws Exception + { + overlayManager.add(agilityOverlay); + overlayManager.add(lapCounterOverlay); + agilityLevel = client.getBoostedSkillLevel(Skill.AGILITY); + } + + @Override + protected void shutDown() throws Exception + { + overlayManager.remove(agilityOverlay); + overlayManager.remove(lapCounterOverlay); + marksOfGrace.clear(); + obstacles.clear(); + session = null; + agilityLevel = 0; + } + + @Subscribe + public void onGameStateChanged(GameStateChanged event) + { + switch (event.getGameState()) + { + case HOPPING: + case LOGIN_SCREEN: + session = null; + lastArenaTicketPosition = null; + removeAgilityArenaTimer(); + break; + case LOADING: + marksOfGrace.clear(); + obstacles.clear(); + break; + case LOGGED_IN: + if (!isInAgilityArena()) + { + lastArenaTicketPosition = null; + removeAgilityArenaTimer(); + } + break; + } + } + + @Subscribe + public void onConfigChanged(ConfigChanged event) + { + if (!config.showAgilityArenaTimer()) + { + removeAgilityArenaTimer(); + } + } + + @Subscribe + public void onExperienceChanged(ExperienceChanged event) + { + if (event.getSkill() != AGILITY || !config.showLapCount()) + { + return; + } + + // Determine how much EXP was actually gained + int agilityXp = client.getSkillExperience(AGILITY); + int skillGained = agilityXp - lastAgilityXp; + lastAgilityXp = agilityXp; + + // Get course + Courses course = Courses.getCourse(client.getLocalPlayer().getWorldLocation().getRegionID()); + if (course == null + || (course.getCourseEndWorldPoints().length == 0 + ? Math.abs(course.getLastObstacleXp() - skillGained) > 1 + : Arrays.stream(course.getCourseEndWorldPoints()).noneMatch(wp -> wp.equals(client.getLocalPlayer().getWorldLocation())))) + { + return; + } + + if (session != null && session.getCourse() == course) + { + session.incrementLapCount(client); + } + else + { + session = new AgilitySession(course); + // New course found, reset lap count and set new course + session.resetLapCount(); + session.incrementLapCount(client); + } + } + + + @Subscribe + public void onBoostedLevelChanged(BoostedLevelChanged boostedLevelChanged) + { + Skill skill = boostedLevelChanged.getSkill(); + if (skill == AGILITY) + { + agilityLevel = client.getBoostedSkillLevel(skill); + } + } + + @Subscribe + public void onItemSpawned(ItemSpawned itemSpawned) + { + if (obstacles.isEmpty()) + { + return; + } + + final Item item = itemSpawned.getItem(); + final Tile tile = itemSpawned.getTile(); + + if (item.getId() == ItemID.MARK_OF_GRACE) + { + marksOfGrace.add(tile); + } + } + + @Subscribe + public void onItemDespawned(ItemDespawned itemDespawned) + { + final Tile tile = itemDespawned.getTile(); + marksOfGrace.remove(tile); + } + + @Subscribe + public void onGameTick(GameTick tick) + { + if (isInAgilityArena()) + { + // Hint arrow has no plane, and always returns the current plane + WorldPoint newTicketPosition = client.getHintArrowPoint(); + WorldPoint oldTickPosition = lastArenaTicketPosition; + + lastArenaTicketPosition = newTicketPosition; + + if (oldTickPosition != null && newTicketPosition != null + && (oldTickPosition.getX() != newTicketPosition.getX() || oldTickPosition.getY() != newTicketPosition.getY())) + { + log.debug("Ticked position moved from {} to {}", oldTickPosition, newTicketPosition); + + if (config.notifyAgilityArena()) + { + notifier.notify("Ticket location changed"); + } + + if (config.showAgilityArenaTimer()) + { + showNewAgilityArenaTimer(); + } + } + } + } + + private boolean isInAgilityArena() + { + Player local = client.getLocalPlayer(); + if (local == null) + { + return false; + } + + WorldPoint location = local.getWorldLocation(); + return location.getRegionID() == AGILITY_ARENA_REGION_ID; + } + + private void removeAgilityArenaTimer() + { + infoBoxManager.removeIf(infoBox -> infoBox instanceof AgilityArenaTimer); + } + + private void showNewAgilityArenaTimer() + { + removeAgilityArenaTimer(); + infoBoxManager.addInfoBox(new AgilityArenaTimer(this, itemManager.getImage(AGILITY_ARENA_TICKET))); + } + + @Subscribe + public void onGameObjectSpawned(GameObjectSpawned event) + { + onTileObject(event.getTile(), null, event.getGameObject()); + } + + @Subscribe + public void onGameObjectChanged(GameObjectChanged event) + { + onTileObject(event.getTile(), event.getPrevious(), event.getGameObject()); + } + + @Subscribe + public void onGameObjectDespawned(GameObjectDespawned event) + { + onTileObject(event.getTile(), event.getGameObject(), null); + } + + @Subscribe + public void onGroundObjectSpawned(GroundObjectSpawned event) + { + onTileObject(event.getTile(), null, event.getGroundObject()); + } + + @Subscribe + public void onGroundObjectChanged(GroundObjectChanged event) + { + onTileObject(event.getTile(), event.getPrevious(), event.getGroundObject()); + } + + @Subscribe + public void onGroundObjectDespawned(GroundObjectDespawned event) + { + onTileObject(event.getTile(), event.getGroundObject(), null); + } + + @Subscribe + public void onWallObjectSpawned(WallObjectSpawned event) + { + onTileObject(event.getTile(), null, event.getWallObject()); + } + + @Subscribe + public void onWallObjectChanged(WallObjectChanged event) + { + onTileObject(event.getTile(), event.getPrevious(), event.getWallObject()); + } + + @Subscribe + public void onWallObjectDespawned(WallObjectDespawned event) + { + onTileObject(event.getTile(), event.getWallObject(), null); + } + + @Subscribe + public void onDecorativeObjectSpawned(DecorativeObjectSpawned event) + { + onTileObject(event.getTile(), null, event.getDecorativeObject()); + } + + @Subscribe + public void onDecorativeObjectChanged(DecorativeObjectChanged event) + { + onTileObject(event.getTile(), event.getPrevious(), event.getDecorativeObject()); + } + + @Subscribe + public void onDecorativeObjectDespawned(DecorativeObjectDespawned event) + { + onTileObject(event.getTile(), event.getDecorativeObject(), null); + } + + private void onTileObject(Tile tile, TileObject oldObject, TileObject newObject) + { + obstacles.remove(oldObject); + + if (newObject == null) + { + return; + } + + if (Obstacles.COURSE_OBSTACLE_IDS.contains(newObject.getId()) || + (Obstacles.TRAP_OBSTACLE_IDS.contains(newObject.getId()) + && Obstacles.TRAP_OBSTACLE_REGIONS.contains(newObject.getWorldLocation().getRegionID()))) + { + 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)); + } + } + } + + @Subscribe + public void onMenuEntryAdded(MenuEntryAdded event) + { + if (!config.showShortcutLevel()) + { + return; + } + + //Guarding against non-first option because agility shortcuts are always that type of event. + if (event.getType() != MenuAction.GAME_OBJECT_FIRST_OPTION.getId()) + { + return; + } + + final int entryId = event.getIdentifier(); + MenuEntry[] menuEntries = client.getMenuEntries(); + + for (Obstacle nearbyObstacle : getObstacles().values()) + { + AgilityShortcut shortcut = nearbyObstacle.getShortcut(); + if (shortcut != null && Arrays.stream(shortcut.getObstacleIds()).anyMatch(i -> i == entryId)) + { + MenuEntry entry = menuEntries[menuEntries.length - 1]; + int level = shortcut.getLevel(); + Color color = level <= getAgilityLevel() ? Color.GREEN : Color.RED; + String requirementText = " (level-" + level + ")"; + + entry.setTarget(event.getTarget() + ColorUtil.prependColorTag(requirementText, color)); + client.setMenuEntries(menuEntries); + return; + } + } + } +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/agility/Obstacles.java b/runelite-client/src/main/java/net/runelite/client/plugins/agility/Obstacles.java index 92df605a36..8017ba2581 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/agility/Obstacles.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/agility/Obstacles.java @@ -1,131 +1,334 @@ -/* - * Copyright (c) 2018, SomeoneWithAnInternetConnection - * 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.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.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 -{ - static final Set COURSE_OBSTACLE_IDS = ImmutableSet.of( - // Gnome - OBSTACLE_NET_23134, TREE_BRANCH_23559, TREE_BRANCH_23560, OBSTACLE_NET_23135, OBSTACLE_PIPE_23138, - OBSTACLE_PIPE_23139, LOG_BALANCE_23145, BALANCING_ROPE_23557, - // Brimhaven - PLANK_3572, PLANK_3571, PLANK_3570, ROPE_SWING, PILLAR_3578, LOW_WALL, LOG_BALANCE, LOG_BALANCE_3557, - BALANCING_LEDGE_3561, BALANCING_LEDGE, MONKEY_BARS_3564, BALANCING_ROPE, HAND_HOLDS_3583, - // Draynor - ROUGH_WALL, TIGHTROPE, TIGHTROPE_10075, NARROW_WALL, WALL_10084, GAP_10085, CRATE_10086, STILE_7527, - // Al-Kharid - ROUGH_WALL_10093, TIGHTROPE_10284, CABLE, ZIP_LINE, TROPICAL_TREE_10357, ROOF_TOP_BEAMS, - TIGHTROPE_10583, GAP_10352, - // Pyramid - STAIRS_10857, LOW_WALL_10865, LEDGE_10860, PLANK_10868, GAP_10882, LEDGE_10886, STAIRS_10857, GAP_10884, - GAP_10859, GAP_10861, LOW_WALL_10865, GAP_10859, LEDGE_10888, PLANK_10868, CLIMBING_ROCKS_10851, DOORWAY_10855, - // Varrock - ROUGH_WALL_10586, CLOTHES_LINE, GAP_10642, WALL_10777, GAP_10778, GAP_10779, GAP_10780, LEDGE_10781, EDGE, - // Penguin - STEPPING_STONE_21120, STEPPING_STONE_21126, STEPPING_STONE_21128, STEPPING_STONE_21129, - STEPPING_STONE_21130, STEPPING_STONE_21131, STEPPING_STONE_21132, STEPPING_STONE_21133, - ICICLES, ICE, ICE_21149, ICE_21150, ICE_21151, ICE_21152, ICE_21153, ICE_21154, ICE_21155, ICE_21156, - // Barbarian - ROPESWING_23131, LOG_BALANCE_23144, OBSTACLE_NET_20211, BALANCING_LEDGE_23547, LADDER_16682, CRUMBLING_WALL_1948, - // Canifis - TALL_TREE_10819, GAP_10820, GAP_10821, GAP_10828, GAP_10822, POLEVAULT, GAP_10823, GAP_10832, - // Ape atoll - 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_11369, LEDGE_11370, EDGE_11371, - // Wilderness - OBSTACLE_PIPE_23137, ROPESWING_23132, STEPPING_STONE_23556, LOG_BALANCE_23542, ROCKS_23640, - // Seers - WALL_11373, GAP_11374, TIGHTROPE_11378, GAP_11375, GAP_11376, EDGE_11377, - // Dorgesh-Kaan - CABLE_22569, CABLE_22572, LADDER_22564, JUTTING_WALL_22552, TUNNEL_22557, PYLON_22664, - CONSOLE, BOILER_22635, STAIRS_22650, STAIRS_22651, STAIRS_22609, STAIRS_22608, - // Pollniveach - BASKET_11380, MARKET_STALL_11381, BANNER_11382, GAP_11383, TREE_11384, ROUGH_WALL_11385, - MONKEYBARS, TREE_11389, DRYING_LINE, - // Rellaka - ROUGH_WALL_11391, GAP_11392, TIGHTROPE_11393, GAP_11395, GAP_11396, TIGHTROPE_11397, PILE_OF_FISH, - // Ardougne - GAP_11406, GAP_11429, GAP_11430, STEEP_ROOF, GAP_11630, PLANK_11631, WOODEN_BEAMS, - // Meiyerditch - NULL_12945, ROCK_17958, ROCK_17959, ROCK_17960, BOAT_17961, NULL_18122, NULL_18124, WALL_RUBBLE, - WALL_RUBBLE_18038, FLOORBOARDS, FLOORBOARDS_18071, FLOORBOARDS_18072, FLOORBOARDS_18073, NULL_18129, NULL_18130, - WALL_18078, NULL_18132, NULL_18133, NULL_18083, TUNNEL_18085, SHELF_18086, SHELF_18087, WALL_18088, - FLOORBOARDS_18089, FLOORBOARDS_18090, DOOR_18091, FLOORBOARDS_18093, FLOORBOARDS_18094, SHELF_18095, - SHELF_18096, FLOORBOARDS_18097, FLOORBOARDS_18098, WASHING_LINE_18099, WASHING_LINE_18100, - NULL_18135, NULL_18136, SHELF_18105, SHELF_18106, SHELF_18107, SHELF_18108, FLOORBOARDS_18109, - FLOORBOARDS_18110, FLOORBOARDS_18112, FLOORBOARDS_18111, FLOORBOARDS_18114, FLOORBOARDS_18113, - NULL_18116, FLOORBOARDS_18117, FLOORBOARDS_18118, STAIRS_DOWN, WALL_17980, - // Werewolf - STEPPING_STONE_11643, HURDLE, HURDLE_11639, HURDLE_11640, PIPE_11657, SKULL_SLOPE, ZIP_LINE_11644, - ZIP_LINE_11645, ZIP_LINE_11646 - ); - - static final Multimap SHORTCUT_OBSTACLE_IDS; - - static final Set TRAP_OBSTACLE_IDS = ImmutableSet.of( - // Agility pyramid - NULL_3550, NULL_10872, NULL_10873 - ); - - static final List TRAP_OBSTACLE_REGIONS = ImmutableList.of(12105, 13356); - - static - { - final ImmutableMultimap.Builder builder = ImmutableMultimap.builder(); - for (final AgilityShortcut item : AgilityShortcut.values()) - { - for (int obstacle : item.getObstacleIds()) - { - builder.put(obstacle, item); - } - } - SHORTCUT_OBSTACLE_IDS = builder.build(); - } -} +/* + * Copyright (c) 2018, SomeoneWithAnInternetConnection + * 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.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.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.BALANCING_LEDGE; +import static net.runelite.api.ObjectID.BALANCING_LEDGE_23547; +import static net.runelite.api.ObjectID.BALANCING_LEDGE_3561; +import static net.runelite.api.ObjectID.BALANCING_ROPE; +import static net.runelite.api.ObjectID.BALANCING_ROPE_23557; +import static net.runelite.api.ObjectID.BANNER_11382; +import static net.runelite.api.ObjectID.BASKET_11380; +import static net.runelite.api.ObjectID.BOAT_17961; +import static net.runelite.api.ObjectID.BOILER_22635; +import static net.runelite.api.ObjectID.CABLE; +import static net.runelite.api.ObjectID.CABLE_22569; +import static net.runelite.api.ObjectID.CABLE_22572; +import static net.runelite.api.ObjectID.CLIMBING_ROCKS_10851; +import static net.runelite.api.ObjectID.CLOTHES_LINE; +import static net.runelite.api.ObjectID.CONSOLE; +import static net.runelite.api.ObjectID.CRATE_10086; +import static net.runelite.api.ObjectID.CRUMBLING_WALL_1948; +import static net.runelite.api.ObjectID.DOORWAY_10855; +import static net.runelite.api.ObjectID.DOOR_18091; +import static net.runelite.api.ObjectID.DRYING_LINE; +import static net.runelite.api.ObjectID.EDGE; +import static net.runelite.api.ObjectID.EDGE_11371; +import static net.runelite.api.ObjectID.EDGE_11377; +import static net.runelite.api.ObjectID.FLOORBOARDS; +import static net.runelite.api.ObjectID.FLOORBOARDS_18071; +import static net.runelite.api.ObjectID.FLOORBOARDS_18072; +import static net.runelite.api.ObjectID.FLOORBOARDS_18073; +import static net.runelite.api.ObjectID.FLOORBOARDS_18089; +import static net.runelite.api.ObjectID.FLOORBOARDS_18090; +import static net.runelite.api.ObjectID.FLOORBOARDS_18093; +import static net.runelite.api.ObjectID.FLOORBOARDS_18094; +import static net.runelite.api.ObjectID.FLOORBOARDS_18097; +import static net.runelite.api.ObjectID.FLOORBOARDS_18098; +import static net.runelite.api.ObjectID.FLOORBOARDS_18109; +import static net.runelite.api.ObjectID.FLOORBOARDS_18110; +import static net.runelite.api.ObjectID.FLOORBOARDS_18111; +import static net.runelite.api.ObjectID.FLOORBOARDS_18112; +import static net.runelite.api.ObjectID.FLOORBOARDS_18113; +import static net.runelite.api.ObjectID.FLOORBOARDS_18114; +import static net.runelite.api.ObjectID.FLOORBOARDS_18117; +import static net.runelite.api.ObjectID.FLOORBOARDS_18118; +import static net.runelite.api.ObjectID.GAP_10085; +import static net.runelite.api.ObjectID.GAP_10352; +import static net.runelite.api.ObjectID.GAP_10642; +import static net.runelite.api.ObjectID.GAP_10778; +import static net.runelite.api.ObjectID.GAP_10779; +import static net.runelite.api.ObjectID.GAP_10780; +import static net.runelite.api.ObjectID.GAP_10820; +import static net.runelite.api.ObjectID.GAP_10821; +import static net.runelite.api.ObjectID.GAP_10822; +import static net.runelite.api.ObjectID.GAP_10823; +import static net.runelite.api.ObjectID.GAP_10828; +import static net.runelite.api.ObjectID.GAP_10832; +import static net.runelite.api.ObjectID.GAP_10859; +import static net.runelite.api.ObjectID.GAP_10861; +import static net.runelite.api.ObjectID.GAP_10882; +import static net.runelite.api.ObjectID.GAP_10884; +import static net.runelite.api.ObjectID.GAP_11161; +import static net.runelite.api.ObjectID.GAP_11360; +import static net.runelite.api.ObjectID.GAP_11365; +import static net.runelite.api.ObjectID.GAP_11374; +import static net.runelite.api.ObjectID.GAP_11375; +import static net.runelite.api.ObjectID.GAP_11376; +import static net.runelite.api.ObjectID.GAP_11383; +import static net.runelite.api.ObjectID.GAP_11392; +import static net.runelite.api.ObjectID.GAP_11395; +import static net.runelite.api.ObjectID.GAP_11396; +import static net.runelite.api.ObjectID.GAP_11406; +import static net.runelite.api.ObjectID.GAP_11429; +import static net.runelite.api.ObjectID.GAP_11430; +import static net.runelite.api.ObjectID.GAP_11630; +import static net.runelite.api.ObjectID.HAND_HOLDS_10836; +import static net.runelite.api.ObjectID.HAND_HOLDS_3583; +import static net.runelite.api.ObjectID.HURDLE; +import static net.runelite.api.ObjectID.HURDLE_11639; +import static net.runelite.api.ObjectID.HURDLE_11640; +import static net.runelite.api.ObjectID.ICE; +import static net.runelite.api.ObjectID.ICE_21149; +import static net.runelite.api.ObjectID.ICE_21150; +import static net.runelite.api.ObjectID.ICE_21151; +import static net.runelite.api.ObjectID.ICE_21152; +import static net.runelite.api.ObjectID.ICE_21153; +import static net.runelite.api.ObjectID.ICE_21154; +import static net.runelite.api.ObjectID.ICE_21155; +import static net.runelite.api.ObjectID.ICE_21156; +import static net.runelite.api.ObjectID.ICICLES; +import static net.runelite.api.ObjectID.JUTTING_WALL_22552; +import static net.runelite.api.ObjectID.LADDER_16682; +import static net.runelite.api.ObjectID.LADDER_22564; +import static net.runelite.api.ObjectID.LEDGE_10781; +import static net.runelite.api.ObjectID.LEDGE_10860; +import static net.runelite.api.ObjectID.LEDGE_10886; +import static net.runelite.api.ObjectID.LEDGE_10888; +import static net.runelite.api.ObjectID.LEDGE_11366; +import static net.runelite.api.ObjectID.LEDGE_11367; +import static net.runelite.api.ObjectID.LEDGE_11369; +import static net.runelite.api.ObjectID.LEDGE_11370; +import static net.runelite.api.ObjectID.LOG_BALANCE; +import static net.runelite.api.ObjectID.LOG_BALANCE_23144; +import static net.runelite.api.ObjectID.LOG_BALANCE_23145; +import static net.runelite.api.ObjectID.LOG_BALANCE_23542; +import static net.runelite.api.ObjectID.LOG_BALANCE_3557; +import static net.runelite.api.ObjectID.LOW_WALL; +import static net.runelite.api.ObjectID.LOW_WALL_10865; +import static net.runelite.api.ObjectID.MARKET_STALL_11381; +import static net.runelite.api.ObjectID.MONKEYBARS; +import static net.runelite.api.ObjectID.MONKEYBARS_15417; +import static net.runelite.api.ObjectID.MONKEY_BARS_3564; +import static net.runelite.api.ObjectID.NARROW_WALL; +import static net.runelite.api.ObjectID.OBSTACLE_NET_20211; +import static net.runelite.api.ObjectID.OBSTACLE_NET_23134; +import static net.runelite.api.ObjectID.OBSTACLE_NET_23135; +import static net.runelite.api.ObjectID.OBSTACLE_PIPE_23137; +import static net.runelite.api.ObjectID.OBSTACLE_PIPE_23138; +import static net.runelite.api.ObjectID.OBSTACLE_PIPE_23139; +import static net.runelite.api.ObjectID.PILE_OF_FISH; +import static net.runelite.api.ObjectID.PILLAR_3578; +import static net.runelite.api.ObjectID.PIPE_11657; +import static net.runelite.api.ObjectID.PLANK_10868; +import static net.runelite.api.ObjectID.PLANK_11631; +import static net.runelite.api.ObjectID.PLANK_3570; +import static net.runelite.api.ObjectID.PLANK_3571; +import static net.runelite.api.ObjectID.PLANK_3572; +import static net.runelite.api.ObjectID.POLEVAULT; +import static net.runelite.api.ObjectID.PYLON_22664; +import static net.runelite.api.ObjectID.ROCKS_23640; +import static net.runelite.api.ObjectID.ROCK_17958; +import static net.runelite.api.ObjectID.ROCK_17959; +import static net.runelite.api.ObjectID.ROCK_17960; +import static net.runelite.api.ObjectID.ROOF_TOP_BEAMS; +import static net.runelite.api.ObjectID.ROPESWING_23131; +import static net.runelite.api.ObjectID.ROPESWING_23132; +import static net.runelite.api.ObjectID.ROPE_15487; +import static net.runelite.api.ObjectID.ROPE_SWING; +import static net.runelite.api.ObjectID.ROUGH_WALL; +import static net.runelite.api.ObjectID.ROUGH_WALL_10093; +import static net.runelite.api.ObjectID.ROUGH_WALL_10586; +import static net.runelite.api.ObjectID.ROUGH_WALL_10833; +import static net.runelite.api.ObjectID.ROUGH_WALL_11385; +import static net.runelite.api.ObjectID.ROUGH_WALL_11391; +import static net.runelite.api.ObjectID.SHELF_18086; +import static net.runelite.api.ObjectID.SHELF_18087; +import static net.runelite.api.ObjectID.SHELF_18095; +import static net.runelite.api.ObjectID.SHELF_18096; +import static net.runelite.api.ObjectID.SHELF_18105; +import static net.runelite.api.ObjectID.SHELF_18106; +import static net.runelite.api.ObjectID.SHELF_18107; +import static net.runelite.api.ObjectID.SHELF_18108; +import static net.runelite.api.ObjectID.SKULL_SLOPE; +import static net.runelite.api.ObjectID.SKULL_SLOPE_15483; +import static net.runelite.api.ObjectID.STAIRS_10857; +import static net.runelite.api.ObjectID.STAIRS_22608; +import static net.runelite.api.ObjectID.STAIRS_22609; +import static net.runelite.api.ObjectID.STAIRS_22650; +import static net.runelite.api.ObjectID.STAIRS_22651; +import static net.runelite.api.ObjectID.STAIRS_DOWN; +import static net.runelite.api.ObjectID.STEEP_ROOF; +import static net.runelite.api.ObjectID.STEPPING_STONE_11643; +import static net.runelite.api.ObjectID.STEPPING_STONE_15412; +import static net.runelite.api.ObjectID.STEPPING_STONE_21120; +import static net.runelite.api.ObjectID.STEPPING_STONE_21126; +import static net.runelite.api.ObjectID.STEPPING_STONE_21128; +import static net.runelite.api.ObjectID.STEPPING_STONE_21129; +import static net.runelite.api.ObjectID.STEPPING_STONE_21130; +import static net.runelite.api.ObjectID.STEPPING_STONE_21131; +import static net.runelite.api.ObjectID.STEPPING_STONE_21132; +import static net.runelite.api.ObjectID.STEPPING_STONE_21133; +import static net.runelite.api.ObjectID.STEPPING_STONE_23556; +import static net.runelite.api.ObjectID.STILE_7527; +import static net.runelite.api.ObjectID.TALL_TREE_10819; +import static net.runelite.api.ObjectID.TIGHTROPE; +import static net.runelite.api.ObjectID.TIGHTROPE_10075; +import static net.runelite.api.ObjectID.TIGHTROPE_10284; +import static net.runelite.api.ObjectID.TIGHTROPE_10583; +import static net.runelite.api.ObjectID.TIGHTROPE_10834; +import static net.runelite.api.ObjectID.TIGHTROPE_11361; +import static net.runelite.api.ObjectID.TIGHTROPE_11364; +import static net.runelite.api.ObjectID.TIGHTROPE_11378; +import static net.runelite.api.ObjectID.TIGHTROPE_11393; +import static net.runelite.api.ObjectID.TIGHTROPE_11397; +import static net.runelite.api.ObjectID.TREE_11384; +import static net.runelite.api.ObjectID.TREE_11389; +import static net.runelite.api.ObjectID.TREE_BRANCH_23559; +import static net.runelite.api.ObjectID.TREE_BRANCH_23560; +import static net.runelite.api.ObjectID.TROPICAL_TREE_10357; +import static net.runelite.api.ObjectID.TROPICAL_TREE_15414; +import static net.runelite.api.ObjectID.TROPICAL_TREE_16062; +import static net.runelite.api.ObjectID.TUNNEL_18085; +import static net.runelite.api.ObjectID.TUNNEL_22557; +import static net.runelite.api.ObjectID.WALL_10084; +import static net.runelite.api.ObjectID.WALL_10777; +import static net.runelite.api.ObjectID.WALL_11373; +import static net.runelite.api.ObjectID.WALL_17980; +import static net.runelite.api.ObjectID.WALL_18078; +import static net.runelite.api.ObjectID.WALL_18088; +import static net.runelite.api.ObjectID.WALL_RUBBLE; +import static net.runelite.api.ObjectID.WALL_RUBBLE_18038; +import static net.runelite.api.ObjectID.WASHING_LINE_18099; +import static net.runelite.api.ObjectID.WASHING_LINE_18100; +import static net.runelite.api.ObjectID.WOODEN_BEAMS; +import static net.runelite.api.ObjectID.ZIP_LINE; +import static net.runelite.api.ObjectID.ZIP_LINE_11644; +import static net.runelite.api.ObjectID.ZIP_LINE_11645; +import static net.runelite.api.ObjectID.ZIP_LINE_11646; +import net.runelite.client.game.AgilityShortcut; + +class Obstacles +{ + static final Set COURSE_OBSTACLE_IDS = ImmutableSet.of( + // Gnome + OBSTACLE_NET_23134, TREE_BRANCH_23559, TREE_BRANCH_23560, OBSTACLE_NET_23135, OBSTACLE_PIPE_23138, + OBSTACLE_PIPE_23139, LOG_BALANCE_23145, BALANCING_ROPE_23557, + // Brimhaven + PLANK_3572, PLANK_3571, PLANK_3570, ROPE_SWING, PILLAR_3578, LOW_WALL, LOG_BALANCE, LOG_BALANCE_3557, + BALANCING_LEDGE_3561, BALANCING_LEDGE, MONKEY_BARS_3564, BALANCING_ROPE, HAND_HOLDS_3583, + // Draynor + ROUGH_WALL, TIGHTROPE, TIGHTROPE_10075, NARROW_WALL, WALL_10084, GAP_10085, CRATE_10086, STILE_7527, + // Al-Kharid + ROUGH_WALL_10093, TIGHTROPE_10284, CABLE, ZIP_LINE, TROPICAL_TREE_10357, ROOF_TOP_BEAMS, + TIGHTROPE_10583, GAP_10352, + // Pyramid + STAIRS_10857, LOW_WALL_10865, LEDGE_10860, PLANK_10868, GAP_10882, LEDGE_10886, STAIRS_10857, GAP_10884, + GAP_10859, GAP_10861, LOW_WALL_10865, GAP_10859, LEDGE_10888, PLANK_10868, CLIMBING_ROCKS_10851, DOORWAY_10855, + // Varrock + ROUGH_WALL_10586, CLOTHES_LINE, GAP_10642, WALL_10777, GAP_10778, GAP_10779, GAP_10780, LEDGE_10781, EDGE, + // Penguin + STEPPING_STONE_21120, STEPPING_STONE_21126, STEPPING_STONE_21128, STEPPING_STONE_21129, + STEPPING_STONE_21130, STEPPING_STONE_21131, STEPPING_STONE_21132, STEPPING_STONE_21133, + ICICLES, ICE, ICE_21149, ICE_21150, ICE_21151, ICE_21152, ICE_21153, ICE_21154, ICE_21155, ICE_21156, + // Barbarian + ROPESWING_23131, LOG_BALANCE_23144, OBSTACLE_NET_20211, BALANCING_LEDGE_23547, LADDER_16682, CRUMBLING_WALL_1948, + // Canifis + TALL_TREE_10819, GAP_10820, GAP_10821, GAP_10828, GAP_10822, POLEVAULT, GAP_10823, GAP_10832, + // Ape atoll + 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_11369, LEDGE_11370, EDGE_11371, + // Wilderness + OBSTACLE_PIPE_23137, ROPESWING_23132, STEPPING_STONE_23556, LOG_BALANCE_23542, ROCKS_23640, + // Seers + WALL_11373, GAP_11374, TIGHTROPE_11378, GAP_11375, GAP_11376, EDGE_11377, + // Dorgesh-Kaan + CABLE_22569, CABLE_22572, LADDER_22564, JUTTING_WALL_22552, TUNNEL_22557, PYLON_22664, + CONSOLE, BOILER_22635, STAIRS_22650, STAIRS_22651, STAIRS_22609, STAIRS_22608, + // Pollniveach + BASKET_11380, MARKET_STALL_11381, BANNER_11382, GAP_11383, TREE_11384, ROUGH_WALL_11385, + MONKEYBARS, TREE_11389, DRYING_LINE, + // Rellaka + ROUGH_WALL_11391, GAP_11392, TIGHTROPE_11393, GAP_11395, GAP_11396, TIGHTROPE_11397, PILE_OF_FISH, + // Ardougne + GAP_11406, GAP_11429, GAP_11430, STEEP_ROOF, GAP_11630, PLANK_11631, WOODEN_BEAMS, + // Meiyerditch + NULL_12945, ROCK_17958, ROCK_17959, ROCK_17960, BOAT_17961, NULL_18122, NULL_18124, WALL_RUBBLE, + WALL_RUBBLE_18038, FLOORBOARDS, FLOORBOARDS_18071, FLOORBOARDS_18072, FLOORBOARDS_18073, NULL_18129, NULL_18130, + WALL_18078, NULL_18132, NULL_18133, NULL_18083, TUNNEL_18085, SHELF_18086, SHELF_18087, WALL_18088, + FLOORBOARDS_18089, FLOORBOARDS_18090, DOOR_18091, FLOORBOARDS_18093, FLOORBOARDS_18094, SHELF_18095, + SHELF_18096, FLOORBOARDS_18097, FLOORBOARDS_18098, WASHING_LINE_18099, WASHING_LINE_18100, + NULL_18135, NULL_18136, SHELF_18105, SHELF_18106, SHELF_18107, SHELF_18108, FLOORBOARDS_18109, + FLOORBOARDS_18110, FLOORBOARDS_18112, FLOORBOARDS_18111, FLOORBOARDS_18114, FLOORBOARDS_18113, + NULL_18116, FLOORBOARDS_18117, FLOORBOARDS_18118, STAIRS_DOWN, WALL_17980, + // Werewolf + STEPPING_STONE_11643, HURDLE, HURDLE_11639, HURDLE_11640, PIPE_11657, SKULL_SLOPE, ZIP_LINE_11644, + ZIP_LINE_11645, ZIP_LINE_11646 + ); + + static final Multimap SHORTCUT_OBSTACLE_IDS; + + static final Set TRAP_OBSTACLE_IDS = ImmutableSet.of( + // Agility pyramid + NULL_3550, NULL_10872, NULL_10873 + ); + + static final List TRAP_OBSTACLE_REGIONS = ImmutableList.of(12105, 13356); + + static + { + final ImmutableMultimap.Builder builder = ImmutableMultimap.builder(); + for (final AgilityShortcut item : AgilityShortcut.values()) + { + for (int obstacle : item.getObstacleIds()) + { + builder.put(obstacle, item); + } + } + SHORTCUT_OBSTACLE_IDS = builder.build(); + } +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/alchemicalhydra/HydraPhase.java b/runelite-client/src/main/java/net/runelite/client/plugins/alchemicalhydra/HydraPhase.java index 471e8517fb..d06588e168 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/alchemicalhydra/HydraPhase.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/alchemicalhydra/HydraPhase.java @@ -1,71 +1,71 @@ -/* - * Copyright (c) 2019, Lucas - * 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.alchemicalhydra; - -import lombok.Getter; -import net.runelite.api.AnimationID; -import net.runelite.api.ProjectileID; -import net.runelite.api.SpriteID; -import net.runelite.api.coords.WorldPoint; - -enum HydraPhase -{ // Sorry for the autism - ONE (3, AnimationID.HYDRA_1_1, AnimationID.HYDRA_1_2, ProjectileID.HYDRA_POISON, 0, SpriteID.BIG_ASS_GUTHIX_SPELL, new WorldPoint(1371, 10263, 0)), - TWO (3, AnimationID.HYDRA_2_1, AnimationID.HYDRA_2_2, 0, AnimationID.HYDRA_LIGHTNING, SpriteID.BIG_SPEC_TRANSFER, new WorldPoint(1371, 10272, 0)), - THREE (3, AnimationID.HYDRA_3_1, AnimationID.HYDRA_3_2, 0, AnimationID.HYDRA_FIRE, SpriteID.BIG_SUPERHEAT, new WorldPoint(1362, 10272, 0)), - FOUR (1, AnimationID.HYDRA_4_1, AnimationID.HYDRA_4_2, ProjectileID.HYDRA_POISON, 0, SpriteID.BIG_ASS_GUTHIX_SPELL, null); - - @Getter - private final int attacksPerSwitch; - - @Getter - private final int deathAnim1; - - @Getter - private final int deathAnim2; - - @Getter - private final int specProjectileId; - - @Getter - private final int specAnimationId; - - @Getter - private final int specImage; - - @Getter - private WorldPoint fountain; - - HydraPhase(int attacksPerSwitch, int deathAnim1, int deathAnim2, int specProjectileId, int specAnimationId, int specImage, WorldPoint fountain) - { - this.attacksPerSwitch = attacksPerSwitch; - this.deathAnim1 = deathAnim1; - this.deathAnim2 = deathAnim2; - this.specProjectileId = specProjectileId; - this.specAnimationId = specAnimationId; - this.specImage = specImage; - this.fountain = fountain; - } +/* + * Copyright (c) 2019, Lucas + * 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.alchemicalhydra; + +import lombok.Getter; +import net.runelite.api.AnimationID; +import net.runelite.api.ProjectileID; +import net.runelite.api.SpriteID; +import net.runelite.api.coords.WorldPoint; + +enum HydraPhase +{ // Sorry for the autism + ONE(3, AnimationID.HYDRA_1_1, AnimationID.HYDRA_1_2, ProjectileID.HYDRA_POISON, 0, SpriteID.BIG_ASS_GUTHIX_SPELL, new WorldPoint(1371, 10263, 0)), + TWO(3, AnimationID.HYDRA_2_1, AnimationID.HYDRA_2_2, 0, AnimationID.HYDRA_LIGHTNING, SpriteID.BIG_SPEC_TRANSFER, new WorldPoint(1371, 10272, 0)), + THREE(3, AnimationID.HYDRA_3_1, AnimationID.HYDRA_3_2, 0, AnimationID.HYDRA_FIRE, SpriteID.BIG_SUPERHEAT, new WorldPoint(1362, 10272, 0)), + FOUR(1, AnimationID.HYDRA_4_1, AnimationID.HYDRA_4_2, ProjectileID.HYDRA_POISON, 0, SpriteID.BIG_ASS_GUTHIX_SPELL, null); + + @Getter + private final int attacksPerSwitch; + + @Getter + private final int deathAnim1; + + @Getter + private final int deathAnim2; + + @Getter + private final int specProjectileId; + + @Getter + private final int specAnimationId; + + @Getter + private final int specImage; + + @Getter + private WorldPoint fountain; + + HydraPhase(int attacksPerSwitch, int deathAnim1, int deathAnim2, int specProjectileId, int specAnimationId, int specImage, WorldPoint fountain) + { + this.attacksPerSwitch = attacksPerSwitch; + this.deathAnim1 = deathAnim1; + this.deathAnim2 = deathAnim2; + this.specProjectileId = specProjectileId; + this.specAnimationId = specAnimationId; + this.specImage = specImage; + this.fountain = fountain; + } } \ No newline at end of file diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/alchemicalhydra/HydraPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/alchemicalhydra/HydraPlugin.java index 13026e660c..940c34c76f 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/alchemicalhydra/HydraPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/alchemicalhydra/HydraPlugin.java @@ -117,9 +117,9 @@ public class HydraPlugin extends Plugin { if (hydra != null) - { - removeOverlays(); - hydra = null; + { + removeOverlays(); + hydra = null; } return; } @@ -305,8 +305,8 @@ public class HydraPlugin extends Plugin } else { - hydra.setNextSwitch(hydra.getNextSwitch() - 1); - hydra.setLastAttack(hydra.getNextAttack()); + hydra.setNextSwitch(hydra.getNextSwitch() - 1); + hydra.setLastAttack(hydra.getNextAttack()); } hydra.setAttackCount(hydra.getAttackCount() + 1); diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/alchemicalhydra/HydraPoisonOverlay.java b/runelite-client/src/main/java/net/runelite/client/plugins/alchemicalhydra/HydraPoisonOverlay.java index 2d8b9b843b..f4cd114acc 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/alchemicalhydra/HydraPoisonOverlay.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/alchemicalhydra/HydraPoisonOverlay.java @@ -1,145 +1,145 @@ -/* - * Copyright (c) 2019, Lucas - * 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.alchemicalhydra; - -import java.awt.Color; -import java.awt.Dimension; -import java.awt.Graphics2D; -import java.awt.Polygon; -import java.awt.geom.Area; -import java.util.Collection; -import java.util.Map; -import javax.inject.Inject; -import javax.inject.Singleton; -import net.runelite.api.Client; -import static net.runelite.api.Perspective.getCanvasTileAreaPoly; -import net.runelite.api.Projectile; -import net.runelite.api.coords.LocalPoint; -import net.runelite.api.coords.WorldArea; -import net.runelite.api.coords.WorldPoint; -import net.runelite.client.ui.overlay.Overlay; -import net.runelite.client.ui.overlay.OverlayLayer; -import net.runelite.client.ui.overlay.OverlayPosition; - -@Singleton -class HydraPoisonOverlay extends Overlay -{ - private final HydraPlugin plugin; - private final Client client; - - @Inject - public HydraPoisonOverlay(Client client, HydraPlugin plugin) - { - setPosition(OverlayPosition.DYNAMIC); - setLayer(OverlayLayer.UNDER_WIDGETS); - this.plugin = plugin; - this.client = client; - } - - @Override - public Dimension render(Graphics2D graphics) - { - Hydra hydra = plugin.getHydra(); - final Map poisonProjectiles = plugin.getPoisonProjectiles(); - - if (!poisonProjectiles.isEmpty()) - { - drawPoisonArea(graphics, poisonProjectiles); - } - - if (hydra.getPhase().getFountain() != null) - { - drawFountain(graphics, hydra); - } - - return null; - } - - private void drawPoisonArea(Graphics2D graphics, Map poisonProjectiles) - { - Area poisonTiles = new Area(); - - for (Map.Entry entry : poisonProjectiles.entrySet()) - { - if (entry.getValue().getEndCycle() < client.getGameCycle()) - { - continue; - } - - LocalPoint point = entry.getKey(); - Polygon poly = getCanvasTileAreaPoly(client, point, 3); - - if (poly != null) - { - poisonTiles.add(new Area(poly)); - } - } - - graphics.setPaintMode(); - graphics.setColor(new Color(255, 0, 0, 100)); - graphics.draw(poisonTiles); - graphics.setColor(new Color(255, 0, 0, 50)); - graphics.fill(poisonTiles); - } - - private void drawFountain(Graphics2D graphics, Hydra hydra) - { - Collection fountainWorldPoint = WorldPoint.toLocalInstance(client, hydra.getPhase().getFountain()); // thanks - if (fountainWorldPoint.size() > 1) // for - { - return; - } - - WorldPoint wp = null; - for (WorldPoint p : fountainWorldPoint) // this - { - wp = p; - } - - LocalPoint fountainPoint = wp == null ? null : LocalPoint.fromWorld(client, wp); // trash - - if (fountainPoint == null || hydra.isWeakened()) // I - { - return; - } - - final Polygon poly = getCanvasTileAreaPoly(client, fountainPoint, 3); // don't - - if (poly == null) - { - return; - } - - Color color = new Color(255, 0, 0, 100); // like - - if (hydra.getNpc().getWorldArea().intersectsWith(new WorldArea(wp, 1, 1))) // coords - { // WHICH FUCKING RETARD DID X, Y, dX, dY, Z???? IT'S XYZdXdY REEEEEEEEEE - color = new Color(0, 255, 0, 100); - } - - graphics.setColor(color); - graphics.draw(poly); - } +/* + * Copyright (c) 2019, Lucas + * 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.alchemicalhydra; + +import java.awt.Color; +import java.awt.Dimension; +import java.awt.Graphics2D; +import java.awt.Polygon; +import java.awt.geom.Area; +import java.util.Collection; +import java.util.Map; +import javax.inject.Inject; +import javax.inject.Singleton; +import net.runelite.api.Client; +import static net.runelite.api.Perspective.getCanvasTileAreaPoly; +import net.runelite.api.Projectile; +import net.runelite.api.coords.LocalPoint; +import net.runelite.api.coords.WorldArea; +import net.runelite.api.coords.WorldPoint; +import net.runelite.client.ui.overlay.Overlay; +import net.runelite.client.ui.overlay.OverlayLayer; +import net.runelite.client.ui.overlay.OverlayPosition; + +@Singleton +class HydraPoisonOverlay extends Overlay +{ + private final HydraPlugin plugin; + private final Client client; + + @Inject + public HydraPoisonOverlay(Client client, HydraPlugin plugin) + { + setPosition(OverlayPosition.DYNAMIC); + setLayer(OverlayLayer.UNDER_WIDGETS); + this.plugin = plugin; + this.client = client; + } + + @Override + public Dimension render(Graphics2D graphics) + { + Hydra hydra = plugin.getHydra(); + final Map poisonProjectiles = plugin.getPoisonProjectiles(); + + if (!poisonProjectiles.isEmpty()) + { + drawPoisonArea(graphics, poisonProjectiles); + } + + if (hydra.getPhase().getFountain() != null) + { + drawFountain(graphics, hydra); + } + + return null; + } + + private void drawPoisonArea(Graphics2D graphics, Map poisonProjectiles) + { + Area poisonTiles = new Area(); + + for (Map.Entry entry : poisonProjectiles.entrySet()) + { + if (entry.getValue().getEndCycle() < client.getGameCycle()) + { + continue; + } + + LocalPoint point = entry.getKey(); + Polygon poly = getCanvasTileAreaPoly(client, point, 3); + + if (poly != null) + { + poisonTiles.add(new Area(poly)); + } + } + + graphics.setPaintMode(); + graphics.setColor(new Color(255, 0, 0, 100)); + graphics.draw(poisonTiles); + graphics.setColor(new Color(255, 0, 0, 50)); + graphics.fill(poisonTiles); + } + + private void drawFountain(Graphics2D graphics, Hydra hydra) + { + Collection fountainWorldPoint = WorldPoint.toLocalInstance(client, hydra.getPhase().getFountain()); // thanks + if (fountainWorldPoint.size() > 1) // for + { + return; + } + + WorldPoint wp = null; + for (WorldPoint p : fountainWorldPoint) // this + { + wp = p; + } + + LocalPoint fountainPoint = wp == null ? null : LocalPoint.fromWorld(client, wp); // trash + + if (fountainPoint == null || hydra.isWeakened()) // I + { + return; + } + + final Polygon poly = getCanvasTileAreaPoly(client, fountainPoint, 3); // don't + + if (poly == null) + { + return; + } + + Color color = new Color(255, 0, 0, 100); // like + + if (hydra.getNpc().getWorldArea().intersectsWith(new WorldArea(wp, 1, 1))) // coords + { // WHICH FUCKING RETARD DID X, Y, dX, dY, Z???? IT'S XYZdXdY REEEEEEEEEE + color = new Color(0, 255, 0, 100); + } + + graphics.setColor(color); + graphics.draw(poly); + } } \ No newline at end of file diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/antidrag/AntiDragConfig.java b/runelite-client/src/main/java/net/runelite/client/plugins/antidrag/AntiDragConfig.java index 58c959eb52..bde5839c8d 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/antidrag/AntiDragConfig.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/antidrag/AntiDragConfig.java @@ -26,8 +26,8 @@ package net.runelite.client.plugins.antidrag; import java.awt.Color; import java.awt.event.KeyEvent; -import net.runelite.client.config.Alpha; import net.runelite.api.Constants; +import net.runelite.client.config.Alpha; import net.runelite.client.config.Config; import net.runelite.client.config.ConfigGroup; import net.runelite.client.config.ConfigItem; diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/aoewarnings/AoeProjectileInfo.java b/runelite-client/src/main/java/net/runelite/client/plugins/aoewarnings/AoeProjectileInfo.java index 1fb9a72b29..35d2072a19 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/aoewarnings/AoeProjectileInfo.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/aoewarnings/AoeProjectileInfo.java @@ -32,7 +32,6 @@ import java.util.Map; import net.runelite.api.ProjectileID; - public enum AoeProjectileInfo { LIZARDMAN_SHAMAN_AOE(ProjectileID.LIZARDMAN_SHAMAN_AOE, 5), @@ -108,10 +107,10 @@ public enum AoeProjectileInfo ADDY_DRAG_POISON(ProjectileID.ADDY_DRAG_POISON, 1), /** - * the Breath of the Drake - */ + * the Breath of the Drake + */ DRAKE_BREATH(ProjectileID.DRAKE_BREATH, 1), - + /** * Cerbs fire */ diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/aoewarnings/AoeWarningOverlay.java b/runelite-client/src/main/java/net/runelite/client/plugins/aoewarnings/AoeWarningOverlay.java index 6b6bed9569..c063c3c92e 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/aoewarnings/AoeWarningOverlay.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/aoewarnings/AoeWarningOverlay.java @@ -71,7 +71,7 @@ public class AoeWarningOverlay extends Overlay { for (WorldPoint point : plugin.getLightningTrail()) { - drawTile(graphics, point, new Color(0,150,200), 2, 150, 50); + drawTile(graphics, point, new Color(0, 150, 200), 2, 150, 50); } for (WorldPoint point : plugin.getAcidTrail()) { @@ -84,7 +84,7 @@ public class AoeWarningOverlay extends Overlay Instant now = Instant.now(); Map projectiles = plugin.getProjectiles(); - for (Iterator it = projectiles.values().iterator(); it.hasNext();) + for (Iterator it = projectiles.values().iterator(); it.hasNext(); ) { AoeProjectile aoeProjectile = it.next(); @@ -145,18 +145,22 @@ public class AoeWarningOverlay extends Overlay return null; } - private void drawTile(Graphics2D graphics, WorldPoint point, Color color, int strokeWidth, int outlineAlpha, int fillAlpha) { + private void drawTile(Graphics2D graphics, WorldPoint point, Color color, int strokeWidth, int outlineAlpha, int fillAlpha) + { WorldPoint playerLocation = client.getLocalPlayer().getWorldLocation(); - if (point.distanceTo(playerLocation) >= 32) { + if (point.distanceTo(playerLocation) >= 32) + { return; } LocalPoint lp = LocalPoint.fromWorld(client, point); - if (lp == null) { + if (lp == null) + { return; } Polygon poly = Perspective.getCanvasTilePoly(client, lp); - if (poly == null) { + if (poly == null) + { return; } //OverlayUtil.renderPolygon(graphics, poly, color); diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/aoewarnings/AoeWarningPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/aoewarnings/AoeWarningPlugin.java index 53c5a36b6c..b380dc3a55 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/aoewarnings/AoeWarningPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/aoewarnings/AoeWarningPlugin.java @@ -301,8 +301,8 @@ public class AoeWarningPlugin extends Plugin return config.isXarpusEnabled(); case ADDY_DRAG_POISON: return config.addyDrags(); - case DRAKE_BREATH: - return config.isDrakeEnabled(); + case DRAKE_BREATH: + return config.isDrakeEnabled(); case CERB_FIRE: return config.isCerbFireEnabled(); } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/aoewarnings/BombOverlay.java b/runelite-client/src/main/java/net/runelite/client/plugins/aoewarnings/BombOverlay.java index c117ba5853..b538b3df25 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/aoewarnings/BombOverlay.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/aoewarnings/BombOverlay.java @@ -73,7 +73,7 @@ public class BombOverlay extends Overlay //Utilized from the npc highlight code for formatting text being displayed on the client canvas. private static final NumberFormat TIME_LEFT_FORMATTER = - DecimalFormat.getInstance(Locale.US); + DecimalFormat.getInstance(Locale.US); static { @@ -157,22 +157,22 @@ public class BombOverlay extends Overlay Instant now = Instant.now(); double timeLeft = ((BOMB_DETONATE_TIME - (client.getTickCount() - - bomb.getTickStarted())) * ESTIMATED_TICK_LENGTH) - - (now.toEpochMilli() - bomb.getLastClockUpdate().toEpochMilli()) / 1000.0; - //divided by 1000.00 because of milliseconds :) + bomb.getTickStarted())) * ESTIMATED_TICK_LENGTH) - + (now.toEpochMilli() - bomb.getLastClockUpdate().toEpochMilli()) / 1000.0; + //divided by 1000.00 because of milliseconds :) timeLeft = Math.max(0.0, timeLeft); String bombTimerString = TIME_LEFT_FORMATTER.format(timeLeft); int textWidth = graphics.getFontMetrics().stringWidth(bombTimerString); int textHeight = graphics.getFontMetrics().getAscent(); Point canvasPoint = Perspective.localToCanvas(client, localLoc.getX(), - localLoc.getY(), bomb.getWorldLocation().getPlane()); + localLoc.getY(), bomb.getWorldLocation().getPlane()); if (canvasPoint != null) { Point canvasCenterPoint = new Point( - canvasPoint.getX() - textWidth / 2, - canvasPoint.getY() + textHeight / 2); + canvasPoint.getX() - textWidth / 2, + canvasPoint.getY() + textHeight / 2); OverlayUtil.renderTextLocation(graphics, canvasCenterPoint, bombTimerString, color_code); } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/banktags/BankTagsConfig.java b/runelite-client/src/main/java/net/runelite/client/plugins/banktags/BankTagsConfig.java index c1e7f9ffde..ce3320b7e0 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/banktags/BankTagsConfig.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/banktags/BankTagsConfig.java @@ -1,113 +1,113 @@ -/* - * Copyright (c) 2018, Ron Young - * 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.banktags; - -import net.runelite.client.config.Config; -import net.runelite.client.config.ConfigGroup; -import net.runelite.client.config.ConfigItem; - -@ConfigGroup("banktags") -public interface BankTagsConfig extends Config -{ - @ConfigItem( - keyName = "useTabs", - name = "Use Tag Tabs", - description = "Enable the ability to add tabs to your bank which allow fast access to tags.", - position = 1 - ) - default boolean tabs() - { - return true; - } - - @ConfigItem( - keyName = "rememberTab", - name = "Remember last Tag Tab", - description = "Enable the ability to remember last Tag Tab when closing/opening the bank.", - position = 2 - ) - default boolean rememberTab() - { - return true; - } - - @ConfigItem( - keyName = "removeSeparators", - name = "Remove tab separators in Tag Tabs", - description = "Removes tab separators and corrects item layouts in Tag Tabs to mimic a regular tab", - position = 3 - ) - default boolean removeSeparators() - { - return true; - } - - @ConfigItem( - keyName = "hidePlaceholders", - name = "Hide placeholders", - description = "Hide placeholders in tag tabs or tag search.", - position = 4 - ) - default boolean hidePlaceholders() - { - return false; - } - - @ConfigItem( - keyName = "position", - name = "", - description = "", - hidden = true - ) - default int position() - { - return 0; - } - - @ConfigItem( - keyName = "position", - name = "", - description = "" - ) - void position(int idx); - - @ConfigItem( - keyName = "tab", - name = "", - description = "", - hidden = true - ) - default String tab() - { - return ""; - } - - @ConfigItem( - keyName = "tab", - name = "", - description = "" - ) - void tab(String tab); -} +/* + * Copyright (c) 2018, Ron Young + * 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.banktags; + +import net.runelite.client.config.Config; +import net.runelite.client.config.ConfigGroup; +import net.runelite.client.config.ConfigItem; + +@ConfigGroup("banktags") +public interface BankTagsConfig extends Config +{ + @ConfigItem( + keyName = "useTabs", + name = "Use Tag Tabs", + description = "Enable the ability to add tabs to your bank which allow fast access to tags.", + position = 1 + ) + default boolean tabs() + { + return true; + } + + @ConfigItem( + keyName = "rememberTab", + name = "Remember last Tag Tab", + description = "Enable the ability to remember last Tag Tab when closing/opening the bank.", + position = 2 + ) + default boolean rememberTab() + { + return true; + } + + @ConfigItem( + keyName = "removeSeparators", + name = "Remove tab separators in Tag Tabs", + description = "Removes tab separators and corrects item layouts in Tag Tabs to mimic a regular tab", + position = 3 + ) + default boolean removeSeparators() + { + return true; + } + + @ConfigItem( + keyName = "hidePlaceholders", + name = "Hide placeholders", + description = "Hide placeholders in tag tabs or tag search.", + position = 4 + ) + default boolean hidePlaceholders() + { + return false; + } + + @ConfigItem( + keyName = "position", + name = "", + description = "", + hidden = true + ) + default int position() + { + return 0; + } + + @ConfigItem( + keyName = "position", + name = "", + description = "" + ) + void position(int idx); + + @ConfigItem( + keyName = "tab", + name = "", + description = "", + hidden = true + ) + default String tab() + { + return ""; + } + + @ConfigItem( + keyName = "tab", + name = "", + description = "" + ) + void tab(String tab); +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/barbarianassault/BarbarianAssaultPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/barbarianassault/BarbarianAssaultPlugin.java index 4d4c1addb2..c5ecb74d6e 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/barbarianassault/BarbarianAssaultPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/barbarianassault/BarbarianAssaultPlugin.java @@ -24,7 +24,6 @@ */ package net.runelite.client.plugins.barbarianassault; -import com.google.common.collect.ImmutableList; import com.google.inject.Provides; import java.awt.Color; import java.awt.Font; diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/barbarianassault/HealerTeam.java b/runelite-client/src/main/java/net/runelite/client/plugins/barbarianassault/HealerTeam.java index 5521d620f7..1d8994f2ed 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/barbarianassault/HealerTeam.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/barbarianassault/HealerTeam.java @@ -1,44 +1,44 @@ -/* - * Copyright (c) 2018, whartd - * 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.barbarianassault; - -import lombok.AllArgsConstructor; -import lombok.Getter; -import net.runelite.api.Point; -import net.runelite.api.widgets.WidgetInfo; - -@Getter -@AllArgsConstructor -enum HealerTeam -{ - TEAMMATE1(WidgetInfo.BA_HEAL_TEAMMATE1, new Point(28, 2), 115), - TEAMMATE2(WidgetInfo.BA_HEAL_TEAMMATE2, new Point(26, 2), 115), - TEAMMATE3(WidgetInfo.BA_HEAL_TEAMMATE3, new Point(26, 2), 115), - TEAMMATE4(WidgetInfo.BA_HEAL_TEAMMATE4, new Point(25, 2), 115); - - private WidgetInfo teammate; - private Point offset; - private int width; -} +/* + * Copyright (c) 2018, whartd + * 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.barbarianassault; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import net.runelite.api.Point; +import net.runelite.api.widgets.WidgetInfo; + +@Getter +@AllArgsConstructor +enum HealerTeam +{ + TEAMMATE1(WidgetInfo.BA_HEAL_TEAMMATE1, new Point(28, 2), 115), + TEAMMATE2(WidgetInfo.BA_HEAL_TEAMMATE2, new Point(26, 2), 115), + TEAMMATE3(WidgetInfo.BA_HEAL_TEAMMATE3, new Point(26, 2), 115), + TEAMMATE4(WidgetInfo.BA_HEAL_TEAMMATE4, new Point(25, 2), 115); + + private WidgetInfo teammate; + private Point offset; + private int width; +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/barrows/BarrowsBrotherSlainOverlay.java b/runelite-client/src/main/java/net/runelite/client/plugins/barrows/BarrowsBrotherSlainOverlay.java index 678ed41834..d851b406fa 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/barrows/BarrowsBrotherSlainOverlay.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/barrows/BarrowsBrotherSlainOverlay.java @@ -1,99 +1,99 @@ -/* - * Copyright (c) 2018, Seth - * 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.barrows; - -import java.awt.Color; -import java.awt.Dimension; -import java.awt.Graphics2D; -import javax.inject.Inject; -import net.runelite.api.Client; -import static net.runelite.api.MenuAction.RUNELITE_OVERLAY_CONFIG; -import net.runelite.api.Varbits; -import net.runelite.api.widgets.Widget; -import net.runelite.api.widgets.WidgetInfo; -import net.runelite.client.ui.overlay.Overlay; -import static net.runelite.client.ui.overlay.OverlayManager.OPTION_CONFIGURE; -import net.runelite.client.ui.overlay.OverlayMenuEntry; -import net.runelite.client.ui.overlay.OverlayPosition; -import net.runelite.client.ui.overlay.OverlayPriority; -import net.runelite.client.ui.overlay.components.LineComponent; -import net.runelite.client.ui.overlay.components.PanelComponent; - -public class BarrowsBrotherSlainOverlay extends Overlay -{ - private final Client client; - private final PanelComponent panelComponent = new PanelComponent(); - - @Inject - private BarrowsBrotherSlainOverlay(BarrowsPlugin plugin, Client client) - { - super(plugin); - setPosition(OverlayPosition.TOP_LEFT); - setPriority(OverlayPriority.LOW); - this.client = client; - getMenuEntries().add(new OverlayMenuEntry(RUNELITE_OVERLAY_CONFIG, OPTION_CONFIGURE, "Barrows overlay")); - } - - @Override - public Dimension render(Graphics2D graphics) - { - // Do not display overlay if potential is null/hidden - final Widget potential = client.getWidget(WidgetInfo.BARROWS_POTENTIAL); - if (potential == null || potential.isHidden()) - { - return null; - } - - // Hide original overlay - final Widget barrowsBrothers = client.getWidget(WidgetInfo.BARROWS_BROTHERS); - if (barrowsBrothers != null) - { - barrowsBrothers.setHidden(true); - potential.setHidden(true); - } - - panelComponent.getChildren().clear(); - - for (BarrowsBrothers brother : BarrowsBrothers.values()) - { - final boolean brotherSlain = client.getVar(brother.getKilledVarbit()) > 0; - String slain = brotherSlain ? "\u2713" : "\u2717"; - panelComponent.getChildren().add(LineComponent.builder() - .left(brother.getName()) - .right(slain) - .rightColor(brotherSlain ? Color.GREEN : Color.RED) - .build()); - } - - float rewardPercent = client.getVar(Varbits.BARROWS_REWARD_POTENTIAL) / 10.0f; - panelComponent.getChildren().add(LineComponent.builder() - .left("Potential") - .right(rewardPercent != 0 ? rewardPercent + "%" : "0%") - .rightColor(rewardPercent >= 73.0f && rewardPercent <= 88.0f ? Color.GREEN : rewardPercent < 65.6f ? Color.WHITE : Color.YELLOW) - .build()); - - return panelComponent.render(graphics); - } -} +/* + * Copyright (c) 2018, Seth + * 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.barrows; + +import java.awt.Color; +import java.awt.Dimension; +import java.awt.Graphics2D; +import javax.inject.Inject; +import net.runelite.api.Client; +import static net.runelite.api.MenuAction.RUNELITE_OVERLAY_CONFIG; +import net.runelite.api.Varbits; +import net.runelite.api.widgets.Widget; +import net.runelite.api.widgets.WidgetInfo; +import net.runelite.client.ui.overlay.Overlay; +import static net.runelite.client.ui.overlay.OverlayManager.OPTION_CONFIGURE; +import net.runelite.client.ui.overlay.OverlayMenuEntry; +import net.runelite.client.ui.overlay.OverlayPosition; +import net.runelite.client.ui.overlay.OverlayPriority; +import net.runelite.client.ui.overlay.components.LineComponent; +import net.runelite.client.ui.overlay.components.PanelComponent; + +public class BarrowsBrotherSlainOverlay extends Overlay +{ + private final Client client; + private final PanelComponent panelComponent = new PanelComponent(); + + @Inject + private BarrowsBrotherSlainOverlay(BarrowsPlugin plugin, Client client) + { + super(plugin); + setPosition(OverlayPosition.TOP_LEFT); + setPriority(OverlayPriority.LOW); + this.client = client; + getMenuEntries().add(new OverlayMenuEntry(RUNELITE_OVERLAY_CONFIG, OPTION_CONFIGURE, "Barrows overlay")); + } + + @Override + public Dimension render(Graphics2D graphics) + { + // Do not display overlay if potential is null/hidden + final Widget potential = client.getWidget(WidgetInfo.BARROWS_POTENTIAL); + if (potential == null || potential.isHidden()) + { + return null; + } + + // Hide original overlay + final Widget barrowsBrothers = client.getWidget(WidgetInfo.BARROWS_BROTHERS); + if (barrowsBrothers != null) + { + barrowsBrothers.setHidden(true); + potential.setHidden(true); + } + + panelComponent.getChildren().clear(); + + for (BarrowsBrothers brother : BarrowsBrothers.values()) + { + final boolean brotherSlain = client.getVar(brother.getKilledVarbit()) > 0; + String slain = brotherSlain ? "\u2713" : "\u2717"; + panelComponent.getChildren().add(LineComponent.builder() + .left(brother.getName()) + .right(slain) + .rightColor(brotherSlain ? Color.GREEN : Color.RED) + .build()); + } + + float rewardPercent = client.getVar(Varbits.BARROWS_REWARD_POTENTIAL) / 10.0f; + panelComponent.getChildren().add(LineComponent.builder() + .left("Potential") + .right(rewardPercent != 0 ? rewardPercent + "%" : "0%") + .rightColor(rewardPercent >= 73.0f && rewardPercent <= 88.0f ? Color.GREEN : rewardPercent < 65.6f ? Color.WHITE : Color.YELLOW) + .build()); + + return panelComponent.render(graphics); + } +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/barrows/BarrowsOverlay.java b/runelite-client/src/main/java/net/runelite/client/plugins/barrows/BarrowsOverlay.java index 4ecdebccf3..e3d5ca2619 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/barrows/BarrowsOverlay.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/barrows/BarrowsOverlay.java @@ -1,243 +1,244 @@ -/* - * Copyright (c) 2018, Seth - * 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.barrows; - -import java.awt.Color; -import java.awt.Dimension; -import java.awt.Graphics2D; -import java.awt.Rectangle; -import java.util.List; -import javax.inject.Inject; -import net.runelite.api.Client; -import net.runelite.api.GameObject; -import net.runelite.api.NPC; -import net.runelite.api.NPCComposition; -import net.runelite.api.ObjectComposition; -import net.runelite.api.Perspective; -import net.runelite.api.Player; -import net.runelite.api.WallObject; -import net.runelite.api.coords.LocalPoint; -import net.runelite.api.widgets.Widget; -import net.runelite.client.ui.overlay.Overlay; -import net.runelite.client.ui.overlay.OverlayLayer; -import net.runelite.client.ui.overlay.OverlayPosition; - -class BarrowsOverlay extends Overlay -{ - private static final int MAX_DISTANCE = 2350; - - private final Client client; - private final BarrowsPlugin plugin; - private final BarrowsConfig config; - - @Inject - private BarrowsOverlay(Client client, BarrowsPlugin plugin, BarrowsConfig config) - { - setPosition(OverlayPosition.DYNAMIC); - setLayer(OverlayLayer.ABOVE_WIDGETS); - this.client = client; - this.plugin = plugin; - this.config = config; - } - - @Override - public Dimension render(Graphics2D graphics) - { - Player local = client.getLocalPlayer(); - final Color npcColor = getMinimapDotColor(1); - final Color playerColor = getMinimapDotColor(2); - Widget puzzleAnswer = plugin.getPuzzleAnswer(); - - // tunnels are only on z=0 - if (!plugin.getWalls().isEmpty() && client.getPlane() == 0 && config.showMinimap()) - { - // NPC dots - graphics.setColor(npcColor); - final List npcs = client.getNpcs(); - for (NPC npc : npcs) - { - final NPCComposition composition = npc.getComposition(); - - if (composition != null && !composition.isMinimapVisible()) - { - continue; - } - - net.runelite.api.Point minimapLocation = npc.getMinimapLocation(); - if (minimapLocation != null) - { - graphics.fillOval(minimapLocation.getX(), minimapLocation.getY(), 4, 4); - } - } - - // Player dots - graphics.setColor(playerColor); - final List 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) - { - graphics.fillOval(minimapLocation.getX(), minimapLocation.getY(), 4, 4); - } - } - - // Render barrows walls/doors - renderObjects(graphics, local); - - // Local player square - graphics.setColor(playerColor); - graphics.fillRect(local.getMinimapLocation().getX(), local.getMinimapLocation().getY(), 3, 3); - } - else if (config.showBrotherLoc()) - { - renderBarrowsBrothers(graphics); - } - - if (puzzleAnswer != null && config.showPuzzleAnswer() && !puzzleAnswer.isHidden()) - { - Rectangle answerRect = puzzleAnswer.getBounds(); - graphics.setColor(Color.GREEN); - graphics.draw(answerRect); - } - - return null; - } - - private void renderObjects(Graphics2D graphics, Player localPlayer) - { - LocalPoint localLocation = localPlayer.getLocalLocation(); - for (WallObject wall : plugin.getWalls()) - { - LocalPoint location = wall.getLocalLocation(); - if (localLocation.distanceTo(location) <= MAX_DISTANCE) - { - renderWalls(graphics, wall); - } - } - - for (GameObject ladder : plugin.getLadders()) - { - LocalPoint location = ladder.getLocalLocation(); - if (localLocation.distanceTo(location) <= MAX_DISTANCE) - { - renderLadders(graphics, ladder); - } - } - } - - private void renderWalls(Graphics2D graphics, WallObject wall) - { - net.runelite.api.Point minimapLocation = wall.getMinimapLocation(); - - if (minimapLocation == null) - { - return; - } - - ObjectComposition objectComp = client.getObjectDefinition(wall.getId()); - ObjectComposition impostor = objectComp.getImpostorIds() != null ? objectComp.getImpostor() : null; - - if (impostor != null && impostor.getActions()[0] != null) - { - graphics.setColor(Color.green); - } - else - { - graphics.setColor(Color.gray); - } - - graphics.fillRect(minimapLocation.getX(), minimapLocation.getY(), 3, 3); - } - - /** - * Get minimap dot color from client - * @param typeIndex index of minimap dot type (1 npcs, 2 players) - * @return color - */ - private Color getMinimapDotColor(int typeIndex) - { - final int pixel = client.getMapDots()[typeIndex].getPixels()[1]; - return new Color(pixel); - } - - private void renderLadders(Graphics2D graphics, GameObject ladder) - { - net.runelite.api.Point minimapLocation = ladder.getMinimapLocation(); - - if (minimapLocation == null) - { - return; - } - - ObjectComposition objectComp = client.getObjectDefinition(ladder.getId()); - - if (objectComp.getImpostorIds() != null && objectComp.getImpostor() != null) - { - graphics.setColor(Color.orange); - graphics.fillRect(minimapLocation.getX(), minimapLocation.getY(), 6, 6); - } - } - - private void renderBarrowsBrothers(Graphics2D graphics) - { - for (BarrowsBrothers brother : BarrowsBrothers.values()) - { - LocalPoint localLocation = LocalPoint.fromWorld(client, brother.getLocation()); - - if (localLocation == null) - { - continue; - } - - String brotherLetter = Character.toString(brother.getName().charAt(0)); - net.runelite.api.Point minimapText = Perspective.getCanvasTextMiniMapLocation(client, graphics, - localLocation, brotherLetter); - - if (minimapText != null) - { - graphics.setColor(Color.black); - graphics.drawString(brotherLetter, minimapText.getX() + 1, minimapText.getY() + 1); - - if (client.getVar(brother.getKilledVarbit()) > 0) - { - graphics.setColor(config.deadBrotherLocColor()); - } - else - { - graphics.setColor(config.brotherLocColor()); - } - - graphics.drawString(brotherLetter, minimapText.getX(), minimapText.getY()); - } - } - } +/* + * Copyright (c) 2018, Seth + * 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.barrows; + +import java.awt.Color; +import java.awt.Dimension; +import java.awt.Graphics2D; +import java.awt.Rectangle; +import java.util.List; +import javax.inject.Inject; +import net.runelite.api.Client; +import net.runelite.api.GameObject; +import net.runelite.api.NPC; +import net.runelite.api.NPCComposition; +import net.runelite.api.ObjectComposition; +import net.runelite.api.Perspective; +import net.runelite.api.Player; +import net.runelite.api.WallObject; +import net.runelite.api.coords.LocalPoint; +import net.runelite.api.widgets.Widget; +import net.runelite.client.ui.overlay.Overlay; +import net.runelite.client.ui.overlay.OverlayLayer; +import net.runelite.client.ui.overlay.OverlayPosition; + +class BarrowsOverlay extends Overlay +{ + private static final int MAX_DISTANCE = 2350; + + private final Client client; + private final BarrowsPlugin plugin; + private final BarrowsConfig config; + + @Inject + private BarrowsOverlay(Client client, BarrowsPlugin plugin, BarrowsConfig config) + { + setPosition(OverlayPosition.DYNAMIC); + setLayer(OverlayLayer.ABOVE_WIDGETS); + this.client = client; + this.plugin = plugin; + this.config = config; + } + + @Override + public Dimension render(Graphics2D graphics) + { + Player local = client.getLocalPlayer(); + final Color npcColor = getMinimapDotColor(1); + final Color playerColor = getMinimapDotColor(2); + Widget puzzleAnswer = plugin.getPuzzleAnswer(); + + // tunnels are only on z=0 + if (!plugin.getWalls().isEmpty() && client.getPlane() == 0 && config.showMinimap()) + { + // NPC dots + graphics.setColor(npcColor); + final List npcs = client.getNpcs(); + for (NPC npc : npcs) + { + final NPCComposition composition = npc.getComposition(); + + if (composition != null && !composition.isMinimapVisible()) + { + continue; + } + + net.runelite.api.Point minimapLocation = npc.getMinimapLocation(); + if (minimapLocation != null) + { + graphics.fillOval(minimapLocation.getX(), minimapLocation.getY(), 4, 4); + } + } + + // Player dots + graphics.setColor(playerColor); + final List 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) + { + graphics.fillOval(minimapLocation.getX(), minimapLocation.getY(), 4, 4); + } + } + + // Render barrows walls/doors + renderObjects(graphics, local); + + // Local player square + graphics.setColor(playerColor); + graphics.fillRect(local.getMinimapLocation().getX(), local.getMinimapLocation().getY(), 3, 3); + } + else if (config.showBrotherLoc()) + { + renderBarrowsBrothers(graphics); + } + + if (puzzleAnswer != null && config.showPuzzleAnswer() && !puzzleAnswer.isHidden()) + { + Rectangle answerRect = puzzleAnswer.getBounds(); + graphics.setColor(Color.GREEN); + graphics.draw(answerRect); + } + + return null; + } + + private void renderObjects(Graphics2D graphics, Player localPlayer) + { + LocalPoint localLocation = localPlayer.getLocalLocation(); + for (WallObject wall : plugin.getWalls()) + { + LocalPoint location = wall.getLocalLocation(); + if (localLocation.distanceTo(location) <= MAX_DISTANCE) + { + renderWalls(graphics, wall); + } + } + + for (GameObject ladder : plugin.getLadders()) + { + LocalPoint location = ladder.getLocalLocation(); + if (localLocation.distanceTo(location) <= MAX_DISTANCE) + { + renderLadders(graphics, ladder); + } + } + } + + private void renderWalls(Graphics2D graphics, WallObject wall) + { + net.runelite.api.Point minimapLocation = wall.getMinimapLocation(); + + if (minimapLocation == null) + { + return; + } + + ObjectComposition objectComp = client.getObjectDefinition(wall.getId()); + ObjectComposition impostor = objectComp.getImpostorIds() != null ? objectComp.getImpostor() : null; + + if (impostor != null && impostor.getActions()[0] != null) + { + graphics.setColor(Color.green); + } + else + { + graphics.setColor(Color.gray); + } + + graphics.fillRect(minimapLocation.getX(), minimapLocation.getY(), 3, 3); + } + + /** + * Get minimap dot color from client + * + * @param typeIndex index of minimap dot type (1 npcs, 2 players) + * @return color + */ + private Color getMinimapDotColor(int typeIndex) + { + final int pixel = client.getMapDots()[typeIndex].getPixels()[1]; + return new Color(pixel); + } + + private void renderLadders(Graphics2D graphics, GameObject ladder) + { + net.runelite.api.Point minimapLocation = ladder.getMinimapLocation(); + + if (minimapLocation == null) + { + return; + } + + ObjectComposition objectComp = client.getObjectDefinition(ladder.getId()); + + if (objectComp.getImpostorIds() != null && objectComp.getImpostor() != null) + { + graphics.setColor(Color.orange); + graphics.fillRect(minimapLocation.getX(), minimapLocation.getY(), 6, 6); + } + } + + private void renderBarrowsBrothers(Graphics2D graphics) + { + for (BarrowsBrothers brother : BarrowsBrothers.values()) + { + LocalPoint localLocation = LocalPoint.fromWorld(client, brother.getLocation()); + + if (localLocation == null) + { + continue; + } + + String brotherLetter = Character.toString(brother.getName().charAt(0)); + net.runelite.api.Point minimapText = Perspective.getCanvasTextMiniMapLocation(client, graphics, + localLocation, brotherLetter); + + if (minimapText != null) + { + graphics.setColor(Color.black); + graphics.drawString(brotherLetter, minimapText.getX() + 1, minimapText.getY() + 1); + + if (client.getVar(brother.getKilledVarbit()) > 0) + { + graphics.setColor(config.deadBrotherLocColor()); + } + else + { + graphics.setColor(config.brotherLocColor()); + } + + graphics.drawString(brotherLetter, minimapText.getX(), minimapText.getY()); + } + } + } } \ No newline at end of file diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/barrows/BarrowsPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/barrows/BarrowsPlugin.java index 30ecefb885..0b8de1c15b 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/barrows/BarrowsPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/barrows/BarrowsPlugin.java @@ -81,13 +81,13 @@ public class BarrowsPlugin extends Plugin { @Getter(AccessLevel.PACKAGE) private static final Set BARROWS_WALLS = Sets.newHashSet - ( - ObjectID.DOOR_20678, NullObjectID.NULL_20681, NullObjectID.NULL_20682, NullObjectID.NULL_20683, NullObjectID.NULL_20684, NullObjectID.NULL_20685, NullObjectID.NULL_20686, NullObjectID.NULL_20687, - NullObjectID.NULL_20688, NullObjectID.NULL_20689, NullObjectID.NULL_20690, NullObjectID.NULL_20691, NullObjectID.NULL_20692, NullObjectID.NULL_20693, NullObjectID.NULL_20694, NullObjectID.NULL_20695, - NullObjectID.NULL_20696, ObjectID.DOOR_20697, NullObjectID.NULL_20700, NullObjectID.NULL_20701, NullObjectID.NULL_20702, NullObjectID.NULL_20703, NullObjectID.NULL_20704, NullObjectID.NULL_20705, - NullObjectID.NULL_20706, NullObjectID.NULL_20707, NullObjectID.NULL_20708, NullObjectID.NULL_20709, NullObjectID.NULL_20710, NullObjectID.NULL_20711, NullObjectID.NULL_20712, NullObjectID.NULL_20713, - NullObjectID.NULL_20714, NullObjectID.NULL_20715, NullObjectID.NULL_20728, NullObjectID.NULL_20730 - ); + ( + ObjectID.DOOR_20678, NullObjectID.NULL_20681, NullObjectID.NULL_20682, NullObjectID.NULL_20683, NullObjectID.NULL_20684, NullObjectID.NULL_20685, NullObjectID.NULL_20686, NullObjectID.NULL_20687, + NullObjectID.NULL_20688, NullObjectID.NULL_20689, NullObjectID.NULL_20690, NullObjectID.NULL_20691, NullObjectID.NULL_20692, NullObjectID.NULL_20693, NullObjectID.NULL_20694, NullObjectID.NULL_20695, + NullObjectID.NULL_20696, ObjectID.DOOR_20697, NullObjectID.NULL_20700, NullObjectID.NULL_20701, NullObjectID.NULL_20702, NullObjectID.NULL_20703, NullObjectID.NULL_20704, NullObjectID.NULL_20705, + NullObjectID.NULL_20706, NullObjectID.NULL_20707, NullObjectID.NULL_20708, NullObjectID.NULL_20709, NullObjectID.NULL_20710, NullObjectID.NULL_20711, NullObjectID.NULL_20712, NullObjectID.NULL_20713, + NullObjectID.NULL_20714, NullObjectID.NULL_20715, NullObjectID.NULL_20728, NullObjectID.NULL_20730 + ); private static final Set BARROWS_LADDERS = Sets.newHashSet(NullObjectID.NULL_20675, NullObjectID.NULL_20676, NullObjectID.NULL_20677); private static final ImmutableList POSSIBLE_SOLUTIONS = ImmutableList.of( diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/batools/BAToolsOverlay.java b/runelite-client/src/main/java/net/runelite/client/plugins/batools/BAToolsOverlay.java index f200ae5272..c3b4b7e5b5 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/batools/BAToolsOverlay.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/batools/BAToolsOverlay.java @@ -31,8 +31,6 @@ import java.time.Duration; import java.time.Instant; import javax.inject.Inject; import lombok.extern.slf4j.Slf4j; -import net.runelite.api.Client; -import net.runelite.api.NPCComposition; import net.runelite.client.ui.overlay.Overlay; import net.runelite.client.ui.overlay.OverlayLayer; import net.runelite.client.ui.overlay.OverlayPosition; diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/batools/BAToolsPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/batools/BAToolsPlugin.java index a65e8a89fd..5f7980900b 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/batools/BAToolsPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/batools/BAToolsPlugin.java @@ -63,7 +63,6 @@ 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.ChatMessageManager; import net.runelite.client.config.ConfigManager; import net.runelite.client.eventbus.Subscribe; import net.runelite.client.game.ItemManager; @@ -371,10 +370,7 @@ public class BAToolsPlugin extends Plugin implements KeyListener @Subscribe public void onNpcDespawned(NpcDespawned event) { - if (healers.remove(event.getNpc()) != null && healers.isEmpty()) - { - healers.clear(); - } + healers.remove(event.getNpc()); } @Subscribe @@ -450,7 +446,7 @@ public class BAToolsPlugin extends Plugin implements KeyListener { remove(new String[]{"take", "light"}, target, true); } - else//remove "Light" option (and "Take" option if not defender). + else //remove "Light" option (and "Take" option if not defender). { remove("light", target, true); } @@ -466,7 +462,8 @@ public class BAToolsPlugin extends Plugin implements KeyListener List poison = Arrays.asList("poisoned tofu", "poisoned meat", "poisoned worms"); List vials = Arrays.asList("healing vial", "healing vial(1)", "healing vial(2)", "healing vial(3)", "healing vial(4)");//"healing vial(4)" if (poison.contains(item)) - {//if item is a poison item + { + //if item is a poison item int calledPoison = 0; switch (healer.getText())//choose which poison to hide the use/destroy option for { @@ -509,11 +506,13 @@ public class BAToolsPlugin extends Plugin implements KeyListener } } else if (option.equals("attack") && client.getWidget(WidgetInfo.BA_ATK_ROLE_TEXT) == null && !target.equals("queen spawn"))//if not attacker - {//remove attack option from everything but queen spawns + { + //remove attack option from everything but queen spawns remove(option, target, true); } else if ((option.equals("fix") || (option.equals("block") && target.equals("penance cave"))) && client.getWidget(WidgetInfo.BA_DEF_ROLE_TEXT) == null)//if not defender - {//the check for option requires checking target as well because defensive attack style option is also called "block". + { + //the check for option requires checking target as well because defensive attack style option is also called "block". remove(option, target, true); } else if ((option.equals("load")) && client.getWidget(WidgetInfo.BA_COLL_ROLE_TEXT) == null)//if not collector, remove hopper options @@ -632,7 +631,7 @@ public class BAToolsPlugin extends Plugin implements KeyListener if (correctEgg != null) { entries.add(correctEgg); - client.setMenuEntries(entries.toArray(new MenuEntry[entries.size()])); + client.setMenuEntries(entries.toArray(new MenuEntry[0])); } } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/batools/Calls.java b/runelite-client/src/main/java/net/runelite/client/plugins/batools/Calls.java index 581039179d..0fb721d7a2 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/batools/Calls.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/batools/Calls.java @@ -24,10 +24,10 @@ */ package net.runelite.client.plugins.batools; -import lombok.Getter; - import java.util.HashMap; import java.util.Map; +import lombok.Getter; + @Getter public enum Calls { diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/batools/CycleCounter.java b/runelite-client/src/main/java/net/runelite/client/plugins/batools/CycleCounter.java index af7dd4e57f..e6c026fe05 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/batools/CycleCounter.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/batools/CycleCounter.java @@ -24,11 +24,10 @@ */ package net.runelite.client.plugins.batools; +import java.awt.image.BufferedImage; import net.runelite.client.plugins.Plugin; import net.runelite.client.ui.overlay.infobox.Counter; -import java.awt.image.BufferedImage; - class CycleCounter extends Counter { CycleCounter(BufferedImage img, Plugin plugin, int tick) diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/batools/Healer.java b/runelite-client/src/main/java/net/runelite/client/plugins/batools/Healer.java index 45078e7772..93382e57c0 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/batools/Healer.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/batools/Healer.java @@ -27,9 +27,7 @@ package net.runelite.client.plugins.batools; import lombok.Getter; import lombok.Setter; - import net.runelite.api.NPC; -import net.runelite.api.Actor; class Healer @@ -75,7 +73,7 @@ class Healer private HealerCode getCode(int wave) { - switch(wave) + switch (wave) { case 1: return HealerCode.WAVEONE; @@ -97,7 +95,8 @@ class Healer return HealerCode.WAVENINE; case 10: return HealerCode.WAVETEN; - default: return null; + default: + return null; } } } \ No newline at end of file diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/batools/HealerCode.java b/runelite-client/src/main/java/net/runelite/client/plugins/batools/HealerCode.java index 7d5211604d..a604239045 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/batools/HealerCode.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/batools/HealerCode.java @@ -30,16 +30,16 @@ import lombok.Getter; enum HealerCode { - WAVEONE(new int[] {1,1}, new int[] {0,0}, new int[] {0,0}), - WAVETWO(new int[] {1,1,2}, new int[] {0,0,0}, new int[] {0,0,21}), - WAVETHREE(new int[] {1,6,2}, new int[] {0,0,0}, new int[] {0,0,0}), - WAVEFOUR(new int[] {2,5,2,0}, new int[] {0,0,7,10}, new int[] {0,0,0,0}), - WAVEFIVE(new int[] {2,5,2,3,0}, new int[] {0,0,0,0,7}, new int[] {0,0,21,30,0}), - WAVESIX(new int[] {3,5,2,2,0,0}, new int[] {0,0,0,2,9,10}, new int[] {12,18,21,0,0,0}), - WAVESEVEN(new int[] {3,7,1,1,0,0,0}, new int[] {2,0,1,1,2,4,10}, new int[] {0,21,0,0,30,45,0}), - WAVEEIGHT(new int[] {1,9,1,1,0,0,0}, new int[] {1,0,1,1,2,2,10}, new int[] {0,0,0,0,33,42,0}), - WAVENINE(new int[] {2,8,1,1,0,0,0,0}, new int[] {1,0,1,1,2,1,1,10}, new int[] {0,21,0,0,0,0,0,0,0}), - WAVETEN(new int[] {2,5,1,1,0,0,0}, new int[] {1,0,1,1,4,4,8}, new int[] {21,33,0,33,30,45,0}); + WAVEONE(new int[]{1, 1}, new int[]{0, 0}, new int[]{0, 0}), + WAVETWO(new int[]{1, 1, 2}, new int[]{0, 0, 0}, new int[]{0, 0, 21}), + WAVETHREE(new int[]{1, 6, 2}, new int[]{0, 0, 0}, new int[]{0, 0, 0}), + WAVEFOUR(new int[]{2, 5, 2, 0}, new int[]{0, 0, 7, 10}, new int[]{0, 0, 0, 0}), + WAVEFIVE(new int[]{2, 5, 2, 3, 0}, new int[]{0, 0, 0, 0, 7}, new int[]{0, 0, 21, 30, 0}), + WAVESIX(new int[]{3, 5, 2, 2, 0, 0}, new int[]{0, 0, 0, 2, 9, 10}, new int[]{12, 18, 21, 0, 0, 0}), + WAVESEVEN(new int[]{3, 7, 1, 1, 0, 0, 0}, new int[]{2, 0, 1, 1, 2, 4, 10}, new int[]{0, 21, 0, 0, 30, 45, 0}), + WAVEEIGHT(new int[]{1, 9, 1, 1, 0, 0, 0}, new int[]{1, 0, 1, 1, 2, 2, 10}, new int[]{0, 0, 0, 0, 33, 42, 0}), + WAVENINE(new int[]{2, 8, 1, 1, 0, 0, 0, 0}, new int[]{1, 0, 1, 1, 2, 1, 1, 10}, new int[]{0, 21, 0, 0, 0, 0, 0, 0, 0}), + WAVETEN(new int[]{2, 5, 1, 1, 0, 0, 0}, new int[]{1, 0, 1, 1, 4, 4, 8}, new int[]{21, 33, 0, 33, 30, 45, 0}); @Getter diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/blastmine/BlastMineOreCountOverlay.java b/runelite-client/src/main/java/net/runelite/client/plugins/blastmine/BlastMineOreCountOverlay.java index e7fdc8848f..8cff73bd55 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/blastmine/BlastMineOreCountOverlay.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/blastmine/BlastMineOreCountOverlay.java @@ -36,7 +36,6 @@ import net.runelite.api.widgets.Widget; import net.runelite.api.widgets.WidgetInfo; import net.runelite.client.game.ItemManager; import net.runelite.client.ui.overlay.Overlay; -import net.runelite.client.ui.overlay.OverlayPosition; import static net.runelite.client.ui.overlay.OverlayManager.OPTION_CONFIGURE; import net.runelite.client.ui.overlay.OverlayMenuEntry; import net.runelite.client.ui.overlay.OverlayPosition; diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/blastmine/BlastMinePluginConfig.java b/runelite-client/src/main/java/net/runelite/client/plugins/blastmine/BlastMinePluginConfig.java index 76848a66e2..d6a0e9ecf2 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/blastmine/BlastMinePluginConfig.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/blastmine/BlastMinePluginConfig.java @@ -1,101 +1,100 @@ -/* - * Copyright (c) 2018, Unmoon - * 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.blastmine; - -import net.runelite.client.config.Config; -import net.runelite.client.config.ConfigGroup; -import net.runelite.client.config.ConfigItem; - -import java.awt.Color; - -@ConfigGroup("blastmine") -public interface BlastMinePluginConfig extends Config -{ - @ConfigItem( - position = 0, - keyName = "showOreOverlay", - name = "Show ore overlay", - description = "Configures whether or not the ore count overlay is displayed" - ) - default boolean showOreOverlay() - { - return true; - } - - @ConfigItem( - position = 1, - keyName = "showRockIconOverlay", - name = "Show icons overlay", - description = "Configures whether or not the icon overlay is displayed" - ) - default boolean showRockIconOverlay() - { - return true; - } - - @ConfigItem( - position = 2, - keyName = "showTimerOverlay", - name = "Show timer overlay", - description = "Configures whether or not the timer overlay is displayed" - ) - default boolean showTimerOverlay() - { - return true; - } - - @ConfigItem( - position = 3, - keyName = "showWarningOverlay", - name = "Show explosion warning", - description = "Configures whether or not the explosion warning overlay is displayed" - ) - default boolean showWarningOverlay() - { - return true; - } - - @ConfigItem( - position = 4, - keyName = "hexTimerColor", - name = "Timer color", - description = "Color of timer overlay" - ) - default Color getTimerColor() - { - return new Color(217, 54, 0); - } - - @ConfigItem( - position = 5, - keyName = "hexWarningColor", - name = "Warning color", - description = "Color of warning overlay" - ) - default Color getWarningColor() - { - return new Color(217, 54, 0); - } -} +/* + * Copyright (c) 2018, Unmoon + * 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.blastmine; + +import java.awt.Color; +import net.runelite.client.config.Config; +import net.runelite.client.config.ConfigGroup; +import net.runelite.client.config.ConfigItem; + +@ConfigGroup("blastmine") +public interface BlastMinePluginConfig extends Config +{ + @ConfigItem( + position = 0, + keyName = "showOreOverlay", + name = "Show ore overlay", + description = "Configures whether or not the ore count overlay is displayed" + ) + default boolean showOreOverlay() + { + return true; + } + + @ConfigItem( + position = 1, + keyName = "showRockIconOverlay", + name = "Show icons overlay", + description = "Configures whether or not the icon overlay is displayed" + ) + default boolean showRockIconOverlay() + { + return true; + } + + @ConfigItem( + position = 2, + keyName = "showTimerOverlay", + name = "Show timer overlay", + description = "Configures whether or not the timer overlay is displayed" + ) + default boolean showTimerOverlay() + { + return true; + } + + @ConfigItem( + position = 3, + keyName = "showWarningOverlay", + name = "Show explosion warning", + description = "Configures whether or not the explosion warning overlay is displayed" + ) + default boolean showWarningOverlay() + { + return true; + } + + @ConfigItem( + position = 4, + keyName = "hexTimerColor", + name = "Timer color", + description = "Color of timer overlay" + ) + default Color getTimerColor() + { + return new Color(217, 54, 0); + } + + @ConfigItem( + position = 5, + keyName = "hexWarningColor", + name = "Warning color", + description = "Color of warning overlay" + ) + default Color getWarningColor() + { + return new Color(217, 54, 0); + } +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/boosts/BoostsPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/boosts/BoostsPlugin.java index eb255b81b9..511359206e 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/boosts/BoostsPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/boosts/BoostsPlugin.java @@ -356,7 +356,7 @@ public class BoostsPlugin extends Plugin * section it will "activate" adding an additional 15 second section * to the boost timing. If again the preserve prayer is active for that * entire section a second 15 second section will be added. - * + *

* Preserve is only required to be on for the 4th and 5th sections of the boost timer * to gain full effect (seconds 45-75). * @@ -365,8 +365,8 @@ public class BoostsPlugin extends Plugin int getChangeDownTicks() { if (lastChangeDown == -1 || - config.displayNextBuffChange() == BoostsConfig.DisplayChangeMode.NEVER || - (config.displayNextBuffChange() == BoostsConfig.DisplayChangeMode.BOOSTED && !isChangedUp)) + config.displayNextBuffChange() == BoostsConfig.DisplayChangeMode.NEVER || + (config.displayNextBuffChange() == BoostsConfig.DisplayChangeMode.BOOSTED && !isChangedUp)) { return -1; } @@ -393,8 +393,8 @@ public class BoostsPlugin extends Plugin int getChangeUpTicks() { if (lastChangeUp == -1 || - config.displayNextDebuffChange() == BoostsConfig.DisplayChangeMode.NEVER || - (config.displayNextDebuffChange() == BoostsConfig.DisplayChangeMode.BOOSTED && !isChangedDown)) + config.displayNextDebuffChange() == BoostsConfig.DisplayChangeMode.NEVER || + (config.displayNextDebuffChange() == BoostsConfig.DisplayChangeMode.BOOSTED && !isChangedDown)) { return -1; } @@ -406,12 +406,13 @@ public class BoostsPlugin extends Plugin /** * Converts tick-based time to accurate second time + * * @param time tick-based time * @return second-based time */ int getChangeTime(final int time) { final long diff = System.currentTimeMillis() - lastTickMillis; - return time != -1 ? (int)((time * Constants.GAME_TICK_LENGTH - diff) / 1000d) : time; + return time != -1 ? (int) ((time * Constants.GAME_TICK_LENGTH - diff) / 1000d) : time; } } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/bosstimer/Boss.java b/runelite-client/src/main/java/net/runelite/client/plugins/bosstimer/Boss.java index 47752f415b..f315956a1b 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/bosstimer/Boss.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/bosstimer/Boss.java @@ -77,7 +77,7 @@ enum Boss bosses = builder.build(); } - private Boss(int id, long period, ChronoUnit unit, int itemSpriteId) + Boss(int id, long period, ChronoUnit unit, int itemSpriteId) { this.id = id; this.spawnTime = Duration.of(period, unit); diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/cannon/CannonOverlay.java b/runelite-client/src/main/java/net/runelite/client/plugins/cannon/CannonOverlay.java index ebee009d3b..591e55908b 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/cannon/CannonOverlay.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/cannon/CannonOverlay.java @@ -1,141 +1,142 @@ -/* - * Copyright (c) 2016-2018, Seth - * 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.cannon; - -import java.awt.Color; -import java.awt.Dimension; -import java.awt.Graphics2D; -import java.awt.Polygon; -import javax.inject.Inject; -import net.runelite.api.Client; -import net.runelite.api.Perspective; -import static net.runelite.api.Perspective.LOCAL_TILE_SIZE; -import net.runelite.api.Point; -import net.runelite.api.coords.LocalPoint; -import net.runelite.client.ui.overlay.Overlay; -import net.runelite.client.ui.overlay.OverlayPosition; -import net.runelite.client.ui.overlay.OverlayPriority; -import net.runelite.client.ui.overlay.OverlayUtil; -import net.runelite.client.ui.overlay.components.TextComponent; - -class CannonOverlay extends Overlay -{ - private static final int MAX_DISTANCE = 2500; - - private final Client client; - private final CannonConfig config; - private final CannonPlugin plugin; - private final TextComponent textComponent = new TextComponent(); - - @Inject - CannonOverlay(Client client, CannonConfig config, CannonPlugin plugin) - { - setPosition(OverlayPosition.DYNAMIC); - setPriority(OverlayPriority.MED); - this.client = client; - this.config = config; - this.plugin = plugin; - } - - @Override - public Dimension render(Graphics2D graphics) - { - if (!plugin.isCannonPlaced() || plugin.getCannonPosition() == null) - { - return null; - } - - LocalPoint cannonPoint = LocalPoint.fromWorld(client, plugin.getCannonPosition()); - - if (cannonPoint == null) - { - return null; - } - - LocalPoint localLocation = client.getLocalPlayer().getLocalLocation(); - - if (localLocation.distanceTo(cannonPoint) <= MAX_DISTANCE) - { - Point cannonLoc = Perspective.getCanvasTextLocation(client, - graphics, - cannonPoint, - String.valueOf(plugin.getCballsLeft()), 150); - - if (cannonLoc != null) - { - textComponent.setText(String.valueOf(plugin.getCballsLeft())); - textComponent.setPosition(new java.awt.Point(cannonLoc.getX(), cannonLoc.getY())); - textComponent.setColor(plugin.getStateColor()); - textComponent.render(graphics); - } - - if (config.showDoubleHitSpot()) - { - Color color = config.highlightDoubleHitColor(); - drawDoubleHitSpots(graphics, cannonPoint, color); - } - } - - return null; - } - - - /** - * Draw the double hit spots on a 6 by 6 grid around the cannon - * @param startTile The position of the cannon - */ - private void drawDoubleHitSpots(Graphics2D graphics, LocalPoint startTile, Color color) - { - for (int x = -3; x <= 3; x++) - { - for (int y = -3; y <= 3; y++) - { - if (y != 1 && x != 1 && y != -1 && x != -1) - { - continue; - } - - //Ignore center square - if (y >= -1 && y <= 1 && x >= -1 && x <= 1) - { - continue; - } - - int xPos = startTile.getX() - (x * LOCAL_TILE_SIZE); - int yPos = startTile.getY() - (y * LOCAL_TILE_SIZE); - - LocalPoint marker = new LocalPoint(xPos, yPos); - Polygon poly = Perspective.getCanvasTilePoly(client, marker); - - if (poly == null) - { - continue; - } - - OverlayUtil.renderPolygon(graphics, poly, color); - } - } - } +/* + * Copyright (c) 2016-2018, Seth + * 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.cannon; + +import java.awt.Color; +import java.awt.Dimension; +import java.awt.Graphics2D; +import java.awt.Polygon; +import javax.inject.Inject; +import net.runelite.api.Client; +import net.runelite.api.Perspective; +import static net.runelite.api.Perspective.LOCAL_TILE_SIZE; +import net.runelite.api.Point; +import net.runelite.api.coords.LocalPoint; +import net.runelite.client.ui.overlay.Overlay; +import net.runelite.client.ui.overlay.OverlayPosition; +import net.runelite.client.ui.overlay.OverlayPriority; +import net.runelite.client.ui.overlay.OverlayUtil; +import net.runelite.client.ui.overlay.components.TextComponent; + +class CannonOverlay extends Overlay +{ + private static final int MAX_DISTANCE = 2500; + + private final Client client; + private final CannonConfig config; + private final CannonPlugin plugin; + private final TextComponent textComponent = new TextComponent(); + + @Inject + CannonOverlay(Client client, CannonConfig config, CannonPlugin plugin) + { + setPosition(OverlayPosition.DYNAMIC); + setPriority(OverlayPriority.MED); + this.client = client; + this.config = config; + this.plugin = plugin; + } + + @Override + public Dimension render(Graphics2D graphics) + { + if (!plugin.isCannonPlaced() || plugin.getCannonPosition() == null) + { + return null; + } + + LocalPoint cannonPoint = LocalPoint.fromWorld(client, plugin.getCannonPosition()); + + if (cannonPoint == null) + { + return null; + } + + LocalPoint localLocation = client.getLocalPlayer().getLocalLocation(); + + if (localLocation.distanceTo(cannonPoint) <= MAX_DISTANCE) + { + Point cannonLoc = Perspective.getCanvasTextLocation(client, + graphics, + cannonPoint, + String.valueOf(plugin.getCballsLeft()), 150); + + if (cannonLoc != null) + { + textComponent.setText(String.valueOf(plugin.getCballsLeft())); + textComponent.setPosition(new java.awt.Point(cannonLoc.getX(), cannonLoc.getY())); + textComponent.setColor(plugin.getStateColor()); + textComponent.render(graphics); + } + + if (config.showDoubleHitSpot()) + { + Color color = config.highlightDoubleHitColor(); + drawDoubleHitSpots(graphics, cannonPoint, color); + } + } + + return null; + } + + + /** + * Draw the double hit spots on a 6 by 6 grid around the cannon + * + * @param startTile The position of the cannon + */ + private void drawDoubleHitSpots(Graphics2D graphics, LocalPoint startTile, Color color) + { + for (int x = -3; x <= 3; x++) + { + for (int y = -3; y <= 3; y++) + { + if (y != 1 && x != 1 && y != -1 && x != -1) + { + continue; + } + + //Ignore center square + if (y >= -1 && y <= 1 && x >= -1 && x <= 1) + { + continue; + } + + int xPos = startTile.getX() - (x * LOCAL_TILE_SIZE); + int yPos = startTile.getY() - (y * LOCAL_TILE_SIZE); + + LocalPoint marker = new LocalPoint(xPos, yPos); + Polygon poly = Perspective.getCanvasTilePoly(client, marker); + + if (poly == null) + { + continue; + } + + OverlayUtil.renderPolygon(graphics, poly, color); + } + } + } } \ No newline at end of file diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/cerberus/CerberusGhost.java b/runelite-client/src/main/java/net/runelite/client/plugins/cerberus/CerberusGhost.java index 744085c9a4..354dd0edf4 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/cerberus/CerberusGhost.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/cerberus/CerberusGhost.java @@ -60,6 +60,7 @@ public enum CerberusGhost /** * Try to identify if NPC is ghost + * * @param npc npc * @return optional ghost */ diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/cerberus/CerberusOverlay.java b/runelite-client/src/main/java/net/runelite/client/plugins/cerberus/CerberusOverlay.java index 68018b6c3b..2f384fcd80 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/cerberus/CerberusOverlay.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/cerberus/CerberusOverlay.java @@ -63,13 +63,13 @@ public class CerberusOverlay extends Overlay // Ghosts are already sorted plugin.getGhosts().stream() - // Iterate only through the correct amount of ghosts - .limit(CerberusGhost.values().length) - .forEach(npc -> CerberusGhost - .fromNPC(npc) - .ifPresent(ghost -> panelComponent - .getChildren() - .add(new ImageComponent(iconManager.getSkillImage(ghost.getType()))))); + // Iterate only through the correct amount of ghosts + .limit(CerberusGhost.values().length) + .forEach(npc -> CerberusGhost + .fromNPC(npc) + .ifPresent(ghost -> panelComponent + .getChildren() + .add(new ImageComponent(iconManager.getSkillImage(ghost.getType()))))); return panelComponent.render(graphics); diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/chatboxperformance/ChatboxPerformancePlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/chatboxperformance/ChatboxPerformancePlugin.java index aaf6634ead..b19ab92f6f 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/chatboxperformance/ChatboxPerformancePlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/chatboxperformance/ChatboxPerformancePlugin.java @@ -1,158 +1,158 @@ -/* - * Copyright (c) 2018, Woox - * 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.chatboxperformance; - -import javax.inject.Inject; -import net.runelite.api.Client; -import net.runelite.api.widgets.WidgetType; -import net.runelite.api.events.WidgetPositioned; -import net.runelite.api.widgets.Widget; -import net.runelite.api.widgets.WidgetInfo; -import net.runelite.api.widgets.WidgetPositionMode; -import net.runelite.api.widgets.WidgetSizeMode; -import net.runelite.client.eventbus.Subscribe; -import net.runelite.client.plugins.Plugin; -import net.runelite.client.plugins.PluginDescriptor; - -@PluginDescriptor( - name = "Chatbox performance", - hidden = true -) -public class ChatboxPerformancePlugin extends Plugin -{ - @Inject - private Client client; - - @Subscribe - public void onWidgetPositioned(WidgetPositioned event) - { - if (!areWidgetsFixed()) - { - fixChatbox(); - } - } - - private boolean areWidgetsFixed() - { - Widget widget = client.getWidget(WidgetInfo.CHATBOX_TRANSPARENT_BACKGROUND); - if (widget == null) - { - return true; - } - - Widget[] widgets = widget.getChildren(); - - if (widgets != null && widgets.length > 0) - { - Widget last = widgets[widgets.length - 1]; - return last != null && last.getOpacity() < 254; - } - - return false; - } - - private void fixChatbox() - { - fixDarkBackground(); - fixWhiteLines(true); - fixWhiteLines(false); - } - - private void fixDarkBackground() - { - int currOpacity = 256; - int prevY = 0; - Widget[] children = client.getWidget(WidgetInfo.CHATBOX_TRANSPARENT_BACKGROUND).getDynamicChildren(); - Widget prev = null; - for (Widget w : children) - { - if (w.getType() != WidgetType.RECTANGLE) - { - continue; - } - - if (prev != null) - { - int relY = w.getRelativeY(); - prev.setHeightMode(WidgetSizeMode.ABSOLUTE); - prev.setYPositionMode(WidgetPositionMode.ABSOLUTE_TOP); - prev.setRelativeY(prevY); - prev.setOriginalY(prev.getRelativeY()); - prev.setHeight(relY - prevY); - prev.setOriginalHeight(prev.getHeight()); - prev.setOpacity(currOpacity); - } - - prevY = w.getRelativeY(); - currOpacity -= 3; // Rough number, can't get exactly the same as Jagex because of rounding - prev = w; - } - if (prev != null) - { - prev.setOpacity(currOpacity); - } - } - - private void fixWhiteLines(boolean upperLine) - { - int currOpacity = 256; - int prevWidth = 0; - Widget[] children = client.getWidget(WidgetInfo.CHATBOX_TRANSPARENT_LINES).getDynamicChildren(); - Widget prev = null; - for (Widget w : children) - { - if (w.getType() != WidgetType.RECTANGLE) - { - continue; - } - - if ((w.getRelativeY() == 0 && !upperLine) || - (w.getRelativeY() != 0 && upperLine)) - { - continue; - } - - if (prev != null) - { - int width = w.getWidth(); - prev.setWidthMode(WidgetSizeMode.ABSOLUTE); - prev.setRelativeX(width); - prev.setOriginalX(width); - prev.setWidth(prevWidth - width); - prev.setOriginalWidth(prev.getWidth()); - prev.setOpacity(currOpacity); - } - - prevWidth = w.getWidth(); - - currOpacity -= upperLine ? 3 : 4; // Rough numbers, can't get exactly the same as Jagex because of rounding - prev = w; - } - if (prev != null) - { - prev.setOpacity(currOpacity); - } - } -} +/* + * Copyright (c) 2018, Woox + * 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.chatboxperformance; + +import javax.inject.Inject; +import net.runelite.api.Client; +import net.runelite.api.events.WidgetPositioned; +import net.runelite.api.widgets.Widget; +import net.runelite.api.widgets.WidgetInfo; +import net.runelite.api.widgets.WidgetPositionMode; +import net.runelite.api.widgets.WidgetSizeMode; +import net.runelite.api.widgets.WidgetType; +import net.runelite.client.eventbus.Subscribe; +import net.runelite.client.plugins.Plugin; +import net.runelite.client.plugins.PluginDescriptor; + +@PluginDescriptor( + name = "Chatbox performance", + hidden = true +) +public class ChatboxPerformancePlugin extends Plugin +{ + @Inject + private Client client; + + @Subscribe + public void onWidgetPositioned(WidgetPositioned event) + { + if (!areWidgetsFixed()) + { + fixChatbox(); + } + } + + private boolean areWidgetsFixed() + { + Widget widget = client.getWidget(WidgetInfo.CHATBOX_TRANSPARENT_BACKGROUND); + if (widget == null) + { + return true; + } + + Widget[] widgets = widget.getChildren(); + + if (widgets != null && widgets.length > 0) + { + Widget last = widgets[widgets.length - 1]; + return last != null && last.getOpacity() < 254; + } + + return false; + } + + private void fixChatbox() + { + fixDarkBackground(); + fixWhiteLines(true); + fixWhiteLines(false); + } + + private void fixDarkBackground() + { + int currOpacity = 256; + int prevY = 0; + Widget[] children = client.getWidget(WidgetInfo.CHATBOX_TRANSPARENT_BACKGROUND).getDynamicChildren(); + Widget prev = null; + for (Widget w : children) + { + if (w.getType() != WidgetType.RECTANGLE) + { + continue; + } + + if (prev != null) + { + int relY = w.getRelativeY(); + prev.setHeightMode(WidgetSizeMode.ABSOLUTE); + prev.setYPositionMode(WidgetPositionMode.ABSOLUTE_TOP); + prev.setRelativeY(prevY); + prev.setOriginalY(prev.getRelativeY()); + prev.setHeight(relY - prevY); + prev.setOriginalHeight(prev.getHeight()); + prev.setOpacity(currOpacity); + } + + prevY = w.getRelativeY(); + currOpacity -= 3; // Rough number, can't get exactly the same as Jagex because of rounding + prev = w; + } + if (prev != null) + { + prev.setOpacity(currOpacity); + } + } + + private void fixWhiteLines(boolean upperLine) + { + int currOpacity = 256; + int prevWidth = 0; + Widget[] children = client.getWidget(WidgetInfo.CHATBOX_TRANSPARENT_LINES).getDynamicChildren(); + Widget prev = null; + for (Widget w : children) + { + if (w.getType() != WidgetType.RECTANGLE) + { + continue; + } + + if ((w.getRelativeY() == 0 && !upperLine) || + (w.getRelativeY() != 0 && upperLine)) + { + continue; + } + + if (prev != null) + { + int width = w.getWidth(); + prev.setWidthMode(WidgetSizeMode.ABSOLUTE); + prev.setRelativeX(width); + prev.setOriginalX(width); + prev.setWidth(prevWidth - width); + prev.setOriginalWidth(prev.getWidth()); + prev.setOpacity(currOpacity); + } + + prevWidth = w.getWidth(); + + currOpacity -= upperLine ? 3 : 4; // Rough numbers, can't get exactly the same as Jagex because of rounding + prev = w; + } + if (prev != null) + { + prev.setOpacity(currOpacity); + } + } +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/chatcommands/ChatCommandsPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/chatcommands/ChatCommandsPlugin.java index bd7c941ee1..b926e9528f 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/chatcommands/ChatCommandsPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/chatcommands/ChatCommandsPlugin.java @@ -653,7 +653,7 @@ public class ChatCommandsPlugin extends Plugin * response. * * @param chatMessage The chat message containing the command. - * @param message The chat message + * @param message The chat message */ private void itemPriceLookup(ChatMessage chatMessage, String message) { @@ -689,17 +689,17 @@ public class ChatCommandsPlugin extends Plugin int itemPrice = item.getPrice(); final ChatMessageBuilder builder = new ChatMessageBuilder(); - builder.append(ChatColorType.NORMAL); - builder.append(ChatColorType.HIGHLIGHT); - builder.append(item.getName()); - builder.append(ChatColorType.NORMAL); - builder.append(": GE "); - builder.append(ChatColorType.HIGHLIGHT); - builder.append(StackFormatter.formatNumber(itemPrice)); - builder.append(ChatColorType.NORMAL); - builder.append(": OSB "); - builder.append(ChatColorType.HIGHLIGHT); - builder.append(StackFormatter.formatNumber(osbresult.getOverall_average())); + builder.append(ChatColorType.NORMAL); + builder.append(ChatColorType.HIGHLIGHT); + builder.append(item.getName()); + builder.append(ChatColorType.NORMAL); + builder.append(": GE "); + builder.append(ChatColorType.HIGHLIGHT); + builder.append(StackFormatter.formatNumber(itemPrice)); + builder.append(ChatColorType.NORMAL); + builder.append(": OSB "); + builder.append(ChatColorType.HIGHLIGHT); + builder.append(StackFormatter.formatNumber(osbresult.getOverall_average())); ItemComposition itemComposition = itemManager.getItemComposition(itemId); if (itemComposition != null) @@ -726,7 +726,7 @@ public class ChatCommandsPlugin extends Plugin * response. * * @param chatMessage The chat message containing the command. - * @param message The chat message + * @param message The chat message */ private void playerSkillLookup(ChatMessage chatMessage, String message) { diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/chathistory/ChatHistoryPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/chathistory/ChatHistoryPlugin.java index 03aa7c2110..11e2c98e21 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/chathistory/ChatHistoryPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/chathistory/ChatHistoryPlugin.java @@ -1,262 +1,263 @@ -/* - * Copyright (c) 2018, Tomas Slusny - * 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 com.google.common.collect.EvictingQueue; -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 javax.inject.Inject; -import net.runelite.api.ChatMessageType; -import net.runelite.api.Client; -import net.runelite.api.ScriptID; -import net.runelite.api.VarClientInt; -import net.runelite.api.VarClientStr; -import net.runelite.api.events.ChatMessage; -import net.runelite.api.events.MenuOptionClicked; -import net.runelite.api.vars.InputType; -import net.runelite.client.callback.ClientThread; -import net.runelite.client.chat.ChatMessageManager; -import net.runelite.client.chat.QueuedMessage; -import net.runelite.client.config.ConfigManager; -import net.runelite.client.eventbus.Subscribe; -import net.runelite.client.input.KeyListener; -import net.runelite.client.input.KeyManager; -import net.runelite.client.plugins.Plugin; -import net.runelite.client.plugins.PluginDescriptor; -import net.runelite.client.util.Text; - -@PluginDescriptor( - name = "Chat History", - description = "Retain your chat history when logging in/out or world hopping", - tags = {"chat", "history", "retain", "cycle", "pm"} -) -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 = "Private:"; - private static final int CYCLE_HOTKEY = KeyEvent.VK_TAB; - private static final int FRIENDS_MAX_SIZE = 5; - - private Queue messageQueue; - private Deque 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<>(FRIENDS_MAX_SIZE + 1); - keyManager.registerKeyListener(this); - } - - @Override - protected void shutDown() - { - messageQueue.clear(); - messageQueue = null; - friends.clear(); - friends = null; - keyManager.unregisterKeyListener(this); - } - - @Subscribe - 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 (chatMessage.getMessage().equals(WELCOME_MESSAGE)) - { - if (!config.retainChatHistory()) - { - return; - } - - QueuedMessage queuedMessage; - - while ((queuedMessage = messageQueue.poll()) != null) - { - chatMessageManager.queue(queuedMessage); - } - - return; - } - - switch (chatMessage.getType()) - { - case PRIVATECHATOUT: - case PRIVATECHAT: - case MODPRIVATECHAT: - final String name = Text.removeTags(chatMessage.getName()); - // Remove to ensure uniqueness & its place in history - if (!friends.remove(name)) - { - // If the friend didn't previously exist ensure deque capacity doesn't increase by adding them - if (friends.size() >= FRIENDS_MAX_SIZE) - { - friends.remove(); - } - } - friends.add(name); - // intentional fall-through - case PUBLICCHAT: - case MODCHAT: - case FRIENDSCHAT: - case CONSOLE: - 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); - } - } - } - - @Subscribe - public void onMenuOptionClicked(MenuOptionClicked event) - { - String menuOption = event.getMenuOption(); - - if (menuOption.contains(CLEAR_HISTORY)) - { - if (menuOption.startsWith(CLEAR_PRIVATE)) - { - messageQueue.removeIf(e -> e.getType() == ChatMessageType.PRIVATECHAT || - e.getType() == ChatMessageType.PRIVATECHATOUT || e.getType() == ChatMessageType.MODPRIVATECHAT); - friends.clear(); - } - else - { - messageQueue.removeIf(e -> e.getType() == ChatMessageType.PUBLICCHAT || e.getType() == ChatMessageType.MODCHAT); - } - } - } - - /** - * Small hack to prevent plugins checking for specific messages to match - * @param message message - * @return message with nbsp - */ - private static String nbsp(final String message) - { - if (message != null) - { - return message.replace(' ', '\u00A0'); - } - - 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 it = friends.descendingIterator(); it.hasNext(); ) - { - String friend = it.next(); - if (friend.equals(currentTarget)) - { - return it.hasNext() ? it.next() : friends.getLast(); - } - } - - return friends.getLast(); - } -} +/* + * Copyright (c) 2018, Tomas Slusny + * 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 com.google.common.collect.EvictingQueue; +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 javax.inject.Inject; +import net.runelite.api.ChatMessageType; +import net.runelite.api.Client; +import net.runelite.api.ScriptID; +import net.runelite.api.VarClientInt; +import net.runelite.api.VarClientStr; +import net.runelite.api.events.ChatMessage; +import net.runelite.api.events.MenuOptionClicked; +import net.runelite.api.vars.InputType; +import net.runelite.client.callback.ClientThread; +import net.runelite.client.chat.ChatMessageManager; +import net.runelite.client.chat.QueuedMessage; +import net.runelite.client.config.ConfigManager; +import net.runelite.client.eventbus.Subscribe; +import net.runelite.client.input.KeyListener; +import net.runelite.client.input.KeyManager; +import net.runelite.client.plugins.Plugin; +import net.runelite.client.plugins.PluginDescriptor; +import net.runelite.client.util.Text; + +@PluginDescriptor( + name = "Chat History", + description = "Retain your chat history when logging in/out or world hopping", + tags = {"chat", "history", "retain", "cycle", "pm"} +) +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 = "Private:"; + private static final int CYCLE_HOTKEY = KeyEvent.VK_TAB; + private static final int FRIENDS_MAX_SIZE = 5; + + private Queue messageQueue; + private Deque 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<>(FRIENDS_MAX_SIZE + 1); + keyManager.registerKeyListener(this); + } + + @Override + protected void shutDown() + { + messageQueue.clear(); + messageQueue = null; + friends.clear(); + friends = null; + keyManager.unregisterKeyListener(this); + } + + @Subscribe + 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 (chatMessage.getMessage().equals(WELCOME_MESSAGE)) + { + if (!config.retainChatHistory()) + { + return; + } + + QueuedMessage queuedMessage; + + while ((queuedMessage = messageQueue.poll()) != null) + { + chatMessageManager.queue(queuedMessage); + } + + return; + } + + switch (chatMessage.getType()) + { + case PRIVATECHATOUT: + case PRIVATECHAT: + case MODPRIVATECHAT: + final String name = Text.removeTags(chatMessage.getName()); + // Remove to ensure uniqueness & its place in history + if (!friends.remove(name)) + { + // If the friend didn't previously exist ensure deque capacity doesn't increase by adding them + if (friends.size() >= FRIENDS_MAX_SIZE) + { + friends.remove(); + } + } + friends.add(name); + // intentional fall-through + case PUBLICCHAT: + case MODCHAT: + case FRIENDSCHAT: + case CONSOLE: + 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); + } + } + } + + @Subscribe + public void onMenuOptionClicked(MenuOptionClicked event) + { + String menuOption = event.getMenuOption(); + + if (menuOption.contains(CLEAR_HISTORY)) + { + if (menuOption.startsWith(CLEAR_PRIVATE)) + { + messageQueue.removeIf(e -> e.getType() == ChatMessageType.PRIVATECHAT || + e.getType() == ChatMessageType.PRIVATECHATOUT || e.getType() == ChatMessageType.MODPRIVATECHAT); + friends.clear(); + } + else + { + messageQueue.removeIf(e -> e.getType() == ChatMessageType.PUBLICCHAT || e.getType() == ChatMessageType.MODCHAT); + } + } + } + + /** + * Small hack to prevent plugins checking for specific messages to match + * + * @param message message + * @return message with nbsp + */ + private static String nbsp(final String message) + { + if (message != null) + { + return message.replace(' ', '\u00A0'); + } + + 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 it = friends.descendingIterator(); it.hasNext(); ) + { + String friend = it.next(); + if (friend.equals(currentTarget)) + { + return it.hasNext() ? it.next() : friends.getLast(); + } + } + + return friends.getLast(); + } +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/chatnotifications/ChatNotificationsPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/chatnotifications/ChatNotificationsPlugin.java index e2e2699f2a..8b2fc8d652 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/chatnotifications/ChatNotificationsPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/chatnotifications/ChatNotificationsPlugin.java @@ -1,231 +1,231 @@ -/* - * Copyright (c) 2018, Hydrox6 - * Copyright (c) 2018, Adam - * 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.chatnotifications; - -import com.google.common.base.Strings; -import com.google.inject.Provides; -import java.util.List; -import java.util.regex.Matcher; -import java.util.regex.Pattern; -import static java.util.regex.Pattern.quote; -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.client.Notifier; -import net.runelite.client.RuneLiteProperties; -import net.runelite.client.chat.ChatColorType; -import net.runelite.client.chat.ChatMessageManager; -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; - -@PluginDescriptor( - name = "Chat Notifications", - description = "Highlight and notify you of chat messages", - tags = {"duel", "messages", "notifications", "trade", "username"}, - enabledByDefault = false -) -public class ChatNotificationsPlugin extends Plugin -{ - @Inject - private Client client; - - @Inject - private ChatNotificationsConfig config; - - @Inject - private ChatMessageManager chatMessageManager; - - @Inject - private Notifier notifier; - - @Inject - private RuneLiteProperties runeLiteProperties; - - //Custom Highlights - private Pattern usernameMatcher = null; - private String usernameReplacer = ""; - private Pattern highlightMatcher = null; - - @Provides - ChatNotificationsConfig provideConfig(ConfigManager configManager) - { - return configManager.getConfig(ChatNotificationsConfig.class); - } - - @Override - public void startUp() - { - updateHighlights(); - } - - @Subscribe - public void onGameStateChanged(GameStateChanged event) - { - switch (event.getGameState()) - { - case LOGIN_SCREEN: - case HOPPING: - usernameMatcher = null; - break; - } - } - - @Subscribe - public void onConfigChanged(ConfigChanged event) - { - if (event.getGroup().equals("chatnotification")) - { - updateHighlights(); - } - } - - private void updateHighlights() - { - highlightMatcher = null; - - if (!config.highlightWordsString().trim().equals("")) - { - List items = Text.fromCSV(config.highlightWordsString()); - String joined = items.stream() - .map(Pattern::quote) - .collect(Collectors.joining("|")); - highlightMatcher = Pattern.compile("\\b(" + joined + ")\\b", Pattern.CASE_INSENSITIVE); - } - } - - @Subscribe - public void onChatMessage(ChatMessage chatMessage) - { - MessageNode messageNode = chatMessage.getMessageNode(); - String nodeValue = Text.removeTags(messageNode.getValue()); - boolean update = false; - - switch (chatMessage.getType()) - { - case TRADEREQ: - if (chatMessage.getMessage().contains("wishes to trade with you.") && config.notifyOnTrade()) - { - notifier.notify(chatMessage.getMessage()); - } - break; - case CHALREQ_TRADE: - if (chatMessage.getMessage().contains("wishes to duel with you.") && config.notifyOnDuel()) - { - notifier.notify(chatMessage.getMessage()); - } - break; - case CONSOLE: - // Don't notify for notification messages - if (chatMessage.getName().equals(runeLiteProperties.getTitle())) - { - return; - } - break; - } - - if (usernameMatcher == null && client.getLocalPlayer() != null && client.getLocalPlayer().getName() != null) - { - String username = client.getLocalPlayer().getName(); - usernameMatcher = Pattern.compile("\\b(" + quote(username) + ")\\b", Pattern.CASE_INSENSITIVE); - usernameReplacer = "" + username + ""; - } - - if (config.highlightOwnName() && usernameMatcher != null) - { - Matcher matcher = usernameMatcher.matcher(messageNode.getValue()); - if (matcher.find()) - { - messageNode.setValue(matcher.replaceAll(usernameReplacer)); - update = true; - - if (config.notifyOnOwnName()) - { - sendNotification(chatMessage); - } - } - } - - if (highlightMatcher != null) - { - Matcher matcher = highlightMatcher.matcher(nodeValue); - boolean found = false; - StringBuffer stringBuffer = new StringBuffer(); - - while (matcher.find()) - { - String value = matcher.group(); - matcher.appendReplacement(stringBuffer, "" + value + ""); - update = true; - found = true; - } - - if (found) - { - matcher.appendTail(stringBuffer); - messageNode.setValue(stringBuffer.toString()); - - if (config.notifyOnHighlight()) - { - sendNotification(chatMessage); - } - } - } - - if (update) - { - messageNode.setRuneLiteFormatMessage(messageNode.getValue()); - chatMessageManager.update(messageNode); - } - } - - private void sendNotification(ChatMessage message) - { - String name = Text.removeTags(message.getName()); - String sender = message.getSender(); - StringBuilder stringBuilder = new StringBuilder(); - - if (!Strings.isNullOrEmpty(sender)) - { - stringBuilder.append('[').append(sender).append("] "); - } - - if (!Strings.isNullOrEmpty(name)) - { - stringBuilder.append(name).append(": "); - } - - stringBuilder.append(Text.removeTags(message.getMessage())); - String notification = stringBuilder.toString(); - notifier.notify(notification); - } -} +/* + * Copyright (c) 2018, Hydrox6 + * Copyright (c) 2018, Adam + * 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.chatnotifications; + +import com.google.common.base.Strings; +import com.google.inject.Provides; +import java.util.List; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import static java.util.regex.Pattern.quote; +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.client.Notifier; +import net.runelite.client.RuneLiteProperties; +import net.runelite.client.chat.ChatColorType; +import net.runelite.client.chat.ChatMessageManager; +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; + +@PluginDescriptor( + name = "Chat Notifications", + description = "Highlight and notify you of chat messages", + tags = {"duel", "messages", "notifications", "trade", "username"}, + enabledByDefault = false +) +public class ChatNotificationsPlugin extends Plugin +{ + @Inject + private Client client; + + @Inject + private ChatNotificationsConfig config; + + @Inject + private ChatMessageManager chatMessageManager; + + @Inject + private Notifier notifier; + + @Inject + private RuneLiteProperties runeLiteProperties; + + //Custom Highlights + private Pattern usernameMatcher = null; + private String usernameReplacer = ""; + private Pattern highlightMatcher = null; + + @Provides + ChatNotificationsConfig provideConfig(ConfigManager configManager) + { + return configManager.getConfig(ChatNotificationsConfig.class); + } + + @Override + public void startUp() + { + updateHighlights(); + } + + @Subscribe + public void onGameStateChanged(GameStateChanged event) + { + switch (event.getGameState()) + { + case LOGIN_SCREEN: + case HOPPING: + usernameMatcher = null; + break; + } + } + + @Subscribe + public void onConfigChanged(ConfigChanged event) + { + if (event.getGroup().equals("chatnotification")) + { + updateHighlights(); + } + } + + private void updateHighlights() + { + highlightMatcher = null; + + if (!config.highlightWordsString().trim().equals("")) + { + List items = Text.fromCSV(config.highlightWordsString()); + String joined = items.stream() + .map(Pattern::quote) + .collect(Collectors.joining("|")); + highlightMatcher = Pattern.compile("\\b(" + joined + ")\\b", Pattern.CASE_INSENSITIVE); + } + } + + @Subscribe + public void onChatMessage(ChatMessage chatMessage) + { + MessageNode messageNode = chatMessage.getMessageNode(); + String nodeValue = Text.removeTags(messageNode.getValue()); + boolean update = false; + + switch (chatMessage.getType()) + { + case TRADEREQ: + if (chatMessage.getMessage().contains("wishes to trade with you.") && config.notifyOnTrade()) + { + notifier.notify(chatMessage.getMessage()); + } + break; + case CHALREQ_TRADE: + if (chatMessage.getMessage().contains("wishes to duel with you.") && config.notifyOnDuel()) + { + notifier.notify(chatMessage.getMessage()); + } + break; + case CONSOLE: + // Don't notify for notification messages + if (chatMessage.getName().equals(runeLiteProperties.getTitle())) + { + return; + } + break; + } + + if (usernameMatcher == null && client.getLocalPlayer() != null && client.getLocalPlayer().getName() != null) + { + String username = client.getLocalPlayer().getName(); + usernameMatcher = Pattern.compile("\\b(" + quote(username) + ")\\b", Pattern.CASE_INSENSITIVE); + usernameReplacer = "" + username + ""; + } + + if (config.highlightOwnName() && usernameMatcher != null) + { + Matcher matcher = usernameMatcher.matcher(messageNode.getValue()); + if (matcher.find()) + { + messageNode.setValue(matcher.replaceAll(usernameReplacer)); + update = true; + + if (config.notifyOnOwnName()) + { + sendNotification(chatMessage); + } + } + } + + if (highlightMatcher != null) + { + Matcher matcher = highlightMatcher.matcher(nodeValue); + boolean found = false; + StringBuffer stringBuffer = new StringBuffer(); + + while (matcher.find()) + { + String value = matcher.group(); + matcher.appendReplacement(stringBuffer, "" + value + ""); + update = true; + found = true; + } + + if (found) + { + matcher.appendTail(stringBuffer); + messageNode.setValue(stringBuffer.toString()); + + if (config.notifyOnHighlight()) + { + sendNotification(chatMessage); + } + } + } + + if (update) + { + messageNode.setRuneLiteFormatMessage(messageNode.getValue()); + chatMessageManager.update(messageNode); + } + } + + private void sendNotification(ChatMessage message) + { + String name = Text.removeTags(message.getName()); + String sender = message.getSender(); + StringBuilder stringBuilder = new StringBuilder(); + + if (!Strings.isNullOrEmpty(sender)) + { + stringBuilder.append('[').append(sender).append("] "); + } + + if (!Strings.isNullOrEmpty(name)) + { + stringBuilder.append(name).append(": "); + } + + stringBuilder.append(Text.removeTags(message.getMessage())); + String notification = stringBuilder.toString(); + notifier.notify(notification); + } +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/clanchat/ClanChatPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/clanchat/ClanChatPlugin.java index 8e2f32f2ba..a8403c65d5 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/clanchat/ClanChatPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/clanchat/ClanChatPlugin.java @@ -33,13 +33,11 @@ import java.awt.Color; import java.awt.image.BufferedImage; import java.util.ArrayDeque; import java.util.ArrayList; -import java.util.Arrays; import java.util.Deque; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.CopyOnWriteArrayList; import javax.inject.Inject; import net.runelite.api.ChatLineBuffer; @@ -49,9 +47,7 @@ import net.runelite.api.ClanMemberRank; import net.runelite.api.Client; import net.runelite.api.GameState; import net.runelite.api.MessageNode; -import net.runelite.api.Opcodes; import net.runelite.api.Player; -import net.runelite.api.Script; import net.runelite.api.ScriptID; import net.runelite.api.SpriteID; import net.runelite.api.VarClientStr; @@ -65,10 +61,7 @@ import net.runelite.api.events.GameStateChanged; import net.runelite.api.events.GameTick; import net.runelite.api.events.PlayerDespawned; import net.runelite.api.events.PlayerSpawned; -import net.runelite.api.events.ScriptCallbackEvent; import net.runelite.api.events.VarClientStrChanged; -import net.runelite.api.events.WidgetMenuOptionClicked; -import net.runelite.api.widgets.JavaScriptCallback; import net.runelite.api.widgets.Widget; import net.runelite.api.widgets.WidgetInfo; import net.runelite.api.widgets.WidgetType; @@ -78,8 +71,6 @@ 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.menus.MenuManager; -import net.runelite.client.menus.WidgetMenuOption; import net.runelite.client.plugins.Plugin; import net.runelite.client.plugins.PluginDescriptor; import static net.runelite.client.ui.JagexColors.CHAT_CLAN_NAME_OPAQUE_BACKGROUND; @@ -120,16 +111,13 @@ public class ClanChatPlugin extends Plugin @Inject private ClientThread clientThread; - @Inject - private MenuManager menuManager; - private List chats = new ArrayList<>(); - + public static CopyOnWriteArrayList getClanMembers() { return (CopyOnWriteArrayList) clanMembers.clone(); } - + private static CopyOnWriteArrayList clanMembers = new CopyOnWriteArrayList<>(); private ClanChatIndicator clanMemberCounter; /** @@ -139,8 +127,6 @@ public class ClanChatPlugin extends Plugin private Map activityBuffer = new HashMap<>(); private int clanJoinedTick; - private ConcurrentHashMap ccWidgetMap = new ConcurrentHashMap(); - @Provides ClanChatConfig getConfig(ConfigManager configManager) { @@ -561,13 +547,14 @@ public class ClanChatPlugin extends Plugin private void loadClanChats() { Widget clanChatList = client.getWidget(WidgetInfo.CLAN_CHAT_LIST); - clanChatList.setScrollHeight( 14 * chats.size()); - clanChatList.revalidateScroll(); if (clanChatList == null) { return; } + clanChatList.setScrollHeight(14 * chats.size()); + clanChatList.revalidateScroll(); + int y = 2; clanChatList.setChildren(null); for (String chat : Lists.reverse(chats)) diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/clanmanmode/ClanManModeOverlay.java b/runelite-client/src/main/java/net/runelite/client/plugins/clanmanmode/ClanManModeOverlay.java index 28ebb3fe29..4cfc1cd6ad 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/clanmanmode/ClanManModeOverlay.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/clanmanmode/ClanManModeOverlay.java @@ -7,7 +7,6 @@ import javax.inject.Inject; import javax.inject.Singleton; import net.runelite.api.Player; import net.runelite.api.Point; -import net.runelite.client.game.ClanManager; import net.runelite.client.ui.FontManager; import net.runelite.client.ui.overlay.Overlay; import net.runelite.client.ui.overlay.OverlayPosition; @@ -49,7 +48,8 @@ public class ClanManModeOverlay extends Overlay if (textLocation != null) { - if (config.getClanAttackableColor().equals(color) && config.ShowBold()) { + if (config.getClanAttackableColor().equals(color) && config.ShowBold()) + { graphics.setFont(FontManager.getRunescapeBoldFont()); } OverlayUtil.renderTextLocation(graphics, textLocation, name, color); diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/clanmanmode/ClanManModePlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/clanmanmode/ClanManModePlugin.java index 9c597bafe3..63d0c6c37d 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/clanmanmode/ClanManModePlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/clanmanmode/ClanManModePlugin.java @@ -70,14 +70,16 @@ public class ClanManModePlugin extends Plugin Map clan = new HashMap<>(); @Override - protected void startUp() throws Exception { + protected void startUp() throws Exception + { overlayManager.add(ClanManModeOverlay); overlayManager.add(ClanManModeTileOverlay); overlayManager.add(ClanManModeMinimapOverlay); } @Override - protected void shutDown() throws Exception { + protected void shutDown() throws Exception + { overlayManager.remove(ClanManModeOverlay); overlayManager.remove(ClanManModeTileOverlay); overlayManager.remove(ClanManModeMinimapOverlay); @@ -90,17 +92,21 @@ public class ClanManModePlugin extends Plugin } @Subscribe - public void onGameStateChanged(GameStateChanged gameStateChanged) { - if (gameStateChanged.getGameState() == GameState.LOGIN_SCREEN || gameStateChanged.getGameState() == GameState.HOPPING) { + public void onGameStateChanged(GameStateChanged gameStateChanged) + { + if (gameStateChanged.getGameState() == GameState.LOGIN_SCREEN || gameStateChanged.getGameState() == GameState.HOPPING) + { ticks = 0; } } @Subscribe - public void onGameTick(GameTick event) { + public void onGameTick(GameTick event) + { ticks++; final Player localPlayer = client.getLocalPlayer(); - if (!clan.containsKey(localPlayer.getName())) { + if (!clan.containsKey(localPlayer.getName())) + { clan.put(localPlayer.getName(), localPlayer.getCombatLevel()); } WorldPoint a = localPlayer.getWorldLocation(); @@ -108,30 +114,38 @@ public class ClanManModePlugin extends Plugin int upperLevel = ((a.getY() - 3520) / 8) + 1; wildernessLevel = a.getY() > 6400 ? underLevel : upperLevel; inwildy = client.getVar(Varbits.IN_WILDERNESS); - if (clan.size() > 0) { + if (clan.size() > 0) + { clanmin = Collections.min(clan.values()); clanmax = Collections.max(clan.values()); } } @Subscribe - public void onMenuEntryAdded(MenuEntryAdded event) { - if (!config.hideAtkOpt()) { + public void onMenuEntryAdded(MenuEntryAdded event) + { + if (!config.hideAtkOpt()) + { return; } - if (client.getGameState() != GameState.LOGGED_IN) { + if (client.getGameState() != GameState.LOGGED_IN) + { return; } final String option = Text.removeTags(event.getOption()).toLowerCase(); - if (option.equals("attack")) { + if (option.equals("attack")) + { final Pattern ppattern = Pattern.compile("(.+?) 6400 ? underLevel : upperLevel; int wildydiff = plugin.wildernessLevel - wildernessLevel; - if (wildydiff < 0) { + if (wildydiff < 0) + { wildydiff = 0; } - if (config.CalcSelfCB()) { - if (interacting.getCombatLevel() <= selfmax && interacting.getCombatLevel() - wildydiff >= selfmin && !interactor.isClanMember()) { + if (config.CalcSelfCB()) + { + if (interacting.getCombatLevel() <= selfmax && interacting.getCombatLevel() - wildydiff >= selfmin && !interactor.isClanMember()) + { interactors.put(interactor.getName(), player.getName()); consumer.accept(interactor, config.getClanAttackableColor()); } - } else { - if (interacting.getCombatLevel() <= maxatk && interacting.getCombatLevel() - wildydiff >= minatk && !interactor.isClanMember()) { + } + else + { + if (interacting.getCombatLevel() <= maxatk && interacting.getCombatLevel() - wildydiff >= minatk && !interactor.isClanMember()) + { interactors.put(interactor.getName(), player.getName()); consumer.accept(interactor, config.getClanAttackableColor()); } @@ -92,43 +110,61 @@ public class ClanManModeService } } } - } else { - if (config.PersistentClan()) { - if (plugin.clan.containsKey(player.getName())) { + } + else + { + if (config.PersistentClan()) + { + if (plugin.clan.containsKey(player.getName())) + { consumer.accept(player, config.getClanMemberColor()); } } - if (config.highlightAttacked()) { - if (interactors.containsKey(player.getName())) { + if (config.highlightAttacked()) + { + if (interactors.containsKey(player.getName())) + { String attackername = interactors.get(player.getName()); boolean found = false; - for (Player attacker : client.getPlayers()) { - if (attacker == null || attacker.getName() == null) { + for (Player attacker : client.getPlayers()) + { + if (attacker == null || attacker.getName() == null) + { continue; } - if (attacker.getName().equals(attackername)) { + if (attacker.getName().equals(attackername)) + { found = true; Actor ainteract = attacker.getInteracting(); - if (ainteract != null) { - if (ainteract.getName().equals(player.getName())) { + if (ainteract != null) + { + if (ainteract.getName().equals(player.getName())) + { consumer.accept(player, config.getClanAttackableColor()); - } else { + } + else + { interactors.remove(player.getName()); } - } else { + } + else + { interactors.remove(player.getName()); } break; } } - if (!found) { + if (!found) + { interactors.remove(player.getName()); } continue; } } - if (config.highlightAttackable()) { - if ((config.hideAttackable() && plugin.ticks >= config.hideTime()) || plugin.clan.containsKey(player.getName())) { + if (config.highlightAttackable()) + { + if ((config.hideAttackable() && plugin.ticks >= config.hideTime()) || plugin.clan.containsKey(player.getName())) + { continue; } WorldPoint a = player.getWorldLocation(); @@ -136,15 +172,21 @@ public class ClanManModeService int upperLevel = ((a.getY() - 3520) / 8) + 1; int wildernessLevel = a.getY() > 6400 ? underLevel : upperLevel; int wildydiff = plugin.wildernessLevel - wildernessLevel; - if (wildydiff < 0) { + if (wildydiff < 0) + { wildydiff = 0; } - if (config.CalcSelfCB()) { - if (player.getCombatLevel() <= selfmax && player.getCombatLevel() - wildydiff >= selfmin) { + if (config.CalcSelfCB()) + { + if (player.getCombatLevel() <= selfmax && player.getCombatLevel() - wildydiff >= selfmin) + { consumer.accept(player, config.getAttackableColor()); } - } else { - if (player.getCombatLevel() <= maxatk && player.getCombatLevel() - wildydiff >= minatk) { + } + else + { + if (player.getCombatLevel() <= maxatk && player.getCombatLevel() - wildydiff >= minatk) + { consumer.accept(player, config.getAttackableColor()); } } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/ClueScrollPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/ClueScrollPlugin.java index d060f1a3e4..6dc32fde32 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/ClueScrollPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/ClueScrollPlugin.java @@ -749,7 +749,7 @@ public class ClueScrollPlugin extends Plugin textComponent.render(graphics); } - void scrollToWidget(WidgetInfo list, WidgetInfo scrollbar, Widget ... toHighlight) + void scrollToWidget(WidgetInfo list, WidgetInfo scrollbar, Widget... toHighlight) { final Widget parent = client.getWidget(list); int averageCentralY = 0; diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/clues/AnagramClue.java b/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/clues/AnagramClue.java index c59a79728c..a343f49357 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/clues/AnagramClue.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/clues/AnagramClue.java @@ -267,12 +267,12 @@ public class AnagramClue extends ClueScroll implements TextClueScroll, NpcClueSc @Override public String[] getNpcs() { - return new String[] {npc}; + return new String[]{npc}; } @Override public int[] getObjectIds() { - return new int[] {objectId}; + return new int[]{objectId}; } } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/clues/CipherClue.java b/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/clues/CipherClue.java index 404ce70eae..a4aa491c32 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/clues/CipherClue.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/clues/CipherClue.java @@ -133,6 +133,6 @@ public class CipherClue extends ClueScroll implements TextClueScroll, NpcClueScr public String[] getNpcs() { - return new String[] {npc}; + return new String[]{npc}; } } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/clues/CrypticClue.java b/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/clues/CrypticClue.java index f8582fe1c0..888458197e 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/clues/CrypticClue.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/clues/CrypticClue.java @@ -32,7 +32,56 @@ import lombok.Getter; import net.runelite.api.NPC; import static net.runelite.api.NullObjectID.NULL_1293; import net.runelite.api.ObjectComposition; -import static net.runelite.api.ObjectID.*; +import static net.runelite.api.ObjectID.BOOKCASE_12539; +import static net.runelite.api.ObjectID.BOOKCASE_380; +import static net.runelite.api.ObjectID.BOOKCASE_394; +import static net.runelite.api.ObjectID.BOOKCASE_9523; +import static net.runelite.api.ObjectID.BOXES; +import static net.runelite.api.ObjectID.BOXES_360; +import static net.runelite.api.ObjectID.BOXES_361; +import static net.runelite.api.ObjectID.BOXES_3686; +import static net.runelite.api.ObjectID.BOXES_5111; +import static net.runelite.api.ObjectID.BOXES_6176; +import static net.runelite.api.ObjectID.BUCKET_9568; +import static net.runelite.api.ObjectID.BUSH_2357; +import static net.runelite.api.ObjectID.CLOSED_CHEST_25592; +import static net.runelite.api.ObjectID.CLOSED_CHEST_375; +import static net.runelite.api.ObjectID.CLOSED_CHEST_5108; +import static net.runelite.api.ObjectID.COFFIN; +import static net.runelite.api.ObjectID.CRATES_11600; +import static net.runelite.api.ObjectID.CRATES_24088; +import static net.runelite.api.ObjectID.CRATE_11485; +import static net.runelite.api.ObjectID.CRATE_12963; +import static net.runelite.api.ObjectID.CRATE_18204; +import static net.runelite.api.ObjectID.CRATE_18506; +import static net.runelite.api.ObjectID.CRATE_18889; +import static net.runelite.api.ObjectID.CRATE_24344; +import static net.runelite.api.ObjectID.CRATE_25775; +import static net.runelite.api.ObjectID.CRATE_26635; +import static net.runelite.api.ObjectID.CRATE_27532; +import static net.runelite.api.ObjectID.CRATE_27533; +import static net.runelite.api.ObjectID.CRATE_354; +import static net.runelite.api.ObjectID.CRATE_355; +import static net.runelite.api.ObjectID.CRATE_356; +import static net.runelite.api.ObjectID.CRATE_357; +import static net.runelite.api.ObjectID.CRATE_358; +import static net.runelite.api.ObjectID.CRATE_366; +import static net.runelite.api.ObjectID.CRATE_5106; +import static net.runelite.api.ObjectID.CRATE_5107; +import static net.runelite.api.ObjectID.CRATE_5113; +import static net.runelite.api.ObjectID.CRATE_9534; +import static net.runelite.api.ObjectID.DRAWERS; +import static net.runelite.api.ObjectID.DRAWERS_25766; +import static net.runelite.api.ObjectID.DRAWERS_350; +import static net.runelite.api.ObjectID.DRAWERS_352; +import static net.runelite.api.ObjectID.DRAWERS_5618; +import static net.runelite.api.ObjectID.DRAWERS_7194; +import static net.runelite.api.ObjectID.HAYSTACK; +import static net.runelite.api.ObjectID.JUNA; +import static net.runelite.api.ObjectID.MINE_CART_6045; +import static net.runelite.api.ObjectID.STONES_26633; +import static net.runelite.api.ObjectID.WARDROBE_5622; +import static net.runelite.api.ObjectID.WHEELBARROW_9625; import net.runelite.api.TileObject; import net.runelite.api.coords.LocalPoint; import net.runelite.api.coords.WorldPoint; @@ -116,7 +165,7 @@ public class CrypticClue extends ClueScroll implements TextClueScroll, NpcClueSc new CrypticClue("Probably filled with wizards socks.", "Wizard", DRAWERS_350, new WorldPoint(3116, 9562, 0), "Search the drawers in the basement of the Wizard's Tower south of Draynor Village. Kill one of the Wizards for the key. Fairy ring DIS"), new CrypticClue("Even the seers say this clue goes right over their heads.", CRATE_26635, new WorldPoint(2707, 3488, 2), "Search the crate on the Seers Agility Course in Seers Village"), new CrypticClue("Speak to a Wyse man.", "Wyson the gardener", new WorldPoint(3026, 3378, 0), "Talk to Wyson the gardener at Falador Park."), - new CrypticClue("You'll need to look for a town with a central fountain. Look for a locked chest in the town's chapel.", "Monk" , CLOSED_CHEST_5108, new WorldPoint(3256, 3487, 0), "Search the chest by the stairs in the Varrock church. Kill a Monk in Ardougne Monastery to obtain the key."), + new CrypticClue("You'll need to look for a town with a central fountain. Look for a locked chest in the town's chapel.", "Monk", CLOSED_CHEST_5108, new WorldPoint(3256, 3487, 0), "Search the chest by the stairs in the Varrock church. Kill a Monk in Ardougne Monastery to obtain the key."), new CrypticClue("Talk to Ambassador Spanfipple in the White Knights Castle.", "Ambassador Spanfipple", new WorldPoint(2979, 3340, 0), "Ambassador Spanfipple can be found roaming on the first floor of the White Knights Castle."), new CrypticClue("Mine was the strangest birth under the sun. I left the crimson sack, yet life had not begun. Entered the world, and yet was seen by none.", new WorldPoint(2832, 9586, 0), "Inside Karamja Volcano, dig directly underneath the Red spiders' eggs respawn."), new CrypticClue("Search for a crate in Varrock Castle.", CRATE_5113, new WorldPoint(3224, 3492, 0), "Search the crate in the corner of the kitchen in Varrock Castle."), @@ -196,13 +245,13 @@ public class CrypticClue extends ClueScroll implements TextClueScroll, NpcClueSc new CrypticClue("Search a bookcase in Lumbridge swamp.", BOOKCASE_9523, new WorldPoint(3146, 3177, 0), "Located in Father Urhney's house."), new CrypticClue("Surround my bones in fire, ontop the wooden pyre. Finally lay me to rest, before my one last test.", null, "Kill a confused/lost barbarian to receive mangled bones. Construct and burn a pyre ship. Kill the ferocious barbarian spirit that spawns to receive a clue casket."), new CrypticClue("Fiendish cooks probably won't dig the dirty dishes.", new WorldPoint(3043, 4974, 1), "Dig by the fire in the Rogues' Den."), - new CrypticClue("My life was spared but these voices remain, now guarding these iron gates is my bane.", "Key Master", new WorldPoint(1310, 1251, 0), "Speak to the Key Master in Cerberus' Lair."), + new CrypticClue("My life was spared but these voices remain, now guarding these iron gates is my bane.", "Key Master", new WorldPoint(1310, 1251, 0), "Speak to the Key Master in Cerberus' Lair."), new CrypticClue("Search the boxes in one of the tents in Al Kharid.", BOXES_361, new WorldPoint(3308, 3206, 0), "Search the boxes in the tent east of the Silk trader."), - new CrypticClue("One of several rhyming brothers, in business attire with an obsession for paper work.", "Piles", new WorldPoint(3186, 3936, 0), "Speak to Piles in the Wilderness Resource Area. An entry fee of 7,500 coins is required, or less if Wilderness Diaries have been completed."), + new CrypticClue("One of several rhyming brothers, in business attire with an obsession for paper work.", "Piles", new WorldPoint(3186, 3936, 0), "Speak to Piles in the Wilderness Resource Area. An entry fee of 7,500 coins is required, or less if Wilderness Diaries have been completed."), new CrypticClue("Search the drawers on the first floor of a building overlooking Ardougne's Market.", DRAWERS_352, new WorldPoint(2657, 3322, 1), "Climb the ladder in the house north of the market."), new CrypticClue("'A bag belt only?', he asked his balding brothers.", "Abbot Langley", new WorldPoint(3058, 3487, 0), "Talk-to Abbot Langley in Monastery west of Edgeville"), new CrypticClue("Search the drawers upstairs in Falador's shield shop.", DRAWERS, new WorldPoint(2971, 3386, 1), "Cassie's Shield Shop at the northern Falador entrance."), - new CrypticClue("Go to this building to be illuminated, and check the drawers while you are there.", "Market Guard", DRAWERS_350 , new WorldPoint(2512, 3641, 1), "Search the drawers in the first floor of the Lighthouse. Kill a Rellekka marketplace guard to obtain the key."), + new CrypticClue("Go to this building to be illuminated, and check the drawers while you are there.", "Market Guard", DRAWERS_350, new WorldPoint(2512, 3641, 1), "Search the drawers in the first floor of the Lighthouse. Kill a Rellekka marketplace guard to obtain the key."), new CrypticClue("Dig near some giant mushrooms, behind the Grand Tree.", new WorldPoint(2458, 3504, 0), "Dig near the red mushrooms northwest of the Grand Tree."), new CrypticClue("Pentagrams and demons, burnt bones and remains, I wonder what the blood contains.", new WorldPoint(3297, 3890, 0), "Dig under the blood rune spawn next the the Demonic Ruins."), new CrypticClue("Search the drawers above Varrock's shops.", DRAWERS_7194, new WorldPoint(3206, 3419, 1), "Located upstairs in Thessalia's Fine Clothes shop in Varrock."), @@ -276,7 +325,7 @@ public class CrypticClue extends ClueScroll implements TextClueScroll, NpcClueSc new CrypticClue("Ghommal wishes to be impressed by how strong your equipment is.", "Ghommal", new WorldPoint(2878, 3546, 0), "Speak to Ghommal at the Warriors' Guild with a total Melee Strength bonus of over 100."), new CrypticClue("Shhhh!", "Logosia", new WorldPoint(1633, 3808, 0), "Speak to Logosia in the Arceuus Library's ground floor."), new CrypticClue("Salty peter.", "Konoo", new WorldPoint(1703, 3524, 0), "Talk to Konoo who is digging saltpetre in Hosidius, south of the bank."), - new CrypticClue("Talk to Zeke in Al Kharid.", "Zeke", new WorldPoint(3287, 3190, 0), "Zeke is the owner of the scimitar shop in Al Kharid."), + new CrypticClue("Talk to Zeke in Al Kharid.", "Zeke", new WorldPoint(3287, 3190, 0), "Zeke is the owner of the scimitar shop in Al Kharid."), new CrypticClue("Guthix left his mark in a fiery lake, dig at the tip of it.", new WorldPoint(3069, 3935, 0), "Dig at the tip of the lava lake that is shaped like a Guthixian symbol, west of the Mage Arena."), new CrypticClue("Search the drawers in the upstairs of a house in Catherby.", DRAWERS_350, new WorldPoint(2809, 3451, 1), "Perdu's house in Catherby."), new CrypticClue("Search a crate in the Haymaker's arms.", CRATE_27532, new WorldPoint(1720, 3652, 1), "Search the crate in the north-east corner of The Haymaker's Arms tavern east of Kourend Castle."), @@ -294,9 +343,9 @@ public class CrypticClue extends ClueScroll implements TextClueScroll, NpcClueSc new CrypticClue("Dig in the centre of a great kingdom of 5 cities.", new WorldPoint(1639, 3673, 0), "Dig in front of the large statue in the centre of Great Kourend."), new CrypticClue("Hopefully this set of armour will help you to keep surviving.", "Sir Vyvin", new WorldPoint(2982, 3336, 2), "Speak to Sir Vyvin while wearing a white platebody, and platelegs."), new CrypticClue("The beasts retreat, for their Queen is gone; the song of this town still plays on. Dig near the birthplace of a blade, be careful not to melt your spade.", new WorldPoint(2342, 3677, 0), "Dig in front of the small furnace in the Piscatoris Fishing Colony."), - new CrypticClue("Darkness wanders around me, but fills my mind with knowledge.", "Biblia", new WorldPoint(1633, 3825, 2), "Speak to Biblia on the Arceuus Library's top floor."), + new CrypticClue("Darkness wanders around me, but fills my mind with knowledge.", "Biblia", new WorldPoint(1633, 3825, 2), "Speak to Biblia on the Arceuus Library's top floor."), new CrypticClue("I would make a chemistry joke, but I'm afraid I wouldn't get a reaction.", "Chemist", new WorldPoint(2932, 3212, 0), "Talk to the Chemist in Rimmington"), - new CrypticClue("Show this to Hazelmere.", "Hazelmere", new WorldPoint(2677, 3088, 1), "Hazelmere is found upstairs on the island located just east of Yanille."), + new CrypticClue("Show this to Hazelmere.", "Hazelmere", new WorldPoint(2677, 3088, 1), "Hazelmere is found upstairs on the island located just east of Yanille."), 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 north-east of the general store in Hosidius."), new CrypticClue("Dig under Ithoi's cabin.", new WorldPoint(2529, 2838, 0), "Dig under Ithoi's cabin in the Corsair Cove."), @@ -428,7 +477,7 @@ public class CrypticClue extends ClueScroll implements TextClueScroll, NpcClueSc for (TileObject gameObject : plugin.getObjectsToMark()) { OverlayUtil.renderHoverableArea(graphics, gameObject.getClickbox(), mousePosition, - CLICKBOX_FILL_COLOR, CLICKBOX_BORDER_COLOR, CLICKBOX_HOVER_BORDER_COLOR); + CLICKBOX_FILL_COLOR, CLICKBOX_BORDER_COLOR, CLICKBOX_HOVER_BORDER_COLOR); OverlayUtil.renderImageLocation(plugin.getClient(), graphics, gameObject.getLocalLocation(), plugin.getClueScrollImage(), IMAGE_Z_OFFSET); } @@ -452,12 +501,12 @@ public class CrypticClue extends ClueScroll implements TextClueScroll, NpcClueSc @Override public int[] getObjectIds() { - return new int[] {objectId}; + return new int[]{objectId}; } @Override public String[] getNpcs() { - return new String[] {npc}; + return new String[]{npc}; } } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/clues/EmoteClue.java b/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/clues/EmoteClue.java index eb4e89cef0..15352c56b2 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/clues/EmoteClue.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/clues/EmoteClue.java @@ -1,312 +1,827 @@ -/* - * Copyright (c) 2018, Lotto - * 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.cluescrolls.clues; - -import com.google.common.collect.ImmutableSet; -import java.awt.Color; -import java.awt.Graphics2D; -import java.util.Set; -import javax.annotation.Nonnull; -import lombok.Getter; -import net.runelite.api.EquipmentInventorySlot; -import static net.runelite.api.EquipmentInventorySlot.*; -import static net.runelite.api.EquipmentInventorySlot.LEGS; -import net.runelite.api.Item; -import net.runelite.api.ItemID; -import static net.runelite.api.ItemID.*; -import net.runelite.api.coords.LocalPoint; -import net.runelite.api.coords.WorldPoint; -import static net.runelite.client.plugins.cluescrolls.ClueScrollOverlay.TITLED_CONTENT_COLOR; -import net.runelite.client.plugins.cluescrolls.ClueScrollPlugin; -import net.runelite.client.plugins.cluescrolls.clues.emote.AllRequirementsCollection; -import net.runelite.client.plugins.cluescrolls.clues.emote.AnyRequirementCollection; -import net.runelite.client.plugins.cluescrolls.clues.emote.Emote; -import static net.runelite.client.plugins.cluescrolls.clues.emote.Emote.*; -import static net.runelite.client.plugins.cluescrolls.clues.emote.Emote.BULL_ROARER; -import net.runelite.client.plugins.cluescrolls.clues.emote.ItemRequirement; -import net.runelite.client.plugins.cluescrolls.clues.emote.RangeItemRequirement; -import static net.runelite.client.plugins.cluescrolls.clues.emote.STASHUnit.*; -import static net.runelite.client.plugins.cluescrolls.clues.emote.STASHUnit.SHANTAY_PASS; -import net.runelite.client.plugins.cluescrolls.clues.emote.SingleItemRequirement; -import net.runelite.client.plugins.cluescrolls.clues.emote.SlotLimitationRequirement; -import net.runelite.client.ui.overlay.OverlayUtil; -import net.runelite.client.ui.overlay.components.LineComponent; -import net.runelite.client.ui.overlay.components.PanelComponent; -import net.runelite.client.ui.overlay.components.TitleComponent; - -@Getter -public class EmoteClue extends ClueScroll implements TextClueScroll, LocationClueScroll -{ - private static final Set CLUES = ImmutableSet.of( - new EmoteClue("Beckon on the east coast of the Kharazi Jungle. Beware of double agents! Equip any vestment stole and a heraldic rune shield.", NORTHEAST_CORNER_OF_THE_KHARAZI_JUNGLE, new WorldPoint(2954, 2933, 0), BECKON, any("Any stole", item(GUTHIX_STOLE), item(SARADOMIN_STOLE), item(ZAMORAK_STOLE), item(ARMADYL_STOLE), item(BANDOS_STOLE), item(ANCIENT_STOLE)), any("Any heraldic rune shield", item(RUNE_SHIELD_H1), item(RUNE_SHIELD_H2), item(RUNE_SHIELD_H3), item(RUNE_SHIELD_H4), item(RUNE_SHIELD_H5))), - new EmoteClue("Cheer in the Barbarian Agility Arena. Headbang before you talk to me. Equip a steel platebody, maple shortbow and a Wilderness cape.", BARBARIAN_OUTPOST_OBSTACLE_COURSE, new WorldPoint(2552, 3556, 0), CHEER, HEADBANG, item(STEEL_PLATEBODY), item(MAPLE_SHORTBOW), range("Any team cape", TEAM1_CAPE, TEAM50_CAPE)), - new EmoteClue("Bow upstairs in the Edgeville Monastery. Equip a completed prayer book.", SOUTHEAST_CORNER_OF_THE_MONASTERY, new WorldPoint(3056, 3484, 1), BOW, any("Any god book", item(HOLY_BOOK), item(BOOK_OF_BALANCE), item(UNHOLY_BOOK), item(BOOK_OF_LAW), item(BOOK_OF_WAR), item(BOOK_OF_DARKNESS))), - new EmoteClue("Cheer in the Shadow dungeon. Equip a rune crossbow, climbing boots and any mitre.", ENTRANCE_OF_THE_CAVE_OF_DAMIS, new WorldPoint(2629, 5071, 0), CHEER, any("Any mitre", item(GUTHIX_MITRE), item(SARADOMIN_MITRE), item(ZAMORAK_MITRE), item(ANCIENT_MITRE), item(BANDOS_MITRE), item(ARMADYL_MITRE)), item(RUNE_CROSSBOW), item(CLIMBING_BOOTS), item(RING_OF_VISIBILITY)), - new EmoteClue("Cheer at the top of the agility pyramid. Beware of double agents! Equip a blue mystic robe top, and any rune heraldic shield.", AGILITY_PYRAMID, new WorldPoint(3043, 4697, 3), CHEER, item(MYSTIC_ROBE_TOP), any("Any rune heraldic shield", item(RUNE_SHIELD_H1), item(RUNE_SHIELD_H2), item(RUNE_SHIELD_H3), item(RUNE_SHIELD_H4), item(RUNE_SHIELD_H5))), - new EmoteClue("Dance in Iban's temple. Beware of double agents! Equip Iban's staff, a black mystic top and a black mystic bottom.", WELL_OF_VOYAGE, new WorldPoint(2011, 4712, 0), DANCE, any("Any iban's staff", item(IBANS_STAFF), item(IBANS_STAFF_U)), item(MYSTIC_ROBE_TOP_DARK), item(MYSTIC_ROBE_BOTTOM_DARK)), - new EmoteClue("Dance on the Fishing Platform. Equip barrows gloves, an amulet of glory and a dragon med helm.", SOUTHEAST_CORNER_OF_THE_FISHING_PLATFORM, new WorldPoint(2782, 3273, 0), DANCE, any("Any amulet of glory", item(AMULET_OF_GLORY), item(AMULET_OF_GLORY1), item(AMULET_OF_GLORY2), item(AMULET_OF_GLORY3), item(AMULET_OF_GLORY4), item(AMULET_OF_GLORY5), item(AMULET_OF_GLORY6)), item(BARROWS_GLOVES), item(DRAGON_MED_HELM)), - new EmoteClue("Flap at the death altar. Beware of double agents! Equip a death tiara, a legend's cape and any ring of wealth.", DEATH_ALTAR, new WorldPoint(2205, 4838, 0), FLAP, any("Any ring of wealth", item(RING_OF_WEALTH), item(RING_OF_WEALTH_1), item(RING_OF_WEALTH_2), item(RING_OF_WEALTH_3), item(RING_OF_WEALTH_4), item(RING_OF_WEALTH_5), item(RING_OF_WEALTH_I), item(RING_OF_WEALTH_I1), item(RING_OF_WEALTH_I2), item(RING_OF_WEALTH_I3), item(RING_OF_WEALTH_I4), item(RING_OF_WEALTH_I5)), item(DEATH_TIARA), item(CAPE_OF_LEGENDS)), - new EmoteClue("Headbang in the Fight Arena pub. Equip a pirate bandana, a dragonstone necklace and and a magic longbow.", OUTSIDE_THE_BAR_BY_THE_FIGHT_ARENA, new WorldPoint(2568, 3149, 0), HEADBANG, any("Any pirate bandana", item(PIRATE_BANDANA), item(PIRATE_BANDANA_7124), item(PIRATE_BANDANA_7130), item(PIRATE_BANDANA_7136)), item(DRAGON_NECKLACE), item(MAGIC_LONGBOW)), - new EmoteClue("Do a jig at the barrow's chest. Beware of double agents! Equip any full barrows set.", BARROWS_CHEST, new WorldPoint(3551, 9694, 0), JIG, any("Any full barrows set", all(range(AHRIMS_HOOD_100, AHRIMS_HOOD_0), range(AHRIMS_STAFF_100, AHRIMS_STAFF_0), range(AHRIMS_ROBETOP_100, AHRIMS_ROBETOP_0), range(AHRIMS_ROBESKIRT_100, AHRIMS_ROBESKIRT_0)), all(range(DHAROKS_HELM_100, DHAROKS_HELM_0), range(DHAROKS_GREATAXE_100, DHAROKS_GREATAXE_0), range(DHAROKS_PLATEBODY_100, DHAROKS_PLATEBODY_0), range(DHAROKS_PLATELEGS_100, DHAROKS_PLATELEGS_0)), all(range(GUTHANS_HELM_100, GUTHANS_HELM_0), range(GUTHANS_WARSPEAR_100, GUTHANS_WARSPEAR_0), range(GUTHANS_PLATEBODY_100, GUTHANS_PLATEBODY_0), range(GUTHANS_CHAINSKIRT_100, GUTHANS_CHAINSKIRT_0)), all(range(KARILS_COIF_100, KARILS_COIF_0), range(KARILS_CROSSBOW_100, KARILS_CROSSBOW_0), range(KARILS_LEATHERTOP_100, KARILS_LEATHERTOP_0), range(KARILS_LEATHERSKIRT_100, KARILS_LEATHERSKIRT_0)), all(range(TORAGS_HELM_100, TORAGS_HELM_0), range(TORAGS_HAMMERS_100, TORAGS_HAMMERS_0), range(TORAGS_PLATEBODY_100, TORAGS_PLATEBODY_0), range(TORAGS_PLATELEGS_100, TORAGS_PLATELEGS_0)), all(range(VERACS_HELM_100, VERACS_HELM_0), range(VERACS_FLAIL_100, VERACS_FLAIL_0), range(VERACS_BRASSARD_100, VERACS_BRASSARD_0), range(VERACS_PLATESKIRT_100, VERACS_PLATESKIRT_0)))), - new EmoteClue("Jig at Jiggig. Beware of double agents! Equip a Rune spear, rune platelegs and any rune heraldic helm.", IN_THE_MIDDLE_OF_JIGGIG, new WorldPoint(2477, 3047, 0), JIG, range("Any rune heraldic helm", RUNE_HELM_H1, RUNE_HELM_H5), item(RUNE_SPEAR), item(RUNE_PLATELEGS)), - new EmoteClue("Cheer at the games room. Have nothing equipped at all when you do.", null, new WorldPoint(2207, 4952, 0), CHEER, emptySlot("Nothing at all", HEAD, CAPE, AMULET, WEAPON, BODY, SHIELD, LEGS, GLOVES, BOOTS, RING, AMMO)), - new EmoteClue("Panic on the pier where you catch the Fishing trawler. Have nothing equipped at all when you do.", null, new WorldPoint(2676, 3169, 0), PANIC, emptySlot("Nothing at all", HEAD, CAPE, AMULET, WEAPON, BODY, SHIELD, LEGS, GLOVES, BOOTS, RING, AMMO)), - new EmoteClue("Panic in the heart of the Haunted Woods. Beware of double agents! Have no items equipped when you do.", null, new WorldPoint(3611, 3492, 0), PANIC, emptySlot("Nothing at all", HEAD, CAPE, AMULET, WEAPON, BODY, SHIELD, LEGS, GLOVES, BOOTS, RING, AMMO)), - 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(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)), - new EmoteClue("Bow on the ground floor of the Legend's guild. Equip Legend's cape, a dragon battleaxe and an amulet of glory.", OUTSIDE_THE_LEGENDS_GUILD_DOOR, new WorldPoint(2728, 3377, 0), BOW, item(CAPE_OF_LEGENDS), item(DRAGON_BATTLEAXE), any("Any amulet of glory", item(AMULET_OF_GLORY), item(AMULET_OF_GLORY1), item(AMULET_OF_GLORY2), item(AMULET_OF_GLORY3), item(AMULET_OF_GLORY4), item(AMULET_OF_GLORY5), item(AMULET_OF_GLORY6))), - new EmoteClue("Bow in the ticket office of the Duel Arena. Equip an iron chain body, leather chaps and coif.", MUBARIZS_ROOM_AT_THE_DUEL_ARENA, new WorldPoint(3314, 3241, 0), BOW, item(IRON_CHAINBODY), item(LEATHER_CHAPS), item(COIF)), - new EmoteClue("Bow at the top of the lighthouse. Beware of double agents! Equip a blue dragonhide body, blue dragonhide vambraces and no jewelry.", TOP_FLOOR_OF_THE_LIGHTHOUSE, new WorldPoint(2511, 3641, 2), BOW, item(BLUE_DHIDE_BODY), item(BLUE_DHIDE_VAMB), emptySlot("No jewelry", AMULET, RING)), - new EmoteClue("Blow a kiss between the tables in Shilo Village bank. Beware of double agents! Equip a blue mystic hat, bone spear and rune platebody.", SHILO_VILLAGE_BANK, new WorldPoint(2851, 2954, 0), BLOW_KISS, item(MYSTIC_HAT), item(BONE_SPEAR), item(RUNE_PLATEBODY)), - new EmoteClue("Blow a kiss in the heart of the lava maze. Equip black dragonhide chaps, a spotted cape and a rolling pin.", NEAR_A_LADDER_IN_THE_WILDERNESS_LAVA_MAZE, new WorldPoint(3069, 3861, 0), BLOW_KISS, item(BLACK_DHIDE_CHAPS), any("Spotted cape", item(SPOTTED_CAPE), item(SPOTTED_CAPE_10073)), item(ROLLING_PIN)), - new EmoteClue("Blow a kiss outside K'ril Tsutsaroth's chamber. Beware of double agents! Equip a zamorak full helm and the shadow sword.", OUTSIDE_KRIL_TSUTSAROTHS_ROOM, new WorldPoint(2925, 5333, 0), BLOW_KISS, item(ZAMORAK_FULL_HELM), item(SHADOW_SWORD)), - new EmoteClue("Cheer at the Druids' Circle. Equip a blue wizard hat, a bronze two-handed sword and HAM boots.", TAVERLEY_STONE_CIRCLE, new WorldPoint(2924, 3478, 0), CHEER, item(BLUE_WIZARD_HAT), item(BRONZE_2H_SWORD), item(HAM_BOOTS)), - new EmoteClue("Cheer in the Edgeville general store. Dance before you talk to me. Equip a brown apron, leather boots and leather gloves.", NORTH_OF_EVIL_DAVES_HOUSE_IN_EDGEVILLE, new WorldPoint(3080, 3509, 0), CHEER, DANCE, item(BROWN_APRON), item(LEATHER_BOOTS), item(LEATHER_GLOVES)), - new EmoteClue("Cheer in the Ogre Pen in the Training Camp. Show you are angry before you talk to me. Equip a green dragonhide body and chaps and a steel square shield.", OGRE_CAGE_IN_KING_LATHAS_TRAINING_CAMP, new WorldPoint(2527, 3375, 0), CHEER, ANGRY, item(GREEN_DHIDE_BODY), item(GREEN_DHIDE_CHAPS), item(STEEL_SQ_SHIELD)), - new EmoteClue("Cheer in the Entrana church. Beware of double agents! Equip a full set of black dragonhide armour.", ENTRANA_CHAPEL, new WorldPoint(2852, 3349, 0), CHEER, item(BLACK_DHIDE_VAMB), item(BLACK_DHIDE_CHAPS), item(BLACK_DHIDE_BODY)), - new EmoteClue("Cheer for the monks at Port Sarim. Equip a coif, steel plateskirt and a sapphire necklace.", NEAR_THE_ENTRANA_FERRY_IN_PORT_SARIM, new WorldPoint(3047, 3237, 0), CHEER, item(COIF), item(STEEL_PLATESKIRT), item(SAPPHIRE_NECKLACE)), - new EmoteClue("Clap in the main exam room in the Exam Centre. Equip a white apron, green gnome boots and leather gloves.", INSIDE_THE_DIGSITE_EXAM_CENTRE, new WorldPoint(3361, 3339, 0), CLAP, item(WHITE_APRON), item(GREEN_BOOTS), item(LEATHER_GLOVES)), - new EmoteClue("Clap on the causeway to the Wizards' Tower. Equip an iron medium helmet, emerald ring and a white apron.", ON_THE_BRIDGE_TO_THE_MISTHALIN_WIZARDS_TOWER, new WorldPoint(3113, 3196, 0), CLAP, item(IRON_MED_HELM), item(EMERALD_RING), item(WHITE_APRON)), - new EmoteClue("Clap on the top level of the mill, north of East Ardougne. Equip a blue gnome robe top, HAM robe bottom and an unenchanted tiara.", UPSTAIRS_IN_THE_ARDOUGNE_WINDMILL, new WorldPoint(2635, 3385, 3), CLAP, item(BLUE_ROBE_TOP), item(HAM_ROBE), item(TIARA)), - new EmoteClue("Clap in Seers court house. Spin before you talk to me. Equip an adamant halberd, blue mystic robe bottom and a diamond ring.", OUTSIDE_THE_SEERS_VILLAGE_COURTHOUSE, new WorldPoint(2735, 3469, 0), CLAP, SPIN, item(ADAMANT_HALBERD), item(MYSTIC_ROBE_BOTTOM), item(DIAMOND_RING)), - new EmoteClue("Clap in the magic axe hut. Beware of double agents! Equip only some flared trousers.", OUTSIDE_THE_WILDERNESS_AXE_HUT, new WorldPoint(3191, 3960, 0), CLAP, item(FLARED_TROUSERS), item(LOCKPICK), emptySlot("Nothing else", HEAD, CAPE, AMULET, WEAPON, BODY, SHIELD, GLOVES, BOOTS, RING, AMMO)), - new EmoteClue("Clap your hands north of Mount Karuulm Spin before you talk to me. Equip an adamant warhammer, a ring of life and a pair of mithril boots.", NORTH_OF_MOUNT_KARUULM, new WorldPoint(1306, 3839, 0), CLAP, SPIN, item(ADAMANT_WARHAMMER), item(RING_OF_LIFE), item(MITHRIL_BOOTS)), - new EmoteClue("Cry in the Catherby Ranging shop. Bow before you talk to me. Equip blue gnome boots, a hard leather body and an unblessed silver sickle.", HICKTONS_ARCHERY_EMPORIUM, new WorldPoint(2823, 3443, 0), CRY, BOW, item(BLUE_BOOTS), item(HARDLEATHER_BODY), item(SILVER_SICKLE)), - new EmoteClue("Cry on the shore of Catherby beach. Laugh before you talk to me, equip an adamant sq shield, a bone dagger and mithril platebody.", OUTSIDE_HARRYS_FISHING_SHOP_IN_CATHERBY, new WorldPoint(2852, 3429, 0), CRY, LAUGH, item(ADAMANT_SQ_SHIELD), item(BONE_DAGGER), item(MITHRIL_PLATEBODY)), - new EmoteClue("Cry on top of the western tree in the Gnome Agility Arena. Indicate 'no' before you talk to me. Equip a steel kiteshield, ring of forging and green dragonhide chaps.", GNOME_STRONGHOLD_BALANCING_ROPE, new WorldPoint(2473, 3420, 2), CRY, NO, item(STEEL_KITESHIELD), item(RING_OF_FORGING), item(GREEN_DHIDE_CHAPS)), - new EmoteClue("Cry in the TzHaar gem store. Beware of double agents! Equip a fire cape and TokTz-Xil-Ul.", TZHAAR_GEM_STORE, new WorldPoint(2463, 5149, 0), CRY, any("Fire cape", item(FIRE_CAPE), item(FIRE_MAX_CAPE)), item(TOKTZXILUL)), - new EmoteClue("Cry in the Draynor Village jail. Jump for joy before you talk to me. Equip an adamant sword, a sapphire amulet and an adamant plateskirt.", OUTSIDE_DRAYNOR_VILLAGE_JAIL, new WorldPoint(3128, 3245, 0), CRY, JUMP_FOR_JOY, item(ADAMANT_SWORD), item(SAPPHIRE_AMULET), item(ADAMANT_PLATESKIRT)), - new EmoteClue("Dance at the crossroads north of Draynor. Equip an iron chain body, a sapphire ring and a longbow.", CROSSROADS_NORTH_OF_DRAYNOR_VILLAGE, new WorldPoint(3109, 3294, 0), DANCE, item(IRON_CHAINBODY), item(SAPPHIRE_RING), item(LONGBOW)), - new EmoteClue("Dance in the Party Room. Equip a steel full helmet, steel platebody and an iron plateskirt.", OUTSIDE_THE_FALADOR_PARTY_ROOM, new WorldPoint(3045, 3376, 0), DANCE, item(STEEL_FULL_HELM), item(STEEL_PLATEBODY), item(IRON_PLATESKIRT)), - new EmoteClue("Dance in the shack in Lumbridge Swamp. Equip a bronze dagger, iron full helmet and a gold ring.", NEAR_A_SHED_IN_LUMBRIDGE_SWAMP, new WorldPoint(3203, 3169, 0), DANCE, item(BRONZE_DAGGER), item(IRON_FULL_HELM), item(GOLD_RING)), - new EmoteClue("Dance in the dark caves beneath Lumbridge Swamp. Blow a kiss before you talk to me. Equip an air staff, Bronze full helm and an amulet of power.", LUMBRIDGE_SWAMP_CAVES, new WorldPoint(3168, 9571, 0), DANCE, BLOW_KISS, item(STAFF_OF_AIR), item(BRONZE_FULL_HELM), item(AMULET_OF_POWER)), - new EmoteClue("Dance at the cat-doored pyramid in Sophanem. Beware of double agents! Equip a ring of life, an uncharged amulet of glory and an adamant two-handed sword.", OUTSIDE_THE_GREAT_PYRAMID_OF_SOPHANEM, new WorldPoint(3294, 2781, 0), DANCE, item(RING_OF_LIFE), item(AMULET_OF_GLORY), item(ADAMANT_2H_SWORD)), - new EmoteClue("Dance in the centre of Canifis. Bow before you talk to me. Equip a green gnome robe top, mithril plate legs and an iron two-handed sword.", CENTRE_OF_CANIFIS, new WorldPoint(3492, 3488, 0), DANCE, BOW, item(GREEN_ROBE_TOP), item(MITHRIL_PLATELEGS), item(IRON_2H_SWORD)), - new EmoteClue("Dance in the King Black Dragon's lair. Beware of double agents! Equip a black dragonhide body, black dragonhide vambs and a black dragon mask.", KING_BLACK_DRAGONS_LAIR, new WorldPoint(2271, 4680, 0), DANCE, item(BLACK_DHIDE_BODY), item(BLACK_DHIDE_VAMB), item(BLACK_DRAGON_MASK)), - new EmoteClue("Dance at the entrance to the Grand Exchange. Equip a pink skirt, pink robe top and a body tiara.", SOUTH_OF_THE_GRAND_EXCHANGE, new WorldPoint(3165, 3467, 0), DANCE, item(PINK_SKIRT), item(PINK_ROBE_TOP), item(BODY_TIARA)), - new EmoteClue("Goblin Salute in the Goblin Village. Beware of double agents! Equip a bandos godsword, a bandos cloak and a bandos platebody.", OUTSIDE_MUDKNUCKLES_HUT, new WorldPoint(2956, 3505, 0), GOBLIN_SALUTE, item(BANDOS_PLATEBODY), item(BANDOS_CLOAK), item(BANDOS_GODSWORD)), - new EmoteClue("Headbang in the mine north of Al Kharid. Equip a desert shirt, leather gloves and leather boots.", AL_KHARID_SCORPION_MINE, new WorldPoint(3299, 3289, 0), HEADBANG, item(DESERT_SHIRT), item(LEATHER_GLOVES), item(LEATHER_BOOTS)), - new EmoteClue("Headbang at the exam center. Beware of double agents! Equip a mystic fire staff, a diamond bracelet and rune boots.", OUTSIDE_THE_DIGSITE_EXAM_CENTRE, new WorldPoint(3362, 3340, 0), HEADBANG, item(MYSTIC_FIRE_STAFF), item(DIAMOND_BRACELET), item(RUNE_BOOTS)), - new EmoteClue("Headbang at the top of Slayer Tower. Equip a seercull, a combat bracelet and helm of Neitiznot.", OUTSIDE_THE_SLAYER_TOWER_GARGOYLE_ROOM, new WorldPoint(3421, 3537, 2), HEADBANG, item(SEERCULL), range("Combat bracelet", COMBAT_BRACELET4, COMBAT_BRACELET), item(HELM_OF_NEITIZNOT)), - new EmoteClue("Dance a jig by the entrance to the Fishing Guild. Equip an emerald ring, a sapphire amulet, and a bronze chain body.", OUTSIDE_THE_FISHING_GUILD, new WorldPoint(2610, 3391, 0), JIG, item(EMERALD_RING), item(SAPPHIRE_AMULET), item(BRONZE_CHAINBODY)), - new EmoteClue("Dance a jig under Shantay's Awning. Bow before you talk to me. Equip a pointed blue snail helmet, an air staff and a bronze square shield.", SHANTAY_PASS, new WorldPoint(3304, 3124, 0), JIG, BOW, any("Bruise blue snelm (pointed)", item(BRUISE_BLUE_SNELM_3343)), item(STAFF_OF_AIR), item(BRONZE_SQ_SHIELD)), - new EmoteClue("Do a jig in Varrock's rune store. Equip an air tiara and a staff of water.", AUBURYS_SHOP_IN_VARROCK, new WorldPoint(3253, 3401, 0), JIG, item(AIR_TIARA), item(STAFF_OF_WATER)), - new EmoteClue("Jump for joy at the beehives. Equip a desert shirt, green gnome robe bottoms and a steel axe.", CATHERBY_BEEHIVE_FIELD, new WorldPoint(2759, 3445, 0), JUMP_FOR_JOY, item(DESERT_SHIRT), item(GREEN_ROBE_BOTTOMS), item(STEEL_AXE)), - new EmoteClue("Jump for joy in Yanille bank. Dance a jig before you talk to me. Equip a brown apron, adamantite medium helmet and snakeskin chaps.", OUTSIDE_YANILLE_BANK, new WorldPoint(2610, 3092, 0), JUMP_FOR_JOY, JIG, item(BROWN_APRON), item(ADAMANT_MED_HELM), item(SNAKESKIN_CHAPS)), - new EmoteClue("Jump for joy in the TzHaar sword shop. Shrug before you talk to me. Equip a Steel longsword, Blue D'hide body and blue mystic gloves.", TZHAAR_WEAPONS_STORE, new WorldPoint(2477, 5146, 0), JUMP_FOR_JOY, SHRUG, item(STEEL_LONGSWORD), item(BLUE_DHIDE_BODY), item(MYSTIC_GLOVES)), - new EmoteClue("Jump for joy in the Ancient Cavern. Equip a granite shield, splitbark body and any rune heraldic helm.", ENTRANCE_OF_THE_CAVERN_UNDER_THE_WHIRLPOOL, new WorldPoint(1768, 5366, 1), JUMP_FOR_JOY, item(GRANITE_SHIELD), item(SPLITBARK_BODY), range("Any rune heraldic helm", RUNE_HELM_H1, RUNE_HELM_H5)), - new EmoteClue("Jump for joy at the Neitiznot rune rock. Equip Rune boots, a proselyte hauberk and a dragonstone ring.", NEAR_A_RUNITE_ROCK_IN_THE_FREMENNIK_ISLES, new WorldPoint(2375, 3850, 0), JUMP_FOR_JOY, item(RUNE_BOOTS), item(PROSELYTE_HAUBERK), item(DRAGONSTONE_RING)), - new EmoteClue("Jump for joy in the centre of Zul-Andra. Beware of double agents! Equip a dragon 2h sword, bandos boots and an obsidian cape.", NEAR_THE_PIER_IN_ZULANDRA, new WorldPoint(2199, 3056, 0), JUMP_FOR_JOY, item(DRAGON_2H_SWORD), item(BANDOS_BOOTS), item(OBSIDIAN_CAPE)), - new EmoteClue("Laugh by the fountain of heroes. Equip splitbark legs, dragon boots and a Rune longsword.", FOUNTAIN_OF_HEROES, new WorldPoint(2920, 9893, 0), LAUGH, item(SPLITBARK_LEGS), item(DRAGON_BOOTS), item(RUNE_LONGSWORD)), - new EmoteClue("Laugh in Jokul's tent in the Mountain Camp. Beware of double agents! Equip a rune full helmet, blue dragonhide chaps and a fire battlestaff.", MOUNTAIN_CAMP_GOAT_ENCLOSURE, new WorldPoint(2812, 3681, 0), LAUGH, item(RUNE_FULL_HELM), item(BLUE_DHIDE_CHAPS), item(FIRE_BATTLESTAFF)), - new EmoteClue("Laugh at the crossroads south of the Sinclair Mansion. Equip a cowl, a blue wizard robe top and an iron scimitar.", ROAD_JUNCTION_SOUTH_OF_SINCLAIR_MANSION, new WorldPoint(2741, 3536, 0), LAUGH, item(LEATHER_COWL), item(BLUE_WIZARD_ROBE), item(IRON_SCIMITAR)), - new EmoteClue("Laugh in front of the gem store in Ardougne market. Equip a Castlewars bracelet, a dragonstone amulet and a ring of forging.", NEAR_THE_GEM_STALL_IN_ARDOUGNE_MARKET, new WorldPoint(2666, 3304, 0), LAUGH, any("Castle wars bracelet", range(CASTLE_WARS_BRACELET3, CASTLE_WARS_BRACELET1)), item(DRAGONSTONE_AMULET), item(RING_OF_FORGING)), - new EmoteClue("Panic in the Limestone Mine. Equip bronze platelegs, a steel pickaxe and a steel medium helmet.", LIMESTONE_MINE, new WorldPoint(3372, 3498, 0), PANIC, item(BRONZE_PLATELEGS), item(STEEL_PICKAXE), item(STEEL_MED_HELM)), - new EmoteClue("Panic by the mausoleum in Morytania. Wave before you speak to me. Equip a mithril plate skirt, a maple longbow and no boots.", MAUSOLEUM_OFF_THE_MORYTANIA_COAST, new WorldPoint(3504, 3576, 0), PANIC, WAVE, item(MITHRIL_PLATESKIRT), item(MAPLE_LONGBOW), emptySlot("No boots", BOOTS)), - new EmoteClue("Panic on the Wilderness volcano bridge. Beware of double agents! Equip any headband and crozier.", VOLCANO_IN_THE_NORTHEASTERN_WILDERNESS, new WorldPoint(3368, 3935, 0), PANIC, any("Any headband", range(RED_HEADBAND, BROWN_HEADBAND), range(WHITE_HEADBAND, GREEN_HEADBAND)), any("Any crozier", item(ANCIENT_CROZIER), item(ARMADYL_CROZIER), item(BANDOS_CROZIER), range(SARADOMIN_CROZIER, ZAMORAK_CROZIER))), - 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), 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)), - new EmoteClue("Salute in the banana plantation. Beware of double agents! Equip a diamond ring, amulet of power, and nothing on your chest and legs.", WEST_SIDE_OF_THE_KARAMJA_BANANA_PLANTATION, new WorldPoint(2914, 3168, 0), SALUTE, item(DIAMOND_RING), item(AMULET_OF_POWER), emptySlot("Nothing on chest & legs", BODY, LEGS)), - new EmoteClue("Salute in the Warriors' guild bank. Equip only a black salamander.", WARRIORS_GUILD_BANK, new WorldPoint(2844, 3542, 0), SALUTE, item(BLACK_SALAMANDER), emptySlot("Nothing else", HEAD, CAPE, AMULET, BODY, SHIELD, LEGS, GLOVES, BOOTS, RING, AMMO)), - new EmoteClue("Salute in the centre of the mess hall. Beware of double agents! Equip a rune halberd rune platebody, and an amulet of strength.", HOSIDIUS_MESS, new WorldPoint(1646, 3632, 0), SALUTE, item(RUNE_HALBERD), item(RUNE_PLATEBODY), item(AMULET_OF_STRENGTH)), - new EmoteClue("Shrug in the mine near Rimmington. Equip a gold necklace, a gold ring and a bronze spear.", RIMMINGTON_MINE, new WorldPoint(2976, 3238, 0), SHRUG, item(GOLD_NECKLACE), item(GOLD_RING), item(BRONZE_SPEAR)), - new EmoteClue("Shrug in Catherby bank. Yawn before you talk to me. Equip a maple longbow, green d'hide chaps and an iron med helm.", OUTSIDE_CATHERBY_BANK, new WorldPoint(2808, 3440, 0), SHRUG, YAWN, item(MAPLE_LONGBOW), item(GREEN_DHIDE_CHAPS), item(IRON_MED_HELM)), - new EmoteClue("Shrug in the Zamorak temple found in the Eastern Wilderness. Beware of double agents! Equip rune platelegs, an iron platebody and blue dragonhide vambraces.", CHAOS_TEMPLE_IN_THE_SOUTHEASTERN_WILDERNESS, new WorldPoint(3239, 3611, 0), SHRUG, item(RUNE_PLATELEGS), item(IRON_PLATEBODY), item(BLUE_DHIDE_VAMB)), - new EmoteClue("Shrug in the Shayzien command tent. Equip a blue mystic robe bottom, a rune kiteshield and any bob shirt.", SHAYZIEN_WAR_TENT, new WorldPoint(1555, 3537, 0), SHRUG, item(MYSTIC_ROBE_BOTTOM), item(RUNE_KITESHIELD), range("Any bob shirt", BOBS_RED_SHIRT, BOBS_PURPLE_SHIRT)), - new EmoteClue("Slap your head in the centre of the Kourend catacombs. Beware of double agents! Equip the arclight and the amulet of the damned.", CENTRE_OF_THE_CATACOMBS_OF_KOUREND, new WorldPoint(1663, 10045, 0), SLAP_HEAD, item(ARCLIGHT), any("Amulet of the damned", item(AMULET_OF_THE_DAMNED), item(AMULET_OF_THE_DAMNED_FULL))), - new EmoteClue("Spin at the crossroads north of Rimmington. Equip a green gnome hat, cream gnome top and leather chaps.", ROAD_JUNCTION_NORTH_OF_RIMMINGTON, new WorldPoint(2981, 3276, 0), SPIN, item(GREEN_HAT), item(CREAM_ROBE_TOP), item(LEATHER_CHAPS)), - new EmoteClue("Spin in Draynor Manor by the fountain. Equip an iron platebody, studded leather chaps and a bronze full helmet.", DRAYNOR_MANOR_BY_THE_FOUNTAIN, new WorldPoint(3088, 3336, 0), SPIN, item(IRON_PLATEBODY), item(STUDDED_CHAPS), item(BRONZE_FULL_HELM)), - new EmoteClue("Spin in front of the Soul altar. Beware of double agents! Equip a dragon pickaxe, helm of neitiznot and a pair of rune boots.", SOUL_ALTAR, new WorldPoint(1815, 3856, 0), SPIN, any("Dragon pickaxe", item(DRAGON_PICKAXE), item(DRAGON_PICKAXE_12797), item(INFERNAL_PICKAXE), item(INFERNAL_PICKAXE_UNCHARGED)), item(HELM_OF_NEITIZNOT), item(RUNE_BOOTS)), - new EmoteClue("Spin in the Varrock Castle courtyard. Equip a black axe, a coif and a ruby ring.", OUTSIDE_VARROCK_PALACE_COURTYARD, new WorldPoint(3213, 3463, 0), SPIN, item(BLACK_AXE), item(COIF), item(RUBY_RING)), - new EmoteClue("Spin in West Ardougne Church. Equip a dragon spear and red dragonhide chaps.", CHAPEL_IN_WEST_ARDOUGNE, new WorldPoint(2530, 3290, 0), SPIN, item(DRAGON_SPEAR), item(RED_DHIDE_CHAPS)), - new EmoteClue("Spin on the bridge by the Barbarian Village. Salute before you talk to me. Equip purple gloves, a steel kiteshield and a mithril full helmet.", EAST_OF_THE_BARBARIAN_VILLAGE_BRIDGE, new WorldPoint(3105, 3420, 0), SPIN, SALUTE, item(PURPLE_GLOVES), item(STEEL_KITESHIELD), item(MITHRIL_FULL_HELM)), - new EmoteClue("Stamp in the Enchanted valley west of the waterfall. Beware of double agents! Equip a dragon axe.", NORTHWESTERN_CORNER_OF_THE_ENCHANTED_VALLEY, new WorldPoint(3030, 4522, 0), STOMP, item(DRAGON_AXE)), - new EmoteClue("Think in middle of the wheat field by the Lumbridge mill. Equip a blue gnome robetop, a turquoise gnome robe bottom and an oak shortbow.", WHEAT_FIELD_NEAR_THE_LUMBRIDGE_WINDMILL, new WorldPoint(3159, 3298, 0), THINK, item(BLUE_ROBE_TOP), item(TURQUOISE_ROBE_BOTTOMS), item(OAK_SHORTBOW)), - new EmoteClue("Think in the centre of the Observatory. Spin before you talk to me. Equip a mithril chain body, green dragonhide chaps and a ruby amulet.", OBSERVATORY, new WorldPoint(2439, 3161, 0), THINK, SPIN, item(MITHRIL_CHAINBODY), item(GREEN_DHIDE_CHAPS), item(RUBY_AMULET)), - new EmoteClue("Wave along the south fence of the Lumber Yard. Equip a hard leather body, leather chaps and a bronze axe.", NEAR_THE_SAWMILL_OPERATORS_BOOTH, new WorldPoint(3307, 3491, 0), WAVE, item(HARDLEATHER_BODY), item(LEATHER_CHAPS), item(BRONZE_AXE)), - new EmoteClue("Wave in the Falador gem store. Equip a Mithril pickaxe, Black platebody and an Iron Kiteshield.", NEAR_HERQUINS_SHOP_IN_FALADOR, new WorldPoint(2945, 3335, 0), WAVE, item(MITHRIL_PICKAXE), item(BLACK_PLATEBODY), item(IRON_KITESHIELD)), - new EmoteClue("Wave on Mudskipper Point. Equip a black cape, leather chaps and a steel mace.", MUDSKIPPER_POINT, new WorldPoint(2989, 3110, 0), WAVE, item(BLACK_CAPE), item(LEATHER_CHAPS), item(STEEL_MACE)), - new EmoteClue("Wave on the northern wall of Castle Drakan. Beware of double agents! Wear a dragon sq shield, splitbark body and any boater.", NORTHERN_WALL_OF_CASTLE_DRAKAN, new WorldPoint(3560, 3385, 0), WAVE, item(DRAGON_SQ_SHIELD), item(SPLITBARK_BODY), any("Any boater", item(RED_BOATER), item(ORANGE_BOATER), item(GREEN_BOATER), item(BLUE_BOATER), item(BLACK_BOATER), item(PINK_BOATER), item(PURPLE_BOATER), item(WHITE_BOATER))), - new EmoteClue("Yawn in the 7th room of Pyramid Plunder. Beware of double agents! Equip a pharaoh sceptre and a full set of menaphite robes.", _7TH_CHAMBER_OF_JALSAVRAH, new WorldPoint(1944, 4427, 0), YAWN, any("Pharaoh's sceptre", item(PHARAOHS_SCEPTRE), item(PHARAOHS_SCEPTRE_1), item(PHARAOHS_SCEPTRE_2), item(PHARAOHS_SCEPTRE_3), item(PHARAOHS_SCEPTRE_4), item(PHARAOHS_SCEPTRE_5), item(PHARAOHS_SCEPTRE_6), item(PHARAOHS_SCEPTRE_7), item(PHARAOHS_SCEPTRE_8)), any("Full set of menaphite robes", all(item(MENAPHITE_PURPLE_HAT), item(MENAPHITE_PURPLE_TOP), range(MENAPHITE_PURPLE_ROBE, MENAPHITE_PURPLE_KILT)), all(item(MENAPHITE_RED_HAT), item(MENAPHITE_RED_TOP), range(MENAPHITE_RED_ROBE, MENAPHITE_RED_KILT)))), - new EmoteClue("Yawn in the Varrock library. Equip a green gnome robe top, HAM robe bottom and an iron warhammer.", VARROCK_PALACE_LIBRARY, new WorldPoint(3209, 3492, 0), YAWN, item(GREEN_ROBE_TOP), item(HAM_ROBE), item(IRON_WARHAMMER)), - new EmoteClue("Yawn in Draynor Marketplace. Equip studded leather chaps, an iron kiteshield and a steel longsword.", DRAYNOR_VILLAGE_MARKET, new WorldPoint(3083, 3253, 0), YAWN, item(STUDDED_CHAPS), item(IRON_KITESHIELD), item(STEEL_LONGSWORD)), - new EmoteClue("Yawn in the Castle Wars lobby. Shrug before you talk to me. Equip a ruby amulet, a mithril scimitar and a Wilderness cape.", CASTLE_WARS_BANK, new WorldPoint(2440, 3092, 0), YAWN, SHRUG, item(RUBY_AMULET), item(MITHRIL_SCIMITAR), range("Any team cape", TEAM1_CAPE, TEAM50_CAPE)), - new EmoteClue("Yawn in the rogues' general store. Beware of double agents! Equip an adamant square shield, blue dragon vambraces and a rune pickaxe.", NOTERAZZOS_SHOP_IN_THE_WILDERNESS, new WorldPoint(3026, 3701, 0), YAWN, item(ADAMANT_SQ_SHIELD), item(BLUE_DHIDE_VAMB), item(RUNE_PICKAXE)), - new EmoteClue("Yawn at the top of Trollheim. Equip a lava battlestaff, black dragonhide vambraces and a mind shield.", ON_TOP_OF_TROLLHEIM_MOUNTAIN, new WorldPoint(2887, 3676, 0), YAWN, item(LAVA_BATTLESTAFF), item(BLACK_DHIDE_VAMB), item(MIND_SHIELD)), - new EmoteClue("Yawn in the centre of Arceuus library. Nod your head before you talk to me. Equip blue dragonhide vambraces, adamant boots and an adamant dagger.", ENTRANCE_OF_THE_ARCEUUS_LIBRARY, new WorldPoint(1632, 3807, 0), YAWN, YES, item(BLUE_DHIDE_VAMB), item(ADAMANT_BOOTS), item(ADAMANT_DAGGER)), - new EmoteClue("Swing a bullroarer at the top of the watchtower. Beware of double agents! Equip a dragon plateskirt, climbing boots and a dragon chainbody.", TOP_FLOOR_OF_THE_YANILLE_WATCHTOWER, new WorldPoint(2932, 4712, 0), BULL_ROARER, item(DRAGON_PLATESKIRT), item(CLIMBING_BOOTS), item(DRAGON_CHAINBODY_3140), item(ItemID.BULL_ROARER)), - new EmoteClue("Blow a raspberry at Gypsy Aris in her tent. Equip a gold ring and a gold necklace.", GYPSY_TENT_ENTRANCE, new WorldPoint(3203, 3424, 0), RASPBERRY, item(GOLD_RING), item(GOLD_NECKLACE)), - new EmoteClue("Bow to Brugsen Bursen at the Grand Exchange.", null, new WorldPoint(3164, 3477, 0), BOW), - new EmoteClue("Cheer at Iffie Nitter. Equip a chef hat and a red cape.", FINE_CLOTHES_ENTRANCE, new WorldPoint(3205, 3416, 0), CHEER, item(CHEFS_HAT), item(RED_CAPE)), - new EmoteClue("Clap at Bob's Brilliant Axes. Equip a bronze axe and leather boots.", BOB_AXES_ENTRANCE, new WorldPoint(3231, 3203, 0), CLAP, item(BRONZE_AXE), item(LEATHER_BOOTS)), - new EmoteClue("Panic at Al Kharid mine.", null, new WorldPoint(3300, 3314, 0), PANIC), - new EmoteClue("Spin at Flynn's Mace Shop.", null, new WorldPoint(2950, 3387, 0), SPIN)); - - private static SingleItemRequirement item(int itemId) - { - return new SingleItemRequirement(itemId); - } - - private static RangeItemRequirement range(int startItemId, int endItemId) - { - return range(null, startItemId, endItemId); - } - - private static RangeItemRequirement range(String name, int startItemId, int endItemId) - { - return new RangeItemRequirement(name, startItemId, endItemId); - } - - private static AnyRequirementCollection any(String name, ItemRequirement... requirements) - { - return new AnyRequirementCollection(name, requirements); - } - - private static AllRequirementsCollection all(ItemRequirement... requirements) - { - return new AllRequirementsCollection(requirements); - } - - private static SlotLimitationRequirement emptySlot(String description, EquipmentInventorySlot... slots) - { - return new SlotLimitationRequirement(description, slots); - } - - private final String text; - private final Integer stashUnit; - private final WorldPoint location; - private final Emote firstEmote; - private final Emote secondEmote; - @Nonnull - private final ItemRequirement[] itemRequirements; - - private EmoteClue(String text, Integer stashUnit, WorldPoint location, Emote firstEmote, @Nonnull ItemRequirement... itemRequirements) - { - this(text, stashUnit, location, firstEmote, null, itemRequirements); - } - - private EmoteClue(String text, Integer stashUnit, WorldPoint location, Emote firstEmote, Emote secondEmote, @Nonnull ItemRequirement... itemRequirements) - { - this.text = text; - this.stashUnit = stashUnit; - this.location = location; - this.firstEmote = firstEmote; - this.secondEmote = secondEmote; - this.itemRequirements = itemRequirements; - } - - @Override - public void makeOverlayHint(PanelComponent panelComponent, ClueScrollPlugin plugin) - { - panelComponent.getChildren().add(TitleComponent.builder().text("Emote Clue").build()); - panelComponent.getChildren().add(LineComponent.builder().left("Emotes:").build()); - panelComponent.getChildren().add(LineComponent.builder() - .left(getFirstEmote().getName()) - .leftColor(TITLED_CONTENT_COLOR) - .build()); - - if (getSecondEmote() != null) - { - panelComponent.getChildren().add(LineComponent.builder() - .left(getSecondEmote().getName()) - .leftColor(TITLED_CONTENT_COLOR) - .build()); - } - - if (itemRequirements.length > 0) - { - panelComponent.getChildren().add(LineComponent.builder().left("Equip:").build()); - - Item[] equipment = plugin.getEquippedItems(); - Item[] inventory = plugin.getInventoryItems(); - - // If equipment is null, the player is wearing nothing - if (equipment == null) - { - equipment = new Item[0]; - } - - // If inventory is null, the player has nothing in their inventory - if (inventory == null) - { - inventory = new Item[0]; - } - - Item[] combined = new Item[equipment.length + inventory.length]; - System.arraycopy(equipment, 0, combined, 0, equipment.length); - System.arraycopy(inventory, 0, combined, equipment.length, inventory.length); - - for (ItemRequirement requirement : itemRequirements) - { - boolean equipmentFulfilled = requirement.fulfilledBy(equipment); - boolean combinedFulfilled = requirement.fulfilledBy(combined); - - panelComponent.getChildren().add(LineComponent.builder() - .left(requirement.getCollectiveName(plugin.getClient())) - .leftColor(TITLED_CONTENT_COLOR) - .right(combinedFulfilled ? "\u2713" : "\u2717") - .rightColor(equipmentFulfilled ? Color.GREEN : (combinedFulfilled ? Color.ORANGE : Color.RED)) - .build()); - } - } - } - - @Override - public void makeWorldOverlayHint(Graphics2D graphics, ClueScrollPlugin plugin) - { - LocalPoint localLocation = LocalPoint.fromWorld(plugin.getClient(), getLocation()); - - if (localLocation == null) - { - return; - } - - OverlayUtil.renderTileOverlay(plugin.getClient(), graphics, localLocation, plugin.getEmoteImage(), Color.ORANGE); - } - - public static EmoteClue forText(String text) - { - for (EmoteClue clue : CLUES) - { - if (clue.getText().equalsIgnoreCase(text)) - { - return clue; - } - } - - return null; - } -} +/* + * Copyright (c) 2018, Lotto + * 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.cluescrolls.clues; + +import com.google.common.collect.ImmutableSet; +import java.awt.Color; +import java.awt.Graphics2D; +import java.util.Set; +import javax.annotation.Nonnull; +import lombok.Getter; +import net.runelite.api.EquipmentInventorySlot; +import static net.runelite.api.EquipmentInventorySlot.AMMO; +import static net.runelite.api.EquipmentInventorySlot.AMULET; +import static net.runelite.api.EquipmentInventorySlot.BODY; +import static net.runelite.api.EquipmentInventorySlot.BOOTS; +import static net.runelite.api.EquipmentInventorySlot.CAPE; +import static net.runelite.api.EquipmentInventorySlot.GLOVES; +import static net.runelite.api.EquipmentInventorySlot.HEAD; +import static net.runelite.api.EquipmentInventorySlot.LEGS; +import static net.runelite.api.EquipmentInventorySlot.RING; +import static net.runelite.api.EquipmentInventorySlot.SHIELD; +import static net.runelite.api.EquipmentInventorySlot.WEAPON; +import net.runelite.api.Item; +import net.runelite.api.ItemID; +import static net.runelite.api.ItemID.ABYSSAL_WHIP; +import static net.runelite.api.ItemID.ADAMANT_2H_SWORD; +import static net.runelite.api.ItemID.ADAMANT_BOOTS; +import static net.runelite.api.ItemID.ADAMANT_DAGGER; +import static net.runelite.api.ItemID.ADAMANT_FULL_HELM; +import static net.runelite.api.ItemID.ADAMANT_HALBERD; +import static net.runelite.api.ItemID.ADAMANT_MED_HELM; +import static net.runelite.api.ItemID.ADAMANT_PLATEBODY; +import static net.runelite.api.ItemID.ADAMANT_PLATELEGS; +import static net.runelite.api.ItemID.ADAMANT_PLATESKIRT; +import static net.runelite.api.ItemID.ADAMANT_SQ_SHIELD; +import static net.runelite.api.ItemID.ADAMANT_SWORD; +import static net.runelite.api.ItemID.ADAMANT_WARHAMMER; +import static net.runelite.api.ItemID.AHRIMS_HOOD_0; +import static net.runelite.api.ItemID.AHRIMS_HOOD_100; +import static net.runelite.api.ItemID.AHRIMS_ROBESKIRT_0; +import static net.runelite.api.ItemID.AHRIMS_ROBESKIRT_100; +import static net.runelite.api.ItemID.AHRIMS_ROBETOP_0; +import static net.runelite.api.ItemID.AHRIMS_ROBETOP_100; +import static net.runelite.api.ItemID.AHRIMS_STAFF_0; +import static net.runelite.api.ItemID.AHRIMS_STAFF_100; +import static net.runelite.api.ItemID.AIR_TIARA; +import static net.runelite.api.ItemID.AMULET_OF_GLORY; +import static net.runelite.api.ItemID.AMULET_OF_GLORY1; +import static net.runelite.api.ItemID.AMULET_OF_GLORY2; +import static net.runelite.api.ItemID.AMULET_OF_GLORY3; +import static net.runelite.api.ItemID.AMULET_OF_GLORY4; +import static net.runelite.api.ItemID.AMULET_OF_GLORY5; +import static net.runelite.api.ItemID.AMULET_OF_GLORY6; +import static net.runelite.api.ItemID.AMULET_OF_POWER; +import static net.runelite.api.ItemID.AMULET_OF_STRENGTH; +import static net.runelite.api.ItemID.AMULET_OF_THE_DAMNED; +import static net.runelite.api.ItemID.AMULET_OF_THE_DAMNED_FULL; +import static net.runelite.api.ItemID.ANCIENT_CROZIER; +import static net.runelite.api.ItemID.ANCIENT_MITRE; +import static net.runelite.api.ItemID.ANCIENT_STOLE; +import static net.runelite.api.ItemID.ARCLIGHT; +import static net.runelite.api.ItemID.ARMADYL_CROZIER; +import static net.runelite.api.ItemID.ARMADYL_MITRE; +import static net.runelite.api.ItemID.ARMADYL_STOLE; +import static net.runelite.api.ItemID.BANDOS_BOOTS; +import static net.runelite.api.ItemID.BANDOS_CLOAK; +import static net.runelite.api.ItemID.BANDOS_CROZIER; +import static net.runelite.api.ItemID.BANDOS_GODSWORD; +import static net.runelite.api.ItemID.BANDOS_MITRE; +import static net.runelite.api.ItemID.BANDOS_PLATEBODY; +import static net.runelite.api.ItemID.BANDOS_STOLE; +import static net.runelite.api.ItemID.BARROWS_GLOVES; +import static net.runelite.api.ItemID.BLACK_AXE; +import static net.runelite.api.ItemID.BLACK_BOATER; +import static net.runelite.api.ItemID.BLACK_CAPE; +import static net.runelite.api.ItemID.BLACK_DHIDE_BODY; +import static net.runelite.api.ItemID.BLACK_DHIDE_CHAPS; +import static net.runelite.api.ItemID.BLACK_DHIDE_VAMB; +import static net.runelite.api.ItemID.BLACK_DRAGON_MASK; +import static net.runelite.api.ItemID.BLACK_PLATEBODY; +import static net.runelite.api.ItemID.BLACK_SALAMANDER; +import static net.runelite.api.ItemID.BLACK_SLAYER_HELMET; +import static net.runelite.api.ItemID.BLACK_SLAYER_HELMET_I; +import static net.runelite.api.ItemID.BLUE_BOATER; +import static net.runelite.api.ItemID.BLUE_BOOTS; +import static net.runelite.api.ItemID.BLUE_DHIDE_BODY; +import static net.runelite.api.ItemID.BLUE_DHIDE_CHAPS; +import static net.runelite.api.ItemID.BLUE_DHIDE_VAMB; +import static net.runelite.api.ItemID.BLUE_ROBE_TOP; +import static net.runelite.api.ItemID.BLUE_WIZARD_HAT; +import static net.runelite.api.ItemID.BLUE_WIZARD_ROBE; +import static net.runelite.api.ItemID.BOBS_PURPLE_SHIRT; +import static net.runelite.api.ItemID.BOBS_RED_SHIRT; +import static net.runelite.api.ItemID.BODY_TIARA; +import static net.runelite.api.ItemID.BONE_DAGGER; +import static net.runelite.api.ItemID.BONE_SPEAR; +import static net.runelite.api.ItemID.BOOK_OF_BALANCE; +import static net.runelite.api.ItemID.BOOK_OF_DARKNESS; +import static net.runelite.api.ItemID.BOOK_OF_LAW; +import static net.runelite.api.ItemID.BOOK_OF_WAR; +import static net.runelite.api.ItemID.BRINE_SABRE; +import static net.runelite.api.ItemID.BRONZE_2H_SWORD; +import static net.runelite.api.ItemID.BRONZE_AXE; +import static net.runelite.api.ItemID.BRONZE_CHAINBODY; +import static net.runelite.api.ItemID.BRONZE_DAGGER; +import static net.runelite.api.ItemID.BRONZE_FULL_HELM; +import static net.runelite.api.ItemID.BRONZE_PLATELEGS; +import static net.runelite.api.ItemID.BRONZE_SPEAR; +import static net.runelite.api.ItemID.BRONZE_SQ_SHIELD; +import static net.runelite.api.ItemID.BROWN_APRON; +import static net.runelite.api.ItemID.BROWN_HEADBAND; +import static net.runelite.api.ItemID.BRUISE_BLUE_SNELM_3343; +import static net.runelite.api.ItemID.CAPE_OF_LEGENDS; +import static net.runelite.api.ItemID.CASTLE_WARS_BRACELET1; +import static net.runelite.api.ItemID.CASTLE_WARS_BRACELET3; +import static net.runelite.api.ItemID.CHEFS_HAT; +import static net.runelite.api.ItemID.CLIMBING_BOOTS; +import static net.runelite.api.ItemID.COIF; +import static net.runelite.api.ItemID.COMBAT_BRACELET; +import static net.runelite.api.ItemID.COMBAT_BRACELET4; +import static net.runelite.api.ItemID.CREAM_ROBE_TOP; +import static net.runelite.api.ItemID.CRYSTAL_BOW_110_I; +import static net.runelite.api.ItemID.CRYSTAL_BOW_210_I; +import static net.runelite.api.ItemID.CRYSTAL_BOW_310_I; +import static net.runelite.api.ItemID.CRYSTAL_BOW_410_I; +import static net.runelite.api.ItemID.CRYSTAL_BOW_510_I; +import static net.runelite.api.ItemID.CRYSTAL_BOW_610_I; +import static net.runelite.api.ItemID.CRYSTAL_BOW_710_I; +import static net.runelite.api.ItemID.CRYSTAL_BOW_810_I; +import static net.runelite.api.ItemID.CRYSTAL_BOW_910_I; +import static net.runelite.api.ItemID.CRYSTAL_BOW_FULL_I; +import static net.runelite.api.ItemID.DEATH_TIARA; +import static net.runelite.api.ItemID.DESERT_SHIRT; +import static net.runelite.api.ItemID.DHAROKS_GREATAXE_0; +import static net.runelite.api.ItemID.DHAROKS_GREATAXE_100; +import static net.runelite.api.ItemID.DHAROKS_HELM_0; +import static net.runelite.api.ItemID.DHAROKS_HELM_100; +import static net.runelite.api.ItemID.DHAROKS_PLATEBODY_0; +import static net.runelite.api.ItemID.DHAROKS_PLATEBODY_100; +import static net.runelite.api.ItemID.DHAROKS_PLATELEGS_0; +import static net.runelite.api.ItemID.DHAROKS_PLATELEGS_100; +import static net.runelite.api.ItemID.DIAMOND_BRACELET; +import static net.runelite.api.ItemID.DIAMOND_RING; +import static net.runelite.api.ItemID.DRAGONSTONE_AMULET; +import static net.runelite.api.ItemID.DRAGONSTONE_RING; +import static net.runelite.api.ItemID.DRAGON_2H_SWORD; +import static net.runelite.api.ItemID.DRAGON_AXE; +import static net.runelite.api.ItemID.DRAGON_BATTLEAXE; +import static net.runelite.api.ItemID.DRAGON_BOOTS; +import static net.runelite.api.ItemID.DRAGON_CHAINBODY_3140; +import static net.runelite.api.ItemID.DRAGON_DEFENDER; +import static net.runelite.api.ItemID.DRAGON_MED_HELM; +import static net.runelite.api.ItemID.DRAGON_NECKLACE; +import static net.runelite.api.ItemID.DRAGON_PICKAXE; +import static net.runelite.api.ItemID.DRAGON_PICKAXE_12797; +import static net.runelite.api.ItemID.DRAGON_PLATESKIRT; +import static net.runelite.api.ItemID.DRAGON_SPEAR; +import static net.runelite.api.ItemID.DRAGON_SQ_SHIELD; +import static net.runelite.api.ItemID.ELEMENTAL_SHIELD; +import static net.runelite.api.ItemID.EMERALD_AMULET; +import static net.runelite.api.ItemID.EMERALD_RING; +import static net.runelite.api.ItemID.FIRE_BATTLESTAFF; +import static net.runelite.api.ItemID.FIRE_CAPE; +import static net.runelite.api.ItemID.FIRE_MAX_CAPE; +import static net.runelite.api.ItemID.FLARED_TROUSERS; +import static net.runelite.api.ItemID.FROZEN_ABYSSAL_WHIP; +import static net.runelite.api.ItemID.GOLD_NECKLACE; +import static net.runelite.api.ItemID.GOLD_RING; +import static net.runelite.api.ItemID.GRANITE_SHIELD; +import static net.runelite.api.ItemID.GREEN_BOATER; +import static net.runelite.api.ItemID.GREEN_BOOTS; +import static net.runelite.api.ItemID.GREEN_DHIDE_BODY; +import static net.runelite.api.ItemID.GREEN_DHIDE_CHAPS; +import static net.runelite.api.ItemID.GREEN_HAT; +import static net.runelite.api.ItemID.GREEN_HEADBAND; +import static net.runelite.api.ItemID.GREEN_ROBE_BOTTOMS; +import static net.runelite.api.ItemID.GREEN_ROBE_TOP; +import static net.runelite.api.ItemID.GREEN_SLAYER_HELMET; +import static net.runelite.api.ItemID.GREEN_SLAYER_HELMET_I; +import static net.runelite.api.ItemID.GUTHANS_CHAINSKIRT_0; +import static net.runelite.api.ItemID.GUTHANS_CHAINSKIRT_100; +import static net.runelite.api.ItemID.GUTHANS_HELM_0; +import static net.runelite.api.ItemID.GUTHANS_HELM_100; +import static net.runelite.api.ItemID.GUTHANS_PLATEBODY_0; +import static net.runelite.api.ItemID.GUTHANS_PLATEBODY_100; +import static net.runelite.api.ItemID.GUTHANS_WARSPEAR_0; +import static net.runelite.api.ItemID.GUTHANS_WARSPEAR_100; +import static net.runelite.api.ItemID.GUTHIX_MITRE; +import static net.runelite.api.ItemID.GUTHIX_STOLE; +import static net.runelite.api.ItemID.HAM_BOOTS; +import static net.runelite.api.ItemID.HAM_ROBE; +import static net.runelite.api.ItemID.HARDLEATHER_BODY; +import static net.runelite.api.ItemID.HELM_OF_NEITIZNOT; +import static net.runelite.api.ItemID.HOLY_BOOK; +import static net.runelite.api.ItemID.HYDRA_SLAYER_HELMET; +import static net.runelite.api.ItemID.HYDRA_SLAYER_HELMET_I; +import static net.runelite.api.ItemID.IBANS_STAFF; +import static net.runelite.api.ItemID.IBANS_STAFF_U; +import static net.runelite.api.ItemID.INFERNAL_PICKAXE; +import static net.runelite.api.ItemID.INFERNAL_PICKAXE_UNCHARGED; +import static net.runelite.api.ItemID.IRON_2H_SWORD; +import static net.runelite.api.ItemID.IRON_CHAINBODY; +import static net.runelite.api.ItemID.IRON_FULL_HELM; +import static net.runelite.api.ItemID.IRON_KITESHIELD; +import static net.runelite.api.ItemID.IRON_MED_HELM; +import static net.runelite.api.ItemID.IRON_PICKAXE; +import static net.runelite.api.ItemID.IRON_PLATEBODY; +import static net.runelite.api.ItemID.IRON_PLATELEGS; +import static net.runelite.api.ItemID.IRON_PLATESKIRT; +import static net.runelite.api.ItemID.IRON_SCIMITAR; +import static net.runelite.api.ItemID.IRON_WARHAMMER; +import static net.runelite.api.ItemID.KARILS_COIF_0; +import static net.runelite.api.ItemID.KARILS_COIF_100; +import static net.runelite.api.ItemID.KARILS_CROSSBOW_0; +import static net.runelite.api.ItemID.KARILS_CROSSBOW_100; +import static net.runelite.api.ItemID.KARILS_LEATHERSKIRT_0; +import static net.runelite.api.ItemID.KARILS_LEATHERSKIRT_100; +import static net.runelite.api.ItemID.KARILS_LEATHERTOP_0; +import static net.runelite.api.ItemID.KARILS_LEATHERTOP_100; +import static net.runelite.api.ItemID.LAVA_BATTLESTAFF; +import static net.runelite.api.ItemID.LEATHER_BOOTS; +import static net.runelite.api.ItemID.LEATHER_CHAPS; +import static net.runelite.api.ItemID.LEATHER_COWL; +import static net.runelite.api.ItemID.LEATHER_GLOVES; +import static net.runelite.api.ItemID.LOCKPICK; +import static net.runelite.api.ItemID.LONGBOW; +import static net.runelite.api.ItemID.MAGIC_LONGBOW; +import static net.runelite.api.ItemID.MAPLE_LONGBOW; +import static net.runelite.api.ItemID.MAPLE_SHORTBOW; +import static net.runelite.api.ItemID.MENAPHITE_PURPLE_HAT; +import static net.runelite.api.ItemID.MENAPHITE_PURPLE_KILT; +import static net.runelite.api.ItemID.MENAPHITE_PURPLE_ROBE; +import static net.runelite.api.ItemID.MENAPHITE_PURPLE_TOP; +import static net.runelite.api.ItemID.MENAPHITE_RED_HAT; +import static net.runelite.api.ItemID.MENAPHITE_RED_KILT; +import static net.runelite.api.ItemID.MENAPHITE_RED_ROBE; +import static net.runelite.api.ItemID.MENAPHITE_RED_TOP; +import static net.runelite.api.ItemID.MIND_SHIELD; +import static net.runelite.api.ItemID.MITHRIL_BOOTS; +import static net.runelite.api.ItemID.MITHRIL_CHAINBODY; +import static net.runelite.api.ItemID.MITHRIL_FULL_HELM; +import static net.runelite.api.ItemID.MITHRIL_MED_HELM; +import static net.runelite.api.ItemID.MITHRIL_PICKAXE; +import static net.runelite.api.ItemID.MITHRIL_PLATEBODY; +import static net.runelite.api.ItemID.MITHRIL_PLATELEGS; +import static net.runelite.api.ItemID.MITHRIL_PLATESKIRT; +import static net.runelite.api.ItemID.MITHRIL_SCIMITAR; +import static net.runelite.api.ItemID.MYSTIC_FIRE_STAFF; +import static net.runelite.api.ItemID.MYSTIC_GLOVES; +import static net.runelite.api.ItemID.MYSTIC_HAT; +import static net.runelite.api.ItemID.MYSTIC_ROBE_BOTTOM; +import static net.runelite.api.ItemID.MYSTIC_ROBE_BOTTOM_DARK; +import static net.runelite.api.ItemID.MYSTIC_ROBE_TOP; +import static net.runelite.api.ItemID.MYSTIC_ROBE_TOP_DARK; +import static net.runelite.api.ItemID.NEW_CRYSTAL_BOW_I; +import static net.runelite.api.ItemID.OAK_LONGBOW; +import static net.runelite.api.ItemID.OAK_SHORTBOW; +import static net.runelite.api.ItemID.OBSIDIAN_CAPE; +import static net.runelite.api.ItemID.ORANGE_BOATER; +import static net.runelite.api.ItemID.PHARAOHS_SCEPTRE; +import static net.runelite.api.ItemID.PHARAOHS_SCEPTRE_1; +import static net.runelite.api.ItemID.PHARAOHS_SCEPTRE_2; +import static net.runelite.api.ItemID.PHARAOHS_SCEPTRE_3; +import static net.runelite.api.ItemID.PHARAOHS_SCEPTRE_4; +import static net.runelite.api.ItemID.PHARAOHS_SCEPTRE_5; +import static net.runelite.api.ItemID.PHARAOHS_SCEPTRE_6; +import static net.runelite.api.ItemID.PHARAOHS_SCEPTRE_7; +import static net.runelite.api.ItemID.PHARAOHS_SCEPTRE_8; +import static net.runelite.api.ItemID.PINK_BOATER; +import static net.runelite.api.ItemID.PINK_ROBE_TOP; +import static net.runelite.api.ItemID.PINK_SKIRT; +import static net.runelite.api.ItemID.PIRATE_BANDANA; +import static net.runelite.api.ItemID.PIRATE_BANDANA_7124; +import static net.runelite.api.ItemID.PIRATE_BANDANA_7130; +import static net.runelite.api.ItemID.PIRATE_BANDANA_7136; +import static net.runelite.api.ItemID.PROSELYTE_HAUBERK; +import static net.runelite.api.ItemID.PURPLE_BOATER; +import static net.runelite.api.ItemID.PURPLE_GLOVES; +import static net.runelite.api.ItemID.PURPLE_SLAYER_HELMET; +import static net.runelite.api.ItemID.PURPLE_SLAYER_HELMET_I; +import static net.runelite.api.ItemID.RED_BOATER; +import static net.runelite.api.ItemID.RED_CAPE; +import static net.runelite.api.ItemID.RED_DHIDE_CHAPS; +import static net.runelite.api.ItemID.RED_HEADBAND; +import static net.runelite.api.ItemID.RED_SLAYER_HELMET; +import static net.runelite.api.ItemID.RED_SLAYER_HELMET_I; +import static net.runelite.api.ItemID.RING_OF_DUELING1; +import static net.runelite.api.ItemID.RING_OF_DUELING2; +import static net.runelite.api.ItemID.RING_OF_DUELING3; +import static net.runelite.api.ItemID.RING_OF_DUELING4; +import static net.runelite.api.ItemID.RING_OF_DUELING5; +import static net.runelite.api.ItemID.RING_OF_DUELING6; +import static net.runelite.api.ItemID.RING_OF_DUELING7; +import static net.runelite.api.ItemID.RING_OF_DUELING8; +import static net.runelite.api.ItemID.RING_OF_FORGING; +import static net.runelite.api.ItemID.RING_OF_LIFE; +import static net.runelite.api.ItemID.RING_OF_VISIBILITY; +import static net.runelite.api.ItemID.RING_OF_WEALTH; +import static net.runelite.api.ItemID.RING_OF_WEALTH_1; +import static net.runelite.api.ItemID.RING_OF_WEALTH_2; +import static net.runelite.api.ItemID.RING_OF_WEALTH_3; +import static net.runelite.api.ItemID.RING_OF_WEALTH_4; +import static net.runelite.api.ItemID.RING_OF_WEALTH_5; +import static net.runelite.api.ItemID.RING_OF_WEALTH_I; +import static net.runelite.api.ItemID.RING_OF_WEALTH_I1; +import static net.runelite.api.ItemID.RING_OF_WEALTH_I2; +import static net.runelite.api.ItemID.RING_OF_WEALTH_I3; +import static net.runelite.api.ItemID.RING_OF_WEALTH_I4; +import static net.runelite.api.ItemID.RING_OF_WEALTH_I5; +import static net.runelite.api.ItemID.ROLLING_PIN; +import static net.runelite.api.ItemID.RUBY_AMULET; +import static net.runelite.api.ItemID.RUBY_RING; +import static net.runelite.api.ItemID.RUNE_AXE; +import static net.runelite.api.ItemID.RUNE_BOOTS; +import static net.runelite.api.ItemID.RUNE_CROSSBOW; +import static net.runelite.api.ItemID.RUNE_FULL_HELM; +import static net.runelite.api.ItemID.RUNE_HALBERD; +import static net.runelite.api.ItemID.RUNE_HELM_H1; +import static net.runelite.api.ItemID.RUNE_HELM_H5; +import static net.runelite.api.ItemID.RUNE_KITESHIELD; +import static net.runelite.api.ItemID.RUNE_LONGSWORD; +import static net.runelite.api.ItemID.RUNE_PICKAXE; +import static net.runelite.api.ItemID.RUNE_PLATEBODY; +import static net.runelite.api.ItemID.RUNE_PLATELEGS; +import static net.runelite.api.ItemID.RUNE_PLATESKIRT; +import static net.runelite.api.ItemID.RUNE_SHIELD_H1; +import static net.runelite.api.ItemID.RUNE_SHIELD_H2; +import static net.runelite.api.ItemID.RUNE_SHIELD_H3; +import static net.runelite.api.ItemID.RUNE_SHIELD_H4; +import static net.runelite.api.ItemID.RUNE_SHIELD_H5; +import static net.runelite.api.ItemID.RUNE_SPEAR; +import static net.runelite.api.ItemID.RUNE_WARHAMMER; +import static net.runelite.api.ItemID.SAPPHIRE_AMULET; +import static net.runelite.api.ItemID.SAPPHIRE_NECKLACE; +import static net.runelite.api.ItemID.SAPPHIRE_RING; +import static net.runelite.api.ItemID.SARADOMIN_CROZIER; +import static net.runelite.api.ItemID.SARADOMIN_MITRE; +import static net.runelite.api.ItemID.SARADOMIN_STOLE; +import static net.runelite.api.ItemID.SEERCULL; +import static net.runelite.api.ItemID.SHADOW_SWORD; +import static net.runelite.api.ItemID.SILVER_SICKLE; +import static net.runelite.api.ItemID.SLAYER_HELMET; +import static net.runelite.api.ItemID.SLAYER_HELMET_I; +import static net.runelite.api.ItemID.SLED_4084; +import static net.runelite.api.ItemID.SNAKESKIN_BOOTS; +import static net.runelite.api.ItemID.SNAKESKIN_CHAPS; +import static net.runelite.api.ItemID.SPINED_CHAPS; +import static net.runelite.api.ItemID.SPLITBARK_BODY; +import static net.runelite.api.ItemID.SPLITBARK_LEGS; +import static net.runelite.api.ItemID.SPOTTED_CAPE; +import static net.runelite.api.ItemID.SPOTTED_CAPE_10073; +import static net.runelite.api.ItemID.STAFF; +import static net.runelite.api.ItemID.STAFF_OF_AIR; +import static net.runelite.api.ItemID.STAFF_OF_WATER; +import static net.runelite.api.ItemID.STEEL_AXE; +import static net.runelite.api.ItemID.STEEL_FULL_HELM; +import static net.runelite.api.ItemID.STEEL_KITESHIELD; +import static net.runelite.api.ItemID.STEEL_LONGSWORD; +import static net.runelite.api.ItemID.STEEL_MACE; +import static net.runelite.api.ItemID.STEEL_MED_HELM; +import static net.runelite.api.ItemID.STEEL_PICKAXE; +import static net.runelite.api.ItemID.STEEL_PLATEBODY; +import static net.runelite.api.ItemID.STEEL_PLATESKIRT; +import static net.runelite.api.ItemID.STEEL_SQ_SHIELD; +import static net.runelite.api.ItemID.STUDDED_BODY; +import static net.runelite.api.ItemID.STUDDED_CHAPS; +import static net.runelite.api.ItemID.TEAM1_CAPE; +import static net.runelite.api.ItemID.TEAM50_CAPE; +import static net.runelite.api.ItemID.TIARA; +import static net.runelite.api.ItemID.TOKTZKETXIL; +import static net.runelite.api.ItemID.TOKTZXILUL; +import static net.runelite.api.ItemID.TORAGS_HAMMERS_0; +import static net.runelite.api.ItemID.TORAGS_HAMMERS_100; +import static net.runelite.api.ItemID.TORAGS_HELM_0; +import static net.runelite.api.ItemID.TORAGS_HELM_100; +import static net.runelite.api.ItemID.TORAGS_PLATEBODY_0; +import static net.runelite.api.ItemID.TORAGS_PLATEBODY_100; +import static net.runelite.api.ItemID.TORAGS_PLATELEGS_0; +import static net.runelite.api.ItemID.TORAGS_PLATELEGS_100; +import static net.runelite.api.ItemID.TURQUOISE_ROBE_BOTTOMS; +import static net.runelite.api.ItemID.TURQUOISE_SLAYER_HELMET; +import static net.runelite.api.ItemID.TURQUOISE_SLAYER_HELMET_I; +import static net.runelite.api.ItemID.UNHOLY_BOOK; +import static net.runelite.api.ItemID.VERACS_BRASSARD_0; +import static net.runelite.api.ItemID.VERACS_BRASSARD_100; +import static net.runelite.api.ItemID.VERACS_FLAIL_0; +import static net.runelite.api.ItemID.VERACS_FLAIL_100; +import static net.runelite.api.ItemID.VERACS_HELM_0; +import static net.runelite.api.ItemID.VERACS_HELM_100; +import static net.runelite.api.ItemID.VERACS_PLATESKIRT_0; +import static net.runelite.api.ItemID.VERACS_PLATESKIRT_100; +import static net.runelite.api.ItemID.VOLCANIC_ABYSSAL_WHIP; +import static net.runelite.api.ItemID.WHITE_APRON; +import static net.runelite.api.ItemID.WHITE_BOATER; +import static net.runelite.api.ItemID.WHITE_HEADBAND; +import static net.runelite.api.ItemID.ZAMORAK_CROZIER; +import static net.runelite.api.ItemID.ZAMORAK_FULL_HELM; +import static net.runelite.api.ItemID.ZAMORAK_GODSWORD; +import static net.runelite.api.ItemID.ZAMORAK_MITRE; +import static net.runelite.api.ItemID.ZAMORAK_STOLE; +import net.runelite.api.coords.LocalPoint; +import net.runelite.api.coords.WorldPoint; +import static net.runelite.client.plugins.cluescrolls.ClueScrollOverlay.TITLED_CONTENT_COLOR; +import net.runelite.client.plugins.cluescrolls.ClueScrollPlugin; +import net.runelite.client.plugins.cluescrolls.clues.emote.AllRequirementsCollection; +import net.runelite.client.plugins.cluescrolls.clues.emote.AnyRequirementCollection; +import net.runelite.client.plugins.cluescrolls.clues.emote.Emote; +import static net.runelite.client.plugins.cluescrolls.clues.emote.Emote.ANGRY; +import static net.runelite.client.plugins.cluescrolls.clues.emote.Emote.BECKON; +import static net.runelite.client.plugins.cluescrolls.clues.emote.Emote.BLOW_KISS; +import static net.runelite.client.plugins.cluescrolls.clues.emote.Emote.BOW; +import static net.runelite.client.plugins.cluescrolls.clues.emote.Emote.BULL_ROARER; +import static net.runelite.client.plugins.cluescrolls.clues.emote.Emote.CHEER; +import static net.runelite.client.plugins.cluescrolls.clues.emote.Emote.CLAP; +import static net.runelite.client.plugins.cluescrolls.clues.emote.Emote.CRY; +import static net.runelite.client.plugins.cluescrolls.clues.emote.Emote.DANCE; +import static net.runelite.client.plugins.cluescrolls.clues.emote.Emote.FLAP; +import static net.runelite.client.plugins.cluescrolls.clues.emote.Emote.GOBLIN_SALUTE; +import static net.runelite.client.plugins.cluescrolls.clues.emote.Emote.HEADBANG; +import static net.runelite.client.plugins.cluescrolls.clues.emote.Emote.JIG; +import static net.runelite.client.plugins.cluescrolls.clues.emote.Emote.JUMP_FOR_JOY; +import static net.runelite.client.plugins.cluescrolls.clues.emote.Emote.LAUGH; +import static net.runelite.client.plugins.cluescrolls.clues.emote.Emote.NO; +import static net.runelite.client.plugins.cluescrolls.clues.emote.Emote.PANIC; +import static net.runelite.client.plugins.cluescrolls.clues.emote.Emote.PUSH_UP; +import static net.runelite.client.plugins.cluescrolls.clues.emote.Emote.RASPBERRY; +import static net.runelite.client.plugins.cluescrolls.clues.emote.Emote.SALUTE; +import static net.runelite.client.plugins.cluescrolls.clues.emote.Emote.SHRUG; +import static net.runelite.client.plugins.cluescrolls.clues.emote.Emote.SLAP_HEAD; +import static net.runelite.client.plugins.cluescrolls.clues.emote.Emote.SPIN; +import static net.runelite.client.plugins.cluescrolls.clues.emote.Emote.STOMP; +import static net.runelite.client.plugins.cluescrolls.clues.emote.Emote.THINK; +import static net.runelite.client.plugins.cluescrolls.clues.emote.Emote.WAVE; +import static net.runelite.client.plugins.cluescrolls.clues.emote.Emote.YAWN; +import static net.runelite.client.plugins.cluescrolls.clues.emote.Emote.YES; +import net.runelite.client.plugins.cluescrolls.clues.emote.ItemRequirement; +import net.runelite.client.plugins.cluescrolls.clues.emote.RangeItemRequirement; +import static net.runelite.client.plugins.cluescrolls.clues.emote.STASHUnit.AGILITY_PYRAMID; +import static net.runelite.client.plugins.cluescrolls.clues.emote.STASHUnit.AL_KHARID_SCORPION_MINE; +import static net.runelite.client.plugins.cluescrolls.clues.emote.STASHUnit.AUBURYS_SHOP_IN_VARROCK; +import static net.runelite.client.plugins.cluescrolls.clues.emote.STASHUnit.BARBARIAN_OUTPOST_OBSTACLE_COURSE; +import static net.runelite.client.plugins.cluescrolls.clues.emote.STASHUnit.BARROWS_CHEST; +import static net.runelite.client.plugins.cluescrolls.clues.emote.STASHUnit.BEHIND_MISS_SCHISM_IN_DRAYNOR_VILLAGE; +import static net.runelite.client.plugins.cluescrolls.clues.emote.STASHUnit.BOB_AXES_ENTRANCE; +import static net.runelite.client.plugins.cluescrolls.clues.emote.STASHUnit.BY_THE_BEAR_CAGE_IN_VARROCK_PALACE_GARDENS; +import static net.runelite.client.plugins.cluescrolls.clues.emote.STASHUnit.CASTLE_WARS_BANK; +import static net.runelite.client.plugins.cluescrolls.clues.emote.STASHUnit.CATHERBY_BEEHIVE_FIELD; +import static net.runelite.client.plugins.cluescrolls.clues.emote.STASHUnit.CENTRE_OF_CANIFIS; +import static net.runelite.client.plugins.cluescrolls.clues.emote.STASHUnit.CENTRE_OF_THE_CATACOMBS_OF_KOUREND; +import static net.runelite.client.plugins.cluescrolls.clues.emote.STASHUnit.CHAOS_TEMPLE_IN_THE_SOUTHEASTERN_WILDERNESS; +import static net.runelite.client.plugins.cluescrolls.clues.emote.STASHUnit.CHAPEL_IN_WEST_ARDOUGNE; +import static net.runelite.client.plugins.cluescrolls.clues.emote.STASHUnit.CROSSROADS_NORTH_OF_DRAYNOR_VILLAGE; +import static net.runelite.client.plugins.cluescrolls.clues.emote.STASHUnit.DEATH_ALTAR; +import static net.runelite.client.plugins.cluescrolls.clues.emote.STASHUnit.DIGSITE; +import static net.runelite.client.plugins.cluescrolls.clues.emote.STASHUnit.DRAYNOR_MANOR_BY_THE_FOUNTAIN; +import static net.runelite.client.plugins.cluescrolls.clues.emote.STASHUnit.DRAYNOR_VILLAGE_MARKET; +import static net.runelite.client.plugins.cluescrolls.clues.emote.STASHUnit.EAST_OF_THE_BARBARIAN_VILLAGE_BRIDGE; +import static net.runelite.client.plugins.cluescrolls.clues.emote.STASHUnit.ENTRANA_CHAPEL; +import static net.runelite.client.plugins.cluescrolls.clues.emote.STASHUnit.ENTRANCE_OF_THE_ARCEUUS_LIBRARY; +import static net.runelite.client.plugins.cluescrolls.clues.emote.STASHUnit.ENTRANCE_OF_THE_CAVERN_UNDER_THE_WHIRLPOOL; +import static net.runelite.client.plugins.cluescrolls.clues.emote.STASHUnit.ENTRANCE_OF_THE_CAVE_OF_DAMIS; +import static net.runelite.client.plugins.cluescrolls.clues.emote.STASHUnit.FINE_CLOTHES_ENTRANCE; +import static net.runelite.client.plugins.cluescrolls.clues.emote.STASHUnit.FISHING_GUILD_BANK; +import static net.runelite.client.plugins.cluescrolls.clues.emote.STASHUnit.FOUNTAIN_OF_HEROES; +import static net.runelite.client.plugins.cluescrolls.clues.emote.STASHUnit.GNOME_GLIDER_ON_WHITE_WOLF_MOUNTAIN; +import static net.runelite.client.plugins.cluescrolls.clues.emote.STASHUnit.GNOME_STRONGHOLD_BALANCING_ROPE; +import static net.runelite.client.plugins.cluescrolls.clues.emote.STASHUnit.GYPSY_TENT_ENTRANCE; +import static net.runelite.client.plugins.cluescrolls.clues.emote.STASHUnit.HALFWAY_DOWN_TROLLWEISS_MOUNTAIN; +import static net.runelite.client.plugins.cluescrolls.clues.emote.STASHUnit.HICKTONS_ARCHERY_EMPORIUM; +import static net.runelite.client.plugins.cluescrolls.clues.emote.STASHUnit.HOSIDIUS_MESS; +import static net.runelite.client.plugins.cluescrolls.clues.emote.STASHUnit.INSIDE_THE_DIGSITE_EXAM_CENTRE; +import static net.runelite.client.plugins.cluescrolls.clues.emote.STASHUnit.IN_THE_MIDDLE_OF_JIGGIG; +import static net.runelite.client.plugins.cluescrolls.clues.emote.STASHUnit.KING_BLACK_DRAGONS_LAIR; +import static net.runelite.client.plugins.cluescrolls.clues.emote.STASHUnit.LIMESTONE_MINE; +import static net.runelite.client.plugins.cluescrolls.clues.emote.STASHUnit.LUMBRIDGE_SWAMP_CAVES; +import static net.runelite.client.plugins.cluescrolls.clues.emote.STASHUnit.MAUSOLEUM_OFF_THE_MORYTANIA_COAST; +import static net.runelite.client.plugins.cluescrolls.clues.emote.STASHUnit.MOUNTAIN_CAMP_GOAT_ENCLOSURE; +import static net.runelite.client.plugins.cluescrolls.clues.emote.STASHUnit.MUBARIZS_ROOM_AT_THE_DUEL_ARENA; +import static net.runelite.client.plugins.cluescrolls.clues.emote.STASHUnit.MUDSKIPPER_POINT; +import static net.runelite.client.plugins.cluescrolls.clues.emote.STASHUnit.NEAR_A_LADDER_IN_THE_WILDERNESS_LAVA_MAZE; +import static net.runelite.client.plugins.cluescrolls.clues.emote.STASHUnit.NEAR_A_RUNITE_ROCK_IN_THE_FREMENNIK_ISLES; +import static net.runelite.client.plugins.cluescrolls.clues.emote.STASHUnit.NEAR_A_SHED_IN_LUMBRIDGE_SWAMP; +import static net.runelite.client.plugins.cluescrolls.clues.emote.STASHUnit.NEAR_HERQUINS_SHOP_IN_FALADOR; +import static net.runelite.client.plugins.cluescrolls.clues.emote.STASHUnit.NEAR_THE_ENTRANA_FERRY_IN_PORT_SARIM; +import static net.runelite.client.plugins.cluescrolls.clues.emote.STASHUnit.NEAR_THE_GEM_STALL_IN_ARDOUGNE_MARKET; +import static net.runelite.client.plugins.cluescrolls.clues.emote.STASHUnit.NEAR_THE_PARROTS_IN_ARDOUGNE_ZOO; +import static net.runelite.client.plugins.cluescrolls.clues.emote.STASHUnit.NEAR_THE_PIER_IN_ZULANDRA; +import static net.runelite.client.plugins.cluescrolls.clues.emote.STASHUnit.NEAR_THE_SAWMILL_OPERATORS_BOOTH; +import static net.runelite.client.plugins.cluescrolls.clues.emote.STASHUnit.NORTHEAST_CORNER_OF_THE_KHARAZI_JUNGLE; +import static net.runelite.client.plugins.cluescrolls.clues.emote.STASHUnit.NORTHERN_WALL_OF_CASTLE_DRAKAN; +import static net.runelite.client.plugins.cluescrolls.clues.emote.STASHUnit.NORTHWESTERN_CORNER_OF_THE_ENCHANTED_VALLEY; +import static net.runelite.client.plugins.cluescrolls.clues.emote.STASHUnit.NORTH_OF_EVIL_DAVES_HOUSE_IN_EDGEVILLE; +import static net.runelite.client.plugins.cluescrolls.clues.emote.STASHUnit.NORTH_OF_MOUNT_KARUULM; +import static net.runelite.client.plugins.cluescrolls.clues.emote.STASHUnit.NOTERAZZOS_SHOP_IN_THE_WILDERNESS; +import static net.runelite.client.plugins.cluescrolls.clues.emote.STASHUnit.OBSERVATORY; +import static net.runelite.client.plugins.cluescrolls.clues.emote.STASHUnit.OGRE_CAGE_IN_KING_LATHAS_TRAINING_CAMP; +import static net.runelite.client.plugins.cluescrolls.clues.emote.STASHUnit.ON_THE_BRIDGE_TO_THE_MISTHALIN_WIZARDS_TOWER; +import static net.runelite.client.plugins.cluescrolls.clues.emote.STASHUnit.ON_TOP_OF_TROLLHEIM_MOUNTAIN; +import static net.runelite.client.plugins.cluescrolls.clues.emote.STASHUnit.OUTSIDE_CATHERBY_BANK; +import static net.runelite.client.plugins.cluescrolls.clues.emote.STASHUnit.OUTSIDE_DRAYNOR_VILLAGE_JAIL; +import static net.runelite.client.plugins.cluescrolls.clues.emote.STASHUnit.OUTSIDE_HARRYS_FISHING_SHOP_IN_CATHERBY; +import static net.runelite.client.plugins.cluescrolls.clues.emote.STASHUnit.OUTSIDE_KEEP_LE_FAYE; +import static net.runelite.client.plugins.cluescrolls.clues.emote.STASHUnit.OUTSIDE_KRIL_TSUTSAROTHS_ROOM; +import static net.runelite.client.plugins.cluescrolls.clues.emote.STASHUnit.OUTSIDE_MUDKNUCKLES_HUT; +import static net.runelite.client.plugins.cluescrolls.clues.emote.STASHUnit.OUTSIDE_THE_BAR_BY_THE_FIGHT_ARENA; +import static net.runelite.client.plugins.cluescrolls.clues.emote.STASHUnit.OUTSIDE_THE_DIGSITE_EXAM_CENTRE; +import static net.runelite.client.plugins.cluescrolls.clues.emote.STASHUnit.OUTSIDE_THE_FALADOR_PARTY_ROOM; +import static net.runelite.client.plugins.cluescrolls.clues.emote.STASHUnit.OUTSIDE_THE_FISHING_GUILD; +import static net.runelite.client.plugins.cluescrolls.clues.emote.STASHUnit.OUTSIDE_THE_GREAT_PYRAMID_OF_SOPHANEM; +import static net.runelite.client.plugins.cluescrolls.clues.emote.STASHUnit.OUTSIDE_THE_LEGENDS_GUILD_DOOR; +import static net.runelite.client.plugins.cluescrolls.clues.emote.STASHUnit.OUTSIDE_THE_LEGENDS_GUILD_GATES; +import static net.runelite.client.plugins.cluescrolls.clues.emote.STASHUnit.OUTSIDE_THE_SEERS_VILLAGE_COURTHOUSE; +import static net.runelite.client.plugins.cluescrolls.clues.emote.STASHUnit.OUTSIDE_THE_SLAYER_TOWER_GARGOYLE_ROOM; +import static net.runelite.client.plugins.cluescrolls.clues.emote.STASHUnit.OUTSIDE_THE_WILDERNESS_AXE_HUT; +import static net.runelite.client.plugins.cluescrolls.clues.emote.STASHUnit.OUTSIDE_VARROCK_PALACE_COURTYARD; +import static net.runelite.client.plugins.cluescrolls.clues.emote.STASHUnit.OUTSIDE_YANILLE_BANK; +import static net.runelite.client.plugins.cluescrolls.clues.emote.STASHUnit.RIMMINGTON_MINE; +import static net.runelite.client.plugins.cluescrolls.clues.emote.STASHUnit.ROAD_JUNCTION_NORTH_OF_RIMMINGTON; +import static net.runelite.client.plugins.cluescrolls.clues.emote.STASHUnit.ROAD_JUNCTION_SOUTH_OF_SINCLAIR_MANSION; +import static net.runelite.client.plugins.cluescrolls.clues.emote.STASHUnit.SHANTAY_PASS; +import static net.runelite.client.plugins.cluescrolls.clues.emote.STASHUnit.SHAYZIEN_WAR_TENT; +import static net.runelite.client.plugins.cluescrolls.clues.emote.STASHUnit.SHILO_VILLAGE_BANK; +import static net.runelite.client.plugins.cluescrolls.clues.emote.STASHUnit.SOUL_ALTAR; +import static net.runelite.client.plugins.cluescrolls.clues.emote.STASHUnit.SOUTHEAST_CORNER_OF_LAVA_DRAGON_ISLE; +import static net.runelite.client.plugins.cluescrolls.clues.emote.STASHUnit.SOUTHEAST_CORNER_OF_THE_FISHING_PLATFORM; +import static net.runelite.client.plugins.cluescrolls.clues.emote.STASHUnit.SOUTHEAST_CORNER_OF_THE_MONASTERY; +import static net.runelite.client.plugins.cluescrolls.clues.emote.STASHUnit.SOUTH_OF_THE_GRAND_EXCHANGE; +import static net.runelite.client.plugins.cluescrolls.clues.emote.STASHUnit.SOUTH_OF_THE_SHRINE_IN_TAI_BWO_WANNAI_VILLAGE; +import static net.runelite.client.plugins.cluescrolls.clues.emote.STASHUnit.TAVERLEY_STONE_CIRCLE; +import static net.runelite.client.plugins.cluescrolls.clues.emote.STASHUnit.TENT_IN_LORD_IORWERTHS_ENCAMPMENT; +import static net.runelite.client.plugins.cluescrolls.clues.emote.STASHUnit.TOP_FLOOR_OF_THE_LIGHTHOUSE; +import static net.runelite.client.plugins.cluescrolls.clues.emote.STASHUnit.TOP_FLOOR_OF_THE_YANILLE_WATCHTOWER; +import static net.runelite.client.plugins.cluescrolls.clues.emote.STASHUnit.TZHAAR_GEM_STORE; +import static net.runelite.client.plugins.cluescrolls.clues.emote.STASHUnit.TZHAAR_WEAPONS_STORE; +import static net.runelite.client.plugins.cluescrolls.clues.emote.STASHUnit.UPSTAIRS_IN_THE_ARDOUGNE_WINDMILL; +import static net.runelite.client.plugins.cluescrolls.clues.emote.STASHUnit.VARROCK_PALACE_LIBRARY; +import static net.runelite.client.plugins.cluescrolls.clues.emote.STASHUnit.VOLCANO_IN_THE_NORTHEASTERN_WILDERNESS; +import static net.runelite.client.plugins.cluescrolls.clues.emote.STASHUnit.WARRIORS_GUILD_BANK; +import static net.runelite.client.plugins.cluescrolls.clues.emote.STASHUnit.WARRIORS_GUILD_BANK_29047; +import static net.runelite.client.plugins.cluescrolls.clues.emote.STASHUnit.WELL_OF_VOYAGE; +import static net.runelite.client.plugins.cluescrolls.clues.emote.STASHUnit.WEST_OF_THE_SHAYZIEN_COMBAT_RING; +import static net.runelite.client.plugins.cluescrolls.clues.emote.STASHUnit.WEST_SIDE_OF_THE_KARAMJA_BANANA_PLANTATION; +import static net.runelite.client.plugins.cluescrolls.clues.emote.STASHUnit.WHEAT_FIELD_NEAR_THE_LUMBRIDGE_WINDMILL; +import static net.runelite.client.plugins.cluescrolls.clues.emote.STASHUnit._7TH_CHAMBER_OF_JALSAVRAH; +import net.runelite.client.plugins.cluescrolls.clues.emote.SingleItemRequirement; +import net.runelite.client.plugins.cluescrolls.clues.emote.SlotLimitationRequirement; +import net.runelite.client.ui.overlay.OverlayUtil; +import net.runelite.client.ui.overlay.components.LineComponent; +import net.runelite.client.ui.overlay.components.PanelComponent; +import net.runelite.client.ui.overlay.components.TitleComponent; + +@Getter +public class EmoteClue extends ClueScroll implements TextClueScroll, LocationClueScroll +{ + private static final Set CLUES = ImmutableSet.of( + new EmoteClue("Beckon on the east coast of the Kharazi Jungle. Beware of double agents! Equip any vestment stole and a heraldic rune shield.", NORTHEAST_CORNER_OF_THE_KHARAZI_JUNGLE, new WorldPoint(2954, 2933, 0), BECKON, any("Any stole", item(GUTHIX_STOLE), item(SARADOMIN_STOLE), item(ZAMORAK_STOLE), item(ARMADYL_STOLE), item(BANDOS_STOLE), item(ANCIENT_STOLE)), any("Any heraldic rune shield", item(RUNE_SHIELD_H1), item(RUNE_SHIELD_H2), item(RUNE_SHIELD_H3), item(RUNE_SHIELD_H4), item(RUNE_SHIELD_H5))), + new EmoteClue("Cheer in the Barbarian Agility Arena. Headbang before you talk to me. Equip a steel platebody, maple shortbow and a Wilderness cape.", BARBARIAN_OUTPOST_OBSTACLE_COURSE, new WorldPoint(2552, 3556, 0), CHEER, HEADBANG, item(STEEL_PLATEBODY), item(MAPLE_SHORTBOW), range("Any team cape", TEAM1_CAPE, TEAM50_CAPE)), + new EmoteClue("Bow upstairs in the Edgeville Monastery. Equip a completed prayer book.", SOUTHEAST_CORNER_OF_THE_MONASTERY, new WorldPoint(3056, 3484, 1), BOW, any("Any god book", item(HOLY_BOOK), item(BOOK_OF_BALANCE), item(UNHOLY_BOOK), item(BOOK_OF_LAW), item(BOOK_OF_WAR), item(BOOK_OF_DARKNESS))), + new EmoteClue("Cheer in the Shadow dungeon. Equip a rune crossbow, climbing boots and any mitre.", ENTRANCE_OF_THE_CAVE_OF_DAMIS, new WorldPoint(2629, 5071, 0), CHEER, any("Any mitre", item(GUTHIX_MITRE), item(SARADOMIN_MITRE), item(ZAMORAK_MITRE), item(ANCIENT_MITRE), item(BANDOS_MITRE), item(ARMADYL_MITRE)), item(RUNE_CROSSBOW), item(CLIMBING_BOOTS), item(RING_OF_VISIBILITY)), + new EmoteClue("Cheer at the top of the agility pyramid. Beware of double agents! Equip a blue mystic robe top, and any rune heraldic shield.", AGILITY_PYRAMID, new WorldPoint(3043, 4697, 3), CHEER, item(MYSTIC_ROBE_TOP), any("Any rune heraldic shield", item(RUNE_SHIELD_H1), item(RUNE_SHIELD_H2), item(RUNE_SHIELD_H3), item(RUNE_SHIELD_H4), item(RUNE_SHIELD_H5))), + new EmoteClue("Dance in Iban's temple. Beware of double agents! Equip Iban's staff, a black mystic top and a black mystic bottom.", WELL_OF_VOYAGE, new WorldPoint(2011, 4712, 0), DANCE, any("Any iban's staff", item(IBANS_STAFF), item(IBANS_STAFF_U)), item(MYSTIC_ROBE_TOP_DARK), item(MYSTIC_ROBE_BOTTOM_DARK)), + new EmoteClue("Dance on the Fishing Platform. Equip barrows gloves, an amulet of glory and a dragon med helm.", SOUTHEAST_CORNER_OF_THE_FISHING_PLATFORM, new WorldPoint(2782, 3273, 0), DANCE, any("Any amulet of glory", item(AMULET_OF_GLORY), item(AMULET_OF_GLORY1), item(AMULET_OF_GLORY2), item(AMULET_OF_GLORY3), item(AMULET_OF_GLORY4), item(AMULET_OF_GLORY5), item(AMULET_OF_GLORY6)), item(BARROWS_GLOVES), item(DRAGON_MED_HELM)), + new EmoteClue("Flap at the death altar. Beware of double agents! Equip a death tiara, a legend's cape and any ring of wealth.", DEATH_ALTAR, new WorldPoint(2205, 4838, 0), FLAP, any("Any ring of wealth", item(RING_OF_WEALTH), item(RING_OF_WEALTH_1), item(RING_OF_WEALTH_2), item(RING_OF_WEALTH_3), item(RING_OF_WEALTH_4), item(RING_OF_WEALTH_5), item(RING_OF_WEALTH_I), item(RING_OF_WEALTH_I1), item(RING_OF_WEALTH_I2), item(RING_OF_WEALTH_I3), item(RING_OF_WEALTH_I4), item(RING_OF_WEALTH_I5)), item(DEATH_TIARA), item(CAPE_OF_LEGENDS)), + new EmoteClue("Headbang in the Fight Arena pub. Equip a pirate bandana, a dragonstone necklace and and a magic longbow.", OUTSIDE_THE_BAR_BY_THE_FIGHT_ARENA, new WorldPoint(2568, 3149, 0), HEADBANG, any("Any pirate bandana", item(PIRATE_BANDANA), item(PIRATE_BANDANA_7124), item(PIRATE_BANDANA_7130), item(PIRATE_BANDANA_7136)), item(DRAGON_NECKLACE), item(MAGIC_LONGBOW)), + new EmoteClue("Do a jig at the barrow's chest. Beware of double agents! Equip any full barrows set.", BARROWS_CHEST, new WorldPoint(3551, 9694, 0), JIG, any("Any full barrows set", all(range(AHRIMS_HOOD_100, AHRIMS_HOOD_0), range(AHRIMS_STAFF_100, AHRIMS_STAFF_0), range(AHRIMS_ROBETOP_100, AHRIMS_ROBETOP_0), range(AHRIMS_ROBESKIRT_100, AHRIMS_ROBESKIRT_0)), all(range(DHAROKS_HELM_100, DHAROKS_HELM_0), range(DHAROKS_GREATAXE_100, DHAROKS_GREATAXE_0), range(DHAROKS_PLATEBODY_100, DHAROKS_PLATEBODY_0), range(DHAROKS_PLATELEGS_100, DHAROKS_PLATELEGS_0)), all(range(GUTHANS_HELM_100, GUTHANS_HELM_0), range(GUTHANS_WARSPEAR_100, GUTHANS_WARSPEAR_0), range(GUTHANS_PLATEBODY_100, GUTHANS_PLATEBODY_0), range(GUTHANS_CHAINSKIRT_100, GUTHANS_CHAINSKIRT_0)), all(range(KARILS_COIF_100, KARILS_COIF_0), range(KARILS_CROSSBOW_100, KARILS_CROSSBOW_0), range(KARILS_LEATHERTOP_100, KARILS_LEATHERTOP_0), range(KARILS_LEATHERSKIRT_100, KARILS_LEATHERSKIRT_0)), all(range(TORAGS_HELM_100, TORAGS_HELM_0), range(TORAGS_HAMMERS_100, TORAGS_HAMMERS_0), range(TORAGS_PLATEBODY_100, TORAGS_PLATEBODY_0), range(TORAGS_PLATELEGS_100, TORAGS_PLATELEGS_0)), all(range(VERACS_HELM_100, VERACS_HELM_0), range(VERACS_FLAIL_100, VERACS_FLAIL_0), range(VERACS_BRASSARD_100, VERACS_BRASSARD_0), range(VERACS_PLATESKIRT_100, VERACS_PLATESKIRT_0)))), + new EmoteClue("Jig at Jiggig. Beware of double agents! Equip a Rune spear, rune platelegs and any rune heraldic helm.", IN_THE_MIDDLE_OF_JIGGIG, new WorldPoint(2477, 3047, 0), JIG, range("Any rune heraldic helm", RUNE_HELM_H1, RUNE_HELM_H5), item(RUNE_SPEAR), item(RUNE_PLATELEGS)), + new EmoteClue("Cheer at the games room. Have nothing equipped at all when you do.", null, new WorldPoint(2207, 4952, 0), CHEER, emptySlot("Nothing at all", HEAD, CAPE, AMULET, WEAPON, BODY, SHIELD, LEGS, GLOVES, BOOTS, RING, AMMO)), + new EmoteClue("Panic on the pier where you catch the Fishing trawler. Have nothing equipped at all when you do.", null, new WorldPoint(2676, 3169, 0), PANIC, emptySlot("Nothing at all", HEAD, CAPE, AMULET, WEAPON, BODY, SHIELD, LEGS, GLOVES, BOOTS, RING, AMMO)), + new EmoteClue("Panic in the heart of the Haunted Woods. Beware of double agents! Have no items equipped when you do.", null, new WorldPoint(3611, 3492, 0), PANIC, emptySlot("Nothing at all", HEAD, CAPE, AMULET, WEAPON, BODY, SHIELD, LEGS, GLOVES, BOOTS, RING, AMMO)), + 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(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)), + new EmoteClue("Bow on the ground floor of the Legend's guild. Equip Legend's cape, a dragon battleaxe and an amulet of glory.", OUTSIDE_THE_LEGENDS_GUILD_DOOR, new WorldPoint(2728, 3377, 0), BOW, item(CAPE_OF_LEGENDS), item(DRAGON_BATTLEAXE), any("Any amulet of glory", item(AMULET_OF_GLORY), item(AMULET_OF_GLORY1), item(AMULET_OF_GLORY2), item(AMULET_OF_GLORY3), item(AMULET_OF_GLORY4), item(AMULET_OF_GLORY5), item(AMULET_OF_GLORY6))), + new EmoteClue("Bow in the ticket office of the Duel Arena. Equip an iron chain body, leather chaps and coif.", MUBARIZS_ROOM_AT_THE_DUEL_ARENA, new WorldPoint(3314, 3241, 0), BOW, item(IRON_CHAINBODY), item(LEATHER_CHAPS), item(COIF)), + new EmoteClue("Bow at the top of the lighthouse. Beware of double agents! Equip a blue dragonhide body, blue dragonhide vambraces and no jewelry.", TOP_FLOOR_OF_THE_LIGHTHOUSE, new WorldPoint(2511, 3641, 2), BOW, item(BLUE_DHIDE_BODY), item(BLUE_DHIDE_VAMB), emptySlot("No jewelry", AMULET, RING)), + new EmoteClue("Blow a kiss between the tables in Shilo Village bank. Beware of double agents! Equip a blue mystic hat, bone spear and rune platebody.", SHILO_VILLAGE_BANK, new WorldPoint(2851, 2954, 0), BLOW_KISS, item(MYSTIC_HAT), item(BONE_SPEAR), item(RUNE_PLATEBODY)), + new EmoteClue("Blow a kiss in the heart of the lava maze. Equip black dragonhide chaps, a spotted cape and a rolling pin.", NEAR_A_LADDER_IN_THE_WILDERNESS_LAVA_MAZE, new WorldPoint(3069, 3861, 0), BLOW_KISS, item(BLACK_DHIDE_CHAPS), any("Spotted cape", item(SPOTTED_CAPE), item(SPOTTED_CAPE_10073)), item(ROLLING_PIN)), + new EmoteClue("Blow a kiss outside K'ril Tsutsaroth's chamber. Beware of double agents! Equip a zamorak full helm and the shadow sword.", OUTSIDE_KRIL_TSUTSAROTHS_ROOM, new WorldPoint(2925, 5333, 0), BLOW_KISS, item(ZAMORAK_FULL_HELM), item(SHADOW_SWORD)), + new EmoteClue("Cheer at the Druids' Circle. Equip a blue wizard hat, a bronze two-handed sword and HAM boots.", TAVERLEY_STONE_CIRCLE, new WorldPoint(2924, 3478, 0), CHEER, item(BLUE_WIZARD_HAT), item(BRONZE_2H_SWORD), item(HAM_BOOTS)), + new EmoteClue("Cheer in the Edgeville general store. Dance before you talk to me. Equip a brown apron, leather boots and leather gloves.", NORTH_OF_EVIL_DAVES_HOUSE_IN_EDGEVILLE, new WorldPoint(3080, 3509, 0), CHEER, DANCE, item(BROWN_APRON), item(LEATHER_BOOTS), item(LEATHER_GLOVES)), + new EmoteClue("Cheer in the Ogre Pen in the Training Camp. Show you are angry before you talk to me. Equip a green dragonhide body and chaps and a steel square shield.", OGRE_CAGE_IN_KING_LATHAS_TRAINING_CAMP, new WorldPoint(2527, 3375, 0), CHEER, ANGRY, item(GREEN_DHIDE_BODY), item(GREEN_DHIDE_CHAPS), item(STEEL_SQ_SHIELD)), + new EmoteClue("Cheer in the Entrana church. Beware of double agents! Equip a full set of black dragonhide armour.", ENTRANA_CHAPEL, new WorldPoint(2852, 3349, 0), CHEER, item(BLACK_DHIDE_VAMB), item(BLACK_DHIDE_CHAPS), item(BLACK_DHIDE_BODY)), + new EmoteClue("Cheer for the monks at Port Sarim. Equip a coif, steel plateskirt and a sapphire necklace.", NEAR_THE_ENTRANA_FERRY_IN_PORT_SARIM, new WorldPoint(3047, 3237, 0), CHEER, item(COIF), item(STEEL_PLATESKIRT), item(SAPPHIRE_NECKLACE)), + new EmoteClue("Clap in the main exam room in the Exam Centre. Equip a white apron, green gnome boots and leather gloves.", INSIDE_THE_DIGSITE_EXAM_CENTRE, new WorldPoint(3361, 3339, 0), CLAP, item(WHITE_APRON), item(GREEN_BOOTS), item(LEATHER_GLOVES)), + new EmoteClue("Clap on the causeway to the Wizards' Tower. Equip an iron medium helmet, emerald ring and a white apron.", ON_THE_BRIDGE_TO_THE_MISTHALIN_WIZARDS_TOWER, new WorldPoint(3113, 3196, 0), CLAP, item(IRON_MED_HELM), item(EMERALD_RING), item(WHITE_APRON)), + new EmoteClue("Clap on the top level of the mill, north of East Ardougne. Equip a blue gnome robe top, HAM robe bottom and an unenchanted tiara.", UPSTAIRS_IN_THE_ARDOUGNE_WINDMILL, new WorldPoint(2635, 3385, 3), CLAP, item(BLUE_ROBE_TOP), item(HAM_ROBE), item(TIARA)), + new EmoteClue("Clap in Seers court house. Spin before you talk to me. Equip an adamant halberd, blue mystic robe bottom and a diamond ring.", OUTSIDE_THE_SEERS_VILLAGE_COURTHOUSE, new WorldPoint(2735, 3469, 0), CLAP, SPIN, item(ADAMANT_HALBERD), item(MYSTIC_ROBE_BOTTOM), item(DIAMOND_RING)), + new EmoteClue("Clap in the magic axe hut. Beware of double agents! Equip only some flared trousers.", OUTSIDE_THE_WILDERNESS_AXE_HUT, new WorldPoint(3191, 3960, 0), CLAP, item(FLARED_TROUSERS), item(LOCKPICK), emptySlot("Nothing else", HEAD, CAPE, AMULET, WEAPON, BODY, SHIELD, GLOVES, BOOTS, RING, AMMO)), + new EmoteClue("Clap your hands north of Mount Karuulm Spin before you talk to me. Equip an adamant warhammer, a ring of life and a pair of mithril boots.", NORTH_OF_MOUNT_KARUULM, new WorldPoint(1306, 3839, 0), CLAP, SPIN, item(ADAMANT_WARHAMMER), item(RING_OF_LIFE), item(MITHRIL_BOOTS)), + new EmoteClue("Cry in the Catherby Ranging shop. Bow before you talk to me. Equip blue gnome boots, a hard leather body and an unblessed silver sickle.", HICKTONS_ARCHERY_EMPORIUM, new WorldPoint(2823, 3443, 0), CRY, BOW, item(BLUE_BOOTS), item(HARDLEATHER_BODY), item(SILVER_SICKLE)), + new EmoteClue("Cry on the shore of Catherby beach. Laugh before you talk to me, equip an adamant sq shield, a bone dagger and mithril platebody.", OUTSIDE_HARRYS_FISHING_SHOP_IN_CATHERBY, new WorldPoint(2852, 3429, 0), CRY, LAUGH, item(ADAMANT_SQ_SHIELD), item(BONE_DAGGER), item(MITHRIL_PLATEBODY)), + new EmoteClue("Cry on top of the western tree in the Gnome Agility Arena. Indicate 'no' before you talk to me. Equip a steel kiteshield, ring of forging and green dragonhide chaps.", GNOME_STRONGHOLD_BALANCING_ROPE, new WorldPoint(2473, 3420, 2), CRY, NO, item(STEEL_KITESHIELD), item(RING_OF_FORGING), item(GREEN_DHIDE_CHAPS)), + new EmoteClue("Cry in the TzHaar gem store. Beware of double agents! Equip a fire cape and TokTz-Xil-Ul.", TZHAAR_GEM_STORE, new WorldPoint(2463, 5149, 0), CRY, any("Fire cape", item(FIRE_CAPE), item(FIRE_MAX_CAPE)), item(TOKTZXILUL)), + new EmoteClue("Cry in the Draynor Village jail. Jump for joy before you talk to me. Equip an adamant sword, a sapphire amulet and an adamant plateskirt.", OUTSIDE_DRAYNOR_VILLAGE_JAIL, new WorldPoint(3128, 3245, 0), CRY, JUMP_FOR_JOY, item(ADAMANT_SWORD), item(SAPPHIRE_AMULET), item(ADAMANT_PLATESKIRT)), + new EmoteClue("Dance at the crossroads north of Draynor. Equip an iron chain body, a sapphire ring and a longbow.", CROSSROADS_NORTH_OF_DRAYNOR_VILLAGE, new WorldPoint(3109, 3294, 0), DANCE, item(IRON_CHAINBODY), item(SAPPHIRE_RING), item(LONGBOW)), + new EmoteClue("Dance in the Party Room. Equip a steel full helmet, steel platebody and an iron plateskirt.", OUTSIDE_THE_FALADOR_PARTY_ROOM, new WorldPoint(3045, 3376, 0), DANCE, item(STEEL_FULL_HELM), item(STEEL_PLATEBODY), item(IRON_PLATESKIRT)), + new EmoteClue("Dance in the shack in Lumbridge Swamp. Equip a bronze dagger, iron full helmet and a gold ring.", NEAR_A_SHED_IN_LUMBRIDGE_SWAMP, new WorldPoint(3203, 3169, 0), DANCE, item(BRONZE_DAGGER), item(IRON_FULL_HELM), item(GOLD_RING)), + new EmoteClue("Dance in the dark caves beneath Lumbridge Swamp. Blow a kiss before you talk to me. Equip an air staff, Bronze full helm and an amulet of power.", LUMBRIDGE_SWAMP_CAVES, new WorldPoint(3168, 9571, 0), DANCE, BLOW_KISS, item(STAFF_OF_AIR), item(BRONZE_FULL_HELM), item(AMULET_OF_POWER)), + new EmoteClue("Dance at the cat-doored pyramid in Sophanem. Beware of double agents! Equip a ring of life, an uncharged amulet of glory and an adamant two-handed sword.", OUTSIDE_THE_GREAT_PYRAMID_OF_SOPHANEM, new WorldPoint(3294, 2781, 0), DANCE, item(RING_OF_LIFE), item(AMULET_OF_GLORY), item(ADAMANT_2H_SWORD)), + new EmoteClue("Dance in the centre of Canifis. Bow before you talk to me. Equip a green gnome robe top, mithril plate legs and an iron two-handed sword.", CENTRE_OF_CANIFIS, new WorldPoint(3492, 3488, 0), DANCE, BOW, item(GREEN_ROBE_TOP), item(MITHRIL_PLATELEGS), item(IRON_2H_SWORD)), + new EmoteClue("Dance in the King Black Dragon's lair. Beware of double agents! Equip a black dragonhide body, black dragonhide vambs and a black dragon mask.", KING_BLACK_DRAGONS_LAIR, new WorldPoint(2271, 4680, 0), DANCE, item(BLACK_DHIDE_BODY), item(BLACK_DHIDE_VAMB), item(BLACK_DRAGON_MASK)), + new EmoteClue("Dance at the entrance to the Grand Exchange. Equip a pink skirt, pink robe top and a body tiara.", SOUTH_OF_THE_GRAND_EXCHANGE, new WorldPoint(3165, 3467, 0), DANCE, item(PINK_SKIRT), item(PINK_ROBE_TOP), item(BODY_TIARA)), + new EmoteClue("Goblin Salute in the Goblin Village. Beware of double agents! Equip a bandos godsword, a bandos cloak and a bandos platebody.", OUTSIDE_MUDKNUCKLES_HUT, new WorldPoint(2956, 3505, 0), GOBLIN_SALUTE, item(BANDOS_PLATEBODY), item(BANDOS_CLOAK), item(BANDOS_GODSWORD)), + new EmoteClue("Headbang in the mine north of Al Kharid. Equip a desert shirt, leather gloves and leather boots.", AL_KHARID_SCORPION_MINE, new WorldPoint(3299, 3289, 0), HEADBANG, item(DESERT_SHIRT), item(LEATHER_GLOVES), item(LEATHER_BOOTS)), + new EmoteClue("Headbang at the exam center. Beware of double agents! Equip a mystic fire staff, a diamond bracelet and rune boots.", OUTSIDE_THE_DIGSITE_EXAM_CENTRE, new WorldPoint(3362, 3340, 0), HEADBANG, item(MYSTIC_FIRE_STAFF), item(DIAMOND_BRACELET), item(RUNE_BOOTS)), + new EmoteClue("Headbang at the top of Slayer Tower. Equip a seercull, a combat bracelet and helm of Neitiznot.", OUTSIDE_THE_SLAYER_TOWER_GARGOYLE_ROOM, new WorldPoint(3421, 3537, 2), HEADBANG, item(SEERCULL), range("Combat bracelet", COMBAT_BRACELET4, COMBAT_BRACELET), item(HELM_OF_NEITIZNOT)), + new EmoteClue("Dance a jig by the entrance to the Fishing Guild. Equip an emerald ring, a sapphire amulet, and a bronze chain body.", OUTSIDE_THE_FISHING_GUILD, new WorldPoint(2610, 3391, 0), JIG, item(EMERALD_RING), item(SAPPHIRE_AMULET), item(BRONZE_CHAINBODY)), + new EmoteClue("Dance a jig under Shantay's Awning. Bow before you talk to me. Equip a pointed blue snail helmet, an air staff and a bronze square shield.", SHANTAY_PASS, new WorldPoint(3304, 3124, 0), JIG, BOW, any("Bruise blue snelm (pointed)", item(BRUISE_BLUE_SNELM_3343)), item(STAFF_OF_AIR), item(BRONZE_SQ_SHIELD)), + new EmoteClue("Do a jig in Varrock's rune store. Equip an air tiara and a staff of water.", AUBURYS_SHOP_IN_VARROCK, new WorldPoint(3253, 3401, 0), JIG, item(AIR_TIARA), item(STAFF_OF_WATER)), + new EmoteClue("Jump for joy at the beehives. Equip a desert shirt, green gnome robe bottoms and a steel axe.", CATHERBY_BEEHIVE_FIELD, new WorldPoint(2759, 3445, 0), JUMP_FOR_JOY, item(DESERT_SHIRT), item(GREEN_ROBE_BOTTOMS), item(STEEL_AXE)), + new EmoteClue("Jump for joy in Yanille bank. Dance a jig before you talk to me. Equip a brown apron, adamantite medium helmet and snakeskin chaps.", OUTSIDE_YANILLE_BANK, new WorldPoint(2610, 3092, 0), JUMP_FOR_JOY, JIG, item(BROWN_APRON), item(ADAMANT_MED_HELM), item(SNAKESKIN_CHAPS)), + new EmoteClue("Jump for joy in the TzHaar sword shop. Shrug before you talk to me. Equip a Steel longsword, Blue D'hide body and blue mystic gloves.", TZHAAR_WEAPONS_STORE, new WorldPoint(2477, 5146, 0), JUMP_FOR_JOY, SHRUG, item(STEEL_LONGSWORD), item(BLUE_DHIDE_BODY), item(MYSTIC_GLOVES)), + new EmoteClue("Jump for joy in the Ancient Cavern. Equip a granite shield, splitbark body and any rune heraldic helm.", ENTRANCE_OF_THE_CAVERN_UNDER_THE_WHIRLPOOL, new WorldPoint(1768, 5366, 1), JUMP_FOR_JOY, item(GRANITE_SHIELD), item(SPLITBARK_BODY), range("Any rune heraldic helm", RUNE_HELM_H1, RUNE_HELM_H5)), + new EmoteClue("Jump for joy at the Neitiznot rune rock. Equip Rune boots, a proselyte hauberk and a dragonstone ring.", NEAR_A_RUNITE_ROCK_IN_THE_FREMENNIK_ISLES, new WorldPoint(2375, 3850, 0), JUMP_FOR_JOY, item(RUNE_BOOTS), item(PROSELYTE_HAUBERK), item(DRAGONSTONE_RING)), + new EmoteClue("Jump for joy in the centre of Zul-Andra. Beware of double agents! Equip a dragon 2h sword, bandos boots and an obsidian cape.", NEAR_THE_PIER_IN_ZULANDRA, new WorldPoint(2199, 3056, 0), JUMP_FOR_JOY, item(DRAGON_2H_SWORD), item(BANDOS_BOOTS), item(OBSIDIAN_CAPE)), + new EmoteClue("Laugh by the fountain of heroes. Equip splitbark legs, dragon boots and a Rune longsword.", FOUNTAIN_OF_HEROES, new WorldPoint(2920, 9893, 0), LAUGH, item(SPLITBARK_LEGS), item(DRAGON_BOOTS), item(RUNE_LONGSWORD)), + new EmoteClue("Laugh in Jokul's tent in the Mountain Camp. Beware of double agents! Equip a rune full helmet, blue dragonhide chaps and a fire battlestaff.", MOUNTAIN_CAMP_GOAT_ENCLOSURE, new WorldPoint(2812, 3681, 0), LAUGH, item(RUNE_FULL_HELM), item(BLUE_DHIDE_CHAPS), item(FIRE_BATTLESTAFF)), + new EmoteClue("Laugh at the crossroads south of the Sinclair Mansion. Equip a cowl, a blue wizard robe top and an iron scimitar.", ROAD_JUNCTION_SOUTH_OF_SINCLAIR_MANSION, new WorldPoint(2741, 3536, 0), LAUGH, item(LEATHER_COWL), item(BLUE_WIZARD_ROBE), item(IRON_SCIMITAR)), + new EmoteClue("Laugh in front of the gem store in Ardougne market. Equip a Castlewars bracelet, a dragonstone amulet and a ring of forging.", NEAR_THE_GEM_STALL_IN_ARDOUGNE_MARKET, new WorldPoint(2666, 3304, 0), LAUGH, any("Castle wars bracelet", range(CASTLE_WARS_BRACELET3, CASTLE_WARS_BRACELET1)), item(DRAGONSTONE_AMULET), item(RING_OF_FORGING)), + new EmoteClue("Panic in the Limestone Mine. Equip bronze platelegs, a steel pickaxe and a steel medium helmet.", LIMESTONE_MINE, new WorldPoint(3372, 3498, 0), PANIC, item(BRONZE_PLATELEGS), item(STEEL_PICKAXE), item(STEEL_MED_HELM)), + new EmoteClue("Panic by the mausoleum in Morytania. Wave before you speak to me. Equip a mithril plate skirt, a maple longbow and no boots.", MAUSOLEUM_OFF_THE_MORYTANIA_COAST, new WorldPoint(3504, 3576, 0), PANIC, WAVE, item(MITHRIL_PLATESKIRT), item(MAPLE_LONGBOW), emptySlot("No boots", BOOTS)), + new EmoteClue("Panic on the Wilderness volcano bridge. Beware of double agents! Equip any headband and crozier.", VOLCANO_IN_THE_NORTHEASTERN_WILDERNESS, new WorldPoint(3368, 3935, 0), PANIC, any("Any headband", range(RED_HEADBAND, BROWN_HEADBAND), range(WHITE_HEADBAND, GREEN_HEADBAND)), any("Any crozier", item(ANCIENT_CROZIER), item(ARMADYL_CROZIER), item(BANDOS_CROZIER), range(SARADOMIN_CROZIER, ZAMORAK_CROZIER))), + 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), 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)), + new EmoteClue("Salute in the banana plantation. Beware of double agents! Equip a diamond ring, amulet of power, and nothing on your chest and legs.", WEST_SIDE_OF_THE_KARAMJA_BANANA_PLANTATION, new WorldPoint(2914, 3168, 0), SALUTE, item(DIAMOND_RING), item(AMULET_OF_POWER), emptySlot("Nothing on chest & legs", BODY, LEGS)), + new EmoteClue("Salute in the Warriors' guild bank. Equip only a black salamander.", WARRIORS_GUILD_BANK, new WorldPoint(2844, 3542, 0), SALUTE, item(BLACK_SALAMANDER), emptySlot("Nothing else", HEAD, CAPE, AMULET, BODY, SHIELD, LEGS, GLOVES, BOOTS, RING, AMMO)), + new EmoteClue("Salute in the centre of the mess hall. Beware of double agents! Equip a rune halberd rune platebody, and an amulet of strength.", HOSIDIUS_MESS, new WorldPoint(1646, 3632, 0), SALUTE, item(RUNE_HALBERD), item(RUNE_PLATEBODY), item(AMULET_OF_STRENGTH)), + new EmoteClue("Shrug in the mine near Rimmington. Equip a gold necklace, a gold ring and a bronze spear.", RIMMINGTON_MINE, new WorldPoint(2976, 3238, 0), SHRUG, item(GOLD_NECKLACE), item(GOLD_RING), item(BRONZE_SPEAR)), + new EmoteClue("Shrug in Catherby bank. Yawn before you talk to me. Equip a maple longbow, green d'hide chaps and an iron med helm.", OUTSIDE_CATHERBY_BANK, new WorldPoint(2808, 3440, 0), SHRUG, YAWN, item(MAPLE_LONGBOW), item(GREEN_DHIDE_CHAPS), item(IRON_MED_HELM)), + new EmoteClue("Shrug in the Zamorak temple found in the Eastern Wilderness. Beware of double agents! Equip rune platelegs, an iron platebody and blue dragonhide vambraces.", CHAOS_TEMPLE_IN_THE_SOUTHEASTERN_WILDERNESS, new WorldPoint(3239, 3611, 0), SHRUG, item(RUNE_PLATELEGS), item(IRON_PLATEBODY), item(BLUE_DHIDE_VAMB)), + new EmoteClue("Shrug in the Shayzien command tent. Equip a blue mystic robe bottom, a rune kiteshield and any bob shirt.", SHAYZIEN_WAR_TENT, new WorldPoint(1555, 3537, 0), SHRUG, item(MYSTIC_ROBE_BOTTOM), item(RUNE_KITESHIELD), range("Any bob shirt", BOBS_RED_SHIRT, BOBS_PURPLE_SHIRT)), + new EmoteClue("Slap your head in the centre of the Kourend catacombs. Beware of double agents! Equip the arclight and the amulet of the damned.", CENTRE_OF_THE_CATACOMBS_OF_KOUREND, new WorldPoint(1663, 10045, 0), SLAP_HEAD, item(ARCLIGHT), any("Amulet of the damned", item(AMULET_OF_THE_DAMNED), item(AMULET_OF_THE_DAMNED_FULL))), + new EmoteClue("Spin at the crossroads north of Rimmington. Equip a green gnome hat, cream gnome top and leather chaps.", ROAD_JUNCTION_NORTH_OF_RIMMINGTON, new WorldPoint(2981, 3276, 0), SPIN, item(GREEN_HAT), item(CREAM_ROBE_TOP), item(LEATHER_CHAPS)), + new EmoteClue("Spin in Draynor Manor by the fountain. Equip an iron platebody, studded leather chaps and a bronze full helmet.", DRAYNOR_MANOR_BY_THE_FOUNTAIN, new WorldPoint(3088, 3336, 0), SPIN, item(IRON_PLATEBODY), item(STUDDED_CHAPS), item(BRONZE_FULL_HELM)), + new EmoteClue("Spin in front of the Soul altar. Beware of double agents! Equip a dragon pickaxe, helm of neitiznot and a pair of rune boots.", SOUL_ALTAR, new WorldPoint(1815, 3856, 0), SPIN, any("Dragon pickaxe", item(DRAGON_PICKAXE), item(DRAGON_PICKAXE_12797), item(INFERNAL_PICKAXE), item(INFERNAL_PICKAXE_UNCHARGED)), item(HELM_OF_NEITIZNOT), item(RUNE_BOOTS)), + new EmoteClue("Spin in the Varrock Castle courtyard. Equip a black axe, a coif and a ruby ring.", OUTSIDE_VARROCK_PALACE_COURTYARD, new WorldPoint(3213, 3463, 0), SPIN, item(BLACK_AXE), item(COIF), item(RUBY_RING)), + new EmoteClue("Spin in West Ardougne Church. Equip a dragon spear and red dragonhide chaps.", CHAPEL_IN_WEST_ARDOUGNE, new WorldPoint(2530, 3290, 0), SPIN, item(DRAGON_SPEAR), item(RED_DHIDE_CHAPS)), + new EmoteClue("Spin on the bridge by the Barbarian Village. Salute before you talk to me. Equip purple gloves, a steel kiteshield and a mithril full helmet.", EAST_OF_THE_BARBARIAN_VILLAGE_BRIDGE, new WorldPoint(3105, 3420, 0), SPIN, SALUTE, item(PURPLE_GLOVES), item(STEEL_KITESHIELD), item(MITHRIL_FULL_HELM)), + new EmoteClue("Stamp in the Enchanted valley west of the waterfall. Beware of double agents! Equip a dragon axe.", NORTHWESTERN_CORNER_OF_THE_ENCHANTED_VALLEY, new WorldPoint(3030, 4522, 0), STOMP, item(DRAGON_AXE)), + new EmoteClue("Think in middle of the wheat field by the Lumbridge mill. Equip a blue gnome robetop, a turquoise gnome robe bottom and an oak shortbow.", WHEAT_FIELD_NEAR_THE_LUMBRIDGE_WINDMILL, new WorldPoint(3159, 3298, 0), THINK, item(BLUE_ROBE_TOP), item(TURQUOISE_ROBE_BOTTOMS), item(OAK_SHORTBOW)), + new EmoteClue("Think in the centre of the Observatory. Spin before you talk to me. Equip a mithril chain body, green dragonhide chaps and a ruby amulet.", OBSERVATORY, new WorldPoint(2439, 3161, 0), THINK, SPIN, item(MITHRIL_CHAINBODY), item(GREEN_DHIDE_CHAPS), item(RUBY_AMULET)), + new EmoteClue("Wave along the south fence of the Lumber Yard. Equip a hard leather body, leather chaps and a bronze axe.", NEAR_THE_SAWMILL_OPERATORS_BOOTH, new WorldPoint(3307, 3491, 0), WAVE, item(HARDLEATHER_BODY), item(LEATHER_CHAPS), item(BRONZE_AXE)), + new EmoteClue("Wave in the Falador gem store. Equip a Mithril pickaxe, Black platebody and an Iron Kiteshield.", NEAR_HERQUINS_SHOP_IN_FALADOR, new WorldPoint(2945, 3335, 0), WAVE, item(MITHRIL_PICKAXE), item(BLACK_PLATEBODY), item(IRON_KITESHIELD)), + new EmoteClue("Wave on Mudskipper Point. Equip a black cape, leather chaps and a steel mace.", MUDSKIPPER_POINT, new WorldPoint(2989, 3110, 0), WAVE, item(BLACK_CAPE), item(LEATHER_CHAPS), item(STEEL_MACE)), + new EmoteClue("Wave on the northern wall of Castle Drakan. Beware of double agents! Wear a dragon sq shield, splitbark body and any boater.", NORTHERN_WALL_OF_CASTLE_DRAKAN, new WorldPoint(3560, 3385, 0), WAVE, item(DRAGON_SQ_SHIELD), item(SPLITBARK_BODY), any("Any boater", item(RED_BOATER), item(ORANGE_BOATER), item(GREEN_BOATER), item(BLUE_BOATER), item(BLACK_BOATER), item(PINK_BOATER), item(PURPLE_BOATER), item(WHITE_BOATER))), + new EmoteClue("Yawn in the 7th room of Pyramid Plunder. Beware of double agents! Equip a pharaoh sceptre and a full set of menaphite robes.", _7TH_CHAMBER_OF_JALSAVRAH, new WorldPoint(1944, 4427, 0), YAWN, any("Pharaoh's sceptre", item(PHARAOHS_SCEPTRE), item(PHARAOHS_SCEPTRE_1), item(PHARAOHS_SCEPTRE_2), item(PHARAOHS_SCEPTRE_3), item(PHARAOHS_SCEPTRE_4), item(PHARAOHS_SCEPTRE_5), item(PHARAOHS_SCEPTRE_6), item(PHARAOHS_SCEPTRE_7), item(PHARAOHS_SCEPTRE_8)), any("Full set of menaphite robes", all(item(MENAPHITE_PURPLE_HAT), item(MENAPHITE_PURPLE_TOP), range(MENAPHITE_PURPLE_ROBE, MENAPHITE_PURPLE_KILT)), all(item(MENAPHITE_RED_HAT), item(MENAPHITE_RED_TOP), range(MENAPHITE_RED_ROBE, MENAPHITE_RED_KILT)))), + new EmoteClue("Yawn in the Varrock library. Equip a green gnome robe top, HAM robe bottom and an iron warhammer.", VARROCK_PALACE_LIBRARY, new WorldPoint(3209, 3492, 0), YAWN, item(GREEN_ROBE_TOP), item(HAM_ROBE), item(IRON_WARHAMMER)), + new EmoteClue("Yawn in Draynor Marketplace. Equip studded leather chaps, an iron kiteshield and a steel longsword.", DRAYNOR_VILLAGE_MARKET, new WorldPoint(3083, 3253, 0), YAWN, item(STUDDED_CHAPS), item(IRON_KITESHIELD), item(STEEL_LONGSWORD)), + new EmoteClue("Yawn in the Castle Wars lobby. Shrug before you talk to me. Equip a ruby amulet, a mithril scimitar and a Wilderness cape.", CASTLE_WARS_BANK, new WorldPoint(2440, 3092, 0), YAWN, SHRUG, item(RUBY_AMULET), item(MITHRIL_SCIMITAR), range("Any team cape", TEAM1_CAPE, TEAM50_CAPE)), + new EmoteClue("Yawn in the rogues' general store. Beware of double agents! Equip an adamant square shield, blue dragon vambraces and a rune pickaxe.", NOTERAZZOS_SHOP_IN_THE_WILDERNESS, new WorldPoint(3026, 3701, 0), YAWN, item(ADAMANT_SQ_SHIELD), item(BLUE_DHIDE_VAMB), item(RUNE_PICKAXE)), + new EmoteClue("Yawn at the top of Trollheim. Equip a lava battlestaff, black dragonhide vambraces and a mind shield.", ON_TOP_OF_TROLLHEIM_MOUNTAIN, new WorldPoint(2887, 3676, 0), YAWN, item(LAVA_BATTLESTAFF), item(BLACK_DHIDE_VAMB), item(MIND_SHIELD)), + new EmoteClue("Yawn in the centre of Arceuus library. Nod your head before you talk to me. Equip blue dragonhide vambraces, adamant boots and an adamant dagger.", ENTRANCE_OF_THE_ARCEUUS_LIBRARY, new WorldPoint(1632, 3807, 0), YAWN, YES, item(BLUE_DHIDE_VAMB), item(ADAMANT_BOOTS), item(ADAMANT_DAGGER)), + new EmoteClue("Swing a bullroarer at the top of the watchtower. Beware of double agents! Equip a dragon plateskirt, climbing boots and a dragon chainbody.", TOP_FLOOR_OF_THE_YANILLE_WATCHTOWER, new WorldPoint(2932, 4712, 0), BULL_ROARER, item(DRAGON_PLATESKIRT), item(CLIMBING_BOOTS), item(DRAGON_CHAINBODY_3140), item(ItemID.BULL_ROARER)), + new EmoteClue("Blow a raspberry at Gypsy Aris in her tent. Equip a gold ring and a gold necklace.", GYPSY_TENT_ENTRANCE, new WorldPoint(3203, 3424, 0), RASPBERRY, item(GOLD_RING), item(GOLD_NECKLACE)), + new EmoteClue("Bow to Brugsen Bursen at the Grand Exchange.", null, new WorldPoint(3164, 3477, 0), BOW), + new EmoteClue("Cheer at Iffie Nitter. Equip a chef hat and a red cape.", FINE_CLOTHES_ENTRANCE, new WorldPoint(3205, 3416, 0), CHEER, item(CHEFS_HAT), item(RED_CAPE)), + new EmoteClue("Clap at Bob's Brilliant Axes. Equip a bronze axe and leather boots.", BOB_AXES_ENTRANCE, new WorldPoint(3231, 3203, 0), CLAP, item(BRONZE_AXE), item(LEATHER_BOOTS)), + new EmoteClue("Panic at Al Kharid mine.", null, new WorldPoint(3300, 3314, 0), PANIC), + new EmoteClue("Spin at Flynn's Mace Shop.", null, new WorldPoint(2950, 3387, 0), SPIN)); + + private static SingleItemRequirement item(int itemId) + { + return new SingleItemRequirement(itemId); + } + + private static RangeItemRequirement range(int startItemId, int endItemId) + { + return range(null, startItemId, endItemId); + } + + private static RangeItemRequirement range(String name, int startItemId, int endItemId) + { + return new RangeItemRequirement(name, startItemId, endItemId); + } + + private static AnyRequirementCollection any(String name, ItemRequirement... requirements) + { + return new AnyRequirementCollection(name, requirements); + } + + private static AllRequirementsCollection all(ItemRequirement... requirements) + { + return new AllRequirementsCollection(requirements); + } + + private static SlotLimitationRequirement emptySlot(String description, EquipmentInventorySlot... slots) + { + return new SlotLimitationRequirement(description, slots); + } + + private final String text; + private final Integer stashUnit; + private final WorldPoint location; + private final Emote firstEmote; + private final Emote secondEmote; + @Nonnull + private final ItemRequirement[] itemRequirements; + + private EmoteClue(String text, Integer stashUnit, WorldPoint location, Emote firstEmote, @Nonnull ItemRequirement... itemRequirements) + { + this(text, stashUnit, location, firstEmote, null, itemRequirements); + } + + private EmoteClue(String text, Integer stashUnit, WorldPoint location, Emote firstEmote, Emote secondEmote, @Nonnull ItemRequirement... itemRequirements) + { + this.text = text; + this.stashUnit = stashUnit; + this.location = location; + this.firstEmote = firstEmote; + this.secondEmote = secondEmote; + this.itemRequirements = itemRequirements; + } + + @Override + public void makeOverlayHint(PanelComponent panelComponent, ClueScrollPlugin plugin) + { + panelComponent.getChildren().add(TitleComponent.builder().text("Emote Clue").build()); + panelComponent.getChildren().add(LineComponent.builder().left("Emotes:").build()); + panelComponent.getChildren().add(LineComponent.builder() + .left(getFirstEmote().getName()) + .leftColor(TITLED_CONTENT_COLOR) + .build()); + + if (getSecondEmote() != null) + { + panelComponent.getChildren().add(LineComponent.builder() + .left(getSecondEmote().getName()) + .leftColor(TITLED_CONTENT_COLOR) + .build()); + } + + if (itemRequirements.length > 0) + { + panelComponent.getChildren().add(LineComponent.builder().left("Equip:").build()); + + Item[] equipment = plugin.getEquippedItems(); + Item[] inventory = plugin.getInventoryItems(); + + // If equipment is null, the player is wearing nothing + if (equipment == null) + { + equipment = new Item[0]; + } + + // If inventory is null, the player has nothing in their inventory + if (inventory == null) + { + inventory = new Item[0]; + } + + Item[] combined = new Item[equipment.length + inventory.length]; + System.arraycopy(equipment, 0, combined, 0, equipment.length); + System.arraycopy(inventory, 0, combined, equipment.length, inventory.length); + + for (ItemRequirement requirement : itemRequirements) + { + boolean equipmentFulfilled = requirement.fulfilledBy(equipment); + boolean combinedFulfilled = requirement.fulfilledBy(combined); + + panelComponent.getChildren().add(LineComponent.builder() + .left(requirement.getCollectiveName(plugin.getClient())) + .leftColor(TITLED_CONTENT_COLOR) + .right(combinedFulfilled ? "\u2713" : "\u2717") + .rightColor(equipmentFulfilled ? Color.GREEN : (combinedFulfilled ? Color.ORANGE : Color.RED)) + .build()); + } + } + } + + @Override + public void makeWorldOverlayHint(Graphics2D graphics, ClueScrollPlugin plugin) + { + LocalPoint localLocation = LocalPoint.fromWorld(plugin.getClient(), getLocation()); + + if (localLocation == null) + { + return; + } + + OverlayUtil.renderTileOverlay(plugin.getClient(), graphics, localLocation, plugin.getEmoteImage(), Color.ORANGE); + } + + public static EmoteClue forText(String text) + { + for (EmoteClue clue : CLUES) + { + if (clue.getText().equalsIgnoreCase(text)) + { + return clue; + } + } + + return null; + } +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/clues/FaloTheBardClue.java b/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/clues/FaloTheBardClue.java index 68ad2e0af8..00162a541f 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/clues/FaloTheBardClue.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/clues/FaloTheBardClue.java @@ -184,7 +184,7 @@ public class FaloTheBardClue extends ClueScroll implements TextClueScroll, NpcCl @Override public String[] getNpcs() { - return new String[] {FALO_THE_BARD}; + return new String[]{FALO_THE_BARD}; } public static FaloTheBardClue forText(String text) diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/clues/HotColdClue.java b/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/clues/HotColdClue.java index 826017744f..af5deae6cf 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/clues/HotColdClue.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/clues/HotColdClue.java @@ -1,411 +1,411 @@ -/* - * Copyright (c) 2018, Eadgars Ruse - * 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.cluescrolls.clues; - -import com.google.common.collect.Lists; -import java.awt.Color; -import java.awt.Dimension; -import java.awt.Graphics2D; -import java.awt.Point; -import java.awt.Rectangle; -import java.awt.geom.Rectangle2D; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.regex.Matcher; -import java.util.regex.Pattern; -import lombok.Getter; -import net.runelite.api.NPC; -import net.runelite.api.coords.LocalPoint; -import net.runelite.api.coords.WorldPoint; -import static net.runelite.client.plugins.cluescrolls.ClueScrollOverlay.TITLED_CONTENT_COLOR; -import net.runelite.client.plugins.cluescrolls.ClueScrollPlugin; -import static net.runelite.client.plugins.cluescrolls.ClueScrollWorldOverlay.IMAGE_Z_OFFSET; -import net.runelite.client.plugins.cluescrolls.clues.hotcold.HotColdArea; -import net.runelite.client.plugins.cluescrolls.clues.hotcold.HotColdLocation; -import net.runelite.client.ui.overlay.OverlayUtil; -import net.runelite.client.ui.overlay.components.LineComponent; -import net.runelite.client.ui.overlay.components.PanelComponent; -import net.runelite.client.ui.overlay.components.TitleComponent; - -@Getter -public class HotColdClue extends ClueScroll implements LocationClueScroll, LocationsClueScroll, TextClueScroll, NpcClueScroll -{ - private static final Pattern INITIAL_STRANGE_DEVICE_MESSAGE = Pattern.compile("The device is (.*)"); - private static final Pattern STRANGE_DEVICE_MESSAGE = Pattern.compile("The device is (.*), (.*) last time\\."); - private static final Pattern FINAL_STRANGE_DEVICE_MESSAGE = Pattern.compile("The device is visibly shaking.*"); - private static final HotColdClue CLUE = - new HotColdClue("Buried beneath the ground, who knows where it's found. Lucky for you, A man called Jorral may have a clue.", - "Jorral", - "Speak to Jorral to receive a strange device."); - - // list of potential places to dig - private List digLocations = new ArrayList<>(); - private final String text; - private final String npc; - private final String solution; - private WorldPoint location; - private WorldPoint lastWorldPoint; - - public static HotColdClue forText(String text) - { - if (CLUE.text.equalsIgnoreCase(text)) - { - return CLUE; - } - - return null; - } - - private HotColdClue(String text, String npc, String solution) - { - this.text = text; - this.npc = npc; - this.solution = solution; - setRequiresSpade(true); - } - - @Override - public WorldPoint[] getLocations() - { - return Lists.transform(digLocations, HotColdLocation::getWorldPoint).toArray(new WorldPoint[0]); - } - - @Override - public void makeOverlayHint(PanelComponent panelComponent, ClueScrollPlugin plugin) - { - panelComponent.getChildren().add(TitleComponent.builder() - .text("Hot/Cold Clue") - .build()); - panelComponent.setPreferredSize(new Dimension(200, 0)); - - // strange device has not been tested yet, show how to get it - if (lastWorldPoint == null && location == null) - { - if (getNpc() != null) - { - panelComponent.getChildren().add(LineComponent.builder() - .left("NPC:") - .build()); - panelComponent.getChildren().add(LineComponent.builder() - .left(getNpc()) - .leftColor(TITLED_CONTENT_COLOR) - .build()); - } - - panelComponent.getChildren().add(LineComponent.builder() - .left("Solution:") - .build()); - panelComponent.getChildren().add(LineComponent.builder() - .left(getSolution()) - .leftColor(TITLED_CONTENT_COLOR) - .build()); - } - // strange device has been tested, show possible locations for final dig spot - else - { - panelComponent.getChildren().add(LineComponent.builder() - .left("Possible areas:") - .build()); - Map locationCounts = new HashMap<>(); - - for (HotColdLocation hotColdLocation : digLocations) - { - HotColdArea hotColdArea = hotColdLocation.getHotColdArea(); - - if (locationCounts.containsKey(hotColdArea)) - { - locationCounts.put(hotColdArea, locationCounts.get(hotColdArea) + 1); - } - else - { - locationCounts.put(hotColdArea, 1); - } - } - - if (digLocations.size() > 10) - { - for (HotColdArea area : locationCounts.keySet()) - { - panelComponent.getChildren().add(LineComponent.builder() - .left(area.getName()) - .right(Integer.toString(locationCounts.get(area))) - .build()); - } - } - else - { - for (HotColdArea s : locationCounts.keySet()) - { - panelComponent.getChildren().add(LineComponent.builder() - .left(s.getName() + ":") - .build()); - - for (HotColdLocation hotColdLocation : digLocations) - { - if (hotColdLocation.getHotColdArea() == s) - { - Rectangle2D r = hotColdLocation.getRect(); - panelComponent.getChildren().add(LineComponent.builder() - .left("- " + hotColdLocation.getArea()) - .leftColor(Color.LIGHT_GRAY) - .build()); - } - } - } - } - } - } - - @Override - public void makeWorldOverlayHint(Graphics2D graphics, ClueScrollPlugin plugin) - { - // when final location has been found - if (this.location != null) - { - LocalPoint localLocation = LocalPoint.fromWorld(plugin.getClient(), getLocation()); - - if (localLocation != null) - { - OverlayUtil.renderTileOverlay(plugin.getClient(), graphics, localLocation, plugin.getSpadeImage(), Color.ORANGE); - } - - return; - } - - // when strange device hasn't been activated yet, show Jorral - if (lastWorldPoint == null) - { - // Mark NPC - if (plugin.getNpcsToMark() != null) - { - for (NPC npc : plugin.getNpcsToMark()) - { - OverlayUtil.renderActorOverlayImage(graphics, npc, plugin.getClueScrollImage(), Color.ORANGE, IMAGE_Z_OFFSET); - } - } - } - - // once the number of possible dig locations is below 10, show the dig spots - if (digLocations.size() < 10) - { - // Mark potential dig locations - for (HotColdLocation hotColdLocation : digLocations) - { - WorldPoint wp = hotColdLocation.getWorldPoint(); - LocalPoint localLocation = LocalPoint.fromWorld(plugin.getClient(), wp.getX(), wp.getY()); - - if (localLocation == null) - { - return; - } - - OverlayUtil.renderTileOverlay(plugin.getClient(), graphics, localLocation, plugin.getSpadeImage(), Color.ORANGE); - } - } - } - - public boolean update(final String message, final ClueScrollPlugin plugin) - { - if (!message.startsWith("The device is")) - { - return false; - } - - Matcher m1 = FINAL_STRANGE_DEVICE_MESSAGE.matcher(message); - Matcher m2 = STRANGE_DEVICE_MESSAGE.matcher(message); - Matcher m3 = INITIAL_STRANGE_DEVICE_MESSAGE.matcher(message); - - // the order that these pattern matchers are checked is important - if (m1.find()) - { - // final location for hot cold clue has been found - WorldPoint localWorld = plugin.getClient().getLocalPlayer().getWorldLocation(); - - if (localWorld != null) - { - markFinalSpot(localWorld); - return true; - } - } - else if (m2.find()) - { - String temperature = m2.group(1); - String difference = m2.group(2); - WorldPoint localWorld = plugin.getClient().getLocalPlayer().getWorldLocation(); - - if (localWorld != null) - { - updatePossibleArea(localWorld, temperature, difference); - return true; - } - } - else if (m3.find()) - { - String temperature = m3.group(1); - WorldPoint localWorld = plugin.getClient().getLocalPlayer().getWorldLocation(); - - if (localWorld != null) - { - updatePossibleArea(localWorld, temperature, ""); - return true; - } - } - - return false; - } - - @Override - public void reset() - { - this.lastWorldPoint = null; - digLocations.clear(); - } - - private void updatePossibleArea(WorldPoint currentWp, String temperature, String difference) - { - this.location = null; - - if (digLocations.isEmpty()) - { - digLocations.addAll(Arrays.asList(HotColdLocation.values())); - } - - int maxSquaresAway = 5000; - int minSquaresAway = 0; - - switch (temperature) - { - // when the strange device reads a temperature, that means that the center of the final dig location - // is a range of squares away from the player's current location (Chebyshev AKA Chess-board distance) - case "ice cold": - maxSquaresAway = 5000; - minSquaresAway = 500; - break; - case "very cold": - maxSquaresAway = 499; - minSquaresAway = 200; - break; - case "cold": - maxSquaresAway = 199; - minSquaresAway = 150; - break; - case "warm": - maxSquaresAway = 149; - minSquaresAway = 100; - break; - case "hot": - maxSquaresAway = 99; - minSquaresAway = 70; - break; - case "very hot": - maxSquaresAway = 69; - minSquaresAway = 30; - break; - case "incredibly hot": - maxSquaresAway = 29; - minSquaresAway = 5; - break; - } - - // rectangle r1 encompasses all of the points that are within the max possible distance from the player - Point p1 = new Point(currentWp.getX() - maxSquaresAway, currentWp.getY() - maxSquaresAway); - Rectangle r1 = new Rectangle((int) p1.getX(), (int) p1.getY(), 2 * maxSquaresAway + 1, 2 * maxSquaresAway + 1); - // rectangle r2 encompasses all of the points that are within the min possible distance from the player - Point p2 = new Point(currentWp.getX() - minSquaresAway, currentWp.getY() - minSquaresAway); - Rectangle r2 = new Rectangle((int) p2.getX(), (int) p2.getY(), 2 * minSquaresAway + 1, 2 * minSquaresAway + 1); - - // eliminate from consideration dig spots that lie entirely within the min range or entirely outside of the max range - digLocations.removeIf(entry -> r2.contains(entry.getRect()) || !r1.intersects(entry.getRect())); - - // if a previous world point has been recorded, we can consider the warmer/colder result from the strange device - if (lastWorldPoint != null) - { - switch (difference) - { - case "but colder than": - // eliminate spots that are absolutely warmer - digLocations.removeIf(entry -> isFirstPointCloserRect(currentWp, lastWorldPoint, entry.getRect())); - break; - case "and warmer than": - // eliminate spots that are absolutely colder - digLocations.removeIf(entry -> isFirstPointCloserRect(lastWorldPoint, currentWp, entry.getRect())); - break; - case "and the same temperature as": - // I couldn't figure out a clean implementation for this case - // not necessary for quickly determining final location - } - } - - lastWorldPoint = currentWp; - } - - private boolean isFirstPointCloserRect(WorldPoint firstWp, WorldPoint secondWp, Rectangle2D r) - { - WorldPoint p1 = new WorldPoint((int) r.getMaxX(), (int) r.getMaxY(), 0); - - if (!isFirstPointCloser(firstWp, secondWp, p1)) - { - return false; - } - - WorldPoint p2 = new WorldPoint((int) r.getMaxX(), (int) r.getMinY(), 0); - - if (!isFirstPointCloser(firstWp, secondWp, p2)) - { - return false; - } - - WorldPoint p3 = new WorldPoint((int) r.getMinX(), (int)r.getMaxY(), 0); - - if (!isFirstPointCloser(firstWp, secondWp, p3)) - { - return false; - } - - WorldPoint p4 = new WorldPoint((int) r.getMinX(), (int) r.getMinY(), 0); - return (isFirstPointCloser(firstWp, secondWp, p4)); - } - - private boolean isFirstPointCloser(WorldPoint firstWp, WorldPoint secondWp, WorldPoint wp) - { - int firstDistance = firstWp.distanceTo2D(wp); - int secondDistance = secondWp.distanceTo2D(wp); - return (firstDistance < secondDistance); - } - - private void markFinalSpot(WorldPoint wp) - { - this.location = wp; - reset(); - } - - public String[] getNpcs() - { - return new String[] {npc}; - } +/* + * Copyright (c) 2018, Eadgars Ruse + * 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.cluescrolls.clues; + +import com.google.common.collect.Lists; +import java.awt.Color; +import java.awt.Dimension; +import java.awt.Graphics2D; +import java.awt.Point; +import java.awt.Rectangle; +import java.awt.geom.Rectangle2D; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import lombok.Getter; +import net.runelite.api.NPC; +import net.runelite.api.coords.LocalPoint; +import net.runelite.api.coords.WorldPoint; +import static net.runelite.client.plugins.cluescrolls.ClueScrollOverlay.TITLED_CONTENT_COLOR; +import net.runelite.client.plugins.cluescrolls.ClueScrollPlugin; +import static net.runelite.client.plugins.cluescrolls.ClueScrollWorldOverlay.IMAGE_Z_OFFSET; +import net.runelite.client.plugins.cluescrolls.clues.hotcold.HotColdArea; +import net.runelite.client.plugins.cluescrolls.clues.hotcold.HotColdLocation; +import net.runelite.client.ui.overlay.OverlayUtil; +import net.runelite.client.ui.overlay.components.LineComponent; +import net.runelite.client.ui.overlay.components.PanelComponent; +import net.runelite.client.ui.overlay.components.TitleComponent; + +@Getter +public class HotColdClue extends ClueScroll implements LocationClueScroll, LocationsClueScroll, TextClueScroll, NpcClueScroll +{ + private static final Pattern INITIAL_STRANGE_DEVICE_MESSAGE = Pattern.compile("The device is (.*)"); + private static final Pattern STRANGE_DEVICE_MESSAGE = Pattern.compile("The device is (.*), (.*) last time\\."); + private static final Pattern FINAL_STRANGE_DEVICE_MESSAGE = Pattern.compile("The device is visibly shaking.*"); + private static final HotColdClue CLUE = + new HotColdClue("Buried beneath the ground, who knows where it's found. Lucky for you, A man called Jorral may have a clue.", + "Jorral", + "Speak to Jorral to receive a strange device."); + + // list of potential places to dig + private List digLocations = new ArrayList<>(); + private final String text; + private final String npc; + private final String solution; + private WorldPoint location; + private WorldPoint lastWorldPoint; + + public static HotColdClue forText(String text) + { + if (CLUE.text.equalsIgnoreCase(text)) + { + return CLUE; + } + + return null; + } + + private HotColdClue(String text, String npc, String solution) + { + this.text = text; + this.npc = npc; + this.solution = solution; + setRequiresSpade(true); + } + + @Override + public WorldPoint[] getLocations() + { + return Lists.transform(digLocations, HotColdLocation::getWorldPoint).toArray(new WorldPoint[0]); + } + + @Override + public void makeOverlayHint(PanelComponent panelComponent, ClueScrollPlugin plugin) + { + panelComponent.getChildren().add(TitleComponent.builder() + .text("Hot/Cold Clue") + .build()); + panelComponent.setPreferredSize(new Dimension(200, 0)); + + // strange device has not been tested yet, show how to get it + if (lastWorldPoint == null && location == null) + { + if (getNpc() != null) + { + panelComponent.getChildren().add(LineComponent.builder() + .left("NPC:") + .build()); + panelComponent.getChildren().add(LineComponent.builder() + .left(getNpc()) + .leftColor(TITLED_CONTENT_COLOR) + .build()); + } + + panelComponent.getChildren().add(LineComponent.builder() + .left("Solution:") + .build()); + panelComponent.getChildren().add(LineComponent.builder() + .left(getSolution()) + .leftColor(TITLED_CONTENT_COLOR) + .build()); + } + // strange device has been tested, show possible locations for final dig spot + else + { + panelComponent.getChildren().add(LineComponent.builder() + .left("Possible areas:") + .build()); + Map locationCounts = new HashMap<>(); + + for (HotColdLocation hotColdLocation : digLocations) + { + HotColdArea hotColdArea = hotColdLocation.getHotColdArea(); + + if (locationCounts.containsKey(hotColdArea)) + { + locationCounts.put(hotColdArea, locationCounts.get(hotColdArea) + 1); + } + else + { + locationCounts.put(hotColdArea, 1); + } + } + + if (digLocations.size() > 10) + { + for (HotColdArea area : locationCounts.keySet()) + { + panelComponent.getChildren().add(LineComponent.builder() + .left(area.getName()) + .right(Integer.toString(locationCounts.get(area))) + .build()); + } + } + else + { + for (HotColdArea s : locationCounts.keySet()) + { + panelComponent.getChildren().add(LineComponent.builder() + .left(s.getName() + ":") + .build()); + + for (HotColdLocation hotColdLocation : digLocations) + { + if (hotColdLocation.getHotColdArea() == s) + { + Rectangle2D r = hotColdLocation.getRect(); + panelComponent.getChildren().add(LineComponent.builder() + .left("- " + hotColdLocation.getArea()) + .leftColor(Color.LIGHT_GRAY) + .build()); + } + } + } + } + } + } + + @Override + public void makeWorldOverlayHint(Graphics2D graphics, ClueScrollPlugin plugin) + { + // when final location has been found + if (this.location != null) + { + LocalPoint localLocation = LocalPoint.fromWorld(plugin.getClient(), getLocation()); + + if (localLocation != null) + { + OverlayUtil.renderTileOverlay(plugin.getClient(), graphics, localLocation, plugin.getSpadeImage(), Color.ORANGE); + } + + return; + } + + // when strange device hasn't been activated yet, show Jorral + if (lastWorldPoint == null) + { + // Mark NPC + if (plugin.getNpcsToMark() != null) + { + for (NPC npc : plugin.getNpcsToMark()) + { + OverlayUtil.renderActorOverlayImage(graphics, npc, plugin.getClueScrollImage(), Color.ORANGE, IMAGE_Z_OFFSET); + } + } + } + + // once the number of possible dig locations is below 10, show the dig spots + if (digLocations.size() < 10) + { + // Mark potential dig locations + for (HotColdLocation hotColdLocation : digLocations) + { + WorldPoint wp = hotColdLocation.getWorldPoint(); + LocalPoint localLocation = LocalPoint.fromWorld(plugin.getClient(), wp.getX(), wp.getY()); + + if (localLocation == null) + { + return; + } + + OverlayUtil.renderTileOverlay(plugin.getClient(), graphics, localLocation, plugin.getSpadeImage(), Color.ORANGE); + } + } + } + + public boolean update(final String message, final ClueScrollPlugin plugin) + { + if (!message.startsWith("The device is")) + { + return false; + } + + Matcher m1 = FINAL_STRANGE_DEVICE_MESSAGE.matcher(message); + Matcher m2 = STRANGE_DEVICE_MESSAGE.matcher(message); + Matcher m3 = INITIAL_STRANGE_DEVICE_MESSAGE.matcher(message); + + // the order that these pattern matchers are checked is important + if (m1.find()) + { + // final location for hot cold clue has been found + WorldPoint localWorld = plugin.getClient().getLocalPlayer().getWorldLocation(); + + if (localWorld != null) + { + markFinalSpot(localWorld); + return true; + } + } + else if (m2.find()) + { + String temperature = m2.group(1); + String difference = m2.group(2); + WorldPoint localWorld = plugin.getClient().getLocalPlayer().getWorldLocation(); + + if (localWorld != null) + { + updatePossibleArea(localWorld, temperature, difference); + return true; + } + } + else if (m3.find()) + { + String temperature = m3.group(1); + WorldPoint localWorld = plugin.getClient().getLocalPlayer().getWorldLocation(); + + if (localWorld != null) + { + updatePossibleArea(localWorld, temperature, ""); + return true; + } + } + + return false; + } + + @Override + public void reset() + { + this.lastWorldPoint = null; + digLocations.clear(); + } + + private void updatePossibleArea(WorldPoint currentWp, String temperature, String difference) + { + this.location = null; + + if (digLocations.isEmpty()) + { + digLocations.addAll(Arrays.asList(HotColdLocation.values())); + } + + int maxSquaresAway = 5000; + int minSquaresAway = 0; + + switch (temperature) + { + // when the strange device reads a temperature, that means that the center of the final dig location + // is a range of squares away from the player's current location (Chebyshev AKA Chess-board distance) + case "ice cold": + maxSquaresAway = 5000; + minSquaresAway = 500; + break; + case "very cold": + maxSquaresAway = 499; + minSquaresAway = 200; + break; + case "cold": + maxSquaresAway = 199; + minSquaresAway = 150; + break; + case "warm": + maxSquaresAway = 149; + minSquaresAway = 100; + break; + case "hot": + maxSquaresAway = 99; + minSquaresAway = 70; + break; + case "very hot": + maxSquaresAway = 69; + minSquaresAway = 30; + break; + case "incredibly hot": + maxSquaresAway = 29; + minSquaresAway = 5; + break; + } + + // rectangle r1 encompasses all of the points that are within the max possible distance from the player + Point p1 = new Point(currentWp.getX() - maxSquaresAway, currentWp.getY() - maxSquaresAway); + Rectangle r1 = new Rectangle((int) p1.getX(), (int) p1.getY(), 2 * maxSquaresAway + 1, 2 * maxSquaresAway + 1); + // rectangle r2 encompasses all of the points that are within the min possible distance from the player + Point p2 = new Point(currentWp.getX() - minSquaresAway, currentWp.getY() - minSquaresAway); + Rectangle r2 = new Rectangle((int) p2.getX(), (int) p2.getY(), 2 * minSquaresAway + 1, 2 * minSquaresAway + 1); + + // eliminate from consideration dig spots that lie entirely within the min range or entirely outside of the max range + digLocations.removeIf(entry -> r2.contains(entry.getRect()) || !r1.intersects(entry.getRect())); + + // if a previous world point has been recorded, we can consider the warmer/colder result from the strange device + if (lastWorldPoint != null) + { + switch (difference) + { + case "but colder than": + // eliminate spots that are absolutely warmer + digLocations.removeIf(entry -> isFirstPointCloserRect(currentWp, lastWorldPoint, entry.getRect())); + break; + case "and warmer than": + // eliminate spots that are absolutely colder + digLocations.removeIf(entry -> isFirstPointCloserRect(lastWorldPoint, currentWp, entry.getRect())); + break; + case "and the same temperature as": + // I couldn't figure out a clean implementation for this case + // not necessary for quickly determining final location + } + } + + lastWorldPoint = currentWp; + } + + private boolean isFirstPointCloserRect(WorldPoint firstWp, WorldPoint secondWp, Rectangle2D r) + { + WorldPoint p1 = new WorldPoint((int) r.getMaxX(), (int) r.getMaxY(), 0); + + if (!isFirstPointCloser(firstWp, secondWp, p1)) + { + return false; + } + + WorldPoint p2 = new WorldPoint((int) r.getMaxX(), (int) r.getMinY(), 0); + + if (!isFirstPointCloser(firstWp, secondWp, p2)) + { + return false; + } + + WorldPoint p3 = new WorldPoint((int) r.getMinX(), (int) r.getMaxY(), 0); + + if (!isFirstPointCloser(firstWp, secondWp, p3)) + { + return false; + } + + WorldPoint p4 = new WorldPoint((int) r.getMinX(), (int) r.getMinY(), 0); + return (isFirstPointCloser(firstWp, secondWp, p4)); + } + + private boolean isFirstPointCloser(WorldPoint firstWp, WorldPoint secondWp, WorldPoint wp) + { + int firstDistance = firstWp.distanceTo2D(wp); + int secondDistance = secondWp.distanceTo2D(wp); + return (firstDistance < secondDistance); + } + + private void markFinalSpot(WorldPoint wp) + { + this.location = wp; + reset(); + } + + public String[] getNpcs() + { + return new String[]{npc}; + } } \ No newline at end of file diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/clues/MapClue.java b/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/clues/MapClue.java index 99b1eef058..8e27090ddb 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/clues/MapClue.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/clues/MapClue.java @@ -1,209 +1,240 @@ -/* - * Copyright (c) 2018, Lotto - * 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.cluescrolls.clues; - -import com.google.common.collect.ImmutableSet; -import java.awt.Color; -import java.awt.Graphics2D; -import java.util.Set; -import lombok.Getter; -import static net.runelite.api.ItemID.*; -import net.runelite.api.ObjectComposition; -import static net.runelite.api.ObjectID.CRATE_18506; -import static net.runelite.api.ObjectID.CRATE_2620; -import static net.runelite.api.ObjectID.CRATE_354; -import static net.runelite.api.ObjectID.CRATE_357; -import static net.runelite.api.ObjectID.CRATE_6616; -import net.runelite.api.TileObject; -import net.runelite.api.coords.LocalPoint; -import net.runelite.api.coords.WorldPoint; -import net.runelite.client.plugins.cluescrolls.ClueScrollPlugin; -import static net.runelite.client.plugins.cluescrolls.ClueScrollWorldOverlay.CLICKBOX_BORDER_COLOR; -import static net.runelite.client.plugins.cluescrolls.ClueScrollWorldOverlay.CLICKBOX_FILL_COLOR; -import static net.runelite.client.plugins.cluescrolls.ClueScrollWorldOverlay.CLICKBOX_HOVER_BORDER_COLOR; -import static net.runelite.client.plugins.cluescrolls.ClueScrollWorldOverlay.IMAGE_Z_OFFSET; -import net.runelite.client.ui.overlay.OverlayUtil; -import net.runelite.client.ui.overlay.components.LineComponent; -import net.runelite.client.ui.overlay.components.PanelComponent; -import net.runelite.client.ui.overlay.components.TitleComponent; - -@Getter -public class MapClue extends ClueScroll implements ObjectClueScroll -{ - private static final Set CLUES = ImmutableSet.of( - new MapClue(CLUE_SCROLL_EASY_12179, new WorldPoint(3300, 3291, 0)), - new MapClue(CLUE_SCROLL_EASY_2713, new WorldPoint(3166, 3361, 0)), - new MapClue(CLUE_SCROLL_EASY_2716, new WorldPoint(3290, 3374, 0)), - new MapClue(CLUE_SCROLL_EASY_2719, new WorldPoint(3043, 3398, 0)), - new MapClue(CLUE_SCROLL_EASY_3516, new WorldPoint(2612, 3482, 0)), - new MapClue(CLUE_SCROLL_EASY_3518, new WorldPoint(3110, 3152, 0)), - new MapClue(CLUE_SCROLL_EASY_7236, new WorldPoint(2970, 3415, 0)), - new MapClue(CLUE_SCROLL_MEDIUM_2827, new WorldPoint(3091, 3227, 0)), - new MapClue(CLUE_SCROLL_MEDIUM_3596, new WorldPoint(2907, 3295, 0)), - new MapClue(CLUE_SCROLL_MEDIUM_3598, new WorldPoint(2658, 3488, 0), CRATE_357), - new MapClue(CLUE_SCROLL_MEDIUM_3599, new WorldPoint(2651, 3231, 0)), - new MapClue(CLUE_SCROLL_MEDIUM_3601, new WorldPoint(2565, 3248, 0), CRATE_354), - new MapClue(CLUE_SCROLL_MEDIUM_3602, new WorldPoint(2924, 3210, 0)), - new MapClue(CLUE_SCROLL_MEDIUM_7286, new WorldPoint(2536, 3865, 0)), - new MapClue(CLUE_SCROLL_MEDIUM_7288, new WorldPoint(3434, 3265, 0)), - new MapClue(CLUE_SCROLL_MEDIUM_7290, new WorldPoint(2454, 3230, 0)), - new MapClue(CLUE_SCROLL_MEDIUM_7292, new WorldPoint(2578, 3597, 0)), - new MapClue(CLUE_SCROLL_MEDIUM_7294, new WorldPoint(2666, 3562, 0)), - new MapClue(CLUE_SCROLL_HARD, new WorldPoint(3309, 3503, 0), CRATE_2620), - new MapClue(CLUE_SCROLL_HARD_2729, new WorldPoint(3190, 3963, 0)), - new MapClue(CLUE_SCROLL_HARD_3520, new WorldPoint(2615, 3078, 0)), - new MapClue(CLUE_SCROLL_HARD_3522, new WorldPoint(2488, 3308, 0)), - new MapClue(CLUE_SCROLL_HARD_3524, new WorldPoint(2457, 3182, 0), CRATE_18506), - new MapClue(CLUE_SCROLL_HARD_3525, new WorldPoint(3026, 3628, 0), CRATE_354), - new MapClue(CLUE_SCROLL_HARD_7239, new WorldPoint(3021, 3912, 0)), - new MapClue(CLUE_SCROLL_HARD_7241, new WorldPoint(2722, 3338, 0)), - new MapClue(CLUE_SCROLL_ELITE_12130, new WorldPoint(2449, 3130, 0)), - new MapClue(CLUE_SCROLL_ELITE_19782, new WorldPoint(2953, 9523, 1), "In the Mogre Camp, near Port Khazard. You require a Diving Apparatus and a Fishbowl Helmet"), - new MapClue(CLUE_SCROLL_ELITE_19783, new WorldPoint(2202, 3062, 0)), - new MapClue(CLUE_SCROLL_ELITE_19784, new WorldPoint(1815, 3852, 0)), - new MapClue(CLUE_SCROLL_ELITE_19785, new WorldPoint(3538, 3208, 0)), - new MapClue(CLUE_SCROLL_ELITE_19786, new WorldPoint(2703, 2716, 0), CRATE_6616) - ); - - private final int itemId; - private final WorldPoint location; - private final int objectId; - private final String description; - - private MapClue(int itemId, WorldPoint location) - { - this(itemId, location, -1); - } - - private MapClue(int itemId, WorldPoint location, int objectId) - { - this(itemId, location, objectId, null); - } - - private MapClue(int itemId, WorldPoint location, String description) - { - this(itemId, location, -1, description); - } - - private MapClue(int itemId, WorldPoint location, int objectId, String description) - { - this.itemId = itemId; - this.location = location; - this.objectId = objectId; - this.description = description; - setRequiresSpade(objectId == -1); - } - - @Override - public void makeOverlayHint(PanelComponent panelComponent, ClueScrollPlugin plugin) - { - panelComponent.getChildren().add(TitleComponent.builder().text("Map Clue").build()); - - panelComponent.getChildren().add(LineComponent.builder() - .left("Click the clue scroll along the edge of your world map to see your destination.") - .build()); - - if (objectId != -1) - { - ObjectComposition objectToClick = plugin.getClient().getObjectDefinition(getObjectId()); - - String objectName = "N/A"; - - if (objectToClick != null) - { - objectName = objectToClick.getName(); - } - - panelComponent.getChildren().add(LineComponent.builder() - .left("Travel to the destination and click the " + objectName + ".") - .build()); - } - else - { - panelComponent.getChildren().add(LineComponent.builder() - .left("Travel to the destination and dig on the marked tile.") - .build()); - } - - if (description != null) - { - panelComponent.getChildren().add(LineComponent.builder().build()); - panelComponent.getChildren().add(LineComponent.builder() - .left(description) - .build()); - } - } - - @Override - public void makeWorldOverlayHint(Graphics2D graphics, ClueScrollPlugin plugin) - { - LocalPoint localLocation = LocalPoint.fromWorld(plugin.getClient(), getLocation()); - - if (localLocation == null) - { - return; - } - - // Mark game object - if (objectId != -1) - { - net.runelite.api.Point mousePosition = plugin.getClient().getMouseCanvasPosition(); - - if (plugin.getObjectsToMark() != null) - { - for (TileObject gameObject : plugin.getObjectsToMark()) - { - OverlayUtil.renderHoverableArea(graphics, gameObject.getClickbox(), mousePosition, - CLICKBOX_FILL_COLOR, CLICKBOX_BORDER_COLOR, CLICKBOX_HOVER_BORDER_COLOR); - - OverlayUtil.renderImageLocation(plugin.getClient(), graphics, gameObject.getLocalLocation(), plugin.getClueScrollImage(), IMAGE_Z_OFFSET); - } - } - } - // Mark tile - else - { - OverlayUtil.renderTileOverlay(plugin.getClient(), graphics, localLocation, plugin.getSpadeImage(), Color.ORANGE); - } - } - - public static MapClue forItemId(int itemId) - { - for (MapClue clue : CLUES) - { - if (clue.itemId == itemId) - { - return clue; - } - } - - return null; - } - - public int[] getObjectIds() - { - return new int[] {objectId}; - } -} +/* + * Copyright (c) 2018, Lotto + * 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.cluescrolls.clues; + +import com.google.common.collect.ImmutableSet; +import java.awt.Color; +import java.awt.Graphics2D; +import java.util.Set; +import lombok.Getter; +import static net.runelite.api.ItemID.CLUE_SCROLL_EASY_12179; +import static net.runelite.api.ItemID.CLUE_SCROLL_EASY_2713; +import static net.runelite.api.ItemID.CLUE_SCROLL_EASY_2716; +import static net.runelite.api.ItemID.CLUE_SCROLL_EASY_2719; +import static net.runelite.api.ItemID.CLUE_SCROLL_EASY_3516; +import static net.runelite.api.ItemID.CLUE_SCROLL_EASY_3518; +import static net.runelite.api.ItemID.CLUE_SCROLL_EASY_7236; +import static net.runelite.api.ItemID.CLUE_SCROLL_ELITE_12130; +import static net.runelite.api.ItemID.CLUE_SCROLL_ELITE_19782; +import static net.runelite.api.ItemID.CLUE_SCROLL_ELITE_19783; +import static net.runelite.api.ItemID.CLUE_SCROLL_ELITE_19784; +import static net.runelite.api.ItemID.CLUE_SCROLL_ELITE_19785; +import static net.runelite.api.ItemID.CLUE_SCROLL_ELITE_19786; +import static net.runelite.api.ItemID.CLUE_SCROLL_HARD; +import static net.runelite.api.ItemID.CLUE_SCROLL_HARD_2729; +import static net.runelite.api.ItemID.CLUE_SCROLL_HARD_3520; +import static net.runelite.api.ItemID.CLUE_SCROLL_HARD_3522; +import static net.runelite.api.ItemID.CLUE_SCROLL_HARD_3524; +import static net.runelite.api.ItemID.CLUE_SCROLL_HARD_3525; +import static net.runelite.api.ItemID.CLUE_SCROLL_HARD_7239; +import static net.runelite.api.ItemID.CLUE_SCROLL_HARD_7241; +import static net.runelite.api.ItemID.CLUE_SCROLL_MEDIUM_2827; +import static net.runelite.api.ItemID.CLUE_SCROLL_MEDIUM_3596; +import static net.runelite.api.ItemID.CLUE_SCROLL_MEDIUM_3598; +import static net.runelite.api.ItemID.CLUE_SCROLL_MEDIUM_3599; +import static net.runelite.api.ItemID.CLUE_SCROLL_MEDIUM_3601; +import static net.runelite.api.ItemID.CLUE_SCROLL_MEDIUM_3602; +import static net.runelite.api.ItemID.CLUE_SCROLL_MEDIUM_7286; +import static net.runelite.api.ItemID.CLUE_SCROLL_MEDIUM_7288; +import static net.runelite.api.ItemID.CLUE_SCROLL_MEDIUM_7290; +import static net.runelite.api.ItemID.CLUE_SCROLL_MEDIUM_7292; +import static net.runelite.api.ItemID.CLUE_SCROLL_MEDIUM_7294; +import net.runelite.api.ObjectComposition; +import static net.runelite.api.ObjectID.CRATE_18506; +import static net.runelite.api.ObjectID.CRATE_2620; +import static net.runelite.api.ObjectID.CRATE_354; +import static net.runelite.api.ObjectID.CRATE_357; +import static net.runelite.api.ObjectID.CRATE_6616; +import net.runelite.api.TileObject; +import net.runelite.api.coords.LocalPoint; +import net.runelite.api.coords.WorldPoint; +import net.runelite.client.plugins.cluescrolls.ClueScrollPlugin; +import static net.runelite.client.plugins.cluescrolls.ClueScrollWorldOverlay.CLICKBOX_BORDER_COLOR; +import static net.runelite.client.plugins.cluescrolls.ClueScrollWorldOverlay.CLICKBOX_FILL_COLOR; +import static net.runelite.client.plugins.cluescrolls.ClueScrollWorldOverlay.CLICKBOX_HOVER_BORDER_COLOR; +import static net.runelite.client.plugins.cluescrolls.ClueScrollWorldOverlay.IMAGE_Z_OFFSET; +import net.runelite.client.ui.overlay.OverlayUtil; +import net.runelite.client.ui.overlay.components.LineComponent; +import net.runelite.client.ui.overlay.components.PanelComponent; +import net.runelite.client.ui.overlay.components.TitleComponent; + +@Getter +public class MapClue extends ClueScroll implements ObjectClueScroll +{ + private static final Set CLUES = ImmutableSet.of( + new MapClue(CLUE_SCROLL_EASY_12179, new WorldPoint(3300, 3291, 0)), + new MapClue(CLUE_SCROLL_EASY_2713, new WorldPoint(3166, 3361, 0)), + new MapClue(CLUE_SCROLL_EASY_2716, new WorldPoint(3290, 3374, 0)), + new MapClue(CLUE_SCROLL_EASY_2719, new WorldPoint(3043, 3398, 0)), + new MapClue(CLUE_SCROLL_EASY_3516, new WorldPoint(2612, 3482, 0)), + new MapClue(CLUE_SCROLL_EASY_3518, new WorldPoint(3110, 3152, 0)), + new MapClue(CLUE_SCROLL_EASY_7236, new WorldPoint(2970, 3415, 0)), + new MapClue(CLUE_SCROLL_MEDIUM_2827, new WorldPoint(3091, 3227, 0)), + new MapClue(CLUE_SCROLL_MEDIUM_3596, new WorldPoint(2907, 3295, 0)), + new MapClue(CLUE_SCROLL_MEDIUM_3598, new WorldPoint(2658, 3488, 0), CRATE_357), + new MapClue(CLUE_SCROLL_MEDIUM_3599, new WorldPoint(2651, 3231, 0)), + new MapClue(CLUE_SCROLL_MEDIUM_3601, new WorldPoint(2565, 3248, 0), CRATE_354), + new MapClue(CLUE_SCROLL_MEDIUM_3602, new WorldPoint(2924, 3210, 0)), + new MapClue(CLUE_SCROLL_MEDIUM_7286, new WorldPoint(2536, 3865, 0)), + new MapClue(CLUE_SCROLL_MEDIUM_7288, new WorldPoint(3434, 3265, 0)), + new MapClue(CLUE_SCROLL_MEDIUM_7290, new WorldPoint(2454, 3230, 0)), + new MapClue(CLUE_SCROLL_MEDIUM_7292, new WorldPoint(2578, 3597, 0)), + new MapClue(CLUE_SCROLL_MEDIUM_7294, new WorldPoint(2666, 3562, 0)), + new MapClue(CLUE_SCROLL_HARD, new WorldPoint(3309, 3503, 0), CRATE_2620), + new MapClue(CLUE_SCROLL_HARD_2729, new WorldPoint(3190, 3963, 0)), + new MapClue(CLUE_SCROLL_HARD_3520, new WorldPoint(2615, 3078, 0)), + new MapClue(CLUE_SCROLL_HARD_3522, new WorldPoint(2488, 3308, 0)), + new MapClue(CLUE_SCROLL_HARD_3524, new WorldPoint(2457, 3182, 0), CRATE_18506), + new MapClue(CLUE_SCROLL_HARD_3525, new WorldPoint(3026, 3628, 0), CRATE_354), + new MapClue(CLUE_SCROLL_HARD_7239, new WorldPoint(3021, 3912, 0)), + new MapClue(CLUE_SCROLL_HARD_7241, new WorldPoint(2722, 3338, 0)), + new MapClue(CLUE_SCROLL_ELITE_12130, new WorldPoint(2449, 3130, 0)), + new MapClue(CLUE_SCROLL_ELITE_19782, new WorldPoint(2953, 9523, 1), "In the Mogre Camp, near Port Khazard. You require a Diving Apparatus and a Fishbowl Helmet"), + new MapClue(CLUE_SCROLL_ELITE_19783, new WorldPoint(2202, 3062, 0)), + new MapClue(CLUE_SCROLL_ELITE_19784, new WorldPoint(1815, 3852, 0)), + new MapClue(CLUE_SCROLL_ELITE_19785, new WorldPoint(3538, 3208, 0)), + new MapClue(CLUE_SCROLL_ELITE_19786, new WorldPoint(2703, 2716, 0), CRATE_6616) + ); + + private final int itemId; + private final WorldPoint location; + private final int objectId; + private final String description; + + private MapClue(int itemId, WorldPoint location) + { + this(itemId, location, -1); + } + + private MapClue(int itemId, WorldPoint location, int objectId) + { + this(itemId, location, objectId, null); + } + + private MapClue(int itemId, WorldPoint location, String description) + { + this(itemId, location, -1, description); + } + + private MapClue(int itemId, WorldPoint location, int objectId, String description) + { + this.itemId = itemId; + this.location = location; + this.objectId = objectId; + this.description = description; + setRequiresSpade(objectId == -1); + } + + @Override + public void makeOverlayHint(PanelComponent panelComponent, ClueScrollPlugin plugin) + { + panelComponent.getChildren().add(TitleComponent.builder().text("Map Clue").build()); + + panelComponent.getChildren().add(LineComponent.builder() + .left("Click the clue scroll along the edge of your world map to see your destination.") + .build()); + + if (objectId != -1) + { + ObjectComposition objectToClick = plugin.getClient().getObjectDefinition(getObjectId()); + + String objectName = "N/A"; + + if (objectToClick != null) + { + objectName = objectToClick.getName(); + } + + panelComponent.getChildren().add(LineComponent.builder() + .left("Travel to the destination and click the " + objectName + ".") + .build()); + } + else + { + panelComponent.getChildren().add(LineComponent.builder() + .left("Travel to the destination and dig on the marked tile.") + .build()); + } + + if (description != null) + { + panelComponent.getChildren().add(LineComponent.builder().build()); + panelComponent.getChildren().add(LineComponent.builder() + .left(description) + .build()); + } + } + + @Override + public void makeWorldOverlayHint(Graphics2D graphics, ClueScrollPlugin plugin) + { + LocalPoint localLocation = LocalPoint.fromWorld(plugin.getClient(), getLocation()); + + if (localLocation == null) + { + return; + } + + // Mark game object + if (objectId != -1) + { + net.runelite.api.Point mousePosition = plugin.getClient().getMouseCanvasPosition(); + + if (plugin.getObjectsToMark() != null) + { + for (TileObject gameObject : plugin.getObjectsToMark()) + { + OverlayUtil.renderHoverableArea(graphics, gameObject.getClickbox(), mousePosition, + CLICKBOX_FILL_COLOR, CLICKBOX_BORDER_COLOR, CLICKBOX_HOVER_BORDER_COLOR); + + OverlayUtil.renderImageLocation(plugin.getClient(), graphics, gameObject.getLocalLocation(), plugin.getClueScrollImage(), IMAGE_Z_OFFSET); + } + } + } + // Mark tile + else + { + OverlayUtil.renderTileOverlay(plugin.getClient(), graphics, localLocation, plugin.getSpadeImage(), Color.ORANGE); + } + } + + public static MapClue forItemId(int itemId) + { + for (MapClue clue : CLUES) + { + if (clue.itemId == itemId) + { + return clue; + } + } + + return null; + } + + public int[] getObjectIds() + { + return new int[]{objectId}; + } +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/clues/MusicClue.java b/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/clues/MusicClue.java index 6ed7ce176f..a2e7d8696b 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/clues/MusicClue.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/clues/MusicClue.java @@ -1,107 +1,107 @@ -/* - * Copyright (c) 2019, Hydrox6 - * 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.cluescrolls.clues; - -import java.awt.Color; -import java.awt.Graphics2D; -import java.util.regex.Matcher; -import java.util.regex.Pattern; -import lombok.AccessLevel; -import lombok.AllArgsConstructor; -import lombok.Getter; -import net.runelite.api.NPC; -import net.runelite.api.coords.WorldPoint; -import static net.runelite.client.plugins.cluescrolls.ClueScrollOverlay.TITLED_CONTENT_COLOR; -import net.runelite.client.plugins.cluescrolls.ClueScrollPlugin; -import static net.runelite.client.plugins.cluescrolls.ClueScrollWorldOverlay.IMAGE_Z_OFFSET; -import net.runelite.client.ui.overlay.OverlayUtil; -import net.runelite.client.ui.overlay.components.LineComponent; -import net.runelite.client.ui.overlay.components.PanelComponent; -import net.runelite.client.ui.overlay.components.TitleComponent; - -@AllArgsConstructor(access = AccessLevel.PRIVATE) -@Getter -public class MusicClue extends ClueScroll implements NpcClueScroll -{ - private static final WorldPoint LOCATION = new WorldPoint(2990, 3384, 0); - private static final String CECILIA = "Cecilia"; - private static final Pattern SONG_PATTERN = Pattern.compile("([A-Za-z !&',.]+)"); - - private final String song; - - @Override - public void makeOverlayHint(PanelComponent panelComponent, ClueScrollPlugin plugin) - { - panelComponent.getChildren().add(TitleComponent.builder().text("Music Clue").build()); - panelComponent.getChildren().add(LineComponent.builder().left("NPC:").build()); - panelComponent.getChildren().add(LineComponent.builder() - .left(CECILIA) - .leftColor(TITLED_CONTENT_COLOR) - .build()); - - panelComponent.getChildren().add(LineComponent.builder().left("Area:").build()); - panelComponent.getChildren().add(LineComponent.builder() - .left("Falador Park") - .leftColor(TITLED_CONTENT_COLOR) - .build()); - - panelComponent.getChildren().add(LineComponent.builder().left("Song:").build()); - panelComponent.getChildren().add(LineComponent.builder() - .left(song) - .leftColor(TITLED_CONTENT_COLOR) - .build()); - } - - @Override - public void makeWorldOverlayHint(Graphics2D graphics, ClueScrollPlugin plugin) - { - if (!LOCATION.isInScene(plugin.getClient())) - { - return; - } - - for (NPC npc : plugin.getNpcsToMark()) - { - OverlayUtil.renderActorOverlayImage(graphics, npc, plugin.getClueScrollImage(), Color.ORANGE, IMAGE_Z_OFFSET); - } - } - - @Override - public String[] getNpcs() - { - return new String[] {CECILIA}; - } - - public static MusicClue forText(String text) - { - final Matcher m = SONG_PATTERN.matcher(text); - if (m.find()) - { - final String song = m.group(1); - return new MusicClue(song); - } - return null; - } -} +/* + * Copyright (c) 2019, Hydrox6 + * 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.cluescrolls.clues; + +import java.awt.Color; +import java.awt.Graphics2D; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import lombok.AccessLevel; +import lombok.AllArgsConstructor; +import lombok.Getter; +import net.runelite.api.NPC; +import net.runelite.api.coords.WorldPoint; +import static net.runelite.client.plugins.cluescrolls.ClueScrollOverlay.TITLED_CONTENT_COLOR; +import net.runelite.client.plugins.cluescrolls.ClueScrollPlugin; +import static net.runelite.client.plugins.cluescrolls.ClueScrollWorldOverlay.IMAGE_Z_OFFSET; +import net.runelite.client.ui.overlay.OverlayUtil; +import net.runelite.client.ui.overlay.components.LineComponent; +import net.runelite.client.ui.overlay.components.PanelComponent; +import net.runelite.client.ui.overlay.components.TitleComponent; + +@AllArgsConstructor(access = AccessLevel.PRIVATE) +@Getter +public class MusicClue extends ClueScroll implements NpcClueScroll +{ + private static final WorldPoint LOCATION = new WorldPoint(2990, 3384, 0); + private static final String CECILIA = "Cecilia"; + private static final Pattern SONG_PATTERN = Pattern.compile("([A-Za-z !&',.]+)"); + + private final String song; + + @Override + public void makeOverlayHint(PanelComponent panelComponent, ClueScrollPlugin plugin) + { + panelComponent.getChildren().add(TitleComponent.builder().text("Music Clue").build()); + panelComponent.getChildren().add(LineComponent.builder().left("NPC:").build()); + panelComponent.getChildren().add(LineComponent.builder() + .left(CECILIA) + .leftColor(TITLED_CONTENT_COLOR) + .build()); + + panelComponent.getChildren().add(LineComponent.builder().left("Area:").build()); + panelComponent.getChildren().add(LineComponent.builder() + .left("Falador Park") + .leftColor(TITLED_CONTENT_COLOR) + .build()); + + panelComponent.getChildren().add(LineComponent.builder().left("Song:").build()); + panelComponent.getChildren().add(LineComponent.builder() + .left(song) + .leftColor(TITLED_CONTENT_COLOR) + .build()); + } + + @Override + public void makeWorldOverlayHint(Graphics2D graphics, ClueScrollPlugin plugin) + { + if (!LOCATION.isInScene(plugin.getClient())) + { + return; + } + + for (NPC npc : plugin.getNpcsToMark()) + { + OverlayUtil.renderActorOverlayImage(graphics, npc, plugin.getClueScrollImage(), Color.ORANGE, IMAGE_Z_OFFSET); + } + } + + @Override + public String[] getNpcs() + { + return new String[]{CECILIA}; + } + + public static MusicClue forText(String text) + { + final Matcher m = SONG_PATTERN.matcher(text); + if (m.find()) + { + final String song = m.group(1); + return new MusicClue(song); + } + return null; + } +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/clues/emote/Emote.java b/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/clues/emote/Emote.java index 67019d58d0..10ecc5793c 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/clues/emote/Emote.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/clues/emote/Emote.java @@ -1,75 +1,101 @@ -/* - * Copyright (c) 2018, Lotto - * 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.cluescrolls.clues.emote; - -import lombok.Getter; -import static net.runelite.api.SpriteID.*; - -@Getter -public enum Emote -{ - BULL_ROARER("Bull Roarer", -1), - YES("Yes", EMOTE_YES), - NO("No", EMOTE_NO), - THINK("Think", EMOTE_THINK), - BOW("Bow", EMOTE_BOW), - ANGRY("Angry", EMOTE_ANGRY), - CRY("Cry", EMOTE_CRY), - LAUGH("Laugh", EMOTE_LAUGH), - CHEER("Cheer", EMOTE_CHEER), - WAVE("Wave", EMOTE_WAVE), - BECKON("Beckon", EMOTE_BECKON), - DANCE("Dance", EMOTE_DANCE), - CLAP("Clap", EMOTE_CLAP), - PANIC("Panic", EMOTE_PANIC), - JIG("Jig", EMOTE_JIG), - SPIN("Spin", EMOTE_SPIN), - HEADBANG("Headbang", EMOTE_HEADBANG), - JUMP_FOR_JOY("Jump for Joy", EMOTE_JUMP_FOR_JOY), - RASPBERRY("Raspberry", EMOTE_RASPBERRY), - YAWN("Yawn", EMOTE_YAWN), - SALUTE("Salute", EMOTE_SALUTE), - SHRUG("Shrug", EMOTE_SHRUG), - BLOW_KISS("Blow Kiss", EMOTE_BLOW_KISS), - GOBLIN_SALUTE("Goblin Salute", EMOTE_GOBLIN_SALUTE), - SLAP_HEAD("Slap Head", EMOTE_SLAP_HEAD), - STOMP("Stomp", EMOTE_STOMP), - FLAP("Flap", EMOTE_FLAP), - PUSH_UP("Push up", EMOTE_PUSH_UP); - - private String name; - private int spriteId; - - Emote(String name, int spriteId) - { - this.name = name; - this.spriteId = spriteId; - } - - public boolean hasSprite() - { - return spriteId != -1; - } -} +/* + * Copyright (c) 2018, Lotto + * 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.cluescrolls.clues.emote; + +import lombok.Getter; +import static net.runelite.api.SpriteID.EMOTE_ANGRY; +import static net.runelite.api.SpriteID.EMOTE_BECKON; +import static net.runelite.api.SpriteID.EMOTE_BLOW_KISS; +import static net.runelite.api.SpriteID.EMOTE_BOW; +import static net.runelite.api.SpriteID.EMOTE_CHEER; +import static net.runelite.api.SpriteID.EMOTE_CLAP; +import static net.runelite.api.SpriteID.EMOTE_CRY; +import static net.runelite.api.SpriteID.EMOTE_DANCE; +import static net.runelite.api.SpriteID.EMOTE_FLAP; +import static net.runelite.api.SpriteID.EMOTE_GOBLIN_SALUTE; +import static net.runelite.api.SpriteID.EMOTE_HEADBANG; +import static net.runelite.api.SpriteID.EMOTE_JIG; +import static net.runelite.api.SpriteID.EMOTE_JUMP_FOR_JOY; +import static net.runelite.api.SpriteID.EMOTE_LAUGH; +import static net.runelite.api.SpriteID.EMOTE_NO; +import static net.runelite.api.SpriteID.EMOTE_PANIC; +import static net.runelite.api.SpriteID.EMOTE_PUSH_UP; +import static net.runelite.api.SpriteID.EMOTE_RASPBERRY; +import static net.runelite.api.SpriteID.EMOTE_SALUTE; +import static net.runelite.api.SpriteID.EMOTE_SHRUG; +import static net.runelite.api.SpriteID.EMOTE_SLAP_HEAD; +import static net.runelite.api.SpriteID.EMOTE_SPIN; +import static net.runelite.api.SpriteID.EMOTE_STOMP; +import static net.runelite.api.SpriteID.EMOTE_THINK; +import static net.runelite.api.SpriteID.EMOTE_WAVE; +import static net.runelite.api.SpriteID.EMOTE_YAWN; +import static net.runelite.api.SpriteID.EMOTE_YES; + +@Getter +public enum Emote +{ + BULL_ROARER("Bull Roarer", -1), + YES("Yes", EMOTE_YES), + NO("No", EMOTE_NO), + THINK("Think", EMOTE_THINK), + BOW("Bow", EMOTE_BOW), + ANGRY("Angry", EMOTE_ANGRY), + CRY("Cry", EMOTE_CRY), + LAUGH("Laugh", EMOTE_LAUGH), + CHEER("Cheer", EMOTE_CHEER), + WAVE("Wave", EMOTE_WAVE), + BECKON("Beckon", EMOTE_BECKON), + DANCE("Dance", EMOTE_DANCE), + CLAP("Clap", EMOTE_CLAP), + PANIC("Panic", EMOTE_PANIC), + JIG("Jig", EMOTE_JIG), + SPIN("Spin", EMOTE_SPIN), + HEADBANG("Headbang", EMOTE_HEADBANG), + JUMP_FOR_JOY("Jump for Joy", EMOTE_JUMP_FOR_JOY), + RASPBERRY("Raspberry", EMOTE_RASPBERRY), + YAWN("Yawn", EMOTE_YAWN), + SALUTE("Salute", EMOTE_SALUTE), + SHRUG("Shrug", EMOTE_SHRUG), + BLOW_KISS("Blow Kiss", EMOTE_BLOW_KISS), + GOBLIN_SALUTE("Goblin Salute", EMOTE_GOBLIN_SALUTE), + SLAP_HEAD("Slap Head", EMOTE_SLAP_HEAD), + STOMP("Stomp", EMOTE_STOMP), + FLAP("Flap", EMOTE_FLAP), + PUSH_UP("Push up", EMOTE_PUSH_UP); + + private String name; + private int spriteId; + + Emote(String name, int spriteId) + { + this.name = name; + this.spriteId = spriteId; + } + + public boolean hasSprite() + { + return spriteId != -1; + } +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/combatlevel/CombatLevelOverlay.java b/runelite-client/src/main/java/net/runelite/client/plugins/combatlevel/CombatLevelOverlay.java index 6e81a7a983..3e811a60d2 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/combatlevel/CombatLevelOverlay.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/combatlevel/CombatLevelOverlay.java @@ -25,6 +25,11 @@ package net.runelite.client.plugins.combatlevel; import com.google.common.annotations.VisibleForTesting; +import java.awt.Color; +import java.awt.Dimension; +import java.awt.Graphics2D; +import java.awt.Rectangle; +import javax.inject.Inject; import net.runelite.api.Client; import net.runelite.api.Experience; import net.runelite.api.Skill; @@ -34,11 +39,6 @@ import net.runelite.client.ui.overlay.Overlay; import net.runelite.client.ui.overlay.tooltip.Tooltip; import net.runelite.client.ui.overlay.tooltip.TooltipManager; import net.runelite.client.util.ColorUtil; -import javax.inject.Inject; -import java.awt.Color; -import java.awt.Dimension; -import java.awt.Graphics2D; -import java.awt.Rectangle; class CombatLevelOverlay extends Overlay { @@ -143,10 +143,11 @@ class CombatLevelOverlay extends Overlay /** * Calculate skill levels required for increasing combat level, meant * for all combat skills besides prayer, ranged, and magic. - * @param start initial value - * @param end ending value (combat level + 1) - * @param multiple how much adding one skill level will change combat - * @return levels required for a specific skill to level up combat + * + * @param start initial value + * @param end ending value (combat level + 1) + * @param multiple how much adding one skill level will change combat + * @return levels required for a specific skill to level up combat */ @VisibleForTesting static int calcLevels(double start, int end, double multiple) @@ -158,8 +159,9 @@ class CombatLevelOverlay extends Overlay * Calculate skill levels for increasing combat level, meant ONLY for the Prayer skill. *

* Note: Prayer is a special case, only leveling up upon even level numbers. This is accounted - * for in this function. + * for in this function. *

+ * * @param start current combat level * @param end ending value (combat level + 1) * @param prayerLevel the player's current prayer level @@ -191,10 +193,11 @@ class CombatLevelOverlay extends Overlay /** * Calculate skill levels required for increasing combat level, meant * ONLY for Ranged and Magic skills. - * @param start either the current ranged or magic level - * @param end ending value (combat level + 1) - * @param dhp defence, hitpoints, and prayer; this is the initial calculated "base" value - * @return levels required for a specific skill to level up combat + * + * @param start either the current ranged or magic level + * @param end ending value (combat level + 1) + * @param dhp defence, hitpoints, and prayer; this is the initial calculated "base" value + * @return levels required for a specific skill to level up combat */ @VisibleForTesting static int calcLevelsRM(double start, int end, double dhp) diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/combatlevel/CombatLevelPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/combatlevel/CombatLevelPlugin.java index bbde15c2e0..eb7c318320 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/combatlevel/CombatLevelPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/combatlevel/CombatLevelPlugin.java @@ -1,244 +1,244 @@ -/* - * Copyright (c) 2017, Devin French - * Copyright (c) 2019, Jordan Atwood - * 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.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; -import net.runelite.client.plugins.PluginDescriptor; -import net.runelite.client.ui.overlay.OverlayManager; - -@PluginDescriptor( - name = "Combat Level", - 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 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; - - @Inject - private OverlayManager overlayManager; - - @Provides - CombatLevelConfig provideConfig(ConfigManager configManager) - { - return configManager.getConfig(CombatLevelConfig.class); - } - - @Override - protected void startUp() throws Exception - { - overlayManager.add(overlay); - - if (config.wildernessAttackLevelRange()) - { - appendAttackLevelRangeText(); - } - } - - @Override - protected void shutDown() throws Exception - { - overlayManager.remove(overlay); - Widget combatLevelWidget = client.getWidget(WidgetInfo.COMBAT_LEVEL); - - if (combatLevelWidget != null) - { - String widgetText = combatLevelWidget.getText(); - - if (widgetText.contains(".")) - { - combatLevelWidget.setText(widgetText.substring(0, widgetText.indexOf("."))); - } - } - - shutDownAttackLevelRange(); - } - - @Subscribe - public void onGameTick(GameTick event) - { - if (client.getGameState() != GameState.LOGGED_IN) - { - return; - } - - Widget combatLevelWidget = client.getWidget(WidgetInfo.COMBAT_LEVEL); - if (combatLevelWidget == null) - { - return; - } - - double combatLevelPrecise = Experience.getCombatLevelPrecise( - client.getRealSkillLevel(Skill.ATTACK), - client.getRealSkillLevel(Skill.STRENGTH), - client.getRealSkillLevel(Skill.DEFENCE), - client.getRealSkillLevel(Skill.HITPOINTS), - client.getRealSkillLevel(Skill.MAGIC), - client.getRealSkillLevel(Skill.RANGED), - client.getRealSkillLevel(Skill.PRAYER) - ); - - 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 + "
" + 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("
")) - { - wildernessLevelWidget.setText(wildernessLevelText.substring(0, wildernessLevelText.indexOf("
"))); - } - 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); - } -} +/* + * Copyright (c) 2017, Devin French + * Copyright (c) 2019, Jordan Atwood + * 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.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; +import net.runelite.client.plugins.PluginDescriptor; +import net.runelite.client.ui.overlay.OverlayManager; + +@PluginDescriptor( + name = "Combat Level", + 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 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; + + @Inject + private OverlayManager overlayManager; + + @Provides + CombatLevelConfig provideConfig(ConfigManager configManager) + { + return configManager.getConfig(CombatLevelConfig.class); + } + + @Override + protected void startUp() throws Exception + { + overlayManager.add(overlay); + + if (config.wildernessAttackLevelRange()) + { + appendAttackLevelRangeText(); + } + } + + @Override + protected void shutDown() throws Exception + { + overlayManager.remove(overlay); + Widget combatLevelWidget = client.getWidget(WidgetInfo.COMBAT_LEVEL); + + if (combatLevelWidget != null) + { + String widgetText = combatLevelWidget.getText(); + + if (widgetText.contains(".")) + { + combatLevelWidget.setText(widgetText.substring(0, widgetText.indexOf("."))); + } + } + + shutDownAttackLevelRange(); + } + + @Subscribe + public void onGameTick(GameTick event) + { + if (client.getGameState() != GameState.LOGGED_IN) + { + return; + } + + Widget combatLevelWidget = client.getWidget(WidgetInfo.COMBAT_LEVEL); + if (combatLevelWidget == null) + { + return; + } + + double combatLevelPrecise = Experience.getCombatLevelPrecise( + client.getRealSkillLevel(Skill.ATTACK), + client.getRealSkillLevel(Skill.STRENGTH), + client.getRealSkillLevel(Skill.DEFENCE), + client.getRealSkillLevel(Skill.HITPOINTS), + client.getRealSkillLevel(Skill.MAGIC), + client.getRealSkillLevel(Skill.RANGED), + client.getRealSkillLevel(Skill.PRAYER) + ); + + 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 + "
" + 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("
")) + { + wildernessLevelWidget.setText(wildernessLevelText.substring(0, wildernessLevelText.indexOf("
"))); + } + 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); + } +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/config/ConfigPanel.java b/runelite-client/src/main/java/net/runelite/client/plugins/config/ConfigPanel.java index 6f6d469c0b..152458de73 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/config/ConfigPanel.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/config/ConfigPanel.java @@ -83,7 +83,6 @@ import net.runelite.client.plugins.PluginDescriptor; import net.runelite.client.plugins.PluginInstantiationException; import net.runelite.client.plugins.PluginManager; import net.runelite.client.plugins.PluginType; -import net.runelite.client.plugins.pluginsorter.PluginSorterPlugin; import net.runelite.client.ui.ColorScheme; import net.runelite.client.ui.DynamicGridLayout; import net.runelite.client.ui.PluginPanel; @@ -197,8 +196,8 @@ public class ConfigPanel extends PluginPanel // set RuneLite config on top, as it should always have been final PluginListItem runeLite = new PluginListItem(this, configManager, runeLiteConfig, - configManager.getConfigDescriptor(runeLiteConfig), - RUNELITE_PLUGIN, "RuneLite client settings", "client"); + configManager.getConfigDescriptor(runeLiteConfig), + RUNELITE_PLUGIN, "RuneLite client settings", "client"); runeLite.setPinned(pinnedPlugins.contains(RUNELITE_PLUGIN)); runeLite.nameLabel.setForeground(Color.WHITE); pluginList.add(runeLite); @@ -279,13 +278,13 @@ public class ConfigPanel extends PluginPanel // populate pluginList with all vanilla RL plugins List vanillaPlugins = new ArrayList<>(); pluginManager.getPlugins().stream() - .filter(plugin -> !plugin.getClass().getAnnotation(PluginDescriptor.class).hidden()) - .filter(plugin -> !plugin.getClass().getAnnotation(PluginDescriptor.class).type().equals(PluginType.PVM)) - .filter(plugin -> !plugin.getClass().getAnnotation(PluginDescriptor.class).type().equals(PluginType.PVP)) - .filter(plugin -> !plugin.getClass().getAnnotation(PluginDescriptor.class).type().equals(PluginType.UTILITY)) - .filter(plugin -> !plugin.getClass().getAnnotation(PluginDescriptor.class).type().equals(PluginType.PLUGIN_ORGANIZER)) - .filter(plugin -> !plugin.getClass().getAnnotation(PluginDescriptor.class).type().equals(PluginType.EXTERNAL)) - .forEach(plugin -> + .filter(plugin -> !plugin.getClass().getAnnotation(PluginDescriptor.class).hidden()) + .filter(plugin -> !plugin.getClass().getAnnotation(PluginDescriptor.class).type().equals(PluginType.PVM)) + .filter(plugin -> !plugin.getClass().getAnnotation(PluginDescriptor.class).type().equals(PluginType.PVP)) + .filter(plugin -> !plugin.getClass().getAnnotation(PluginDescriptor.class).type().equals(PluginType.UTILITY)) + .filter(plugin -> !plugin.getClass().getAnnotation(PluginDescriptor.class).type().equals(PluginType.PLUGIN_ORGANIZER)) + .filter(plugin -> !plugin.getClass().getAnnotation(PluginDescriptor.class).type().equals(PluginType.EXTERNAL)) + .forEach(plugin -> { final PluginDescriptor descriptor = plugin.getClass().getAnnotation(PluginDescriptor.class); final Config config = pluginManager.getPluginConfigProxy(plugin); @@ -295,11 +294,11 @@ public class ConfigPanel extends PluginPanel listItem.setPinned(pinnedPlugins.contains(listItem.getName())); vanillaPlugins.add(listItem); } - ); + ); final PluginListItem chatColor = new PluginListItem(this, configManager, chatColorConfig, - configManager.getConfigDescriptor(chatColorConfig), - CHAT_COLOR_PLUGIN, "Recolor chat text", "colour", "messages"); + configManager.getConfigDescriptor(chatColorConfig), + CHAT_COLOR_PLUGIN, "Recolor chat text", "colour", "messages"); chatColor.setPinned(pinnedPlugins.contains(CHAT_COLOR_PLUGIN)); chatColor.nameLabel.setForeground(Color.WHITE); vanillaPlugins.add(chatColor); @@ -404,7 +403,9 @@ public class ConfigPanel extends PluginPanel topPanel.add(topPanelBackButton, BorderLayout.WEST); if (!listItem.getName().equals("RuneLitePlus")) - topPanel.add(listItem.createToggleButton(), BorderLayout.EAST); + { + topPanel.add(listItem.createToggleButton(), BorderLayout.EAST); + } String name = listItem.getName(); JLabel title = new JLabel(name); @@ -520,7 +521,7 @@ public class ConfigPanel extends PluginPanel public void mouseClicked(MouseEvent e) { RuneliteColorPicker colorPicker = new RuneliteColorPicker(SwingUtilities.windowForComponent(ConfigPanel.this), - colorPickerBtn.getBackground(), cid.getItem().name(), cid.getAlpha() == null); + colorPickerBtn.getBackground(), cid.getItem().name(), cid.getAlpha() == null); colorPicker.setLocation(getLocationOnScreen()); colorPicker.setOnColorChange(c -> { @@ -566,7 +567,7 @@ public class ConfigPanel extends PluginPanel heightSpinnerTextField.setColumns(4); ChangeListener listener = e -> - configManager.setConfiguration(cd.getGroup().value(), cid.getItem().keyName(), widthSpinner.getValue() + "x" + heightSpinner.getValue()); + configManager.setConfiguration(cd.getGroup().value(), cid.getItem().keyName(), widthSpinner.getValue() + "x" + heightSpinner.getValue()); widthSpinner.addChangeListener(listener); heightSpinner.addChangeListener(listener); @@ -611,8 +612,8 @@ public class ConfigPanel extends PluginPanel if (cid.getType() == Keybind.class || cid.getType() == ModifierlessKeybind.class) { Keybind startingValue = configManager.getConfiguration(cd.getGroup().value(), - cid.getItem().keyName(), - (Class) cid.getType()); + cid.getItem().keyName(), + (Class) cid.getType()); HotkeyButton button = new HotkeyButton(startingValue, cid.getType() == ModifierlessKeybind.class); @@ -635,8 +636,8 @@ public class ConfigPanel extends PluginPanel resetButton.addActionListener((e) -> { final int result = JOptionPane.showOptionDialog(resetButton, "Are you sure you want to reset this plugin's configuration?", - "Are you sure?", JOptionPane.YES_NO_OPTION, JOptionPane.WARNING_MESSAGE, - null, new String[]{"Yes", "No"}, "No"); + "Are you sure?", JOptionPane.YES_NO_OPTION, JOptionPane.WARNING_MESSAGE, + null, new String[]{"Yes", "No"}, "No"); if (result == JOptionPane.YES_OPTION) { @@ -663,8 +664,8 @@ public class ConfigPanel extends PluginPanel if (!Strings.isNullOrEmpty(configItem.warning())) { final int result = JOptionPane.showOptionDialog(component, configItem.warning(), - "Are you sure?", JOptionPane.YES_NO_OPTION, JOptionPane.WARNING_MESSAGE, - null, new String[]{"Yes", "No"}, "No"); + "Are you sure?", JOptionPane.YES_NO_OPTION, JOptionPane.WARNING_MESSAGE, + null, new String[]{"Yes", "No"}, "No"); if (result != JOptionPane.YES_OPTION) { @@ -758,9 +759,9 @@ public class ConfigPanel extends PluginPanel void savePinnedPlugins() { final String value = pluginList.stream() - .filter(PluginListItem::isPinned) - .map(PluginListItem::getName) - .collect(Collectors.joining(",")); + .filter(PluginListItem::isPinned) + .map(PluginListItem::getName) + .collect(Collectors.joining(",")); configManager.setConfiguration(RUNELITE_GROUP_NAME, PINNED_PLUGINS_CONFIG_KEY, value); } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/config/PluginListItem.java b/runelite-client/src/main/java/net/runelite/client/plugins/config/PluginListItem.java index 6daab8d582..9481a9f1f6 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/config/PluginListItem.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/config/PluginListItem.java @@ -25,7 +25,6 @@ package net.runelite.client.plugins.config; import java.awt.BorderLayout; -import java.awt.Color; import java.awt.Dimension; import java.awt.GridLayout; import java.awt.image.BufferedImage; @@ -33,7 +32,6 @@ import java.util.ArrayList; import java.util.Collections; import java.util.List; import javax.annotation.Nullable; -import javax.inject.Inject; import javax.swing.ImageIcon; import javax.swing.JLabel; import javax.swing.JPanel; @@ -41,13 +39,11 @@ import lombok.AccessLevel; import lombok.Getter; import net.runelite.client.config.Config; import net.runelite.client.config.ConfigDescriptor; -import net.runelite.client.config.ConfigItemDescriptor; import net.runelite.client.config.ConfigManager; import net.runelite.client.plugins.Plugin; import net.runelite.client.plugins.PluginDescriptor; import net.runelite.client.ui.PluginPanel; import net.runelite.client.ui.components.IconButton; -import net.runelite.client.util.ColorUtil; import net.runelite.client.util.ImageUtil; import org.apache.commons.text.similarity.JaroWinklerDistance; @@ -105,17 +101,17 @@ public class PluginListItem extends JPanel ON_STAR = new ImageIcon(onStar); CONFIG_ICON_HOVER = new ImageIcon(ImageUtil.grayscaleOffset(configIcon, -100)); BufferedImage offSwitcherImage = ImageUtil.flipImage( - ImageUtil.grayscaleOffset( - ImageUtil.grayscaleImage(onSwitcher), - 0.61f - ), - true, - false + ImageUtil.grayscaleOffset( + ImageUtil.grayscaleImage(onSwitcher), + 0.61f + ), + true, + false ); OFF_SWITCHER = new ImageIcon(offSwitcherImage); BufferedImage offStar = ImageUtil.grayscaleOffset( - ImageUtil.grayscaleImage(onStar), - 0.77f + ImageUtil.grayscaleImage(onStar), + 0.77f ); OFF_STAR = new ImageIcon(offStar); } @@ -130,7 +126,7 @@ public class PluginListItem extends JPanel @Nullable Config config, @Nullable ConfigDescriptor configDescriptor) { this(configPanel, configManager, plugin, config, configDescriptor, - descriptor.name(), descriptor.description(), descriptor.tags()); + descriptor.name(), descriptor.description(), descriptor.tags()); } /** @@ -179,27 +175,28 @@ public class PluginListItem extends JPanel }); - final JPanel buttonPanel = new JPanel(); - buttonPanel.setLayout(new GridLayout(1, 2)); - add(buttonPanel, BorderLayout.LINE_END); + final JPanel buttonPanel = new JPanel(); + buttonPanel.setLayout(new GridLayout(1, 2)); + add(buttonPanel, BorderLayout.LINE_END); - configButton.setPreferredSize(new Dimension(25, 0)); - configButton.setVisible(false); - buttonPanel.add(configButton); + configButton.setPreferredSize(new Dimension(25, 0)); + configButton.setVisible(false); + buttonPanel.add(configButton); - // add a listener to configButton only if there are config items to show - if (config != null && !configDescriptor.getItems().stream().allMatch(item -> item.getItem().hidden())) + // add a listener to configButton only if there are config items to show + if (config != null && !configDescriptor.getItems().stream().allMatch(item -> item.getItem().hidden())) + { + configButton.addActionListener(e -> { - configButton.addActionListener(e -> - { - configButton.setIcon(CONFIG_ICON); - configPanel.openGroupConfigPanel(PluginListItem.this, config, configDescriptor); - }); + configButton.setIcon(CONFIG_ICON); + configPanel.openGroupConfigPanel(PluginListItem.this, config, configDescriptor); + }); - configButton.setVisible(true); - configButton.setToolTipText("Edit plugin configuration"); - } - if (!name.equals("RuneLitePlus")) { + configButton.setVisible(true); + configButton.setToolTipText("Edit plugin configuration"); + } + if (!name.equals("RuneLitePlus")) + { toggleButton.setPreferredSize(new Dimension(25, 0)); attachToggleButtonListener(toggleButton); buttonPanel.add(toggleButton); @@ -261,6 +258,7 @@ public class PluginListItem extends JPanel /** * Checks if all the search terms in the given list matches at least one keyword. + * * @return true if all search terms matches at least one keyword, or false if otherwise. */ boolean matchesSearchTerms(String[] searchTerms) @@ -268,7 +266,7 @@ public class PluginListItem extends JPanel for (String term : searchTerms) { if (keywords.stream().noneMatch((t) -> t.contains(term) || - DISTANCE.apply(t, term) > 0.9)) + DISTANCE.apply(t, term) > 0.9)) { return false; } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/dailytaskindicators/DailyTasksPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/dailytaskindicators/DailyTasksPlugin.java index 82f1624f1d..fe0ce2cdad 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/dailytaskindicators/DailyTasksPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/dailytaskindicators/DailyTasksPlugin.java @@ -251,7 +251,7 @@ public class DailyTasksPlugin extends Plugin max += BONEMEAL_PER_DIARY; } } - if (dailyReset || collected < max) + if (dailyReset || collected < max) { sendChatMessage(BONEMEAL_MESSAGE); } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/defaultworld/DefaultWorldPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/defaultworld/DefaultWorldPlugin.java index d68791d289..7bcd26fd8b 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/defaultworld/DefaultWorldPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/defaultworld/DefaultWorldPlugin.java @@ -1,152 +1,152 @@ -/* - * Copyright (c) 2018, Tomas Slusny - * 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.defaultworld; - -import com.google.inject.Provides; -import java.io.IOException; -import javax.inject.Inject; -import lombok.extern.slf4j.Slf4j; -import net.runelite.api.Client; -import net.runelite.api.GameState; -import net.runelite.api.events.GameStateChanged; -import net.runelite.client.events.SessionOpen; -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.WorldUtil; -import net.runelite.http.api.worlds.World; -import net.runelite.http.api.worlds.WorldClient; -import net.runelite.http.api.worlds.WorldResult; - -@PluginDescriptor( - name = "Default World", - description = "Enable a default world to be selected when launching the client", - tags = {"home"} -) -@Slf4j -public class DefaultWorldPlugin extends Plugin -{ - @Inject - private Client client; - - @Inject - private DefaultWorldConfig config; - - private final WorldClient worldClient = new WorldClient(); - private int worldCache; - private boolean worldChangeRequired; - - @Override - protected void startUp() throws Exception - { - worldChangeRequired = true; - applyWorld(); - } - - @Override - protected void shutDown() throws Exception - { - worldChangeRequired = true; - changeWorld(worldCache); - } - - @Provides - DefaultWorldConfig getConfig(ConfigManager configManager) - { - return configManager.getConfig(DefaultWorldConfig.class); - } - - @Subscribe - public void onSessionOpen(SessionOpen event) - { - worldChangeRequired = true; - applyWorld(); - } - - @Subscribe - public void onGameStateChanged(GameStateChanged event) - { - applyWorld(); - } - - private void changeWorld(int newWorld) - { - if (!worldChangeRequired || client.getGameState() != GameState.LOGIN_SCREEN) - { - return; - } - - worldChangeRequired = false; - int correctedWorld = newWorld < 300 ? newWorld + 300 : newWorld; - - // Old School RuneScape worlds start on 301 so don't even bother trying to find lower id ones - // and also do not try to set world if we are already on it - if (correctedWorld <= 300 || client.getWorld() == correctedWorld) - { - return; - } - - try - { - final WorldResult worldResult = worldClient.lookupWorlds(); - final World world = worldResult.findWorld(correctedWorld); - - if (world != null) - { - final net.runelite.api.World rsWorld = client.createWorld(); - rsWorld.setActivity(world.getActivity()); - rsWorld.setAddress(world.getAddress()); - rsWorld.setId(world.getId()); - rsWorld.setPlayerCount(world.getPlayers()); - rsWorld.setLocation(world.getLocation()); - rsWorld.setTypes(WorldUtil.toWorldTypes(world.getTypes())); - - client.changeWorld(rsWorld); - log.debug("Applied new world {}", correctedWorld); - } - else - { - log.warn("World {} not found.", correctedWorld); - } - } - catch (IOException e) - { - log.warn("Error looking up world {}. Error: {}", correctedWorld, e); - } - } - - private void applyWorld() - { - if (worldCache == 0) - { - worldCache = client.getWorld(); - log.debug("Stored old world {}", worldCache); - } - - final int newWorld = config.getWorld(); - changeWorld(newWorld); - } -} +/* + * Copyright (c) 2018, Tomas Slusny + * 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.defaultworld; + +import com.google.inject.Provides; +import java.io.IOException; +import javax.inject.Inject; +import lombok.extern.slf4j.Slf4j; +import net.runelite.api.Client; +import net.runelite.api.GameState; +import net.runelite.api.events.GameStateChanged; +import net.runelite.client.config.ConfigManager; +import net.runelite.client.eventbus.Subscribe; +import net.runelite.client.events.SessionOpen; +import net.runelite.client.plugins.Plugin; +import net.runelite.client.plugins.PluginDescriptor; +import net.runelite.client.util.WorldUtil; +import net.runelite.http.api.worlds.World; +import net.runelite.http.api.worlds.WorldClient; +import net.runelite.http.api.worlds.WorldResult; + +@PluginDescriptor( + name = "Default World", + description = "Enable a default world to be selected when launching the client", + tags = {"home"} +) +@Slf4j +public class DefaultWorldPlugin extends Plugin +{ + @Inject + private Client client; + + @Inject + private DefaultWorldConfig config; + + private final WorldClient worldClient = new WorldClient(); + private int worldCache; + private boolean worldChangeRequired; + + @Override + protected void startUp() throws Exception + { + worldChangeRequired = true; + applyWorld(); + } + + @Override + protected void shutDown() throws Exception + { + worldChangeRequired = true; + changeWorld(worldCache); + } + + @Provides + DefaultWorldConfig getConfig(ConfigManager configManager) + { + return configManager.getConfig(DefaultWorldConfig.class); + } + + @Subscribe + public void onSessionOpen(SessionOpen event) + { + worldChangeRequired = true; + applyWorld(); + } + + @Subscribe + public void onGameStateChanged(GameStateChanged event) + { + applyWorld(); + } + + private void changeWorld(int newWorld) + { + if (!worldChangeRequired || client.getGameState() != GameState.LOGIN_SCREEN) + { + return; + } + + worldChangeRequired = false; + int correctedWorld = newWorld < 300 ? newWorld + 300 : newWorld; + + // Old School RuneScape worlds start on 301 so don't even bother trying to find lower id ones + // and also do not try to set world if we are already on it + if (correctedWorld <= 300 || client.getWorld() == correctedWorld) + { + return; + } + + try + { + final WorldResult worldResult = worldClient.lookupWorlds(); + final World world = worldResult.findWorld(correctedWorld); + + if (world != null) + { + final net.runelite.api.World rsWorld = client.createWorld(); + rsWorld.setActivity(world.getActivity()); + rsWorld.setAddress(world.getAddress()); + rsWorld.setId(world.getId()); + rsWorld.setPlayerCount(world.getPlayers()); + rsWorld.setLocation(world.getLocation()); + rsWorld.setTypes(WorldUtil.toWorldTypes(world.getTypes())); + + client.changeWorld(rsWorld); + log.debug("Applied new world {}", correctedWorld); + } + else + { + log.warn("World {} not found.", correctedWorld); + } + } + catch (IOException e) + { + log.warn("Error looking up world {}. Error: {}", correctedWorld, e); + } + } + + private void applyWorld() + { + if (worldCache == 0) + { + worldCache = client.getWorld(); + log.debug("Stored old world {}", worldCache); + } + + final int newWorld = config.getWorld(); + changeWorld(newWorld); + } +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/demonicgorilla/DemonicGorillaOverlay.java b/runelite-client/src/main/java/net/runelite/client/plugins/demonicgorilla/DemonicGorillaOverlay.java index 2fa191d5ba..4396c71d73 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/demonicgorilla/DemonicGorillaOverlay.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/demonicgorilla/DemonicGorillaOverlay.java @@ -1,154 +1,157 @@ -/* - * Copyright (c) 2018, Woox - * 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.demonicgorilla; - -import java.awt.BasicStroke; -import java.awt.Color; -import java.awt.Dimension; -import java.awt.Graphics2D; -import java.awt.geom.Arc2D; -import java.awt.image.BufferedImage; -import java.util.ArrayList; -import java.util.List; -import javax.inject.Inject; -import net.runelite.api.Client; -import net.runelite.api.Perspective; -import net.runelite.api.Point; -import net.runelite.api.Skill; -import net.runelite.api.coords.LocalPoint; -import net.runelite.client.game.SkillIconManager; -import net.runelite.client.ui.overlay.Overlay; -import net.runelite.client.ui.overlay.OverlayLayer; -import net.runelite.client.ui.overlay.OverlayPosition; - -public class DemonicGorillaOverlay extends Overlay -{ - private static final Color COLOR_ICON_BACKGROUND = new Color(0, 0, 0, 128); - private static final Color COLOR_ICON_BORDER = new Color(0, 0, 0, 255); - private static final Color COLOR_ICON_BORDER_FILL = new Color(219, 175, 0, 255); - private static final int OVERLAY_ICON_DISTANCE = 50; - private static final int OVERLAY_ICON_MARGIN = 8; - - private Client client; - private DemonicGorillaPlugin plugin; - - @Inject - private SkillIconManager iconManager; - - @Inject - public DemonicGorillaOverlay(Client client, DemonicGorillaPlugin plugin) - { - setPosition(OverlayPosition.DYNAMIC); - setLayer(OverlayLayer.ABOVE_SCENE); - this.client = client; - this.plugin = plugin; - } - - private BufferedImage getIcon(DemonicGorilla.AttackStyle attackStyle) - { - switch (attackStyle) - { - case MELEE: return iconManager.getSkillImage(Skill.ATTACK); - case RANGED: return iconManager.getSkillImage(Skill.RANGED); - case MAGIC: return iconManager.getSkillImage(Skill.MAGIC); - } - return null; - } - - @Override - public Dimension render(Graphics2D graphics) - { - for (DemonicGorilla gorilla : plugin.getGorillas().values()) - { - if (gorilla.getNpc().getInteracting() == null) - { - continue; - } - - LocalPoint lp = gorilla.getNpc().getLocalLocation(); - if (lp != null) - { - Point point = Perspective.localToCanvas(client, lp, client.getPlane(), - gorilla.getNpc().getLogicalHeight() + 16); - if (point != null) - { - point = new Point(point.getX(), point.getY()); - - List attackStyles = gorilla.getNextPosibleAttackStyles(); - List icons = new ArrayList<>(); - int totalWidth = (attackStyles.size() - 1) * OVERLAY_ICON_MARGIN; - for (DemonicGorilla.AttackStyle attackStyle : attackStyles) - { - BufferedImage icon = getIcon(attackStyle); - icons.add(icon); - totalWidth += icon.getWidth(); - } - - int bgPadding = 4; - int currentPosX = 0; - for (BufferedImage icon : icons) - { - graphics.setStroke(new BasicStroke(2)); - graphics.setColor(COLOR_ICON_BACKGROUND); - graphics.fillOval( - point.getX() - totalWidth / 2 + currentPosX - bgPadding, - point.getY() - icon.getHeight() / 2 - OVERLAY_ICON_DISTANCE - bgPadding, - icon.getWidth() + bgPadding * 2, - icon.getHeight() + bgPadding * 2); - - graphics.setColor(COLOR_ICON_BORDER); - graphics.drawOval( - point.getX() - totalWidth / 2 + currentPosX - bgPadding, - point.getY() - icon.getHeight() / 2 - OVERLAY_ICON_DISTANCE - bgPadding, - icon.getWidth() + bgPadding * 2, - icon.getHeight() + bgPadding * 2); - - graphics.drawImage( - icon, - point.getX() - totalWidth / 2 + currentPosX, - point.getY() - icon.getHeight() / 2 - OVERLAY_ICON_DISTANCE, - null); - - graphics.setColor(COLOR_ICON_BORDER_FILL); - Arc2D.Double arc = new Arc2D.Double( - point.getX() - totalWidth / 2 + currentPosX - bgPadding, - point.getY() - icon.getHeight() / 2 - OVERLAY_ICON_DISTANCE - bgPadding, - icon.getWidth() + bgPadding * 2, - icon.getHeight() + bgPadding * 2, - 90.0, - -360.0 * (DemonicGorilla.ATTACKS_PER_SWITCH - - gorilla.getAttacksUntilSwitch()) / DemonicGorilla.ATTACKS_PER_SWITCH, - Arc2D.OPEN); - graphics.draw(arc); - - currentPosX += icon.getWidth() + OVERLAY_ICON_MARGIN; - } - } - } - } - - return null; - } +/* + * Copyright (c) 2018, Woox + * 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.demonicgorilla; + +import java.awt.BasicStroke; +import java.awt.Color; +import java.awt.Dimension; +import java.awt.Graphics2D; +import java.awt.geom.Arc2D; +import java.awt.image.BufferedImage; +import java.util.ArrayList; +import java.util.List; +import javax.inject.Inject; +import net.runelite.api.Client; +import net.runelite.api.Perspective; +import net.runelite.api.Point; +import net.runelite.api.Skill; +import net.runelite.api.coords.LocalPoint; +import net.runelite.client.game.SkillIconManager; +import net.runelite.client.ui.overlay.Overlay; +import net.runelite.client.ui.overlay.OverlayLayer; +import net.runelite.client.ui.overlay.OverlayPosition; + +public class DemonicGorillaOverlay extends Overlay +{ + private static final Color COLOR_ICON_BACKGROUND = new Color(0, 0, 0, 128); + private static final Color COLOR_ICON_BORDER = new Color(0, 0, 0, 255); + private static final Color COLOR_ICON_BORDER_FILL = new Color(219, 175, 0, 255); + private static final int OVERLAY_ICON_DISTANCE = 50; + private static final int OVERLAY_ICON_MARGIN = 8; + + private Client client; + private DemonicGorillaPlugin plugin; + + @Inject + private SkillIconManager iconManager; + + @Inject + public DemonicGorillaOverlay(Client client, DemonicGorillaPlugin plugin) + { + setPosition(OverlayPosition.DYNAMIC); + setLayer(OverlayLayer.ABOVE_SCENE); + this.client = client; + this.plugin = plugin; + } + + private BufferedImage getIcon(DemonicGorilla.AttackStyle attackStyle) + { + switch (attackStyle) + { + case MELEE: + return iconManager.getSkillImage(Skill.ATTACK); + case RANGED: + return iconManager.getSkillImage(Skill.RANGED); + case MAGIC: + return iconManager.getSkillImage(Skill.MAGIC); + } + return null; + } + + @Override + public Dimension render(Graphics2D graphics) + { + for (DemonicGorilla gorilla : plugin.getGorillas().values()) + { + if (gorilla.getNpc().getInteracting() == null) + { + continue; + } + + LocalPoint lp = gorilla.getNpc().getLocalLocation(); + if (lp != null) + { + Point point = Perspective.localToCanvas(client, lp, client.getPlane(), + gorilla.getNpc().getLogicalHeight() + 16); + if (point != null) + { + point = new Point(point.getX(), point.getY()); + + List attackStyles = gorilla.getNextPosibleAttackStyles(); + List icons = new ArrayList<>(); + int totalWidth = (attackStyles.size() - 1) * OVERLAY_ICON_MARGIN; + for (DemonicGorilla.AttackStyle attackStyle : attackStyles) + { + BufferedImage icon = getIcon(attackStyle); + icons.add(icon); + totalWidth += icon.getWidth(); + } + + int bgPadding = 4; + int currentPosX = 0; + for (BufferedImage icon : icons) + { + graphics.setStroke(new BasicStroke(2)); + graphics.setColor(COLOR_ICON_BACKGROUND); + graphics.fillOval( + point.getX() - totalWidth / 2 + currentPosX - bgPadding, + point.getY() - icon.getHeight() / 2 - OVERLAY_ICON_DISTANCE - bgPadding, + icon.getWidth() + bgPadding * 2, + icon.getHeight() + bgPadding * 2); + + graphics.setColor(COLOR_ICON_BORDER); + graphics.drawOval( + point.getX() - totalWidth / 2 + currentPosX - bgPadding, + point.getY() - icon.getHeight() / 2 - OVERLAY_ICON_DISTANCE - bgPadding, + icon.getWidth() + bgPadding * 2, + icon.getHeight() + bgPadding * 2); + + graphics.drawImage( + icon, + point.getX() - totalWidth / 2 + currentPosX, + point.getY() - icon.getHeight() / 2 - OVERLAY_ICON_DISTANCE, + null); + + graphics.setColor(COLOR_ICON_BORDER_FILL); + Arc2D.Double arc = new Arc2D.Double( + point.getX() - totalWidth / 2 + currentPosX - bgPadding, + point.getY() - icon.getHeight() / 2 - OVERLAY_ICON_DISTANCE - bgPadding, + icon.getWidth() + bgPadding * 2, + icon.getHeight() + bgPadding * 2, + 90.0, + -360.0 * (DemonicGorilla.ATTACKS_PER_SWITCH - + gorilla.getAttacksUntilSwitch()) / DemonicGorilla.ATTACKS_PER_SWITCH, + Arc2D.OPEN); + graphics.draw(arc); + + currentPosX += icon.getWidth() + OVERLAY_ICON_MARGIN; + } + } + } + } + + return null; + } } \ No newline at end of file diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/demonicgorilla/DemonicGorillaPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/demonicgorilla/DemonicGorillaPlugin.java index 0e9660b918..e0bc04dfad 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/demonicgorilla/DemonicGorillaPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/demonicgorilla/DemonicGorillaPlugin.java @@ -1,716 +1,716 @@ -/* - * Copyright (c) 2018, Woox - * 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.demonicgorilla; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.HashMap; -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import java.util.stream.Collectors; -import javax.inject.Inject; -import lombok.Getter; -import net.runelite.api.AnimationID; -import net.runelite.api.Client; -import net.runelite.api.GameState; -import net.runelite.api.HeadIcon; -import net.runelite.api.Hitsplat; -import net.runelite.api.NPC; -import net.runelite.api.NpcID; -import net.runelite.api.Player; -import net.runelite.api.Projectile; -import net.runelite.api.ProjectileID; -import net.runelite.api.coords.WorldArea; -import net.runelite.api.coords.WorldPoint; -import net.runelite.api.events.GameStateChanged; -import net.runelite.api.events.GameTick; -import net.runelite.api.events.HitsplatApplied; -import net.runelite.api.events.NpcDespawned; -import net.runelite.api.events.NpcSpawned; -import net.runelite.api.events.PlayerDespawned; -import net.runelite.api.events.PlayerSpawned; -import net.runelite.api.events.ProjectileMoved; -import net.runelite.client.callback.ClientThread; -import net.runelite.client.eventbus.Subscribe; -import net.runelite.client.plugins.Plugin; -import net.runelite.client.plugins.PluginDescriptor; -import net.runelite.client.ui.overlay.OverlayManager; - -@PluginDescriptor( - name = "Demonic Gorillas", - description = "Count demonic gorilla attacks and display their next possible attack styles", - tags = {"combat", "overlay", "pve", "pvm"} -) -public class DemonicGorillaPlugin extends Plugin -{ - @Inject - private Client client; - - @Inject - private OverlayManager overlayManager; - - @Inject - private DemonicGorillaOverlay overlay; - - @Inject - private ClientThread clientThread; - - @Getter - private Map gorillas; - - private List recentBoulders; - - private List pendingAttacks; - - private Map memorizedPlayers; - - @Override - protected void startUp() throws Exception - { - overlayManager.add(overlay); - gorillas = new HashMap<>(); - recentBoulders = new ArrayList<>(); - pendingAttacks = new ArrayList<>(); - memorizedPlayers = new HashMap<>(); - clientThread.invoke(this::reset); // Updates the list of gorillas and players - } - - @Override - protected void shutDown() throws Exception - { - overlayManager.remove(overlay); - gorillas = null; - recentBoulders = null; - pendingAttacks = null; - memorizedPlayers = null; - } - - private void clear() - { - recentBoulders.clear(); - pendingAttacks.clear(); - memorizedPlayers.clear(); - gorillas.clear(); - } - - private void reset() - { - recentBoulders.clear(); - pendingAttacks.clear(); - resetGorillas(); - resetPlayers(); - } - - private void resetGorillas() - { - gorillas.clear(); - for (NPC npc : client.getNpcs()) - { - if (isNpcGorilla(npc.getId())) - { - gorillas.put(npc, new DemonicGorilla(npc)); - } - } - } - - private void resetPlayers() - { - memorizedPlayers.clear(); - for (Player player : client.getPlayers()) - { - memorizedPlayers.put(player, new MemorizedPlayer(player)); - } - } - - public static boolean isNpcGorilla(int npcId) - { - return npcId == NpcID.DEMONIC_GORILLA || - npcId == NpcID.DEMONIC_GORILLA_7145 || - npcId == NpcID.DEMONIC_GORILLA_7146 || - npcId == NpcID.DEMONIC_GORILLA_7147 || - npcId == NpcID.DEMONIC_GORILLA_7148 || - npcId == NpcID.DEMONIC_GORILLA_7149; - } - - private void checkGorillaAttackStyleSwitch(DemonicGorilla gorilla, - final DemonicGorilla.AttackStyle... protectedStyles) - { - if (gorilla.getAttacksUntilSwitch() <= 0 || - gorilla.getNextPosibleAttackStyles().isEmpty()) - { - gorilla.setNextPosibleAttackStyles(Arrays - .stream(DemonicGorilla.ALL_REGULAR_ATTACK_STYLES) - .filter(x -> Arrays.stream(protectedStyles).noneMatch(y -> x == y)) - .collect(Collectors.toList())); - gorilla.setAttacksUntilSwitch(DemonicGorilla.ATTACKS_PER_SWITCH); - gorilla.setChangedAttackStyleThisTick(true); - } - } - - private DemonicGorilla.AttackStyle getProtectedStyle(Player player) - { - HeadIcon headIcon = player.getOverheadIcon(); - if (headIcon == null) - { - return null; - } - switch (headIcon) - { - case MELEE: - return DemonicGorilla.AttackStyle.MELEE; - case RANGED: - return DemonicGorilla.AttackStyle.RANGED; - case MAGIC: - return DemonicGorilla.AttackStyle.MAGIC; - default: - return null; - } - } - - private void onGorillaAttack(DemonicGorilla gorilla, final DemonicGorilla.AttackStyle attackStyle) - { - gorilla.setInitiatedCombat(true); - - Player target = (Player)gorilla.getNpc().getInteracting(); - - DemonicGorilla.AttackStyle protectedStyle = null; - if (target != null) - { - protectedStyle = getProtectedStyle(target); - } - boolean correctPrayer = - target == null || // If player is out of memory, assume prayer was correct - attackStyle == protectedStyle; - - if (attackStyle == DemonicGorilla.AttackStyle.BOULDER) - { - // The gorilla can't throw boulders when it's meleeing - gorilla.setNextPosibleAttackStyles(gorilla - .getNextPosibleAttackStyles() - .stream() - .filter(x -> x != DemonicGorilla.AttackStyle.MELEE) - .collect(Collectors.toList())); - } - else - { - if (correctPrayer) - { - gorilla.setAttacksUntilSwitch(gorilla.getAttacksUntilSwitch() - 1); - } - else - { - // We're not sure if the attack will hit a 0 or not, - // so we don't know if we should decrease the counter or not, - // so we keep track of the attack here until the damage splat - // has appeared on the player. - - int damagesOnTick = client.getTickCount(); - if (attackStyle == DemonicGorilla.AttackStyle.MAGIC) - { - MemorizedPlayer mp = memorizedPlayers.get(target); - WorldArea lastPlayerArea = mp.getLastWorldArea(); - if (lastPlayerArea != null) - { - int dist = gorilla.getNpc().getWorldArea().distanceTo(lastPlayerArea); - damagesOnTick += (dist + DemonicGorilla.PROJECTILE_MAGIC_DELAY) / - DemonicGorilla.PROJECTILE_MAGIC_SPEED; - } - } - else if (attackStyle == DemonicGorilla.AttackStyle.RANGED) - { - MemorizedPlayer mp = memorizedPlayers.get(target); - WorldArea lastPlayerArea = mp.getLastWorldArea(); - if (lastPlayerArea != null) - { - int dist = gorilla.getNpc().getWorldArea().distanceTo(lastPlayerArea); - damagesOnTick += (dist + DemonicGorilla.PROJECTILE_RANGED_DELAY) / - DemonicGorilla.PROJECTILE_RANGED_SPEED; - } - } - pendingAttacks.add(new PendingGorillaAttack(gorilla, attackStyle, target, damagesOnTick)); - } - - gorilla.setNextPosibleAttackStyles(gorilla - .getNextPosibleAttackStyles() - .stream() - .filter(x -> x == attackStyle) - .collect(Collectors.toList())); - - if (gorilla.getNextPosibleAttackStyles().isEmpty()) - { - // Sometimes the gorilla can switch attack style before it's supposed to - // if someone was fighting it earlier and then left, so we just - // reset the counter in that case. - - gorilla.setNextPosibleAttackStyles(Arrays - .stream(DemonicGorilla.ALL_REGULAR_ATTACK_STYLES) - .filter(x -> x == attackStyle) - .collect(Collectors.toList())); - gorilla.setAttacksUntilSwitch(DemonicGorilla.ATTACKS_PER_SWITCH - - (correctPrayer ? 1 : 0)); - } - } - - checkGorillaAttackStyleSwitch(gorilla, protectedStyle); - - int tickCounter = client.getTickCount(); - gorilla.setNextAttackTick(tickCounter + DemonicGorilla.ATTACK_RATE); - } - - private void checkGorillaAttacks() - { - int tickCounter = client.getTickCount(); - for (DemonicGorilla gorilla : gorillas.values()) - { - Player interacting = (Player)gorilla.getNpc().getInteracting(); - MemorizedPlayer mp = memorizedPlayers.get(interacting); - - if (gorilla.getLastTickInteracting() != null && interacting == null) - { - gorilla.setInitiatedCombat(false); - } - else if (mp != null && mp.getLastWorldArea() != null && - !gorilla.isInitiatedCombat() && - tickCounter < gorilla.getNextAttackTick() && - gorilla.getNpc().getWorldArea().isInMeleeDistance(mp.getLastWorldArea())) - { - gorilla.setInitiatedCombat(true); - gorilla.setNextAttackTick(tickCounter + 1); - } - - int animationId = gorilla.getNpc().getAnimation(); - - if (gorilla.isTakenDamageRecently() && - tickCounter >= gorilla.getNextAttackTick() + 4) - { - // The gorilla was flinched, so its next attack gets delayed - gorilla.setNextAttackTick(tickCounter + DemonicGorilla.ATTACK_RATE / 2); - gorilla.setInitiatedCombat(true); - - if (mp != null && mp.getLastWorldArea() != null && - !gorilla.getNpc().getWorldArea().isInMeleeDistance(mp.getLastWorldArea()) && - !gorilla.getNpc().getWorldArea().intersectsWith(mp.getLastWorldArea())) - { - // Gorillas stop meleeing when they get flinched - // and the target isn't in melee distance - gorilla.setNextPosibleAttackStyles(gorilla - .getNextPosibleAttackStyles() - .stream() - .filter(x -> x != DemonicGorilla.AttackStyle.MELEE) - .collect(Collectors.toList())); - checkGorillaAttackStyleSwitch(gorilla, DemonicGorilla.AttackStyle.MELEE, - getProtectedStyle(interacting)); - } - } - else if (animationId != gorilla.getLastTickAnimation()) - { - if (animationId == AnimationID.DEMONIC_GORILLA_MELEE_ATTACK) - { - onGorillaAttack(gorilla, DemonicGorilla.AttackStyle.MELEE); - } - else if (animationId == AnimationID.DEMONIC_GORILLA_MAGIC_ATTACK) - { - onGorillaAttack(gorilla, DemonicGorilla.AttackStyle.MAGIC); - } - else if (animationId == AnimationID.DEMONIC_GORILLA_RANGED_ATTACK) - { - onGorillaAttack(gorilla, DemonicGorilla.AttackStyle.RANGED); - } - else if (animationId == AnimationID.DEMONIC_GORILLA_AOE_ATTACK && interacting != null) - { - // Note that AoE animation is the same as prayer switch animation - // so we need to check if the prayer was switched or not. - // It also does this animation when it spawns, so - // we need the interacting != null check. - - if (gorilla.getOverheadIcon() == gorilla.getLastTickOverheadIcon()) - { - // Confirmed, the gorilla used the AoE attack - onGorillaAttack(gorilla, DemonicGorilla.AttackStyle.BOULDER); - } - else - { - if (tickCounter >= gorilla.getNextAttackTick()) - { - gorilla.setChangedPrayerThisTick(true); - - // This part is more complicated because the gorilla may have - // used an attack, but the prayer switch animation takes - // priority over normal attack animations. - - int projectileId = gorilla.getRecentProjectileId(); - if (projectileId == ProjectileID.DEMONIC_GORILLA_MAGIC) - { - onGorillaAttack(gorilla, DemonicGorilla.AttackStyle.MAGIC); - } - else if (projectileId == ProjectileID.DEMONIC_GORILLA_RANGED) - { - onGorillaAttack(gorilla, DemonicGorilla.AttackStyle.RANGED); - } - else if (mp != null) - { - WorldArea lastPlayerArea = mp.getLastWorldArea(); - if (lastPlayerArea != null && - interacting != null && recentBoulders.stream() - .anyMatch(x -> x.distanceTo(lastPlayerArea) == 0)) - { - // A boulder started falling on the gorillas target, - // so we assume it was the gorilla who shot it - onGorillaAttack(gorilla, DemonicGorilla.AttackStyle.BOULDER); - } - else if (!mp.getRecentHitsplats().isEmpty()) - { - // It wasn't any of the three other attacks, - // but the player took damage, so we assume - // it's a melee attack - onGorillaAttack(gorilla, DemonicGorilla.AttackStyle.MELEE); - } - } - } - - // The next attack tick is always delayed if the - // gorilla switched prayer - gorilla.setNextAttackTick(tickCounter + DemonicGorilla.ATTACK_RATE); - gorilla.setChangedPrayerThisTick(true); - } - } - } - - if (gorilla.getDisabledMeleeMovementForTicks() > 0) - { - gorilla.setDisabledMeleeMovementForTicks(gorilla.getDisabledMeleeMovementForTicks() - 1); - } - else if (gorilla.isInitiatedCombat() && - gorilla.getNpc().getInteracting() != null && - !gorilla.isChangedAttackStyleThisTick() && - gorilla.getNextPosibleAttackStyles().size() >= 2 && - gorilla.getNextPosibleAttackStyles().stream() - .anyMatch(x -> x == DemonicGorilla.AttackStyle.MELEE)) - { - // If melee is a possibility, we can check if the gorilla - // is or isn't moving toward the player to determine if - // it is actually attempting to melee or not. - // We only run this check if the gorilla is in combat - // because otherwise it attempts to travel to melee - // distance before attacking its target. - - if (mp != null && mp.getLastWorldArea() != null && gorilla.getLastWorldArea() != null) - { - WorldArea predictedNewArea = gorilla.getLastWorldArea().calculateNextTravellingPoint( - client, mp.getLastWorldArea(), true, x -> - { - // Gorillas can't normally walk through other gorillas - // or other players - final WorldArea area1 = new WorldArea(x, 1, 1); - return area1 != null && - gorillas.values().stream().noneMatch(y -> - { - if (y == gorilla) - { - return false; - } - final WorldArea area2 = - y.getNpc().getIndex() < gorilla.getNpc().getIndex() ? - y.getNpc().getWorldArea() : y.getLastWorldArea(); - return area2 != null && area1.intersectsWith(area2); - }) && - memorizedPlayers.values().stream().noneMatch(y -> - { - final WorldArea area2 = y.getLastWorldArea(); - return area2 != null && area1.intersectsWith(area2); - }); - - // There is a special case where if a player walked through - // a gorilla, or a player walked through another player, - // the tiles that were walked through becomes - // walkable, but I didn't feel like it's necessary to handle - // that special case as it should rarely happen. - }); - if (predictedNewArea != null) - { - int distance = gorilla.getNpc().getWorldArea().distanceTo(mp.getLastWorldArea()); - WorldPoint predictedMovement = predictedNewArea.toWorldPoint(); - if (distance <= DemonicGorilla.MAX_ATTACK_RANGE && - mp != null && - mp.getLastWorldArea().hasLineOfSightTo(client, gorilla.getLastWorldArea())) - { - if (predictedMovement.distanceTo(gorilla.getLastWorldArea().toWorldPoint()) != 0) - { - if (predictedMovement.distanceTo(gorilla.getNpc().getWorldLocation()) == 0) - { - gorilla.setNextPosibleAttackStyles(gorilla - .getNextPosibleAttackStyles() - .stream() - .filter(x -> x == DemonicGorilla.AttackStyle.MELEE) - .collect(Collectors.toList())); - } - else - { - gorilla.setNextPosibleAttackStyles(gorilla - .getNextPosibleAttackStyles() - .stream() - .filter(x -> x != DemonicGorilla.AttackStyle.MELEE) - .collect(Collectors.toList())); - } - } - else if (tickCounter >= gorilla.getNextAttackTick() && - gorilla.getRecentProjectileId() == -1 && - recentBoulders.stream().noneMatch(x -> x.distanceTo(mp.getLastWorldArea()) == 0)) - { - gorilla.setNextPosibleAttackStyles(gorilla - .getNextPosibleAttackStyles() - .stream() - .filter(x -> x == DemonicGorilla.AttackStyle.MELEE) - .collect(Collectors.toList())); - } - } - } - } - } - - if (gorilla.isTakenDamageRecently()) - { - gorilla.setInitiatedCombat(true); - } - - if (gorilla.getOverheadIcon() != gorilla.getLastTickOverheadIcon()) - { - if (gorilla.isChangedAttackStyleLastTick() || - gorilla.isChangedAttackStyleThisTick()) - { - // Apparently if it changes attack style and changes - // prayer on the same tick or 1 tick apart, it won't - // be able to move for the next 2 ticks if it attempts - // to melee - gorilla.setDisabledMeleeMovementForTicks(2); - } - else - { - // If it didn't change attack style lately, - // it's only for the next 1 tick - gorilla.setDisabledMeleeMovementForTicks(1); - } - } - gorilla.setLastTickAnimation(gorilla.getNpc().getAnimation()); - gorilla.setLastWorldArea(gorilla.getNpc().getWorldArea()); - gorilla.setLastTickInteracting(gorilla.getNpc().getInteracting()); - gorilla.setTakenDamageRecently(false); - gorilla.setChangedPrayerThisTick(false); - gorilla.setChangedAttackStyleLastTick(gorilla.isChangedAttackStyleThisTick()); - gorilla.setChangedAttackStyleThisTick(false); - gorilla.setLastTickOverheadIcon(gorilla.getOverheadIcon()); - gorilla.setRecentProjectileId(-1); - } - } - - @Subscribe - public void onProjectileMoved(ProjectileMoved event) - { - Projectile projectile = event.getProjectile(); - int projectileId = projectile.getId(); - if (projectileId != ProjectileID.DEMONIC_GORILLA_RANGED && - projectileId != ProjectileID.DEMONIC_GORILLA_MAGIC && - projectileId != ProjectileID.DEMONIC_GORILLA_BOULDER) - { - return; - } - - // The event fires once before the projectile starts moving, - // and we only want to check each projectile once - if (client.getGameCycle() >= projectile.getStartMovementCycle()) - { - return; - } - - if (projectileId == ProjectileID.DEMONIC_GORILLA_BOULDER) - { - recentBoulders.add(WorldPoint.fromLocal(client, event.getPosition())); - } - else if (projectileId == ProjectileID.DEMONIC_GORILLA_MAGIC || - projectileId == ProjectileID.DEMONIC_GORILLA_RANGED) - { - WorldPoint projectileSourcePosition = WorldPoint.fromLocal( - client, projectile.getX1(), projectile.getY1(), client.getPlane()); - for (DemonicGorilla gorilla : gorillas.values()) - { - if (gorilla.getNpc().getWorldLocation().distanceTo(projectileSourcePosition) == 0) - { - gorilla.setRecentProjectileId(projectile.getId()); - } - } - } - } - - private void checkPendingAttacks() - { - Iterator it = pendingAttacks.iterator(); - int tickCounter = client.getTickCount(); - while (it.hasNext()) - { - PendingGorillaAttack attack = it.next(); - if (tickCounter >= attack.getFinishesOnTick()) - { - boolean shouldDecreaseCounter = false; - DemonicGorilla gorilla = attack.getAttacker(); - MemorizedPlayer target = memorizedPlayers.get(attack.getTarget()); - if (target == null) - { - // Player went out of memory, so assume the hit was a 0 - shouldDecreaseCounter = true; - } - else if (target.getRecentHitsplats().isEmpty()) - { - // No hitsplats was applied. This may happen in some cases - // where the player was out of memory while the - // projectile was travelling. So we assume the hit was a 0. - shouldDecreaseCounter = true; - } - else if (target.getRecentHitsplats().stream() - .anyMatch(x -> x.getHitsplatType() == Hitsplat.HitsplatType.BLOCK)) - { - // A blue hitsplat appeared, so we assume the gorilla hit a 0 - shouldDecreaseCounter = true; - } - - if (shouldDecreaseCounter) - { - gorilla.setAttacksUntilSwitch(gorilla.getAttacksUntilSwitch() - 1); - checkGorillaAttackStyleSwitch(gorilla); - } - - it.remove(); - } - } - } - - private void updatePlayers() - { - for (MemorizedPlayer mp : memorizedPlayers.values()) - { - mp.setLastWorldArea(mp.getPlayer().getWorldArea()); - mp.getRecentHitsplats().clear(); - } - } - - @Subscribe - public void onHitsplatApplied(HitsplatApplied event) - { - if (gorillas.isEmpty()) - { - return; - } - - if (event.getActor() instanceof Player) - { - Player player = (Player)event.getActor(); - MemorizedPlayer mp = memorizedPlayers.get(player); - if (mp != null) - { - mp.getRecentHitsplats().add(event.getHitsplat()); - } - } - else if (event.getActor() instanceof NPC) - { - DemonicGorilla gorilla = gorillas.get(event.getActor()); - Hitsplat.HitsplatType hitsplatType = event.getHitsplat().getHitsplatType(); - if (gorilla != null && (hitsplatType == Hitsplat.HitsplatType.BLOCK || - hitsplatType == Hitsplat.HitsplatType.DAMAGE)) - { - gorilla.setTakenDamageRecently(true); - } - } - } - - @Subscribe - public void onGameStateChanged(GameStateChanged event) - { - GameState gs = event.getGameState(); - if (gs == GameState.LOGGING_IN || - gs == GameState.CONNECTION_LOST || - gs == GameState.HOPPING) - { - reset(); - } - } - - @Subscribe - public void onPlayerSpawned(PlayerSpawned event) - { - if (gorillas.isEmpty()) - { - return; - } - - Player player = event.getPlayer(); - memorizedPlayers.put(player, new MemorizedPlayer(player)); - } - - @Subscribe - public void onPlayerDespawned(PlayerDespawned event) - { - if (gorillas.isEmpty()) - { - return; - } - - memorizedPlayers.remove(event.getPlayer()); - } - - @Subscribe - public void onNpcSpawned(NpcSpawned event) - { - NPC npc = event.getNpc(); - if (isNpcGorilla(npc.getId())) - { - if (gorillas.isEmpty()) - { - // Players are not kept track of when there are no gorillas in - // memory, so we need to add the players that were already in memory. - resetPlayers(); - } - - gorillas.put(npc, new DemonicGorilla(npc)); - } - } - - @Subscribe - public void onNpcDespawned(NpcDespawned event) - { - if (gorillas.remove(event.getNpc()) != null && gorillas.isEmpty()) - { - clear(); - } - } - - @Subscribe - public void onGameTick(GameTick event) - { - checkGorillaAttacks(); - checkPendingAttacks(); - updatePlayers(); - recentBoulders.clear(); - } +/* + * Copyright (c) 2018, Woox + * 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.demonicgorilla; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; +import javax.inject.Inject; +import lombok.Getter; +import net.runelite.api.AnimationID; +import net.runelite.api.Client; +import net.runelite.api.GameState; +import net.runelite.api.HeadIcon; +import net.runelite.api.Hitsplat; +import net.runelite.api.NPC; +import net.runelite.api.NpcID; +import net.runelite.api.Player; +import net.runelite.api.Projectile; +import net.runelite.api.ProjectileID; +import net.runelite.api.coords.WorldArea; +import net.runelite.api.coords.WorldPoint; +import net.runelite.api.events.GameStateChanged; +import net.runelite.api.events.GameTick; +import net.runelite.api.events.HitsplatApplied; +import net.runelite.api.events.NpcDespawned; +import net.runelite.api.events.NpcSpawned; +import net.runelite.api.events.PlayerDespawned; +import net.runelite.api.events.PlayerSpawned; +import net.runelite.api.events.ProjectileMoved; +import net.runelite.client.callback.ClientThread; +import net.runelite.client.eventbus.Subscribe; +import net.runelite.client.plugins.Plugin; +import net.runelite.client.plugins.PluginDescriptor; +import net.runelite.client.ui.overlay.OverlayManager; + +@PluginDescriptor( + name = "Demonic Gorillas", + description = "Count demonic gorilla attacks and display their next possible attack styles", + tags = {"combat", "overlay", "pve", "pvm"} +) +public class DemonicGorillaPlugin extends Plugin +{ + @Inject + private Client client; + + @Inject + private OverlayManager overlayManager; + + @Inject + private DemonicGorillaOverlay overlay; + + @Inject + private ClientThread clientThread; + + @Getter + private Map gorillas; + + private List recentBoulders; + + private List pendingAttacks; + + private Map memorizedPlayers; + + @Override + protected void startUp() throws Exception + { + overlayManager.add(overlay); + gorillas = new HashMap<>(); + recentBoulders = new ArrayList<>(); + pendingAttacks = new ArrayList<>(); + memorizedPlayers = new HashMap<>(); + clientThread.invoke(this::reset); // Updates the list of gorillas and players + } + + @Override + protected void shutDown() throws Exception + { + overlayManager.remove(overlay); + gorillas = null; + recentBoulders = null; + pendingAttacks = null; + memorizedPlayers = null; + } + + private void clear() + { + recentBoulders.clear(); + pendingAttacks.clear(); + memorizedPlayers.clear(); + gorillas.clear(); + } + + private void reset() + { + recentBoulders.clear(); + pendingAttacks.clear(); + resetGorillas(); + resetPlayers(); + } + + private void resetGorillas() + { + gorillas.clear(); + for (NPC npc : client.getNpcs()) + { + if (isNpcGorilla(npc.getId())) + { + gorillas.put(npc, new DemonicGorilla(npc)); + } + } + } + + private void resetPlayers() + { + memorizedPlayers.clear(); + for (Player player : client.getPlayers()) + { + memorizedPlayers.put(player, new MemorizedPlayer(player)); + } + } + + public static boolean isNpcGorilla(int npcId) + { + return npcId == NpcID.DEMONIC_GORILLA || + npcId == NpcID.DEMONIC_GORILLA_7145 || + npcId == NpcID.DEMONIC_GORILLA_7146 || + npcId == NpcID.DEMONIC_GORILLA_7147 || + npcId == NpcID.DEMONIC_GORILLA_7148 || + npcId == NpcID.DEMONIC_GORILLA_7149; + } + + private void checkGorillaAttackStyleSwitch(DemonicGorilla gorilla, + final DemonicGorilla.AttackStyle... protectedStyles) + { + if (gorilla.getAttacksUntilSwitch() <= 0 || + gorilla.getNextPosibleAttackStyles().isEmpty()) + { + gorilla.setNextPosibleAttackStyles(Arrays + .stream(DemonicGorilla.ALL_REGULAR_ATTACK_STYLES) + .filter(x -> Arrays.stream(protectedStyles).noneMatch(y -> x == y)) + .collect(Collectors.toList())); + gorilla.setAttacksUntilSwitch(DemonicGorilla.ATTACKS_PER_SWITCH); + gorilla.setChangedAttackStyleThisTick(true); + } + } + + private DemonicGorilla.AttackStyle getProtectedStyle(Player player) + { + HeadIcon headIcon = player.getOverheadIcon(); + if (headIcon == null) + { + return null; + } + switch (headIcon) + { + case MELEE: + return DemonicGorilla.AttackStyle.MELEE; + case RANGED: + return DemonicGorilla.AttackStyle.RANGED; + case MAGIC: + return DemonicGorilla.AttackStyle.MAGIC; + default: + return null; + } + } + + private void onGorillaAttack(DemonicGorilla gorilla, final DemonicGorilla.AttackStyle attackStyle) + { + gorilla.setInitiatedCombat(true); + + Player target = (Player) gorilla.getNpc().getInteracting(); + + DemonicGorilla.AttackStyle protectedStyle = null; + if (target != null) + { + protectedStyle = getProtectedStyle(target); + } + boolean correctPrayer = + target == null || // If player is out of memory, assume prayer was correct + attackStyle == protectedStyle; + + if (attackStyle == DemonicGorilla.AttackStyle.BOULDER) + { + // The gorilla can't throw boulders when it's meleeing + gorilla.setNextPosibleAttackStyles(gorilla + .getNextPosibleAttackStyles() + .stream() + .filter(x -> x != DemonicGorilla.AttackStyle.MELEE) + .collect(Collectors.toList())); + } + else + { + if (correctPrayer) + { + gorilla.setAttacksUntilSwitch(gorilla.getAttacksUntilSwitch() - 1); + } + else + { + // We're not sure if the attack will hit a 0 or not, + // so we don't know if we should decrease the counter or not, + // so we keep track of the attack here until the damage splat + // has appeared on the player. + + int damagesOnTick = client.getTickCount(); + if (attackStyle == DemonicGorilla.AttackStyle.MAGIC) + { + MemorizedPlayer mp = memorizedPlayers.get(target); + WorldArea lastPlayerArea = mp.getLastWorldArea(); + if (lastPlayerArea != null) + { + int dist = gorilla.getNpc().getWorldArea().distanceTo(lastPlayerArea); + damagesOnTick += (dist + DemonicGorilla.PROJECTILE_MAGIC_DELAY) / + DemonicGorilla.PROJECTILE_MAGIC_SPEED; + } + } + else if (attackStyle == DemonicGorilla.AttackStyle.RANGED) + { + MemorizedPlayer mp = memorizedPlayers.get(target); + WorldArea lastPlayerArea = mp.getLastWorldArea(); + if (lastPlayerArea != null) + { + int dist = gorilla.getNpc().getWorldArea().distanceTo(lastPlayerArea); + damagesOnTick += (dist + DemonicGorilla.PROJECTILE_RANGED_DELAY) / + DemonicGorilla.PROJECTILE_RANGED_SPEED; + } + } + pendingAttacks.add(new PendingGorillaAttack(gorilla, attackStyle, target, damagesOnTick)); + } + + gorilla.setNextPosibleAttackStyles(gorilla + .getNextPosibleAttackStyles() + .stream() + .filter(x -> x == attackStyle) + .collect(Collectors.toList())); + + if (gorilla.getNextPosibleAttackStyles().isEmpty()) + { + // Sometimes the gorilla can switch attack style before it's supposed to + // if someone was fighting it earlier and then left, so we just + // reset the counter in that case. + + gorilla.setNextPosibleAttackStyles(Arrays + .stream(DemonicGorilla.ALL_REGULAR_ATTACK_STYLES) + .filter(x -> x == attackStyle) + .collect(Collectors.toList())); + gorilla.setAttacksUntilSwitch(DemonicGorilla.ATTACKS_PER_SWITCH - + (correctPrayer ? 1 : 0)); + } + } + + checkGorillaAttackStyleSwitch(gorilla, protectedStyle); + + int tickCounter = client.getTickCount(); + gorilla.setNextAttackTick(tickCounter + DemonicGorilla.ATTACK_RATE); + } + + private void checkGorillaAttacks() + { + int tickCounter = client.getTickCount(); + for (DemonicGorilla gorilla : gorillas.values()) + { + Player interacting = (Player) gorilla.getNpc().getInteracting(); + MemorizedPlayer mp = memorizedPlayers.get(interacting); + + if (gorilla.getLastTickInteracting() != null && interacting == null) + { + gorilla.setInitiatedCombat(false); + } + else if (mp != null && mp.getLastWorldArea() != null && + !gorilla.isInitiatedCombat() && + tickCounter < gorilla.getNextAttackTick() && + gorilla.getNpc().getWorldArea().isInMeleeDistance(mp.getLastWorldArea())) + { + gorilla.setInitiatedCombat(true); + gorilla.setNextAttackTick(tickCounter + 1); + } + + int animationId = gorilla.getNpc().getAnimation(); + + if (gorilla.isTakenDamageRecently() && + tickCounter >= gorilla.getNextAttackTick() + 4) + { + // The gorilla was flinched, so its next attack gets delayed + gorilla.setNextAttackTick(tickCounter + DemonicGorilla.ATTACK_RATE / 2); + gorilla.setInitiatedCombat(true); + + if (mp != null && mp.getLastWorldArea() != null && + !gorilla.getNpc().getWorldArea().isInMeleeDistance(mp.getLastWorldArea()) && + !gorilla.getNpc().getWorldArea().intersectsWith(mp.getLastWorldArea())) + { + // Gorillas stop meleeing when they get flinched + // and the target isn't in melee distance + gorilla.setNextPosibleAttackStyles(gorilla + .getNextPosibleAttackStyles() + .stream() + .filter(x -> x != DemonicGorilla.AttackStyle.MELEE) + .collect(Collectors.toList())); + checkGorillaAttackStyleSwitch(gorilla, DemonicGorilla.AttackStyle.MELEE, + getProtectedStyle(interacting)); + } + } + else if (animationId != gorilla.getLastTickAnimation()) + { + if (animationId == AnimationID.DEMONIC_GORILLA_MELEE_ATTACK) + { + onGorillaAttack(gorilla, DemonicGorilla.AttackStyle.MELEE); + } + else if (animationId == AnimationID.DEMONIC_GORILLA_MAGIC_ATTACK) + { + onGorillaAttack(gorilla, DemonicGorilla.AttackStyle.MAGIC); + } + else if (animationId == AnimationID.DEMONIC_GORILLA_RANGED_ATTACK) + { + onGorillaAttack(gorilla, DemonicGorilla.AttackStyle.RANGED); + } + else if (animationId == AnimationID.DEMONIC_GORILLA_AOE_ATTACK && interacting != null) + { + // Note that AoE animation is the same as prayer switch animation + // so we need to check if the prayer was switched or not. + // It also does this animation when it spawns, so + // we need the interacting != null check. + + if (gorilla.getOverheadIcon() == gorilla.getLastTickOverheadIcon()) + { + // Confirmed, the gorilla used the AoE attack + onGorillaAttack(gorilla, DemonicGorilla.AttackStyle.BOULDER); + } + else + { + if (tickCounter >= gorilla.getNextAttackTick()) + { + gorilla.setChangedPrayerThisTick(true); + + // This part is more complicated because the gorilla may have + // used an attack, but the prayer switch animation takes + // priority over normal attack animations. + + int projectileId = gorilla.getRecentProjectileId(); + if (projectileId == ProjectileID.DEMONIC_GORILLA_MAGIC) + { + onGorillaAttack(gorilla, DemonicGorilla.AttackStyle.MAGIC); + } + else if (projectileId == ProjectileID.DEMONIC_GORILLA_RANGED) + { + onGorillaAttack(gorilla, DemonicGorilla.AttackStyle.RANGED); + } + else if (mp != null) + { + WorldArea lastPlayerArea = mp.getLastWorldArea(); + if (lastPlayerArea != null && + interacting != null && recentBoulders.stream() + .anyMatch(x -> x.distanceTo(lastPlayerArea) == 0)) + { + // A boulder started falling on the gorillas target, + // so we assume it was the gorilla who shot it + onGorillaAttack(gorilla, DemonicGorilla.AttackStyle.BOULDER); + } + else if (!mp.getRecentHitsplats().isEmpty()) + { + // It wasn't any of the three other attacks, + // but the player took damage, so we assume + // it's a melee attack + onGorillaAttack(gorilla, DemonicGorilla.AttackStyle.MELEE); + } + } + } + + // The next attack tick is always delayed if the + // gorilla switched prayer + gorilla.setNextAttackTick(tickCounter + DemonicGorilla.ATTACK_RATE); + gorilla.setChangedPrayerThisTick(true); + } + } + } + + if (gorilla.getDisabledMeleeMovementForTicks() > 0) + { + gorilla.setDisabledMeleeMovementForTicks(gorilla.getDisabledMeleeMovementForTicks() - 1); + } + else if (gorilla.isInitiatedCombat() && + gorilla.getNpc().getInteracting() != null && + !gorilla.isChangedAttackStyleThisTick() && + gorilla.getNextPosibleAttackStyles().size() >= 2 && + gorilla.getNextPosibleAttackStyles().stream() + .anyMatch(x -> x == DemonicGorilla.AttackStyle.MELEE)) + { + // If melee is a possibility, we can check if the gorilla + // is or isn't moving toward the player to determine if + // it is actually attempting to melee or not. + // We only run this check if the gorilla is in combat + // because otherwise it attempts to travel to melee + // distance before attacking its target. + + if (mp != null && mp.getLastWorldArea() != null && gorilla.getLastWorldArea() != null) + { + WorldArea predictedNewArea = gorilla.getLastWorldArea().calculateNextTravellingPoint( + client, mp.getLastWorldArea(), true, x -> + { + // Gorillas can't normally walk through other gorillas + // or other players + final WorldArea area1 = new WorldArea(x, 1, 1); + return area1 != null && + gorillas.values().stream().noneMatch(y -> + { + if (y == gorilla) + { + return false; + } + final WorldArea area2 = + y.getNpc().getIndex() < gorilla.getNpc().getIndex() ? + y.getNpc().getWorldArea() : y.getLastWorldArea(); + return area2 != null && area1.intersectsWith(area2); + }) && + memorizedPlayers.values().stream().noneMatch(y -> + { + final WorldArea area2 = y.getLastWorldArea(); + return area2 != null && area1.intersectsWith(area2); + }); + + // There is a special case where if a player walked through + // a gorilla, or a player walked through another player, + // the tiles that were walked through becomes + // walkable, but I didn't feel like it's necessary to handle + // that special case as it should rarely happen. + }); + if (predictedNewArea != null) + { + int distance = gorilla.getNpc().getWorldArea().distanceTo(mp.getLastWorldArea()); + WorldPoint predictedMovement = predictedNewArea.toWorldPoint(); + if (distance <= DemonicGorilla.MAX_ATTACK_RANGE && + mp != null && + mp.getLastWorldArea().hasLineOfSightTo(client, gorilla.getLastWorldArea())) + { + if (predictedMovement.distanceTo(gorilla.getLastWorldArea().toWorldPoint()) != 0) + { + if (predictedMovement.distanceTo(gorilla.getNpc().getWorldLocation()) == 0) + { + gorilla.setNextPosibleAttackStyles(gorilla + .getNextPosibleAttackStyles() + .stream() + .filter(x -> x == DemonicGorilla.AttackStyle.MELEE) + .collect(Collectors.toList())); + } + else + { + gorilla.setNextPosibleAttackStyles(gorilla + .getNextPosibleAttackStyles() + .stream() + .filter(x -> x != DemonicGorilla.AttackStyle.MELEE) + .collect(Collectors.toList())); + } + } + else if (tickCounter >= gorilla.getNextAttackTick() && + gorilla.getRecentProjectileId() == -1 && + recentBoulders.stream().noneMatch(x -> x.distanceTo(mp.getLastWorldArea()) == 0)) + { + gorilla.setNextPosibleAttackStyles(gorilla + .getNextPosibleAttackStyles() + .stream() + .filter(x -> x == DemonicGorilla.AttackStyle.MELEE) + .collect(Collectors.toList())); + } + } + } + } + } + + if (gorilla.isTakenDamageRecently()) + { + gorilla.setInitiatedCombat(true); + } + + if (gorilla.getOverheadIcon() != gorilla.getLastTickOverheadIcon()) + { + if (gorilla.isChangedAttackStyleLastTick() || + gorilla.isChangedAttackStyleThisTick()) + { + // Apparently if it changes attack style and changes + // prayer on the same tick or 1 tick apart, it won't + // be able to move for the next 2 ticks if it attempts + // to melee + gorilla.setDisabledMeleeMovementForTicks(2); + } + else + { + // If it didn't change attack style lately, + // it's only for the next 1 tick + gorilla.setDisabledMeleeMovementForTicks(1); + } + } + gorilla.setLastTickAnimation(gorilla.getNpc().getAnimation()); + gorilla.setLastWorldArea(gorilla.getNpc().getWorldArea()); + gorilla.setLastTickInteracting(gorilla.getNpc().getInteracting()); + gorilla.setTakenDamageRecently(false); + gorilla.setChangedPrayerThisTick(false); + gorilla.setChangedAttackStyleLastTick(gorilla.isChangedAttackStyleThisTick()); + gorilla.setChangedAttackStyleThisTick(false); + gorilla.setLastTickOverheadIcon(gorilla.getOverheadIcon()); + gorilla.setRecentProjectileId(-1); + } + } + + @Subscribe + public void onProjectileMoved(ProjectileMoved event) + { + Projectile projectile = event.getProjectile(); + int projectileId = projectile.getId(); + if (projectileId != ProjectileID.DEMONIC_GORILLA_RANGED && + projectileId != ProjectileID.DEMONIC_GORILLA_MAGIC && + projectileId != ProjectileID.DEMONIC_GORILLA_BOULDER) + { + return; + } + + // The event fires once before the projectile starts moving, + // and we only want to check each projectile once + if (client.getGameCycle() >= projectile.getStartMovementCycle()) + { + return; + } + + if (projectileId == ProjectileID.DEMONIC_GORILLA_BOULDER) + { + recentBoulders.add(WorldPoint.fromLocal(client, event.getPosition())); + } + else if (projectileId == ProjectileID.DEMONIC_GORILLA_MAGIC || + projectileId == ProjectileID.DEMONIC_GORILLA_RANGED) + { + WorldPoint projectileSourcePosition = WorldPoint.fromLocal( + client, projectile.getX1(), projectile.getY1(), client.getPlane()); + for (DemonicGorilla gorilla : gorillas.values()) + { + if (gorilla.getNpc().getWorldLocation().distanceTo(projectileSourcePosition) == 0) + { + gorilla.setRecentProjectileId(projectile.getId()); + } + } + } + } + + private void checkPendingAttacks() + { + Iterator it = pendingAttacks.iterator(); + int tickCounter = client.getTickCount(); + while (it.hasNext()) + { + PendingGorillaAttack attack = it.next(); + if (tickCounter >= attack.getFinishesOnTick()) + { + boolean shouldDecreaseCounter = false; + DemonicGorilla gorilla = attack.getAttacker(); + MemorizedPlayer target = memorizedPlayers.get(attack.getTarget()); + if (target == null) + { + // Player went out of memory, so assume the hit was a 0 + shouldDecreaseCounter = true; + } + else if (target.getRecentHitsplats().isEmpty()) + { + // No hitsplats was applied. This may happen in some cases + // where the player was out of memory while the + // projectile was travelling. So we assume the hit was a 0. + shouldDecreaseCounter = true; + } + else if (target.getRecentHitsplats().stream() + .anyMatch(x -> x.getHitsplatType() == Hitsplat.HitsplatType.BLOCK)) + { + // A blue hitsplat appeared, so we assume the gorilla hit a 0 + shouldDecreaseCounter = true; + } + + if (shouldDecreaseCounter) + { + gorilla.setAttacksUntilSwitch(gorilla.getAttacksUntilSwitch() - 1); + checkGorillaAttackStyleSwitch(gorilla); + } + + it.remove(); + } + } + } + + private void updatePlayers() + { + for (MemorizedPlayer mp : memorizedPlayers.values()) + { + mp.setLastWorldArea(mp.getPlayer().getWorldArea()); + mp.getRecentHitsplats().clear(); + } + } + + @Subscribe + public void onHitsplatApplied(HitsplatApplied event) + { + if (gorillas.isEmpty()) + { + return; + } + + if (event.getActor() instanceof Player) + { + Player player = (Player) event.getActor(); + MemorizedPlayer mp = memorizedPlayers.get(player); + if (mp != null) + { + mp.getRecentHitsplats().add(event.getHitsplat()); + } + } + else if (event.getActor() instanceof NPC) + { + DemonicGorilla gorilla = gorillas.get(event.getActor()); + Hitsplat.HitsplatType hitsplatType = event.getHitsplat().getHitsplatType(); + if (gorilla != null && (hitsplatType == Hitsplat.HitsplatType.BLOCK || + hitsplatType == Hitsplat.HitsplatType.DAMAGE)) + { + gorilla.setTakenDamageRecently(true); + } + } + } + + @Subscribe + public void onGameStateChanged(GameStateChanged event) + { + GameState gs = event.getGameState(); + if (gs == GameState.LOGGING_IN || + gs == GameState.CONNECTION_LOST || + gs == GameState.HOPPING) + { + reset(); + } + } + + @Subscribe + public void onPlayerSpawned(PlayerSpawned event) + { + if (gorillas.isEmpty()) + { + return; + } + + Player player = event.getPlayer(); + memorizedPlayers.put(player, new MemorizedPlayer(player)); + } + + @Subscribe + public void onPlayerDespawned(PlayerDespawned event) + { + if (gorillas.isEmpty()) + { + return; + } + + memorizedPlayers.remove(event.getPlayer()); + } + + @Subscribe + public void onNpcSpawned(NpcSpawned event) + { + NPC npc = event.getNpc(); + if (isNpcGorilla(npc.getId())) + { + if (gorillas.isEmpty()) + { + // Players are not kept track of when there are no gorillas in + // memory, so we need to add the players that were already in memory. + resetPlayers(); + } + + gorillas.put(npc, new DemonicGorilla(npc)); + } + } + + @Subscribe + public void onNpcDespawned(NpcDespawned event) + { + if (gorillas.remove(event.getNpc()) != null && gorillas.isEmpty()) + { + clear(); + } + } + + @Subscribe + public void onGameTick(GameTick event) + { + checkGorillaAttacks(); + checkPendingAttacks(); + updatePlayers(); + recentBoulders.clear(); + } } \ No newline at end of file diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/devtools/CameraOverlay.java b/runelite-client/src/main/java/net/runelite/client/plugins/devtools/CameraOverlay.java index 882fe4201c..7a23ae3003 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/devtools/CameraOverlay.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/devtools/CameraOverlay.java @@ -1,98 +1,98 @@ -/* - * Copyright (c) 2018, Matthew Steglinski - * 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.devtools; - -import java.awt.Dimension; -import java.awt.Graphics2D; -import javax.inject.Inject; -import net.runelite.api.Client; -import net.runelite.client.ui.overlay.Overlay; -import net.runelite.client.ui.overlay.OverlayPosition; -import net.runelite.client.ui.overlay.components.LineComponent; -import net.runelite.client.ui.overlay.components.PanelComponent; -import net.runelite.client.ui.overlay.components.TitleComponent; - -public class CameraOverlay extends Overlay -{ - private final Client client; - private final DevToolsPlugin plugin; - private final PanelComponent panelComponent = new PanelComponent(); - - @Inject - CameraOverlay(Client client, DevToolsPlugin plugin) - { - this.client = client; - this.plugin = plugin; - panelComponent.setPreferredSize(new Dimension(150, 0)); - setPosition(OverlayPosition.TOP_LEFT); - } - - @Override - public Dimension render(Graphics2D graphics) - { - if (!plugin.getCameraPosition().isActive()) - { - return null; - } - - panelComponent.getChildren().clear(); - - panelComponent.getChildren().add(TitleComponent.builder() - .text("Camera") - .build()); - - panelComponent.getChildren().add(LineComponent.builder() - .left("X") - .right("" + client.getCameraX()) - .build()); - - panelComponent.getChildren().add(LineComponent.builder() - .left("Y") - .right("" + client.getCameraY()) - .build()); - - panelComponent.getChildren().add(LineComponent.builder() - .left("Z") - .right("" + client.getCameraZ()) - .build()); - - panelComponent.getChildren().add(LineComponent.builder() - .left("Pitch") - .right("" + client.getCameraPitch()) - .build()); - - panelComponent.getChildren().add(LineComponent.builder() - .left("Yaw") - .right("" + client.getCameraYaw()) - .build()); - - panelComponent.getChildren().add(LineComponent.builder() - .left("Scale") - .right("" + client.getScale()) - .build()); - - return panelComponent.render(graphics); - } -} +/* + * Copyright (c) 2018, Matthew Steglinski + * 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.devtools; + +import java.awt.Dimension; +import java.awt.Graphics2D; +import javax.inject.Inject; +import net.runelite.api.Client; +import net.runelite.client.ui.overlay.Overlay; +import net.runelite.client.ui.overlay.OverlayPosition; +import net.runelite.client.ui.overlay.components.LineComponent; +import net.runelite.client.ui.overlay.components.PanelComponent; +import net.runelite.client.ui.overlay.components.TitleComponent; + +public class CameraOverlay extends Overlay +{ + private final Client client; + private final DevToolsPlugin plugin; + private final PanelComponent panelComponent = new PanelComponent(); + + @Inject + CameraOverlay(Client client, DevToolsPlugin plugin) + { + this.client = client; + this.plugin = plugin; + panelComponent.setPreferredSize(new Dimension(150, 0)); + setPosition(OverlayPosition.TOP_LEFT); + } + + @Override + public Dimension render(Graphics2D graphics) + { + if (!plugin.getCameraPosition().isActive()) + { + return null; + } + + panelComponent.getChildren().clear(); + + panelComponent.getChildren().add(TitleComponent.builder() + .text("Camera") + .build()); + + panelComponent.getChildren().add(LineComponent.builder() + .left("X") + .right("" + client.getCameraX()) + .build()); + + panelComponent.getChildren().add(LineComponent.builder() + .left("Y") + .right("" + client.getCameraY()) + .build()); + + panelComponent.getChildren().add(LineComponent.builder() + .left("Z") + .right("" + client.getCameraZ()) + .build()); + + panelComponent.getChildren().add(LineComponent.builder() + .left("Pitch") + .right("" + client.getCameraPitch()) + .build()); + + panelComponent.getChildren().add(LineComponent.builder() + .left("Yaw") + .right("" + client.getCameraYaw()) + .build()); + + panelComponent.getChildren().add(LineComponent.builder() + .left("Scale") + .right("" + client.getScale()) + .build()); + + return panelComponent.render(graphics); + } +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/devtools/DevToolsPanel.java b/runelite-client/src/main/java/net/runelite/client/plugins/devtools/DevToolsPanel.java index d9a90b79fe..e3c42445cb 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/devtools/DevToolsPanel.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/devtools/DevToolsPanel.java @@ -118,11 +118,11 @@ class DevToolsPanel extends PluginPanel varInspector.open(); } }); - + container.add(plugin.getLogMenuActions()); plugin.getLogMenuActions().addActionListener((ev) -> { - if(plugin.getLogMenuActions().isActive()) + if (plugin.getLogMenuActions().isActive()) { client.setPrintMenuActions(false); } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/devtools/DevToolsPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/devtools/DevToolsPlugin.java index 3b540d414d..4f77b25c26 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/devtools/DevToolsPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/devtools/DevToolsPlugin.java @@ -71,7 +71,7 @@ import org.slf4j.LoggerFactory; public class DevToolsPlugin extends Plugin { private static final List EXAMINE_MENU_ACTIONS = ImmutableList.of(MenuAction.EXAMINE_ITEM, - MenuAction.EXAMINE_ITEM_GROUND, MenuAction.EXAMINE_NPC, MenuAction.EXAMINE_OBJECT); + MenuAction.EXAMINE_ITEM_GROUND, MenuAction.EXAMINE_NPC, MenuAction.EXAMINE_OBJECT); @Inject private Client client; @@ -119,7 +119,7 @@ public class DevToolsPlugin extends Plugin private DevToolsButton validMovement; private DevToolsButton lineOfSight; private DevToolsButton cameraPosition; - private DevToolsButton worldMapLocation ; + private DevToolsButton worldMapLocation; private DevToolsButton tileLocation; private DevToolsButton interacting; private DevToolsButton examine; @@ -174,7 +174,7 @@ public class DevToolsPlugin extends Plugin overlayManager.add(cameraOverlay); overlayManager.add(worldMapLocationOverlay); overlayManager.add(mapRegionOverlay); - + logMenuActions = new DevToolsButton("Menu Actions"); final DevToolsPanel panel = injector.getInstance(DevToolsPanel.class); diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/devtools/LocationOverlay.java b/runelite-client/src/main/java/net/runelite/client/plugins/devtools/LocationOverlay.java index e9f9d2b608..7caa1691fb 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/devtools/LocationOverlay.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/devtools/LocationOverlay.java @@ -1,122 +1,122 @@ -/* - * Copyright (c) 2018, Seth - * 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.devtools; - -import java.awt.Color; -import java.awt.Dimension; -import java.awt.Graphics2D; -import javax.inject.Inject; -import net.runelite.api.Client; -import static net.runelite.api.Constants.CHUNK_SIZE; -import net.runelite.api.coords.LocalPoint; -import net.runelite.api.coords.WorldPoint; -import net.runelite.client.ui.overlay.Overlay; -import net.runelite.client.ui.overlay.OverlayPosition; -import net.runelite.client.ui.overlay.components.LineComponent; -import net.runelite.client.ui.overlay.components.PanelComponent; - -public class LocationOverlay extends Overlay -{ - private final Client client; - private final DevToolsPlugin plugin; - private final PanelComponent panelComponent = new PanelComponent(); - - @Inject - LocationOverlay(Client client, DevToolsPlugin plugin) - { - this.client = client; - this.plugin = plugin; - panelComponent.setPreferredSize(new Dimension(150, 0)); - setPosition(OverlayPosition.TOP_LEFT); - } - - @Override - public Dimension render(Graphics2D graphics) - { - if (!plugin.getLocation().isActive()) - { - return null; - } - - panelComponent.getChildren().clear(); - WorldPoint localWorld = client.getLocalPlayer().getWorldLocation(); - LocalPoint localPoint = client.getLocalPlayer().getLocalLocation(); - - int regionID = localWorld.getRegionID(); - - if (client.isInInstancedRegion()) - { - panelComponent.getChildren().add(LineComponent.builder() - .left("Instance") - .build()); - - int[][][] instanceTemplateChunks = client.getInstanceTemplateChunks(); - int z = client.getPlane(); - int chunkData = instanceTemplateChunks[z][localPoint.getSceneX() / CHUNK_SIZE][localPoint.getSceneY() / CHUNK_SIZE]; - - int rotation = chunkData >> 1 & 0x3; - int chunkY = (chunkData >> 3 & 0x7FF) * CHUNK_SIZE; - int chunkX = (chunkData >> 14 & 0x3FF) * CHUNK_SIZE; - - panelComponent.getChildren().add(LineComponent.builder() - .left("Chunk " + localPoint.getSceneX() / CHUNK_SIZE + "," + localPoint.getSceneY() / CHUNK_SIZE) - .right(rotation + " " + chunkX + " " + chunkY) - .build()); - } - - panelComponent.getChildren().add(LineComponent.builder() - .left("Base") - .right(client.getBaseX() + ", " + client.getBaseY()) - .build()); - - panelComponent.getChildren().add(LineComponent.builder() - .left("Local") - .right(localPoint.getX() + ", " + localPoint.getY()) - .build()); - - panelComponent.getChildren().add(LineComponent.builder() - .left("Scene") - .right(localPoint.getSceneX() + ", " + localPoint.getSceneY()) - .build()); - - panelComponent.getChildren().add(LineComponent.builder() - .left("Tile") - .right(localWorld.getX() + ", " + localWorld.getY() + ", " + client.getPlane()) - .build()); - - for (int i = 0; i < client.getMapRegions().length; i++) - { - int region = client.getMapRegions()[i]; - - panelComponent.getChildren().add(LineComponent.builder() - .left((i == 0) ? "Map regions" : " ") - .right(String.valueOf(region)) - .rightColor((region == regionID) ? Color.GREEN : Color.WHITE) - .build()); - } - - return panelComponent.render(graphics); - } -} +/* + * Copyright (c) 2018, Seth + * 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.devtools; + +import java.awt.Color; +import java.awt.Dimension; +import java.awt.Graphics2D; +import javax.inject.Inject; +import net.runelite.api.Client; +import static net.runelite.api.Constants.CHUNK_SIZE; +import net.runelite.api.coords.LocalPoint; +import net.runelite.api.coords.WorldPoint; +import net.runelite.client.ui.overlay.Overlay; +import net.runelite.client.ui.overlay.OverlayPosition; +import net.runelite.client.ui.overlay.components.LineComponent; +import net.runelite.client.ui.overlay.components.PanelComponent; + +public class LocationOverlay extends Overlay +{ + private final Client client; + private final DevToolsPlugin plugin; + private final PanelComponent panelComponent = new PanelComponent(); + + @Inject + LocationOverlay(Client client, DevToolsPlugin plugin) + { + this.client = client; + this.plugin = plugin; + panelComponent.setPreferredSize(new Dimension(150, 0)); + setPosition(OverlayPosition.TOP_LEFT); + } + + @Override + public Dimension render(Graphics2D graphics) + { + if (!plugin.getLocation().isActive()) + { + return null; + } + + panelComponent.getChildren().clear(); + WorldPoint localWorld = client.getLocalPlayer().getWorldLocation(); + LocalPoint localPoint = client.getLocalPlayer().getLocalLocation(); + + int regionID = localWorld.getRegionID(); + + if (client.isInInstancedRegion()) + { + panelComponent.getChildren().add(LineComponent.builder() + .left("Instance") + .build()); + + int[][][] instanceTemplateChunks = client.getInstanceTemplateChunks(); + int z = client.getPlane(); + int chunkData = instanceTemplateChunks[z][localPoint.getSceneX() / CHUNK_SIZE][localPoint.getSceneY() / CHUNK_SIZE]; + + int rotation = chunkData >> 1 & 0x3; + int chunkY = (chunkData >> 3 & 0x7FF) * CHUNK_SIZE; + int chunkX = (chunkData >> 14 & 0x3FF) * CHUNK_SIZE; + + panelComponent.getChildren().add(LineComponent.builder() + .left("Chunk " + localPoint.getSceneX() / CHUNK_SIZE + "," + localPoint.getSceneY() / CHUNK_SIZE) + .right(rotation + " " + chunkX + " " + chunkY) + .build()); + } + + panelComponent.getChildren().add(LineComponent.builder() + .left("Base") + .right(client.getBaseX() + ", " + client.getBaseY()) + .build()); + + panelComponent.getChildren().add(LineComponent.builder() + .left("Local") + .right(localPoint.getX() + ", " + localPoint.getY()) + .build()); + + panelComponent.getChildren().add(LineComponent.builder() + .left("Scene") + .right(localPoint.getSceneX() + ", " + localPoint.getSceneY()) + .build()); + + panelComponent.getChildren().add(LineComponent.builder() + .left("Tile") + .right(localWorld.getX() + ", " + localWorld.getY() + ", " + client.getPlane()) + .build()); + + for (int i = 0; i < client.getMapRegions().length; i++) + { + int region = client.getMapRegions()[i]; + + panelComponent.getChildren().add(LineComponent.builder() + .left((i == 0) ? "Map regions" : " ") + .right(String.valueOf(region)) + .rightColor((region == regionID) ? Color.GREEN : Color.WHITE) + .build()); + } + + return panelComponent.render(graphics); + } +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/devtools/WorldMapLocationOverlay.java b/runelite-client/src/main/java/net/runelite/client/plugins/devtools/WorldMapLocationOverlay.java index b109ef67ad..2d5542c1bc 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/devtools/WorldMapLocationOverlay.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/devtools/WorldMapLocationOverlay.java @@ -1,106 +1,106 @@ -/* - * Copyright (c) 2018, Morgan Lewis - * 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.devtools; - -import java.awt.Color; -import java.awt.Dimension; -import java.awt.FontMetrics; -import java.awt.Graphics2D; -import java.awt.Rectangle; -import javax.inject.Inject; -import net.runelite.api.Client; -import net.runelite.api.Point; -import net.runelite.api.RenderOverview; -import net.runelite.api.coords.WorldPoint; -import net.runelite.api.widgets.Widget; -import net.runelite.api.widgets.WidgetInfo; -import net.runelite.client.ui.overlay.Overlay; -import net.runelite.client.ui.overlay.OverlayLayer; -import net.runelite.client.ui.overlay.OverlayPosition; -import net.runelite.client.ui.overlay.OverlayPriority; -import net.runelite.client.ui.overlay.worldmap.WorldMapOverlay; - -public class WorldMapLocationOverlay extends Overlay -{ - private final Client client; - private final WorldMapOverlay worldMapOverlay; - private final DevToolsPlugin plugin; - - @Inject - private WorldMapLocationOverlay(Client client, WorldMapOverlay worldMapOverlay, DevToolsPlugin plugin) - { - this.client = client; - this.worldMapOverlay = worldMapOverlay; - this.plugin = plugin; - setPosition(OverlayPosition.DYNAMIC); - setPriority(OverlayPriority.HIGH); - setLayer(OverlayLayer.ABOVE_MAP); - } - - @Override - public Dimension render(Graphics2D graphics) - { - if (!plugin.getWorldMapLocation().isActive()) - { - return null; - } - - RenderOverview ro = client.getRenderOverview(); - Widget worldMapWidget = client.getWidget(WidgetInfo.WORLD_MAP_VIEW); - - if (ro == null || worldMapWidget == null) - { - return null; - } - - Rectangle worldMapRectangle = worldMapWidget.getBounds(); - - graphics.setClip(worldMapRectangle); - graphics.setColor(Color.CYAN); - - WorldPoint mapCenterPoint = new WorldPoint(ro.getWorldMapPosition().getX(), ro.getWorldMapPosition().getY(), 0); - Point middle = worldMapOverlay.mapWorldPointToGraphicsPoint(mapCenterPoint); - - if (middle == null) - { - return null; - } - - graphics.drawLine(middle.getX(), worldMapRectangle.y, middle.getX(), worldMapRectangle.y + worldMapRectangle.height); - graphics.drawLine(worldMapRectangle.x, middle.getY(), worldMapRectangle.x + worldMapRectangle.width, middle.getY()); - - String output = "Center: " + mapCenterPoint.getX() + ", " + mapCenterPoint.getY(); - graphics.setColor(Color.white); - FontMetrics fm = graphics.getFontMetrics(); - int height = fm.getHeight(); - int width = fm.stringWidth(output); - graphics.fillRect((int)worldMapRectangle.getX(), (int)worldMapRectangle.getY() + worldMapRectangle.height - height, (int)worldMapRectangle.getX() + width, (int)worldMapRectangle.getY() + worldMapRectangle.height); - - graphics.setColor(Color.BLACK); - graphics.drawString(output, (int) worldMapRectangle.getX(), (int) worldMapRectangle.getY() + worldMapRectangle.height); - - return null; - } -} +/* + * Copyright (c) 2018, Morgan Lewis + * 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.devtools; + +import java.awt.Color; +import java.awt.Dimension; +import java.awt.FontMetrics; +import java.awt.Graphics2D; +import java.awt.Rectangle; +import javax.inject.Inject; +import net.runelite.api.Client; +import net.runelite.api.Point; +import net.runelite.api.RenderOverview; +import net.runelite.api.coords.WorldPoint; +import net.runelite.api.widgets.Widget; +import net.runelite.api.widgets.WidgetInfo; +import net.runelite.client.ui.overlay.Overlay; +import net.runelite.client.ui.overlay.OverlayLayer; +import net.runelite.client.ui.overlay.OverlayPosition; +import net.runelite.client.ui.overlay.OverlayPriority; +import net.runelite.client.ui.overlay.worldmap.WorldMapOverlay; + +public class WorldMapLocationOverlay extends Overlay +{ + private final Client client; + private final WorldMapOverlay worldMapOverlay; + private final DevToolsPlugin plugin; + + @Inject + private WorldMapLocationOverlay(Client client, WorldMapOverlay worldMapOverlay, DevToolsPlugin plugin) + { + this.client = client; + this.worldMapOverlay = worldMapOverlay; + this.plugin = plugin; + setPosition(OverlayPosition.DYNAMIC); + setPriority(OverlayPriority.HIGH); + setLayer(OverlayLayer.ABOVE_MAP); + } + + @Override + public Dimension render(Graphics2D graphics) + { + if (!plugin.getWorldMapLocation().isActive()) + { + return null; + } + + RenderOverview ro = client.getRenderOverview(); + Widget worldMapWidget = client.getWidget(WidgetInfo.WORLD_MAP_VIEW); + + if (ro == null || worldMapWidget == null) + { + return null; + } + + Rectangle worldMapRectangle = worldMapWidget.getBounds(); + + graphics.setClip(worldMapRectangle); + graphics.setColor(Color.CYAN); + + WorldPoint mapCenterPoint = new WorldPoint(ro.getWorldMapPosition().getX(), ro.getWorldMapPosition().getY(), 0); + Point middle = worldMapOverlay.mapWorldPointToGraphicsPoint(mapCenterPoint); + + if (middle == null) + { + return null; + } + + graphics.drawLine(middle.getX(), worldMapRectangle.y, middle.getX(), worldMapRectangle.y + worldMapRectangle.height); + graphics.drawLine(worldMapRectangle.x, middle.getY(), worldMapRectangle.x + worldMapRectangle.width, middle.getY()); + + String output = "Center: " + mapCenterPoint.getX() + ", " + mapCenterPoint.getY(); + graphics.setColor(Color.white); + FontMetrics fm = graphics.getFontMetrics(); + int height = fm.getHeight(); + int width = fm.stringWidth(output); + graphics.fillRect((int) worldMapRectangle.getX(), (int) worldMapRectangle.getY() + worldMapRectangle.height - height, (int) worldMapRectangle.getX() + width, (int) worldMapRectangle.getY() + worldMapRectangle.height); + + graphics.setColor(Color.BLACK); + graphics.drawString(output, (int) worldMapRectangle.getX(), (int) worldMapRectangle.getY() + worldMapRectangle.height); + + return null; + } +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/discord/DiscordGameEventType.java b/runelite-client/src/main/java/net/runelite/client/plugins/discord/DiscordGameEventType.java index cd05521228..6a6c621f78 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/discord/DiscordGameEventType.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/discord/DiscordGameEventType.java @@ -86,68 +86,68 @@ enum DiscordGameEventType BOSS_ZULRAH("Zulrah", DiscordAreaType.BOSSES, 9007), // Cities - CITY_AL_KHARID("Al Kharid" , DiscordAreaType.CITIES, 13105, 13106), - CITY_APE_ATOLL("Ape Atoll" , DiscordAreaType.CITIES, 10795, 11051, 10974, 11050), - CITY_ARCEUUS_HOUSE("Arceuus" , DiscordAreaType.CITIES, 6459, 6715, 6458, 6714), - CITY_ARDOUGNE("Ardougne" , DiscordAreaType.CITIES, 10548, 10547, 10292, 10291, 10036, 10035, 9780, 9779), - CITY_BARBARIAN_VILLAGE("Barbarian Village" , DiscordAreaType.CITIES, 12341), - CITY_BANDIT_CAMP("Bandit Camp" , DiscordAreaType.CITIES, 12591), - CITY_BEDABIN_CAMP("Bedabin Camp" , DiscordAreaType.CITIES, 12590), - CITY_BRIMHAVEN("Brimhaven" , DiscordAreaType.CITIES, 11057, 11058), - CITY_BURGH_DE_ROTT("Burgh de Rott" , DiscordAreaType.CITIES, 13874, 13873, 14130, 14129), - CITY_BURTHORPE("Burthorpe" , DiscordAreaType.CITIES, 11319, 11575), - CITY_CANIFIS("Canifis" , DiscordAreaType.CITIES, 13878), - CITY_CATHERBY("Catherby" , DiscordAreaType.CITIES, 11317, 11318, 11061), - CITY_CORSAIR_CAVE("Corsair Cove" , DiscordAreaType.CITIES, 10028, 10284), - CITY_DORGESH_KAAN("Dorgesh-Kaan" , DiscordAreaType.CITIES, 10835, 10834), - CITY_DRAYNOR("Draynor" , DiscordAreaType.CITIES, 12338), - CITY_EDGEVILLE("Edgeville" , DiscordAreaType.CITIES, 12342), - CITY_ENTRANA("Entrana" , DiscordAreaType.CITIES, 11060, 11316), - CITY_FALADOR("Falador" , DiscordAreaType.CITIES, 11828, 11572, 11571, 11827, 12084), - CITY_GOBLIN_VILLAGE("Goblin Village" , DiscordAreaType.CITIES, 11830), - CITY_GUTANOTH("Gu'Tanoth" , DiscordAreaType.CITIES, 10031), - CITY_HOSIDIUS_HOUSE("Hosidius" , DiscordAreaType.CITIES, 6713, 6712, 6455, 6711, 6710, 6965, 6966, 7222, 7223, 6967), - CITY_JATISZO("Jatizso" , DiscordAreaType.CITIES, 9531), - CITY_JIGGIG("Jiggig" , DiscordAreaType.CITIES, 9775), - CITY_KARAMJA("Karamja" , DiscordAreaType.CITIES, 11569, 11568, 11567, 11566, 11313, 11312, 11311), - CITY_KELDAGRIM("Keldagrim" , DiscordAreaType.CITIES, 11423, 11422, 11679, 11678), - CITY_LLETYA("Lletya" , DiscordAreaType.CITIES, 9265), - CITY_LOVAKENGJ_HOUSE("Lovakengj" , DiscordAreaType.CITIES, 5692, 5948, 5691, 5947, 6203, 6202, 5690, 5946), - CITY_LUMBRIDGE("Lumbridge" , DiscordAreaType.CITIES, 12850), - CITY_LUNAR_ISLE("Lunar Isle" , DiscordAreaType.CITIES, 8253, 8252, 8509, 8508), - CITY_MEIYERDITCH("Meiyerditch" , DiscordAreaType.CITIES, 14132, 14388, 14387, 14386, 14385), - CITY_MISCELLANIA("Miscellania" , DiscordAreaType.CITIES, 10044, 10300), - CITY_MOS_LE_HARMLESS("Mos Le'Harmless" , DiscordAreaType.CITIES, 14638), - CITY_MORTTON("Mort'ton" , DiscordAreaType.CITIES, 13875), - CITY_MOR_UI_REK("Mor UI Rek" , DiscordAreaType.CITIES, 9808, 9807, 10064, 10063), + CITY_AL_KHARID("Al Kharid", DiscordAreaType.CITIES, 13105, 13106), + CITY_APE_ATOLL("Ape Atoll", DiscordAreaType.CITIES, 10795, 11051, 10974, 11050), + CITY_ARCEUUS_HOUSE("Arceuus", DiscordAreaType.CITIES, 6459, 6715, 6458, 6714), + CITY_ARDOUGNE("Ardougne", DiscordAreaType.CITIES, 10548, 10547, 10292, 10291, 10036, 10035, 9780, 9779), + CITY_BARBARIAN_VILLAGE("Barbarian Village", DiscordAreaType.CITIES, 12341), + CITY_BANDIT_CAMP("Bandit Camp", DiscordAreaType.CITIES, 12591), + CITY_BEDABIN_CAMP("Bedabin Camp", DiscordAreaType.CITIES, 12590), + CITY_BRIMHAVEN("Brimhaven", DiscordAreaType.CITIES, 11057, 11058), + CITY_BURGH_DE_ROTT("Burgh de Rott", DiscordAreaType.CITIES, 13874, 13873, 14130, 14129), + CITY_BURTHORPE("Burthorpe", DiscordAreaType.CITIES, 11319, 11575), + CITY_CANIFIS("Canifis", DiscordAreaType.CITIES, 13878), + CITY_CATHERBY("Catherby", DiscordAreaType.CITIES, 11317, 11318, 11061), + CITY_CORSAIR_CAVE("Corsair Cove", DiscordAreaType.CITIES, 10028, 10284), + CITY_DORGESH_KAAN("Dorgesh-Kaan", DiscordAreaType.CITIES, 10835, 10834), + CITY_DRAYNOR("Draynor", DiscordAreaType.CITIES, 12338), + CITY_EDGEVILLE("Edgeville", DiscordAreaType.CITIES, 12342), + CITY_ENTRANA("Entrana", DiscordAreaType.CITIES, 11060, 11316), + CITY_FALADOR("Falador", DiscordAreaType.CITIES, 11828, 11572, 11571, 11827, 12084), + CITY_GOBLIN_VILLAGE("Goblin Village", DiscordAreaType.CITIES, 11830), + CITY_GUTANOTH("Gu'Tanoth", DiscordAreaType.CITIES, 10031), + CITY_HOSIDIUS_HOUSE("Hosidius", DiscordAreaType.CITIES, 6713, 6712, 6455, 6711, 6710, 6965, 6966, 7222, 7223, 6967), + CITY_JATISZO("Jatizso", DiscordAreaType.CITIES, 9531), + CITY_JIGGIG("Jiggig", DiscordAreaType.CITIES, 9775), + CITY_KARAMJA("Karamja", DiscordAreaType.CITIES, 11569, 11568, 11567, 11566, 11313, 11312, 11311), + CITY_KELDAGRIM("Keldagrim", DiscordAreaType.CITIES, 11423, 11422, 11679, 11678), + CITY_LLETYA("Lletya", DiscordAreaType.CITIES, 9265), + CITY_LOVAKENGJ_HOUSE("Lovakengj", DiscordAreaType.CITIES, 5692, 5948, 5691, 5947, 6203, 6202, 5690, 5946), + CITY_LUMBRIDGE("Lumbridge", DiscordAreaType.CITIES, 12850), + CITY_LUNAR_ISLE("Lunar Isle", DiscordAreaType.CITIES, 8253, 8252, 8509, 8508), + CITY_MEIYERDITCH("Meiyerditch", DiscordAreaType.CITIES, 14132, 14388, 14387, 14386, 14385), + CITY_MISCELLANIA("Miscellania", DiscordAreaType.CITIES, 10044, 10300), + CITY_MOS_LE_HARMLESS("Mos Le'Harmless", DiscordAreaType.CITIES, 14638), + CITY_MORTTON("Mort'ton", DiscordAreaType.CITIES, 13875), + CITY_MOR_UI_REK("Mor UI Rek", DiscordAreaType.CITIES, 9808, 9807, 10064, 10063), CITY_MOUNT_KARUULM("Mount Karuulm", DiscordAreaType.CITIES, 5179, 4923, 5180), - CITY_NARDAH("Nardah" , DiscordAreaType.CITIES, 13613), - CITY_NEITIZNOT("Neitiznot" , DiscordAreaType.CITIES, 9275), - CITY_PISCATORIS("Piscatoris" , DiscordAreaType.CITIES, 9273), - CITY_POLLNIVNEACH("Pollnivneach" , DiscordAreaType.CITIES, 13358), - CITY_PORT_KHAZARD("Port Khazard" , DiscordAreaType.CITIES, 10545), - CITY_PORT_PHASMATYS("Port Phasmatys" , DiscordAreaType.CITIES, 14646), - CITY_PORT_SARIM("Port Sarim" , DiscordAreaType.CITIES, 12082), - CITY_PISCARILIUS_HOUSE("Port Piscarilius" , DiscordAreaType.CITIES, 6971, 7227, 6970, 7226), - CITY_RELLEKKA("Rellekka" , DiscordAreaType.CITIES, 10553), - CITY_RIMMINGTON("Rimmington" , DiscordAreaType.CITIES, 11826, 11570), - CITY_SEERS_VILLAGE("Seers' Village" , DiscordAreaType.CITIES, 10806), - CITY_SHAYZIEN_HOUSE("Shayzien" , DiscordAreaType.CITIES, 5944, 5943, 6200, 6199, 5688), - CITY_SHILO_VILLAGE("Shilo Village" , DiscordAreaType.CITIES, 11310), - CITY_SOPHANEM("Sophanem" , DiscordAreaType.CITIES, 13099), - CITY_TAI_BWO_WANNAI("Tai Bwo Wannai" , DiscordAreaType.CITIES, 11056, 11055), - CITY_TAVERLEY("Taverley" , DiscordAreaType.CITIES, 11574, 11573), - CITY_TREE_GNOME_STRONGHOLD("Tree Gnome Stronghold" , DiscordAreaType.CITIES, 9782, 9781), - CITY_TREE_GNOME_VILLAGE("Tree Gnome Village" , DiscordAreaType.CITIES, 10033), - CITY_TROLL_STRONGHOLD("Troll Stronghold" , DiscordAreaType.CITIES, 11321), - CITY_TYRAS_CAMP("Tyras Camp" , DiscordAreaType.CITIES, 8753, 8752), - CITY_UZER("Uzer" , DiscordAreaType.CITIES, 13872), - CITY_VARROCK("Varrock" , DiscordAreaType.CITIES, 12596, 12597, 12598, 12852, 12853, 12854, 13108, 13109, 13110), - CITY_WITCHHAVEN("Witchaven" , DiscordAreaType.CITIES, 10803), + CITY_NARDAH("Nardah", DiscordAreaType.CITIES, 13613), + CITY_NEITIZNOT("Neitiznot", DiscordAreaType.CITIES, 9275), + CITY_PISCATORIS("Piscatoris", DiscordAreaType.CITIES, 9273), + CITY_POLLNIVNEACH("Pollnivneach", DiscordAreaType.CITIES, 13358), + CITY_PORT_KHAZARD("Port Khazard", DiscordAreaType.CITIES, 10545), + CITY_PORT_PHASMATYS("Port Phasmatys", DiscordAreaType.CITIES, 14646), + CITY_PORT_SARIM("Port Sarim", DiscordAreaType.CITIES, 12082), + CITY_PISCARILIUS_HOUSE("Port Piscarilius", DiscordAreaType.CITIES, 6971, 7227, 6970, 7226), + CITY_RELLEKKA("Rellekka", DiscordAreaType.CITIES, 10553), + CITY_RIMMINGTON("Rimmington", DiscordAreaType.CITIES, 11826, 11570), + CITY_SEERS_VILLAGE("Seers' Village", DiscordAreaType.CITIES, 10806), + CITY_SHAYZIEN_HOUSE("Shayzien", DiscordAreaType.CITIES, 5944, 5943, 6200, 6199, 5688), + CITY_SHILO_VILLAGE("Shilo Village", DiscordAreaType.CITIES, 11310), + CITY_SOPHANEM("Sophanem", DiscordAreaType.CITIES, 13099), + CITY_TAI_BWO_WANNAI("Tai Bwo Wannai", DiscordAreaType.CITIES, 11056, 11055), + CITY_TAVERLEY("Taverley", DiscordAreaType.CITIES, 11574, 11573), + CITY_TREE_GNOME_STRONGHOLD("Tree Gnome Stronghold", DiscordAreaType.CITIES, 9782, 9781), + CITY_TREE_GNOME_VILLAGE("Tree Gnome Village", DiscordAreaType.CITIES, 10033), + CITY_TROLL_STRONGHOLD("Troll Stronghold", DiscordAreaType.CITIES, 11321), + CITY_TYRAS_CAMP("Tyras Camp", DiscordAreaType.CITIES, 8753, 8752), + CITY_UZER("Uzer", DiscordAreaType.CITIES, 13872), + CITY_VARROCK("Varrock", DiscordAreaType.CITIES, 12596, 12597, 12598, 12852, 12853, 12854, 13108, 13109, 13110), + CITY_WITCHHAVEN("Witchaven", DiscordAreaType.CITIES, 10803), CITY_WOODCUTTING_GUILD("Woodcutting Guild", DiscordAreaType.CITIES, 6454, 6198, 6298), - CITY_YANILLE("Yanille" , DiscordAreaType.CITIES, 10288, 10032), - CITY_ZANARIS("Zanaris" , DiscordAreaType.CITIES, 9285, 9541, 9540, 9797), - CITY_ZULANDRA("Zul-Andra" , DiscordAreaType.CITIES, 8751), + CITY_YANILLE("Yanille", DiscordAreaType.CITIES, 10288, 10032), + CITY_ZANARIS("Zanaris", DiscordAreaType.CITIES, 9285, 9541, 9540, 9797), + CITY_ZULANDRA("Zul-Andra", DiscordAreaType.CITIES, 8751), // Dungeons DUNGEON_ABANDONED_MINE("Abandoned Mine", DiscordAreaType.DUNGEONS, 13718, 11079, 11078, 11077, 10823, 10822, 10821), @@ -358,29 +358,52 @@ enum DiscordGameEventType { switch (skill) { - case ATTACK: return TRAINING_ATTACK; - case DEFENCE: return TRAINING_DEFENCE; - case STRENGTH: return TRAINING_STRENGTH; - case RANGED: return TRAINING_RANGED; - case PRAYER: return TRAINING_PRAYER; - case MAGIC: return TRAINING_MAGIC; - case COOKING: return TRAINING_COOKING; - case WOODCUTTING: return TRAINING_WOODCUTTING; - case FLETCHING: return TRAINING_FLETCHING; - case FISHING: return TRAINING_FISHING; - case FIREMAKING: return TRAINING_FIREMAKING; - case CRAFTING: return TRAINING_CRAFTING; - case SMITHING: return TRAINING_SMITHING; - case MINING: return TRAINING_MINING; - case HERBLORE: return TRAINING_HERBLORE; - case AGILITY: return TRAINING_AGILITY; - case THIEVING: return TRAINING_THIEVING; - case SLAYER: return TRAINING_SLAYER; - case FARMING: return TRAINING_FARMING; - case RUNECRAFT: return TRAINING_RUNECRAFT; - case HUNTER: return TRAINING_HUNTER; - case CONSTRUCTION: return TRAINING_CONSTRUCTION; - default: return null; + case ATTACK: + return TRAINING_ATTACK; + case DEFENCE: + return TRAINING_DEFENCE; + case STRENGTH: + return TRAINING_STRENGTH; + case RANGED: + return TRAINING_RANGED; + case PRAYER: + return TRAINING_PRAYER; + case MAGIC: + return TRAINING_MAGIC; + case COOKING: + return TRAINING_COOKING; + case WOODCUTTING: + return TRAINING_WOODCUTTING; + case FLETCHING: + return TRAINING_FLETCHING; + case FISHING: + return TRAINING_FISHING; + case FIREMAKING: + return TRAINING_FIREMAKING; + case CRAFTING: + return TRAINING_CRAFTING; + case SMITHING: + return TRAINING_SMITHING; + case MINING: + return TRAINING_MINING; + case HERBLORE: + return TRAINING_HERBLORE; + case AGILITY: + return TRAINING_AGILITY; + case THIEVING: + return TRAINING_THIEVING; + case SLAYER: + return TRAINING_SLAYER; + case FARMING: + return TRAINING_FARMING; + case RUNECRAFT: + return TRAINING_RUNECRAFT; + case HUNTER: + return TRAINING_HUNTER; + case CONSTRUCTION: + return TRAINING_CONSTRUCTION; + default: + return null; } } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/discord/DiscordPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/discord/DiscordPlugin.java index b14bd00dce..6ad277721e 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/discord/DiscordPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/discord/DiscordPlugin.java @@ -417,10 +417,14 @@ public class DiscordPlugin extends Plugin switch (event.getDiscordAreaType()) { - case BOSSES: return config.showBossActivity(); - case CITIES: return config.showCityActivity(); - case DUNGEONS: return config.showDungeonActivity(); - case MINIGAMES: return config.showMinigameActivity(); + case BOSSES: + return config.showBossActivity(); + case CITIES: + return config.showCityActivity(); + case DUNGEONS: + return config.showDungeonActivity(); + case MINIGAMES: + return config.showMinigameActivity(); } return false; diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/easyscape/DuelingRingMode.java b/runelite-client/src/main/java/net/runelite/client/plugins/easyscape/DuelingRingMode.java index 56b18591d9..1cb3651b5b 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/easyscape/DuelingRingMode.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/easyscape/DuelingRingMode.java @@ -1,42 +1,45 @@ -/* - * Copyright (c) 2018, https://runelitepl.us - * 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.easyscape; - -public enum DuelingRingMode { - DUEL_ARENA("Duel Arena"), - CASTLE_WARS("Castle Wars"), - CLAN_WARS("Clan Wars"); - - private final String name; - - DuelingRingMode(String name) { - this.name = name; - } - - @Override - public String toString() { - return name; - } -} +/* + * Copyright (c) 2018, https://runelitepl.us + * 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.easyscape; + +public enum DuelingRingMode +{ + DUEL_ARENA("Duel Arena"), + CASTLE_WARS("Castle Wars"), + CLAN_WARS("Clan Wars"); + + private final String name; + + DuelingRingMode(String name) + { + this.name = name; + } + + @Override + public String toString() + { + return name; + } +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/easyscape/EasyscapePlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/easyscape/EasyscapePlugin.java index ef4741434f..6ad12ca97a 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/easyscape/EasyscapePlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/easyscape/EasyscapePlugin.java @@ -25,10 +25,13 @@ package net.runelite.client.plugins.easyscape; import com.google.inject.Provides; +import javax.inject.Inject; import lombok.extern.slf4j.Slf4j; import net.runelite.api.Client; import net.runelite.api.GameState; import net.runelite.api.MenuAction; +import static net.runelite.api.MenuAction.MENU_ACTION_DEPRIORITIZE_OFFSET; +import static net.runelite.api.MenuAction.WALK; import net.runelite.api.MenuEntry; import net.runelite.api.Player; import net.runelite.api.coords.WorldPoint; @@ -43,322 +46,390 @@ import net.runelite.client.plugins.PluginType; import static net.runelite.client.util.MenuUtil.swap; import net.runelite.client.util.Text; import org.apache.commons.lang3.ArrayUtils; -import javax.inject.Inject; -import static net.runelite.api.MenuAction.MENU_ACTION_DEPRIORITIZE_OFFSET; -import static net.runelite.api.MenuAction.WALK; @PluginDescriptor( - name = "Easyscape", - description = "Easyscape.", - tags = {"Easyscape"}, - enabledByDefault = false, - type = PluginType.UTILITY + name = "Easyscape", + description = "Easyscape.", + tags = {"Easyscape"}, + enabledByDefault = false, + type = PluginType.UTILITY ) @Slf4j -public class EasyscapePlugin extends Plugin { +public class EasyscapePlugin extends Plugin +{ - private static final int PURO_PURO_REGION_ID = 10307; - private static final int HOUSE_REGION_ID = 7513; + private static final int PURO_PURO_REGION_ID = 10307; + private static final int HOUSE_REGION_ID = 7513; - private MenuEntry[] entries; + private MenuEntry[] entries; - @Inject - private Client client; + @Inject + private Client client; - @Inject - private EasyscapePluginConfig config; + @Inject + private EasyscapePluginConfig config; - @Provides - EasyscapePluginConfig provideConfig(ConfigManager configManager) { - return configManager.getConfig(EasyscapePluginConfig.class); - } + @Provides + EasyscapePluginConfig provideConfig(ConfigManager configManager) + { + return configManager.getConfig(EasyscapePluginConfig.class); + } - @Override - public void startUp() { - log.debug("Easyscape Started."); - } + @Override + public void startUp() + { + log.debug("Easyscape Started."); + } - @Override - public void shutDown() { - log.debug("Easyscape Stopped."); - } + @Override + public void shutDown() + { + log.debug("Easyscape Stopped."); + } - @Subscribe - public void onMenuEntryAdded(MenuEntryAdded event) { + @Subscribe + public void onMenuEntryAdded(MenuEntryAdded event) + { - if (client.getGameState() != GameState.LOGGED_IN) { - return; - } + if (client.getGameState() != GameState.LOGGED_IN) + { + return; + } - Widget loginScreenOne = client.getWidget(WidgetInfo.LOGIN_CLICK_TO_PLAY_SCREEN); - Widget loginScreenTwo = client.getWidget(WidgetInfo.LOGIN_CLICK_TO_PLAY_SCREEN_MESSAGE_OF_THE_DAY); + Widget loginScreenOne = client.getWidget(WidgetInfo.LOGIN_CLICK_TO_PLAY_SCREEN); + Widget loginScreenTwo = client.getWidget(WidgetInfo.LOGIN_CLICK_TO_PLAY_SCREEN_MESSAGE_OF_THE_DAY); - if (loginScreenOne != null || loginScreenTwo != null) { - return; - } + if (loginScreenOne != null || loginScreenTwo != null) + { + return; + } - final String option = Text.removeTags(event.getOption()).toLowerCase(); - final String target = Text.removeTags(event.getTarget()).toLowerCase(); + final String option = Text.removeTags(event.getOption()).toLowerCase(); + final String target = Text.removeTags(event.getTarget()).toLowerCase(); - entries = client.getMenuEntries(); + entries = client.getMenuEntries(); - if (config.getRemoveExamine()) { - for (int i = entries.length - 1; i >= 0; i--) { - if (entries[i].getOption().equals("Examine")) { - entries = ArrayUtils.remove(entries, i); - i--; - } - } - client.setMenuEntries(entries); - } + if (config.getRemoveExamine()) + { + for (int i = entries.length - 1; i >= 0; i--) + { + if (entries[i].getOption().equals("Examine")) + { + entries = ArrayUtils.remove(entries, i); + i--; + } + } + client.setMenuEntries(entries); + } - if (config.getRemoveObjects() && !config.getRemovedObjects().equals("")) { - for (String removed : config.getRemovedObjects().split(",")) { - removed = removed.trim(); - if (target.contains("->")) { - String trimmed = target.split("->")[1].trim(); - if (trimmed.length() >= removed.length() && trimmed.substring(0, removed.length()).equalsIgnoreCase(removed)) { - delete(event.getIdentifier()); - break; - } - } - if (target.length() >= removed.length() && target.substring(0, removed.length()).equalsIgnoreCase(removed)) { - delete(event.getIdentifier()); - break; - } - } - } + if (config.getRemoveObjects() && !config.getRemovedObjects().equals("")) + { + for (String removed : config.getRemovedObjects().split(",")) + { + removed = removed.trim(); + if (target.contains("->")) + { + String trimmed = target.split("->")[1].trim(); + if (trimmed.length() >= removed.length() && trimmed.substring(0, removed.length()).equalsIgnoreCase(removed)) + { + delete(event.getIdentifier()); + break; + } + } + if (target.length() >= removed.length() && target.substring(0, removed.length()).equalsIgnoreCase(removed)) + { + delete(event.getIdentifier()); + break; + } + } + } - if (config.getSwapPuro() && isPuroPuro()) { - if (event.getType() == WALK.getId()) { - MenuEntry menuEntry = entries[entries.length - 1]; - menuEntry.setType(MenuAction.WALK.getId() + MENU_ACTION_DEPRIORITIZE_OFFSET); - client.setMenuEntries(entries); - } - else if (option.equalsIgnoreCase("examine")) { - swap(client, "push-through", option, target); - } - else if (option.equalsIgnoreCase("use")) { - swap(client, "escape", option, target); - } - } + if (config.getSwapPuro() && isPuroPuro()) + { + if (event.getType() == WALK.getId()) + { + MenuEntry menuEntry = entries[entries.length - 1]; + menuEntry.setType(MenuAction.WALK.getId() + MENU_ACTION_DEPRIORITIZE_OFFSET); + client.setMenuEntries(entries); + } + else if (option.equalsIgnoreCase("examine")) + { + swap(client, "push-through", option, target); + } + else if (option.equalsIgnoreCase("use")) + { + swap(client, "escape", option, target); + } + } - if (config.getEasyConstruction() && !config.getConstructionItems().equals("")) { - if (event.getType() == WALK.getId()) { - MenuEntry menuEntry = entries[entries.length - 1]; - menuEntry.setType(MenuAction.WALK.getId() + MENU_ACTION_DEPRIORITIZE_OFFSET); - client.setMenuEntries(entries); - } + if (config.getEasyConstruction() && !config.getConstructionItems().equals("")) + { + if (event.getType() == WALK.getId()) + { + MenuEntry menuEntry = entries[entries.length - 1]; + menuEntry.setType(MenuAction.WALK.getId() + MENU_ACTION_DEPRIORITIZE_OFFSET); + client.setMenuEntries(entries); + } - swap(client, "Build", option, target); + swap(client, "Build", option, target); - for (int i = entries.length - 1; i >= 0; i--) { - for (String item : config.getConstructionItems().split(",")) { - if (item.trim().equalsIgnoreCase(Text.removeTags(entries[i].getTarget()))) { - if (!entries[i].getOption().equalsIgnoreCase("remove")) { - entries = ArrayUtils.remove(entries, i); - i--; - } - } - } - } + for (int i = entries.length - 1; i >= 0; i--) + { + for (String item : config.getConstructionItems().split(",")) + { + if (item.trim().equalsIgnoreCase(Text.removeTags(entries[i].getTarget()))) + { + if (!entries[i].getOption().equalsIgnoreCase("remove")) + { + entries = ArrayUtils.remove(entries, i); + i--; + } + } + } + } - client.setMenuEntries(entries); - } + client.setMenuEntries(entries); + } - if (config.getSwapShop() && !config.getSwappedItems().equals("")) { - for (String item : config.getSwappedItems().split(",")) { - if (target.equalsIgnoreCase(item.trim())) { - swap(client, "Buy 50", option, target); - } - } - } + if (config.getSwapShop() && !config.getSwappedItems().equals("")) + { + for (String item : config.getSwappedItems().split(",")) + { + if (target.equalsIgnoreCase(item.trim())) + { + swap(client, "Buy 50", option, target); + } + } + } - if (config.getSwapSmithing()) { - if (option.equalsIgnoreCase("Smith 1")) { - swap(client, "Smith All", option, target); - } else if (option.equalsIgnoreCase("Smith 1 Set")) { - swap(client, "Smith All Sets", option, target); - } - } + if (config.getSwapSmithing()) + { + if (option.equalsIgnoreCase("Smith 1")) + { + swap(client, "Smith All", option, target); + } + else if (option.equalsIgnoreCase("Smith 1 Set")) + { + swap(client, "Smith All Sets", option, target); + } + } - if (config.getSwapTanning() && option.equalsIgnoreCase("Tan 1")) { - swap(client, "Tan All", option, target); - } + if (config.getSwapTanning() && option.equalsIgnoreCase("Tan 1")) + { + swap(client, "Tan All", option, target); + } - if (config.getSwapCrafting() && option.equalsIgnoreCase("Make-1")) { - swap(client, "Make-All", option, target); - } + if (config.getSwapCrafting() && option.equalsIgnoreCase("Make-1")) + { + swap(client, "Make-All", option, target); + } - if (config.getSwapSawmill() && target.equalsIgnoreCase("Sawmill operator")) { - swap(client, "Buy-plank", option, target); - } + if (config.getSwapSawmill() && target.equalsIgnoreCase("Sawmill operator")) + { + swap(client, "Buy-plank", option, target); + } - if (config.getSwapSawmillPlanks() && option.equalsIgnoreCase("Buy 1")) { - swap(client, "Buy All", option, target); - } + if (config.getSwapSawmillPlanks() && option.equalsIgnoreCase("Buy 1")) + { + swap(client, "Buy All", option, target); + } - if (config.getSwapStairs() && option.equalsIgnoreCase("Climb Stairs")) { - swap(client, "Climb Up Stairs", option, target); - } + if (config.getSwapStairs() && option.equalsIgnoreCase("Climb Stairs")) + { + swap(client, "Climb Up Stairs", option, target); + } - if (option.equalsIgnoreCase("Clear-All") && target.equalsIgnoreCase("Bank Filler")) { - swap(client, "Clear", option, target); - } + if (option.equalsIgnoreCase("Clear-All") && target.equalsIgnoreCase("Bank Filler")) + { + swap(client, "Clear", option, target); + } - if (target.toLowerCase().contains("ardougne cloak") && config.getSwapArdougneCape()) { - swap(client, "Kandarin Monastery", option, target); - swap(client, "Monastery Teleport", option, target); - } + if (target.toLowerCase().contains("ardougne cloak") && config.getSwapArdougneCape()) + { + swap(client, "Kandarin Monastery", option, target); + swap(client, "Monastery Teleport", option, target); + } - if (config.getSwapEssencePouch()) { - if (isEssencePouch(target)) { - Widget widgetBankTitleBar = client.getWidget(WidgetInfo.BANK_TITLE_BAR); - switch (config.getEssenceMode()) { - case RUNECRAFTING: - if (widgetBankTitleBar == null || widgetBankTitleBar.isHidden()) { - swap(client, "Empty", option, target); - } else { - swap(client, "Fill", option, target); - } - break; - case ESSENCE_MINING: - if (widgetBankTitleBar == null || widgetBankTitleBar.isHidden()) { - swap(client, "Fill", option, target); - } else { - swap(client, "Empty", option, target); - } - break; - default: - break; - } - } - } + if (config.getSwapEssencePouch()) + { + if (isEssencePouch(target)) + { + Widget widgetBankTitleBar = client.getWidget(WidgetInfo.BANK_TITLE_BAR); + switch (config.getEssenceMode()) + { + case RUNECRAFTING: + if (widgetBankTitleBar == null || widgetBankTitleBar.isHidden()) + { + swap(client, "Empty", option, target); + } + else + { + swap(client, "Fill", option, target); + } + break; + case ESSENCE_MINING: + if (widgetBankTitleBar == null || widgetBankTitleBar.isHidden()) + { + swap(client, "Fill", option, target); + } + else + { + swap(client, "Empty", option, target); + } + break; + default: + break; + } + } + } - if (config.getGamesNecklace()) { - if (target.toLowerCase().contains("games necklace")) { - switch (config.getGamesNecklaceMode()) { - case BURTHORPE: - swap(client, GamesNecklaceMode.BURTHORPE.toString(), option, target); - break; - case BARBARIAN_OUTPOST: - swap(client, GamesNecklaceMode.BARBARIAN_OUTPOST.toString(), option, target); - break; - case CORPOREAL_BEAST: - swap(client, GamesNecklaceMode.CORPOREAL_BEAST.toString(), option, target); - break; - case TEARS_OF_GUTHIX: - swap(client, GamesNecklaceMode.TEARS_OF_GUTHIX.toString(), option, target); - break; - case WINTERTODT: - swap(client, GamesNecklaceMode.WINTERTODT.toString(), option, target); - break; - default: - break; - } - } - } + if (config.getGamesNecklace()) + { + if (target.toLowerCase().contains("games necklace")) + { + switch (config.getGamesNecklaceMode()) + { + case BURTHORPE: + swap(client, GamesNecklaceMode.BURTHORPE.toString(), option, target); + break; + case BARBARIAN_OUTPOST: + swap(client, GamesNecklaceMode.BARBARIAN_OUTPOST.toString(), option, target); + break; + case CORPOREAL_BEAST: + swap(client, GamesNecklaceMode.CORPOREAL_BEAST.toString(), option, target); + break; + case TEARS_OF_GUTHIX: + swap(client, GamesNecklaceMode.TEARS_OF_GUTHIX.toString(), option, target); + break; + case WINTERTODT: + swap(client, GamesNecklaceMode.WINTERTODT.toString(), option, target); + break; + default: + break; + } + } + } - if (config.getDuelingRing()) { - if (target.toLowerCase().contains("ring of dueling")) { - switch (config.getDuelingRingMode()) { - case DUEL_ARENA: - swap(client, DuelingRingMode.DUEL_ARENA.toString(), option, target); - break; - case CASTLE_WARS: - swap(client, DuelingRingMode.CASTLE_WARS.toString(), option, target); - break; - case CLAN_WARS: - swap(client, DuelingRingMode.CLAN_WARS.toString(), option, target); - break; - default: - break; - } - } - } + if (config.getDuelingRing()) + { + if (target.toLowerCase().contains("ring of dueling")) + { + switch (config.getDuelingRingMode()) + { + case DUEL_ARENA: + swap(client, DuelingRingMode.DUEL_ARENA.toString(), option, target); + break; + case CASTLE_WARS: + swap(client, DuelingRingMode.CASTLE_WARS.toString(), option, target); + break; + case CLAN_WARS: + swap(client, DuelingRingMode.CLAN_WARS.toString(), option, target); + break; + default: + break; + } + } + } - if (config.getWealthRing()) { - if (target.toLowerCase().contains("ring of wealth")) { - switch (config.getWealthRingMode()) { - case MISCELLANIA: - swap(client, WealthRingMode.MISCELLANIA.toString(), option, target); - break; - case GRAND_EXCHANGE: - swap(client, WealthRingMode.GRAND_EXCHANGE.toString(), option, target); - break; - case FALADOR: - swap(client, WealthRingMode.FALADOR.toString(), option, target); - break; + if (config.getWealthRing()) + { + if (target.toLowerCase().contains("ring of wealth")) + { + switch (config.getWealthRingMode()) + { + case MISCELLANIA: + swap(client, WealthRingMode.MISCELLANIA.toString(), option, target); + break; + case GRAND_EXCHANGE: + swap(client, WealthRingMode.GRAND_EXCHANGE.toString(), option, target); + break; + case FALADOR: + swap(client, WealthRingMode.FALADOR.toString(), option, target); + break; case DONDAKAN: - swap(client, WealthRingMode.DONDAKAN.toString(), option, target); - break; - default: - break; - } - } - } + swap(client, WealthRingMode.DONDAKAN.toString(), option, target); + break; + default: + break; + } + } + } - if (config.getGlory()) { - if (target.toLowerCase().contains("amulet of glory") || target.toLowerCase().contains("amulet of eternal glory")) { - switch (config.getGloryMode()) { - case EDGEVILLE: - swap(client, GloryMode.EDGEVILLE.toString(), option, target); - break; - case KARAMJA: - swap(client, GloryMode.KARAMJA.toString(), option, target); - break; - case DRAYNOR_VILLAGE: - swap(client, GloryMode.DRAYNOR_VILLAGE.toString(), option, target); - break; - case AL_KHARID: - swap(client, GloryMode.AL_KHARID.toString(), option, target); - break; - default: - break; - } - } - } + if (config.getGlory()) + { + if (target.toLowerCase().contains("amulet of glory") || target.toLowerCase().contains("amulet of eternal glory")) + { + switch (config.getGloryMode()) + { + case EDGEVILLE: + swap(client, GloryMode.EDGEVILLE.toString(), option, target); + break; + case KARAMJA: + swap(client, GloryMode.KARAMJA.toString(), option, target); + break; + case DRAYNOR_VILLAGE: + swap(client, GloryMode.DRAYNOR_VILLAGE.toString(), option, target); + break; + case AL_KHARID: + swap(client, GloryMode.AL_KHARID.toString(), option, target); + break; + default: + break; + } + } + } - if (target.toLowerCase().contains("crafting cape") && config.getSwapCraftingCape()) { - swap(client, "Teleport", option, target); + if (target.toLowerCase().contains("crafting cape") && config.getSwapCraftingCape()) + { + swap(client, "Teleport", option, target); - } + } - if (target.toLowerCase().contains("construct. cape") && config.getSwapConstructionCape()) { - swap(client, "Tele to poh", option, target); + if (target.toLowerCase().contains("construct. cape") && config.getSwapConstructionCape()) + { + swap(client, "Tele to poh", option, target); - } - } + } + } - private void delete(int target) { - for (int i = entries.length - 1; i >= 0; i--) { - if (entries[i].getIdentifier() == target) { - entries = ArrayUtils.remove(entries, i); - i--; - } - } - client.setMenuEntries(entries); - } + private void delete(int target) + { + for (int i = entries.length - 1; i >= 0; i--) + { + if (entries[i].getIdentifier() == target) + { + entries = ArrayUtils.remove(entries, i); + i--; + } + } + client.setMenuEntries(entries); + } - private boolean isEssencePouch(String target) { - return (target.equalsIgnoreCase("Small Pouch") || target.equalsIgnoreCase("Medium Pouch") || target.equalsIgnoreCase("Large Pouch") || target.equalsIgnoreCase("Giant Pouch")); - } + private boolean isEssencePouch(String target) + { + return (target.equalsIgnoreCase("Small Pouch") || target.equalsIgnoreCase("Medium Pouch") || target.equalsIgnoreCase("Large Pouch") || target.equalsIgnoreCase("Giant Pouch")); + } - private boolean isHouse() { - return client.getMapRegions()[0] == HOUSE_REGION_ID; - } + private boolean isHouse() + { + return client.getMapRegions()[0] == HOUSE_REGION_ID; + } - private boolean isPuroPuro() { - Player player = client.getLocalPlayer(); + private boolean isPuroPuro() + { + Player player = client.getLocalPlayer(); - if (player == null) { - return false; - } else { - WorldPoint location = player.getWorldLocation(); - return location.getRegionID() == PURO_PURO_REGION_ID; - } - } + if (player == null) + { + return false; + } + else + { + WorldPoint location = player.getWorldLocation(); + return location.getRegionID() == PURO_PURO_REGION_ID; + } + } } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/easyscape/EasyscapePluginConfig.java b/runelite-client/src/main/java/net/runelite/client/plugins/easyscape/EasyscapePluginConfig.java index 60e73281fd..ac0f61b361 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/easyscape/EasyscapePluginConfig.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/easyscape/EasyscapePluginConfig.java @@ -29,285 +29,313 @@ import net.runelite.client.config.ConfigGroup; import net.runelite.client.config.ConfigItem; @ConfigGroup("easyscape") -public interface EasyscapePluginConfig extends Config { +public interface EasyscapePluginConfig extends Config +{ - @ConfigItem( - keyName = "removeExamine", - name = "Remove Examine", - description = "", - position = 0 - ) - default boolean getRemoveExamine() { - return true; - } + @ConfigItem( + keyName = "removeExamine", + name = "Remove Examine", + description = "", + position = 0 + ) + default boolean getRemoveExamine() + { + return true; + } - @ConfigItem( - keyName = "swapShop", - name = "Easy Shop", - description = "Enables swapping of items in the shop with their buy-50 option.", - position = 1 - ) - default boolean getSwapShop() { - return true; - } + @ConfigItem( + keyName = "swapShop", + name = "Easy Shop", + description = "Enables swapping of items in the shop with their buy-50 option.", + position = 1 + ) + default boolean getSwapShop() + { + return true; + } - @ConfigItem( - keyName = "swappedItems", - name = "Shop Items", - description = "Items listed here will have their value and buy-50 options swapped.", - position = 2 - ) - default String getSwappedItems() { - return ""; - } + @ConfigItem( + keyName = "swappedItems", + name = "Shop Items", + description = "Items listed here will have their value and buy-50 options swapped.", + position = 2 + ) + default String getSwappedItems() + { + return ""; + } - @ConfigItem( - keyName = "easyConstruction", - name = "Easy Construction", - description = "", - position = 3 - ) + @ConfigItem( + keyName = "easyConstruction", + name = "Easy Construction", + description = "", + position = 3 + ) - default boolean getEasyConstruction() { - return true; - } + default boolean getEasyConstruction() + { + return true; + } - @ConfigItem( - keyName = "constructionItems", - name = "Construction Items", - description = "", - position = 4 - ) + @ConfigItem( + keyName = "constructionItems", + name = "Construction Items", + description = "", + position = 4 + ) - default String getConstructionItems() { - return ""; - } + default String getConstructionItems() + { + return ""; + } - @ConfigItem( - keyName = "removeObjects", - name = "Remove Objects", - description = "", - position = 5 - ) - default boolean getRemoveObjects() { - return true; - } + @ConfigItem( + keyName = "removeObjects", + name = "Remove Objects", + description = "", + position = 5 + ) + default boolean getRemoveObjects() + { + return true; + } - @ConfigItem( - keyName = "removedObjects", - name = "Removed Objects", - description = "", - position = 6 - ) - default String getRemovedObjects() { - return ""; - } + @ConfigItem( + keyName = "removedObjects", + name = "Removed Objects", + description = "", + position = 6 + ) + default String getRemovedObjects() + { + return ""; + } - @ConfigItem( - keyName = "swapSmithing", - name = "Swap Smithing", - description = "Enables swapping of smith-1 and smith-all options.", - position = 7 - ) - default boolean getSwapSmithing() { - return true; - } + @ConfigItem( + keyName = "swapSmithing", + name = "Swap Smithing", + description = "Enables swapping of smith-1 and smith-all options.", + position = 7 + ) + default boolean getSwapSmithing() + { + return true; + } - @ConfigItem( - keyName = "swapTanning", - name = "Swap Tanning", - description = "Enables swapping of tan-1 and tan-all options.", - position = 8 - ) - default boolean getSwapTanning() { - return true; - } + @ConfigItem( + keyName = "swapTanning", + name = "Swap Tanning", + description = "Enables swapping of tan-1 and tan-all options.", + position = 8 + ) + default boolean getSwapTanning() + { + return true; + } - @ConfigItem( - keyName = "swapCrafting", - name = "Swap Crafting", - description = "", - position = 9 - ) - default boolean getSwapCrafting() { - return true; - } + @ConfigItem( + keyName = "swapCrafting", + name = "Swap Crafting", + description = "", + position = 9 + ) + default boolean getSwapCrafting() + { + return true; + } - @ConfigItem( - keyName = "swapArdougneCape", - name = "Swap Ardougne Cape", - description = "Enables swapping of teleport and wear.", - position = 10 - ) - default boolean getSwapArdougneCape() { - return true; - } + @ConfigItem( + keyName = "swapArdougneCape", + name = "Swap Ardougne Cape", + description = "Enables swapping of teleport and wear.", + position = 10 + ) + default boolean getSwapArdougneCape() + { + return true; + } - @ConfigItem( - keyName = "swapStairs", - name = "Swap Stairs", - description = "", - position = 11 - ) + @ConfigItem( + keyName = "swapStairs", + name = "Swap Stairs", + description = "", + position = 11 + ) - default boolean getSwapStairs() { - return true; - } + default boolean getSwapStairs() + { + return true; + } - @ConfigItem( - keyName = "swapSawmill", - name = "Swap Sawmill Operator", - description = "", - position = 12 - ) - default boolean getSwapSawmill() { - return true; - } + @ConfigItem( + keyName = "swapSawmill", + name = "Swap Sawmill Operator", + description = "", + position = 12 + ) + default boolean getSwapSawmill() + { + return true; + } - @ConfigItem( - keyName = "swapSawmillPlanks", - name = "Swap Buy Planks", - description = "", - position = 13 - ) + @ConfigItem( + keyName = "swapSawmillPlanks", + name = "Swap Buy Planks", + description = "", + position = 13 + ) - default boolean getSwapSawmillPlanks() { - return true; - } + default boolean getSwapSawmillPlanks() + { + return true; + } - @ConfigItem( - keyName = "swapPuroPuro", - name = "Swap Puro Puro Wheat", - description = "", - position = 14 - ) - default boolean getSwapPuro() { - return true; - } + @ConfigItem( + keyName = "swapPuroPuro", + name = "Swap Puro Puro Wheat", + description = "", + position = 14 + ) + default boolean getSwapPuro() + { + return true; + } - @ConfigItem( - keyName = "swapEssencePounch", - name = "Swap Essence Pouch", - description = "Enables swapping of fill and empty for essence pounch.", - position = 15 - ) - default boolean getSwapEssencePouch() { - return true; - } + @ConfigItem( + keyName = "swapEssencePounch", + name = "Swap Essence Pouch", + description = "Enables swapping of fill and empty for essence pounch.", + position = 15 + ) + default boolean getSwapEssencePouch() + { + return true; + } - @ConfigItem( - keyName = "essenceMode", - name = "Essence Pouch Mode", - description = "Runecrafting or essence mining mode.", - position = 16 - ) + @ConfigItem( + keyName = "essenceMode", + name = "Essence Pouch Mode", + description = "Runecrafting or essence mining mode.", + position = 16 + ) - default EssenceMode getEssenceMode() { - return EssenceMode.RUNECRAFTING; - } + default EssenceMode getEssenceMode() + { + return EssenceMode.RUNECRAFTING; + } - @ConfigItem( - keyName = "swapGamesNecklace", - name = "Swap Games Necklace", - description = "Enables swapping of games necklace.", - position = 17 - ) - default boolean getGamesNecklace() { - return true; - } + @ConfigItem( + keyName = "swapGamesNecklace", + name = "Swap Games Necklace", + description = "Enables swapping of games necklace.", + position = 17 + ) + default boolean getGamesNecklace() + { + return true; + } - @ConfigItem( - keyName = "gamesNecklaceMode", - name = "Games Necklace Mode", - description = "Teleport location mode.", - position = 18 - ) + @ConfigItem( + keyName = "gamesNecklaceMode", + name = "Games Necklace Mode", + description = "Teleport location mode.", + position = 18 + ) - default GamesNecklaceMode getGamesNecklaceMode() { - return GamesNecklaceMode.BURTHORPE; - } + default GamesNecklaceMode getGamesNecklaceMode() + { + return GamesNecklaceMode.BURTHORPE; + } - @ConfigItem( - keyName = "swapDuelingRing", - name = "Swap Dueling Ring", - description = "Enables swapping of dueling ring.", - position = 19 - ) - default boolean getDuelingRing() { - return true; - } + @ConfigItem( + keyName = "swapDuelingRing", + name = "Swap Dueling Ring", + description = "Enables swapping of dueling ring.", + position = 19 + ) + default boolean getDuelingRing() + { + return true; + } - @ConfigItem( - keyName = "duelingRingMode", - name = "Dueling Ring Mode", - description = "Teleport location mode.", - position = 20 - ) + @ConfigItem( + keyName = "duelingRingMode", + name = "Dueling Ring Mode", + description = "Teleport location mode.", + position = 20 + ) - default DuelingRingMode getDuelingRingMode() { - return DuelingRingMode.DUEL_ARENA; - } + default DuelingRingMode getDuelingRingMode() + { + return DuelingRingMode.DUEL_ARENA; + } - @ConfigItem( - keyName = "swapGlory", - name = "Swap Glory", - description = "Enables swapping of Amulet of Glory.", - position = 21 - ) - default boolean getGlory() { - return true; - } + @ConfigItem( + keyName = "swapGlory", + name = "Swap Glory", + description = "Enables swapping of Amulet of Glory.", + position = 21 + ) + default boolean getGlory() + { + return true; + } - @ConfigItem( - keyName = "gloryMode", - name = "Glory Mode", - description = "Teleport location mode.", - position = 22 - ) + @ConfigItem( + keyName = "gloryMode", + name = "Glory Mode", + description = "Teleport location mode.", + position = 22 + ) - default GloryMode getGloryMode() { - return GloryMode.EDGEVILLE; - } + default GloryMode getGloryMode() + { + return GloryMode.EDGEVILLE; + } - @ConfigItem( - keyName = "swapWealthRing", - name = "Swap Ring of Wealth", - description = "Enables swapping of Ring of Wealth.", - position = 23 - ) - default boolean getWealthRing() { - return true; - } + @ConfigItem( + keyName = "swapWealthRing", + name = "Swap Ring of Wealth", + description = "Enables swapping of Ring of Wealth.", + position = 23 + ) + default boolean getWealthRing() + { + return true; + } - @ConfigItem( - keyName = "WealthRingMode", - name = "Wealth Ring Mode", - description = "Teleport location mode.", - position = 24 - ) + @ConfigItem( + keyName = "WealthRingMode", + name = "Wealth Ring Mode", + description = "Teleport location mode.", + position = 24 + ) - default WealthRingMode getWealthRingMode() { - return WealthRingMode.GRAND_EXCHANGE; - } + default WealthRingMode getWealthRingMode() + { + return WealthRingMode.GRAND_EXCHANGE; + } - @ConfigItem( - keyName = "swapConstructionCape", - name = "Swap Construction Cape", - description = "Enables swapping of teleport and wear.", - position = 25 - ) - default boolean getSwapConstructionCape() { - return true; - } + @ConfigItem( + keyName = "swapConstructionCape", + name = "Swap Construction Cape", + description = "Enables swapping of teleport and wear.", + position = 25 + ) + default boolean getSwapConstructionCape() + { + return true; + } - @ConfigItem( - keyName = "swapCraftingCape", - name = "Swap Crafting Cape", - description = "Enables swapping of teleport and wear.", - position = 26 - ) - default boolean getSwapCraftingCape() { - return true; - } + @ConfigItem( + keyName = "swapCraftingCape", + name = "Swap Crafting Cape", + description = "Enables swapping of teleport and wear.", + position = 26 + ) + default boolean getSwapCraftingCape() + { + return true; + } } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/easyscape/EssenceMode.java b/runelite-client/src/main/java/net/runelite/client/plugins/easyscape/EssenceMode.java index e5d21e61fa..fe001dbea4 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/easyscape/EssenceMode.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/easyscape/EssenceMode.java @@ -1,41 +1,44 @@ -/* - * Copyright (c) 2018, https://runelitepl.us - * 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.easyscape; - -public enum EssenceMode { - RUNECRAFTING("Runecrafting"), - ESSENCE_MINING("Essence Mining"); - - private final String name; - - EssenceMode(String name) { - this.name = name; - } - - @Override - public String toString() { - return name; - } -} +/* + * Copyright (c) 2018, https://runelitepl.us + * 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.easyscape; + +public enum EssenceMode +{ + RUNECRAFTING("Runecrafting"), + ESSENCE_MINING("Essence Mining"); + + private final String name; + + EssenceMode(String name) + { + this.name = name; + } + + @Override + public String toString() + { + return name; + } +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/easyscape/GamesNecklaceMode.java b/runelite-client/src/main/java/net/runelite/client/plugins/easyscape/GamesNecklaceMode.java index e4e54c4b90..457fc100bc 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/easyscape/GamesNecklaceMode.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/easyscape/GamesNecklaceMode.java @@ -1,44 +1,47 @@ -/* - * Copyright (c) 2018, https://runelitepl.us - * 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.easyscape; - -public enum GamesNecklaceMode { - BURTHORPE("Burthorpe"), - BARBARIAN_OUTPOST("Barbarian Outpost"), - CORPOREAL_BEAST("Corporeal Beast"), - TEARS_OF_GUTHIX("Tears of Guthix"), - WINTERTODT("Wintertodt Camp"); - - private final String name; - - GamesNecklaceMode(String name) { - this.name = name; - } - - @Override - public String toString() { - return name; - } -} +/* + * Copyright (c) 2018, https://runelitepl.us + * 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.easyscape; + +public enum GamesNecklaceMode +{ + BURTHORPE("Burthorpe"), + BARBARIAN_OUTPOST("Barbarian Outpost"), + CORPOREAL_BEAST("Corporeal Beast"), + TEARS_OF_GUTHIX("Tears of Guthix"), + WINTERTODT("Wintertodt Camp"); + + private final String name; + + GamesNecklaceMode(String name) + { + this.name = name; + } + + @Override + public String toString() + { + return name; + } +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/easyscape/GloryMode.java b/runelite-client/src/main/java/net/runelite/client/plugins/easyscape/GloryMode.java index 4d83526dfc..f160c41c56 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/easyscape/GloryMode.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/easyscape/GloryMode.java @@ -1,43 +1,46 @@ -/* - * Copyright (c) 2018, https://runelitepl.us - * 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.easyscape; - -public enum GloryMode { - EDGEVILLE("Edgeville"), - KARAMJA("Karamja"), - DRAYNOR_VILLAGE("Draynor Village"), - AL_KHARID("Al Kharid"); - - private final String name; - - GloryMode(String name) { - this.name = name; - } - - @Override - public String toString() { - return name; - } -} +/* + * Copyright (c) 2018, https://runelitepl.us + * 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.easyscape; + +public enum GloryMode +{ + EDGEVILLE("Edgeville"), + KARAMJA("Karamja"), + DRAYNOR_VILLAGE("Draynor Village"), + AL_KHARID("Al Kharid"); + + private final String name; + + GloryMode(String name) + { + this.name = name; + } + + @Override + public String toString() + { + return name; + } +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/easyscape/WealthRingMode.java b/runelite-client/src/main/java/net/runelite/client/plugins/easyscape/WealthRingMode.java index f865dd5da9..525aa5ee3c 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/easyscape/WealthRingMode.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/easyscape/WealthRingMode.java @@ -1,43 +1,46 @@ -/* - * Copyright (c) 2018, https://runelitepl.us - * 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.easyscape; - -public enum WealthRingMode { - MISCELLANIA ("Miscellania"), - GRAND_EXCHANGE ("Grand Exchange"), - FALADOR ("Falador"), - DONDAKAN ("Dondakan"); - - private final String name; - - WealthRingMode(String name) { - this.name = name; - } - - @Override - public String toString() { - return name; - } -} +/* + * Copyright (c) 2018, https://runelitepl.us + * 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.easyscape; + +public enum WealthRingMode +{ + MISCELLANIA("Miscellania"), + GRAND_EXCHANGE("Grand Exchange"), + FALADOR("Falador"), + DONDAKAN("Dondakan"); + + private final String name; + + WealthRingMode(String name) + { + this.name = name; + } + + @Override + public String toString() + { + return name; + } +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/equipmentinspector/ItemPanel.java b/runelite-client/src/main/java/net/runelite/client/plugins/equipmentinspector/ItemPanel.java index b9b10d2531..9a4807a981 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/equipmentinspector/ItemPanel.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/equipmentinspector/ItemPanel.java @@ -40,7 +40,7 @@ class ItemPanel extends JPanel ItemPanel(ItemComposition item, KitType kitType, AsyncBufferedImage icon) { - setBorder(new EmptyBorder(3, 3, 3, 3)); + setBorder(new EmptyBorder(3, 3, 3, 3)); setBackground(ColorScheme.DARK_GRAY_COLOR); GroupLayout layout = new GroupLayout(this); @@ -55,20 +55,20 @@ class ItemPanel extends JPanel icon.addTo(imageLabel); layout.setVerticalGroup(layout.createParallelGroup() - .addComponent(imageLabel) - .addGroup(layout.createSequentialGroup() - .addComponent(name) - .addComponent(location) - ) + .addComponent(imageLabel) + .addGroup(layout.createSequentialGroup() + .addComponent(name) + .addComponent(location) + ) ); layout.setHorizontalGroup(layout.createSequentialGroup() - .addComponent(imageLabel) - .addGap(8) - .addGroup(layout.createParallelGroup() - .addComponent(name) - .addComponent(location) - ) + .addComponent(imageLabel) + .addGap(8) + .addGroup(layout.createParallelGroup() + .addComponent(name) + .addComponent(location) + ) ); // AWT's Z order is weird. This put image at the back of the stack diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/examine/CacheKey.java b/runelite-client/src/main/java/net/runelite/client/plugins/examine/CacheKey.java index 135b300979..f38d90d9d2 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/examine/CacheKey.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/examine/CacheKey.java @@ -1,75 +1,71 @@ -/* - * Copyright (c) 2017, Adam - * 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.examine; - -import java.util.Objects; - -class CacheKey -{ - private final ExamineType type; - private final int id; - - public CacheKey(ExamineType type, int id) - { - this.type = type; - this.id = id; - } - - @Override - public int hashCode() - { - int hash = 3; - hash = 23 * hash + Objects.hashCode(this.type); - hash = 23 * hash + this.id; - return hash; - } - - @Override - public boolean equals(Object obj) - { - if (this == obj) - { - return true; - } - if (obj == null) - { - return false; - } - if (getClass() != obj.getClass()) - { - return false; - } - final CacheKey other = (CacheKey) obj; - if (this.id != other.id) - { - return false; - } - if (this.type != other.type) - { - return false; - } - return true; - } -} +/* + * Copyright (c) 2017, Adam + * 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.examine; + +import java.util.Objects; + +class CacheKey +{ + private final ExamineType type; + private final int id; + + public CacheKey(ExamineType type, int id) + { + this.type = type; + this.id = id; + } + + @Override + public int hashCode() + { + int hash = 3; + hash = 23 * hash + Objects.hashCode(this.type); + hash = 23 * hash + this.id; + return hash; + } + + @Override + public boolean equals(Object obj) + { + if (this == obj) + { + return true; + } + if (obj == null) + { + return false; + } + if (getClass() != obj.getClass()) + { + return false; + } + final CacheKey other = (CacheKey) obj; + if (this.id != other.id) + { + return false; + } + return this.type == other.type; + } +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/examine/ExamineType.java b/runelite-client/src/main/java/net/runelite/client/plugins/examine/ExamineType.java index 790d0f1d77..5cda430a50 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/examine/ExamineType.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/examine/ExamineType.java @@ -1,33 +1,33 @@ -/* - * Copyright (c) 2017, Adam - * 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.examine; - -public enum ExamineType -{ - ITEM, - ITEM_BANK_EQ, - NPC, - OBJECT; -} +/* + * Copyright (c) 2017, Adam + * 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.examine; + +public enum ExamineType +{ + ITEM, + ITEM_BANK_EQ, + NPC, + OBJECT +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/experiencedrop/PrayerType.java b/runelite-client/src/main/java/net/runelite/client/plugins/experiencedrop/PrayerType.java index 4e7efb793c..a47f96283c 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/experiencedrop/PrayerType.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/experiencedrop/PrayerType.java @@ -1,32 +1,32 @@ -/* - * Copyright (c) 2018, Adam - * 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.experiencedrop; - -enum PrayerType -{ - MELEE, - RANGE, - MAGIC; -} +/* + * Copyright (c) 2018, Adam + * 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.experiencedrop; + +enum PrayerType +{ + MELEE, + RANGE, + MAGIC +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/experiencedrop/XpDropConfig.java b/runelite-client/src/main/java/net/runelite/client/plugins/experiencedrop/XpDropConfig.java index 0d1beab3e7..fa5aeab690 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/experiencedrop/XpDropConfig.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/experiencedrop/XpDropConfig.java @@ -1,112 +1,112 @@ -/* - * Copyright (c) 2018, Cameron - * 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.experiencedrop; - -import java.awt.Color; -import net.runelite.client.config.Config; -import net.runelite.client.config.ConfigGroup; -import net.runelite.client.config.ConfigItem; - -@ConfigGroup("xpdrop") -public interface XpDropConfig extends Config -{ - @ConfigItem( - keyName = "hideSkillIcons", - name = "Hide skill icons", - description = "Configure if XP drops will show their respective skill icons", - position = 0 - ) - default boolean hideSkillIcons() - { - return false; - } - - @ConfigItem( - keyName = "meleePrayerColor", - name = "Melee Prayer Color", - description = "XP drop color when a melee prayer is active", - position = 1 - ) - default Color getMeleePrayerColor() - { - return new Color(0x15, 0x80, 0xAD); - } - - @ConfigItem( - keyName = "rangePrayerColor", - name = "Range Prayer Color", - description = "XP drop color when a range prayer is active", - position = 2 - ) - default Color getRangePrayerColor() - { - return new Color(0x15, 0x80, 0xAD); - } - - @ConfigItem( - keyName = "magePrayerColor", - name = "Mage Prayer Color", - description = "XP drop color when a mage prayer is active", - position = 3 - ) - default Color getMagePrayerColor() - { - return new Color(0x15, 0x80, 0xAD); - } - - @ConfigItem( - keyName = "fakeXpDropDelay", - name = "Fake Xp Drop delay", - description = "Configures how many ticks should pass between fake XP drops, 0 to disable", - position = 4 - ) - default int fakeXpDropDelay() - { - return 0; - } - - @ConfigItem( - keyName = "showDamage", - name = "Show Damage on XP Drop", - description = "Show what you hit next to the XP drop", - position = 5 - ) - default boolean showDamage() - { - return false; - } - - @ConfigItem( - keyName = "damageColor", - name = "Damage Color", - description = "The color you want the text to be for damage", - position = 6 - ) - default Color getDamageColor() - { - return Color.RED; - } - -} +/* + * Copyright (c) 2018, Cameron + * 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.experiencedrop; + +import java.awt.Color; +import net.runelite.client.config.Config; +import net.runelite.client.config.ConfigGroup; +import net.runelite.client.config.ConfigItem; + +@ConfigGroup("xpdrop") +public interface XpDropConfig extends Config +{ + @ConfigItem( + keyName = "hideSkillIcons", + name = "Hide skill icons", + description = "Configure if XP drops will show their respective skill icons", + position = 0 + ) + default boolean hideSkillIcons() + { + return false; + } + + @ConfigItem( + keyName = "meleePrayerColor", + name = "Melee Prayer Color", + description = "XP drop color when a melee prayer is active", + position = 1 + ) + default Color getMeleePrayerColor() + { + return new Color(0x15, 0x80, 0xAD); + } + + @ConfigItem( + keyName = "rangePrayerColor", + name = "Range Prayer Color", + description = "XP drop color when a range prayer is active", + position = 2 + ) + default Color getRangePrayerColor() + { + return new Color(0x15, 0x80, 0xAD); + } + + @ConfigItem( + keyName = "magePrayerColor", + name = "Mage Prayer Color", + description = "XP drop color when a mage prayer is active", + position = 3 + ) + default Color getMagePrayerColor() + { + return new Color(0x15, 0x80, 0xAD); + } + + @ConfigItem( + keyName = "fakeXpDropDelay", + name = "Fake Xp Drop delay", + description = "Configures how many ticks should pass between fake XP drops, 0 to disable", + position = 4 + ) + default int fakeXpDropDelay() + { + return 0; + } + + @ConfigItem( + keyName = "showDamage", + name = "Show Damage on XP Drop", + description = "Show what you hit next to the XP drop", + position = 5 + ) + default boolean showDamage() + { + return false; + } + + @ConfigItem( + keyName = "damageColor", + name = "Damage Color", + description = "The color you want the text to be for damage", + position = 6 + ) + default Color getDamageColor() + { + return Color.RED; + } + +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/experiencedrop/XpDropOverlay.java b/runelite-client/src/main/java/net/runelite/client/plugins/experiencedrop/XpDropOverlay.java index 119da63597..c3b9bf916b 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/experiencedrop/XpDropOverlay.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/experiencedrop/XpDropOverlay.java @@ -1,73 +1,72 @@ -/* - * Copyright (c) 2017, honeyhoney - * 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.experiencedrop; - -import java.awt.Dimension; -import java.awt.Graphics2D; -import javax.inject.Inject; - -import net.runelite.api.Actor; -import net.runelite.api.Point; -import net.runelite.client.ui.overlay.Overlay; -import net.runelite.client.ui.overlay.OverlayPosition; -import net.runelite.client.ui.overlay.OverlayPriority; -import net.runelite.client.ui.overlay.OverlayUtil; - -class XpDropOverlay extends Overlay -{ - private final XpDropPlugin plugin; - private final XpDropConfig config; - - @Inject - private XpDropOverlay(XpDropPlugin plugin, XpDropConfig config) - { - this.plugin = plugin; - this.config = config; - setPosition(OverlayPosition.DYNAMIC); - setPriority(OverlayPriority.MED); - } - - @Override - public Dimension render(Graphics2D graphics) - { - if (config.showDamage()) - { - final Actor opponent = plugin.getLastOpponent(); - if (opponent != null) - { - int offset = opponent.getLogicalHeight() + 50; - String damageStr = String.valueOf(this.plugin.getDamage()); - Point textLocation = opponent.getCanvasTextLocation(graphics, damageStr, offset); - - if (textLocation != null && this.plugin.getDamage() != 0) - { - OverlayUtil.renderTextLocation(graphics, textLocation, damageStr, config.getDamageColor()); - } - } - } - - return null; - } -} +/* + * Copyright (c) 2017, honeyhoney + * 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.experiencedrop; + +import java.awt.Dimension; +import java.awt.Graphics2D; +import javax.inject.Inject; +import net.runelite.api.Actor; +import net.runelite.api.Point; +import net.runelite.client.ui.overlay.Overlay; +import net.runelite.client.ui.overlay.OverlayPosition; +import net.runelite.client.ui.overlay.OverlayPriority; +import net.runelite.client.ui.overlay.OverlayUtil; + +class XpDropOverlay extends Overlay +{ + private final XpDropPlugin plugin; + private final XpDropConfig config; + + @Inject + private XpDropOverlay(XpDropPlugin plugin, XpDropConfig config) + { + this.plugin = plugin; + this.config = config; + setPosition(OverlayPosition.DYNAMIC); + setPriority(OverlayPriority.MED); + } + + @Override + public Dimension render(Graphics2D graphics) + { + if (config.showDamage()) + { + final Actor opponent = plugin.getLastOpponent(); + if (opponent != null) + { + int offset = opponent.getLogicalHeight() + 50; + String damageStr = String.valueOf(this.plugin.getDamage()); + Point textLocation = opponent.getCanvasTextLocation(graphics, damageStr, offset); + + if (textLocation != null && this.plugin.getDamage() != 0) + { + OverlayUtil.renderTextLocation(graphics, textLocation, damageStr, config.getDamageColor()); + } + } + } + + return null; + } +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/experiencedrop/XpDropPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/experiencedrop/XpDropPlugin.java index e2344f7929..50e64e1558 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/experiencedrop/XpDropPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/experiencedrop/XpDropPlugin.java @@ -1,453 +1,469 @@ -/* - * Copyright (c) 2018, Cameron , SoyChai - * 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.experiencedrop; - -import com.google.inject.Provides; - -import java.time.Duration; -import java.time.Instant; -import java.util.Arrays; -import java.util.EnumMap; -import java.util.Map; -import java.util.stream.IntStream; -import javax.inject.Inject; - -import lombok.AccessLevel; -import lombok.Getter; -import net.runelite.api.*; - -import static net.runelite.api.ScriptID.XPDROP_DISABLED; -import static net.runelite.client.plugins.attackstyles.AttackStyle.*; - -import net.runelite.api.events.*; -import net.runelite.api.widgets.Widget; -import net.runelite.api.widgets.WidgetID; -import net.runelite.api.widgets.WidgetInfo; -import net.runelite.client.config.ConfigManager; -import net.runelite.client.eventbus.Subscribe; -import net.runelite.client.game.HiscoreManager; -import net.runelite.client.game.NPCManager; -import net.runelite.client.plugins.Plugin; -import net.runelite.client.plugins.PluginDescriptor; -import net.runelite.client.plugins.attackstyles.AttackStyle; -import net.runelite.client.plugins.attackstyles.WeaponType; -import net.runelite.client.ui.overlay.OverlayManager; -import net.runelite.client.util.Text; -import net.runelite.http.api.hiscore.HiscoreEndpoint; -import net.runelite.http.api.hiscore.HiscoreResult; - -@PluginDescriptor( - name = "XP Drop", - description = "Enable customization of the way XP drops are displayed", - tags = {"experience", "levels", "tick"} -) -public class XpDropPlugin extends Plugin -{ - private static final int XPDROP_PADDING = 2; // space between xp drop icons - private static final Duration WAIT = Duration.ofSeconds(5); - - @Inject - private Client client; - - @Inject - private XpDropConfig config; - - private int tickCounter = 0; - private int previousExpGained; - private boolean hasHit = false; - private boolean hasDropped = false; - private boolean correctPrayer; - private Skill lastSkill = null; - private Map previousSkillExpTable = new EnumMap<>(Skill.class); - private PrayerType currentTickPrayer; - private AttackStyle attackStyle; - private int attackStyleVarbit = -1; - private int equippedWeaponTypeVarbit = -1; - private int castingModeVarbit = -1; - private int opponentHealth = -1; - private int xpGains = 0; - private AttackStyle[] offensiveStyles = {ACCURATE, AGGRESSIVE, DEFENSIVE, CONTROLLED, RANGING, LONGRANGE, CASTING, DEFENSIVE_CASTING}; - - @Getter(AccessLevel.PACKAGE) - private int damage = 0; - - @Getter(AccessLevel.PACKAGE) - private Actor lastOpponent; - - private Instant lastTime; - - @Inject - private OverlayManager overlayManager; - - @Inject - private XpDropOverlay overlay; - - @Inject - private NPCManager npcManager; - - @Inject - private HiscoreManager hiscoreManager; - - @Provides - XpDropConfig provideConfig(ConfigManager configManager) - { - return configManager.getConfig(XpDropConfig.class); - } - - @Override - protected void startUp() throws Exception - { - lastOpponent = null; - overlayManager.add(overlay); - if (client.getGameState() == GameState.LOGGED_IN) - { - attackStyleVarbit = client.getVar(VarPlayer.ATTACK_STYLE); - equippedWeaponTypeVarbit = client.getVar(Varbits.EQUIPPED_WEAPON_TYPE); - castingModeVarbit = client.getVar(Varbits.DEFENSIVE_CASTING_MODE); - updateAttackStyle( - equippedWeaponTypeVarbit, - attackStyleVarbit, - castingModeVarbit); - } - } - - @Subscribe - public void onWidgetHiddenChanged(WidgetHiddenChanged event) - { - Widget widget = event.getWidget(); - - int group = WidgetInfo.TO_GROUP(widget.getId()); - - if (group != WidgetID.EXPERIENCE_DROP_GROUP_ID) - { - return; - } - - if (widget.isHidden()) - { - return; - } - - if (config.hideSkillIcons()) - { - if (widget.getSpriteId() > 0) - { - widget.setHidden(true); - return; - } - else if (!widget.getText().isEmpty()) - { - // Align text accordingly to take up hidden skill icon space - int width = 0; - for (Widget w : widget.getParent().getDynamicChildren()) - { - if (w.getSpriteId() != -1) - { - if (width > 0) - { - // Add in space between sprites - width += XPDROP_PADDING; - } - width += w.getWidth(); // width of sprite - } - } - - final int xpDropPosition = client.getVar(Varbits.EXPERIENCE_TRACKER_POSITION); - switch (xpDropPosition) - { - case 2: // left - int cur = widget.getRelativeX(); - cur -= width; - widget.setRelativeX(cur); - break; - case 0: // right - break; - case 1: // center - cur = widget.getRelativeX(); - cur -= width / 2; - widget.setRelativeX(cur); - break; - } - } - } - - PrayerType prayer = currentTickPrayer; - if (prayer == null) - { - resetTextColor(widget); - return; - } - - String text = widget.getText(); - final IntStream spriteIDs = - Arrays.stream(widget.getParent().getDynamicChildren()).mapToInt(Widget::getSpriteId); - - if (text != null) - { - int color = widget.getTextColor(); - - switch (prayer) - { - case MELEE: - if (spriteIDs.anyMatch(id -> - id == SpriteID.SKILL_ATTACK || id == SpriteID.SKILL_STRENGTH || id == SpriteID.SKILL_DEFENCE - || correctPrayer)) - { - color = config.getMeleePrayerColor().getRGB(); - correctPrayer = true; - } - break; - case RANGE: - if (spriteIDs.anyMatch(id -> id == SpriteID.SKILL_RANGED || correctPrayer)) - { - color = config.getRangePrayerColor().getRGB(); - correctPrayer = true; - } - break; - case MAGIC: - if (spriteIDs.anyMatch(id -> id == SpriteID.SKILL_MAGIC || correctPrayer)) - { - color = config.getMagePrayerColor().getRGB(); - correctPrayer = true; - } - break; - } - - widget.setTextColor(color); - } - } - - private void resetTextColor(Widget widget) - { - int defaultColorIdx = client.getVar(Varbits.EXPERIENCE_DROP_COLOR); - int defaultColor = DefaultColors.values()[defaultColorIdx].getColor().getRGB(); - widget.setTextColor(defaultColor); - } - - private PrayerType getActivePrayerType() - { - for (XpPrayer prayer : XpPrayer.values()) - { - if (client.isPrayerActive(prayer.getPrayer())) - { - return prayer.getType(); - } - } - return null; - } - - @Subscribe - public void onGameTick(GameTick tick) - { - // Detect hitting a 0 - if (lastOpponent != null) - { - int health = calculateHealth(lastOpponent); - if (health != -1 && opponentHealth != -1 && health == opponentHealth && hasHit) - { - damage = 0; - hasHit = false; - } - } - - // Handle getting XP gains - if (hasDropped) - { - if (xpGains != 0 && attackStyle.getSkills().length > 1 && attackStyle != LONGRANGE) - { - damage = (int) (xpGains / (attackStyle.getSkills().length * 1.3)); - } - else if (xpGains != 0) - { - damage = xpGains / 4; - } - - xpGains = 0; - hasDropped = false; - } - - // Clear opponent - if (lastOpponent != null && lastTime != null && client.getLocalPlayer().getInteracting() == null) - { - if (Duration.between(lastTime, Instant.now()).compareTo(WAIT) > 0) - { - lastOpponent = null; - } - } - - currentTickPrayer = getActivePrayerType(); - correctPrayer = false; - - final int fakeTickDelay = config.fakeXpDropDelay(); - - if (fakeTickDelay == 0 || lastSkill == null) - { - return; - } - - // If an xp drop was created this tick, reset the counter - if (hasDropped) - { - hasDropped = false; - tickCounter = 0; - return; - } - - if (++tickCounter % fakeTickDelay != 0) - { - return; - } - - client.runScript(XPDROP_DISABLED, lastSkill.ordinal(), previousExpGained); - } - - @Subscribe - public void onExperienceChanged(ExperienceChanged event) - { - final Skill skill = event.getSkill(); - final int xp = client.getSkillExperience(skill); - - lastSkill = skill; - - Integer previous = previousSkillExpTable.put(skill, xp); - if (previous != null) - { - opponentHealth = calculateHealth(lastOpponent); - previousExpGained = xp - previous; - if (skill != Skill.HITPOINTS && Arrays.stream(offensiveStyles).anyMatch(attackStyle::equals)) - { - xpGains += previousExpGained; - } - - hasDropped = true; - hasHit = true; - } - } - - private void updateAttackStyle(int equippedWeaponType, int attackStyleIndex, int castingMode) - { - AttackStyle[] attackStyles = WeaponType.getWeaponType(equippedWeaponType).getAttackStyles(); - if (attackStyleIndex < attackStyles.length) - { - attackStyle = attackStyles[attackStyleIndex]; - if (attackStyle == null) - { - attackStyle = OTHER; - } - else if ((attackStyle == CASTING) && (castingMode == 1)) - { - attackStyle = DEFENSIVE_CASTING; - } - } - } - - @Subscribe - public void onInteractingChanged(InteractingChanged event) - { - if (event.getSource() != client.getLocalPlayer()) - { - return; - } - - Actor opponent = event.getTarget(); - - if (opponent == null) - { - lastTime = Instant.now(); - return; - } - else if (opponent.getName().equalsIgnoreCase("fishing spot")) - { - lastTime = Instant.now().minus(WAIT); - return; - } - - damage = 0; - lastOpponent = opponent; - opponentHealth = calculateHealth(opponent); - } - - private int calculateHealth(Actor target) - { - if (target == null || target.getName() == null) - { - return -1; - } - - final int healthScale = target.getHealth(); - final int healthRatio = target.getHealthRatio(); - final String targetName = Text.removeTags(target.getName()); - - Integer maxHealth = -1; - if (target instanceof NPC) - { - maxHealth = npcManager.getHealth(targetName, target.getCombatLevel()); - } - else if (target instanceof Player) - { - final HiscoreResult hiscoreResult = hiscoreManager.lookupAsync(targetName, HiscoreEndpoint.NORMAL); - if (hiscoreResult != null) - { - final int hp = hiscoreResult.getHitpoints().getLevel(); - if (hp > 0) - { - maxHealth = hp; - } - } - } - - if (healthRatio < 0 || healthScale <= 0 || maxHealth == null) - { - return -1; - } - - return (int)((maxHealth * healthRatio / healthScale) + 0.5f); - } - - @Subscribe - public void onVarbitChanged(VarbitChanged event) - { - if (attackStyleVarbit == -1 || attackStyleVarbit != client.getVar(VarPlayer.ATTACK_STYLE)) - { - attackStyleVarbit = client.getVar(VarPlayer.ATTACK_STYLE); - updateAttackStyle(client.getVar(Varbits.EQUIPPED_WEAPON_TYPE), attackStyleVarbit, - client.getVar(Varbits.DEFENSIVE_CASTING_MODE)); - } - - if (equippedWeaponTypeVarbit == -1 || equippedWeaponTypeVarbit != client.getVar(Varbits.EQUIPPED_WEAPON_TYPE)) - { - equippedWeaponTypeVarbit = client.getVar(Varbits.EQUIPPED_WEAPON_TYPE); - updateAttackStyle(equippedWeaponTypeVarbit, client.getVar(VarPlayer.ATTACK_STYLE), - client.getVar(Varbits.DEFENSIVE_CASTING_MODE)); - } - - if (castingModeVarbit == -1 || castingModeVarbit != client.getVar(Varbits.DEFENSIVE_CASTING_MODE)) - { - castingModeVarbit = client.getVar(Varbits.DEFENSIVE_CASTING_MODE); - updateAttackStyle(client.getVar(Varbits.EQUIPPED_WEAPON_TYPE), client.getVar(VarPlayer.ATTACK_STYLE), - castingModeVarbit); - } - } -} +/* + * Copyright (c) 2018, Cameron , SoyChai + * 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.experiencedrop; + +import com.google.inject.Provides; +import java.time.Duration; +import java.time.Instant; +import java.util.Arrays; +import java.util.EnumMap; +import java.util.Map; +import java.util.stream.IntStream; +import javax.inject.Inject; +import lombok.AccessLevel; +import lombok.Getter; +import net.runelite.api.Actor; +import net.runelite.api.Client; +import net.runelite.api.GameState; +import net.runelite.api.NPC; +import net.runelite.api.Player; +import static net.runelite.api.ScriptID.XPDROP_DISABLED; +import net.runelite.api.Skill; +import net.runelite.api.SpriteID; +import net.runelite.api.VarPlayer; +import net.runelite.api.Varbits; +import net.runelite.api.events.ExperienceChanged; +import net.runelite.api.events.GameTick; +import net.runelite.api.events.InteractingChanged; +import net.runelite.api.events.VarbitChanged; +import net.runelite.api.events.WidgetHiddenChanged; +import net.runelite.api.widgets.Widget; +import net.runelite.api.widgets.WidgetID; +import net.runelite.api.widgets.WidgetInfo; +import net.runelite.client.config.ConfigManager; +import net.runelite.client.eventbus.Subscribe; +import net.runelite.client.game.HiscoreManager; +import net.runelite.client.game.NPCManager; +import net.runelite.client.plugins.Plugin; +import net.runelite.client.plugins.PluginDescriptor; +import net.runelite.client.plugins.attackstyles.AttackStyle; +import static net.runelite.client.plugins.attackstyles.AttackStyle.ACCURATE; +import static net.runelite.client.plugins.attackstyles.AttackStyle.AGGRESSIVE; +import static net.runelite.client.plugins.attackstyles.AttackStyle.CASTING; +import static net.runelite.client.plugins.attackstyles.AttackStyle.CONTROLLED; +import static net.runelite.client.plugins.attackstyles.AttackStyle.DEFENSIVE; +import static net.runelite.client.plugins.attackstyles.AttackStyle.DEFENSIVE_CASTING; +import static net.runelite.client.plugins.attackstyles.AttackStyle.LONGRANGE; +import static net.runelite.client.plugins.attackstyles.AttackStyle.OTHER; +import static net.runelite.client.plugins.attackstyles.AttackStyle.RANGING; +import net.runelite.client.plugins.attackstyles.WeaponType; +import net.runelite.client.ui.overlay.OverlayManager; +import net.runelite.client.util.Text; +import net.runelite.http.api.hiscore.HiscoreEndpoint; +import net.runelite.http.api.hiscore.HiscoreResult; + +@PluginDescriptor( + name = "XP Drop", + description = "Enable customization of the way XP drops are displayed", + tags = {"experience", "levels", "tick"} +) +public class XpDropPlugin extends Plugin +{ + private static final int XPDROP_PADDING = 2; // space between xp drop icons + private static final Duration WAIT = Duration.ofSeconds(5); + + @Inject + private Client client; + + @Inject + private XpDropConfig config; + + private int tickCounter = 0; + private int previousExpGained; + private boolean hasHit = false; + private boolean hasDropped = false; + private boolean correctPrayer; + private Skill lastSkill = null; + private Map previousSkillExpTable = new EnumMap<>(Skill.class); + private PrayerType currentTickPrayer; + private AttackStyle attackStyle; + private int attackStyleVarbit = -1; + private int equippedWeaponTypeVarbit = -1; + private int castingModeVarbit = -1; + private int opponentHealth = -1; + private int xpGains = 0; + private AttackStyle[] offensiveStyles = {ACCURATE, AGGRESSIVE, DEFENSIVE, CONTROLLED, RANGING, LONGRANGE, CASTING, DEFENSIVE_CASTING}; + + @Getter(AccessLevel.PACKAGE) + private int damage = 0; + + @Getter(AccessLevel.PACKAGE) + private Actor lastOpponent; + + private Instant lastTime; + + @Inject + private OverlayManager overlayManager; + + @Inject + private XpDropOverlay overlay; + + @Inject + private NPCManager npcManager; + + @Inject + private HiscoreManager hiscoreManager; + + @Provides + XpDropConfig provideConfig(ConfigManager configManager) + { + return configManager.getConfig(XpDropConfig.class); + } + + @Override + protected void startUp() throws Exception + { + lastOpponent = null; + overlayManager.add(overlay); + if (client.getGameState() == GameState.LOGGED_IN) + { + attackStyleVarbit = client.getVar(VarPlayer.ATTACK_STYLE); + equippedWeaponTypeVarbit = client.getVar(Varbits.EQUIPPED_WEAPON_TYPE); + castingModeVarbit = client.getVar(Varbits.DEFENSIVE_CASTING_MODE); + updateAttackStyle( + equippedWeaponTypeVarbit, + attackStyleVarbit, + castingModeVarbit); + } + } + + @Subscribe + public void onWidgetHiddenChanged(WidgetHiddenChanged event) + { + Widget widget = event.getWidget(); + + int group = WidgetInfo.TO_GROUP(widget.getId()); + + if (group != WidgetID.EXPERIENCE_DROP_GROUP_ID) + { + return; + } + + if (widget.isHidden()) + { + return; + } + + if (config.hideSkillIcons()) + { + if (widget.getSpriteId() > 0) + { + widget.setHidden(true); + return; + } + else if (!widget.getText().isEmpty()) + { + // Align text accordingly to take up hidden skill icon space + int width = 0; + for (Widget w : widget.getParent().getDynamicChildren()) + { + if (w.getSpriteId() != -1) + { + if (width > 0) + { + // Add in space between sprites + width += XPDROP_PADDING; + } + width += w.getWidth(); // width of sprite + } + } + + final int xpDropPosition = client.getVar(Varbits.EXPERIENCE_TRACKER_POSITION); + switch (xpDropPosition) + { + case 2: // left + int cur = widget.getRelativeX(); + cur -= width; + widget.setRelativeX(cur); + break; + case 0: // right + break; + case 1: // center + cur = widget.getRelativeX(); + cur -= width / 2; + widget.setRelativeX(cur); + break; + } + } + } + + PrayerType prayer = currentTickPrayer; + if (prayer == null) + { + resetTextColor(widget); + return; + } + + String text = widget.getText(); + final IntStream spriteIDs = + Arrays.stream(widget.getParent().getDynamicChildren()).mapToInt(Widget::getSpriteId); + + if (text != null) + { + int color = widget.getTextColor(); + + switch (prayer) + { + case MELEE: + if (spriteIDs.anyMatch(id -> + id == SpriteID.SKILL_ATTACK || id == SpriteID.SKILL_STRENGTH || id == SpriteID.SKILL_DEFENCE + || correctPrayer)) + { + color = config.getMeleePrayerColor().getRGB(); + correctPrayer = true; + } + break; + case RANGE: + if (spriteIDs.anyMatch(id -> id == SpriteID.SKILL_RANGED || correctPrayer)) + { + color = config.getRangePrayerColor().getRGB(); + correctPrayer = true; + } + break; + case MAGIC: + if (spriteIDs.anyMatch(id -> id == SpriteID.SKILL_MAGIC || correctPrayer)) + { + color = config.getMagePrayerColor().getRGB(); + correctPrayer = true; + } + break; + } + + widget.setTextColor(color); + } + } + + private void resetTextColor(Widget widget) + { + int defaultColorIdx = client.getVar(Varbits.EXPERIENCE_DROP_COLOR); + int defaultColor = DefaultColors.values()[defaultColorIdx].getColor().getRGB(); + widget.setTextColor(defaultColor); + } + + private PrayerType getActivePrayerType() + { + for (XpPrayer prayer : XpPrayer.values()) + { + if (client.isPrayerActive(prayer.getPrayer())) + { + return prayer.getType(); + } + } + return null; + } + + @Subscribe + public void onGameTick(GameTick tick) + { + // Detect hitting a 0 + if (lastOpponent != null) + { + int health = calculateHealth(lastOpponent); + if (health != -1 && opponentHealth != -1 && health == opponentHealth && hasHit) + { + damage = 0; + hasHit = false; + } + } + + // Handle getting XP gains + if (hasDropped) + { + if (xpGains != 0 && attackStyle.getSkills().length > 1 && attackStyle != LONGRANGE) + { + damage = (int) (xpGains / (attackStyle.getSkills().length * 1.3)); + } + else if (xpGains != 0) + { + damage = xpGains / 4; + } + + xpGains = 0; + hasDropped = false; + } + + // Clear opponent + if (lastOpponent != null && lastTime != null && client.getLocalPlayer().getInteracting() == null) + { + if (Duration.between(lastTime, Instant.now()).compareTo(WAIT) > 0) + { + lastOpponent = null; + } + } + + currentTickPrayer = getActivePrayerType(); + correctPrayer = false; + + final int fakeTickDelay = config.fakeXpDropDelay(); + + if (fakeTickDelay == 0 || lastSkill == null) + { + return; + } + + // If an xp drop was created this tick, reset the counter + if (hasDropped) + { + hasDropped = false; + tickCounter = 0; + return; + } + + if (++tickCounter % fakeTickDelay != 0) + { + return; + } + + client.runScript(XPDROP_DISABLED, lastSkill.ordinal(), previousExpGained); + } + + @Subscribe + public void onExperienceChanged(ExperienceChanged event) + { + final Skill skill = event.getSkill(); + final int xp = client.getSkillExperience(skill); + + lastSkill = skill; + + Integer previous = previousSkillExpTable.put(skill, xp); + if (previous != null) + { + opponentHealth = calculateHealth(lastOpponent); + previousExpGained = xp - previous; + if (skill != Skill.HITPOINTS && Arrays.stream(offensiveStyles).anyMatch(attackStyle::equals)) + { + xpGains += previousExpGained; + } + + hasDropped = true; + hasHit = true; + } + } + + private void updateAttackStyle(int equippedWeaponType, int attackStyleIndex, int castingMode) + { + AttackStyle[] attackStyles = WeaponType.getWeaponType(equippedWeaponType).getAttackStyles(); + if (attackStyleIndex < attackStyles.length) + { + attackStyle = attackStyles[attackStyleIndex]; + if (attackStyle == null) + { + attackStyle = OTHER; + } + else if ((attackStyle == CASTING) && (castingMode == 1)) + { + attackStyle = DEFENSIVE_CASTING; + } + } + } + + @Subscribe + public void onInteractingChanged(InteractingChanged event) + { + if (event.getSource() != client.getLocalPlayer()) + { + return; + } + + Actor opponent = event.getTarget(); + + if (opponent == null) + { + lastTime = Instant.now(); + return; + } + else if (opponent.getName().equalsIgnoreCase("fishing spot")) + { + lastTime = Instant.now().minus(WAIT); + return; + } + + damage = 0; + lastOpponent = opponent; + opponentHealth = calculateHealth(opponent); + } + + private int calculateHealth(Actor target) + { + if (target == null || target.getName() == null) + { + return -1; + } + + final int healthScale = target.getHealth(); + final int healthRatio = target.getHealthRatio(); + final String targetName = Text.removeTags(target.getName()); + + Integer maxHealth = -1; + if (target instanceof NPC) + { + maxHealth = npcManager.getHealth(targetName, target.getCombatLevel()); + } + else if (target instanceof Player) + { + final HiscoreResult hiscoreResult = hiscoreManager.lookupAsync(targetName, HiscoreEndpoint.NORMAL); + if (hiscoreResult != null) + { + final int hp = hiscoreResult.getHitpoints().getLevel(); + if (hp > 0) + { + maxHealth = hp; + } + } + } + + if (healthRatio < 0 || healthScale <= 0 || maxHealth == null) + { + return -1; + } + + return (int) ((maxHealth * healthRatio / healthScale) + 0.5f); + } + + @Subscribe + public void onVarbitChanged(VarbitChanged event) + { + if (attackStyleVarbit == -1 || attackStyleVarbit != client.getVar(VarPlayer.ATTACK_STYLE)) + { + attackStyleVarbit = client.getVar(VarPlayer.ATTACK_STYLE); + updateAttackStyle(client.getVar(Varbits.EQUIPPED_WEAPON_TYPE), attackStyleVarbit, + client.getVar(Varbits.DEFENSIVE_CASTING_MODE)); + } + + if (equippedWeaponTypeVarbit == -1 || equippedWeaponTypeVarbit != client.getVar(Varbits.EQUIPPED_WEAPON_TYPE)) + { + equippedWeaponTypeVarbit = client.getVar(Varbits.EQUIPPED_WEAPON_TYPE); + updateAttackStyle(equippedWeaponTypeVarbit, client.getVar(VarPlayer.ATTACK_STYLE), + client.getVar(Varbits.DEFENSIVE_CASTING_MODE)); + } + + if (castingModeVarbit == -1 || castingModeVarbit != client.getVar(Varbits.DEFENSIVE_CASTING_MODE)) + { + castingModeVarbit = client.getVar(Varbits.DEFENSIVE_CASTING_MODE); + updateAttackStyle(client.getVar(Varbits.EQUIPPED_WEAPON_TYPE), client.getVar(VarPlayer.ATTACK_STYLE), + castingModeVarbit); + } + } +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/experiencedrop/XpPrayer.java b/runelite-client/src/main/java/net/runelite/client/plugins/experiencedrop/XpPrayer.java index 61ff0b088c..b1b80f2509 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/experiencedrop/XpPrayer.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/experiencedrop/XpPrayer.java @@ -1,63 +1,78 @@ -/* - * Copyright (c) 2018, Adam - * 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.experiencedrop; - -import lombok.Getter; -import net.runelite.api.Prayer; -import static net.runelite.api.Prayer.*; -import static net.runelite.client.plugins.experiencedrop.PrayerType.MAGIC; -import static net.runelite.client.plugins.experiencedrop.PrayerType.MELEE; -import static net.runelite.client.plugins.experiencedrop.PrayerType.RANGE; - -enum XpPrayer -{ - XP_BURST_OF_STRENGTH(BURST_OF_STRENGTH, MELEE), - XP_CLARITY_OF_THOUGHT(CLARITY_OF_THOUGHT, MELEE), - XP_SHARP_EYE(SHARP_EYE, RANGE), - XP_MYSTIC_WILL(MYSTIC_WILL, MAGIC), - XP_SUPERHUMAN_STRENGTH(SUPERHUMAN_STRENGTH, MELEE), - XP_IMPROVED_REFLEXES(IMPROVED_REFLEXES, MELEE), - XP_HAWK_EYE(HAWK_EYE, RANGE), - XP_MYSTIC_LORE(MYSTIC_LORE, MAGIC), - XP_ULTIMATE_STRENGTH(ULTIMATE_STRENGTH, MELEE), - XP_INCREDIBLE_REFLEXES(INCREDIBLE_REFLEXES, MELEE), - XP_EAGLE_EYE(EAGLE_EYE, RANGE), - XP_MYSTIC_MIGHT(MYSTIC_MIGHT, MAGIC), - XP_CHIVALRY(CHIVALRY, MELEE), - XP_PIETY(PIETY, MELEE), - XP_RIGOUR(RIGOUR, RANGE), - XP_AUGURY(AUGURY, MAGIC); - - @Getter - private final Prayer prayer; - @Getter - private final PrayerType type; - - XpPrayer(Prayer prayer, PrayerType type) - { - this.prayer = prayer; - this.type = type; - } -} +/* + * Copyright (c) 2018, Adam + * 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.experiencedrop; + +import lombok.Getter; +import net.runelite.api.Prayer; +import static net.runelite.api.Prayer.AUGURY; +import static net.runelite.api.Prayer.BURST_OF_STRENGTH; +import static net.runelite.api.Prayer.CHIVALRY; +import static net.runelite.api.Prayer.CLARITY_OF_THOUGHT; +import static net.runelite.api.Prayer.EAGLE_EYE; +import static net.runelite.api.Prayer.HAWK_EYE; +import static net.runelite.api.Prayer.IMPROVED_REFLEXES; +import static net.runelite.api.Prayer.INCREDIBLE_REFLEXES; +import static net.runelite.api.Prayer.MYSTIC_LORE; +import static net.runelite.api.Prayer.MYSTIC_MIGHT; +import static net.runelite.api.Prayer.MYSTIC_WILL; +import static net.runelite.api.Prayer.PIETY; +import static net.runelite.api.Prayer.RIGOUR; +import static net.runelite.api.Prayer.SHARP_EYE; +import static net.runelite.api.Prayer.SUPERHUMAN_STRENGTH; +import static net.runelite.api.Prayer.ULTIMATE_STRENGTH; +import static net.runelite.client.plugins.experiencedrop.PrayerType.MAGIC; +import static net.runelite.client.plugins.experiencedrop.PrayerType.MELEE; +import static net.runelite.client.plugins.experiencedrop.PrayerType.RANGE; + +enum XpPrayer +{ + XP_BURST_OF_STRENGTH(BURST_OF_STRENGTH, MELEE), + XP_CLARITY_OF_THOUGHT(CLARITY_OF_THOUGHT, MELEE), + XP_SHARP_EYE(SHARP_EYE, RANGE), + XP_MYSTIC_WILL(MYSTIC_WILL, MAGIC), + XP_SUPERHUMAN_STRENGTH(SUPERHUMAN_STRENGTH, MELEE), + XP_IMPROVED_REFLEXES(IMPROVED_REFLEXES, MELEE), + XP_HAWK_EYE(HAWK_EYE, RANGE), + XP_MYSTIC_LORE(MYSTIC_LORE, MAGIC), + XP_ULTIMATE_STRENGTH(ULTIMATE_STRENGTH, MELEE), + XP_INCREDIBLE_REFLEXES(INCREDIBLE_REFLEXES, MELEE), + XP_EAGLE_EYE(EAGLE_EYE, RANGE), + XP_MYSTIC_MIGHT(MYSTIC_MIGHT, MAGIC), + XP_CHIVALRY(CHIVALRY, MELEE), + XP_PIETY(PIETY, MELEE), + XP_RIGOUR(RIGOUR, RANGE), + XP_AUGURY(AUGURY, MAGIC); + + @Getter + private final Prayer prayer; + @Getter + private final PrayerType type; + + XpPrayer(Prayer prayer, PrayerType type) + { + this.prayer = prayer; + this.type = type; + } +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/fairyring/FairyRingPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/fairyring/FairyRingPlugin.java index 644c05859b..c0e91cf335 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/fairyring/FairyRingPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/fairyring/FairyRingPlugin.java @@ -1,366 +1,366 @@ -/* - * Copyright (c) 2018 Abex - * Copyright (c) 2017, Tyler - * Copyright (c) 2018, Yoav Ram - * Copyright (c) 2018, Infinitay - * 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.fairyring; - -import com.google.common.base.Strings; -import com.google.inject.Provides; -import java.util.Collection; -import java.util.Map; -import java.util.TreeMap; -import javax.annotation.Nullable; -import javax.inject.Inject; -import lombok.Data; -import lombok.extern.slf4j.Slf4j; -import net.runelite.api.Client; -import net.runelite.api.ScriptEvent; -import net.runelite.api.ScriptID; -import net.runelite.api.SoundEffectID; -import net.runelite.api.SpriteID; -import net.runelite.api.Varbits; -import net.runelite.api.widgets.WidgetType; -import net.runelite.api.events.GameTick; -import net.runelite.api.events.VarbitChanged; -import net.runelite.api.events.WidgetLoaded; -import net.runelite.api.widgets.JavaScriptCallback; -import net.runelite.api.widgets.Widget; -import net.runelite.api.widgets.WidgetID; -import net.runelite.api.widgets.WidgetInfo; -import net.runelite.client.callback.ClientThread; -import net.runelite.client.config.ConfigManager; -import net.runelite.client.eventbus.Subscribe; -import net.runelite.client.game.chatbox.ChatboxPanelManager; -import net.runelite.client.game.chatbox.ChatboxTextInput; -import net.runelite.client.plugins.Plugin; -import net.runelite.client.plugins.PluginDescriptor; -import net.runelite.client.util.Text; - -@Slf4j -@PluginDescriptor( - name = "Fairy Rings", - description = "Show the location of the fairy ring teleport", - tags = {"teleportation"} -) -public class FairyRingPlugin extends Plugin -{ - private static final String[] leftDial = new String[]{"A", "D", "C", "B"}; - private static final String[] middleDial = new String[]{"I", "L", "K", "J"}; - private static final String[] rightDial = new String[]{"P", "S", "R", "Q"}; - - private static final int ENTRY_PADDING = 3; - - private static final String MENU_OPEN = "Open"; - private static final String MENU_CLOSE = "Close"; - - @Inject - private Client client; - - @Inject - private FairyRingConfig config; - - @Inject - private ChatboxPanelManager chatboxPanelManager; - - @Inject - private ClientThread clientThread; - - private ChatboxTextInput searchInput = null; - private Widget searchBtn; - private Collection codes = null; - - @Data - private static class CodeWidgets - { - // The fairy hideout has both of these null, because its not the same as the rest of them - @Nullable - private Widget favorite; - - @Nullable - private Widget code; - - private Widget description; - } - - @Provides - FairyRingConfig getConfig(ConfigManager configManager) - { - return configManager.getConfig(FairyRingConfig.class); - } - - @Subscribe - public void onVarbitChanged(VarbitChanged event) - { - setWidgetTextToDestination(); - } - - @Subscribe - public void onWidgetLoaded(WidgetLoaded widgetLoaded) - { - if (widgetLoaded.getGroupId() == WidgetID.FAIRY_RING_PANEL_GROUP_ID) - { - setWidgetTextToDestination(); - - Widget header = client.getWidget(WidgetInfo.FAIRY_RING_HEADER); - if (header != null) - { - searchBtn = header.createChild(-1, WidgetType.GRAPHIC); - searchBtn.setSpriteId(SpriteID.GE_SEARCH); - searchBtn.setOriginalWidth(17); - searchBtn.setOriginalHeight(17); - searchBtn.setOriginalX(11); - searchBtn.setOriginalY(11); - searchBtn.setHasListener(true); - searchBtn.setAction(1, MENU_OPEN); - searchBtn.setOnOpListener((JavaScriptCallback) this::menuOpen); - searchBtn.setName("Search"); - searchBtn.revalidate(); - - codes = null; - - if (config.autoOpen()) - { - openSearch(); - } - } - } - } - - private void menuOpen(ScriptEvent e) - { - openSearch(); - client.playSoundEffect(SoundEffectID.UI_BOOP); - } - - private void menuClose(ScriptEvent e) - { - updateFilter(""); - chatboxPanelManager.close(); - client.playSoundEffect(SoundEffectID.UI_BOOP); - } - - private void setWidgetTextToDestination() - { - Widget fairyRingTeleportButton = client.getWidget(WidgetInfo.FAIRY_RING_TELEPORT_BUTTON); - if (fairyRingTeleportButton != null && !fairyRingTeleportButton.isHidden()) - { - String destination; - try - { - FairyRings fairyRingDestination = getFairyRingDestination(client.getVar(Varbits.FAIRY_RING_DIAL_ADCB), - client.getVar(Varbits.FAIRY_RIGH_DIAL_ILJK), client.getVar(Varbits.FAIRY_RING_DIAL_PSRQ)); - destination = fairyRingDestination.getDestination(); - } - catch (IllegalArgumentException ex) - { - destination = "Invalid location"; - } - - fairyRingTeleportButton.setText(destination); - } - } - - private FairyRings getFairyRingDestination(int varbitValueDialLeft, int varbitValueDialMiddle, int varbitValueDialRight) - { - return FairyRings.valueOf(leftDial[varbitValueDialLeft] + middleDial[varbitValueDialMiddle] + rightDial[varbitValueDialRight]); - } - - private void openSearch() - { - updateFilter(""); - searchBtn.setAction(1, MENU_CLOSE); - searchBtn.setOnOpListener((JavaScriptCallback) this::menuClose); - searchInput = chatboxPanelManager.openTextInput("Filter fairy rings") - .onChanged(s -> clientThread.invokeLater(() -> updateFilter(s))) - .onClose(() -> - { - clientThread.invokeLater(() -> updateFilter("")); - searchBtn.setOnOpListener((JavaScriptCallback) this::menuOpen); - searchBtn.setAction(1, MENU_OPEN); - }) - .build(); - } - - @Subscribe - public void onGameTick(GameTick t) - { - // This has to happen because the only widget that gets hidden is the tli one - Widget fairyRingTeleportButton = client.getWidget(WidgetInfo.FAIRY_RING_TELEPORT_BUTTON); - boolean fairyRingWidgetOpen = fairyRingTeleportButton != null && !fairyRingTeleportButton.isHidden(); - boolean chatboxOpen = searchInput != null && chatboxPanelManager.getCurrentInput() == searchInput; - - if (!fairyRingWidgetOpen && chatboxOpen) - { - chatboxPanelManager.close(); - } - } - - private void updateFilter(String filter) - { - filter = filter.toLowerCase(); - final Widget list = client.getWidget(WidgetInfo.FAIRY_RING_LIST); - final Widget favorites = client.getWidget(WidgetInfo.FAIRY_RING_FAVORITES); - - if (list == null) - { - return; - } - - if (codes != null) - { - // Check to make sure the list hasn't been rebuild since we were last her - // Do this by making sure the list's dynamic children are the same as when we last saw them - if (codes.stream().noneMatch(w -> - { - Widget codeWidget = w.getCode(); - if (codeWidget == null) - { - return false; - } - return list.getChild(codeWidget.getIndex()) == codeWidget; - })) - { - codes = null; - } - } - - if (codes == null) - { - // Find all of the widgets that we care about, grouping by their Y value - Map codeMap = new TreeMap<>(); - - for (Widget w : list.getStaticChildren()) - { - if (w.isSelfHidden()) - { - continue; - } - - if (w.getSpriteId() != -1) - { - codeMap.computeIfAbsent(w.getRelativeY(), k -> new CodeWidgets()).setFavorite(w); - } - else if (!Strings.isNullOrEmpty(w.getText())) - { - codeMap.computeIfAbsent(w.getRelativeY(), k -> new CodeWidgets()).setDescription(w); - } - } - - for (Widget w : list.getDynamicChildren()) - { - if (w.isSelfHidden()) - { - continue; - } - - CodeWidgets c = codeMap.computeIfAbsent(w.getRelativeY(), k -> new CodeWidgets()); - c.setCode(w); - } - - codes = codeMap.values(); - } - - // Relayout the panel - int y = 0; - - if (favorites != null) - { - boolean hide = !filter.isEmpty(); - favorites.setHidden(hide); - if (!hide) - { - y += favorites.getOriginalHeight() + ENTRY_PADDING; - } - } - - for (CodeWidgets c : codes) - { - String code = Text.removeTags(c.getDescription().getName()).replaceAll(" ", ""); - String tags = null; - - if (!code.isEmpty()) - { - try - { - FairyRings ring = FairyRings.valueOf(code); - tags = ring.getTags(); - } - catch (IllegalArgumentException e) - { - log.warn("Unable to find ring with code '{}'", code, e); - } - } - - boolean hidden = !(filter.isEmpty() - || Text.removeTags(c.getDescription().getText()).toLowerCase().contains(filter) - || code.toLowerCase().contains(filter) - || tags != null && tags.contains(filter)); - - if (c.getCode() != null) - { - c.getCode().setHidden(hidden); - c.getCode().setOriginalY(y); - } - - if (c.getFavorite() != null) - { - c.getFavorite().setHidden(hidden); - c.getFavorite().setOriginalY(y); - } - - c.getDescription().setHidden(hidden); - c.getDescription().setOriginalY(y); - - if (!hidden) - { - y += c.getDescription().getHeight() + ENTRY_PADDING; - } - } - - y -= ENTRY_PADDING; - - if (y < 0) - { - y = 0; - } - - int newHeight = 0; - if (list.getScrollHeight() > 0) - { - newHeight = (list.getScrollY() * y) / list.getScrollHeight(); - } - - list.setScrollHeight(y); - list.revalidateScroll(); - client.runScript( - ScriptID.UPDATE_SCROLLBAR, - WidgetInfo.FAIRY_RING_LIST_SCROLLBAR.getId(), - WidgetInfo.FAIRY_RING_LIST.getId(), - newHeight - ); - } -} +/* + * Copyright (c) 2018 Abex + * Copyright (c) 2017, Tyler + * Copyright (c) 2018, Yoav Ram + * Copyright (c) 2018, Infinitay + * 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.fairyring; + +import com.google.common.base.Strings; +import com.google.inject.Provides; +import java.util.Collection; +import java.util.Map; +import java.util.TreeMap; +import javax.annotation.Nullable; +import javax.inject.Inject; +import lombok.Data; +import lombok.extern.slf4j.Slf4j; +import net.runelite.api.Client; +import net.runelite.api.ScriptEvent; +import net.runelite.api.ScriptID; +import net.runelite.api.SoundEffectID; +import net.runelite.api.SpriteID; +import net.runelite.api.Varbits; +import net.runelite.api.events.GameTick; +import net.runelite.api.events.VarbitChanged; +import net.runelite.api.events.WidgetLoaded; +import net.runelite.api.widgets.JavaScriptCallback; +import net.runelite.api.widgets.Widget; +import net.runelite.api.widgets.WidgetID; +import net.runelite.api.widgets.WidgetInfo; +import net.runelite.api.widgets.WidgetType; +import net.runelite.client.callback.ClientThread; +import net.runelite.client.config.ConfigManager; +import net.runelite.client.eventbus.Subscribe; +import net.runelite.client.game.chatbox.ChatboxPanelManager; +import net.runelite.client.game.chatbox.ChatboxTextInput; +import net.runelite.client.plugins.Plugin; +import net.runelite.client.plugins.PluginDescriptor; +import net.runelite.client.util.Text; + +@Slf4j +@PluginDescriptor( + name = "Fairy Rings", + description = "Show the location of the fairy ring teleport", + tags = {"teleportation"} +) +public class FairyRingPlugin extends Plugin +{ + private static final String[] leftDial = new String[]{"A", "D", "C", "B"}; + private static final String[] middleDial = new String[]{"I", "L", "K", "J"}; + private static final String[] rightDial = new String[]{"P", "S", "R", "Q"}; + + private static final int ENTRY_PADDING = 3; + + private static final String MENU_OPEN = "Open"; + private static final String MENU_CLOSE = "Close"; + + @Inject + private Client client; + + @Inject + private FairyRingConfig config; + + @Inject + private ChatboxPanelManager chatboxPanelManager; + + @Inject + private ClientThread clientThread; + + private ChatboxTextInput searchInput = null; + private Widget searchBtn; + private Collection codes = null; + + @Data + private static class CodeWidgets + { + // The fairy hideout has both of these null, because its not the same as the rest of them + @Nullable + private Widget favorite; + + @Nullable + private Widget code; + + private Widget description; + } + + @Provides + FairyRingConfig getConfig(ConfigManager configManager) + { + return configManager.getConfig(FairyRingConfig.class); + } + + @Subscribe + public void onVarbitChanged(VarbitChanged event) + { + setWidgetTextToDestination(); + } + + @Subscribe + public void onWidgetLoaded(WidgetLoaded widgetLoaded) + { + if (widgetLoaded.getGroupId() == WidgetID.FAIRY_RING_PANEL_GROUP_ID) + { + setWidgetTextToDestination(); + + Widget header = client.getWidget(WidgetInfo.FAIRY_RING_HEADER); + if (header != null) + { + searchBtn = header.createChild(-1, WidgetType.GRAPHIC); + searchBtn.setSpriteId(SpriteID.GE_SEARCH); + searchBtn.setOriginalWidth(17); + searchBtn.setOriginalHeight(17); + searchBtn.setOriginalX(11); + searchBtn.setOriginalY(11); + searchBtn.setHasListener(true); + searchBtn.setAction(1, MENU_OPEN); + searchBtn.setOnOpListener((JavaScriptCallback) this::menuOpen); + searchBtn.setName("Search"); + searchBtn.revalidate(); + + codes = null; + + if (config.autoOpen()) + { + openSearch(); + } + } + } + } + + private void menuOpen(ScriptEvent e) + { + openSearch(); + client.playSoundEffect(SoundEffectID.UI_BOOP); + } + + private void menuClose(ScriptEvent e) + { + updateFilter(""); + chatboxPanelManager.close(); + client.playSoundEffect(SoundEffectID.UI_BOOP); + } + + private void setWidgetTextToDestination() + { + Widget fairyRingTeleportButton = client.getWidget(WidgetInfo.FAIRY_RING_TELEPORT_BUTTON); + if (fairyRingTeleportButton != null && !fairyRingTeleportButton.isHidden()) + { + String destination; + try + { + FairyRings fairyRingDestination = getFairyRingDestination(client.getVar(Varbits.FAIRY_RING_DIAL_ADCB), + client.getVar(Varbits.FAIRY_RIGH_DIAL_ILJK), client.getVar(Varbits.FAIRY_RING_DIAL_PSRQ)); + destination = fairyRingDestination.getDestination(); + } + catch (IllegalArgumentException ex) + { + destination = "Invalid location"; + } + + fairyRingTeleportButton.setText(destination); + } + } + + private FairyRings getFairyRingDestination(int varbitValueDialLeft, int varbitValueDialMiddle, int varbitValueDialRight) + { + return FairyRings.valueOf(leftDial[varbitValueDialLeft] + middleDial[varbitValueDialMiddle] + rightDial[varbitValueDialRight]); + } + + private void openSearch() + { + updateFilter(""); + searchBtn.setAction(1, MENU_CLOSE); + searchBtn.setOnOpListener((JavaScriptCallback) this::menuClose); + searchInput = chatboxPanelManager.openTextInput("Filter fairy rings") + .onChanged(s -> clientThread.invokeLater(() -> updateFilter(s))) + .onClose(() -> + { + clientThread.invokeLater(() -> updateFilter("")); + searchBtn.setOnOpListener((JavaScriptCallback) this::menuOpen); + searchBtn.setAction(1, MENU_OPEN); + }) + .build(); + } + + @Subscribe + public void onGameTick(GameTick t) + { + // This has to happen because the only widget that gets hidden is the tli one + Widget fairyRingTeleportButton = client.getWidget(WidgetInfo.FAIRY_RING_TELEPORT_BUTTON); + boolean fairyRingWidgetOpen = fairyRingTeleportButton != null && !fairyRingTeleportButton.isHidden(); + boolean chatboxOpen = searchInput != null && chatboxPanelManager.getCurrentInput() == searchInput; + + if (!fairyRingWidgetOpen && chatboxOpen) + { + chatboxPanelManager.close(); + } + } + + private void updateFilter(String filter) + { + filter = filter.toLowerCase(); + final Widget list = client.getWidget(WidgetInfo.FAIRY_RING_LIST); + final Widget favorites = client.getWidget(WidgetInfo.FAIRY_RING_FAVORITES); + + if (list == null) + { + return; + } + + if (codes != null) + { + // Check to make sure the list hasn't been rebuild since we were last her + // Do this by making sure the list's dynamic children are the same as when we last saw them + if (codes.stream().noneMatch(w -> + { + Widget codeWidget = w.getCode(); + if (codeWidget == null) + { + return false; + } + return list.getChild(codeWidget.getIndex()) == codeWidget; + })) + { + codes = null; + } + } + + if (codes == null) + { + // Find all of the widgets that we care about, grouping by their Y value + Map codeMap = new TreeMap<>(); + + for (Widget w : list.getStaticChildren()) + { + if (w.isSelfHidden()) + { + continue; + } + + if (w.getSpriteId() != -1) + { + codeMap.computeIfAbsent(w.getRelativeY(), k -> new CodeWidgets()).setFavorite(w); + } + else if (!Strings.isNullOrEmpty(w.getText())) + { + codeMap.computeIfAbsent(w.getRelativeY(), k -> new CodeWidgets()).setDescription(w); + } + } + + for (Widget w : list.getDynamicChildren()) + { + if (w.isSelfHidden()) + { + continue; + } + + CodeWidgets c = codeMap.computeIfAbsent(w.getRelativeY(), k -> new CodeWidgets()); + c.setCode(w); + } + + codes = codeMap.values(); + } + + // Relayout the panel + int y = 0; + + if (favorites != null) + { + boolean hide = !filter.isEmpty(); + favorites.setHidden(hide); + if (!hide) + { + y += favorites.getOriginalHeight() + ENTRY_PADDING; + } + } + + for (CodeWidgets c : codes) + { + String code = Text.removeTags(c.getDescription().getName()).replaceAll(" ", ""); + String tags = null; + + if (!code.isEmpty()) + { + try + { + FairyRings ring = FairyRings.valueOf(code); + tags = ring.getTags(); + } + catch (IllegalArgumentException e) + { + log.warn("Unable to find ring with code '{}'", code, e); + } + } + + boolean hidden = !(filter.isEmpty() + || Text.removeTags(c.getDescription().getText()).toLowerCase().contains(filter) + || code.toLowerCase().contains(filter) + || tags != null && tags.contains(filter)); + + if (c.getCode() != null) + { + c.getCode().setHidden(hidden); + c.getCode().setOriginalY(y); + } + + if (c.getFavorite() != null) + { + c.getFavorite().setHidden(hidden); + c.getFavorite().setOriginalY(y); + } + + c.getDescription().setHidden(hidden); + c.getDescription().setOriginalY(y); + + if (!hidden) + { + y += c.getDescription().getHeight() + ENTRY_PADDING; + } + } + + y -= ENTRY_PADDING; + + if (y < 0) + { + y = 0; + } + + int newHeight = 0; + if (list.getScrollHeight() > 0) + { + newHeight = (list.getScrollY() * y) / list.getScrollHeight(); + } + + list.setScrollHeight(y); + list.revalidateScroll(); + client.runScript( + ScriptID.UPDATE_SCROLLBAR, + WidgetInfo.FAIRY_RING_LIST_SCROLLBAR.getId(), + WidgetInfo.FAIRY_RING_LIST.getId(), + newHeight + ); + } +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/fightcave/JadAttack.java b/runelite-client/src/main/java/net/runelite/client/plugins/fightcave/JadAttack.java index 99f8cd2bb3..3da9f544a3 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/fightcave/JadAttack.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/fightcave/JadAttack.java @@ -1,53 +1,53 @@ -/* - * Copyright (c) 2017, Devin French - * 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.fightcave; - -import net.runelite.api.AnimationID; -import net.runelite.api.Prayer; - -public enum JadAttack -{ - MAGIC(AnimationID.TZTOK_JAD_MAGIC_ATTACK, Prayer.PROTECT_FROM_MAGIC), - RANGE(AnimationID.TZTOK_JAD_RANGE_ATTACK, Prayer.PROTECT_FROM_MISSILES); - - private final int animation; - private final Prayer prayer; - - JadAttack(int animation, Prayer prayer) - { - this.animation = animation; - this.prayer = prayer; - } - - public int getAnimation() - { - return animation; - } - - public Prayer getPrayer() - { - return prayer; - } +/* + * Copyright (c) 2017, Devin French + * 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.fightcave; + +import net.runelite.api.AnimationID; +import net.runelite.api.Prayer; + +public enum JadAttack +{ + MAGIC(AnimationID.TZTOK_JAD_MAGIC_ATTACK, Prayer.PROTECT_FROM_MAGIC), + RANGE(AnimationID.TZTOK_JAD_RANGE_ATTACK, Prayer.PROTECT_FROM_MISSILES); + + private final int animation; + private final Prayer prayer; + + JadAttack(int animation, Prayer prayer) + { + this.animation = animation; + this.prayer = prayer; + } + + public int getAnimation() + { + return animation; + } + + public Prayer getPrayer() + { + return prayer; + } } \ No newline at end of file diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/fightcave/JadOverlay.java b/runelite-client/src/main/java/net/runelite/client/plugins/fightcave/JadOverlay.java index 0f31a153a4..b5998e2bfa 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/fightcave/JadOverlay.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/fightcave/JadOverlay.java @@ -1,87 +1,87 @@ -/* - * Copyright (c) 2017, Devin French - * 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.fightcave; - -import java.awt.Color; -import java.awt.Dimension; -import java.awt.Graphics2D; -import java.awt.image.BufferedImage; -import javax.inject.Inject; -import net.runelite.api.Client; -import net.runelite.api.SpriteID; -import net.runelite.client.game.SpriteManager; -import net.runelite.client.ui.overlay.Overlay; -import net.runelite.client.ui.overlay.OverlayPosition; -import net.runelite.client.ui.overlay.OverlayPriority; -import net.runelite.client.ui.overlay.components.ComponentConstants; -import net.runelite.client.ui.overlay.components.ImageComponent; -import net.runelite.client.ui.overlay.components.PanelComponent; - -public class JadOverlay extends Overlay -{ - private static final Color NOT_ACTIVATED_BACKGROUND_COLOR = new Color(150, 0, 0, 150); - - private final Client client; - private final FightCavePlugin plugin; - private final SpriteManager spriteManager; - private final PanelComponent imagePanelComponent = new PanelComponent(); - - @Inject - private JadOverlay(Client client, FightCavePlugin plugin, SpriteManager spriteManager) - { - setPosition(OverlayPosition.BOTTOM_RIGHT); - setPriority(OverlayPriority.HIGH); - this.client = client; - this.plugin = plugin; - this.spriteManager = spriteManager; - } - - @Override - public Dimension render(Graphics2D graphics) - { - final JadAttack attack = plugin.getAttack(); - - if (attack == null) - { - return null; - } - - final BufferedImage prayerImage = getPrayerImage(attack); - - imagePanelComponent.getChildren().clear(); - imagePanelComponent.getChildren().add(new ImageComponent(prayerImage)); - imagePanelComponent.setBackgroundColor(client.isPrayerActive(attack.getPrayer()) - ? ComponentConstants.STANDARD_BACKGROUND_COLOR - : NOT_ACTIVATED_BACKGROUND_COLOR); - - return imagePanelComponent.render(graphics); - } - - private BufferedImage getPrayerImage(JadAttack attack) - { - final int prayerSpriteID = attack == JadAttack.MAGIC ? SpriteID.PRAYER_PROTECT_FROM_MAGIC : SpriteID.PRAYER_PROTECT_FROM_MISSILES; - return spriteManager.getSprite(prayerSpriteID, 0); - } +/* + * Copyright (c) 2017, Devin French + * 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.fightcave; + +import java.awt.Color; +import java.awt.Dimension; +import java.awt.Graphics2D; +import java.awt.image.BufferedImage; +import javax.inject.Inject; +import net.runelite.api.Client; +import net.runelite.api.SpriteID; +import net.runelite.client.game.SpriteManager; +import net.runelite.client.ui.overlay.Overlay; +import net.runelite.client.ui.overlay.OverlayPosition; +import net.runelite.client.ui.overlay.OverlayPriority; +import net.runelite.client.ui.overlay.components.ComponentConstants; +import net.runelite.client.ui.overlay.components.ImageComponent; +import net.runelite.client.ui.overlay.components.PanelComponent; + +public class JadOverlay extends Overlay +{ + private static final Color NOT_ACTIVATED_BACKGROUND_COLOR = new Color(150, 0, 0, 150); + + private final Client client; + private final FightCavePlugin plugin; + private final SpriteManager spriteManager; + private final PanelComponent imagePanelComponent = new PanelComponent(); + + @Inject + private JadOverlay(Client client, FightCavePlugin plugin, SpriteManager spriteManager) + { + setPosition(OverlayPosition.BOTTOM_RIGHT); + setPriority(OverlayPriority.HIGH); + this.client = client; + this.plugin = plugin; + this.spriteManager = spriteManager; + } + + @Override + public Dimension render(Graphics2D graphics) + { + final JadAttack attack = plugin.getAttack(); + + if (attack == null) + { + return null; + } + + final BufferedImage prayerImage = getPrayerImage(attack); + + imagePanelComponent.getChildren().clear(); + imagePanelComponent.getChildren().add(new ImageComponent(prayerImage)); + imagePanelComponent.setBackgroundColor(client.isPrayerActive(attack.getPrayer()) + ? ComponentConstants.STANDARD_BACKGROUND_COLOR + : NOT_ACTIVATED_BACKGROUND_COLOR); + + return imagePanelComponent.render(graphics); + } + + private BufferedImage getPrayerImage(JadAttack attack) + { + final int prayerSpriteID = attack == JadAttack.MAGIC ? SpriteID.PRAYER_PROTECT_FROM_MAGIC : SpriteID.PRAYER_PROTECT_FROM_MISSILES; + return spriteManager.getSprite(prayerSpriteID, 0); + } } \ No newline at end of file diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/fightcave/WaveOverlay.java b/runelite-client/src/main/java/net/runelite/client/plugins/fightcave/WaveOverlay.java index e9c5678bcf..8561919254 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/fightcave/WaveOverlay.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/fightcave/WaveOverlay.java @@ -1,124 +1,125 @@ -/* - * Copyright (c) 2018, Jordan Atwood - * 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.fightcave; - -import java.awt.Color; -import java.awt.Dimension; -import java.awt.Graphics2D; -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; -import java.util.Map; -import javax.inject.Inject; -import net.runelite.client.ui.ColorScheme; -import net.runelite.client.ui.overlay.Overlay; -import net.runelite.client.ui.overlay.OverlayPosition; -import net.runelite.client.ui.overlay.components.LineComponent; -import net.runelite.client.ui.overlay.components.PanelComponent; -import net.runelite.client.ui.overlay.components.TitleComponent; - -class WaveOverlay extends Overlay -{ - private static final Color HEADER_COLOR = ColorScheme.BRAND_ORANGE; - - private final FightCaveConfig config; - private final FightCavePlugin plugin; - - private final PanelComponent panelComponent = new PanelComponent(); - - @Inject - private WaveOverlay(FightCaveConfig config, FightCavePlugin plugin) - { - setPosition(OverlayPosition.TOP_RIGHT); - this.config = config; - this.plugin = plugin; - } - - @Override - public Dimension render(Graphics2D graphics) - { - if (!plugin.inFightCave() - || plugin.getCurrentWave() < 0) - { - return null; - } - - panelComponent.getChildren().clear(); - - final int currentWave = plugin.getCurrentWave(); - final int waveIndex = currentWave - 1; - - if (config.waveDisplay() == WaveDisplayMode.CURRENT - || config.waveDisplay() == WaveDisplayMode.BOTH) - { - final Map waveContents = FightCavePlugin.getWAVES().get(waveIndex); - - addWaveInfo("Wave " + plugin.getCurrentWave(), waveContents); - } - - if ((config.waveDisplay() == WaveDisplayMode.NEXT - || config.waveDisplay() == WaveDisplayMode.BOTH) - && currentWave != FightCavePlugin.MAX_WAVE) - { - final Map waveContents = FightCavePlugin.getWAVES().get(waveIndex + 1); - - addWaveInfo("Next wave", waveContents); - } - - return panelComponent.render(graphics); - } - private void addWaveInfo(final String headerText, final Map waveContents) - { - panelComponent.getChildren().add(TitleComponent.builder() - .text(headerText) - .color(HEADER_COLOR) - .build()); - - for (LineComponent line : buildWaveLines(waveContents)) - { - panelComponent.getChildren().add(line); - } - } - - private static Collection buildWaveLines(final Map wave) - { - final List> monsters = new ArrayList<>(wave.entrySet()); - monsters.sort(Map.Entry.comparingByKey()); - final List outputLines = new ArrayList<>(); - - for (Map.Entry monsterEntry : monsters) - { - final WaveMonster monster = monsterEntry.getKey(); - final int quantity = monsterEntry.getValue(); - final LineComponent line = LineComponent.builder() - .left(FightCavePlugin.formatMonsterQuantity(monster, quantity)) - .build(); - - outputLines.add(line); - } - - return outputLines; - } -} +/* + * Copyright (c) 2018, Jordan Atwood + * 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.fightcave; + +import java.awt.Color; +import java.awt.Dimension; +import java.awt.Graphics2D; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.Map; +import javax.inject.Inject; +import net.runelite.client.ui.ColorScheme; +import net.runelite.client.ui.overlay.Overlay; +import net.runelite.client.ui.overlay.OverlayPosition; +import net.runelite.client.ui.overlay.components.LineComponent; +import net.runelite.client.ui.overlay.components.PanelComponent; +import net.runelite.client.ui.overlay.components.TitleComponent; + +class WaveOverlay extends Overlay +{ + private static final Color HEADER_COLOR = ColorScheme.BRAND_ORANGE; + + private final FightCaveConfig config; + private final FightCavePlugin plugin; + + private final PanelComponent panelComponent = new PanelComponent(); + + @Inject + private WaveOverlay(FightCaveConfig config, FightCavePlugin plugin) + { + setPosition(OverlayPosition.TOP_RIGHT); + this.config = config; + this.plugin = plugin; + } + + @Override + public Dimension render(Graphics2D graphics) + { + if (!plugin.inFightCave() + || plugin.getCurrentWave() < 0) + { + return null; + } + + panelComponent.getChildren().clear(); + + final int currentWave = plugin.getCurrentWave(); + final int waveIndex = currentWave - 1; + + if (config.waveDisplay() == WaveDisplayMode.CURRENT + || config.waveDisplay() == WaveDisplayMode.BOTH) + { + final Map waveContents = FightCavePlugin.getWAVES().get(waveIndex); + + addWaveInfo("Wave " + plugin.getCurrentWave(), waveContents); + } + + if ((config.waveDisplay() == WaveDisplayMode.NEXT + || config.waveDisplay() == WaveDisplayMode.BOTH) + && currentWave != FightCavePlugin.MAX_WAVE) + { + final Map waveContents = FightCavePlugin.getWAVES().get(waveIndex + 1); + + addWaveInfo("Next wave", waveContents); + } + + return panelComponent.render(graphics); + } + + private void addWaveInfo(final String headerText, final Map waveContents) + { + panelComponent.getChildren().add(TitleComponent.builder() + .text(headerText) + .color(HEADER_COLOR) + .build()); + + for (LineComponent line : buildWaveLines(waveContents)) + { + panelComponent.getChildren().add(line); + } + } + + private static Collection buildWaveLines(final Map wave) + { + final List> monsters = new ArrayList<>(wave.entrySet()); + monsters.sort(Map.Entry.comparingByKey()); + final List outputLines = new ArrayList<>(); + + for (Map.Entry monsterEntry : monsters) + { + final WaveMonster monster = monsterEntry.getKey(); + final int quantity = monsterEntry.getValue(); + final LineComponent line = LineComponent.builder() + .left(FightCavePlugin.formatMonsterQuantity(monster, quantity)) + .build(); + + outputLines.add(line); + } + + return outputLines; + } +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/fishing/FishingSpotOverlay.java b/runelite-client/src/main/java/net/runelite/client/plugins/fishing/FishingSpotOverlay.java index 80cdaec1e4..31b2160b3f 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/fishing/FishingSpotOverlay.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/fishing/FishingSpotOverlay.java @@ -1,182 +1,182 @@ -/* - * Copyright (c) 2017, Seth - * 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.fishing; - -import java.awt.Color; -import java.awt.Dimension; -import java.awt.Graphics2D; -import java.awt.Polygon; -import java.awt.image.BufferedImage; -import java.time.Duration; -import java.time.Instant; -import javax.inject.Inject; -import lombok.AccessLevel; -import lombok.Setter; -import net.runelite.api.Client; -import net.runelite.api.GraphicID; -import net.runelite.api.NPC; -import net.runelite.api.Perspective; -import net.runelite.api.Point; -import net.runelite.api.coords.LocalPoint; -import net.runelite.client.game.ItemManager; -import net.runelite.client.ui.overlay.Overlay; -import net.runelite.client.ui.overlay.OverlayLayer; -import net.runelite.client.ui.overlay.OverlayPosition; -import net.runelite.client.ui.overlay.OverlayUtil; -import net.runelite.client.ui.overlay.components.ProgressPieComponent; -import net.runelite.client.util.ImageUtil; - -class FishingSpotOverlay extends Overlay -{ - private static final Duration MINNOW_MOVE = Duration.ofSeconds(15); - private static final Duration MINNOW_WARN = Duration.ofSeconds(3); - private static final int ONE_TICK_AERIAL_FISHING = 3; - - private final FishingPlugin plugin; - private final FishingConfig config; - private final Client client; - private final ItemManager itemManager; - - @Setter(AccessLevel.PACKAGE) - private boolean hidden; - - @Inject - private FishingSpotOverlay(FishingPlugin plugin, FishingConfig config, Client client, ItemManager itemManager) - { - setPosition(OverlayPosition.DYNAMIC); - setLayer(OverlayLayer.ABOVE_SCENE); - this.plugin = plugin; - this.config = config; - this.client = client; - this.itemManager = itemManager; - } - - @Override - public Dimension render(Graphics2D graphics) - { - if (hidden) - { - return null; - } - - for (NPC npc : plugin.getFishingSpots()) - { - FishingSpot spot = FishingSpot.getSPOTS().get(npc.getId()); - - if (spot == null) - { - continue; - } - - if (config.onlyCurrentSpot() && plugin.getCurrentSpot() != null && plugin.getCurrentSpot() != spot) - { - continue; - } - - Color color = npc.getGraphic() == GraphicID.FLYING_FISH ? Color.RED : Color.CYAN; - - if (spot == FishingSpot.MINNOW && config.showMinnowOverlay()) - { - MinnowSpot minnowSpot = plugin.getMinnowSpots().get(npc.getIndex()); - if (minnowSpot != null) - { - long millisLeft = MINNOW_MOVE.toMillis() - Duration.between(minnowSpot.getTime(), Instant.now()).toMillis(); - if (millisLeft < MINNOW_WARN.toMillis()) - { - color = Color.ORANGE; - } - - LocalPoint localPoint = npc.getLocalLocation(); - Point location = Perspective.localToCanvas(client, localPoint, client.getPlane()); - - if (location != null) - { - ProgressPieComponent pie = new ProgressPieComponent(); - pie.setFill(color); - pie.setBorderColor(color); - pie.setPosition(location); - pie.setProgress((float) millisLeft / MINNOW_MOVE.toMillis()); - pie.render(graphics); - } - } - } - - if (config.showSpotTiles()) - { - Polygon poly = npc.getCanvasTilePoly(); - - if (spot == FishingSpot.COMMON_TENCH - && npc.getWorldLocation().distanceTo2D(client.getLocalPlayer().getWorldLocation()) <= ONE_TICK_AERIAL_FISHING) - { - color = Color.GREEN; - } - - if (poly != null) - { - OverlayUtil.renderPolygon(graphics, poly, color.darker()); - } - } - - if (config.showSpotIcons()) - { - BufferedImage fishImage = itemManager.getImage(spot.getFishSpriteId());; - - if (spot == FishingSpot.COMMON_TENCH - && npc.getWorldLocation().distanceTo2D(client.getLocalPlayer().getWorldLocation()) <= ONE_TICK_AERIAL_FISHING) - { - fishImage = ImageUtil.outlineImage(itemManager.getImage(spot.getFishSpriteId()), Color.GREEN); - } - - if (fishImage != null) - { - Point imageLocation = npc.getCanvasImageLocation(fishImage, npc.getLogicalHeight()); - if (imageLocation != null) - { - OverlayUtil.renderImageLocation(graphics, imageLocation, fishImage); - } - } - } - - if (config.showSpotNames()) - { - String text = spot.getName(); - Point textLocation = npc.getCanvasTextLocation(graphics, text, npc.getLogicalHeight() + 40); - - if (spot == FishingSpot.COMMON_TENCH - && npc.getWorldLocation().distanceTo2D(client.getLocalPlayer().getWorldLocation()) <= ONE_TICK_AERIAL_FISHING) - { - color = Color.GREEN; - } - - if (textLocation != null) - { - OverlayUtil.renderTextLocation(graphics, textLocation, text, color.darker()); - } - } - } - - return null; - } -} +/* + * Copyright (c) 2017, Seth + * 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.fishing; + +import java.awt.Color; +import java.awt.Dimension; +import java.awt.Graphics2D; +import java.awt.Polygon; +import java.awt.image.BufferedImage; +import java.time.Duration; +import java.time.Instant; +import javax.inject.Inject; +import lombok.AccessLevel; +import lombok.Setter; +import net.runelite.api.Client; +import net.runelite.api.GraphicID; +import net.runelite.api.NPC; +import net.runelite.api.Perspective; +import net.runelite.api.Point; +import net.runelite.api.coords.LocalPoint; +import net.runelite.client.game.ItemManager; +import net.runelite.client.ui.overlay.Overlay; +import net.runelite.client.ui.overlay.OverlayLayer; +import net.runelite.client.ui.overlay.OverlayPosition; +import net.runelite.client.ui.overlay.OverlayUtil; +import net.runelite.client.ui.overlay.components.ProgressPieComponent; +import net.runelite.client.util.ImageUtil; + +class FishingSpotOverlay extends Overlay +{ + private static final Duration MINNOW_MOVE = Duration.ofSeconds(15); + private static final Duration MINNOW_WARN = Duration.ofSeconds(3); + private static final int ONE_TICK_AERIAL_FISHING = 3; + + private final FishingPlugin plugin; + private final FishingConfig config; + private final Client client; + private final ItemManager itemManager; + + @Setter(AccessLevel.PACKAGE) + private boolean hidden; + + @Inject + private FishingSpotOverlay(FishingPlugin plugin, FishingConfig config, Client client, ItemManager itemManager) + { + setPosition(OverlayPosition.DYNAMIC); + setLayer(OverlayLayer.ABOVE_SCENE); + this.plugin = plugin; + this.config = config; + this.client = client; + this.itemManager = itemManager; + } + + @Override + public Dimension render(Graphics2D graphics) + { + if (hidden) + { + return null; + } + + for (NPC npc : plugin.getFishingSpots()) + { + FishingSpot spot = FishingSpot.getSPOTS().get(npc.getId()); + + if (spot == null) + { + continue; + } + + if (config.onlyCurrentSpot() && plugin.getCurrentSpot() != null && plugin.getCurrentSpot() != spot) + { + continue; + } + + Color color = npc.getGraphic() == GraphicID.FLYING_FISH ? Color.RED : Color.CYAN; + + if (spot == FishingSpot.MINNOW && config.showMinnowOverlay()) + { + MinnowSpot minnowSpot = plugin.getMinnowSpots().get(npc.getIndex()); + if (minnowSpot != null) + { + long millisLeft = MINNOW_MOVE.toMillis() - Duration.between(minnowSpot.getTime(), Instant.now()).toMillis(); + if (millisLeft < MINNOW_WARN.toMillis()) + { + color = Color.ORANGE; + } + + LocalPoint localPoint = npc.getLocalLocation(); + Point location = Perspective.localToCanvas(client, localPoint, client.getPlane()); + + if (location != null) + { + ProgressPieComponent pie = new ProgressPieComponent(); + pie.setFill(color); + pie.setBorderColor(color); + pie.setPosition(location); + pie.setProgress((float) millisLeft / MINNOW_MOVE.toMillis()); + pie.render(graphics); + } + } + } + + if (config.showSpotTiles()) + { + Polygon poly = npc.getCanvasTilePoly(); + + if (spot == FishingSpot.COMMON_TENCH + && npc.getWorldLocation().distanceTo2D(client.getLocalPlayer().getWorldLocation()) <= ONE_TICK_AERIAL_FISHING) + { + color = Color.GREEN; + } + + if (poly != null) + { + OverlayUtil.renderPolygon(graphics, poly, color.darker()); + } + } + + if (config.showSpotIcons()) + { + BufferedImage fishImage = itemManager.getImage(spot.getFishSpriteId()); + + if (spot == FishingSpot.COMMON_TENCH + && npc.getWorldLocation().distanceTo2D(client.getLocalPlayer().getWorldLocation()) <= ONE_TICK_AERIAL_FISHING) + { + fishImage = ImageUtil.outlineImage(itemManager.getImage(spot.getFishSpriteId()), Color.GREEN); + } + + if (fishImage != null) + { + Point imageLocation = npc.getCanvasImageLocation(fishImage, npc.getLogicalHeight()); + if (imageLocation != null) + { + OverlayUtil.renderImageLocation(graphics, imageLocation, fishImage); + } + } + } + + if (config.showSpotNames()) + { + String text = spot.getName(); + Point textLocation = npc.getCanvasTextLocation(graphics, text, npc.getLogicalHeight() + 40); + + if (spot == FishingSpot.COMMON_TENCH + && npc.getWorldLocation().distanceTo2D(client.getLocalPlayer().getWorldLocation()) <= ONE_TICK_AERIAL_FISHING) + { + color = Color.GREEN; + } + + if (textLocation != null) + { + OverlayUtil.renderTextLocation(graphics, textLocation, text, color.darker()); + } + } + } + + return null; + } +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/flexo/FlexoOverlay.java b/runelite-client/src/main/java/net/runelite/client/plugins/flexo/FlexoOverlay.java index daf2d69c67..4c145ae303 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/flexo/FlexoOverlay.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/flexo/FlexoOverlay.java @@ -34,9 +34,7 @@ import java.awt.Point; import java.awt.Rectangle; import java.awt.geom.Line2D; import java.util.ArrayList; -import javax.annotation.Nullable; import javax.inject.Inject; -import net.runelite.api.Client; import net.runelite.client.ui.overlay.Overlay; import net.runelite.client.ui.overlay.OverlayLayer; import net.runelite.client.ui.overlay.OverlayPosition; diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/fps/FpsDrawListener.java b/runelite-client/src/main/java/net/runelite/client/plugins/fps/FpsDrawListener.java index 3be17f5577..2ee44ed9ac 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/fps/FpsDrawListener.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/fps/FpsDrawListener.java @@ -36,7 +36,7 @@ import net.runelite.api.events.FocusChanged; * For low powered computers, the RS client is often throttled by the hardware or OS and draws at 25-30 fps. * The nano timer is not used in this scenario. * Instead to catch up the RS client runs several cycles before drawing, thus maintaining 50 cycles / second. - * + *

* Enforcing FPS in the draw code does not impact the client engine's ability to run including its audio, * even when forced to 1 FPS with this plugin. */ diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/freezetimers/PlayerSpellEffect.java b/runelite-client/src/main/java/net/runelite/client/plugins/freezetimers/PlayerSpellEffect.java index 41df487ee8..3f83335d19 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/freezetimers/PlayerSpellEffect.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/freezetimers/PlayerSpellEffect.java @@ -57,10 +57,12 @@ public enum PlayerSpellEffect public static PlayerSpellEffect getFromSpotAnim(int spotAnim) { - for(PlayerSpellEffect effect : values()) + for (PlayerSpellEffect effect : values()) { - if(effect.getSpotAnimId() == spotAnim) + if (effect.getSpotAnimId() == spotAnim) + { return effect; + } } return NONE; } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/friendtagging/FriendTaggingPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/friendtagging/FriendTaggingPlugin.java index 1352b351bb..896363e681 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/friendtagging/FriendTaggingPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/friendtagging/FriendTaggingPlugin.java @@ -11,8 +11,7 @@ package net.runelite.client.plugins.friendtagging; import com.google.common.base.Strings; import com.google.common.collect.ObjectArrays; - -import java.awt.*; +import java.awt.Toolkit; import java.awt.datatransfer.StringSelection; import java.util.Arrays; import java.util.HashSet; @@ -21,8 +20,17 @@ import java.util.concurrent.ConcurrentHashMap; import javax.inject.Inject; import lombok.NonNull; import lombok.extern.slf4j.Slf4j; -import net.runelite.api.*; -import net.runelite.api.events.*; +import net.runelite.api.Client; +import net.runelite.api.Friend; +import net.runelite.api.Ignore; +import net.runelite.api.MenuAction; +import net.runelite.api.MenuEntry; +import net.runelite.api.Nameable; +import net.runelite.api.events.MenuEntryAdded; +import net.runelite.api.events.MenuOptionClicked; +import net.runelite.api.events.NameableNameChanged; +import net.runelite.api.events.RemovedFriend; +import net.runelite.api.events.WidgetMenuOptionClicked; import net.runelite.api.widgets.WidgetInfo; import net.runelite.client.config.ConfigManager; import net.runelite.client.eventbus.Subscribe; @@ -40,8 +48,8 @@ import org.apache.commons.lang3.ArrayUtils; @PluginDescriptor( name = "Friend Tagging", description = "Tag people on your friends list.", - tags = {"PVP", "friend", "finder", "pk", "pklite"}, - type = PluginType.UTILITY + tags = {"PVP", "friend", "finder", "pk", "pklite"}, + type = PluginType.UTILITY ) public class FriendTaggingPlugin extends Plugin { @@ -267,8 +275,8 @@ public class FriendTaggingPlugin extends Plugin } /** - * This method combines the list of usernames on local players friend/ignore list into a comma delimited string - * and then copies it to the clipboard. + * This method combines the list of usernames on local players friend/ignore list into a comma delimited string + * and then copies it to the clipboard. */ private void friendIgnoreToClipboard() { diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/gpu/GpuPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/gpu/GpuPlugin.java index 80d37e7566..449f1b5441 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/gpu/GpuPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/gpu/GpuPlugin.java @@ -74,7 +74,18 @@ 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.*; +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.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.glGetInteger; +import static net.runelite.client.plugins.gpu.GLUtil.inputStreamToString; import net.runelite.client.plugins.gpu.config.AntiAliasingMode; import net.runelite.client.plugins.gpu.template.Template; import net.runelite.client.ui.DrawManager; @@ -414,8 +425,8 @@ public class GpuPlugin extends Plugin implements DrawCallbacks { glVersionHeader = "#version 420\n" + - "#extension GL_ARB_compute_shader : require\n" + - "#extension GL_ARB_shader_storage_buffer_object : require\n"; + "#extension GL_ARB_compute_shader : require\n" + + "#extension GL_ARB_shader_storage_buffer_object : require\n"; } else { @@ -707,8 +718,8 @@ public class GpuPlugin extends Plugin implements DrawCallbacks } public void drawScenePaint(int orientation, int pitchSin, int pitchCos, int yawSin, int yawCos, int x, int y, int z, - SceneTilePaint paint, int tileZ, int tileX, int tileY, - int zoom, int centerX, int centerY) + SceneTilePaint paint, int tileZ, int tileX, int tileY, + int zoom, int centerX, int centerY) { if (paint.getBufferLen() > 0) { @@ -733,8 +744,8 @@ public class GpuPlugin extends Plugin implements DrawCallbacks } public void drawSceneModel(int orientation, int pitchSin, int pitchCos, int yawSin, int yawCos, int x, int y, int z, - SceneTileModel model, int tileZ, int tileX, int tileY, - int zoom, int centerX, int centerY) + SceneTileModel model, int tileZ, int tileX, int tileY, + int zoom, int centerX, int centerY) { if (model.getBufferLen() > 0) { @@ -980,18 +991,18 @@ public class GpuPlugin extends Plugin implements DrawCallbacks renderCanvasHeight = dim.height; double scaleFactorY = dim.getHeight() / canvasHeight; - double scaleFactorX = dim.getWidth() / canvasWidth; + double scaleFactorX = dim.getWidth() / canvasWidth; // Pad the viewport a little because having ints for our viewport dimensions can introduce off-by-one errors. final int padding = 1; // Ceil the sizes because even if the size is 599.1 we want to treat it as size 600 (i.e. render to the x=599 pixel). renderViewportHeight = (int) Math.ceil(scaleFactorY * (renderViewportHeight)) + padding * 2; - renderViewportWidth = (int) Math.ceil(scaleFactorX * (renderViewportWidth )) + padding * 2; + renderViewportWidth = (int) Math.ceil(scaleFactorX * (renderViewportWidth)) + padding * 2; // Floor the offsets because even if the offset is 4.9, we want to render to the x=4 pixel anyway. - renderHeightOff = (int) Math.floor(scaleFactorY * (renderHeightOff)) - padding; - renderWidthOff = (int) Math.floor(scaleFactorX * (renderWidthOff )) - padding; + renderHeightOff = (int) Math.floor(scaleFactorY * (renderHeightOff)) - padding; + renderWidthOff = (int) Math.floor(scaleFactorX * (renderWidthOff)) - padding; } glDpiAwareViewport(renderWidthOff, renderCanvasHeight - renderViewportHeight - renderHeightOff, renderViewportWidth, renderViewportHeight); @@ -1169,13 +1180,13 @@ public class GpuPlugin extends Plugin implements DrawCallbacks */ private Image screenshot() { - int width = client.getCanvasWidth(); + int width = client.getCanvasWidth(); int height = client.getCanvasHeight(); if (client.isStretchedEnabled()) { Dimension dim = client.getStretchedDimensions(); - width = dim.width; + width = dim.width; height = dim.height; } @@ -1295,10 +1306,7 @@ public class GpuPlugin extends Plugin implements DrawCallbacks { int var21 = (pitchCos * modelHeight >> 16) + var19; int var22 = (var18 - var21) * zoom; - if (var22 / var14 < Rasterizer3D_clipMidY2) - { - return true; - } + return var22 / var14 < Rasterizer3D_clipMidY2; } } } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/gpu/GpuPluginConfig.java b/runelite-client/src/main/java/net/runelite/client/plugins/gpu/GpuPluginConfig.java index 94878c69dc..4d8c2b1801 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/gpu/GpuPluginConfig.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/gpu/GpuPluginConfig.java @@ -1,87 +1,87 @@ -/* - * Copyright (c) 2018, Adam - * 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.gpu; - -import net.runelite.client.config.Config; -import net.runelite.client.config.ConfigGroup; -import net.runelite.client.config.ConfigItem; -import net.runelite.client.config.Range; -import static net.runelite.client.plugins.gpu.GpuPlugin.MAX_FOG_DEPTH; -import net.runelite.client.plugins.gpu.config.AntiAliasingMode; -import static net.runelite.client.plugins.gpu.GpuPlugin.MAX_DISTANCE; - -@ConfigGroup("gpu") -public interface GpuPluginConfig extends Config -{ - @Range( - max = MAX_DISTANCE - ) - @ConfigItem( - keyName = "drawDistance", - name = "Draw Distance", - description = "Draw distance", - position = 1 - ) - default int drawDistance() - { - return 25; - } - - @ConfigItem( - keyName = "smoothBanding", - name = "Remove Color Banding", - description = "Smooths out the color banding that is present in the CPU renderer", - position = 2 - ) - default boolean smoothBanding() - { - return false; - } - - @ConfigItem( - keyName = "antiAliasingMode", - name = "Anti Aliasing", - description = "Configures the anti-aliasing mode", - position = 3 - ) - default AntiAliasingMode antiAliasingMode() - { - return AntiAliasingMode.DISABLED; - } - - @Range( - max = MAX_FOG_DEPTH - ) - @ConfigItem( - keyName = "fogDepth", - name = "Fog depth", - description = "Distance from the scene edge the fog starts", - position = 4 - ) - default int fogDepth() - { - return 0; - } -} +/* + * Copyright (c) 2018, Adam + * 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.gpu; + +import net.runelite.client.config.Config; +import net.runelite.client.config.ConfigGroup; +import net.runelite.client.config.ConfigItem; +import net.runelite.client.config.Range; +import static net.runelite.client.plugins.gpu.GpuPlugin.MAX_DISTANCE; +import static net.runelite.client.plugins.gpu.GpuPlugin.MAX_FOG_DEPTH; +import net.runelite.client.plugins.gpu.config.AntiAliasingMode; + +@ConfigGroup("gpu") +public interface GpuPluginConfig extends Config +{ + @Range( + max = MAX_DISTANCE + ) + @ConfigItem( + keyName = "drawDistance", + name = "Draw Distance", + description = "Draw distance", + position = 1 + ) + default int drawDistance() + { + return 25; + } + + @ConfigItem( + keyName = "smoothBanding", + name = "Remove Color Banding", + description = "Smooths out the color banding that is present in the CPU renderer", + position = 2 + ) + default boolean smoothBanding() + { + return false; + } + + @ConfigItem( + keyName = "antiAliasingMode", + name = "Anti Aliasing", + description = "Configures the anti-aliasing mode", + position = 3 + ) + default AntiAliasingMode antiAliasingMode() + { + return AntiAliasingMode.DISABLED; + } + + @Range( + max = MAX_FOG_DEPTH + ) + @ConfigItem( + keyName = "fogDepth", + name = "Fog depth", + description = "Distance from the scene edge the fog starts", + position = 4 + ) + default int fogDepth() + { + return 0; + } +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/grandexchange/GrandExchangeOfferSlot.java b/runelite-client/src/main/java/net/runelite/client/plugins/grandexchange/GrandExchangeOfferSlot.java index 14090170fe..1b7c3d2f76 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/grandexchange/GrandExchangeOfferSlot.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/grandexchange/GrandExchangeOfferSlot.java @@ -1,277 +1,277 @@ -/* - * Copyright (c) 2018, SomeoneWithAnInternetConnection - * Copyright (c) 2018, Psikoi - * 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 java.awt.BorderLayout; -import java.awt.CardLayout; -import java.awt.Color; -import java.awt.Component; -import java.awt.Dimension; -import java.awt.GridLayout; -import java.awt.event.MouseAdapter; -import java.awt.event.MouseEvent; -import java.awt.event.MouseListener; -import java.awt.image.BufferedImage; -import javax.annotation.Nullable; -import javax.swing.ImageIcon; -import javax.swing.JLabel; -import javax.swing.JPanel; -import javax.swing.border.EmptyBorder; -import net.runelite.api.GrandExchangeOffer; -import net.runelite.api.GrandExchangeOfferState; -import static net.runelite.api.GrandExchangeOfferState.CANCELLED_BUY; -import static net.runelite.api.GrandExchangeOfferState.CANCELLED_SELL; -import static net.runelite.api.GrandExchangeOfferState.EMPTY; -import net.runelite.api.ItemComposition; -import net.runelite.client.ui.ColorScheme; -import net.runelite.client.ui.FontManager; -import net.runelite.client.ui.components.ThinProgressBar; -import net.runelite.client.util.ColorUtil; -import net.runelite.client.util.ImageUtil; -import net.runelite.client.util.StackFormatter; - -public class GrandExchangeOfferSlot extends JPanel -{ - private static final String FACE_CARD = "FACE_CARD"; - private static final String DETAILS_CARD = "DETAILS_CARD"; - - private static final ImageIcon RIGHT_ARROW_ICON; - private static final ImageIcon LEFT_ARROW_ICON; - - private final JPanel container = new JPanel(); - private final CardLayout cardLayout = new CardLayout(); - - private final JLabel itemIcon = new JLabel(); - private final JLabel itemName = new JLabel(); - private final JLabel offerInfo = new JLabel(); - - private final JLabel itemPrice = new JLabel(); - private final JLabel offerSpent = new JLabel(); - - private final ThinProgressBar progressBar = new ThinProgressBar(); - - private boolean showingFace = true; - - static - { - final BufferedImage rightArrow = ImageUtil.alphaOffset(ImageUtil.getResourceStreamFromClass(GrandExchangeOfferSlot.class, "/util/arrow_right.png"), 0.25f); - RIGHT_ARROW_ICON = new ImageIcon(rightArrow); - LEFT_ARROW_ICON = new ImageIcon(ImageUtil.flipImage(rightArrow, true, false)); - } - - /** - * This (sub)panel is used for each GE slot displayed - * in the sidebar - */ - GrandExchangeOfferSlot() - { - setLayout(new BorderLayout()); - setBackground(ColorScheme.DARK_GRAY_COLOR); - setBorder(new EmptyBorder(7, 0, 0, 0)); - - final MouseListener ml = new MouseAdapter() - { - @Override - public void mousePressed(MouseEvent mouseEvent) - { - super.mousePressed(mouseEvent); - switchPanel(); - } - - @Override - public void mouseEntered(MouseEvent mouseEvent) - { - super.mouseEntered(mouseEvent); - container.setBackground(ColorScheme.DARKER_GRAY_HOVER_COLOR); - } - - @Override - public void mouseExited(MouseEvent mouseEvent) - { - super.mouseExited(mouseEvent); - container.setBackground(ColorScheme.DARKER_GRAY_COLOR); - } - }; - - container.setLayout(cardLayout); - container.setBackground(ColorScheme.DARKER_GRAY_COLOR); - - JPanel faceCard = new JPanel(); - faceCard.setBackground(ColorScheme.DARKER_GRAY_COLOR); - faceCard.setLayout(new BorderLayout()); - faceCard.addMouseListener(ml); - - itemIcon.setVerticalAlignment(JLabel.CENTER); - itemIcon.setHorizontalAlignment(JLabel.CENTER); - itemIcon.setPreferredSize(new Dimension(45, 45)); - - itemName.setForeground(Color.WHITE); - itemName.setVerticalAlignment(JLabel.BOTTOM); - itemName.setFont(FontManager.getRunescapeSmallFont()); - - offerInfo.setForeground(ColorScheme.LIGHT_GRAY_COLOR); - offerInfo.setVerticalAlignment(JLabel.TOP); - offerInfo.setFont(FontManager.getRunescapeSmallFont()); - - JLabel switchFaceViewIcon = new JLabel(); - switchFaceViewIcon.setIcon(RIGHT_ARROW_ICON); - switchFaceViewIcon.setVerticalAlignment(JLabel.CENTER); - switchFaceViewIcon.setHorizontalAlignment(JLabel.CENTER); - switchFaceViewIcon.setPreferredSize(new Dimension(30, 45)); - - JPanel offerFaceDetails = new JPanel(); - offerFaceDetails.setBackground(ColorScheme.DARKER_GRAY_COLOR); - offerFaceDetails.setLayout(new GridLayout(2, 1, 0, 2)); - - offerFaceDetails.add(itemName); - offerFaceDetails.add(offerInfo); - - faceCard.add(offerFaceDetails, BorderLayout.CENTER); - faceCard.add(itemIcon, BorderLayout.WEST); - faceCard.add(switchFaceViewIcon, BorderLayout.EAST); - - JPanel detailsCard = new JPanel(); - detailsCard.setBackground(ColorScheme.DARKER_GRAY_COLOR); - detailsCard.setLayout(new BorderLayout()); - detailsCard.setBorder(new EmptyBorder(0, 15, 0, 0)); - detailsCard.addMouseListener(ml); - - itemPrice.setForeground(Color.WHITE); - itemPrice.setVerticalAlignment(JLabel.BOTTOM); - itemPrice.setFont(FontManager.getRunescapeSmallFont()); - - offerSpent.setForeground(Color.WHITE); - offerSpent.setVerticalAlignment(JLabel.TOP); - offerSpent.setFont(FontManager.getRunescapeSmallFont()); - - JLabel switchDetailsViewIcon = new JLabel(); - switchDetailsViewIcon.setIcon(LEFT_ARROW_ICON); - switchDetailsViewIcon.setVerticalAlignment(JLabel.CENTER); - switchDetailsViewIcon.setHorizontalAlignment(JLabel.CENTER); - switchDetailsViewIcon.setPreferredSize(new Dimension(30, 45)); - - JPanel offerDetails = new JPanel(); - offerDetails.setBackground(ColorScheme.DARKER_GRAY_COLOR); - offerDetails.setLayout(new GridLayout(2, 1)); - - offerDetails.add(itemPrice); - offerDetails.add(offerSpent); - - detailsCard.add(offerDetails, BorderLayout.CENTER); - detailsCard.add(switchDetailsViewIcon, BorderLayout.EAST); - - container.add(faceCard, FACE_CARD); - container.add(detailsCard, DETAILS_CARD); - - cardLayout.show(container, FACE_CARD); - - add(container, BorderLayout.CENTER); - add(progressBar, BorderLayout.SOUTH); - } - - void updateOffer(ItemComposition offerItem, BufferedImage itemImage, @Nullable GrandExchangeOffer newOffer) - { - if (newOffer == null || newOffer.getState() == EMPTY) - { - return; - } - else - { - cardLayout.show(container, FACE_CARD); - - itemName.setText(offerItem.getName()); - itemIcon.setIcon(new ImageIcon(itemImage)); - - boolean buying = newOffer.getState() == GrandExchangeOfferState.BOUGHT - || newOffer.getState() == GrandExchangeOfferState.BUYING - || newOffer.getState() == GrandExchangeOfferState.CANCELLED_BUY; - - String offerState = (buying ? "Bought " : "Sold ") - + StackFormatter.quantityToRSDecimalStack(newOffer.getQuantitySold()) + " / " - + StackFormatter.quantityToRSDecimalStack(newOffer.getTotalQuantity()); - - offerInfo.setText(offerState); - - itemPrice.setText(htmlLabel("Price each: ", StackFormatter.formatNumber(newOffer.getPrice()))); - - String action = buying ? "Spent: " : "Received: "; - - offerSpent.setText(htmlLabel(action, StackFormatter.formatNumber(newOffer.getSpent()) + " / " - + StackFormatter.formatNumber(newOffer.getPrice() * newOffer.getTotalQuantity()))); - - progressBar.setForeground(getProgressColor(newOffer)); - progressBar.setMaximumValue(newOffer.getTotalQuantity()); - progressBar.setValue(newOffer.getQuantitySold()); - - /* Couldn't set the tooltip for the container panel as the children override it, so I'm setting - * the tooltips on the children instead. */ - for (Component c : container.getComponents()) - { - if (c instanceof JPanel) - { - JPanel panel = (JPanel) c; - panel.setToolTipText(htmlTooltip(((int) progressBar.getPercentage()) + "%")); - } - } - } - - revalidate(); - repaint(); - } - - private String htmlTooltip(String value) - { - return "Progress: " + value + ""; - } - - private String htmlLabel(String key, String value) - { - return "" + key + "" + value + ""; - } - - private void switchPanel() - { - this.showingFace = !this.showingFace; - cardLayout.show(container, showingFace ? FACE_CARD : DETAILS_CARD); - } - - private Color getProgressColor(GrandExchangeOffer offer) - { - if (offer.getState() == CANCELLED_BUY || offer.getState() == CANCELLED_SELL) - { - return ColorScheme.PROGRESS_ERROR_COLOR; - } - - if (offer.getQuantitySold() == offer.getTotalQuantity()) - { - return ColorScheme.PROGRESS_COMPLETE_COLOR; - } - - return ColorScheme.PROGRESS_INPROGRESS_COLOR; - } -} - +/* + * Copyright (c) 2018, SomeoneWithAnInternetConnection + * Copyright (c) 2018, Psikoi + * 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 java.awt.BorderLayout; +import java.awt.CardLayout; +import java.awt.Color; +import java.awt.Component; +import java.awt.Dimension; +import java.awt.GridLayout; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import java.awt.event.MouseListener; +import java.awt.image.BufferedImage; +import javax.annotation.Nullable; +import javax.swing.ImageIcon; +import javax.swing.JLabel; +import javax.swing.JPanel; +import javax.swing.border.EmptyBorder; +import net.runelite.api.GrandExchangeOffer; +import net.runelite.api.GrandExchangeOfferState; +import static net.runelite.api.GrandExchangeOfferState.CANCELLED_BUY; +import static net.runelite.api.GrandExchangeOfferState.CANCELLED_SELL; +import static net.runelite.api.GrandExchangeOfferState.EMPTY; +import net.runelite.api.ItemComposition; +import net.runelite.client.ui.ColorScheme; +import net.runelite.client.ui.FontManager; +import net.runelite.client.ui.components.ThinProgressBar; +import net.runelite.client.util.ColorUtil; +import net.runelite.client.util.ImageUtil; +import net.runelite.client.util.StackFormatter; + +public class GrandExchangeOfferSlot extends JPanel +{ + private static final String FACE_CARD = "FACE_CARD"; + private static final String DETAILS_CARD = "DETAILS_CARD"; + + private static final ImageIcon RIGHT_ARROW_ICON; + private static final ImageIcon LEFT_ARROW_ICON; + + private final JPanel container = new JPanel(); + private final CardLayout cardLayout = new CardLayout(); + + private final JLabel itemIcon = new JLabel(); + private final JLabel itemName = new JLabel(); + private final JLabel offerInfo = new JLabel(); + + private final JLabel itemPrice = new JLabel(); + private final JLabel offerSpent = new JLabel(); + + private final ThinProgressBar progressBar = new ThinProgressBar(); + + private boolean showingFace = true; + + static + { + final BufferedImage rightArrow = ImageUtil.alphaOffset(ImageUtil.getResourceStreamFromClass(GrandExchangeOfferSlot.class, "/util/arrow_right.png"), 0.25f); + RIGHT_ARROW_ICON = new ImageIcon(rightArrow); + LEFT_ARROW_ICON = new ImageIcon(ImageUtil.flipImage(rightArrow, true, false)); + } + + /** + * This (sub)panel is used for each GE slot displayed + * in the sidebar + */ + GrandExchangeOfferSlot() + { + setLayout(new BorderLayout()); + setBackground(ColorScheme.DARK_GRAY_COLOR); + setBorder(new EmptyBorder(7, 0, 0, 0)); + + final MouseListener ml = new MouseAdapter() + { + @Override + public void mousePressed(MouseEvent mouseEvent) + { + super.mousePressed(mouseEvent); + switchPanel(); + } + + @Override + public void mouseEntered(MouseEvent mouseEvent) + { + super.mouseEntered(mouseEvent); + container.setBackground(ColorScheme.DARKER_GRAY_HOVER_COLOR); + } + + @Override + public void mouseExited(MouseEvent mouseEvent) + { + super.mouseExited(mouseEvent); + container.setBackground(ColorScheme.DARKER_GRAY_COLOR); + } + }; + + container.setLayout(cardLayout); + container.setBackground(ColorScheme.DARKER_GRAY_COLOR); + + JPanel faceCard = new JPanel(); + faceCard.setBackground(ColorScheme.DARKER_GRAY_COLOR); + faceCard.setLayout(new BorderLayout()); + faceCard.addMouseListener(ml); + + itemIcon.setVerticalAlignment(JLabel.CENTER); + itemIcon.setHorizontalAlignment(JLabel.CENTER); + itemIcon.setPreferredSize(new Dimension(45, 45)); + + itemName.setForeground(Color.WHITE); + itemName.setVerticalAlignment(JLabel.BOTTOM); + itemName.setFont(FontManager.getRunescapeSmallFont()); + + offerInfo.setForeground(ColorScheme.LIGHT_GRAY_COLOR); + offerInfo.setVerticalAlignment(JLabel.TOP); + offerInfo.setFont(FontManager.getRunescapeSmallFont()); + + JLabel switchFaceViewIcon = new JLabel(); + switchFaceViewIcon.setIcon(RIGHT_ARROW_ICON); + switchFaceViewIcon.setVerticalAlignment(JLabel.CENTER); + switchFaceViewIcon.setHorizontalAlignment(JLabel.CENTER); + switchFaceViewIcon.setPreferredSize(new Dimension(30, 45)); + + JPanel offerFaceDetails = new JPanel(); + offerFaceDetails.setBackground(ColorScheme.DARKER_GRAY_COLOR); + offerFaceDetails.setLayout(new GridLayout(2, 1, 0, 2)); + + offerFaceDetails.add(itemName); + offerFaceDetails.add(offerInfo); + + faceCard.add(offerFaceDetails, BorderLayout.CENTER); + faceCard.add(itemIcon, BorderLayout.WEST); + faceCard.add(switchFaceViewIcon, BorderLayout.EAST); + + JPanel detailsCard = new JPanel(); + detailsCard.setBackground(ColorScheme.DARKER_GRAY_COLOR); + detailsCard.setLayout(new BorderLayout()); + detailsCard.setBorder(new EmptyBorder(0, 15, 0, 0)); + detailsCard.addMouseListener(ml); + + itemPrice.setForeground(Color.WHITE); + itemPrice.setVerticalAlignment(JLabel.BOTTOM); + itemPrice.setFont(FontManager.getRunescapeSmallFont()); + + offerSpent.setForeground(Color.WHITE); + offerSpent.setVerticalAlignment(JLabel.TOP); + offerSpent.setFont(FontManager.getRunescapeSmallFont()); + + JLabel switchDetailsViewIcon = new JLabel(); + switchDetailsViewIcon.setIcon(LEFT_ARROW_ICON); + switchDetailsViewIcon.setVerticalAlignment(JLabel.CENTER); + switchDetailsViewIcon.setHorizontalAlignment(JLabel.CENTER); + switchDetailsViewIcon.setPreferredSize(new Dimension(30, 45)); + + JPanel offerDetails = new JPanel(); + offerDetails.setBackground(ColorScheme.DARKER_GRAY_COLOR); + offerDetails.setLayout(new GridLayout(2, 1)); + + offerDetails.add(itemPrice); + offerDetails.add(offerSpent); + + detailsCard.add(offerDetails, BorderLayout.CENTER); + detailsCard.add(switchDetailsViewIcon, BorderLayout.EAST); + + container.add(faceCard, FACE_CARD); + container.add(detailsCard, DETAILS_CARD); + + cardLayout.show(container, FACE_CARD); + + add(container, BorderLayout.CENTER); + add(progressBar, BorderLayout.SOUTH); + } + + void updateOffer(ItemComposition offerItem, BufferedImage itemImage, @Nullable GrandExchangeOffer newOffer) + { + if (newOffer == null || newOffer.getState() == EMPTY) + { + return; + } + else + { + cardLayout.show(container, FACE_CARD); + + itemName.setText(offerItem.getName()); + itemIcon.setIcon(new ImageIcon(itemImage)); + + boolean buying = newOffer.getState() == GrandExchangeOfferState.BOUGHT + || newOffer.getState() == GrandExchangeOfferState.BUYING + || newOffer.getState() == GrandExchangeOfferState.CANCELLED_BUY; + + String offerState = (buying ? "Bought " : "Sold ") + + StackFormatter.quantityToRSDecimalStack(newOffer.getQuantitySold()) + " / " + + StackFormatter.quantityToRSDecimalStack(newOffer.getTotalQuantity()); + + offerInfo.setText(offerState); + + itemPrice.setText(htmlLabel("Price each: ", StackFormatter.formatNumber(newOffer.getPrice()))); + + String action = buying ? "Spent: " : "Received: "; + + offerSpent.setText(htmlLabel(action, StackFormatter.formatNumber(newOffer.getSpent()) + " / " + + StackFormatter.formatNumber(newOffer.getPrice() * newOffer.getTotalQuantity()))); + + progressBar.setForeground(getProgressColor(newOffer)); + progressBar.setMaximumValue(newOffer.getTotalQuantity()); + progressBar.setValue(newOffer.getQuantitySold()); + + /* Couldn't set the tooltip for the container panel as the children override it, so I'm setting + * the tooltips on the children instead. */ + for (Component c : container.getComponents()) + { + if (c instanceof JPanel) + { + JPanel panel = (JPanel) c; + panel.setToolTipText(htmlTooltip(((int) progressBar.getPercentage()) + "%")); + } + } + } + + revalidate(); + repaint(); + } + + private String htmlTooltip(String value) + { + return "Progress: " + value + ""; + } + + private String htmlLabel(String key, String value) + { + return "" + key + "" + value + ""; + } + + private void switchPanel() + { + this.showingFace = !this.showingFace; + cardLayout.show(container, showingFace ? FACE_CARD : DETAILS_CARD); + } + + private Color getProgressColor(GrandExchangeOffer offer) + { + if (offer.getState() == CANCELLED_BUY || offer.getState() == CANCELLED_SELL) + { + return ColorScheme.PROGRESS_ERROR_COLOR; + } + + if (offer.getQuantitySold() == offer.getTotalQuantity()) + { + return ColorScheme.PROGRESS_COMPLETE_COLOR; + } + + return ColorScheme.PROGRESS_INPROGRESS_COLOR; + } +} + diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/grandexchange/GrandExchangePlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/grandexchange/GrandExchangePlugin.java index 01fde6181d..d6ed26161e 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/grandexchange/GrandExchangePlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/grandexchange/GrandExchangePlugin.java @@ -1,497 +1,497 @@ -/* - * Copyright (c) 2019, Adam - * Copyright (c) 2017, Robbie - * Copyright (c) 2018, SomeoneWithAnInternetConnection - * 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 com.google.common.reflect.TypeToken; -import com.google.gson.Gson; -import com.google.inject.Provides; -import java.awt.image.BufferedImage; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.util.Map; -import java.util.concurrent.ScheduledExecutorService; -import javax.inject.Inject; -import javax.swing.SwingUtilities; -import lombok.AccessLevel; -import lombok.Getter; -import lombok.Setter; -import lombok.extern.slf4j.Slf4j; -import net.runelite.api.ChatMessageType; -import net.runelite.api.Client; -import net.runelite.api.GameState; -import net.runelite.api.GrandExchangeOffer; -import net.runelite.api.GrandExchangeOfferState; -import net.runelite.api.ItemComposition; -import net.runelite.api.MenuAction; -import net.runelite.api.MenuEntry; -import net.runelite.api.events.ChatMessage; -import net.runelite.api.events.ConfigChanged; -import net.runelite.api.events.FocusChanged; -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; -import net.runelite.client.input.KeyManager; -import net.runelite.client.input.MouseManager; -import net.runelite.client.plugins.Plugin; -import net.runelite.client.plugins.PluginDescriptor; -import net.runelite.client.ui.ClientToolbar; -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.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", - description = "Provide additional and/or easier access to Grand Exchange information", - tags = {"external", "integration", "notifications", "panel", "prices", "trade"} -) -@Slf4j -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 OSBGrandExchangeClient CLIENT = new OSBGrandExchangeClient(); - private static final String OSB_GE_TEXT = "
OSBuddy Actively traded price: "; - - private static final String BUY_LIMIT_GE_TEXT = "
Buy limit: "; - private static final Gson GSON = new Gson(); - private static final TypeToken> BUY_LIMIT_TOKEN = new TypeToken>() - { - }; - - static final String SEARCH_GRAND_EXCHANGE = "Search Grand Exchange"; - - @Getter(AccessLevel.PACKAGE) - private NavigationButton button; - - @Getter(AccessLevel.PACKAGE) - private GrandExchangePanel panel; - - @Getter(AccessLevel.PACKAGE) - @Setter(AccessLevel.PACKAGE) - private boolean hotKeyPressed; - - @Inject - private GrandExchangeInputListener inputListener; - - @Inject - private ItemManager itemManager; - - @Inject - private MouseManager mouseManager; - - @Inject - private KeyManager keyManager; - - @Inject - private Client client; - - @Inject - private ClientToolbar clientToolbar; - - @Inject - private GrandExchangeConfig config; - - @Inject - private Notifier notifier; - - @Inject - private ScheduledExecutorService executorService; - - @Inject - private SessionManager sessionManager; - - @Inject - private ConfigManager configManager; - - private Widget grandExchangeText; - private Widget grandExchangeItem; - private Map 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) - { - return configManager.getConfig(GrandExchangeConfig.class); - } - - @Override - protected void startUp() - { - itemGELimits = loadGELimits(); - panel = injector.getInstance(GrandExchangePanel.class); - panel.setGELimits(itemGELimits); - - final BufferedImage icon = ImageUtil.getResourceStreamFromClass(getClass(), "ge_icon.png"); - - button = NavigationButton.builder() - .tooltip("Grand Exchange") - .icon(icon) - .priority(3) - .panel(panel) - .build(); - - clientToolbar.addNavigation(button); - - if (config.quickLookup()) - { - mouseManager.registerMouseListener(inputListener); - keyManager.registerKeyListener(inputListener); - } - - AccountSession accountSession = sessionManager.getAccountSession(); - if (accountSession != null) - { - grandExchangeClient = new GrandExchangeClient(accountSession.getUuid()); - } - } - - @Override - protected void shutDown() - { - clientToolbar.removeNavigation(button); - mouseManager.unregisterMouseListener(inputListener); - keyManager.unregisterKeyListener(inputListener); - 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 - public void onConfigChanged(ConfigChanged event) - { - if (event.getGroup().equals("grandexchange")) - { - if (event.getKey().equals("quickLookup")) - { - if (config.quickLookup()) - { - mouseManager.registerMouseListener(inputListener); - keyManager.registerKeyListener(inputListener); - } - else - { - mouseManager.unregisterMouseListener(inputListener); - keyManager.unregisterKeyListener(inputListener); - } - } - } - } - - @Subscribe - public void onGrandExchangeOfferChanged(GrandExchangeOfferChanged offerEvent) - { - 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, 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 - public void onChatMessage(ChatMessage event) - { - if (!this.config.enableNotifications() || event.getType() != ChatMessageType.GAMEMESSAGE) - { - return; - } - - String message = Text.removeTags(event.getMessage()); - - if (message.startsWith("Grand Exchange:")) - { - this.notifier.notify(message); - } - } - - @Subscribe - public void onGameStateChanged(GameStateChanged gameStateChanged) - { - if (gameStateChanged.getGameState() == GameState.LOGIN_SCREEN) - { - panel.getOffersPanel().resetOffers(); - } - } - - @Subscribe - public void onMenuEntryAdded(MenuEntryAdded event) - { - // At the moment, if the user disables quick lookup, the input listener gets disabled. Thus, isHotKeyPressed() - // should always return false when quick lookup is disabled. - // Replace the default option with "Search ..." when holding alt - if (client.getGameState() != GameState.LOGGED_IN || !hotKeyPressed) - { - return; - } - - final MenuEntry[] entries = client.getMenuEntries(); - final MenuEntry menuEntry = entries[entries.length - 1]; - final int widgetId = menuEntry.getParam1(); - final int groupId = WidgetInfo.TO_GROUP(widgetId); - - switch (groupId) - { - case WidgetID.BANK_GROUP_ID: - // Don't show for view tabs and such - if (WidgetInfo.TO_CHILD(widgetId) != WidgetInfo.BANK_ITEM_CONTAINER.getChildId()) - { - break; - } - case WidgetID.INVENTORY_GROUP_ID: - case WidgetID.BANK_INVENTORY_GROUP_ID: - case WidgetID.GRAND_EXCHANGE_INVENTORY_GROUP_ID: - case WidgetID.SHOP_INVENTORY_GROUP_ID: - menuEntry.setOption(SEARCH_GRAND_EXCHANGE); - menuEntry.setType(MenuAction.RUNELITE.getId()); - client.setMenuEntries(entries); - } - } - - @Subscribe - public void onFocusChanged(FocusChanged focusChanged) - { - if (!focusChanged.isFocused()) - { - setHotKeyPressed(false); - } - } - - @Subscribe - public void onWidgetLoaded(WidgetLoaded event) - { - switch (event.getGroupId()) - { - // Grand exchange was opened. - case WidgetID.GRAND_EXCHANGE_GROUP_ID: - Widget grandExchangeOffer = client.getWidget(WidgetInfo.GRAND_EXCHANGE_OFFER_CONTAINER); - grandExchangeText = client.getWidget(WidgetInfo.GRAND_EXCHANGE_OFFER_TEXT); - grandExchangeItem = grandExchangeOffer.getDynamicChildren()[OFFER_CONTAINER_ITEM]; - break; - // Grand exchange was closed (if it was open before). - case WidgetID.INVENTORY_GROUP_ID: - grandExchangeText = null; - grandExchangeItem = null; - break; - } - } - - @Subscribe - public void onGameTick(GameTick event) - { - if (grandExchangeText == null || grandExchangeItem == null || grandExchangeItem.isHidden()) - { - return; - } - - final Widget geText = grandExchangeText; - final String geTextString = geText.getText(); - final int itemId = grandExchangeItem.getItemId(); - - if (itemId == OFFER_DEFAULT_ITEM_ID || itemId == -1) - { - // This item is invalid/nothing has been searched for - return; - } - - if (config.enableGELimits() && itemGELimits != null && !geTextString.contains(BUY_LIMIT_GE_TEXT)) - { - final Integer itemLimit = itemGELimits.get(itemId); - - // If we have item buy limit, append it - if (itemLimit != null) - { - final String text = geText.getText() + BUY_LIMIT_GE_TEXT + StackFormatter.formatNumber(itemLimit); - geText.setText(text); - } - } - - if (!config.enableOsbPrices() || geTextString.contains(OSB_GE_TEXT)) - { - // OSB prices are disabled or price was already looked up, so no need to set it again - return; - } - - log.debug("Looking up OSB item price {}", itemId); - - executorService.submit(() -> - { - if (geText.getText().contains(OSB_GE_TEXT)) - { - // If there are multiple tasks queued and one of them have already added the price - return; - } - - try - { - final OSBGrandExchangeResult result = CLIENT.lookupItem(itemId); - final String text = geText.getText() + OSB_GE_TEXT + StackFormatter.formatNumber(result.getOverall_average()); - geText.setText(text); - } - catch (IOException e) - { - log.debug("Error getting price of item {}", itemId, e); - } - }); - } - - private static Map loadGELimits() - { - final InputStream geLimitData = GrandExchangePlugin.class.getResourceAsStream("ge_limits.json"); - final Map itemGELimits = GSON.fromJson(new InputStreamReader(geLimitData), BUY_LIMIT_TOKEN.getType()); - log.debug("Loaded {} limits", itemGELimits.size()); - return itemGELimits; - } -} +/* + * Copyright (c) 2019, Adam + * Copyright (c) 2017, Robbie + * Copyright (c) 2018, SomeoneWithAnInternetConnection + * 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 com.google.common.reflect.TypeToken; +import com.google.gson.Gson; +import com.google.inject.Provides; +import java.awt.image.BufferedImage; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.util.Map; +import java.util.concurrent.ScheduledExecutorService; +import javax.inject.Inject; +import javax.swing.SwingUtilities; +import lombok.AccessLevel; +import lombok.Getter; +import lombok.Setter; +import lombok.extern.slf4j.Slf4j; +import net.runelite.api.ChatMessageType; +import net.runelite.api.Client; +import net.runelite.api.GameState; +import net.runelite.api.GrandExchangeOffer; +import net.runelite.api.GrandExchangeOfferState; +import net.runelite.api.ItemComposition; +import net.runelite.api.MenuAction; +import net.runelite.api.MenuEntry; +import net.runelite.api.events.ChatMessage; +import net.runelite.api.events.ConfigChanged; +import net.runelite.api.events.FocusChanged; +import net.runelite.api.events.GameStateChanged; +import net.runelite.api.events.GameTick; +import net.runelite.api.events.GrandExchangeOfferChanged; +import net.runelite.api.events.MenuEntryAdded; +import net.runelite.api.events.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.events.SessionClose; +import net.runelite.client.events.SessionOpen; +import net.runelite.client.game.ItemManager; +import net.runelite.client.input.KeyManager; +import net.runelite.client.input.MouseManager; +import net.runelite.client.plugins.Plugin; +import net.runelite.client.plugins.PluginDescriptor; +import net.runelite.client.ui.ClientToolbar; +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.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", + description = "Provide additional and/or easier access to Grand Exchange information", + tags = {"external", "integration", "notifications", "panel", "prices", "trade"} +) +@Slf4j +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 OSBGrandExchangeClient CLIENT = new OSBGrandExchangeClient(); + private static final String OSB_GE_TEXT = "
OSBuddy Actively traded price: "; + + private static final String BUY_LIMIT_GE_TEXT = "
Buy limit: "; + private static final Gson GSON = new Gson(); + private static final TypeToken> BUY_LIMIT_TOKEN = new TypeToken>() + { + }; + + static final String SEARCH_GRAND_EXCHANGE = "Search Grand Exchange"; + + @Getter(AccessLevel.PACKAGE) + private NavigationButton button; + + @Getter(AccessLevel.PACKAGE) + private GrandExchangePanel panel; + + @Getter(AccessLevel.PACKAGE) + @Setter(AccessLevel.PACKAGE) + private boolean hotKeyPressed; + + @Inject + private GrandExchangeInputListener inputListener; + + @Inject + private ItemManager itemManager; + + @Inject + private MouseManager mouseManager; + + @Inject + private KeyManager keyManager; + + @Inject + private Client client; + + @Inject + private ClientToolbar clientToolbar; + + @Inject + private GrandExchangeConfig config; + + @Inject + private Notifier notifier; + + @Inject + private ScheduledExecutorService executorService; + + @Inject + private SessionManager sessionManager; + + @Inject + private ConfigManager configManager; + + private Widget grandExchangeText; + private Widget grandExchangeItem; + private Map 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) + { + return configManager.getConfig(GrandExchangeConfig.class); + } + + @Override + protected void startUp() + { + itemGELimits = loadGELimits(); + panel = injector.getInstance(GrandExchangePanel.class); + panel.setGELimits(itemGELimits); + + final BufferedImage icon = ImageUtil.getResourceStreamFromClass(getClass(), "ge_icon.png"); + + button = NavigationButton.builder() + .tooltip("Grand Exchange") + .icon(icon) + .priority(3) + .panel(panel) + .build(); + + clientToolbar.addNavigation(button); + + if (config.quickLookup()) + { + mouseManager.registerMouseListener(inputListener); + keyManager.registerKeyListener(inputListener); + } + + AccountSession accountSession = sessionManager.getAccountSession(); + if (accountSession != null) + { + grandExchangeClient = new GrandExchangeClient(accountSession.getUuid()); + } + } + + @Override + protected void shutDown() + { + clientToolbar.removeNavigation(button); + mouseManager.unregisterMouseListener(inputListener); + keyManager.unregisterKeyListener(inputListener); + 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 + public void onConfigChanged(ConfigChanged event) + { + if (event.getGroup().equals("grandexchange")) + { + if (event.getKey().equals("quickLookup")) + { + if (config.quickLookup()) + { + mouseManager.registerMouseListener(inputListener); + keyManager.registerKeyListener(inputListener); + } + else + { + mouseManager.unregisterMouseListener(inputListener); + keyManager.unregisterKeyListener(inputListener); + } + } + } + } + + @Subscribe + public void onGrandExchangeOfferChanged(GrandExchangeOfferChanged offerEvent) + { + 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, 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 + public void onChatMessage(ChatMessage event) + { + if (!this.config.enableNotifications() || event.getType() != ChatMessageType.GAMEMESSAGE) + { + return; + } + + String message = Text.removeTags(event.getMessage()); + + if (message.startsWith("Grand Exchange:")) + { + this.notifier.notify(message); + } + } + + @Subscribe + public void onGameStateChanged(GameStateChanged gameStateChanged) + { + if (gameStateChanged.getGameState() == GameState.LOGIN_SCREEN) + { + panel.getOffersPanel().resetOffers(); + } + } + + @Subscribe + public void onMenuEntryAdded(MenuEntryAdded event) + { + // At the moment, if the user disables quick lookup, the input listener gets disabled. Thus, isHotKeyPressed() + // should always return false when quick lookup is disabled. + // Replace the default option with "Search ..." when holding alt + if (client.getGameState() != GameState.LOGGED_IN || !hotKeyPressed) + { + return; + } + + final MenuEntry[] entries = client.getMenuEntries(); + final MenuEntry menuEntry = entries[entries.length - 1]; + final int widgetId = menuEntry.getParam1(); + final int groupId = WidgetInfo.TO_GROUP(widgetId); + + switch (groupId) + { + case WidgetID.BANK_GROUP_ID: + // Don't show for view tabs and such + if (WidgetInfo.TO_CHILD(widgetId) != WidgetInfo.BANK_ITEM_CONTAINER.getChildId()) + { + break; + } + case WidgetID.INVENTORY_GROUP_ID: + case WidgetID.BANK_INVENTORY_GROUP_ID: + case WidgetID.GRAND_EXCHANGE_INVENTORY_GROUP_ID: + case WidgetID.SHOP_INVENTORY_GROUP_ID: + menuEntry.setOption(SEARCH_GRAND_EXCHANGE); + menuEntry.setType(MenuAction.RUNELITE.getId()); + client.setMenuEntries(entries); + } + } + + @Subscribe + public void onFocusChanged(FocusChanged focusChanged) + { + if (!focusChanged.isFocused()) + { + setHotKeyPressed(false); + } + } + + @Subscribe + public void onWidgetLoaded(WidgetLoaded event) + { + switch (event.getGroupId()) + { + // Grand exchange was opened. + case WidgetID.GRAND_EXCHANGE_GROUP_ID: + Widget grandExchangeOffer = client.getWidget(WidgetInfo.GRAND_EXCHANGE_OFFER_CONTAINER); + grandExchangeText = client.getWidget(WidgetInfo.GRAND_EXCHANGE_OFFER_TEXT); + grandExchangeItem = grandExchangeOffer.getDynamicChildren()[OFFER_CONTAINER_ITEM]; + break; + // Grand exchange was closed (if it was open before). + case WidgetID.INVENTORY_GROUP_ID: + grandExchangeText = null; + grandExchangeItem = null; + break; + } + } + + @Subscribe + public void onGameTick(GameTick event) + { + if (grandExchangeText == null || grandExchangeItem == null || grandExchangeItem.isHidden()) + { + return; + } + + final Widget geText = grandExchangeText; + final String geTextString = geText.getText(); + final int itemId = grandExchangeItem.getItemId(); + + if (itemId == OFFER_DEFAULT_ITEM_ID || itemId == -1) + { + // This item is invalid/nothing has been searched for + return; + } + + if (config.enableGELimits() && itemGELimits != null && !geTextString.contains(BUY_LIMIT_GE_TEXT)) + { + final Integer itemLimit = itemGELimits.get(itemId); + + // If we have item buy limit, append it + if (itemLimit != null) + { + final String text = geText.getText() + BUY_LIMIT_GE_TEXT + StackFormatter.formatNumber(itemLimit); + geText.setText(text); + } + } + + if (!config.enableOsbPrices() || geTextString.contains(OSB_GE_TEXT)) + { + // OSB prices are disabled or price was already looked up, so no need to set it again + return; + } + + log.debug("Looking up OSB item price {}", itemId); + + executorService.submit(() -> + { + if (geText.getText().contains(OSB_GE_TEXT)) + { + // If there are multiple tasks queued and one of them have already added the price + return; + } + + try + { + final OSBGrandExchangeResult result = CLIENT.lookupItem(itemId); + final String text = geText.getText() + OSB_GE_TEXT + StackFormatter.formatNumber(result.getOverall_average()); + geText.setText(text); + } + catch (IOException e) + { + log.debug("Error getting price of item {}", itemId, e); + } + }); + } + + private static Map loadGELimits() + { + final InputStream geLimitData = GrandExchangePlugin.class.getResourceAsStream("ge_limits.json"); + final Map itemGELimits = GSON.fromJson(new InputStreamReader(geLimitData), BUY_LIMIT_TOKEN.getType()); + log.debug("Loaded {} limits", itemGELimits.size()); + return itemGELimits; + } +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/grotesqueguardians/GrotesqueGuardiansPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/grotesqueguardians/GrotesqueGuardiansPlugin.java index e41c1a4b47..7d461f8cfd 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/grotesqueguardians/GrotesqueGuardiansPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/grotesqueguardians/GrotesqueGuardiansPlugin.java @@ -1,58 +1,58 @@ -/* - * Copyright (c) 2018, Damen - * 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.grotesqueguardians; - -import javax.inject.Inject; -import net.runelite.client.plugins.Plugin; -import net.runelite.client.plugins.PluginDescriptor; -import net.runelite.client.plugins.PluginType; -import net.runelite.client.ui.overlay.OverlayManager; - -@PluginDescriptor( - name = "Grotesque Guardians", - description = "Display tile indicators for the Grotesque Guardian special attacks", - tags = {"grotesque", "guardians", "gargoyle", "garg"}, - type = PluginType.PVM -) -public class GrotesqueGuardiansPlugin extends Plugin -{ - @Inject - private OverlayManager overlayManager; - - @Inject - private GrotesqueGuardiansOverlay overlay; - - @Override - protected void startUp() throws Exception - { - overlayManager.add(overlay); - } - - @Override - protected void shutDown() throws Exception - { - overlayManager.remove(overlay); - } -} +/* + * Copyright (c) 2018, Damen + * 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.grotesqueguardians; + +import javax.inject.Inject; +import net.runelite.client.plugins.Plugin; +import net.runelite.client.plugins.PluginDescriptor; +import net.runelite.client.plugins.PluginType; +import net.runelite.client.ui.overlay.OverlayManager; + +@PluginDescriptor( + name = "Grotesque Guardians", + description = "Display tile indicators for the Grotesque Guardian special attacks", + tags = {"grotesque", "guardians", "gargoyle", "garg"}, + type = PluginType.PVM +) +public class GrotesqueGuardiansPlugin extends Plugin +{ + @Inject + private OverlayManager overlayManager; + + @Inject + private GrotesqueGuardiansOverlay overlay; + + @Override + protected void startUp() throws Exception + { + overlayManager.add(overlay); + } + + @Override + protected void shutDown() throws Exception + { + overlayManager.remove(overlay); + } +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/grounditems/GroundItemsConfig.java b/runelite-client/src/main/java/net/runelite/client/plugins/grounditems/GroundItemsConfig.java index 008429abf1..c722b202f0 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/grounditems/GroundItemsConfig.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/grounditems/GroundItemsConfig.java @@ -1,383 +1,383 @@ -/* - * Copyright (c) 2017, Aria - * 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.grounditems; - -import java.awt.Color; -import net.runelite.client.config.Config; -import net.runelite.client.config.ConfigGroup; -import net.runelite.client.config.ConfigItem; -import net.runelite.client.plugins.grounditems.config.ItemHighlightMode; -import net.runelite.client.plugins.grounditems.config.MenuHighlightMode; -import net.runelite.client.plugins.grounditems.config.PriceDisplayMode; -import net.runelite.client.plugins.grounditems.config.ValueCalculationMode; - -@ConfigGroup("grounditems") -public interface GroundItemsConfig extends Config -{ - @ConfigItem( - keyName = "highlightedItems", - name = "Highlighted Items", - description = "Configures specifically highlighted ground items. Format: (item), (item)", - position = 0 - ) - default String getHighlightItems() - { - return ""; - } - - @ConfigItem( - keyName = "highlightedItems", - name = "", - description = "" - ) - void setHighlightedItem(String key); - - @ConfigItem( - keyName = "hiddenItems", - name = "Hidden Items", - description = "Configures hidden ground items. Format: (item), (item)", - position = 1 - ) - default String getHiddenItems() - { - return "Vial, Ashes, Coins, Bones, Bucket, Jug, Seaweed"; - } - - @ConfigItem( - keyName = "hiddenItems", - name = "", - description = "" - ) - void setHiddenItems(String key); - - @ConfigItem( - keyName = "showHighlightedOnly", - name = "Show Highlighted items only", - description = "Configures whether or not to draw items only on your highlighted list", - position = 2 - ) - default boolean showHighlightedOnly() - { - return false; - } - - @ConfigItem( - keyName = "dontHideUntradeables", - name = "Do not hide untradeables", - description = "Configures whether or not untradeable items ignore hiding under settings", - position = 3 - ) - default boolean dontHideUntradeables() - { - return true; - } - - @ConfigItem( - keyName = "showMenuItemQuantities", - name = "Show Menu Item Quantities", - description = "Configures whether or not to show the item quantities in the menu", - position = 4 - ) - default boolean showMenuItemQuantities() - { - return true; - } - - @ConfigItem( - keyName = "recolorMenuHiddenItems", - name = "Recolor Menu Hidden Items", - description = "Configures whether or not hidden items in right click menu will be recolored", - position = 5 - ) - default boolean recolorMenuHiddenItems() - { - return false; - } - - @ConfigItem( - keyName = "highlightTiles", - name = "Highlight Tiles", - description = "Configures whether or not to highlight tiles containing ground items", - position = 6 - ) - default boolean highlightTiles() - { - return false; - } - - @ConfigItem( - keyName = "notifyHighlightedDrops", - name = "Notify for Highlighted drops", - description = "Configures whether or not to notify for drops on your highlighted list", - position = 7 - ) - default boolean notifyHighlightedDrops() - { - return false; - } - - @ConfigItem( - keyName = "priceDisplayMode", - name = "Price Display Mode", - description = "Configures what price types are shown alongside of ground item name", - position = 8 - ) - default PriceDisplayMode priceDisplayMode() - { - return PriceDisplayMode.BOTH; - } - - @ConfigItem( - keyName = "itemHighlightMode", - name = "Item Highlight Mode", - description = "Configures how ground items will be highlighted", - position = 9 - ) - default ItemHighlightMode itemHighlightMode() - { - return ItemHighlightMode.BOTH; - } - - @ConfigItem( - keyName = "menuHighlightMode", - name = "Menu Highlight Mode", - description = "Configures what to highlight in right-click menu", - position = 10 - ) - default MenuHighlightMode menuHighlightMode() - { - return MenuHighlightMode.NAME; - } - - @ConfigItem( - keyName = "highlightValueCalculation", - name = "Highlight Value Calculation", - description = "Configures which coin value is used to determine highlight color", - position = 11 - ) - default ValueCalculationMode valueCalculationMode() - { - return ValueCalculationMode.HIGHEST; - } - - @ConfigItem( - keyName = "highlightOverValue2", - name = "Highlight > Value", - description = "Configures highlighted ground items over either GE or HA value", - position = 12 - ) - default int getHighlightOverValue() - { - return 0; - } - - @ConfigItem( - keyName = "hideUnderValue", - name = "Hide < Value", - description = "Configures hidden ground items under both GE and HA value", - position = 13 - ) - default int getHideUnderValue() - { - return 0; - } - - @ConfigItem( - keyName = "defaultColor", - name = "Default items color", - description = "Configures the color for default, non-highlighted items", - position = 14 - ) - default Color defaultColor() - { - return Color.WHITE; - } - - @ConfigItem( - keyName = "highlightedColor", - name = "Highlighted items color", - description = "Configures the color for highlighted items", - position = 15 - ) - default Color highlightedColor() - { - return Color.decode("#AA00FF"); - } - - @ConfigItem( - keyName = "hiddenColor", - name = "Hidden items color", - description = "Configures the color for hidden items in right-click menu and when holding ALT", - position = 16 - ) - default Color hiddenColor() - { - return Color.GRAY; - } - - @ConfigItem( - keyName = "lowValueColor", - name = "Low value items color", - description = "Configures the color for low value items", - position = 17 - ) - default Color lowValueColor() - { - return Color.decode("#66B2FF"); - } - - @ConfigItem( - keyName = "lowValuePrice", - name = "Low value price", - description = "Configures the start price for low value items", - position = 18 - ) - default int lowValuePrice() - { - return 20000; - } - - @ConfigItem( - keyName = "mediumValueColor", - name = "Medium value items color", - description = "Configures the color for medium value items", - position = 19 - ) - default Color mediumValueColor() - { - return Color.decode("#99FF99"); - } - - @ConfigItem( - keyName = "mediumValuePrice", - name = "Medium value price", - description = "Configures the start price for medium value items", - position = 20 - ) - default int mediumValuePrice() - { - return 100000; - } - - @ConfigItem( - keyName = "highValueColor", - name = "High value items color", - description = "Configures the color for high value items", - position = 21 - ) - default Color highValueColor() - { - return Color.decode("#FF9600"); - } - - @ConfigItem( - keyName = "highValuePrice", - name = "High value price", - description = "Configures the start price for high value items", - position = 22 - ) - default int highValuePrice() - { - return 1000000; - } - - @ConfigItem( - keyName = "insaneValueColor", - name = "Insane value items color", - description = "Configures the color for insane value items", - position = 23 - ) - default Color insaneValueColor() - { - return Color.decode("#FF66B2"); - } - - @ConfigItem( - keyName = "insaneValuePrice", - name = "Insane value price", - description = "Configures the start price for insane value items", - position = 24 - ) - default int insaneValuePrice() - { - return 10000000; - } - - @ConfigItem( - keyName = "onlyShowLoot", - name = "Only show loot", - description = "Only shows drops from NPCs and players", - position = 25 - ) - default boolean onlyShowLoot() - { - return false; - } - - @ConfigItem( - keyName = "doubleTapDelay", - name = "Delay for double-tap ALT to hide", - description = "Decrease this number if you accidentally hide ground items often. (0 = Disabled)", - position = 26 - ) - default int doubleTapDelay() - { - return 250; - } - - @ConfigItem( - keyName = "collapseEntries", - name = "Collapse ground item menu entries", - description = "Collapses ground item menu entries together and appends count", - position = 27 - ) - default boolean collapseEntries() - { - return false; - } - - @ConfigItem( - position = 27, - keyName = "removeIgnored", - name = "Hide Ignored", - description = "Remove take option for items that are on the hidden items list." - ) - default boolean removeIgnored() - { - return false; - } - - @ConfigItem( - keyName = "toggleOutline", - name = "Text Outline", - description = "Use an outline around text instead of a text shadow", - position = 29 - ) - default boolean toggleOutline() - { - return false; - } -} +/* + * Copyright (c) 2017, Aria + * 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.grounditems; + +import java.awt.Color; +import net.runelite.client.config.Config; +import net.runelite.client.config.ConfigGroup; +import net.runelite.client.config.ConfigItem; +import net.runelite.client.plugins.grounditems.config.ItemHighlightMode; +import net.runelite.client.plugins.grounditems.config.MenuHighlightMode; +import net.runelite.client.plugins.grounditems.config.PriceDisplayMode; +import net.runelite.client.plugins.grounditems.config.ValueCalculationMode; + +@ConfigGroup("grounditems") +public interface GroundItemsConfig extends Config +{ + @ConfigItem( + keyName = "highlightedItems", + name = "Highlighted Items", + description = "Configures specifically highlighted ground items. Format: (item), (item)", + position = 0 + ) + default String getHighlightItems() + { + return ""; + } + + @ConfigItem( + keyName = "highlightedItems", + name = "", + description = "" + ) + void setHighlightedItem(String key); + + @ConfigItem( + keyName = "hiddenItems", + name = "Hidden Items", + description = "Configures hidden ground items. Format: (item), (item)", + position = 1 + ) + default String getHiddenItems() + { + return "Vial, Ashes, Coins, Bones, Bucket, Jug, Seaweed"; + } + + @ConfigItem( + keyName = "hiddenItems", + name = "", + description = "" + ) + void setHiddenItems(String key); + + @ConfigItem( + keyName = "showHighlightedOnly", + name = "Show Highlighted items only", + description = "Configures whether or not to draw items only on your highlighted list", + position = 2 + ) + default boolean showHighlightedOnly() + { + return false; + } + + @ConfigItem( + keyName = "dontHideUntradeables", + name = "Do not hide untradeables", + description = "Configures whether or not untradeable items ignore hiding under settings", + position = 3 + ) + default boolean dontHideUntradeables() + { + return true; + } + + @ConfigItem( + keyName = "showMenuItemQuantities", + name = "Show Menu Item Quantities", + description = "Configures whether or not to show the item quantities in the menu", + position = 4 + ) + default boolean showMenuItemQuantities() + { + return true; + } + + @ConfigItem( + keyName = "recolorMenuHiddenItems", + name = "Recolor Menu Hidden Items", + description = "Configures whether or not hidden items in right click menu will be recolored", + position = 5 + ) + default boolean recolorMenuHiddenItems() + { + return false; + } + + @ConfigItem( + keyName = "highlightTiles", + name = "Highlight Tiles", + description = "Configures whether or not to highlight tiles containing ground items", + position = 6 + ) + default boolean highlightTiles() + { + return false; + } + + @ConfigItem( + keyName = "notifyHighlightedDrops", + name = "Notify for Highlighted drops", + description = "Configures whether or not to notify for drops on your highlighted list", + position = 7 + ) + default boolean notifyHighlightedDrops() + { + return false; + } + + @ConfigItem( + keyName = "priceDisplayMode", + name = "Price Display Mode", + description = "Configures what price types are shown alongside of ground item name", + position = 8 + ) + default PriceDisplayMode priceDisplayMode() + { + return PriceDisplayMode.BOTH; + } + + @ConfigItem( + keyName = "itemHighlightMode", + name = "Item Highlight Mode", + description = "Configures how ground items will be highlighted", + position = 9 + ) + default ItemHighlightMode itemHighlightMode() + { + return ItemHighlightMode.BOTH; + } + + @ConfigItem( + keyName = "menuHighlightMode", + name = "Menu Highlight Mode", + description = "Configures what to highlight in right-click menu", + position = 10 + ) + default MenuHighlightMode menuHighlightMode() + { + return MenuHighlightMode.NAME; + } + + @ConfigItem( + keyName = "highlightValueCalculation", + name = "Highlight Value Calculation", + description = "Configures which coin value is used to determine highlight color", + position = 11 + ) + default ValueCalculationMode valueCalculationMode() + { + return ValueCalculationMode.HIGHEST; + } + + @ConfigItem( + keyName = "highlightOverValue2", + name = "Highlight > Value", + description = "Configures highlighted ground items over either GE or HA value", + position = 12 + ) + default int getHighlightOverValue() + { + return 0; + } + + @ConfigItem( + keyName = "hideUnderValue", + name = "Hide < Value", + description = "Configures hidden ground items under both GE and HA value", + position = 13 + ) + default int getHideUnderValue() + { + return 0; + } + + @ConfigItem( + keyName = "defaultColor", + name = "Default items color", + description = "Configures the color for default, non-highlighted items", + position = 14 + ) + default Color defaultColor() + { + return Color.WHITE; + } + + @ConfigItem( + keyName = "highlightedColor", + name = "Highlighted items color", + description = "Configures the color for highlighted items", + position = 15 + ) + default Color highlightedColor() + { + return Color.decode("#AA00FF"); + } + + @ConfigItem( + keyName = "hiddenColor", + name = "Hidden items color", + description = "Configures the color for hidden items in right-click menu and when holding ALT", + position = 16 + ) + default Color hiddenColor() + { + return Color.GRAY; + } + + @ConfigItem( + keyName = "lowValueColor", + name = "Low value items color", + description = "Configures the color for low value items", + position = 17 + ) + default Color lowValueColor() + { + return Color.decode("#66B2FF"); + } + + @ConfigItem( + keyName = "lowValuePrice", + name = "Low value price", + description = "Configures the start price for low value items", + position = 18 + ) + default int lowValuePrice() + { + return 20000; + } + + @ConfigItem( + keyName = "mediumValueColor", + name = "Medium value items color", + description = "Configures the color for medium value items", + position = 19 + ) + default Color mediumValueColor() + { + return Color.decode("#99FF99"); + } + + @ConfigItem( + keyName = "mediumValuePrice", + name = "Medium value price", + description = "Configures the start price for medium value items", + position = 20 + ) + default int mediumValuePrice() + { + return 100000; + } + + @ConfigItem( + keyName = "highValueColor", + name = "High value items color", + description = "Configures the color for high value items", + position = 21 + ) + default Color highValueColor() + { + return Color.decode("#FF9600"); + } + + @ConfigItem( + keyName = "highValuePrice", + name = "High value price", + description = "Configures the start price for high value items", + position = 22 + ) + default int highValuePrice() + { + return 1000000; + } + + @ConfigItem( + keyName = "insaneValueColor", + name = "Insane value items color", + description = "Configures the color for insane value items", + position = 23 + ) + default Color insaneValueColor() + { + return Color.decode("#FF66B2"); + } + + @ConfigItem( + keyName = "insaneValuePrice", + name = "Insane value price", + description = "Configures the start price for insane value items", + position = 24 + ) + default int insaneValuePrice() + { + return 10000000; + } + + @ConfigItem( + keyName = "onlyShowLoot", + name = "Only show loot", + description = "Only shows drops from NPCs and players", + position = 25 + ) + default boolean onlyShowLoot() + { + return false; + } + + @ConfigItem( + keyName = "doubleTapDelay", + name = "Delay for double-tap ALT to hide", + description = "Decrease this number if you accidentally hide ground items often. (0 = Disabled)", + position = 26 + ) + default int doubleTapDelay() + { + return 250; + } + + @ConfigItem( + keyName = "collapseEntries", + name = "Collapse ground item menu entries", + description = "Collapses ground item menu entries together and appends count", + position = 27 + ) + default boolean collapseEntries() + { + return false; + } + + @ConfigItem( + position = 27, + keyName = "removeIgnored", + name = "Hide Ignored", + description = "Remove take option for items that are on the hidden items list." + ) + default boolean removeIgnored() + { + return false; + } + + @ConfigItem( + keyName = "toggleOutline", + name = "Text Outline", + description = "Use an outline around text instead of a text shadow", + position = 29 + ) + default boolean toggleOutline() + { + return false; + } +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/grounditems/GroundItemsOverlay.java b/runelite-client/src/main/java/net/runelite/client/plugins/grounditems/GroundItemsOverlay.java index 17c0151ae7..4d7e2601cd 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/grounditems/GroundItemsOverlay.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/grounditems/GroundItemsOverlay.java @@ -1,391 +1,391 @@ -/* - * Copyright (c) 2017, Aria - * Copyright (c) 2018, Adam - * 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.grounditems; - -import java.awt.Color; -import java.awt.Dimension; -import java.awt.FontMetrics; -import java.awt.Graphics2D; -import java.awt.Polygon; -import java.awt.Rectangle; -import java.util.AbstractMap.SimpleEntry; -import java.util.ArrayList; -import java.util.Collection; -import java.util.HashMap; -import java.util.Map; -import javax.inject.Inject; -import net.runelite.api.Client; -import net.runelite.api.Perspective; -import net.runelite.api.Player; -import net.runelite.api.Point; -import net.runelite.api.coords.LocalPoint; -import net.runelite.api.coords.WorldPoint; -import static net.runelite.client.plugins.grounditems.config.ItemHighlightMode.MENU; -import net.runelite.client.plugins.grounditems.config.PriceDisplayMode; -import net.runelite.client.ui.overlay.Overlay; -import net.runelite.client.ui.overlay.OverlayLayer; -import net.runelite.client.ui.overlay.OverlayPosition; -import net.runelite.client.ui.overlay.OverlayUtil; -import net.runelite.client.ui.overlay.components.BackgroundComponent; -import net.runelite.client.ui.overlay.components.TextComponent; -import net.runelite.client.util.StackFormatter; - -public class GroundItemsOverlay extends Overlay -{ - private static final int MAX_DISTANCE = 2500; - // We must offset the text on the z-axis such that - // it doesn't obscure the ground items below it. - private static final int OFFSET_Z = 20; - // The game won't send anything higher than this value to the plugin - - // so we replace any item quantity higher with "Lots" instead. - private static final int MAX_QUANTITY = 65535; - // The 15 pixel gap between each drawn ground item. - private static final int STRING_GAP = 15; - // Size of the hidden/highlight boxes - private static final int RECTANGLE_SIZE = 8; - - private final Client client; - private final GroundItemsPlugin plugin; - private final GroundItemsConfig config; - private final StringBuilder itemStringBuilder = new StringBuilder(); - private final BackgroundComponent backgroundComponent = new BackgroundComponent(); - private final TextComponent textComponent = new TextComponent(); - private final Map offsetMap = new HashMap<>(); - - @Inject - private GroundItemsOverlay(Client client, GroundItemsPlugin plugin, GroundItemsConfig config) - { - setPosition(OverlayPosition.DYNAMIC); - setLayer(OverlayLayer.ABOVE_SCENE); - this.client = client; - this.plugin = plugin; - this.config = config; - } - - @Override - public Dimension render(Graphics2D graphics) - { - final boolean dontShowOverlay = (config.itemHighlightMode() == MENU || plugin.isHideAll()) && !plugin.isHotKeyPressed(); - - if (dontShowOverlay && !config.highlightTiles()) - { - return null; - } - - final FontMetrics fm = graphics.getFontMetrics(); - final Player player = client.getLocalPlayer(); - - if (player == null || client.getViewportWidget() == null) - { - return null; - } - - offsetMap.clear(); - final LocalPoint localLocation = player.getLocalLocation(); - final Point mousePos = client.getMouseCanvasPosition(); - Collection groundItemList = plugin.getCollectedGroundItems().values(); - GroundItem topGroundItem = null; - - if (plugin.isHotKeyPressed()) - { - // Make copy of ground items because we are going to modify them here, and the array list supports our - // desired behaviour here - groundItemList = new ArrayList<>(groundItemList); - final java.awt.Point awtMousePos = new java.awt.Point(mousePos.getX(), mousePos.getY()); - GroundItem groundItem = null; - - for (GroundItem item : groundItemList) - { - item.setOffset(offsetMap.compute(item.getLocation(), (k, v) -> v != null ? v + 1 : 0)); - - if (groundItem != null) - { - continue; - } - - if (plugin.getTextBoxBounds() != null - && item.equals(plugin.getTextBoxBounds().getValue()) - && plugin.getTextBoxBounds().getKey().contains(awtMousePos)) - { - groundItem = item; - continue; - } - - if (plugin.getHiddenBoxBounds() != null - && item.equals(plugin.getHiddenBoxBounds().getValue()) - && plugin.getHiddenBoxBounds().getKey().contains(awtMousePos)) - { - groundItem = item; - continue; - } - - if (plugin.getHighlightBoxBounds() != null - && item.equals(plugin.getHighlightBoxBounds().getValue()) - && plugin.getHighlightBoxBounds().getKey().contains(awtMousePos)) - { - groundItem = item; - } - } - - if (groundItem != null) - { - groundItemList.remove(groundItem); - groundItemList.add(groundItem); - topGroundItem = groundItem; - } - } - - plugin.setTextBoxBounds(null); - plugin.setHiddenBoxBounds(null); - plugin.setHighlightBoxBounds(null); - - final boolean onlyShowLoot = config.onlyShowLoot(); - - for (GroundItem item : groundItemList) - { - final LocalPoint groundPoint = LocalPoint.fromWorld(client, item.getLocation()); - - if (groundPoint == null || localLocation.distanceTo(groundPoint) > MAX_DISTANCE - || (onlyShowLoot && !item.isMine())) - { - continue; - } - - final Color highlighted = plugin.getHighlighted(item.getName(), item.getGePrice(), item.getHaPrice()); - final Color hidden = plugin.getHidden(item.getName(), item.getGePrice(), item.getHaPrice(), item.isTradeable()); - - if (highlighted == null && !plugin.isHotKeyPressed()) - { - // Do not display hidden items - if (hidden != null) - { - continue; - } - - // Do not display non-highlighted items - if (config.showHighlightedOnly()) - { - continue; - } - } - - final Color color = plugin.getItemColor(highlighted, hidden); - - if (config.highlightTiles()) - { - final Polygon poly = Perspective.getCanvasTilePoly(client, groundPoint); - - if (poly != null) - { - OverlayUtil.renderPolygon(graphics, poly, color); - } - } - - if (dontShowOverlay) - { - continue; - } - - itemStringBuilder.append(item.getName()); - - if (item.getQuantity() > 1) - { - if (item.getQuantity() >= MAX_QUANTITY) - { - itemStringBuilder.append(" (Lots!)"); - } - else - { - itemStringBuilder.append(" (") - .append(StackFormatter.quantityToStackSize(item.getQuantity())) - .append(")"); - } - } - - if (config.priceDisplayMode() == PriceDisplayMode.BOTH) - { - if (item.getGePrice() > 0) - { - itemStringBuilder.append(" (EX: ") - .append(StackFormatter.quantityToStackSize(item.getGePrice())) - .append(" gp)"); - } - - if (item.getHaPrice() > 0) - { - itemStringBuilder.append(" (HA: ") - .append(StackFormatter.quantityToStackSize(item.getHaPrice())) - .append(" gp)"); - } - } - else if (config.priceDisplayMode() != PriceDisplayMode.OFF) - { - final int price = config.priceDisplayMode() == PriceDisplayMode.GE - ? item.getGePrice() - : item.getHaPrice(); - - if (price > 0) - { - itemStringBuilder - .append(" (") - .append(StackFormatter.quantityToStackSize(price)) - .append(" gp)"); - } - } - - final String itemString = itemStringBuilder.toString(); - itemStringBuilder.setLength(0); - - final Point textPoint = Perspective.getCanvasTextLocation(client, - graphics, - groundPoint, - itemString, - item.getHeight() + OFFSET_Z); - - if (textPoint == null) - { - continue; - } - - final int offset = plugin.isHotKeyPressed() - ? item.getOffset() - : offsetMap.compute(item.getLocation(), (k, v) -> v != null ? v + 1 : 0); - - final int textX = textPoint.getX(); - final int textY = textPoint.getY() - (STRING_GAP * offset); - - if (plugin.isHotKeyPressed()) - { - final int stringWidth = fm.stringWidth(itemString); - final int stringHeight = fm.getHeight(); - - // Item bounds - int x = textX - 2; - int y = textY - stringHeight - 2; - int width = stringWidth + 4; - int height = stringHeight + 4; - final Rectangle itemBounds = new Rectangle(x, y, width, height); - - // Hidden box - x += width + 2; - y = textY - (RECTANGLE_SIZE + stringHeight) / 2; - width = height = RECTANGLE_SIZE; - final Rectangle itemHiddenBox = new Rectangle(x, y, width, height); - - // Highlight box - x += width + 2; - final Rectangle itemHighlightBox = new Rectangle(x, y, width, height); - - boolean mouseInBox = itemBounds.contains(mousePos.getX(), mousePos.getY()); - boolean mouseInHiddenBox = itemHiddenBox.contains(mousePos.getX(), mousePos.getY()); - boolean mouseInHighlightBox = itemHighlightBox.contains(mousePos.getX(), mousePos.getY()); - - if (mouseInBox) - { - plugin.setTextBoxBounds(new SimpleEntry<>(itemBounds, item)); - } - else if (mouseInHiddenBox) - { - plugin.setHiddenBoxBounds(new SimpleEntry<>(itemHiddenBox, item)); - - } - else if (mouseInHighlightBox) - { - plugin.setHighlightBoxBounds(new SimpleEntry<>(itemHighlightBox, item)); - } - - boolean topItem = topGroundItem == item; - - // Draw background if hovering - if (topItem && (mouseInBox || mouseInHiddenBox || mouseInHighlightBox)) - { - backgroundComponent.setRectangle(itemBounds); - backgroundComponent.render(graphics); - } - - // Draw hidden box - drawRectangle(graphics, itemHiddenBox, topItem && mouseInHiddenBox ? Color.RED : color, hidden != null, true); - - // Draw highlight box - drawRectangle(graphics, itemHighlightBox, topItem && mouseInHighlightBox ? Color.GREEN : color, highlighted != null, false); - } - - if (config.toggleOutline()) - { - graphics.setColor(Color.BLACK); - graphics.drawString(itemString, textX + 1, textY + 1); - graphics.drawString(itemString, textX - 1, textY - 1); - graphics.drawString(itemString, textX - 1, textY + 1); - graphics.drawString(itemString, textX + 1, textY - 1); - } - - textComponent.setText(itemString); - textComponent.setColor(color); - textComponent.setPosition(new java.awt.Point(textX, textY)); - textComponent.render(graphics); - } - - return null; - } - - private void drawRectangle(Graphics2D graphics, Rectangle rect, Color color, boolean inList, boolean hiddenBox) - { - graphics.setColor(Color.BLACK); - graphics.drawRect(rect.x + 1, rect.y + 1, rect.width, rect.height); - - graphics.setColor(color); - graphics.draw(rect); - - if (inList) - { - graphics.fill(rect); - } - - graphics.setColor(Color.WHITE); - // Minus symbol - graphics.drawLine - ( - rect.x + 2, - rect.y + (rect.height / 2), - rect.x + rect.width - 2, - rect.y + (rect.height / 2) - ); - - if (!hiddenBox) - { - // Plus symbol - graphics.drawLine - ( - rect.x + (rect.width / 2), - rect.y + 2, - rect.x + (rect.width / 2), - rect.y + rect.height - 2 - ); - } - - } - -} +/* + * Copyright (c) 2017, Aria + * Copyright (c) 2018, Adam + * 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.grounditems; + +import java.awt.Color; +import java.awt.Dimension; +import java.awt.FontMetrics; +import java.awt.Graphics2D; +import java.awt.Polygon; +import java.awt.Rectangle; +import java.util.AbstractMap.SimpleEntry; +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.Map; +import javax.inject.Inject; +import net.runelite.api.Client; +import net.runelite.api.Perspective; +import net.runelite.api.Player; +import net.runelite.api.Point; +import net.runelite.api.coords.LocalPoint; +import net.runelite.api.coords.WorldPoint; +import static net.runelite.client.plugins.grounditems.config.ItemHighlightMode.MENU; +import net.runelite.client.plugins.grounditems.config.PriceDisplayMode; +import net.runelite.client.ui.overlay.Overlay; +import net.runelite.client.ui.overlay.OverlayLayer; +import net.runelite.client.ui.overlay.OverlayPosition; +import net.runelite.client.ui.overlay.OverlayUtil; +import net.runelite.client.ui.overlay.components.BackgroundComponent; +import net.runelite.client.ui.overlay.components.TextComponent; +import net.runelite.client.util.StackFormatter; + +public class GroundItemsOverlay extends Overlay +{ + private static final int MAX_DISTANCE = 2500; + // We must offset the text on the z-axis such that + // it doesn't obscure the ground items below it. + private static final int OFFSET_Z = 20; + // The game won't send anything higher than this value to the plugin - + // so we replace any item quantity higher with "Lots" instead. + private static final int MAX_QUANTITY = 65535; + // The 15 pixel gap between each drawn ground item. + private static final int STRING_GAP = 15; + // Size of the hidden/highlight boxes + private static final int RECTANGLE_SIZE = 8; + + private final Client client; + private final GroundItemsPlugin plugin; + private final GroundItemsConfig config; + private final StringBuilder itemStringBuilder = new StringBuilder(); + private final BackgroundComponent backgroundComponent = new BackgroundComponent(); + private final TextComponent textComponent = new TextComponent(); + private final Map offsetMap = new HashMap<>(); + + @Inject + private GroundItemsOverlay(Client client, GroundItemsPlugin plugin, GroundItemsConfig config) + { + setPosition(OverlayPosition.DYNAMIC); + setLayer(OverlayLayer.ABOVE_SCENE); + this.client = client; + this.plugin = plugin; + this.config = config; + } + + @Override + public Dimension render(Graphics2D graphics) + { + final boolean dontShowOverlay = (config.itemHighlightMode() == MENU || plugin.isHideAll()) && !plugin.isHotKeyPressed(); + + if (dontShowOverlay && !config.highlightTiles()) + { + return null; + } + + final FontMetrics fm = graphics.getFontMetrics(); + final Player player = client.getLocalPlayer(); + + if (player == null || client.getViewportWidget() == null) + { + return null; + } + + offsetMap.clear(); + final LocalPoint localLocation = player.getLocalLocation(); + final Point mousePos = client.getMouseCanvasPosition(); + Collection groundItemList = GroundItemsPlugin.getCollectedGroundItems().values(); + GroundItem topGroundItem = null; + + if (plugin.isHotKeyPressed()) + { + // Make copy of ground items because we are going to modify them here, and the array list supports our + // desired behaviour here + groundItemList = new ArrayList<>(groundItemList); + final java.awt.Point awtMousePos = new java.awt.Point(mousePos.getX(), mousePos.getY()); + GroundItem groundItem = null; + + for (GroundItem item : groundItemList) + { + item.setOffset(offsetMap.compute(item.getLocation(), (k, v) -> v != null ? v + 1 : 0)); + + if (groundItem != null) + { + continue; + } + + if (plugin.getTextBoxBounds() != null + && item.equals(plugin.getTextBoxBounds().getValue()) + && plugin.getTextBoxBounds().getKey().contains(awtMousePos)) + { + groundItem = item; + continue; + } + + if (plugin.getHiddenBoxBounds() != null + && item.equals(plugin.getHiddenBoxBounds().getValue()) + && plugin.getHiddenBoxBounds().getKey().contains(awtMousePos)) + { + groundItem = item; + continue; + } + + if (plugin.getHighlightBoxBounds() != null + && item.equals(plugin.getHighlightBoxBounds().getValue()) + && plugin.getHighlightBoxBounds().getKey().contains(awtMousePos)) + { + groundItem = item; + } + } + + if (groundItem != null) + { + groundItemList.remove(groundItem); + groundItemList.add(groundItem); + topGroundItem = groundItem; + } + } + + plugin.setTextBoxBounds(null); + plugin.setHiddenBoxBounds(null); + plugin.setHighlightBoxBounds(null); + + final boolean onlyShowLoot = config.onlyShowLoot(); + + for (GroundItem item : groundItemList) + { + final LocalPoint groundPoint = LocalPoint.fromWorld(client, item.getLocation()); + + if (groundPoint == null || localLocation.distanceTo(groundPoint) > MAX_DISTANCE + || (onlyShowLoot && !item.isMine())) + { + continue; + } + + final Color highlighted = plugin.getHighlighted(item.getName(), item.getGePrice(), item.getHaPrice()); + final Color hidden = plugin.getHidden(item.getName(), item.getGePrice(), item.getHaPrice(), item.isTradeable()); + + if (highlighted == null && !plugin.isHotKeyPressed()) + { + // Do not display hidden items + if (hidden != null) + { + continue; + } + + // Do not display non-highlighted items + if (config.showHighlightedOnly()) + { + continue; + } + } + + final Color color = plugin.getItemColor(highlighted, hidden); + + if (config.highlightTiles()) + { + final Polygon poly = Perspective.getCanvasTilePoly(client, groundPoint); + + if (poly != null) + { + OverlayUtil.renderPolygon(graphics, poly, color); + } + } + + if (dontShowOverlay) + { + continue; + } + + itemStringBuilder.append(item.getName()); + + if (item.getQuantity() > 1) + { + if (item.getQuantity() >= MAX_QUANTITY) + { + itemStringBuilder.append(" (Lots!)"); + } + else + { + itemStringBuilder.append(" (") + .append(StackFormatter.quantityToStackSize(item.getQuantity())) + .append(")"); + } + } + + if (config.priceDisplayMode() == PriceDisplayMode.BOTH) + { + if (item.getGePrice() > 0) + { + itemStringBuilder.append(" (EX: ") + .append(StackFormatter.quantityToStackSize(item.getGePrice())) + .append(" gp)"); + } + + if (item.getHaPrice() > 0) + { + itemStringBuilder.append(" (HA: ") + .append(StackFormatter.quantityToStackSize(item.getHaPrice())) + .append(" gp)"); + } + } + else if (config.priceDisplayMode() != PriceDisplayMode.OFF) + { + final int price = config.priceDisplayMode() == PriceDisplayMode.GE + ? item.getGePrice() + : item.getHaPrice(); + + if (price > 0) + { + itemStringBuilder + .append(" (") + .append(StackFormatter.quantityToStackSize(price)) + .append(" gp)"); + } + } + + final String itemString = itemStringBuilder.toString(); + itemStringBuilder.setLength(0); + + final Point textPoint = Perspective.getCanvasTextLocation(client, + graphics, + groundPoint, + itemString, + item.getHeight() + OFFSET_Z); + + if (textPoint == null) + { + continue; + } + + final int offset = plugin.isHotKeyPressed() + ? item.getOffset() + : offsetMap.compute(item.getLocation(), (k, v) -> v != null ? v + 1 : 0); + + final int textX = textPoint.getX(); + final int textY = textPoint.getY() - (STRING_GAP * offset); + + if (plugin.isHotKeyPressed()) + { + final int stringWidth = fm.stringWidth(itemString); + final int stringHeight = fm.getHeight(); + + // Item bounds + int x = textX - 2; + int y = textY - stringHeight - 2; + int width = stringWidth + 4; + int height = stringHeight + 4; + final Rectangle itemBounds = new Rectangle(x, y, width, height); + + // Hidden box + x += width + 2; + y = textY - (RECTANGLE_SIZE + stringHeight) / 2; + width = height = RECTANGLE_SIZE; + final Rectangle itemHiddenBox = new Rectangle(x, y, width, height); + + // Highlight box + x += width + 2; + final Rectangle itemHighlightBox = new Rectangle(x, y, width, height); + + boolean mouseInBox = itemBounds.contains(mousePos.getX(), mousePos.getY()); + boolean mouseInHiddenBox = itemHiddenBox.contains(mousePos.getX(), mousePos.getY()); + boolean mouseInHighlightBox = itemHighlightBox.contains(mousePos.getX(), mousePos.getY()); + + if (mouseInBox) + { + plugin.setTextBoxBounds(new SimpleEntry<>(itemBounds, item)); + } + else if (mouseInHiddenBox) + { + plugin.setHiddenBoxBounds(new SimpleEntry<>(itemHiddenBox, item)); + + } + else if (mouseInHighlightBox) + { + plugin.setHighlightBoxBounds(new SimpleEntry<>(itemHighlightBox, item)); + } + + boolean topItem = topGroundItem == item; + + // Draw background if hovering + if (topItem && (mouseInBox || mouseInHiddenBox || mouseInHighlightBox)) + { + backgroundComponent.setRectangle(itemBounds); + backgroundComponent.render(graphics); + } + + // Draw hidden box + drawRectangle(graphics, itemHiddenBox, topItem && mouseInHiddenBox ? Color.RED : color, hidden != null, true); + + // Draw highlight box + drawRectangle(graphics, itemHighlightBox, topItem && mouseInHighlightBox ? Color.GREEN : color, highlighted != null, false); + } + + if (config.toggleOutline()) + { + graphics.setColor(Color.BLACK); + graphics.drawString(itemString, textX + 1, textY + 1); + graphics.drawString(itemString, textX - 1, textY - 1); + graphics.drawString(itemString, textX - 1, textY + 1); + graphics.drawString(itemString, textX + 1, textY - 1); + } + + textComponent.setText(itemString); + textComponent.setColor(color); + textComponent.setPosition(new java.awt.Point(textX, textY)); + textComponent.render(graphics); + } + + return null; + } + + private void drawRectangle(Graphics2D graphics, Rectangle rect, Color color, boolean inList, boolean hiddenBox) + { + graphics.setColor(Color.BLACK); + graphics.drawRect(rect.x + 1, rect.y + 1, rect.width, rect.height); + + graphics.setColor(color); + graphics.draw(rect); + + if (inList) + { + graphics.fill(rect); + } + + graphics.setColor(Color.WHITE); + // Minus symbol + graphics.drawLine + ( + rect.x + 2, + rect.y + (rect.height / 2), + rect.x + rect.width - 2, + rect.y + (rect.height / 2) + ); + + if (!hiddenBox) + { + // Plus symbol + graphics.drawLine + ( + rect.x + (rect.width / 2), + rect.y + 2, + rect.x + (rect.width / 2), + rect.y + rect.height - 2 + ); + } + + } + +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/grounditems/GroundItemsPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/grounditems/GroundItemsPlugin.java index a3bf0f37ea..35ee979085 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/grounditems/GroundItemsPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/grounditems/GroundItemsPlugin.java @@ -1,680 +1,680 @@ -/* - * Copyright (c) 2017, Aria - * Copyright (c) 2018, Adam - * 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.grounditems; - -import com.google.common.cache.CacheBuilder; -import com.google.common.cache.LoadingCache; -import com.google.inject.Provides; -import java.awt.Color; -import java.awt.Rectangle; -import static java.lang.Boolean.TRUE; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.HashSet; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.concurrent.CopyOnWriteArrayList; -import java.util.concurrent.TimeUnit; -import javax.inject.Inject; -import lombok.AccessLevel; -import lombok.Getter; -import lombok.Setter; -import net.runelite.api.Client; -import net.runelite.api.GameState; -import net.runelite.api.Item; -import net.runelite.api.ItemComposition; -import net.runelite.api.ItemID; -import net.runelite.api.ItemLayer; -import net.runelite.api.MenuAction; -import net.runelite.api.MenuEntry; -import net.runelite.api.Node; -import net.runelite.api.Player; -import net.runelite.api.Scene; -import net.runelite.api.Tile; -import net.runelite.api.coords.WorldPoint; -import net.runelite.api.events.ClientTick; -import net.runelite.api.events.ConfigChanged; -import net.runelite.api.events.FocusChanged; -import net.runelite.api.events.GameStateChanged; -import net.runelite.api.events.ItemDespawned; -import net.runelite.api.events.ItemQuantityChanged; -import net.runelite.api.events.ItemSpawned; -import net.runelite.api.events.MenuEntryAdded; -import net.runelite.client.Notifier; -import net.runelite.client.config.ConfigManager; -import net.runelite.client.eventbus.Subscribe; -import net.runelite.client.events.NpcLootReceived; -import net.runelite.client.events.PlayerLootReceived; -import net.runelite.client.game.ItemManager; -import net.runelite.client.game.ItemStack; -import net.runelite.client.input.KeyManager; -import net.runelite.client.input.MouseManager; -import net.runelite.client.plugins.Plugin; -import net.runelite.client.plugins.PluginDescriptor; -import static net.runelite.client.plugins.grounditems.config.ItemHighlightMode.OVERLAY; -import net.runelite.client.plugins.grounditems.config.MenuHighlightMode; -import static net.runelite.client.plugins.grounditems.config.MenuHighlightMode.BOTH; -import static net.runelite.client.plugins.grounditems.config.MenuHighlightMode.NAME; -import static net.runelite.client.plugins.grounditems.config.MenuHighlightMode.OPTION; -import net.runelite.client.plugins.grounditems.config.ValueCalculationMode; -import net.runelite.client.ui.overlay.OverlayManager; -import net.runelite.client.util.ColorUtil; -import net.runelite.client.util.StackFormatter; -import net.runelite.client.util.Text; - -@PluginDescriptor( - name = "Ground Items", - description = "Highlight ground items and/or show price information", - tags = {"grand", "exchange", "high", "alchemy", "prices", "highlight", "overlay"} -) -public class GroundItemsPlugin extends Plugin -{ - // Used when getting High Alchemy value - multiplied by general store price. - private static final float HIGH_ALCHEMY_CONSTANT = 0.6f; - // ItemID for coins - private static final int COINS = ItemID.COINS_995; - // Ground item menu options - private static final int FIRST_OPTION = MenuAction.GROUND_ITEM_FIRST_OPTION.getId(); - private static final int SECOND_OPTION = MenuAction.GROUND_ITEM_SECOND_OPTION.getId(); - private static final int THIRD_OPTION = MenuAction.GROUND_ITEM_THIRD_OPTION.getId(); // this is Take - private static final int FOURTH_OPTION = MenuAction.GROUND_ITEM_FOURTH_OPTION.getId(); - private static final int FIFTH_OPTION = MenuAction.GROUND_ITEM_FIFTH_OPTION.getId(); - private static final int EXAMINE_ITEM = MenuAction.EXAMINE_ITEM_GROUND.getId(); - - @Getter(AccessLevel.PACKAGE) - @Setter(AccessLevel.PACKAGE) - private Map.Entry textBoxBounds; - - @Getter(AccessLevel.PACKAGE) - @Setter(AccessLevel.PACKAGE) - private Map.Entry hiddenBoxBounds; - - @Getter(AccessLevel.PACKAGE) - @Setter(AccessLevel.PACKAGE) - private Map.Entry highlightBoxBounds; - - @Getter(AccessLevel.PACKAGE) - @Setter(AccessLevel.PACKAGE) - private boolean hotKeyPressed; - - @Getter(AccessLevel.PACKAGE) - @Setter(AccessLevel.PACKAGE) - private boolean hideAll; - - private List hiddenItemList = new CopyOnWriteArrayList<>(); - private List highlightedItemsList = new CopyOnWriteArrayList<>(); - - @Inject - private GroundItemInputListener inputListener; - - @Inject - private MouseManager mouseManager; - - @Inject - private KeyManager keyManager; - - @Inject - private Client client; - - @Inject - private ItemManager itemManager; - - @Inject - private OverlayManager overlayManager; - - @Inject - private GroundItemsConfig config; - - @Inject - private GroundItemsOverlay overlay; - - @Inject - private Notifier notifier; - - @Getter - public static final Map collectedGroundItems = new LinkedHashMap<>(); - private final Map priceChecks = new LinkedHashMap<>(); - private LoadingCache highlightedItems; - private LoadingCache hiddenItems; - - @Provides - GroundItemsConfig provideConfig(ConfigManager configManager) - { - return configManager.getConfig(GroundItemsConfig.class); - } - - @Override - protected void startUp() - { - overlayManager.add(overlay); - reset(); - mouseManager.registerMouseListener(inputListener); - keyManager.registerKeyListener(inputListener); - } - - @Override - protected void shutDown() throws Exception - { - overlayManager.remove(overlay); - mouseManager.unregisterMouseListener(inputListener); - keyManager.unregisterKeyListener(inputListener); - highlightedItems.invalidateAll(); - highlightedItems = null; - hiddenItems.invalidateAll(); - hiddenItems = null; - hiddenItemList = null; - highlightedItemsList = null; - collectedGroundItems.clear(); - } - - @Subscribe - public void onConfigChanged(ConfigChanged event) - { - if (event.getGroup().equals("grounditems")) - { - reset(); - } - } - - @Subscribe - public void onGameStateChanged(final GameStateChanged event) - { - if (event.getGameState() == GameState.LOADING) - { - collectedGroundItems.clear(); - } - } - - @Subscribe - public void onItemSpawned(ItemSpawned itemSpawned) - { - Item item = itemSpawned.getItem(); - Tile tile = itemSpawned.getTile(); - - GroundItem groundItem = buildGroundItem(tile, item); - - GroundItem.GroundItemKey groundItemKey = new GroundItem.GroundItemKey(item.getId(), tile.getWorldLocation()); - GroundItem existing = collectedGroundItems.putIfAbsent(groundItemKey, groundItem); - if (existing != null) - { - existing.setQuantity(existing.getQuantity() + groundItem.getQuantity()); - } - - boolean shouldNotify = !config.onlyShowLoot() && config.highlightedColor().equals(getHighlighted( - groundItem.getName(), - groundItem.getGePrice(), - groundItem.getHaPrice())); - - if (config.notifyHighlightedDrops() && shouldNotify) - { - notifyHighlightedItem(groundItem); - } - } - - @Subscribe - public void onItemDespawned(ItemDespawned itemDespawned) - { - Item item = itemDespawned.getItem(); - Tile tile = itemDespawned.getTile(); - - GroundItem.GroundItemKey groundItemKey = new GroundItem.GroundItemKey(item.getId(), tile.getWorldLocation()); - GroundItem groundItem = collectedGroundItems.get(groundItemKey); - if (groundItem == null) - { - return; - } - - if (groundItem.getQuantity() <= item.getQuantity()) - { - collectedGroundItems.remove(groundItemKey); - } - else - { - groundItem.setQuantity(groundItem.getQuantity() - item.getQuantity()); - } - } - - @Subscribe - public void onItemQuantityChanged(ItemQuantityChanged itemQuantityChanged) - { - Item item = itemQuantityChanged.getItem(); - Tile tile = itemQuantityChanged.getTile(); - int oldQuantity = itemQuantityChanged.getOldQuantity(); - int newQuantity = itemQuantityChanged.getNewQuantity(); - - int diff = newQuantity - oldQuantity; - GroundItem.GroundItemKey groundItemKey = new GroundItem.GroundItemKey(item.getId(), tile.getWorldLocation()); - GroundItem groundItem = collectedGroundItems.get(groundItemKey); - if (groundItem != null) - { - groundItem.setQuantity(groundItem.getQuantity() + diff); - } - } - - @Subscribe - public void onNpcLootReceived(NpcLootReceived npcLootReceived) - { - Collection items = npcLootReceived.getItems(); - lootReceived(items); - } - - @Subscribe - public void onPlayerLootReceived(PlayerLootReceived playerLootReceived) - { - Collection items = playerLootReceived.getItems(); - lootReceived(items); - } - - @Subscribe - public void onClientTick(ClientTick event) - { - if (!config.collapseEntries()) - { - return; - } - - final MenuEntry[] menuEntries = client.getMenuEntries(); - final List newEntries = new ArrayList<>(menuEntries.length); - - outer: - for (int i = menuEntries.length - 1; i >= 0; i--) - { - MenuEntry menuEntry = menuEntries[i]; - - int menuType = menuEntry.getType(); - if (menuType == FIRST_OPTION || menuType == SECOND_OPTION || menuType == THIRD_OPTION - || menuType == FOURTH_OPTION || menuType == FIFTH_OPTION || menuType == EXAMINE_ITEM) - { - for (MenuEntryWithCount entryWCount : newEntries) - { - if (entryWCount.getEntry().equals(menuEntry)) - { - entryWCount.increment(); - continue outer; - } - } - } - - newEntries.add(new MenuEntryWithCount(menuEntry)); - } - - Collections.reverse(newEntries); - - client.setMenuEntries(newEntries.stream().map(e -> - { - final MenuEntry entry = e.getEntry(); - final int count = e.getCount(); - if (count > 1) - { - entry.setTarget(entry.getTarget() + " x " + count); - } - - return entry; - }).toArray(MenuEntry[]::new)); - } - - private void lootReceived(Collection items) - { - for (ItemStack itemStack : items) - { - WorldPoint location = WorldPoint.fromLocal(client, itemStack.getLocation()); - GroundItem.GroundItemKey groundItemKey = new GroundItem.GroundItemKey(itemStack.getId(), location); - GroundItem groundItem = collectedGroundItems.get(groundItemKey); - if (groundItem != null) - { - groundItem.setMine(true); - - boolean shouldNotify = config.onlyShowLoot() && config.highlightedColor().equals(getHighlighted( - groundItem.getName(), - groundItem.getGePrice(), - groundItem.getHaPrice())); - - if (config.notifyHighlightedDrops() && shouldNotify) - { - notifyHighlightedItem(groundItem); - } - } - } - } - - private GroundItem buildGroundItem(final Tile tile, final Item item) - { - // Collect the data for the item - final int itemId = item.getId(); - final ItemComposition itemComposition = itemManager.getItemComposition(itemId); - final int realItemId = itemComposition.getNote() != -1 ? itemComposition.getLinkedNoteId() : itemId; - final int alchPrice = Math.round(itemComposition.getPrice() * HIGH_ALCHEMY_CONSTANT); - - final GroundItem groundItem = GroundItem.builder() - .id(itemId) - .location(tile.getWorldLocation()) - .itemId(realItemId) - .quantity(item.getQuantity()) - .name(itemComposition.getName()) - .haPrice(alchPrice) - .height(tile.getItemLayer().getHeight()) - .tradeable(itemComposition.isTradeable()) - .build(); - - - // Update item price in case it is coins - if (realItemId == COINS) - { - groundItem.setHaPrice(1); - groundItem.setGePrice(1); - } - else - { - groundItem.setGePrice(itemManager.getItemPrice(realItemId)); - } - - return groundItem; - } - - private void reset() - { - // gets the hidden items from the text box in the config - hiddenItemList = Text.fromCSV(config.getHiddenItems()); - - // gets the highlighted items from the text box in the config - highlightedItemsList = Text.fromCSV(config.getHighlightItems()); - - highlightedItems = CacheBuilder.newBuilder() - .maximumSize(512L) - .expireAfterAccess(10, TimeUnit.MINUTES) - .build(new WildcardMatchLoader(highlightedItemsList)); - - hiddenItems = CacheBuilder.newBuilder() - .maximumSize(512L) - .expireAfterAccess(10, TimeUnit.MINUTES) - .build(new WildcardMatchLoader(hiddenItemList)); - - // Cache colors - priceChecks.clear(); - - if (config.insaneValuePrice() > 0) - { - priceChecks.put(config.insaneValuePrice(), config.insaneValueColor()); - } - - if (config.highValuePrice() > 0) - { - priceChecks.put(config.highValuePrice(), config.highValueColor()); - } - - if (config.mediumValuePrice() > 0) - { - priceChecks.put(config.mediumValuePrice(), config.mediumValueColor()); - } - - if (config.lowValuePrice() > 0) - { - priceChecks.put(config.lowValuePrice(), config.lowValueColor()); - } - - if (config.getHighlightOverValue() > 0) - { - priceChecks.put(config.getHighlightOverValue(), config.highlightedColor()); - } - } - - @Subscribe - public void onMenuEntryAdded(MenuEntryAdded event) - { - if (config.itemHighlightMode() != OVERLAY - && event.getOption().equals("Take") - && event.getType() == THIRD_OPTION) - { - int itemId = event.getIdentifier(); - Scene scene = client.getScene(); - Tile tile = scene.getTiles()[client.getPlane()][event.getActionParam0()][event.getActionParam1()]; - ItemLayer itemLayer = tile.getItemLayer(); - - if (itemLayer == null) - { - return; - } - - MenuEntry[] menuEntries = client.getMenuEntries(); - MenuEntry lastEntry = menuEntries[menuEntries.length - 1]; - - int quantity = 1; - Node current = itemLayer.getBottom(); - - while (current instanceof Item) - { - Item item = (Item) current; - if (item.getId() == itemId) - { - quantity = item.getQuantity(); - } - current = current.getNext(); - } - - final ItemComposition itemComposition = itemManager.getItemComposition(itemId); - final int realItemId = itemComposition.getNote() != -1 ? itemComposition.getLinkedNoteId() : itemComposition.getId(); - final int itemPrice = itemManager.getItemPrice(realItemId); - final int price = itemPrice <= 0 ? itemComposition.getPrice() : itemPrice; - final int haPrice = Math.round(itemComposition.getPrice() * HIGH_ALCHEMY_CONSTANT) * quantity; - final int gePrice = quantity * price; - final Color hidden = getHidden(itemComposition.getName(), gePrice, haPrice, itemComposition.isTradeable()); - final Color highlighted = getHighlighted(itemComposition.getName(), gePrice, haPrice); - final Color color = getItemColor(highlighted, hidden); - final boolean canBeRecolored = highlighted != null || (hidden != null && config.recolorMenuHiddenItems()); - - if (color != null && canBeRecolored && !color.equals(config.defaultColor())) - { - final MenuHighlightMode mode = config.menuHighlightMode(); - - if (mode == BOTH || mode == OPTION) - { - lastEntry.setOption(ColorUtil.prependColorTag("Take", color)); - } - - if (mode == BOTH || mode == NAME) - { - String target = lastEntry.getTarget().substring(lastEntry.getTarget().indexOf(">") + 1); - lastEntry.setTarget(ColorUtil.prependColorTag(target, color)); - } - } - - if (config.showMenuItemQuantities() && itemComposition.isStackable() && quantity > 1) - { - lastEntry.setTarget(lastEntry.getTarget() + " (" + quantity + ")"); - } - - if(config.removeIgnored() && event.getOption().equals("Take") && hiddenItemList.contains(Text.removeTags(event.getTarget()))) - { - menuEntries = removeOption(event.getOption(), event.getTarget()); - } - - client.setMenuEntries(menuEntries); - } - } - - private MenuEntry[] removeOption(String option, String target) - { - MenuEntry[] entries = client.getMenuEntries(); - int j = 0; - if(entries.length > 1) - { - MenuEntry[] newEntries = new MenuEntry[entries.length - 1]; - for (int i = 0; i < entries.length; ++i) - { - if (!(entries[i].getOption().equals(option) && entries[i].getTarget().equals(target))) - { - newEntries[j++] = entries[i]; - } - } - - return newEntries; - } - else - { - return entries; - } - - - } - - void updateList(String item, boolean hiddenList) - { - final Set hiddenItemSet = new HashSet<>(hiddenItemList); - final Set highlightedItemSet = new HashSet<>(highlightedItemsList); - - if (hiddenList) - { - highlightedItemSet.removeIf(item::equalsIgnoreCase); - } - else - { - hiddenItemSet.removeIf(item::equalsIgnoreCase); - } - - final Set items = hiddenList ? hiddenItemSet : highlightedItemSet; - - if (!items.removeIf(item::equalsIgnoreCase)) - { - items.add(item); - } - - config.setHiddenItems(Text.toCSV(hiddenItemSet)); - config.setHighlightedItem(Text.toCSV(highlightedItemSet)); - } - - Color getHighlighted(String item, int gePrice, int haPrice) - { - if (TRUE.equals(highlightedItems.getUnchecked(item))) - { - return config.highlightedColor(); - } - - // Explicit hide takes priority over implicit highlight - if (TRUE.equals(hiddenItems.getUnchecked(item))) - { - return null; - } - - ValueCalculationMode mode = config.valueCalculationMode(); - for (Map.Entry entry : priceChecks.entrySet()) - { - switch (mode) - { - case GE: - if (gePrice > entry.getKey()) - { - return entry.getValue(); - } - break; - case HA: - if (haPrice > entry.getKey()) - { - return entry.getValue(); - } - break; - default: // case HIGHEST - if (gePrice > entry.getKey() || haPrice > entry.getKey()) - { - return entry.getValue(); - } - break; - } - } - - return null; - } - - Color getHidden(String item, int gePrice, int haPrice, boolean isTradeable) - { - final boolean isExplicitHidden = TRUE.equals(hiddenItems.getUnchecked(item)); - final boolean isExplicitHighlight = TRUE.equals(highlightedItems.getUnchecked(item)); - final boolean canBeHidden = gePrice > 0 || isTradeable || !config.dontHideUntradeables(); - final boolean underGe = gePrice < config.getHideUnderValue(); - final boolean underHa = haPrice < config.getHideUnderValue(); - - // Explicit highlight takes priority over implicit hide - return isExplicitHidden || (!isExplicitHighlight && canBeHidden && underGe && underHa) - ? config.hiddenColor() - : null; - } - - Color getItemColor(Color highlighted, Color hidden) - { - if (highlighted != null) - { - return highlighted; - } - - if (hidden != null) - { - return hidden; - } - - return config.defaultColor(); - } - - @Subscribe - public void onFocusChanged(FocusChanged focusChanged) - { - if (!focusChanged.isFocused()) - { - setHotKeyPressed(false); - } - } - - private void notifyHighlightedItem(GroundItem item) - { - final Player local = client.getLocalPlayer(); - final StringBuilder notificationStringBuilder = new StringBuilder() - .append("[") - .append(local.getName()) - .append("] received a highlighted drop: ") - .append(item.getName()); - - if (item.getQuantity() > 1) - { - notificationStringBuilder.append(" x ").append(item.getQuantity()); - - - if (item.getQuantity() > (int) Character.MAX_VALUE) - { - notificationStringBuilder.append(" (Lots!)"); - } - else - { - notificationStringBuilder.append(" (") - .append(StackFormatter.quantityToStackSize(item.getQuantity())) - .append(")"); - } - } - - notificationStringBuilder.append("!"); - notifier.notify(notificationStringBuilder.toString()); - } -} +/* + * Copyright (c) 2017, Aria + * Copyright (c) 2018, Adam + * 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.grounditems; + +import com.google.common.cache.CacheBuilder; +import com.google.common.cache.LoadingCache; +import com.google.inject.Provides; +import java.awt.Color; +import java.awt.Rectangle; +import static java.lang.Boolean.TRUE; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.HashSet; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.CopyOnWriteArrayList; +import java.util.concurrent.TimeUnit; +import javax.inject.Inject; +import lombok.AccessLevel; +import lombok.Getter; +import lombok.Setter; +import net.runelite.api.Client; +import net.runelite.api.GameState; +import net.runelite.api.Item; +import net.runelite.api.ItemComposition; +import net.runelite.api.ItemID; +import net.runelite.api.ItemLayer; +import net.runelite.api.MenuAction; +import net.runelite.api.MenuEntry; +import net.runelite.api.Node; +import net.runelite.api.Player; +import net.runelite.api.Scene; +import net.runelite.api.Tile; +import net.runelite.api.coords.WorldPoint; +import net.runelite.api.events.ClientTick; +import net.runelite.api.events.ConfigChanged; +import net.runelite.api.events.FocusChanged; +import net.runelite.api.events.GameStateChanged; +import net.runelite.api.events.ItemDespawned; +import net.runelite.api.events.ItemQuantityChanged; +import net.runelite.api.events.ItemSpawned; +import net.runelite.api.events.MenuEntryAdded; +import net.runelite.client.Notifier; +import net.runelite.client.config.ConfigManager; +import net.runelite.client.eventbus.Subscribe; +import net.runelite.client.events.NpcLootReceived; +import net.runelite.client.events.PlayerLootReceived; +import net.runelite.client.game.ItemManager; +import net.runelite.client.game.ItemStack; +import net.runelite.client.input.KeyManager; +import net.runelite.client.input.MouseManager; +import net.runelite.client.plugins.Plugin; +import net.runelite.client.plugins.PluginDescriptor; +import static net.runelite.client.plugins.grounditems.config.ItemHighlightMode.OVERLAY; +import net.runelite.client.plugins.grounditems.config.MenuHighlightMode; +import static net.runelite.client.plugins.grounditems.config.MenuHighlightMode.BOTH; +import static net.runelite.client.plugins.grounditems.config.MenuHighlightMode.NAME; +import static net.runelite.client.plugins.grounditems.config.MenuHighlightMode.OPTION; +import net.runelite.client.plugins.grounditems.config.ValueCalculationMode; +import net.runelite.client.ui.overlay.OverlayManager; +import net.runelite.client.util.ColorUtil; +import net.runelite.client.util.StackFormatter; +import net.runelite.client.util.Text; + +@PluginDescriptor( + name = "Ground Items", + description = "Highlight ground items and/or show price information", + tags = {"grand", "exchange", "high", "alchemy", "prices", "highlight", "overlay"} +) +public class GroundItemsPlugin extends Plugin +{ + // Used when getting High Alchemy value - multiplied by general store price. + private static final float HIGH_ALCHEMY_CONSTANT = 0.6f; + // ItemID for coins + private static final int COINS = ItemID.COINS_995; + // Ground item menu options + private static final int FIRST_OPTION = MenuAction.GROUND_ITEM_FIRST_OPTION.getId(); + private static final int SECOND_OPTION = MenuAction.GROUND_ITEM_SECOND_OPTION.getId(); + private static final int THIRD_OPTION = MenuAction.GROUND_ITEM_THIRD_OPTION.getId(); // this is Take + private static final int FOURTH_OPTION = MenuAction.GROUND_ITEM_FOURTH_OPTION.getId(); + private static final int FIFTH_OPTION = MenuAction.GROUND_ITEM_FIFTH_OPTION.getId(); + private static final int EXAMINE_ITEM = MenuAction.EXAMINE_ITEM_GROUND.getId(); + + @Getter(AccessLevel.PACKAGE) + @Setter(AccessLevel.PACKAGE) + private Map.Entry textBoxBounds; + + @Getter(AccessLevel.PACKAGE) + @Setter(AccessLevel.PACKAGE) + private Map.Entry hiddenBoxBounds; + + @Getter(AccessLevel.PACKAGE) + @Setter(AccessLevel.PACKAGE) + private Map.Entry highlightBoxBounds; + + @Getter(AccessLevel.PACKAGE) + @Setter(AccessLevel.PACKAGE) + private boolean hotKeyPressed; + + @Getter(AccessLevel.PACKAGE) + @Setter(AccessLevel.PACKAGE) + private boolean hideAll; + + private List hiddenItemList = new CopyOnWriteArrayList<>(); + private List highlightedItemsList = new CopyOnWriteArrayList<>(); + + @Inject + private GroundItemInputListener inputListener; + + @Inject + private MouseManager mouseManager; + + @Inject + private KeyManager keyManager; + + @Inject + private Client client; + + @Inject + private ItemManager itemManager; + + @Inject + private OverlayManager overlayManager; + + @Inject + private GroundItemsConfig config; + + @Inject + private GroundItemsOverlay overlay; + + @Inject + private Notifier notifier; + + @Getter + public static final Map collectedGroundItems = new LinkedHashMap<>(); + private final Map priceChecks = new LinkedHashMap<>(); + private LoadingCache highlightedItems; + private LoadingCache hiddenItems; + + @Provides + GroundItemsConfig provideConfig(ConfigManager configManager) + { + return configManager.getConfig(GroundItemsConfig.class); + } + + @Override + protected void startUp() + { + overlayManager.add(overlay); + reset(); + mouseManager.registerMouseListener(inputListener); + keyManager.registerKeyListener(inputListener); + } + + @Override + protected void shutDown() throws Exception + { + overlayManager.remove(overlay); + mouseManager.unregisterMouseListener(inputListener); + keyManager.unregisterKeyListener(inputListener); + highlightedItems.invalidateAll(); + highlightedItems = null; + hiddenItems.invalidateAll(); + hiddenItems = null; + hiddenItemList = null; + highlightedItemsList = null; + collectedGroundItems.clear(); + } + + @Subscribe + public void onConfigChanged(ConfigChanged event) + { + if (event.getGroup().equals("grounditems")) + { + reset(); + } + } + + @Subscribe + public void onGameStateChanged(final GameStateChanged event) + { + if (event.getGameState() == GameState.LOADING) + { + collectedGroundItems.clear(); + } + } + + @Subscribe + public void onItemSpawned(ItemSpawned itemSpawned) + { + Item item = itemSpawned.getItem(); + Tile tile = itemSpawned.getTile(); + + GroundItem groundItem = buildGroundItem(tile, item); + + GroundItem.GroundItemKey groundItemKey = new GroundItem.GroundItemKey(item.getId(), tile.getWorldLocation()); + GroundItem existing = collectedGroundItems.putIfAbsent(groundItemKey, groundItem); + if (existing != null) + { + existing.setQuantity(existing.getQuantity() + groundItem.getQuantity()); + } + + boolean shouldNotify = !config.onlyShowLoot() && config.highlightedColor().equals(getHighlighted( + groundItem.getName(), + groundItem.getGePrice(), + groundItem.getHaPrice())); + + if (config.notifyHighlightedDrops() && shouldNotify) + { + notifyHighlightedItem(groundItem); + } + } + + @Subscribe + public void onItemDespawned(ItemDespawned itemDespawned) + { + Item item = itemDespawned.getItem(); + Tile tile = itemDespawned.getTile(); + + GroundItem.GroundItemKey groundItemKey = new GroundItem.GroundItemKey(item.getId(), tile.getWorldLocation()); + GroundItem groundItem = collectedGroundItems.get(groundItemKey); + if (groundItem == null) + { + return; + } + + if (groundItem.getQuantity() <= item.getQuantity()) + { + collectedGroundItems.remove(groundItemKey); + } + else + { + groundItem.setQuantity(groundItem.getQuantity() - item.getQuantity()); + } + } + + @Subscribe + public void onItemQuantityChanged(ItemQuantityChanged itemQuantityChanged) + { + Item item = itemQuantityChanged.getItem(); + Tile tile = itemQuantityChanged.getTile(); + int oldQuantity = itemQuantityChanged.getOldQuantity(); + int newQuantity = itemQuantityChanged.getNewQuantity(); + + int diff = newQuantity - oldQuantity; + GroundItem.GroundItemKey groundItemKey = new GroundItem.GroundItemKey(item.getId(), tile.getWorldLocation()); + GroundItem groundItem = collectedGroundItems.get(groundItemKey); + if (groundItem != null) + { + groundItem.setQuantity(groundItem.getQuantity() + diff); + } + } + + @Subscribe + public void onNpcLootReceived(NpcLootReceived npcLootReceived) + { + Collection items = npcLootReceived.getItems(); + lootReceived(items); + } + + @Subscribe + public void onPlayerLootReceived(PlayerLootReceived playerLootReceived) + { + Collection items = playerLootReceived.getItems(); + lootReceived(items); + } + + @Subscribe + public void onClientTick(ClientTick event) + { + if (!config.collapseEntries()) + { + return; + } + + final MenuEntry[] menuEntries = client.getMenuEntries(); + final List newEntries = new ArrayList<>(menuEntries.length); + + outer: + for (int i = menuEntries.length - 1; i >= 0; i--) + { + MenuEntry menuEntry = menuEntries[i]; + + int menuType = menuEntry.getType(); + if (menuType == FIRST_OPTION || menuType == SECOND_OPTION || menuType == THIRD_OPTION + || menuType == FOURTH_OPTION || menuType == FIFTH_OPTION || menuType == EXAMINE_ITEM) + { + for (MenuEntryWithCount entryWCount : newEntries) + { + if (entryWCount.getEntry().equals(menuEntry)) + { + entryWCount.increment(); + continue outer; + } + } + } + + newEntries.add(new MenuEntryWithCount(menuEntry)); + } + + Collections.reverse(newEntries); + + client.setMenuEntries(newEntries.stream().map(e -> + { + final MenuEntry entry = e.getEntry(); + final int count = e.getCount(); + if (count > 1) + { + entry.setTarget(entry.getTarget() + " x " + count); + } + + return entry; + }).toArray(MenuEntry[]::new)); + } + + private void lootReceived(Collection items) + { + for (ItemStack itemStack : items) + { + WorldPoint location = WorldPoint.fromLocal(client, itemStack.getLocation()); + GroundItem.GroundItemKey groundItemKey = new GroundItem.GroundItemKey(itemStack.getId(), location); + GroundItem groundItem = collectedGroundItems.get(groundItemKey); + if (groundItem != null) + { + groundItem.setMine(true); + + boolean shouldNotify = config.onlyShowLoot() && config.highlightedColor().equals(getHighlighted( + groundItem.getName(), + groundItem.getGePrice(), + groundItem.getHaPrice())); + + if (config.notifyHighlightedDrops() && shouldNotify) + { + notifyHighlightedItem(groundItem); + } + } + } + } + + private GroundItem buildGroundItem(final Tile tile, final Item item) + { + // Collect the data for the item + final int itemId = item.getId(); + final ItemComposition itemComposition = itemManager.getItemComposition(itemId); + final int realItemId = itemComposition.getNote() != -1 ? itemComposition.getLinkedNoteId() : itemId; + final int alchPrice = Math.round(itemComposition.getPrice() * HIGH_ALCHEMY_CONSTANT); + + final GroundItem groundItem = GroundItem.builder() + .id(itemId) + .location(tile.getWorldLocation()) + .itemId(realItemId) + .quantity(item.getQuantity()) + .name(itemComposition.getName()) + .haPrice(alchPrice) + .height(tile.getItemLayer().getHeight()) + .tradeable(itemComposition.isTradeable()) + .build(); + + + // Update item price in case it is coins + if (realItemId == COINS) + { + groundItem.setHaPrice(1); + groundItem.setGePrice(1); + } + else + { + groundItem.setGePrice(itemManager.getItemPrice(realItemId)); + } + + return groundItem; + } + + private void reset() + { + // gets the hidden items from the text box in the config + hiddenItemList = Text.fromCSV(config.getHiddenItems()); + + // gets the highlighted items from the text box in the config + highlightedItemsList = Text.fromCSV(config.getHighlightItems()); + + highlightedItems = CacheBuilder.newBuilder() + .maximumSize(512L) + .expireAfterAccess(10, TimeUnit.MINUTES) + .build(new WildcardMatchLoader(highlightedItemsList)); + + hiddenItems = CacheBuilder.newBuilder() + .maximumSize(512L) + .expireAfterAccess(10, TimeUnit.MINUTES) + .build(new WildcardMatchLoader(hiddenItemList)); + + // Cache colors + priceChecks.clear(); + + if (config.insaneValuePrice() > 0) + { + priceChecks.put(config.insaneValuePrice(), config.insaneValueColor()); + } + + if (config.highValuePrice() > 0) + { + priceChecks.put(config.highValuePrice(), config.highValueColor()); + } + + if (config.mediumValuePrice() > 0) + { + priceChecks.put(config.mediumValuePrice(), config.mediumValueColor()); + } + + if (config.lowValuePrice() > 0) + { + priceChecks.put(config.lowValuePrice(), config.lowValueColor()); + } + + if (config.getHighlightOverValue() > 0) + { + priceChecks.put(config.getHighlightOverValue(), config.highlightedColor()); + } + } + + @Subscribe + public void onMenuEntryAdded(MenuEntryAdded event) + { + if (config.itemHighlightMode() != OVERLAY + && event.getOption().equals("Take") + && event.getType() == THIRD_OPTION) + { + int itemId = event.getIdentifier(); + Scene scene = client.getScene(); + Tile tile = scene.getTiles()[client.getPlane()][event.getActionParam0()][event.getActionParam1()]; + ItemLayer itemLayer = tile.getItemLayer(); + + if (itemLayer == null) + { + return; + } + + MenuEntry[] menuEntries = client.getMenuEntries(); + MenuEntry lastEntry = menuEntries[menuEntries.length - 1]; + + int quantity = 1; + Node current = itemLayer.getBottom(); + + while (current instanceof Item) + { + Item item = (Item) current; + if (item.getId() == itemId) + { + quantity = item.getQuantity(); + } + current = current.getNext(); + } + + final ItemComposition itemComposition = itemManager.getItemComposition(itemId); + final int realItemId = itemComposition.getNote() != -1 ? itemComposition.getLinkedNoteId() : itemComposition.getId(); + final int itemPrice = itemManager.getItemPrice(realItemId); + final int price = itemPrice <= 0 ? itemComposition.getPrice() : itemPrice; + final int haPrice = Math.round(itemComposition.getPrice() * HIGH_ALCHEMY_CONSTANT) * quantity; + final int gePrice = quantity * price; + final Color hidden = getHidden(itemComposition.getName(), gePrice, haPrice, itemComposition.isTradeable()); + final Color highlighted = getHighlighted(itemComposition.getName(), gePrice, haPrice); + final Color color = getItemColor(highlighted, hidden); + final boolean canBeRecolored = highlighted != null || (hidden != null && config.recolorMenuHiddenItems()); + + if (color != null && canBeRecolored && !color.equals(config.defaultColor())) + { + final MenuHighlightMode mode = config.menuHighlightMode(); + + if (mode == BOTH || mode == OPTION) + { + lastEntry.setOption(ColorUtil.prependColorTag("Take", color)); + } + + if (mode == BOTH || mode == NAME) + { + String target = lastEntry.getTarget().substring(lastEntry.getTarget().indexOf(">") + 1); + lastEntry.setTarget(ColorUtil.prependColorTag(target, color)); + } + } + + if (config.showMenuItemQuantities() && itemComposition.isStackable() && quantity > 1) + { + lastEntry.setTarget(lastEntry.getTarget() + " (" + quantity + ")"); + } + + if (config.removeIgnored() && event.getOption().equals("Take") && hiddenItemList.contains(Text.removeTags(event.getTarget()))) + { + menuEntries = removeOption(event.getOption(), event.getTarget()); + } + + client.setMenuEntries(menuEntries); + } + } + + private MenuEntry[] removeOption(String option, String target) + { + MenuEntry[] entries = client.getMenuEntries(); + int j = 0; + if (entries.length > 1) + { + MenuEntry[] newEntries = new MenuEntry[entries.length - 1]; + for (int i = 0; i < entries.length; ++i) + { + if (!(entries[i].getOption().equals(option) && entries[i].getTarget().equals(target))) + { + newEntries[j++] = entries[i]; + } + } + + return newEntries; + } + else + { + return entries; + } + + + } + + void updateList(String item, boolean hiddenList) + { + final Set hiddenItemSet = new HashSet<>(hiddenItemList); + final Set highlightedItemSet = new HashSet<>(highlightedItemsList); + + if (hiddenList) + { + highlightedItemSet.removeIf(item::equalsIgnoreCase); + } + else + { + hiddenItemSet.removeIf(item::equalsIgnoreCase); + } + + final Set items = hiddenList ? hiddenItemSet : highlightedItemSet; + + if (!items.removeIf(item::equalsIgnoreCase)) + { + items.add(item); + } + + config.setHiddenItems(Text.toCSV(hiddenItemSet)); + config.setHighlightedItem(Text.toCSV(highlightedItemSet)); + } + + Color getHighlighted(String item, int gePrice, int haPrice) + { + if (TRUE.equals(highlightedItems.getUnchecked(item))) + { + return config.highlightedColor(); + } + + // Explicit hide takes priority over implicit highlight + if (TRUE.equals(hiddenItems.getUnchecked(item))) + { + return null; + } + + ValueCalculationMode mode = config.valueCalculationMode(); + for (Map.Entry entry : priceChecks.entrySet()) + { + switch (mode) + { + case GE: + if (gePrice > entry.getKey()) + { + return entry.getValue(); + } + break; + case HA: + if (haPrice > entry.getKey()) + { + return entry.getValue(); + } + break; + default: // case HIGHEST + if (gePrice > entry.getKey() || haPrice > entry.getKey()) + { + return entry.getValue(); + } + break; + } + } + + return null; + } + + Color getHidden(String item, int gePrice, int haPrice, boolean isTradeable) + { + final boolean isExplicitHidden = TRUE.equals(hiddenItems.getUnchecked(item)); + final boolean isExplicitHighlight = TRUE.equals(highlightedItems.getUnchecked(item)); + final boolean canBeHidden = gePrice > 0 || isTradeable || !config.dontHideUntradeables(); + final boolean underGe = gePrice < config.getHideUnderValue(); + final boolean underHa = haPrice < config.getHideUnderValue(); + + // Explicit highlight takes priority over implicit hide + return isExplicitHidden || (!isExplicitHighlight && canBeHidden && underGe && underHa) + ? config.hiddenColor() + : null; + } + + Color getItemColor(Color highlighted, Color hidden) + { + if (highlighted != null) + { + return highlighted; + } + + if (hidden != null) + { + return hidden; + } + + return config.defaultColor(); + } + + @Subscribe + public void onFocusChanged(FocusChanged focusChanged) + { + if (!focusChanged.isFocused()) + { + setHotKeyPressed(false); + } + } + + private void notifyHighlightedItem(GroundItem item) + { + final Player local = client.getLocalPlayer(); + final StringBuilder notificationStringBuilder = new StringBuilder() + .append("[") + .append(local.getName()) + .append("] received a highlighted drop: ") + .append(item.getName()); + + if (item.getQuantity() > 1) + { + notificationStringBuilder.append(" x ").append(item.getQuantity()); + + + if (item.getQuantity() > (int) Character.MAX_VALUE) + { + notificationStringBuilder.append(" (Lots!)"); + } + else + { + notificationStringBuilder.append(" (") + .append(StackFormatter.quantityToStackSize(item.getQuantity())) + .append(")"); + } + } + + notificationStringBuilder.append("!"); + notifier.notify(notificationStringBuilder.toString()); + } +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/groundmarkers/GroundMarkerPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/groundmarkers/GroundMarkerPlugin.java index 88f88560a5..02ccf85756 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/groundmarkers/GroundMarkerPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/groundmarkers/GroundMarkerPlugin.java @@ -1,285 +1,287 @@ -/* - * Copyright (c) 2018, TheLonelyDev - * Copyright (c) 2018, Adam - * 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 com.google.common.base.Strings; -import com.google.gson.Gson; -import com.google.gson.reflect.TypeToken; -import com.google.inject.Provides; -import java.util.ArrayList; -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 net.runelite.api.GameState; -import net.runelite.api.MenuAction; -import net.runelite.api.MenuEntry; -import net.runelite.api.Tile; -import net.runelite.api.coords.LocalPoint; -import net.runelite.api.coords.WorldPoint; -import net.runelite.api.events.FocusChanged; -import net.runelite.api.events.GameStateChanged; -import net.runelite.api.events.MenuEntryAdded; -import net.runelite.api.events.MenuOptionClicked; -import net.runelite.client.config.ConfigManager; -import net.runelite.client.eventbus.Subscribe; -import net.runelite.client.input.KeyManager; -import net.runelite.client.plugins.Plugin; -import net.runelite.client.plugins.PluginDescriptor; -import net.runelite.client.ui.overlay.OverlayManager; - -@Slf4j -@PluginDescriptor( - name = "Ground Markers", - description = "Enable marking of tiles using the Shift key", - tags = {"overlay", "tiles"} -) -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(); - - @Getter(AccessLevel.PACKAGE) - @Setter(AccessLevel.PACKAGE) - private boolean hotKeyPressed; - - @Getter(AccessLevel.PACKAGE) - private final List points = new ArrayList<>(); - - @Inject - private Client client; - - @Inject - private GroundMarkerConfig config; - - @Inject - private GroundMarkerInputListener inputListener; - - @Inject - private ConfigManager configManager; - - @Inject - private OverlayManager overlayManager; - - @Inject - private GroundMarkerOverlay overlay; - - @Inject - private GroundMarkerMinimapOverlay minimapOverlay; - - @Inject - private KeyManager keyManager; - - private void savePoints(int regionId, Collection points) - { - if (points == null || points.isEmpty()) - { - configManager.unsetConfiguration(CONFIG_GROUP, REGION_PREFIX + regionId); - return; - } - - String json = GSON.toJson(points); - configManager.setConfiguration(CONFIG_GROUP, REGION_PREFIX + regionId, json); - } - - private Collection getPoints(int regionId) - { - String json = configManager.getConfiguration(CONFIG_GROUP, REGION_PREFIX + regionId); - if (Strings.isNullOrEmpty(json)) - { - return Collections.emptyList(); - } - - // CHECKSTYLE:OFF - return GSON.fromJson(json, new TypeToken>(){}.getType()); - // CHECKSTYLE:ON - } - - @Provides - GroundMarkerConfig provideConfig(ConfigManager configManager) - { - return configManager.getConfig(GroundMarkerConfig.class); - } - - private void loadPoints() - { - 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 regionPoints = getPoints(regionId); - Collection colorTileMarkers = translateToColorTileMarker(regionPoints); - points.addAll(colorTileMarkers); - } - } - - /** - * Translate a collection of ground marker points to color tile markers, accounting for instances - * - * @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 translateToColorTileMarker(Collection points) - { - if (points.isEmpty()) - { - return Collections.emptyList(); - } - - return points.stream() - .map(point -> new ColorTileMarker( - WorldPoint.fromRegion(point.getRegionId(), point.getRegionX(), point.getRegionY(), point.getZ()), - point.getColor())) - .flatMap(colorTile -> - { - final Collection localWorldPoints = WorldPoint.toLocalInstance(client, colorTile.getWorldPoint()); - return localWorldPoints.stream().map(wp -> new ColorTileMarker(wp, colorTile.getColor())); - }) - .collect(Collectors.toList()); - } - - @Subscribe - public void onGameStateChanged(GameStateChanged gameStateChanged) - { - if (gameStateChanged.getGameState() != GameState.LOGGED_IN) - { - return; - } - - // map region has just been updated - loadPoints(); - } - - @Subscribe - public void onFocusChanged(FocusChanged focusChanged) - { - if (!focusChanged.isFocused()) - { - hotKeyPressed = false; - } - } - - @Subscribe - public void onMenuEntryAdded(MenuEntryAdded event) - { - if (hotKeyPressed && event.getOption().equals(WALK_HERE)) - { - MenuEntry[] menuEntries = client.getMenuEntries(); - menuEntries = Arrays.copyOf(menuEntries, menuEntries.length + 1); - - MenuEntry menuEntry = menuEntries[menuEntries.length - 1] = new MenuEntry(); - - menuEntry.setOption(MARK); - menuEntry.setTarget(event.getTarget()); - menuEntry.setType(MenuAction.CANCEL.getId()); - - client.setMenuEntries(menuEntries); - } - } - - @Subscribe - public void onMenuOptionClicked(MenuOptionClicked event) - { - if (!event.getMenuOption().equals(MARK)) - { - return; - } - - Tile target = client.getSelectedSceneTile(); - if (target == null) - { - return; - } - markTile(target.getLocalLocation()); - } - - @Override - protected void startUp() - { - overlayManager.add(overlay); - overlayManager.add(minimapOverlay); - keyManager.registerKeyListener(inputListener); - loadPoints(); - } - - @Override - protected void shutDown() - { - overlayManager.remove(overlay); - overlayManager.remove(minimapOverlay); - keyManager.unregisterKeyListener(inputListener); - points.clear(); - } - - private void markTile(LocalPoint localPoint) - { - if (localPoint == null) - { - return; - } - - WorldPoint worldPoint = WorldPoint.fromLocalInstance(client, localPoint); - - int regionId = worldPoint.getRegionID(); - GroundMarkerPoint point = new GroundMarkerPoint(regionId, worldPoint.getRegionX(), worldPoint.getRegionY(), client.getPlane(), config.markerColor()); - log.debug("Updating point: {} - {}", point, worldPoint); - - List groundMarkerPoints = new ArrayList<>(getPoints(regionId)); - if (groundMarkerPoints.contains(point)) - { - groundMarkerPoints.remove(point); - } - else - { - groundMarkerPoints.add(point); - } - - savePoints(regionId, groundMarkerPoints); - - loadPoints(); - } -} +/* + * Copyright (c) 2018, TheLonelyDev + * Copyright (c) 2018, Adam + * 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 com.google.common.base.Strings; +import com.google.gson.Gson; +import com.google.gson.reflect.TypeToken; +import com.google.inject.Provides; +import java.util.ArrayList; +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 net.runelite.api.GameState; +import net.runelite.api.MenuAction; +import net.runelite.api.MenuEntry; +import net.runelite.api.Tile; +import net.runelite.api.coords.LocalPoint; +import net.runelite.api.coords.WorldPoint; +import net.runelite.api.events.FocusChanged; +import net.runelite.api.events.GameStateChanged; +import net.runelite.api.events.MenuEntryAdded; +import net.runelite.api.events.MenuOptionClicked; +import net.runelite.client.config.ConfigManager; +import net.runelite.client.eventbus.Subscribe; +import net.runelite.client.input.KeyManager; +import net.runelite.client.plugins.Plugin; +import net.runelite.client.plugins.PluginDescriptor; +import net.runelite.client.ui.overlay.OverlayManager; + +@Slf4j +@PluginDescriptor( + name = "Ground Markers", + description = "Enable marking of tiles using the Shift key", + tags = {"overlay", "tiles"} +) +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(); + + @Getter(AccessLevel.PACKAGE) + @Setter(AccessLevel.PACKAGE) + private boolean hotKeyPressed; + + @Getter(AccessLevel.PACKAGE) + private final List points = new ArrayList<>(); + + @Inject + private Client client; + + @Inject + private GroundMarkerConfig config; + + @Inject + private GroundMarkerInputListener inputListener; + + @Inject + private ConfigManager configManager; + + @Inject + private OverlayManager overlayManager; + + @Inject + private GroundMarkerOverlay overlay; + + @Inject + private GroundMarkerMinimapOverlay minimapOverlay; + + @Inject + private KeyManager keyManager; + + private void savePoints(int regionId, Collection points) + { + if (points == null || points.isEmpty()) + { + configManager.unsetConfiguration(CONFIG_GROUP, REGION_PREFIX + regionId); + return; + } + + String json = GSON.toJson(points); + configManager.setConfiguration(CONFIG_GROUP, REGION_PREFIX + regionId, json); + } + + private Collection getPoints(int regionId) + { + String json = configManager.getConfiguration(CONFIG_GROUP, REGION_PREFIX + regionId); + if (Strings.isNullOrEmpty(json)) + { + return Collections.emptyList(); + } + + // CHECKSTYLE:OFF + return GSON.fromJson(json, new TypeToken>() + { + }.getType()); + // CHECKSTYLE:ON + } + + @Provides + GroundMarkerConfig provideConfig(ConfigManager configManager) + { + return configManager.getConfig(GroundMarkerConfig.class); + } + + private void loadPoints() + { + 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 regionPoints = getPoints(regionId); + Collection colorTileMarkers = translateToColorTileMarker(regionPoints); + points.addAll(colorTileMarkers); + } + } + + /** + * Translate a collection of ground marker points to color tile markers, accounting for instances + * + * @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 translateToColorTileMarker(Collection points) + { + if (points.isEmpty()) + { + return Collections.emptyList(); + } + + return points.stream() + .map(point -> new ColorTileMarker( + WorldPoint.fromRegion(point.getRegionId(), point.getRegionX(), point.getRegionY(), point.getZ()), + point.getColor())) + .flatMap(colorTile -> + { + final Collection localWorldPoints = WorldPoint.toLocalInstance(client, colorTile.getWorldPoint()); + return localWorldPoints.stream().map(wp -> new ColorTileMarker(wp, colorTile.getColor())); + }) + .collect(Collectors.toList()); + } + + @Subscribe + public void onGameStateChanged(GameStateChanged gameStateChanged) + { + if (gameStateChanged.getGameState() != GameState.LOGGED_IN) + { + return; + } + + // map region has just been updated + loadPoints(); + } + + @Subscribe + public void onFocusChanged(FocusChanged focusChanged) + { + if (!focusChanged.isFocused()) + { + hotKeyPressed = false; + } + } + + @Subscribe + public void onMenuEntryAdded(MenuEntryAdded event) + { + if (hotKeyPressed && event.getOption().equals(WALK_HERE)) + { + MenuEntry[] menuEntries = client.getMenuEntries(); + menuEntries = Arrays.copyOf(menuEntries, menuEntries.length + 1); + + MenuEntry menuEntry = menuEntries[menuEntries.length - 1] = new MenuEntry(); + + menuEntry.setOption(MARK); + menuEntry.setTarget(event.getTarget()); + menuEntry.setType(MenuAction.CANCEL.getId()); + + client.setMenuEntries(menuEntries); + } + } + + @Subscribe + public void onMenuOptionClicked(MenuOptionClicked event) + { + if (!event.getMenuOption().equals(MARK)) + { + return; + } + + Tile target = client.getSelectedSceneTile(); + if (target == null) + { + return; + } + markTile(target.getLocalLocation()); + } + + @Override + protected void startUp() + { + overlayManager.add(overlay); + overlayManager.add(minimapOverlay); + keyManager.registerKeyListener(inputListener); + loadPoints(); + } + + @Override + protected void shutDown() + { + overlayManager.remove(overlay); + overlayManager.remove(minimapOverlay); + keyManager.unregisterKeyListener(inputListener); + points.clear(); + } + + private void markTile(LocalPoint localPoint) + { + if (localPoint == null) + { + return; + } + + WorldPoint worldPoint = WorldPoint.fromLocalInstance(client, localPoint); + + int regionId = worldPoint.getRegionID(); + GroundMarkerPoint point = new GroundMarkerPoint(regionId, worldPoint.getRegionX(), worldPoint.getRegionY(), client.getPlane(), config.markerColor()); + log.debug("Updating point: {} - {}", point, worldPoint); + + List groundMarkerPoints = new ArrayList<>(getPoints(regionId)); + if (groundMarkerPoints.contains(point)) + { + groundMarkerPoints.remove(point); + } + else + { + groundMarkerPoints.add(point); + } + + savePoints(regionId, groundMarkerPoints); + + loadPoints(); + } +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/groundmarkers/GroundMarkerPoint.java b/runelite-client/src/main/java/net/runelite/client/plugins/groundmarkers/GroundMarkerPoint.java index 3e10a654c0..53dce275ff 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/groundmarkers/GroundMarkerPoint.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/groundmarkers/GroundMarkerPoint.java @@ -1,44 +1,44 @@ -/* - * Copyright (c) 2018, TheLonelyDev - * Copyright (c) 2018, Adam - * 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.EqualsAndHashCode; -import lombok.Value; - -/** - * Used for serialization of ground marker points. - */ -@Value -@EqualsAndHashCode(exclude = { "color" }) -class GroundMarkerPoint -{ - private int regionId; - private int regionX; - private int regionY; - private int z; - private Color color; -} +/* + * Copyright (c) 2018, TheLonelyDev + * Copyright (c) 2018, Adam + * 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.EqualsAndHashCode; +import lombok.Value; + +/** + * Used for serialization of ground marker points. + */ +@Value +@EqualsAndHashCode(exclude = {"color"}) +class GroundMarkerPoint +{ + private int regionId; + private int regionX; + private int regionY; + private int z; + private Color color; +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/herbiboars/HerbiboarPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/herbiboars/HerbiboarPlugin.java index 83e59c19a4..a5d6e40fb1 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/herbiboars/HerbiboarPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/herbiboars/HerbiboarPlugin.java @@ -1,355 +1,355 @@ -/* - * Copyright (c) 2017, Tyler - * 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.herbiboars; - -import com.google.inject.Provides; -import java.util.Arrays; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; -import javax.inject.Inject; -import lombok.Getter; -import lombok.Setter; -import net.runelite.api.Client; -import static net.runelite.api.ObjectID.DRIFTWOOD_30523; -import static net.runelite.api.ObjectID.MUSHROOM_30520; -import static net.runelite.api.ObjectID.ROCK_30519; -import static net.runelite.api.ObjectID.ROCK_30521; -import static net.runelite.api.ObjectID.ROCK_30522; -import net.runelite.api.Tile; -import net.runelite.api.TileObject; -import net.runelite.api.Varbits; -import net.runelite.api.coords.WorldPoint; -import net.runelite.api.events.GameObjectChanged; -import net.runelite.api.events.GameObjectDespawned; -import net.runelite.api.events.GameObjectSpawned; -import net.runelite.api.events.GameStateChanged; -import net.runelite.api.events.GroundObjectChanged; -import net.runelite.api.events.GroundObjectDespawned; -import net.runelite.api.events.GroundObjectSpawned; -import net.runelite.api.events.VarbitChanged; -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.ui.overlay.OverlayManager; - -@PluginDescriptor( - name = "Herbiboar", - description = "Highlight starting rocks, trails, and the objects to search at the end of each trail", - tags = {"herblore", "hunter", "skilling", "overlay"} -) -public class HerbiboarPlugin extends Plugin -{ - private static final List END_LOCATIONS = Arrays.asList( - new WorldPoint(3693, 3798, 0), - new WorldPoint(3702, 3808, 0), - new WorldPoint(3703, 3826, 0), - new WorldPoint(3710, 3881, 0), - new WorldPoint(3700, 3877, 0), - new WorldPoint(3715, 3840, 0), - new WorldPoint(3751, 3849, 0), - new WorldPoint(3685, 3869, 0), - new WorldPoint(3681, 3863, 0) - ); - - private static final List START_OBJECT_IDS = Arrays.asList( - ROCK_30519, - MUSHROOM_30520, - ROCK_30521, - ROCK_30522, - DRIFTWOOD_30523 - ); - - private static final int[] HERBIBOAR_REGIONS = { - 14652, - 14651, - 14908, - 14907 - }; - - @Inject - private Client client; - - @Inject - private OverlayManager overlayManager; - - @Inject - private HerbiboarOverlay overlay; - - @Inject - private HerbiboarMinimapOverlay minimapOverlay; - - @Getter - private boolean inHerbiboarArea; - - @Getter - private Map trails = new HashMap<>(); - - @Getter - private Map tunnels = new HashMap<>(); - - @Getter - private Map starts = new HashMap<>(); - - @Getter - private Map trailObjects = new HashMap<>(); - - @Getter - @Setter - private Set shownTrails = new HashSet<>(); - - @Getter - @Setter - private HerbiboarTrail currentTrail; - - @Getter - @Setter - private int currentPath; - - @Getter - @Setter - private int finishId; - - @Provides - HerbiboarConfig getConfig(ConfigManager configManager) - { - return configManager.getConfig(HerbiboarConfig.class); - } - - @Override - protected void startUp() throws Exception - { - overlayManager.add(overlay); - overlayManager.add(minimapOverlay); - inHerbiboarArea = checkArea(); - } - - @Override - protected void shutDown() throws Exception - { - overlayManager.remove(overlay); - overlayManager.remove(minimapOverlay); - } - - private void updateTrailData() - { - currentTrail = null; - currentPath = -1; - - // Get trail data - for (HerbiboarTrail trail : HerbiboarTrail.values()) - { - int trailId = trail.getTrailId(); - int value = client.getVar(trail.getVarbit()); - - if (value > 0) - { - shownTrails.add(trailId); - shownTrails.add(trailId + 1); - } - if (value == 1 || value == 2) - { - currentTrail = trail; - currentPath = value; - } - } - - // Get finish data - finishId = client.getVar(Varbits.HB_FINISH); - if (finishId > 0 && currentTrail != null) - { - shownTrails.add(currentTrail.getTrailId()); - shownTrails.add(currentTrail.getTrailId() + 1); - currentTrail = null; - currentPath = -1; - } - - int started = client.getVar(Varbits.HB_STARTED); - if (currentPath == -1 && finishId == 0 && started == 0) - { - resetTrailData(); - } - } - - private void resetTrailData() - { - currentPath = 0; - currentTrail = null; - finishId = 0; - shownTrails.clear(); - } - - private void clearCache() - { - starts.clear(); - trailObjects.clear(); - trails.clear(); - tunnels.clear(); - } - - @Subscribe - public void onGameStateChanged(GameStateChanged event) - { - switch (event.getGameState()) - { - case HOPPING: - case LOGGING_IN: - resetTrailData(); - break; - case LOADING: - clearCache(); - inHerbiboarArea = checkArea(); - break; - default: - break; - } - } - - @Subscribe - public void onVarbitChanged(VarbitChanged event) - { - if (isInHerbiboarArea()) - { - updateTrailData(); - } - } - - @Subscribe - public void onGameObjectSpawned(GameObjectSpawned event) - { - onGameObject(event.getTile(), null, event.getGameObject()); - } - - @Subscribe - public void onGameObjectChanged(GameObjectChanged event) - { - onGameObject(event.getTile(), event.getPrevious(), event.getGameObject()); - } - - @Subscribe - public void onGameObjectDespawned(GameObjectDespawned event) - { - onGameObject(event.getTile(), event.getGameObject(), null); - } - - @Subscribe - public void onGroundObjectSpawned(GroundObjectSpawned event) - { - onGroundObject(event.getTile(), null, event.getGroundObject()); - } - - @Subscribe - public void onGroundObjectChanged(GroundObjectChanged event) - { - onGroundObject(event.getTile(), event.getPrevious(), event.getGroundObject()); - } - - @Subscribe - public void onGroundObjectDespawned(GroundObjectDespawned event) - { - onGroundObject(event.getTile(), event.getGroundObject(), null); - } - - // Store relevant GameObjects (starts, objects used to trigger next trails, and some tunnels) - private void onGameObject(Tile tile, TileObject oldObject, TileObject newObject) - { - if (oldObject != null) - { - WorldPoint oldLocation = oldObject.getWorldLocation(); - trailObjects.remove(oldLocation); - tunnels.remove(oldLocation); - starts.remove(oldLocation); - } - - if (newObject == null) - { - return; - } - - // Starts - if (START_OBJECT_IDS.contains(newObject.getId())) - { - starts.put(newObject.getWorldLocation(), newObject); - return; - } - - // GameObject to trigger next trail (mushrooms, mud, seaweed, etc) - if (HerbiboarTrail.getAllObjectLocs().contains(newObject.getWorldLocation())) - { - trailObjects.put(newObject.getWorldLocation(), newObject); - return; - } - - // Herbiboar tunnel - if (END_LOCATIONS.contains(newObject.getWorldLocation())) - { - tunnels.put(newObject.getWorldLocation(), newObject); - } - } - - // Store relevant GroundObjects (tracks on trails, and some tunnels) - private void onGroundObject(Tile tile, TileObject oldObject, TileObject newObject) - { - if (oldObject != null) - { - WorldPoint oldLocation = oldObject.getWorldLocation(); - trails.remove(oldLocation); - tunnels.remove(oldLocation); - } - - if (newObject == null) - { - return; - } - - //Trails - if (HerbiboarTrail.getTrailIds().contains(newObject.getId())) - { - trails.put(newObject.getWorldLocation(), newObject); - return; - } - - //Herbiboar tunnel - if (END_LOCATIONS.contains(newObject.getWorldLocation())) - { - tunnels.put(newObject.getWorldLocation(), newObject); - } - } - - private boolean checkArea() - { - return client.getMapRegions() != null && Arrays.stream(client.getMapRegions()) - .filter(x -> Arrays.stream(HERBIBOAR_REGIONS).anyMatch(y -> y == x)) - .toArray().length > 0; - } - - public List getEndLocations() - { - return END_LOCATIONS; - } -} +/* + * Copyright (c) 2017, Tyler + * 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.herbiboars; + +import com.google.inject.Provides; +import java.util.Arrays; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import javax.inject.Inject; +import lombok.Getter; +import lombok.Setter; +import net.runelite.api.Client; +import static net.runelite.api.ObjectID.DRIFTWOOD_30523; +import static net.runelite.api.ObjectID.MUSHROOM_30520; +import static net.runelite.api.ObjectID.ROCK_30519; +import static net.runelite.api.ObjectID.ROCK_30521; +import static net.runelite.api.ObjectID.ROCK_30522; +import net.runelite.api.Tile; +import net.runelite.api.TileObject; +import net.runelite.api.Varbits; +import net.runelite.api.coords.WorldPoint; +import net.runelite.api.events.GameObjectChanged; +import net.runelite.api.events.GameObjectDespawned; +import net.runelite.api.events.GameObjectSpawned; +import net.runelite.api.events.GameStateChanged; +import net.runelite.api.events.GroundObjectChanged; +import net.runelite.api.events.GroundObjectDespawned; +import net.runelite.api.events.GroundObjectSpawned; +import net.runelite.api.events.VarbitChanged; +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.ui.overlay.OverlayManager; + +@PluginDescriptor( + name = "Herbiboar", + description = "Highlight starting rocks, trails, and the objects to search at the end of each trail", + tags = {"herblore", "hunter", "skilling", "overlay"} +) +public class HerbiboarPlugin extends Plugin +{ + private static final List END_LOCATIONS = Arrays.asList( + new WorldPoint(3693, 3798, 0), + new WorldPoint(3702, 3808, 0), + new WorldPoint(3703, 3826, 0), + new WorldPoint(3710, 3881, 0), + new WorldPoint(3700, 3877, 0), + new WorldPoint(3715, 3840, 0), + new WorldPoint(3751, 3849, 0), + new WorldPoint(3685, 3869, 0), + new WorldPoint(3681, 3863, 0) + ); + + private static final List START_OBJECT_IDS = Arrays.asList( + ROCK_30519, + MUSHROOM_30520, + ROCK_30521, + ROCK_30522, + DRIFTWOOD_30523 + ); + + private static final int[] HERBIBOAR_REGIONS = { + 14652, + 14651, + 14908, + 14907 + }; + + @Inject + private Client client; + + @Inject + private OverlayManager overlayManager; + + @Inject + private HerbiboarOverlay overlay; + + @Inject + private HerbiboarMinimapOverlay minimapOverlay; + + @Getter + private boolean inHerbiboarArea; + + @Getter + private Map trails = new HashMap<>(); + + @Getter + private Map tunnels = new HashMap<>(); + + @Getter + private Map starts = new HashMap<>(); + + @Getter + private Map trailObjects = new HashMap<>(); + + @Getter + @Setter + private Set shownTrails = new HashSet<>(); + + @Getter + @Setter + private HerbiboarTrail currentTrail; + + @Getter + @Setter + private int currentPath; + + @Getter + @Setter + private int finishId; + + @Provides + HerbiboarConfig getConfig(ConfigManager configManager) + { + return configManager.getConfig(HerbiboarConfig.class); + } + + @Override + protected void startUp() throws Exception + { + overlayManager.add(overlay); + overlayManager.add(minimapOverlay); + inHerbiboarArea = checkArea(); + } + + @Override + protected void shutDown() throws Exception + { + overlayManager.remove(overlay); + overlayManager.remove(minimapOverlay); + } + + private void updateTrailData() + { + currentTrail = null; + currentPath = -1; + + // Get trail data + for (HerbiboarTrail trail : HerbiboarTrail.values()) + { + int trailId = trail.getTrailId(); + int value = client.getVar(trail.getVarbit()); + + if (value > 0) + { + shownTrails.add(trailId); + shownTrails.add(trailId + 1); + } + if (value == 1 || value == 2) + { + currentTrail = trail; + currentPath = value; + } + } + + // Get finish data + finishId = client.getVar(Varbits.HB_FINISH); + if (finishId > 0 && currentTrail != null) + { + shownTrails.add(currentTrail.getTrailId()); + shownTrails.add(currentTrail.getTrailId() + 1); + currentTrail = null; + currentPath = -1; + } + + int started = client.getVar(Varbits.HB_STARTED); + if (currentPath == -1 && finishId == 0 && started == 0) + { + resetTrailData(); + } + } + + private void resetTrailData() + { + currentPath = 0; + currentTrail = null; + finishId = 0; + shownTrails.clear(); + } + + private void clearCache() + { + starts.clear(); + trailObjects.clear(); + trails.clear(); + tunnels.clear(); + } + + @Subscribe + public void onGameStateChanged(GameStateChanged event) + { + switch (event.getGameState()) + { + case HOPPING: + case LOGGING_IN: + resetTrailData(); + break; + case LOADING: + clearCache(); + inHerbiboarArea = checkArea(); + break; + default: + break; + } + } + + @Subscribe + public void onVarbitChanged(VarbitChanged event) + { + if (isInHerbiboarArea()) + { + updateTrailData(); + } + } + + @Subscribe + public void onGameObjectSpawned(GameObjectSpawned event) + { + onGameObject(event.getTile(), null, event.getGameObject()); + } + + @Subscribe + public void onGameObjectChanged(GameObjectChanged event) + { + onGameObject(event.getTile(), event.getPrevious(), event.getGameObject()); + } + + @Subscribe + public void onGameObjectDespawned(GameObjectDespawned event) + { + onGameObject(event.getTile(), event.getGameObject(), null); + } + + @Subscribe + public void onGroundObjectSpawned(GroundObjectSpawned event) + { + onGroundObject(event.getTile(), null, event.getGroundObject()); + } + + @Subscribe + public void onGroundObjectChanged(GroundObjectChanged event) + { + onGroundObject(event.getTile(), event.getPrevious(), event.getGroundObject()); + } + + @Subscribe + public void onGroundObjectDespawned(GroundObjectDespawned event) + { + onGroundObject(event.getTile(), event.getGroundObject(), null); + } + + // Store relevant GameObjects (starts, objects used to trigger next trails, and some tunnels) + private void onGameObject(Tile tile, TileObject oldObject, TileObject newObject) + { + if (oldObject != null) + { + WorldPoint oldLocation = oldObject.getWorldLocation(); + trailObjects.remove(oldLocation); + tunnels.remove(oldLocation); + starts.remove(oldLocation); + } + + if (newObject == null) + { + return; + } + + // Starts + if (START_OBJECT_IDS.contains(newObject.getId())) + { + starts.put(newObject.getWorldLocation(), newObject); + return; + } + + // GameObject to trigger next trail (mushrooms, mud, seaweed, etc) + if (HerbiboarTrail.getAllObjectLocs().contains(newObject.getWorldLocation())) + { + trailObjects.put(newObject.getWorldLocation(), newObject); + return; + } + + // Herbiboar tunnel + if (END_LOCATIONS.contains(newObject.getWorldLocation())) + { + tunnels.put(newObject.getWorldLocation(), newObject); + } + } + + // Store relevant GroundObjects (tracks on trails, and some tunnels) + private void onGroundObject(Tile tile, TileObject oldObject, TileObject newObject) + { + if (oldObject != null) + { + WorldPoint oldLocation = oldObject.getWorldLocation(); + trails.remove(oldLocation); + tunnels.remove(oldLocation); + } + + if (newObject == null) + { + return; + } + + //Trails + if (HerbiboarTrail.getTrailIds().contains(newObject.getId())) + { + trails.put(newObject.getWorldLocation(), newObject); + return; + } + + //Herbiboar tunnel + if (END_LOCATIONS.contains(newObject.getWorldLocation())) + { + tunnels.put(newObject.getWorldLocation(), newObject); + } + } + + private boolean checkArea() + { + return client.getMapRegions() != null && Arrays.stream(client.getMapRegions()) + .filter(x -> Arrays.stream(HERBIBOAR_REGIONS).anyMatch(y -> y == x)) + .toArray().length > 0; + } + + public List getEndLocations() + { + return END_LOCATIONS; + } +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/hideprayers/INDIVIDUAL/HidePrayersINDIVIDUALConfig.java b/runelite-client/src/main/java/net/runelite/client/plugins/hideprayers/INDIVIDUAL/HidePrayersINDIVIDUALConfig.java index a93d794548..e8589c866e 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/hideprayers/INDIVIDUAL/HidePrayersINDIVIDUALConfig.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/hideprayers/INDIVIDUAL/HidePrayersINDIVIDUALConfig.java @@ -35,361 +35,362 @@ import net.runelite.client.config.ConfigItem; public interface HidePrayersINDIVIDUALConfig extends Config { @ConfigItem - ( - position = 0, - keyName = "pk prayers", - name = "Hide Prayers", - description = "Hide/Show Prayers." - ) - default boolean showINDIVIDUALPrayers() - { - return false; + ( + position = 0, + keyName = "pk prayers", + name = "Hide Prayers", + description = "Hide/Show Prayers." + ) + default boolean showINDIVIDUALPrayers() + { + return false; } @ConfigItem - ( - position = 1, - keyName = "thickskin", - name = "Hide Thick Skin", - description = "Hide/Show Thick Skin" - ) + ( + position = 1, + keyName = "thickskin", + name = "Hide Thick Skin", + description = "Hide/Show Thick Skin" + ) default boolean HideTHICK_SKIN() - { - return false; - } + { + return false; + } @ConfigItem - ( - position = 2, - keyName = "burstofstrength", - name = "Hide Burst of Strength", - description = "Hide/Show Burst of Strength" - ) + ( + position = 2, + keyName = "burstofstrength", + name = "Hide Burst of Strength", + description = "Hide/Show Burst of Strength" + ) default boolean HideBURST_OF_STRENGTH() - { - return false; - } + { + return false; + } @ConfigItem - ( - position = 3, - keyName = "clarityofthought", - name = "Hide Clarity of Thought", - description = "Hide/Show Clarity of Thought" - ) + ( + position = 3, + keyName = "clarityofthought", + name = "Hide Clarity of Thought", + description = "Hide/Show Clarity of Thought" + ) default boolean HideCLARITY_OF_THOUGHT() - { - return false; - } - + { + return false; + } + @ConfigItem - ( - position = 4, - keyName = "sharpeye", - name = "Hide Sharp Eye", - description = "Hide/Show Sharp Eye" - ) + ( + position = 4, + keyName = "sharpeye", + name = "Hide Sharp Eye", + description = "Hide/Show Sharp Eye" + ) default boolean HideSHARP_EYE() - { - return false; - } - + { + return false; + } + @ConfigItem - ( - position = 5, - keyName = "mysticwill", - name = "Hide Mystic Will", - description = "Hide/Show Mystic Will" - ) + ( + position = 5, + keyName = "mysticwill", + name = "Hide Mystic Will", + description = "Hide/Show Mystic Will" + ) default boolean HideMYSTIC_WILL() - { - return false; - } - + { + return false; + } + @ConfigItem - ( - position = 6, - keyName = "rockskin", - name = "Hide Rock Skin", - description = "Hide/Show Rock Skin" - ) + ( + position = 6, + keyName = "rockskin", + name = "Hide Rock Skin", + description = "Hide/Show Rock Skin" + ) default boolean HideROCK_SKIN() - { - return false; - } - + { + return false; + } + @ConfigItem - ( - position = 7, - keyName = "superhumanstrength", - name = "Hide Super Human Strength", - description = "Hide/Show Super Human Strength" - ) + ( + position = 7, + keyName = "superhumanstrength", + name = "Hide Super Human Strength", + description = "Hide/Show Super Human Strength" + ) default boolean HideSUPERHUMAN_STRENGTH() - { - return false; - } - + { + return false; + } + @ConfigItem - ( - position = 8, - keyName = "improvedreflexes", - name = "Hide Improved_Reflexes", - description = "Hide/Show Improved_Reflexes" - ) + ( + position = 8, + keyName = "improvedreflexes", + name = "Hide Improved_Reflexes", + description = "Hide/Show Improved_Reflexes" + ) default boolean HideIMPROVED_REFLEXES() - { - return false; - } - + { + return false; + } + @ConfigItem - ( - position = 9, - keyName = "rapidrestore", - name = "Hide Rapid Restore", - description = "Hide/Show Rapid Restore" - ) + ( + position = 9, + keyName = "rapidrestore", + name = "Hide Rapid Restore", + description = "Hide/Show Rapid Restore" + ) default boolean HideRapidRestore() - { - return false; + { + return false; } @ConfigItem - ( - position = 10, - keyName = "rapidheal", - name = "Hide Rapid Heal", - description = "Hide/Show Rapid Heal" - ) - default boolean HideRapidHeal() - { - return false; - } - @ConfigItem - ( - position = 11, - keyName = "protectitem", - name = "Hide Protect Item", - description = "Hide/Show Protect Item" - ) - default boolean HideProtectItem() - { - return false; - } - - @ConfigItem - ( - position = 12, - keyName = "hawkeye", - name = "Hide Hawk Eye", - description = "Hide/Show Hawk Eye" - ) - default boolean HideHAWK_EYE() - { - return false; + ( + position = 10, + keyName = "rapidheal", + name = "Hide Rapid Heal", + description = "Hide/Show Rapid Heal" + ) + default boolean HideRapidHeal() + { + return false; } @ConfigItem - ( - position = 13, - keyName = "mysticlore", - name = "Hide Mystic Lore", - description = "Hide/Show Mystic Lore" - ) + ( + position = 11, + keyName = "protectitem", + name = "Hide Protect Item", + description = "Hide/Show Protect Item" + ) + default boolean HideProtectItem() + { + return false; + } + + @ConfigItem + ( + position = 12, + keyName = "hawkeye", + name = "Hide Hawk Eye", + description = "Hide/Show Hawk Eye" + ) + default boolean HideHAWK_EYE() + { + return false; + } + + @ConfigItem + ( + position = 13, + keyName = "mysticlore", + name = "Hide Mystic Lore", + description = "Hide/Show Mystic Lore" + ) default boolean HideMYSTIC_LORE() - { - return false; + { + return false; } - + @ConfigItem - ( - position = 14, - keyName = "steelskin", - name = "Hide Steel Skin", - description = "Hide/Show Steel skin" - ) - default boolean HideSteelSkin() - { - return false; + ( + position = 14, + keyName = "steelskin", + name = "Hide Steel Skin", + description = "Hide/Show Steel skin" + ) + default boolean HideSteelSkin() + { + return false; } @ConfigItem - ( - position = 15, - keyName = "ultimatestrength", - name = "Hide Ultimate Strength", - description = "Hide/Show Ultimate strength" - ) - default boolean HideUltimateStrength() - { - return false; + ( + position = 15, + keyName = "ultimatestrength", + name = "Hide Ultimate Strength", + description = "Hide/Show Ultimate strength" + ) + default boolean HideUltimateStrength() + { + return false; } @ConfigItem - ( - position = 16, - keyName = "incrediblereflex", - name = "Hide Incredible Reflex", - description = "Hide/Show Incredible Reflex" - ) - default boolean HideIncredibleReflex() - { - return false; + ( + position = 16, + keyName = "incrediblereflex", + name = "Hide Incredible Reflex", + description = "Hide/Show Incredible Reflex" + ) + default boolean HideIncredibleReflex() + { + return false; } @ConfigItem - ( - position = 17, - keyName = "PTFMagic", - name = "Hide Protect From Magic", - description = "Hide/Show Protect From Magic" - ) - default boolean HidePTFMagic() - { - return false; + ( + position = 17, + keyName = "PTFMagic", + name = "Hide Protect From Magic", + description = "Hide/Show Protect From Magic" + ) + default boolean HidePTFMagic() + { + return false; } @ConfigItem - ( - position = 18, - keyName = "PTFRange", - name = "Hide Protect From Range", - description = "Hide/Show Protect from Range" - ) - default boolean HidePTFRange() - { - return false; + ( + position = 18, + keyName = "PTFRange", + name = "Hide Protect From Range", + description = "Hide/Show Protect from Range" + ) + default boolean HidePTFRange() + { + return false; } @ConfigItem - ( - position = 19, - keyName = "PTFMelee", - name = "Hide Protect From Melee", - description = "Hide/Show Protect From Melee" - ) - default boolean HidePTFMelee() - { - return false; + ( + position = 19, + keyName = "PTFMelee", + name = "Hide Protect From Melee", + description = "Hide/Show Protect From Melee" + ) + default boolean HidePTFMelee() + { + return false; } @ConfigItem - ( - position = 20, - keyName = "eagle", - name = "Hide Eagle Eye", - description = "Hide/Show Eagle Eye" - ) - default boolean HideEagle() - { - return false; + ( + position = 20, + keyName = "eagle", + name = "Hide Eagle Eye", + description = "Hide/Show Eagle Eye" + ) + default boolean HideEagle() + { + return false; } @ConfigItem - ( - position = 19, - keyName = "mystic", - name = "Hide Mystic Might", - description = "Hide/Show Mystic Might" - ) - default boolean HideMystic() - { - return false; - } - - @ConfigItem - ( - position = 21, - keyName = "Retribution", - name = "Hide Retribution", - description = "Hide/Show Retribution" - ) - default boolean HideRETRIBUTION() - { - return false; + ( + position = 19, + keyName = "mystic", + name = "Hide Mystic Might", + description = "Hide/Show Mystic Might" + ) + default boolean HideMystic() + { + return false; } @ConfigItem - ( - position = 22, - keyName = "redemption", - name = "Hide Redemption", - description = "Hide/Show Redemption" - ) - default boolean HideRedemption() - { - return false; + ( + position = 21, + keyName = "Retribution", + name = "Hide Retribution", + description = "Hide/Show Retribution" + ) + default boolean HideRETRIBUTION() + { + return false; } @ConfigItem - ( - position = 23, - keyName = "smite", - name = "Hide Smite", - description = "Hide/Show Smite" - ) - default boolean HideSmite() - { - return false; + ( + position = 22, + keyName = "redemption", + name = "Hide Redemption", + description = "Hide/Show Redemption" + ) + default boolean HideRedemption() + { + return false; } @ConfigItem - ( - position = 24, - keyName = "preserve", - name = "Hide Preserve", - description = "Hide/Show Preserve" - ) - default boolean HidePreserve() - { - return false; + ( + position = 23, + keyName = "smite", + name = "Hide Smite", + description = "Hide/Show Smite" + ) + default boolean HideSmite() + { + return false; } @ConfigItem - ( - position = 25, - keyName = "Chivalry", - name = "Hide Chivalry", - description = "Hide/Show Chivalry" - ) - default boolean HideChivalry() - { - return false; + ( + position = 24, + keyName = "preserve", + name = "Hide Preserve", + description = "Hide/Show Preserve" + ) + default boolean HidePreserve() + { + return false; } @ConfigItem - ( - position = 26, - keyName = "Piety", - name = "Hide Piety", - description = "Hide/Show Piety" - ) - default boolean HidePiety() - { - return false; + ( + position = 25, + keyName = "Chivalry", + name = "Hide Chivalry", + description = "Hide/Show Chivalry" + ) + default boolean HideChivalry() + { + return false; } @ConfigItem - ( - position = 27, - keyName = "Rigour", - name = "Hide Rigour", - description = "Hide/Show Rigour" - ) - default boolean HideRigour() - { - return false; + ( + position = 26, + keyName = "Piety", + name = "Hide Piety", + description = "Hide/Show Piety" + ) + default boolean HidePiety() + { + return false; } @ConfigItem - ( - position = 28, - keyName = "Augury", - name = "Hide Augury", - description = "Hide/Show Augury" - ) - default boolean HideAugury() + ( + position = 27, + keyName = "Rigour", + name = "Hide Rigour", + description = "Hide/Show Rigour" + ) + default boolean HideRigour() + { + return false; + } + + @ConfigItem + ( + position = 28, + keyName = "Augury", + name = "Hide Augury", + description = "Hide/Show Augury" + ) + default boolean HideAugury() { return false; } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/hideprayers/INDIVIDUAL/HidePrayersINDIVIDUALPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/hideprayers/INDIVIDUAL/HidePrayersINDIVIDUALPlugin.java index 902e028d24..53a16515f9 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/hideprayers/INDIVIDUAL/HidePrayersINDIVIDUALPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/hideprayers/INDIVIDUAL/HidePrayersINDIVIDUALPlugin.java @@ -29,7 +29,15 @@ package net.runelite.client.plugins.hideprayers.INDIVIDUAL; import com.google.common.collect.ImmutableList; import com.google.inject.Provides; -import net.runelite.api.*; +import java.util.List; +import java.util.Objects; +import java.util.stream.Collectors; +import javax.inject.Inject; +import net.runelite.api.Client; +import net.runelite.api.GameState; +import net.runelite.api.HashTable; +import net.runelite.api.Prayer; +import net.runelite.api.WidgetNode; import net.runelite.api.events.ConfigChanged; import net.runelite.api.events.GameStateChanged; import net.runelite.api.events.WidgetLoaded; @@ -40,15 +48,10 @@ 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.plugins.PluginManager; import net.runelite.client.plugins.PluginType; import net.runelite.client.plugins.hideprayers.util.PrayerTabStates; -import javax.inject.Inject; -import java.util.List; -import java.util.Objects; -import java.util.stream.Collectors; -@PluginDescriptor +@PluginDescriptor ( name = "Show/Hide INDIVIDUAL Prayers", description = "Hides specific Prayers in the Prayer tab individually.", @@ -61,37 +64,37 @@ public class HidePrayersINDIVIDUALPlugin extends Plugin private static final int PRAYER_COUNT = Prayer.values().length; private static final List PRAYER_WIDGET_INFO_LIST = ImmutableList.of - ( - WidgetInfo.PRAYER_THICK_SKIN, //0 - WidgetInfo.PRAYER_BURST_OF_STRENGTH, //1 - WidgetInfo.PRAYER_CLARITY_OF_THOUGHT, //2 - WidgetInfo.PRAYER_SHARP_EYE, //3 - WidgetInfo.PRAYER_MYSTIC_WILL, //4 - WidgetInfo.PRAYER_ROCK_SKIN, //5 - WidgetInfo.PRAYER_SUPERHUMAN_STRENGTH, //6 - WidgetInfo.PRAYER_IMPROVED_REFLEXES, //7 - WidgetInfo.PRAYER_RAPID_RESTORE, //8 - WidgetInfo.PRAYER_RAPID_HEAL, //9 - WidgetInfo.PRAYER_PROTECT_ITEM, //10 - WidgetInfo.PRAYER_HAWK_EYE, //11 - WidgetInfo.PRAYER_MYSTIC_LORE, //12 - WidgetInfo.PRAYER_STEEL_SKIN, //13 - WidgetInfo.PRAYER_ULTIMATE_STRENGTH, //14 - WidgetInfo.PRAYER_INCREDIBLE_REFLEXES, //15 - WidgetInfo.PRAYER_PROTECT_FROM_MAGIC, //16 - WidgetInfo.PRAYER_PROTECT_FROM_MISSILES, //17 - WidgetInfo.PRAYER_PROTECT_FROM_MELEE, //18 - WidgetInfo.PRAYER_EAGLE_EYE, //19 - WidgetInfo.PRAYER_MYSTIC_MIGHT, //20 - WidgetInfo.PRAYER_RETRIBUTION, //21 - WidgetInfo.PRAYER_REDEMPTION, //22 - WidgetInfo.PRAYER_SMITE, //23 - WidgetInfo.PRAYER_PRESERVE, //24 - WidgetInfo.PRAYER_CHIVALRY, //25 - WidgetInfo.PRAYER_PIETY, //26 - WidgetInfo.PRAYER_RIGOUR, //27 - WidgetInfo.PRAYER_AUGURY //28 - ); + ( + WidgetInfo.PRAYER_THICK_SKIN, //0 + WidgetInfo.PRAYER_BURST_OF_STRENGTH, //1 + WidgetInfo.PRAYER_CLARITY_OF_THOUGHT, //2 + WidgetInfo.PRAYER_SHARP_EYE, //3 + WidgetInfo.PRAYER_MYSTIC_WILL, //4 + WidgetInfo.PRAYER_ROCK_SKIN, //5 + WidgetInfo.PRAYER_SUPERHUMAN_STRENGTH, //6 + WidgetInfo.PRAYER_IMPROVED_REFLEXES, //7 + WidgetInfo.PRAYER_RAPID_RESTORE, //8 + WidgetInfo.PRAYER_RAPID_HEAL, //9 + WidgetInfo.PRAYER_PROTECT_ITEM, //10 + WidgetInfo.PRAYER_HAWK_EYE, //11 + WidgetInfo.PRAYER_MYSTIC_LORE, //12 + WidgetInfo.PRAYER_STEEL_SKIN, //13 + WidgetInfo.PRAYER_ULTIMATE_STRENGTH, //14 + WidgetInfo.PRAYER_INCREDIBLE_REFLEXES, //15 + WidgetInfo.PRAYER_PROTECT_FROM_MAGIC, //16 + WidgetInfo.PRAYER_PROTECT_FROM_MISSILES, //17 + WidgetInfo.PRAYER_PROTECT_FROM_MELEE, //18 + WidgetInfo.PRAYER_EAGLE_EYE, //19 + WidgetInfo.PRAYER_MYSTIC_MIGHT, //20 + WidgetInfo.PRAYER_RETRIBUTION, //21 + WidgetInfo.PRAYER_REDEMPTION, //22 + WidgetInfo.PRAYER_SMITE, //23 + WidgetInfo.PRAYER_PRESERVE, //24 + WidgetInfo.PRAYER_CHIVALRY, //25 + WidgetInfo.PRAYER_PIETY, //26 + WidgetInfo.PRAYER_RIGOUR, //27 + WidgetInfo.PRAYER_AUGURY //28 + ); @Inject private Client client; @@ -157,7 +160,8 @@ public class HidePrayersINDIVIDUALPlugin extends Plugin if (widgetNode.getId() == WidgetID.PRAYER_GROUP_ID) { return PrayerTabStates.PRAYERS; - } else if (widgetNode.getId() == WidgetID.QUICK_PRAYERS_GROUP_ID) + } + else if (widgetNode.getId() == WidgetID.QUICK_PRAYERS_GROUP_ID) { return PrayerTabStates.QUICK_PRAYERS; } @@ -168,36 +172,47 @@ public class HidePrayersINDIVIDUALPlugin extends Plugin private void restorePrayers() { if (client.getGameState() != GameState.LOGGED_IN) + { return; - - PrayerTabStates prayerTabState = getPrayerTabState(); - - if (prayerTabState == PrayerTabStates.PRAYERS) { - List prayerWidgets = PRAYER_WIDGET_INFO_LIST.stream().map(client::getWidget) - .filter(Objects::nonNull).collect(Collectors.toList()); - - if (prayerWidgets.size() != PRAYER_WIDGET_INFO_LIST.size()) - return; - - for (int index = 0; index < PRAYER_COUNT; index++) - prayerWidgets.get(Prayer.values()[index].ordinal()).setHidden(false); } - } - - private void hidePrayers() - { - if (client.getGameState() != GameState.LOGGED_IN) - return; PrayerTabStates prayerTabState = getPrayerTabState(); if (prayerTabState == PrayerTabStates.PRAYERS) { List prayerWidgets = PRAYER_WIDGET_INFO_LIST.stream().map(client::getWidget) - .filter(Objects::nonNull).collect(Collectors.toList()); + .filter(Objects::nonNull).collect(Collectors.toList()); if (prayerWidgets.size() != PRAYER_WIDGET_INFO_LIST.size()) + { return; + } + + for (int index = 0; index < PRAYER_COUNT; index++) + { + prayerWidgets.get(Prayer.values()[index].ordinal()).setHidden(false); + } + } + } + + private void hidePrayers() + { + if (client.getGameState() != GameState.LOGGED_IN) + { + return; + } + + PrayerTabStates prayerTabState = getPrayerTabState(); + + if (prayerTabState == PrayerTabStates.PRAYERS) + { + List prayerWidgets = PRAYER_WIDGET_INFO_LIST.stream().map(client::getWidget) + .filter(Objects::nonNull).collect(Collectors.toList()); + + if (prayerWidgets.size() != PRAYER_WIDGET_INFO_LIST.size()) + { + return; + } for (int index = 0; index < PRAYER_COUNT; index++) { @@ -205,213 +220,215 @@ public class HidePrayersINDIVIDUALPlugin extends Plugin Widget prayerWidget = prayerWidgets.get(prayer.ordinal()); if (!config.showINDIVIDUALPrayers() - && !config.HideTHICK_SKIN() - && !config.HideBURST_OF_STRENGTH() - && !config.HideCLARITY_OF_THOUGHT() - && !config.HideSHARP_EYE() - && !config.HideMYSTIC_WILL() - && !config.HideROCK_SKIN() - && !config.HideSUPERHUMAN_STRENGTH() - && !config.HideIMPROVED_REFLEXES() - && !config.HideRapidRestore() - && !config.HideRapidHeal() - && !config.HideProtectItem() - && !config.HideHAWK_EYE() - && !config.HideMYSTIC_LORE() - && !config.HideSteelSkin() - && !config.HideUltimateStrength() - && !config.HideIncredibleReflex() - && !config.HidePTFMagic() - && !config.HidePTFRange() - && !config.HidePTFMelee() - && !config.HideEagle() - && !config.HideMystic() - && !config.HideRETRIBUTION() - && !config.HideRedemption() - && !config.HideSmite() - && !config.HidePreserve() - && !config.HideChivalry() - && !config.HidePiety() - && !config.HideRigour() - && !config.HideAugury()) - prayerWidget.setHidden(false); + && !config.HideTHICK_SKIN() + && !config.HideBURST_OF_STRENGTH() + && !config.HideCLARITY_OF_THOUGHT() + && !config.HideSHARP_EYE() + && !config.HideMYSTIC_WILL() + && !config.HideROCK_SKIN() + && !config.HideSUPERHUMAN_STRENGTH() + && !config.HideIMPROVED_REFLEXES() + && !config.HideRapidRestore() + && !config.HideRapidHeal() + && !config.HideProtectItem() + && !config.HideHAWK_EYE() + && !config.HideMYSTIC_LORE() + && !config.HideSteelSkin() + && !config.HideUltimateStrength() + && !config.HideIncredibleReflex() + && !config.HidePTFMagic() + && !config.HidePTFRange() + && !config.HidePTFMelee() + && !config.HideEagle() + && !config.HideMystic() + && !config.HideRETRIBUTION() + && !config.HideRedemption() + && !config.HideSmite() + && !config.HidePreserve() + && !config.HideChivalry() + && !config.HidePiety() + && !config.HideRigour() + && !config.HideAugury()) + { + prayerWidget.setHidden(false); + } if (config.showINDIVIDUALPrayers()) { prayerWidget.setHidden(true); - prayerWidgets.get(Prayer.values()[0].ordinal()).setHidden(false); // Thick Skin - prayerWidgets.get(Prayer.values()[1].ordinal()).setHidden(false); // Burst of Strength - prayerWidgets.get(Prayer.values()[2].ordinal()).setHidden(false); // Clarity of Thought - prayerWidgets.get(Prayer.values()[3].ordinal()).setHidden(false); // Sharp Eye - prayerWidgets.get(Prayer.values()[4].ordinal()).setHidden(false); // Mystic Will - prayerWidgets.get(Prayer.values()[5].ordinal()).setHidden(false); // Rock Skin - prayerWidgets.get(Prayer.values()[6].ordinal()).setHidden(false); // Super Human Strength - prayerWidgets.get(Prayer.values()[7].ordinal()).setHidden(false); // Improved Reflexed - prayerWidgets.get(Prayer.values()[8].ordinal()).setHidden(false); // Rapid Restore - prayerWidgets.get(Prayer.values()[9].ordinal()).setHidden(false); // Rapid Heal - prayerWidgets.get(Prayer.values()[10].ordinal()).setHidden(false); // Protect Item - prayerWidgets.get(Prayer.values()[11].ordinal()).setHidden(false); // Hawk Eye - prayerWidgets.get(Prayer.values()[12].ordinal()).setHidden(false); // Mystic Lore - prayerWidgets.get(Prayer.values()[13].ordinal()).setHidden(false); // Steel Skin - prayerWidgets.get(Prayer.values()[14].ordinal()).setHidden(false); // Ultimate Strength - prayerWidgets.get(Prayer.values()[15].ordinal()).setHidden(false); // Incredible Reflexes - prayerWidgets.get(Prayer.values()[16].ordinal()).setHidden(false); // Protect from Magic - prayerWidgets.get(Prayer.values()[17].ordinal()).setHidden(false); // Protect from Range - prayerWidgets.get(Prayer.values()[18].ordinal()).setHidden(false); // Protect from Melee - prayerWidgets.get(Prayer.values()[19].ordinal()).setHidden(false); // Eagle Eye - prayerWidgets.get(Prayer.values()[20].ordinal()).setHidden(false); // Mystic Might - prayerWidgets.get(Prayer.values()[21].ordinal()).setHidden(false); // Retribution - prayerWidgets.get(Prayer.values()[22].ordinal()).setHidden(false); // Redemption - prayerWidgets.get(Prayer.values()[23].ordinal()).setHidden(false); // Smite - prayerWidgets.get(Prayer.values()[24].ordinal()).setHidden(false); // Preserve - prayerWidgets.get(Prayer.values()[25].ordinal()).setHidden(false); // Chivalry - prayerWidgets.get(Prayer.values()[26].ordinal()).setHidden(false); // Piety - prayerWidgets.get(Prayer.values()[27].ordinal()).setHidden(false); // Rigour - prayerWidgets.get(Prayer.values()[28].ordinal()).setHidden(false); // Augury + prayerWidgets.get(Prayer.values()[0].ordinal()).setHidden(false); // Thick Skin + prayerWidgets.get(Prayer.values()[1].ordinal()).setHidden(false); // Burst of Strength + prayerWidgets.get(Prayer.values()[2].ordinal()).setHidden(false); // Clarity of Thought + prayerWidgets.get(Prayer.values()[3].ordinal()).setHidden(false); // Sharp Eye + prayerWidgets.get(Prayer.values()[4].ordinal()).setHidden(false); // Mystic Will + prayerWidgets.get(Prayer.values()[5].ordinal()).setHidden(false); // Rock Skin + prayerWidgets.get(Prayer.values()[6].ordinal()).setHidden(false); // Super Human Strength + prayerWidgets.get(Prayer.values()[7].ordinal()).setHidden(false); // Improved Reflexed + prayerWidgets.get(Prayer.values()[8].ordinal()).setHidden(false); // Rapid Restore + prayerWidgets.get(Prayer.values()[9].ordinal()).setHidden(false); // Rapid Heal + prayerWidgets.get(Prayer.values()[10].ordinal()).setHidden(false); // Protect Item + prayerWidgets.get(Prayer.values()[11].ordinal()).setHidden(false); // Hawk Eye + prayerWidgets.get(Prayer.values()[12].ordinal()).setHidden(false); // Mystic Lore + prayerWidgets.get(Prayer.values()[13].ordinal()).setHidden(false); // Steel Skin + prayerWidgets.get(Prayer.values()[14].ordinal()).setHidden(false); // Ultimate Strength + prayerWidgets.get(Prayer.values()[15].ordinal()).setHidden(false); // Incredible Reflexes + prayerWidgets.get(Prayer.values()[16].ordinal()).setHidden(false); // Protect from Magic + prayerWidgets.get(Prayer.values()[17].ordinal()).setHidden(false); // Protect from Range + prayerWidgets.get(Prayer.values()[18].ordinal()).setHidden(false); // Protect from Melee + prayerWidgets.get(Prayer.values()[19].ordinal()).setHidden(false); // Eagle Eye + prayerWidgets.get(Prayer.values()[20].ordinal()).setHidden(false); // Mystic Might + prayerWidgets.get(Prayer.values()[21].ordinal()).setHidden(false); // Retribution + prayerWidgets.get(Prayer.values()[22].ordinal()).setHidden(false); // Redemption + prayerWidgets.get(Prayer.values()[23].ordinal()).setHidden(false); // Smite + prayerWidgets.get(Prayer.values()[24].ordinal()).setHidden(false); // Preserve + prayerWidgets.get(Prayer.values()[25].ordinal()).setHidden(false); // Chivalry + prayerWidgets.get(Prayer.values()[26].ordinal()).setHidden(false); // Piety + prayerWidgets.get(Prayer.values()[27].ordinal()).setHidden(false); // Rigour + prayerWidgets.get(Prayer.values()[28].ordinal()).setHidden(false); // Augury if (config.HideTHICK_SKIN()) { - prayerWidgets.get(Prayer.values()[0].ordinal()).setHidden(true); // Thick Skin + prayerWidgets.get(Prayer.values()[0].ordinal()).setHidden(true); // Thick Skin } - + if (config.HideBURST_OF_STRENGTH()) { - prayerWidgets.get(Prayer.values()[1].ordinal()).setHidden(true); // Burst of Strength + prayerWidgets.get(Prayer.values()[1].ordinal()).setHidden(true); // Burst of Strength } - + if (config.HideCLARITY_OF_THOUGHT()) { - prayerWidgets.get(Prayer.values()[2].ordinal()).setHidden(true); // Clarity of Thought + prayerWidgets.get(Prayer.values()[2].ordinal()).setHidden(true); // Clarity of Thought } - + if (config.HideSHARP_EYE()) { - prayerWidgets.get(Prayer.values()[3].ordinal()).setHidden(true); // Thick Skin + prayerWidgets.get(Prayer.values()[3].ordinal()).setHidden(true); // Thick Skin } - + if (config.HideMYSTIC_WILL()) { - prayerWidgets.get(Prayer.values()[4].ordinal()).setHidden(true); // Mystic Will + prayerWidgets.get(Prayer.values()[4].ordinal()).setHidden(true); // Mystic Will } - + if (config.HideROCK_SKIN()) { - prayerWidgets.get(Prayer.values()[5].ordinal()).setHidden(true); // Rock Skin - } - + prayerWidgets.get(Prayer.values()[5].ordinal()).setHidden(true); // Rock Skin + } + if (config.HideSUPERHUMAN_STRENGTH()) { - prayerWidgets.get(Prayer.values()[6].ordinal()).setHidden(true); // Super Human Strength + prayerWidgets.get(Prayer.values()[6].ordinal()).setHidden(true); // Super Human Strength } - + if (config.HideIMPROVED_REFLEXES()) { - prayerWidgets.get(Prayer.values()[7].ordinal()).setHidden(true); // Improved_Reflexes + prayerWidgets.get(Prayer.values()[7].ordinal()).setHidden(true); // Improved_Reflexes } if (config.HideRapidRestore()) { - prayerWidgets.get(Prayer.values()[8].ordinal()).setHidden(true); // Rapid Restore + prayerWidgets.get(Prayer.values()[8].ordinal()).setHidden(true); // Rapid Restore } if (config.HideRapidHeal()) { - prayerWidgets.get(Prayer.values()[9].ordinal()).setHidden(true); // Rapid Heal + prayerWidgets.get(Prayer.values()[9].ordinal()).setHidden(true); // Rapid Heal } if (config.HideProtectItem()) { - prayerWidgets.get(Prayer.values()[10].ordinal()).setHidden(true); // Protect Item + prayerWidgets.get(Prayer.values()[10].ordinal()).setHidden(true); // Protect Item } if (config.HideHAWK_EYE()) { - prayerWidgets.get(Prayer.values()[11].ordinal()).setHidden(true); // Hawk Eye + prayerWidgets.get(Prayer.values()[11].ordinal()).setHidden(true); // Hawk Eye } if (config.HideMYSTIC_LORE()) { - prayerWidgets.get(Prayer.values()[12].ordinal()).setHidden(true); // Mystic Lore + prayerWidgets.get(Prayer.values()[12].ordinal()).setHidden(true); // Mystic Lore } - + if (config.HideSteelSkin()) { - prayerWidgets.get(Prayer.values()[13].ordinal()).setHidden(true); // Steel Skin + prayerWidgets.get(Prayer.values()[13].ordinal()).setHidden(true); // Steel Skin } if (config.HideUltimateStrength()) { - prayerWidgets.get(Prayer.values()[14].ordinal()).setHidden(true); // Ultimate Strength + prayerWidgets.get(Prayer.values()[14].ordinal()).setHidden(true); // Ultimate Strength } if (config.HideIncredibleReflex()) { - prayerWidgets.get(Prayer.values()[15].ordinal()).setHidden(true); // Incredible Reflexes + prayerWidgets.get(Prayer.values()[15].ordinal()).setHidden(true); // Incredible Reflexes } if (config.HidePTFMagic()) { - prayerWidgets.get(Prayer.values()[16].ordinal()).setHidden(true); // Protect from Magic + prayerWidgets.get(Prayer.values()[16].ordinal()).setHidden(true); // Protect from Magic } if (config.HidePTFRange()) { - prayerWidgets.get(Prayer.values()[17].ordinal()).setHidden(true); // Protect from Range + prayerWidgets.get(Prayer.values()[17].ordinal()).setHidden(true); // Protect from Range } if (config.HidePTFMelee()) { - prayerWidgets.get(Prayer.values()[18].ordinal()).setHidden(true); // Protect from Melee + prayerWidgets.get(Prayer.values()[18].ordinal()).setHidden(true); // Protect from Melee } if (config.HideEagle()) { - prayerWidgets.get(Prayer.values()[19].ordinal()).setHidden(true); // eagle eye + prayerWidgets.get(Prayer.values()[19].ordinal()).setHidden(true); // eagle eye } if (config.HideMystic()) { - prayerWidgets.get(Prayer.values()[20].ordinal()).setHidden(true); // Mystic Might + prayerWidgets.get(Prayer.values()[20].ordinal()).setHidden(true); // Mystic Might } - + if (config.HideRETRIBUTION()) { - prayerWidgets.get(Prayer.values()[21].ordinal()).setHidden(true); // Retribution + prayerWidgets.get(Prayer.values()[21].ordinal()).setHidden(true); // Retribution } if (config.HideRedemption()) { - prayerWidgets.get(Prayer.values()[22].ordinal()).setHidden(true); // Redemption + prayerWidgets.get(Prayer.values()[22].ordinal()).setHidden(true); // Redemption } if (config.HideSmite()) { - prayerWidgets.get(Prayer.values()[23].ordinal()).setHidden(true); // Smite + prayerWidgets.get(Prayer.values()[23].ordinal()).setHidden(true); // Smite } if (config.HidePreserve()) { - prayerWidgets.get(Prayer.values()[24].ordinal()).setHidden(true); // Preserve + prayerWidgets.get(Prayer.values()[24].ordinal()).setHidden(true); // Preserve } if (config.HideChivalry()) { - prayerWidgets.get(Prayer.values()[25].ordinal()).setHidden(true); // Chivalry + prayerWidgets.get(Prayer.values()[25].ordinal()).setHidden(true); // Chivalry } if (config.HidePiety()) { - prayerWidgets.get(Prayer.values()[26].ordinal()).setHidden(true); // Piety + prayerWidgets.get(Prayer.values()[26].ordinal()).setHidden(true); // Piety } if (config.HideRigour()) { - prayerWidgets.get(Prayer.values()[27].ordinal()).setHidden(true); // Rigour + prayerWidgets.get(Prayer.values()[27].ordinal()).setHidden(true); // Rigour } if (config.HideAugury()) { - prayerWidgets.get(Prayer.values()[28].ordinal()).setHidden(true); // Augury + prayerWidgets.get(Prayer.values()[28].ordinal()).setHidden(true); // Augury } } } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/hideprayers/PVM/HidePrayersPVMConfig.java b/runelite-client/src/main/java/net/runelite/client/plugins/hideprayers/PVM/HidePrayersPVMConfig.java index b4fac7e63f..a66461482c 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/hideprayers/PVM/HidePrayersPVMConfig.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/hideprayers/PVM/HidePrayersPVMConfig.java @@ -35,74 +35,98 @@ import net.runelite.client.config.ConfigItem; public interface HidePrayersPVMConfig extends Config { @ConfigItem - ( - position = 0, - keyName = "Barrows", - name = "Barrows", - description = "Shows prayers for Barrows" - ) - default Barrows Barrows() {return Barrows.DISABLED;} + ( + position = 0, + keyName = "Barrows", + name = "Barrows", + description = "Shows prayers for Barrows" + ) + default Barrows Barrows() + { + return Barrows.DISABLED; + } @ConfigItem - ( - position = 1, - keyName = "Cerberus", - name = "Cerberus", - description = "Shows prayers for Cerberus" - ) - default Cerberus Cerberus() {return Cerberus.DISABLED;} + ( + position = 1, + keyName = "Cerberus", + name = "Cerberus", + description = "Shows prayers for Cerberus" + ) + default Cerberus Cerberus() + { + return Cerberus.DISABLED; + } @ConfigItem - ( - position = 2, - keyName = "Vorkath", - name = "Vorkath", - description = "Shows prayers for Vorkath" - ) - default Vorkath Vorkath() {return Vorkath.DISABLED;} + ( + position = 2, + keyName = "Vorkath", + name = "Vorkath", + description = "Shows prayers for Vorkath" + ) + default Vorkath Vorkath() + { + return Vorkath.DISABLED; + } @ConfigItem - ( - position = 3, - keyName = "Zulrah", - name = "Zulrah", - description = "Shows prayers for Zulrah" - ) - default Zulrah Zulrah() {return Zulrah.DISABLED;} + ( + position = 3, + keyName = "Zulrah", + name = "Zulrah", + description = "Shows prayers for Zulrah" + ) + default Zulrah Zulrah() + { + return Zulrah.DISABLED; + } @ConfigItem - ( - position = 4, - keyName = "Armadyl", - name = "Armadyl", - description = "Shows prayers for Armadyl" - ) - default Armadyl Armadyl() {return Armadyl.DISABLED;} + ( + position = 4, + keyName = "Armadyl", + name = "Armadyl", + description = "Shows prayers for Armadyl" + ) + default Armadyl Armadyl() + { + return Armadyl.DISABLED; + } @ConfigItem - ( - position = 5, - keyName = "Bandos", - name = "Bandos", - description = "Shows prayers for Bandos" - ) - default Bandos Bandos() {return Bandos.DISABLED;} + ( + position = 5, + keyName = "Bandos", + name = "Bandos", + description = "Shows prayers for Bandos" + ) + default Bandos Bandos() + { + return Bandos.DISABLED; + } @ConfigItem - ( - position = 6, - keyName = "Saradomin", - name = "Saradomin", - description = "Shows prayers for Saradomin" - ) - default Saradomin Saradomin() {return Saradomin.DISABLED;} + ( + position = 6, + keyName = "Saradomin", + name = "Saradomin", + description = "Shows prayers for Saradomin" + ) + default Saradomin Saradomin() + { + return Saradomin.DISABLED; + } @ConfigItem - ( - position = 7, - keyName = "Zamorak", - name = "Zamorak", - description = "Shows prayers for Zamorak" - ) - default Zamorak Zamorak() {return Zamorak.DISABLED;} + ( + position = 7, + keyName = "Zamorak", + name = "Zamorak", + description = "Shows prayers for Zamorak" + ) + default Zamorak Zamorak() + { + return Zamorak.DISABLED; + } } \ No newline at end of file diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/hideprayers/PVM/HidePrayersPVMPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/hideprayers/PVM/HidePrayersPVMPlugin.java index 49f7fd0a1b..fc4b75684a 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/hideprayers/PVM/HidePrayersPVMPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/hideprayers/PVM/HidePrayersPVMPlugin.java @@ -24,12 +24,20 @@ * (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.hideprayers.PVM; import com.google.common.collect.ImmutableList; import com.google.inject.Provides; -import net.runelite.api.*; +import java.util.List; +import java.util.Objects; +import java.util.stream.Collectors; +import javax.inject.Inject; +import net.runelite.api.Client; +import net.runelite.api.GameState; +import net.runelite.api.HashTable; +import net.runelite.api.Prayer; +import net.runelite.api.WidgetNode; import net.runelite.api.events.ConfigChanged; import net.runelite.api.events.GameStateChanged; import net.runelite.api.events.WidgetLoaded; @@ -42,12 +50,8 @@ import net.runelite.client.plugins.Plugin; import net.runelite.client.plugins.PluginDescriptor; import net.runelite.client.plugins.PluginType; import net.runelite.client.plugins.hideprayers.util.PrayerTabStates; -import javax.inject.Inject; -import java.util.List; -import java.util.Objects; -import java.util.stream.Collectors; -@PluginDescriptor +@PluginDescriptor ( name = "Show/Hide PVM Prayers", description = "Hides specific Prayers in the Prayer tab for PVM.", @@ -60,37 +64,37 @@ public class HidePrayersPVMPlugin extends Plugin private static final int PRAYER_COUNT = Prayer.values().length; private static final List PRAYER_WIDGET_INFO_LIST = ImmutableList.of - ( - WidgetInfo.PRAYER_THICK_SKIN, //0 - WidgetInfo.PRAYER_BURST_OF_STRENGTH, //1 - WidgetInfo.PRAYER_CLARITY_OF_THOUGHT, //2 - WidgetInfo.PRAYER_SHARP_EYE, //3 - WidgetInfo.PRAYER_MYSTIC_WILL, //4 - WidgetInfo.PRAYER_ROCK_SKIN, //5 - WidgetInfo.PRAYER_SUPERHUMAN_STRENGTH, //6 - WidgetInfo.PRAYER_IMPROVED_REFLEXES, //7 - WidgetInfo.PRAYER_RAPID_RESTORE, //8 - WidgetInfo.PRAYER_RAPID_HEAL, //9 - WidgetInfo.PRAYER_PROTECT_ITEM, //10 - WidgetInfo.PRAYER_HAWK_EYE, //11 - WidgetInfo.PRAYER_MYSTIC_LORE, //12 - WidgetInfo.PRAYER_STEEL_SKIN, //13 - WidgetInfo.PRAYER_ULTIMATE_STRENGTH, //14 - WidgetInfo.PRAYER_INCREDIBLE_REFLEXES, //15 - WidgetInfo.PRAYER_PROTECT_FROM_MAGIC, //16 - WidgetInfo.PRAYER_PROTECT_FROM_MISSILES, //17 - WidgetInfo.PRAYER_PROTECT_FROM_MELEE, //18 - WidgetInfo.PRAYER_EAGLE_EYE, //19 - WidgetInfo.PRAYER_MYSTIC_MIGHT, //20 - WidgetInfo.PRAYER_RETRIBUTION, //21 - WidgetInfo.PRAYER_REDEMPTION, //22 - WidgetInfo.PRAYER_SMITE, //23 - WidgetInfo.PRAYER_PRESERVE, //24 - WidgetInfo.PRAYER_CHIVALRY, //25 - WidgetInfo.PRAYER_PIETY, //26 - WidgetInfo.PRAYER_RIGOUR, //27 - WidgetInfo.PRAYER_AUGURY //28 - ); + ( + WidgetInfo.PRAYER_THICK_SKIN, //0 + WidgetInfo.PRAYER_BURST_OF_STRENGTH, //1 + WidgetInfo.PRAYER_CLARITY_OF_THOUGHT, //2 + WidgetInfo.PRAYER_SHARP_EYE, //3 + WidgetInfo.PRAYER_MYSTIC_WILL, //4 + WidgetInfo.PRAYER_ROCK_SKIN, //5 + WidgetInfo.PRAYER_SUPERHUMAN_STRENGTH, //6 + WidgetInfo.PRAYER_IMPROVED_REFLEXES, //7 + WidgetInfo.PRAYER_RAPID_RESTORE, //8 + WidgetInfo.PRAYER_RAPID_HEAL, //9 + WidgetInfo.PRAYER_PROTECT_ITEM, //10 + WidgetInfo.PRAYER_HAWK_EYE, //11 + WidgetInfo.PRAYER_MYSTIC_LORE, //12 + WidgetInfo.PRAYER_STEEL_SKIN, //13 + WidgetInfo.PRAYER_ULTIMATE_STRENGTH, //14 + WidgetInfo.PRAYER_INCREDIBLE_REFLEXES, //15 + WidgetInfo.PRAYER_PROTECT_FROM_MAGIC, //16 + WidgetInfo.PRAYER_PROTECT_FROM_MISSILES, //17 + WidgetInfo.PRAYER_PROTECT_FROM_MELEE, //18 + WidgetInfo.PRAYER_EAGLE_EYE, //19 + WidgetInfo.PRAYER_MYSTIC_MIGHT, //20 + WidgetInfo.PRAYER_RETRIBUTION, //21 + WidgetInfo.PRAYER_REDEMPTION, //22 + WidgetInfo.PRAYER_SMITE, //23 + WidgetInfo.PRAYER_PRESERVE, //24 + WidgetInfo.PRAYER_CHIVALRY, //25 + WidgetInfo.PRAYER_PIETY, //26 + WidgetInfo.PRAYER_RIGOUR, //27 + WidgetInfo.PRAYER_AUGURY //28 + ); @Inject private Client client; @@ -108,7 +112,7 @@ public class HidePrayersPVMPlugin extends Plugin } @Override - protected void startUp() throws Exception + protected void startUp() throws Exception { hidePrayers(); configManager.setConfiguration("runelite", "hideprayerspvmplugin", false); @@ -116,22 +120,22 @@ public class HidePrayersPVMPlugin extends Plugin } @Override - protected void shutDown() throws Exception + protected void shutDown() throws Exception { restorePrayers(); } @Subscribe - public void onGameStateChanged(GameStateChanged event) + public void onGameStateChanged(GameStateChanged event) { - if (event.getGameState() == GameState.LOGGED_IN) + if (event.getGameState() == GameState.LOGGED_IN) { hidePrayers(); } } @Subscribe - public void onConfigChanged(ConfigChanged event) + public void onConfigChanged(ConfigChanged event) { if (event.getGroup().equals("hideprayersPVM")) { @@ -140,9 +144,9 @@ public class HidePrayersPVMPlugin extends Plugin } @Subscribe - public void onWidgetLoaded(WidgetLoaded event) + public void onWidgetLoaded(WidgetLoaded event) { - if (event.getGroupId() == WidgetID.PRAYER_GROUP_ID || event.getGroupId() == WidgetID.QUICK_PRAYERS_GROUP_ID) + if (event.getGroupId() == WidgetID.PRAYER_GROUP_ID || event.getGroupId() == WidgetID.QUICK_PRAYERS_GROUP_ID) { hidePrayers(); } @@ -168,39 +172,49 @@ public class HidePrayersPVMPlugin extends Plugin private void restorePrayers() { if (client.getGameState() != GameState.LOGGED_IN) + { return; + } PrayerTabStates prayerTabState = getPrayerTabState(); if (prayerTabState == PrayerTabStates.PRAYERS) { List prayerWidgets = PRAYER_WIDGET_INFO_LIST.stream().map(client::getWidget) - .filter(Objects::nonNull).collect(Collectors.toList()); + .filter(Objects::nonNull).collect(Collectors.toList()); if (prayerWidgets.size() != PRAYER_WIDGET_INFO_LIST.size()) + { return; + } for (int index = 0; index < PRAYER_COUNT; index++) + { prayerWidgets.get(Prayer.values()[index].ordinal()).setHidden(false); + } } } private void hidePrayers() { if (client.getGameState() != GameState.LOGGED_IN) + { return; + } PrayerTabStates prayerTabState = getPrayerTabState(); if (prayerTabState == PrayerTabStates.PRAYERS) { List prayerWidgets = PRAYER_WIDGET_INFO_LIST.stream().map(client::getWidget) - .filter(Objects::nonNull).collect(Collectors.toList()); + .filter(Objects::nonNull).collect(Collectors.toList()); if (prayerWidgets.size() != PRAYER_WIDGET_INFO_LIST.size()) + { return; + } - for (int index = 0; index < PRAYER_COUNT; index++) + for (int index = 0; index < PRAYER_COUNT; index++) { Prayer prayer = Prayer.values()[index]; Widget prayerWidget = prayerWidgets.get(prayer.ordinal()); @@ -214,7 +228,9 @@ public class HidePrayersPVMPlugin extends Plugin && config.Zamorak() == Zamorak.DISABLED && config.Zulrah() == Zulrah.DISABLED ) - prayerWidget.setHidden(false); + { + prayerWidget.setHidden(false); + } if (config.Zulrah() == Zulrah.ZULRAH_CHEAP) { diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/hideprayers/PVP/CombatPrayers.java b/runelite-client/src/main/java/net/runelite/client/plugins/hideprayers/PVP/CombatPrayers.java index 208c0e22b4..e40dd3218e 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/hideprayers/PVP/CombatPrayers.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/hideprayers/PVP/CombatPrayers.java @@ -40,7 +40,7 @@ public enum CombatPrayers PRAY25("25 prayer build"), PRAY31("31 prayer build"), PRAY43("43 prayer build"), - PRAY44("44 prayer build"), + PRAY44("44 prayer build"), PRAY45("45 prayer build"), PRAY52("52 prayer build"), PRAY55("55 prayer build"), diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/hideprayers/PVP/HidePrayersPVPConfig.java b/runelite-client/src/main/java/net/runelite/client/plugins/hideprayers/PVP/HidePrayersPVPConfig.java index 078870726a..30e482d489 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/hideprayers/PVP/HidePrayersPVPConfig.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/hideprayers/PVP/HidePrayersPVPConfig.java @@ -35,11 +35,14 @@ import net.runelite.client.config.ConfigItem; public interface HidePrayersPVPConfig extends Config { @ConfigItem - ( - position = 0, - keyName = "CombatPrayers", - name = "Combat Prayers", - description = "Shows prayers based on prayer build" - ) - default CombatPrayers CombatPrayers() {return CombatPrayers.DISABLED;} + ( + position = 0, + keyName = "CombatPrayers", + name = "Combat Prayers", + description = "Shows prayers based on prayer build" + ) + default CombatPrayers CombatPrayers() + { + return CombatPrayers.DISABLED; + } } \ No newline at end of file diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/hideprayers/PVP/HidePrayersPVPPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/hideprayers/PVP/HidePrayersPVPPlugin.java index 1bfd4238d7..0fc21ec4a8 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/hideprayers/PVP/HidePrayersPVPPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/hideprayers/PVP/HidePrayersPVPPlugin.java @@ -24,12 +24,20 @@ * (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.hideprayers.PVP; import com.google.common.collect.ImmutableList; import com.google.inject.Provides; -import net.runelite.api.*; +import java.util.List; +import java.util.Objects; +import java.util.stream.Collectors; +import javax.inject.Inject; +import net.runelite.api.Client; +import net.runelite.api.GameState; +import net.runelite.api.HashTable; +import net.runelite.api.Prayer; +import net.runelite.api.WidgetNode; import net.runelite.api.events.ConfigChanged; import net.runelite.api.events.GameStateChanged; import net.runelite.api.events.WidgetLoaded; @@ -42,12 +50,8 @@ import net.runelite.client.plugins.Plugin; import net.runelite.client.plugins.PluginDescriptor; import net.runelite.client.plugins.PluginType; import net.runelite.client.plugins.hideprayers.util.PrayerTabStates; -import javax.inject.Inject; -import java.util.List; -import java.util.Objects; -import java.util.stream.Collectors; -@PluginDescriptor +@PluginDescriptor ( name = "Show/Hide PVP Prayers", description = "Hides specific Prayers in the Prayer tab for PVP.", @@ -60,37 +64,37 @@ public class HidePrayersPVPPlugin extends Plugin private static final int PRAYER_COUNT = Prayer.values().length; private static final List PRAYER_WIDGET_INFO_LIST = ImmutableList.of - ( - WidgetInfo.PRAYER_THICK_SKIN, //0 - WidgetInfo.PRAYER_BURST_OF_STRENGTH, //1 - WidgetInfo.PRAYER_CLARITY_OF_THOUGHT, //2 - WidgetInfo.PRAYER_SHARP_EYE, //3 - WidgetInfo.PRAYER_MYSTIC_WILL, //4 - WidgetInfo.PRAYER_ROCK_SKIN, //5 - WidgetInfo.PRAYER_SUPERHUMAN_STRENGTH, //6 - WidgetInfo.PRAYER_IMPROVED_REFLEXES, //7 - WidgetInfo.PRAYER_RAPID_RESTORE, //8 - WidgetInfo.PRAYER_RAPID_HEAL, //9 - WidgetInfo.PRAYER_PROTECT_ITEM, //10 - WidgetInfo.PRAYER_HAWK_EYE, //11 - WidgetInfo.PRAYER_MYSTIC_LORE, //12 - WidgetInfo.PRAYER_STEEL_SKIN, //13 - WidgetInfo.PRAYER_ULTIMATE_STRENGTH, //14 - WidgetInfo.PRAYER_INCREDIBLE_REFLEXES, //15 - WidgetInfo.PRAYER_PROTECT_FROM_MAGIC, //16 - WidgetInfo.PRAYER_PROTECT_FROM_MISSILES, //17 - WidgetInfo.PRAYER_PROTECT_FROM_MELEE, //18 - WidgetInfo.PRAYER_EAGLE_EYE, //19 - WidgetInfo.PRAYER_MYSTIC_MIGHT, //20 - WidgetInfo.PRAYER_RETRIBUTION, //21 - WidgetInfo.PRAYER_REDEMPTION, //22 - WidgetInfo.PRAYER_SMITE, //23 - WidgetInfo.PRAYER_PRESERVE, //24 - WidgetInfo.PRAYER_CHIVALRY, //25 - WidgetInfo.PRAYER_PIETY, //26 - WidgetInfo.PRAYER_RIGOUR, //27 - WidgetInfo.PRAYER_AUGURY //28 - ); + ( + WidgetInfo.PRAYER_THICK_SKIN, //0 + WidgetInfo.PRAYER_BURST_OF_STRENGTH, //1 + WidgetInfo.PRAYER_CLARITY_OF_THOUGHT, //2 + WidgetInfo.PRAYER_SHARP_EYE, //3 + WidgetInfo.PRAYER_MYSTIC_WILL, //4 + WidgetInfo.PRAYER_ROCK_SKIN, //5 + WidgetInfo.PRAYER_SUPERHUMAN_STRENGTH, //6 + WidgetInfo.PRAYER_IMPROVED_REFLEXES, //7 + WidgetInfo.PRAYER_RAPID_RESTORE, //8 + WidgetInfo.PRAYER_RAPID_HEAL, //9 + WidgetInfo.PRAYER_PROTECT_ITEM, //10 + WidgetInfo.PRAYER_HAWK_EYE, //11 + WidgetInfo.PRAYER_MYSTIC_LORE, //12 + WidgetInfo.PRAYER_STEEL_SKIN, //13 + WidgetInfo.PRAYER_ULTIMATE_STRENGTH, //14 + WidgetInfo.PRAYER_INCREDIBLE_REFLEXES, //15 + WidgetInfo.PRAYER_PROTECT_FROM_MAGIC, //16 + WidgetInfo.PRAYER_PROTECT_FROM_MISSILES, //17 + WidgetInfo.PRAYER_PROTECT_FROM_MELEE, //18 + WidgetInfo.PRAYER_EAGLE_EYE, //19 + WidgetInfo.PRAYER_MYSTIC_MIGHT, //20 + WidgetInfo.PRAYER_RETRIBUTION, //21 + WidgetInfo.PRAYER_REDEMPTION, //22 + WidgetInfo.PRAYER_SMITE, //23 + WidgetInfo.PRAYER_PRESERVE, //24 + WidgetInfo.PRAYER_CHIVALRY, //25 + WidgetInfo.PRAYER_PIETY, //26 + WidgetInfo.PRAYER_RIGOUR, //27 + WidgetInfo.PRAYER_AUGURY //28 + ); @Inject private Client client; @@ -108,7 +112,7 @@ public class HidePrayersPVPPlugin extends Plugin } @Override - protected void startUp() throws Exception + protected void startUp() throws Exception { hidePrayers(); configManager.setConfiguration("runelite", "hideprayerspvmplugin", false); @@ -116,22 +120,22 @@ public class HidePrayersPVPPlugin extends Plugin } @Override - protected void shutDown() throws Exception + protected void shutDown() throws Exception { restorePrayers(); } @Subscribe - public void onGameStateChanged(GameStateChanged event) + public void onGameStateChanged(GameStateChanged event) { - if (event.getGameState() == GameState.LOGGED_IN) + if (event.getGameState() == GameState.LOGGED_IN) { hidePrayers(); } } @Subscribe - public void onConfigChanged(ConfigChanged event) + public void onConfigChanged(ConfigChanged event) { if (event.getGroup().equals("hideprayersPVP")) { @@ -140,9 +144,9 @@ public class HidePrayersPVPPlugin extends Plugin } @Subscribe - public void onWidgetLoaded(WidgetLoaded event) + public void onWidgetLoaded(WidgetLoaded event) { - if (event.getGroupId() == WidgetID.PRAYER_GROUP_ID || event.getGroupId() == WidgetID.QUICK_PRAYERS_GROUP_ID) + if (event.getGroupId() == WidgetID.PRAYER_GROUP_ID || event.getGroupId() == WidgetID.QUICK_PRAYERS_GROUP_ID) { hidePrayers(); } @@ -168,250 +172,262 @@ public class HidePrayersPVPPlugin extends Plugin private void restorePrayers() { if (client.getGameState() != GameState.LOGGED_IN) + { return; + } PrayerTabStates prayerTabState = getPrayerTabState(); if (prayerTabState == PrayerTabStates.PRAYERS) { List prayerWidgets = PRAYER_WIDGET_INFO_LIST.stream().map(client::getWidget) - .filter(Objects::nonNull).collect(Collectors.toList()); + .filter(Objects::nonNull).collect(Collectors.toList()); if (prayerWidgets.size() != PRAYER_WIDGET_INFO_LIST.size()) + { return; + } for (int index = 0; index < PRAYER_COUNT; index++) + { prayerWidgets.get(Prayer.values()[index].ordinal()).setHidden(false); + } } } private void hidePrayers() { if (client.getGameState() != GameState.LOGGED_IN) + { return; + } PrayerTabStates prayerTabState = getPrayerTabState(); if (prayerTabState == PrayerTabStates.PRAYERS) { List prayerWidgets = PRAYER_WIDGET_INFO_LIST.stream().map(client::getWidget) - .filter(Objects::nonNull).collect(Collectors.toList()); + .filter(Objects::nonNull).collect(Collectors.toList()); if (prayerWidgets.size() != PRAYER_WIDGET_INFO_LIST.size()) + { return; + } - for (int index = 0; index < PRAYER_COUNT; index++) + for (int index = 0; index < PRAYER_COUNT; index++) { Prayer prayer = Prayer.values()[index]; Widget prayerWidget = prayerWidgets.get(prayer.ordinal()); if (config.CombatPrayers() == CombatPrayers.DISABLED) - prayerWidget.setHidden(false); + { + prayerWidget.setHidden(false); + } if (config.CombatPrayers() == CombatPrayers.PRAY1) { prayerWidget.setHidden(true); - prayerWidgets.get(Prayer.values()[0].ordinal()).setHidden(false); // Thick Skin + prayerWidgets.get(Prayer.values()[0].ordinal()).setHidden(false); // Thick Skin } - + if (config.CombatPrayers() == CombatPrayers.PRAY13) { prayerWidget.setHidden(true); - prayerWidgets.get(Prayer.values()[0].ordinal()).setHidden(false); // Thick Skin - prayerWidgets.get(Prayer.values()[3].ordinal()).setHidden(false); // Sharp Eye - prayerWidgets.get(Prayer.values()[4].ordinal()).setHidden(false); // Mystic Will - prayerWidgets.get(Prayer.values()[5].ordinal()).setHidden(false); // Rock Skin - prayerWidgets.get(Prayer.values()[6].ordinal()).setHidden(false); // Super Human Strength + prayerWidgets.get(Prayer.values()[0].ordinal()).setHidden(false); // Thick Skin + prayerWidgets.get(Prayer.values()[3].ordinal()).setHidden(false); // Sharp Eye + prayerWidgets.get(Prayer.values()[4].ordinal()).setHidden(false); // Mystic Will + prayerWidgets.get(Prayer.values()[5].ordinal()).setHidden(false); // Rock Skin + prayerWidgets.get(Prayer.values()[6].ordinal()).setHidden(false); // Super Human Strength } - + if (config.CombatPrayers() == CombatPrayers.PRAY16) { prayerWidget.setHidden(true); - prayerWidgets.get(Prayer.values()[3].ordinal()).setHidden(false); // Sharp Eye - prayerWidgets.get(Prayer.values()[4].ordinal()).setHidden(false); // Mystic Will - prayerWidgets.get(Prayer.values()[5].ordinal()).setHidden(false); // Rock Skin - prayerWidgets.get(Prayer.values()[6].ordinal()).setHidden(false); // Super Human Strength - prayerWidgets.get(Prayer.values()[7].ordinal()).setHidden(false); // Improved Reflexed + prayerWidgets.get(Prayer.values()[3].ordinal()).setHidden(false); // Sharp Eye + prayerWidgets.get(Prayer.values()[4].ordinal()).setHidden(false); // Mystic Will + prayerWidgets.get(Prayer.values()[5].ordinal()).setHidden(false); // Rock Skin + prayerWidgets.get(Prayer.values()[6].ordinal()).setHidden(false); // Super Human Strength + prayerWidgets.get(Prayer.values()[7].ordinal()).setHidden(false); // Improved Reflexed } if (config.CombatPrayers() == CombatPrayers.PRAY25) { prayerWidget.setHidden(true); - prayerWidgets.get(Prayer.values()[3].ordinal()).setHidden(false); // Sharp Eye - prayerWidgets.get(Prayer.values()[4].ordinal()).setHidden(false); // Mystic Will - prayerWidgets.get(Prayer.values()[5].ordinal()).setHidden(false); // Rock Skin - prayerWidgets.get(Prayer.values()[6].ordinal()).setHidden(false); // Super Human Strength - prayerWidgets.get(Prayer.values()[7].ordinal()).setHidden(false); // Improved Reflexed - prayerWidgets.get(Prayer.values()[8].ordinal()).setHidden(false); // Rapid Restore - prayerWidgets.get(Prayer.values()[9].ordinal()).setHidden(false); // Rapid Heal - prayerWidgets.get(Prayer.values()[10].ordinal()).setHidden(false); // Protect Item + prayerWidgets.get(Prayer.values()[3].ordinal()).setHidden(false); // Sharp Eye + prayerWidgets.get(Prayer.values()[4].ordinal()).setHidden(false); // Mystic Will + prayerWidgets.get(Prayer.values()[5].ordinal()).setHidden(false); // Rock Skin + prayerWidgets.get(Prayer.values()[6].ordinal()).setHidden(false); // Super Human Strength + prayerWidgets.get(Prayer.values()[7].ordinal()).setHidden(false); // Improved Reflexed + prayerWidgets.get(Prayer.values()[8].ordinal()).setHidden(false); // Rapid Restore + prayerWidgets.get(Prayer.values()[9].ordinal()).setHidden(false); // Rapid Heal + prayerWidgets.get(Prayer.values()[10].ordinal()).setHidden(false); // Protect Item } - + if (config.CombatPrayers() == CombatPrayers.PRAY31) { prayerWidget.setHidden(true); - prayerWidgets.get(Prayer.values()[7].ordinal()).setHidden(false); // Improved Reflexed - prayerWidgets.get(Prayer.values()[8].ordinal()).setHidden(false); // Rapid Restore - prayerWidgets.get(Prayer.values()[9].ordinal()).setHidden(false); // Rapid Heal - prayerWidgets.get(Prayer.values()[10].ordinal()).setHidden(false); // Protect Item - prayerWidgets.get(Prayer.values()[11].ordinal()).setHidden(false); // Hawk Eye - prayerWidgets.get(Prayer.values()[12].ordinal()).setHidden(false); // Mystic Lore - prayerWidgets.get(Prayer.values()[13].ordinal()).setHidden(false); // Steel Skin - prayerWidgets.get(Prayer.values()[14].ordinal()).setHidden(false); // Ultimate Strength + prayerWidgets.get(Prayer.values()[7].ordinal()).setHidden(false); // Improved Reflexed + prayerWidgets.get(Prayer.values()[8].ordinal()).setHidden(false); // Rapid Restore + prayerWidgets.get(Prayer.values()[9].ordinal()).setHidden(false); // Rapid Heal + prayerWidgets.get(Prayer.values()[10].ordinal()).setHidden(false); // Protect Item + prayerWidgets.get(Prayer.values()[11].ordinal()).setHidden(false); // Hawk Eye + prayerWidgets.get(Prayer.values()[12].ordinal()).setHidden(false); // Mystic Lore + prayerWidgets.get(Prayer.values()[13].ordinal()).setHidden(false); // Steel Skin + prayerWidgets.get(Prayer.values()[14].ordinal()).setHidden(false); // Ultimate Strength } if (config.CombatPrayers() == CombatPrayers.PRAY43) { prayerWidget.setHidden(true); - prayerWidgets.get(Prayer.values()[8].ordinal()).setHidden(false); // Rapid Restore - prayerWidgets.get(Prayer.values()[9].ordinal()).setHidden(false); // Rapid Heal - prayerWidgets.get(Prayer.values()[10].ordinal()).setHidden(false); // Protect Item - prayerWidgets.get(Prayer.values()[11].ordinal()).setHidden(false); // Hawk Eye - prayerWidgets.get(Prayer.values()[12].ordinal()).setHidden(false); // Mystic Lore - prayerWidgets.get(Prayer.values()[13].ordinal()).setHidden(false); // Steel Skin - prayerWidgets.get(Prayer.values()[14].ordinal()).setHidden(false); // Ultimate Strength - prayerWidgets.get(Prayer.values()[15].ordinal()).setHidden(false); // Incredible Reflexes - prayerWidgets.get(Prayer.values()[16].ordinal()).setHidden(false); // Protect from Magic - prayerWidgets.get(Prayer.values()[17].ordinal()).setHidden(false); // Protect from Range - prayerWidgets.get(Prayer.values()[18].ordinal()).setHidden(false); // Protect from Melee - } - + prayerWidgets.get(Prayer.values()[8].ordinal()).setHidden(false); // Rapid Restore + prayerWidgets.get(Prayer.values()[9].ordinal()).setHidden(false); // Rapid Heal + prayerWidgets.get(Prayer.values()[10].ordinal()).setHidden(false); // Protect Item + prayerWidgets.get(Prayer.values()[11].ordinal()).setHidden(false); // Hawk Eye + prayerWidgets.get(Prayer.values()[12].ordinal()).setHidden(false); // Mystic Lore + prayerWidgets.get(Prayer.values()[13].ordinal()).setHidden(false); // Steel Skin + prayerWidgets.get(Prayer.values()[14].ordinal()).setHidden(false); // Ultimate Strength + prayerWidgets.get(Prayer.values()[15].ordinal()).setHidden(false); // Incredible Reflexes + prayerWidgets.get(Prayer.values()[16].ordinal()).setHidden(false); // Protect from Magic + prayerWidgets.get(Prayer.values()[17].ordinal()).setHidden(false); // Protect from Range + prayerWidgets.get(Prayer.values()[18].ordinal()).setHidden(false); // Protect from Melee + } + if (config.CombatPrayers() == CombatPrayers.PRAY44) { prayerWidget.setHidden(true); - prayerWidgets.get(Prayer.values()[8].ordinal()).setHidden(false); // Rapid Restore - prayerWidgets.get(Prayer.values()[9].ordinal()).setHidden(false); // Rapid Heal - prayerWidgets.get(Prayer.values()[10].ordinal()).setHidden(false); // Protect Item - prayerWidgets.get(Prayer.values()[12].ordinal()).setHidden(false); // Mystic Lore - prayerWidgets.get(Prayer.values()[13].ordinal()).setHidden(false); // Steel Skin - prayerWidgets.get(Prayer.values()[14].ordinal()).setHidden(false); // Ultimate Strength - prayerWidgets.get(Prayer.values()[15].ordinal()).setHidden(false); // Incredible Reflexes - prayerWidgets.get(Prayer.values()[16].ordinal()).setHidden(false); // Protect from Magic - prayerWidgets.get(Prayer.values()[17].ordinal()).setHidden(false); // Protect from Range - prayerWidgets.get(Prayer.values()[18].ordinal()).setHidden(false); // Protect from Melee - prayerWidgets.get(Prayer.values()[19].ordinal()).setHidden(false); // Eagle Eye + prayerWidgets.get(Prayer.values()[8].ordinal()).setHidden(false); // Rapid Restore + prayerWidgets.get(Prayer.values()[9].ordinal()).setHidden(false); // Rapid Heal + prayerWidgets.get(Prayer.values()[10].ordinal()).setHidden(false); // Protect Item + prayerWidgets.get(Prayer.values()[12].ordinal()).setHidden(false); // Mystic Lore + prayerWidgets.get(Prayer.values()[13].ordinal()).setHidden(false); // Steel Skin + prayerWidgets.get(Prayer.values()[14].ordinal()).setHidden(false); // Ultimate Strength + prayerWidgets.get(Prayer.values()[15].ordinal()).setHidden(false); // Incredible Reflexes + prayerWidgets.get(Prayer.values()[16].ordinal()).setHidden(false); // Protect from Magic + prayerWidgets.get(Prayer.values()[17].ordinal()).setHidden(false); // Protect from Range + prayerWidgets.get(Prayer.values()[18].ordinal()).setHidden(false); // Protect from Melee + prayerWidgets.get(Prayer.values()[19].ordinal()).setHidden(false); // Eagle Eye } - + if (config.CombatPrayers() == CombatPrayers.PRAY45) { prayerWidget.setHidden(true); - prayerWidgets.get(Prayer.values()[8].ordinal()).setHidden(false); // Rapid Restore - prayerWidgets.get(Prayer.values()[9].ordinal()).setHidden(false); // Rapid Heal - prayerWidgets.get(Prayer.values()[10].ordinal()).setHidden(false); // Protect Item - prayerWidgets.get(Prayer.values()[13].ordinal()).setHidden(false); // Steel Skin - prayerWidgets.get(Prayer.values()[14].ordinal()).setHidden(false); // Ultimate Strength - prayerWidgets.get(Prayer.values()[15].ordinal()).setHidden(false); // Incredible Reflexes - prayerWidgets.get(Prayer.values()[16].ordinal()).setHidden(false); // Protect from Magic - prayerWidgets.get(Prayer.values()[17].ordinal()).setHidden(false); // Protect from Range - prayerWidgets.get(Prayer.values()[18].ordinal()).setHidden(false); // Protect from Melee - prayerWidgets.get(Prayer.values()[19].ordinal()).setHidden(false); // Eagle Eye - prayerWidgets.get(Prayer.values()[20].ordinal()).setHidden(false); // Mystic Might - } - + prayerWidgets.get(Prayer.values()[8].ordinal()).setHidden(false); // Rapid Restore + prayerWidgets.get(Prayer.values()[9].ordinal()).setHidden(false); // Rapid Heal + prayerWidgets.get(Prayer.values()[10].ordinal()).setHidden(false); // Protect Item + prayerWidgets.get(Prayer.values()[13].ordinal()).setHidden(false); // Steel Skin + prayerWidgets.get(Prayer.values()[14].ordinal()).setHidden(false); // Ultimate Strength + prayerWidgets.get(Prayer.values()[15].ordinal()).setHidden(false); // Incredible Reflexes + prayerWidgets.get(Prayer.values()[16].ordinal()).setHidden(false); // Protect from Magic + prayerWidgets.get(Prayer.values()[17].ordinal()).setHidden(false); // Protect from Range + prayerWidgets.get(Prayer.values()[18].ordinal()).setHidden(false); // Protect from Melee + prayerWidgets.get(Prayer.values()[19].ordinal()).setHidden(false); // Eagle Eye + prayerWidgets.get(Prayer.values()[20].ordinal()).setHidden(false); // Mystic Might + } + if (config.CombatPrayers() == CombatPrayers.PRAY52) { prayerWidget.setHidden(true); - prayerWidgets.get(Prayer.values()[8].ordinal()).setHidden(false); // Rapid Restore - prayerWidgets.get(Prayer.values()[9].ordinal()).setHidden(false); // Rapid Heal - prayerWidgets.get(Prayer.values()[10].ordinal()).setHidden(false); // Protect Item - prayerWidgets.get(Prayer.values()[13].ordinal()).setHidden(false); // Steel Skin - prayerWidgets.get(Prayer.values()[14].ordinal()).setHidden(false); // Ultimate Strength - prayerWidgets.get(Prayer.values()[15].ordinal()).setHidden(false); // Incredible Reflexes - prayerWidgets.get(Prayer.values()[16].ordinal()).setHidden(false); // Protect from Magic - prayerWidgets.get(Prayer.values()[17].ordinal()).setHidden(false); // Protect from Range - prayerWidgets.get(Prayer.values()[18].ordinal()).setHidden(false); // Protect from Melee - prayerWidgets.get(Prayer.values()[19].ordinal()).setHidden(false); // Eagle Eye - prayerWidgets.get(Prayer.values()[20].ordinal()).setHidden(false); // Mystic Might - prayerWidgets.get(Prayer.values()[22].ordinal()).setHidden(false); // Redemption - prayerWidgets.get(Prayer.values()[23].ordinal()).setHidden(false); // Smite + prayerWidgets.get(Prayer.values()[8].ordinal()).setHidden(false); // Rapid Restore + prayerWidgets.get(Prayer.values()[9].ordinal()).setHidden(false); // Rapid Heal + prayerWidgets.get(Prayer.values()[10].ordinal()).setHidden(false); // Protect Item + prayerWidgets.get(Prayer.values()[13].ordinal()).setHidden(false); // Steel Skin + prayerWidgets.get(Prayer.values()[14].ordinal()).setHidden(false); // Ultimate Strength + prayerWidgets.get(Prayer.values()[15].ordinal()).setHidden(false); // Incredible Reflexes + prayerWidgets.get(Prayer.values()[16].ordinal()).setHidden(false); // Protect from Magic + prayerWidgets.get(Prayer.values()[17].ordinal()).setHidden(false); // Protect from Range + prayerWidgets.get(Prayer.values()[18].ordinal()).setHidden(false); // Protect from Melee + prayerWidgets.get(Prayer.values()[19].ordinal()).setHidden(false); // Eagle Eye + prayerWidgets.get(Prayer.values()[20].ordinal()).setHidden(false); // Mystic Might + prayerWidgets.get(Prayer.values()[22].ordinal()).setHidden(false); // Redemption + prayerWidgets.get(Prayer.values()[23].ordinal()).setHidden(false); // Smite } if (config.CombatPrayers() == CombatPrayers.PRAY55) { prayerWidget.setHidden(true); - prayerWidgets.get(Prayer.values()[8].ordinal()).setHidden(false); // Rapid Restore - prayerWidgets.get(Prayer.values()[9].ordinal()).setHidden(false); // Rapid Heal - prayerWidgets.get(Prayer.values()[10].ordinal()).setHidden(false); // Protect Item - prayerWidgets.get(Prayer.values()[13].ordinal()).setHidden(false); // Steel Skin - prayerWidgets.get(Prayer.values()[14].ordinal()).setHidden(false); // Ultimate Strength - prayerWidgets.get(Prayer.values()[15].ordinal()).setHidden(false); // Incredible Reflexes - prayerWidgets.get(Prayer.values()[16].ordinal()).setHidden(false); // Protect from Magic - prayerWidgets.get(Prayer.values()[17].ordinal()).setHidden(false); // Protect from Range - prayerWidgets.get(Prayer.values()[18].ordinal()).setHidden(false); // Protect from Melee - prayerWidgets.get(Prayer.values()[19].ordinal()).setHidden(false); // Eagle Eye - prayerWidgets.get(Prayer.values()[20].ordinal()).setHidden(false); // Mystic Might - prayerWidgets.get(Prayer.values()[22].ordinal()).setHidden(false); // Redemption - prayerWidgets.get(Prayer.values()[23].ordinal()).setHidden(false); // Smite - prayerWidgets.get(Prayer.values()[24].ordinal()).setHidden(false); // Preserve + prayerWidgets.get(Prayer.values()[8].ordinal()).setHidden(false); // Rapid Restore + prayerWidgets.get(Prayer.values()[9].ordinal()).setHidden(false); // Rapid Heal + prayerWidgets.get(Prayer.values()[10].ordinal()).setHidden(false); // Protect Item + prayerWidgets.get(Prayer.values()[13].ordinal()).setHidden(false); // Steel Skin + prayerWidgets.get(Prayer.values()[14].ordinal()).setHidden(false); // Ultimate Strength + prayerWidgets.get(Prayer.values()[15].ordinal()).setHidden(false); // Incredible Reflexes + prayerWidgets.get(Prayer.values()[16].ordinal()).setHidden(false); // Protect from Magic + prayerWidgets.get(Prayer.values()[17].ordinal()).setHidden(false); // Protect from Range + prayerWidgets.get(Prayer.values()[18].ordinal()).setHidden(false); // Protect from Melee + prayerWidgets.get(Prayer.values()[19].ordinal()).setHidden(false); // Eagle Eye + prayerWidgets.get(Prayer.values()[20].ordinal()).setHidden(false); // Mystic Might + prayerWidgets.get(Prayer.values()[22].ordinal()).setHidden(false); // Redemption + prayerWidgets.get(Prayer.values()[23].ordinal()).setHidden(false); // Smite + prayerWidgets.get(Prayer.values()[24].ordinal()).setHidden(false); // Preserve } if (config.CombatPrayers() == CombatPrayers.PRAY60) { prayerWidget.setHidden(true); - prayerWidgets.get(Prayer.values()[8].ordinal()).setHidden(false); // Rapid Restore - prayerWidgets.get(Prayer.values()[9].ordinal()).setHidden(false); // Rapid Heal - prayerWidgets.get(Prayer.values()[10].ordinal()).setHidden(false); // Protect Item - prayerWidgets.get(Prayer.values()[16].ordinal()).setHidden(false); // Protect from Magic - prayerWidgets.get(Prayer.values()[17].ordinal()).setHidden(false); // Protect from Range - prayerWidgets.get(Prayer.values()[18].ordinal()).setHidden(false); // Protect from Melee - prayerWidgets.get(Prayer.values()[19].ordinal()).setHidden(false); // Eagle Eye - prayerWidgets.get(Prayer.values()[20].ordinal()).setHidden(false); // Mystic Might - prayerWidgets.get(Prayer.values()[22].ordinal()).setHidden(false); // Redemption - prayerWidgets.get(Prayer.values()[23].ordinal()).setHidden(false); // Smite - prayerWidgets.get(Prayer.values()[24].ordinal()).setHidden(false); // Preserve - prayerWidgets.get(Prayer.values()[25].ordinal()).setHidden(false); // Chivalry + prayerWidgets.get(Prayer.values()[8].ordinal()).setHidden(false); // Rapid Restore + prayerWidgets.get(Prayer.values()[9].ordinal()).setHidden(false); // Rapid Heal + prayerWidgets.get(Prayer.values()[10].ordinal()).setHidden(false); // Protect Item + prayerWidgets.get(Prayer.values()[16].ordinal()).setHidden(false); // Protect from Magic + prayerWidgets.get(Prayer.values()[17].ordinal()).setHidden(false); // Protect from Range + prayerWidgets.get(Prayer.values()[18].ordinal()).setHidden(false); // Protect from Melee + prayerWidgets.get(Prayer.values()[19].ordinal()).setHidden(false); // Eagle Eye + prayerWidgets.get(Prayer.values()[20].ordinal()).setHidden(false); // Mystic Might + prayerWidgets.get(Prayer.values()[22].ordinal()).setHidden(false); // Redemption + prayerWidgets.get(Prayer.values()[23].ordinal()).setHidden(false); // Smite + prayerWidgets.get(Prayer.values()[24].ordinal()).setHidden(false); // Preserve + prayerWidgets.get(Prayer.values()[25].ordinal()).setHidden(false); // Chivalry } - + if (config.CombatPrayers() == CombatPrayers.PRAY70) { prayerWidget.setHidden(true); - prayerWidgets.get(Prayer.values()[8].ordinal()).setHidden(false); // Rapid Restore - prayerWidgets.get(Prayer.values()[9].ordinal()).setHidden(false); // Rapid Heal - prayerWidgets.get(Prayer.values()[10].ordinal()).setHidden(false); // Protect Item - prayerWidgets.get(Prayer.values()[16].ordinal()).setHidden(false); // Protect from Magic - prayerWidgets.get(Prayer.values()[17].ordinal()).setHidden(false); // Protect from Range - prayerWidgets.get(Prayer.values()[18].ordinal()).setHidden(false); // Protect from Melee - prayerWidgets.get(Prayer.values()[19].ordinal()).setHidden(false); // Eagle Eye - prayerWidgets.get(Prayer.values()[20].ordinal()).setHidden(false); // Mystic Might - prayerWidgets.get(Prayer.values()[22].ordinal()).setHidden(false); // Redemption - prayerWidgets.get(Prayer.values()[23].ordinal()).setHidden(false); // Smite - prayerWidgets.get(Prayer.values()[24].ordinal()).setHidden(false); // Preserve - prayerWidgets.get(Prayer.values()[26].ordinal()).setHidden(false); // Piety + prayerWidgets.get(Prayer.values()[8].ordinal()).setHidden(false); // Rapid Restore + prayerWidgets.get(Prayer.values()[9].ordinal()).setHidden(false); // Rapid Heal + prayerWidgets.get(Prayer.values()[10].ordinal()).setHidden(false); // Protect Item + prayerWidgets.get(Prayer.values()[16].ordinal()).setHidden(false); // Protect from Magic + prayerWidgets.get(Prayer.values()[17].ordinal()).setHidden(false); // Protect from Range + prayerWidgets.get(Prayer.values()[18].ordinal()).setHidden(false); // Protect from Melee + prayerWidgets.get(Prayer.values()[19].ordinal()).setHidden(false); // Eagle Eye + prayerWidgets.get(Prayer.values()[20].ordinal()).setHidden(false); // Mystic Might + prayerWidgets.get(Prayer.values()[22].ordinal()).setHidden(false); // Redemption + prayerWidgets.get(Prayer.values()[23].ordinal()).setHidden(false); // Smite + prayerWidgets.get(Prayer.values()[24].ordinal()).setHidden(false); // Preserve + prayerWidgets.get(Prayer.values()[26].ordinal()).setHidden(false); // Piety } if (config.CombatPrayers() == CombatPrayers.PRAY74) { prayerWidget.setHidden(true); - prayerWidgets.get(Prayer.values()[8].ordinal()).setHidden(false); // Rapid Restore - prayerWidgets.get(Prayer.values()[9].ordinal()).setHidden(false); // Rapid Heal - prayerWidgets.get(Prayer.values()[10].ordinal()).setHidden(false); // Protect Item - prayerWidgets.get(Prayer.values()[16].ordinal()).setHidden(false); // Protect from Magic - prayerWidgets.get(Prayer.values()[17].ordinal()).setHidden(false); // Protect from Range - prayerWidgets.get(Prayer.values()[18].ordinal()).setHidden(false); // Protect from Melee - prayerWidgets.get(Prayer.values()[20].ordinal()).setHidden(false); // Mystic Might - prayerWidgets.get(Prayer.values()[22].ordinal()).setHidden(false); // Redemption - prayerWidgets.get(Prayer.values()[23].ordinal()).setHidden(false); // Smite - prayerWidgets.get(Prayer.values()[24].ordinal()).setHidden(false); // Preserve - prayerWidgets.get(Prayer.values()[26].ordinal()).setHidden(false); // Piety - prayerWidgets.get(Prayer.values()[27].ordinal()).setHidden(false); // Rigour - } - + prayerWidgets.get(Prayer.values()[8].ordinal()).setHidden(false); // Rapid Restore + prayerWidgets.get(Prayer.values()[9].ordinal()).setHidden(false); // Rapid Heal + prayerWidgets.get(Prayer.values()[10].ordinal()).setHidden(false); // Protect Item + prayerWidgets.get(Prayer.values()[16].ordinal()).setHidden(false); // Protect from Magic + prayerWidgets.get(Prayer.values()[17].ordinal()).setHidden(false); // Protect from Range + prayerWidgets.get(Prayer.values()[18].ordinal()).setHidden(false); // Protect from Melee + prayerWidgets.get(Prayer.values()[20].ordinal()).setHidden(false); // Mystic Might + prayerWidgets.get(Prayer.values()[22].ordinal()).setHidden(false); // Redemption + prayerWidgets.get(Prayer.values()[23].ordinal()).setHidden(false); // Smite + prayerWidgets.get(Prayer.values()[24].ordinal()).setHidden(false); // Preserve + prayerWidgets.get(Prayer.values()[26].ordinal()).setHidden(false); // Piety + prayerWidgets.get(Prayer.values()[27].ordinal()).setHidden(false); // Rigour + } + if (config.CombatPrayers() == CombatPrayers.PRAY77) { prayerWidget.setHidden(true); - prayerWidgets.get(Prayer.values()[8].ordinal()).setHidden(false); // Rapid Restore - prayerWidgets.get(Prayer.values()[9].ordinal()).setHidden(false); // Rapid Heal - prayerWidgets.get(Prayer.values()[10].ordinal()).setHidden(false); // Protect Item - prayerWidgets.get(Prayer.values()[16].ordinal()).setHidden(false); // Protect from Magic - prayerWidgets.get(Prayer.values()[17].ordinal()).setHidden(false); // Protect from Range - prayerWidgets.get(Prayer.values()[18].ordinal()).setHidden(false); // Protect from Melee - prayerWidgets.get(Prayer.values()[22].ordinal()).setHidden(false); // Redemption - prayerWidgets.get(Prayer.values()[23].ordinal()).setHidden(false); // Smite - prayerWidgets.get(Prayer.values()[24].ordinal()).setHidden(false); // Preserve - prayerWidgets.get(Prayer.values()[26].ordinal()).setHidden(false); // Piety - prayerWidgets.get(Prayer.values()[27].ordinal()).setHidden(false); // Rigour - prayerWidgets.get(Prayer.values()[28].ordinal()).setHidden(false); // Augury + prayerWidgets.get(Prayer.values()[8].ordinal()).setHidden(false); // Rapid Restore + prayerWidgets.get(Prayer.values()[9].ordinal()).setHidden(false); // Rapid Heal + prayerWidgets.get(Prayer.values()[10].ordinal()).setHidden(false); // Protect Item + prayerWidgets.get(Prayer.values()[16].ordinal()).setHidden(false); // Protect from Magic + prayerWidgets.get(Prayer.values()[17].ordinal()).setHidden(false); // Protect from Range + prayerWidgets.get(Prayer.values()[18].ordinal()).setHidden(false); // Protect from Melee + prayerWidgets.get(Prayer.values()[22].ordinal()).setHidden(false); // Redemption + prayerWidgets.get(Prayer.values()[23].ordinal()).setHidden(false); // Smite + prayerWidgets.get(Prayer.values()[24].ordinal()).setHidden(false); // Preserve + prayerWidgets.get(Prayer.values()[26].ordinal()).setHidden(false); // Piety + prayerWidgets.get(Prayer.values()[27].ordinal()).setHidden(false); // Rigour + prayerWidgets.get(Prayer.values()[28].ordinal()).setHidden(false); // Augury } } } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/hideprayers/util/PrayerTabStates.java b/runelite-client/src/main/java/net/runelite/client/plugins/hideprayers/util/PrayerTabStates.java index e02efad33f..cf036f1fb7 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/hideprayers/util/PrayerTabStates.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/hideprayers/util/PrayerTabStates.java @@ -24,12 +24,12 @@ * (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.hideprayers.util; public enum PrayerTabStates { - NONE, - PRAYERS, - QUICK_PRAYERS + NONE, + PRAYERS, + QUICK_PRAYERS } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/highalchemy/HighAlchemyOverlay.java b/runelite-client/src/main/java/net/runelite/client/plugins/highalchemy/HighAlchemyOverlay.java index dfaf0be2e6..7a7fc07394 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/highalchemy/HighAlchemyOverlay.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/highalchemy/HighAlchemyOverlay.java @@ -32,8 +32,6 @@ import java.awt.Color; import java.awt.Graphics2D; import java.awt.Rectangle; import java.awt.image.BufferedImage; -import java.util.HashSet; -import java.util.Set; import javax.inject.Inject; import net.runelite.api.ItemComposition; import net.runelite.api.ItemID; diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/highalchemy/HighAlchemyPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/highalchemy/HighAlchemyPlugin.java index af43bb3f77..61439c985f 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/highalchemy/HighAlchemyPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/highalchemy/HighAlchemyPlugin.java @@ -113,7 +113,7 @@ public class HighAlchemyPlugin extends Plugin if (config.showInventory()) { Arrays.stream( - new int[] { + new int[]{ DEPOSIT_BOX_GROUP_ID, BANK_INVENTORY_GROUP_ID, SHOP_INVENTORY_GROUP_ID, diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/hiscore/HiscorePlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/hiscore/HiscorePlugin.java index 5ecd24ae1b..65b978a0b5 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/hiscore/HiscorePlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/hiscore/HiscorePlugin.java @@ -1,256 +1,256 @@ -/* - * Copyright (c) 2017, Adam - * 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.hiscore; - -import com.google.common.collect.ImmutableList; -import com.google.common.collect.ObjectArrays; -import com.google.inject.Provides; -import java.awt.image.BufferedImage; -import java.lang.reflect.InvocationTargetException; -import java.util.concurrent.ScheduledExecutorService; -import java.util.regex.Matcher; -import java.util.regex.Pattern; -import javax.annotation.Nullable; -import javax.inject.Inject; -import javax.inject.Provider; -import javax.swing.SwingUtilities; -import net.runelite.api.ChatMessageType; -import net.runelite.api.Client; -import net.runelite.api.MenuAction; -import net.runelite.api.MenuEntry; -import net.runelite.api.events.ChatMessage; -import net.runelite.api.events.ConfigChanged; -import net.runelite.api.events.MenuEntryAdded; -import net.runelite.api.events.PlayerMenuOptionClicked; -import net.runelite.api.widgets.WidgetInfo; -import net.runelite.client.config.ConfigManager; -import net.runelite.client.eventbus.Subscribe; -import net.runelite.client.menus.MenuManager; -import net.runelite.client.plugins.Plugin; -import net.runelite.client.plugins.PluginDescriptor; -import net.runelite.client.ui.ClientToolbar; -import net.runelite.client.ui.NavigationButton; -import net.runelite.client.util.ImageUtil; -import net.runelite.client.util.Text; -import org.apache.commons.lang3.ArrayUtils; - -@PluginDescriptor( - name = "HiScore", - description = "Enable the HiScore panel and an optional Lookup option on players", - tags = {"panel", "players"}, - loadWhenOutdated = true -) -public class HiscorePlugin extends Plugin -{ - private static final String LOOKUP = "Lookup"; - private static final String KICK_OPTION = "Kick"; - private static final ImmutableList AFTER_OPTIONS = ImmutableList.of("Message", "Add ignore", "Remove friend", KICK_OPTION); - private static final Pattern BOUNTY_PATTERN = Pattern.compile("You've been assigned a target: (.*)"); - - @Inject - @Nullable - private Client client; - - @Inject - private Provider menuManager; - - @Inject - private ClientToolbar clientToolbar; - - @Inject - private ScheduledExecutorService executor; - - @Inject - private HiscoreConfig config; - - private NavigationButton navButton; - private HiscorePanel hiscorePanel; - - @Inject - private NameAutocompleter autocompleter; - - @Provides - HiscoreConfig provideConfig(ConfigManager configManager) - { - return configManager.getConfig(HiscoreConfig.class); - } - - @Override - protected void startUp() throws Exception - { - hiscorePanel = injector.getInstance(HiscorePanel.class); - - final BufferedImage icon = ImageUtil.getResourceStreamFromClass(getClass(), "normal.png"); - - navButton = NavigationButton.builder() - .tooltip("Hiscore") - .icon(icon) - .priority(5) - .panel(hiscorePanel) - .build(); - - clientToolbar.addNavigation(navButton); - - if (config.playerOption() && client != null) - { - menuManager.get().addPlayerMenuItem(LOOKUP); - } - if (config.autocomplete()) - { - hiscorePanel.addInputKeyListener(autocompleter); - } - } - - @Override - protected void shutDown() throws Exception - { - hiscorePanel.removeInputKeyListener(autocompleter); - clientToolbar.removeNavigation(navButton); - - if (client != null) - { - menuManager.get().removePlayerMenuItem(LOOKUP); - } - } - - @Subscribe - public void onConfigChanged(ConfigChanged event) - { - if (event.getGroup().equals("hiscore")) - { - if (client != null) - { - menuManager.get().removePlayerMenuItem(LOOKUP); - - if (config.playerOption()) - { - menuManager.get().addPlayerMenuItem(LOOKUP); - } - } - - if (event.getKey().equals("autocomplete")) - { - if (config.autocomplete()) - { - hiscorePanel.addInputKeyListener(autocompleter); - } - else - { - hiscorePanel.removeInputKeyListener(autocompleter); - } - } - } - } - - @Subscribe - public void onMenuEntryAdded(MenuEntryAdded event) - { - if (!config.menuOption()) - { - return; - } - - int groupId = WidgetInfo.TO_GROUP(event.getActionParam1()); - String option = event.getOption(); - - if (groupId == WidgetInfo.FRIENDS_LIST.getGroupId() || groupId == WidgetInfo.CLAN_CHAT.getGroupId() || - groupId == WidgetInfo.CHATBOX.getGroupId() && !KICK_OPTION.equals(option) || //prevent from adding for Kick option (interferes with the raiding party one) - groupId == WidgetInfo.RAIDING_PARTY.getGroupId() || groupId == WidgetInfo.PRIVATE_CHAT_MESSAGE.getGroupId()) - { - boolean after; - - if (!AFTER_OPTIONS.contains(option)) - { - return; - } - - final MenuEntry lookup = new MenuEntry(); - lookup.setOption(LOOKUP); - lookup.setTarget(event.getTarget()); - lookup.setType(MenuAction.RUNELITE.getId()); - lookup.setParam0(event.getActionParam0()); - lookup.setParam1(event.getActionParam1()); - lookup.setIdentifier(event.getIdentifier()); - - insertMenuEntry(lookup, client.getMenuEntries()); - } - } - - @Subscribe - public void onPlayerMenuOptionClicked(PlayerMenuOptionClicked event) - { - if (event.getMenuOption().equals(LOOKUP)) - { - lookupPlayer(Text.removeTags(event.getMenuTarget())); - } - } - - @Subscribe - public void onChatMessage(ChatMessage event) - { - if (!config.bountylookup() || !event.getType().equals(ChatMessageType.GAMEMESSAGE)) - { - return; - } - - String message = event.getMessage(); - Matcher m = BOUNTY_PATTERN.matcher(message); - if (m.matches()) - { - lookupPlayer(m.group(1)); - } - } - - private void insertMenuEntry(MenuEntry newEntry, MenuEntry[] entries) - { - MenuEntry[] newMenu = ObjectArrays.concat(entries, newEntry); - int menuEntryCount = newMenu.length; - ArrayUtils.swap(newMenu, menuEntryCount - 1, menuEntryCount - 2); - client.setMenuEntries(newMenu); - } - - private void lookupPlayer(String playerName) - { - executor.execute(() -> - { - try - { - SwingUtilities.invokeAndWait(() -> - { - if (!navButton.isSelected()) - { - navButton.getOnSelect().run(); - } - }); - } - catch (InterruptedException | InvocationTargetException e) - { - throw new RuntimeException(e); - } - - hiscorePanel.lookup(playerName); - }); - } -} +/* + * Copyright (c) 2017, Adam + * 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.hiscore; + +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ObjectArrays; +import com.google.inject.Provides; +import java.awt.image.BufferedImage; +import java.lang.reflect.InvocationTargetException; +import java.util.concurrent.ScheduledExecutorService; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import javax.annotation.Nullable; +import javax.inject.Inject; +import javax.inject.Provider; +import javax.swing.SwingUtilities; +import net.runelite.api.ChatMessageType; +import net.runelite.api.Client; +import net.runelite.api.MenuAction; +import net.runelite.api.MenuEntry; +import net.runelite.api.events.ChatMessage; +import net.runelite.api.events.ConfigChanged; +import net.runelite.api.events.MenuEntryAdded; +import net.runelite.api.events.PlayerMenuOptionClicked; +import net.runelite.api.widgets.WidgetInfo; +import net.runelite.client.config.ConfigManager; +import net.runelite.client.eventbus.Subscribe; +import net.runelite.client.menus.MenuManager; +import net.runelite.client.plugins.Plugin; +import net.runelite.client.plugins.PluginDescriptor; +import net.runelite.client.ui.ClientToolbar; +import net.runelite.client.ui.NavigationButton; +import net.runelite.client.util.ImageUtil; +import net.runelite.client.util.Text; +import org.apache.commons.lang3.ArrayUtils; + +@PluginDescriptor( + name = "HiScore", + description = "Enable the HiScore panel and an optional Lookup option on players", + tags = {"panel", "players"}, + loadWhenOutdated = true +) +public class HiscorePlugin extends Plugin +{ + private static final String LOOKUP = "Lookup"; + private static final String KICK_OPTION = "Kick"; + private static final ImmutableList AFTER_OPTIONS = ImmutableList.of("Message", "Add ignore", "Remove friend", KICK_OPTION); + private static final Pattern BOUNTY_PATTERN = Pattern.compile("You've been assigned a target: (.*)"); + + @Inject + @Nullable + private Client client; + + @Inject + private Provider menuManager; + + @Inject + private ClientToolbar clientToolbar; + + @Inject + private ScheduledExecutorService executor; + + @Inject + private HiscoreConfig config; + + private NavigationButton navButton; + private HiscorePanel hiscorePanel; + + @Inject + private NameAutocompleter autocompleter; + + @Provides + HiscoreConfig provideConfig(ConfigManager configManager) + { + return configManager.getConfig(HiscoreConfig.class); + } + + @Override + protected void startUp() throws Exception + { + hiscorePanel = injector.getInstance(HiscorePanel.class); + + final BufferedImage icon = ImageUtil.getResourceStreamFromClass(getClass(), "normal.png"); + + navButton = NavigationButton.builder() + .tooltip("Hiscore") + .icon(icon) + .priority(5) + .panel(hiscorePanel) + .build(); + + clientToolbar.addNavigation(navButton); + + if (config.playerOption() && client != null) + { + menuManager.get().addPlayerMenuItem(LOOKUP); + } + if (config.autocomplete()) + { + hiscorePanel.addInputKeyListener(autocompleter); + } + } + + @Override + protected void shutDown() throws Exception + { + hiscorePanel.removeInputKeyListener(autocompleter); + clientToolbar.removeNavigation(navButton); + + if (client != null) + { + menuManager.get().removePlayerMenuItem(LOOKUP); + } + } + + @Subscribe + public void onConfigChanged(ConfigChanged event) + { + if (event.getGroup().equals("hiscore")) + { + if (client != null) + { + menuManager.get().removePlayerMenuItem(LOOKUP); + + if (config.playerOption()) + { + menuManager.get().addPlayerMenuItem(LOOKUP); + } + } + + if (event.getKey().equals("autocomplete")) + { + if (config.autocomplete()) + { + hiscorePanel.addInputKeyListener(autocompleter); + } + else + { + hiscorePanel.removeInputKeyListener(autocompleter); + } + } + } + } + + @Subscribe + public void onMenuEntryAdded(MenuEntryAdded event) + { + if (!config.menuOption()) + { + return; + } + + int groupId = WidgetInfo.TO_GROUP(event.getActionParam1()); + String option = event.getOption(); + + if (groupId == WidgetInfo.FRIENDS_LIST.getGroupId() || groupId == WidgetInfo.CLAN_CHAT.getGroupId() || + groupId == WidgetInfo.CHATBOX.getGroupId() && !KICK_OPTION.equals(option) || //prevent from adding for Kick option (interferes with the raiding party one) + groupId == WidgetInfo.RAIDING_PARTY.getGroupId() || groupId == WidgetInfo.PRIVATE_CHAT_MESSAGE.getGroupId()) + { + boolean after; + + if (!AFTER_OPTIONS.contains(option)) + { + return; + } + + final MenuEntry lookup = new MenuEntry(); + lookup.setOption(LOOKUP); + lookup.setTarget(event.getTarget()); + lookup.setType(MenuAction.RUNELITE.getId()); + lookup.setParam0(event.getActionParam0()); + lookup.setParam1(event.getActionParam1()); + lookup.setIdentifier(event.getIdentifier()); + + insertMenuEntry(lookup, client.getMenuEntries()); + } + } + + @Subscribe + public void onPlayerMenuOptionClicked(PlayerMenuOptionClicked event) + { + if (event.getMenuOption().equals(LOOKUP)) + { + lookupPlayer(Text.removeTags(event.getMenuTarget())); + } + } + + @Subscribe + public void onChatMessage(ChatMessage event) + { + if (!config.bountylookup() || !event.getType().equals(ChatMessageType.GAMEMESSAGE)) + { + return; + } + + String message = event.getMessage(); + Matcher m = BOUNTY_PATTERN.matcher(message); + if (m.matches()) + { + lookupPlayer(m.group(1)); + } + } + + private void insertMenuEntry(MenuEntry newEntry, MenuEntry[] entries) + { + MenuEntry[] newMenu = ObjectArrays.concat(entries, newEntry); + int menuEntryCount = newMenu.length; + ArrayUtils.swap(newMenu, menuEntryCount - 1, menuEntryCount - 2); + client.setMenuEntries(newMenu); + } + + private void lookupPlayer(String playerName) + { + executor.execute(() -> + { + try + { + SwingUtilities.invokeAndWait(() -> + { + if (!navButton.isSelected()) + { + navButton.getOnSelect().run(); + } + }); + } + catch (InterruptedException | InvocationTargetException e) + { + throw new RuntimeException(e); + } + + hiscorePanel.lookup(playerName); + }); + } +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/hiscore/NameAutocompleter.java b/runelite-client/src/main/java/net/runelite/client/plugins/hiscore/NameAutocompleter.java index 6dcaaecf83..2926be7001 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/hiscore/NameAutocompleter.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/hiscore/NameAutocompleter.java @@ -1,265 +1,265 @@ -/* - * Copyright (c) 2018, John Pettenger - * 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.hiscore; - -import com.google.inject.Inject; -import java.awt.event.KeyEvent; -import java.awt.event.KeyListener; -import java.util.Arrays; -import java.util.Objects; -import java.util.Optional; -import java.util.regex.Pattern; -import javax.annotation.Nullable; -import javax.swing.SwingUtilities; -import javax.swing.text.BadLocationException; -import javax.swing.text.Document; -import javax.swing.text.JTextComponent; -import lombok.extern.slf4j.Slf4j; -import net.runelite.api.ClanMember; -import net.runelite.api.Client; -import net.runelite.api.Friend; -import net.runelite.api.Player; - -@Slf4j -class NameAutocompleter implements KeyListener -{ - /** - * Non-breaking space character. - */ - private static final String NBSP = Character.toString((char)160); - - /** - * Character class for characters that cannot be in an RSN. - */ - private static final Pattern INVALID_CHARS = Pattern.compile("[^a-zA-Z0-9_ -]"); - - private final Client client; - - /** - * The name currently being autocompleted. - */ - private String autocompleteName; - - /** - * Pattern for the name currently being autocompleted. - */ - private Pattern autocompleteNamePattern; - - @Inject - private NameAutocompleter(@Nullable Client client) - { - this.client = client; - } - - @Override - public void keyPressed(KeyEvent e) - { - - } - - @Override - public void keyReleased(KeyEvent e) - { - - } - - @Override - public void keyTyped(KeyEvent e) - { - final JTextComponent input = (JTextComponent)e.getSource(); - final String inputText = input.getText(); - - // Only autocomplete if the selection end is at the end of the text. - if (input.getSelectionEnd() != inputText.length()) - { - return; - } - - // Character to be inserted at the selection start. - final String charToInsert = Character.toString(e.getKeyChar()); - - // Don't attempt to autocomplete if the name is invalid. - // This condition is also true when the user presses a key like backspace. - if (INVALID_CHARS.matcher(charToInsert).find() - || INVALID_CHARS.matcher(inputText).find()) - { - return; - } - - // Check if we are already autocompleting. - if (autocompleteName != null && autocompleteNamePattern.matcher(inputText).matches()) - { - if (isExpectedNext(input, charToInsert)) - { - try - { - // Insert the character and move the selection. - final int insertIndex = input.getSelectionStart(); - Document doc = input.getDocument(); - doc.remove(insertIndex, 1); - doc.insertString(insertIndex, charToInsert, null); - input.select(insertIndex + 1, input.getSelectionEnd()); - } - catch (BadLocationException ex) - { - log.warn("Could not insert character.", ex); - } - - // Prevent default behavior. - e.consume(); - } - else // Character to insert does not match current autocompletion. Look for another name. - { - newAutocomplete(e); - } - } - else // Search for a name to autocomplete - { - newAutocomplete(e); - } - } - - private void newAutocomplete(KeyEvent e) - { - final JTextComponent input = (JTextComponent)e.getSource(); - final String inputText = input.getText(); - final String nameStart = inputText.substring(0, input.getSelectionStart()) + e.getKeyChar(); - - if (findAutocompleteName(nameStart)) - { - // Assert this.autocompleteName != null - final String name = this.autocompleteName; - SwingUtilities.invokeLater(() -> - { - try - { - input.getDocument().insertString( - nameStart.length(), - name.substring(nameStart.length()), - null); - input.select(nameStart.length(), name.length()); - } - catch (BadLocationException ex) - { - log.warn("Could not autocomplete name.", ex); - } - }); - } - } - - private boolean findAutocompleteName(String nameStart) - { - final Pattern pattern; - Optional autocompleteName; - - // Pattern to match names that start with nameStart. - // Allows spaces to be represented as common whitespaces, underscores, - // hyphens, or non-breaking spaces. - // Matching non-breaking spaces is necessary because the API - // returns non-breaking spaces when a name has whitespace. - pattern = Pattern.compile( - "(?i)^" + nameStart.replaceAll("[ _-]", "[ _" + NBSP + "-]") + ".+?"); - - if (client == null) - { - return false; - } - - autocompleteName = Optional.empty(); - - // TODO: Search lookup history - - Friend[] friends = client.getFriends(); - if (friends != null) - { - autocompleteName = Arrays.stream(friends) - .filter(Objects::nonNull) - .map(Friend::getName) - .filter(n -> pattern.matcher(n).matches()) - .findFirst(); - } - - // Search clan if a friend wasn't found - if (!autocompleteName.isPresent()) - { - final ClanMember[] clannies = client.getClanMembers(); - if (clannies != null) - { - autocompleteName = Arrays.stream(clannies) - .filter(Objects::nonNull) - .map(ClanMember::getUsername) - .filter(n -> pattern.matcher(n).matches()) - .findFirst(); - } - } - - // Search cached players if a clannie wasn't found. - if (!autocompleteName.isPresent()) - { - final Player[] cachedPlayers = client.getCachedPlayers(); - autocompleteName = Arrays.stream(cachedPlayers) - .filter(Objects::nonNull) - .map(Player::getName) - .filter(n -> pattern.matcher(n).matches()) - .findFirst(); - } - - if (autocompleteName.isPresent()) - { - this.autocompleteName = autocompleteName.get().replace(NBSP, " "); - this.autocompleteNamePattern = Pattern.compile( - "(?i)^" + this.autocompleteName.replaceAll("[ _-]", "[ _-]") + "$"); - } - else - { - this.autocompleteName = null; - this.autocompleteNamePattern = null; - } - - return autocompleteName.isPresent(); - } - - private boolean isExpectedNext(JTextComponent input, String nextChar) - { - String expected; - if (input.getSelectionStart() < input.getSelectionEnd()) - { - try - { - expected = input.getText(input.getSelectionStart(), 1); - } - catch (BadLocationException ex) - { - log.warn("Could not get first character from input selection.", ex); - return false; - } - } - else - { - expected = ""; - } - return nextChar.equalsIgnoreCase(expected); - } +/* + * Copyright (c) 2018, John Pettenger + * 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.hiscore; + +import com.google.inject.Inject; +import java.awt.event.KeyEvent; +import java.awt.event.KeyListener; +import java.util.Arrays; +import java.util.Objects; +import java.util.Optional; +import java.util.regex.Pattern; +import javax.annotation.Nullable; +import javax.swing.SwingUtilities; +import javax.swing.text.BadLocationException; +import javax.swing.text.Document; +import javax.swing.text.JTextComponent; +import lombok.extern.slf4j.Slf4j; +import net.runelite.api.ClanMember; +import net.runelite.api.Client; +import net.runelite.api.Friend; +import net.runelite.api.Player; + +@Slf4j +class NameAutocompleter implements KeyListener +{ + /** + * Non-breaking space character. + */ + private static final String NBSP = Character.toString((char) 160); + + /** + * Character class for characters that cannot be in an RSN. + */ + private static final Pattern INVALID_CHARS = Pattern.compile("[^a-zA-Z0-9_ -]"); + + private final Client client; + + /** + * The name currently being autocompleted. + */ + private String autocompleteName; + + /** + * Pattern for the name currently being autocompleted. + */ + private Pattern autocompleteNamePattern; + + @Inject + private NameAutocompleter(@Nullable Client client) + { + this.client = client; + } + + @Override + public void keyPressed(KeyEvent e) + { + + } + + @Override + public void keyReleased(KeyEvent e) + { + + } + + @Override + public void keyTyped(KeyEvent e) + { + final JTextComponent input = (JTextComponent) e.getSource(); + final String inputText = input.getText(); + + // Only autocomplete if the selection end is at the end of the text. + if (input.getSelectionEnd() != inputText.length()) + { + return; + } + + // Character to be inserted at the selection start. + final String charToInsert = Character.toString(e.getKeyChar()); + + // Don't attempt to autocomplete if the name is invalid. + // This condition is also true when the user presses a key like backspace. + if (INVALID_CHARS.matcher(charToInsert).find() + || INVALID_CHARS.matcher(inputText).find()) + { + return; + } + + // Check if we are already autocompleting. + if (autocompleteName != null && autocompleteNamePattern.matcher(inputText).matches()) + { + if (isExpectedNext(input, charToInsert)) + { + try + { + // Insert the character and move the selection. + final int insertIndex = input.getSelectionStart(); + Document doc = input.getDocument(); + doc.remove(insertIndex, 1); + doc.insertString(insertIndex, charToInsert, null); + input.select(insertIndex + 1, input.getSelectionEnd()); + } + catch (BadLocationException ex) + { + log.warn("Could not insert character.", ex); + } + + // Prevent default behavior. + e.consume(); + } + else // Character to insert does not match current autocompletion. Look for another name. + { + newAutocomplete(e); + } + } + else // Search for a name to autocomplete + { + newAutocomplete(e); + } + } + + private void newAutocomplete(KeyEvent e) + { + final JTextComponent input = (JTextComponent) e.getSource(); + final String inputText = input.getText(); + final String nameStart = inputText.substring(0, input.getSelectionStart()) + e.getKeyChar(); + + if (findAutocompleteName(nameStart)) + { + // Assert this.autocompleteName != null + final String name = this.autocompleteName; + SwingUtilities.invokeLater(() -> + { + try + { + input.getDocument().insertString( + nameStart.length(), + name.substring(nameStart.length()), + null); + input.select(nameStart.length(), name.length()); + } + catch (BadLocationException ex) + { + log.warn("Could not autocomplete name.", ex); + } + }); + } + } + + private boolean findAutocompleteName(String nameStart) + { + final Pattern pattern; + Optional autocompleteName; + + // Pattern to match names that start with nameStart. + // Allows spaces to be represented as common whitespaces, underscores, + // hyphens, or non-breaking spaces. + // Matching non-breaking spaces is necessary because the API + // returns non-breaking spaces when a name has whitespace. + pattern = Pattern.compile( + "(?i)^" + nameStart.replaceAll("[ _-]", "[ _" + NBSP + "-]") + ".+?"); + + if (client == null) + { + return false; + } + + autocompleteName = Optional.empty(); + + // TODO: Search lookup history + + Friend[] friends = client.getFriends(); + if (friends != null) + { + autocompleteName = Arrays.stream(friends) + .filter(Objects::nonNull) + .map(Friend::getName) + .filter(n -> pattern.matcher(n).matches()) + .findFirst(); + } + + // Search clan if a friend wasn't found + if (!autocompleteName.isPresent()) + { + final ClanMember[] clannies = client.getClanMembers(); + if (clannies != null) + { + autocompleteName = Arrays.stream(clannies) + .filter(Objects::nonNull) + .map(ClanMember::getUsername) + .filter(n -> pattern.matcher(n).matches()) + .findFirst(); + } + } + + // Search cached players if a clannie wasn't found. + if (!autocompleteName.isPresent()) + { + final Player[] cachedPlayers = client.getCachedPlayers(); + autocompleteName = Arrays.stream(cachedPlayers) + .filter(Objects::nonNull) + .map(Player::getName) + .filter(n -> pattern.matcher(n).matches()) + .findFirst(); + } + + if (autocompleteName.isPresent()) + { + this.autocompleteName = autocompleteName.get().replace(NBSP, " "); + this.autocompleteNamePattern = Pattern.compile( + "(?i)^" + this.autocompleteName.replaceAll("[ _-]", "[ _-]") + "$"); + } + else + { + this.autocompleteName = null; + this.autocompleteNamePattern = null; + } + + return autocompleteName.isPresent(); + } + + private boolean isExpectedNext(JTextComponent input, String nextChar) + { + String expected; + if (input.getSelectionStart() < input.getSelectionEnd()) + { + try + { + expected = input.getText(input.getSelectionStart(), 1); + } + catch (BadLocationException ex) + { + log.warn("Could not get first character from input selection.", ex); + return false; + } + } + else + { + expected = ""; + } + return nextChar.equalsIgnoreCase(expected); + } } \ No newline at end of file diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/hunter/HunterPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/hunter/HunterPlugin.java index 1d7c876386..7349352220 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/hunter/HunterPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/hunter/HunterPlugin.java @@ -1,390 +1,390 @@ -/* - * Copyright (c) 2017, Robin Weymans - * 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.hunter; - -import com.google.inject.Provides; -import java.time.Instant; -import java.util.HashMap; -import java.util.Iterator; -import java.util.Map; -import javax.inject.Inject; -import lombok.Getter; -import lombok.extern.slf4j.Slf4j; -import net.runelite.api.Client; -import net.runelite.api.GameObject; -import net.runelite.api.ObjectID; -import net.runelite.api.Player; -import net.runelite.api.Tile; -import net.runelite.api.coords.Direction; -import net.runelite.api.coords.LocalPoint; -import net.runelite.api.coords.WorldPoint; -import net.runelite.api.events.ConfigChanged; -import net.runelite.api.events.GameObjectSpawned; -import net.runelite.api.events.GameTick; -import net.runelite.client.Notifier; -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.ui.overlay.OverlayManager; - -@Slf4j -@PluginDescriptor( - name = "Hunter", - description = "Show the state of your traps", - tags = {"overlay", "skilling", "timers"} -) -public class HunterPlugin extends Plugin -{ - @Inject - private Client client; - - @Inject - private OverlayManager overlayManager; - - @Inject - private TrapOverlay overlay; - - @Inject - private Notifier notifier; - - @Inject - private HunterConfig config; - - @Getter - private final Map traps = new HashMap<>(); - - @Getter - private Instant lastActionTime = Instant.ofEpochMilli(0); - - private WorldPoint lastTickLocalPlayerLocation; - - @Provides - HunterConfig provideConfig(ConfigManager configManager) - { - return configManager.getConfig(HunterConfig.class); - } - - @Override - protected void startUp() - { - overlayManager.add(overlay); - overlay.updateConfig(); - } - - @Override - protected void shutDown() throws Exception - { - overlayManager.remove(overlay); - lastActionTime = Instant.ofEpochMilli(0); - traps.clear(); - } - - @Subscribe - public void onGameObjectSpawned(GameObjectSpawned event) - { - final GameObject gameObject = event.getGameObject(); - final WorldPoint trapLocation = gameObject.getWorldLocation(); - final HunterTrap myTrap = traps.get(trapLocation); - final Player localPlayer = client.getLocalPlayer(); - - switch (gameObject.getId()) - { - /* - * ------------------------------------------------------------------------------ - * Placing traps - * ------------------------------------------------------------------------------ - */ - case ObjectID.DEADFALL: // Deadfall trap placed - if (localPlayer.getWorldLocation().distanceTo(trapLocation) <= 2) - { - log.debug("Trap placed by \"{}\" on {}", localPlayer.getName(), trapLocation); - traps.put(trapLocation, new HunterTrap(gameObject)); - lastActionTime = Instant.now(); - } - break; - - case ObjectID.MONKEY_TRAP: // Maniacal monkey trap placed - // If player is right next to "object" trap assume that player placed the trap - if (localPlayer.getWorldLocation().distanceTo(trapLocation) <= 2) - { - log.debug("Trap placed by \"{}\" on {}", localPlayer.getName(), trapLocation); - traps.put(trapLocation, new HunterTrap(gameObject)); - lastActionTime = Instant.now(); - } - break; - - case ObjectID.MAGIC_BOX: // Imp box placed - case ObjectID.BOX_TRAP_9380: // Box trap placed - case ObjectID.BIRD_SNARE_9345: // Bird snare placed - // If the player is on that tile, assume he is the one that placed the trap - // Note that a player can move and set up a trap in the same tick, and this - // event runs after the player movement has been updated, so we need to - // compare to the trap location to the last location of the player. - if (lastTickLocalPlayerLocation != null - && trapLocation.distanceTo(lastTickLocalPlayerLocation) == 0) - { - log.debug("Trap placed by \"{}\" on {}", localPlayer.getName(), localPlayer.getWorldLocation()); - traps.put(trapLocation, new HunterTrap(gameObject)); - lastActionTime = Instant.now(); - } - break; - - case ObjectID.NET_TRAP_9343: // Net trap placed at green sallys - case ObjectID.NET_TRAP: // Net trap placed at orange sallys - case ObjectID.NET_TRAP_8992: // Net trap placed at red sallys - case ObjectID.NET_TRAP_9002: // Net trap placed at black sallys - if (lastTickLocalPlayerLocation != null - && trapLocation.distanceTo(lastTickLocalPlayerLocation) == 0) - { - // Net traps facing to the north and east must have their tile translated. - // As otherwise, the wrong tile is stored. - Direction trapOrientation = gameObject.getOrientation().getNearestDirection(); - WorldPoint translatedTrapLocation = trapLocation; - - switch (trapOrientation) - { - case NORTH: - translatedTrapLocation = trapLocation.dy(1); - break; - case EAST: - translatedTrapLocation = trapLocation.dx(1); - break; - } - - log.debug("Trap placed by \"{}\" on {}", localPlayer.getName(), translatedTrapLocation); - traps.put(translatedTrapLocation, new HunterTrap(gameObject)); - lastActionTime = Instant.now(); - } - break; - - /* - * ------------------------------------------------------------------------------ - * Catching stuff - * ------------------------------------------------------------------------------ - */ - case ObjectID.MAGIC_BOX_19226: // Imp caught - case ObjectID.SHAKING_BOX: // Black chinchompa caught - case ObjectID.SHAKING_BOX_9382: // Grey chinchompa caught - case ObjectID.SHAKING_BOX_9383: // Red chinchompa caught - case ObjectID.BOULDER_20648: // Prickly kebbit caught - case ObjectID.BOULDER_20649: // Sabre-tooth kebbit caught - case ObjectID.BOULDER_20650: // Barb-tailed kebbit caught - case ObjectID.BOULDER_20651: // Wild kebbit caught - case ObjectID.BIRD_SNARE_9373: // Crimson swift caught - case ObjectID.BIRD_SNARE_9375: // Cerulean twitch caught - case ObjectID.BIRD_SNARE_9377: // Golden warbler caught - case ObjectID.BIRD_SNARE_9379: // Copper longtail caught - case ObjectID.BIRD_SNARE_9348: // Tropical wagtail caught - case ObjectID.NET_TRAP_9004: // Green sally caught - case ObjectID.NET_TRAP_8986: // Red sally caught - case ObjectID.NET_TRAP_8734: // Orange sally caught - case ObjectID.NET_TRAP_8996: // Black sally caught - case ObjectID.LARGE_BOULDER_28830: // Maniacal monkey tail obtained - case ObjectID.LARGE_BOULDER_28831: // Maniacal monkey tail obtained - if (myTrap != null) - { - myTrap.setState(HunterTrap.State.FULL); - myTrap.resetTimer(); - lastActionTime = Instant.now(); - - if (config.maniacalMonkeyNotify() && myTrap.getObjectId() == ObjectID.MONKEY_TRAP) - { - notifier.notify("You've caught part of a monkey's tail."); - } - } - - break; - /* - * ------------------------------------------------------------------------------ - * Failed catch - * ------------------------------------------------------------------------------ - */ - case ObjectID.MAGIC_BOX_FAILED: //Empty imp box - case ObjectID.BOX_TRAP_9385: //Empty box trap - case ObjectID.BIRD_SNARE: //Empty box trap - if (myTrap != null) - { - myTrap.setState(HunterTrap.State.EMPTY); - myTrap.resetTimer(); - lastActionTime = Instant.now(); - } - - break; - /* - * ------------------------------------------------------------------------------ - * Transitions - * ------------------------------------------------------------------------------ - */ - // Imp entering box - case ObjectID.MAGIC_BOX_19225: - - // Black chin shaking box - case ObjectID.BOX_TRAP: - case ObjectID.BOX_TRAP_2026: - case ObjectID.BOX_TRAP_2028: - case ObjectID.BOX_TRAP_2029: - - // Red chin shaking box - case ObjectID.BOX_TRAP_9381: - case ObjectID.BOX_TRAP_9390: - case ObjectID.BOX_TRAP_9391: - case ObjectID.BOX_TRAP_9392: - case ObjectID.BOX_TRAP_9393: - - // Grey chin shaking box - case ObjectID.BOX_TRAP_9386: - case ObjectID.BOX_TRAP_9387: - case ObjectID.BOX_TRAP_9388: - - // Bird traps - case ObjectID.BIRD_SNARE_9346: - case ObjectID.BIRD_SNARE_9347: - case ObjectID.BIRD_SNARE_9349: - case ObjectID.BIRD_SNARE_9374: - case ObjectID.BIRD_SNARE_9376: - case ObjectID.BIRD_SNARE_9378: - - // Deadfall trap - case ObjectID.DEADFALL_19218: - case ObjectID.DEADFALL_19851: - case ObjectID.DEADFALL_20128: - case ObjectID.DEADFALL_20129: - case ObjectID.DEADFALL_20130: - case ObjectID.DEADFALL_20131: - - // Net trap - case ObjectID.NET_TRAP_9003: - case ObjectID.NET_TRAP_9005: - case ObjectID.NET_TRAP_8972: - case ObjectID.NET_TRAP_8974: - case ObjectID.NET_TRAP_8985: - case ObjectID.NET_TRAP_8987: - case ObjectID.NET_TRAP_8993: - case ObjectID.NET_TRAP_8997: - - // Maniacal monkey boulder trap - case ObjectID.MONKEY_TRAP_28828: - case ObjectID.MONKEY_TRAP_28829: - if (myTrap != null) - { - myTrap.setState(HunterTrap.State.TRANSITION); - } - break; - } - } - - /** - * Iterates over all the traps that were placed by the local player and - * checks if the trap is still there. If the trap is gone, it removes - * the trap from the local players trap collection. - */ - @Subscribe - public void onGameTick(GameTick event) - { - // Check if all traps are still there, and remove the ones that are not. - Iterator> it = traps.entrySet().iterator(); - Tile[][][] tiles = client.getScene().getTiles(); - - Instant expire = Instant.now().minus(HunterTrap.TRAP_TIME.multipliedBy(2)); - - while (it.hasNext()) - { - Map.Entry entry = it.next(); - HunterTrap trap = entry.getValue(); - WorldPoint world = entry.getKey(); - LocalPoint local = LocalPoint.fromWorld(client, world); - - // Not within the client's viewport - if (local == null) - { - // Cull very old traps - if (trap.getPlacedOn().isBefore(expire)) - { - log.debug("Trap removed from personal trap collection due to timeout, {} left", traps.size()); - it.remove(); - continue; - } - continue; - } - - Tile tile = tiles[world.getPlane()][local.getSceneX()][local.getSceneY()]; - GameObject[] objects = tile.getGameObjects(); - - boolean containsBoulder = false; - boolean containsAnything = false; - boolean containsYoungTree = false; - for (GameObject object : objects) - { - if (object != null) - { - containsAnything = true; - if (object.getId() == ObjectID.BOULDER_19215 || object.getId() == ObjectID.LARGE_BOULDER) - { - containsBoulder = true; - break; - } - - // Check for young trees (used while catching salamanders) in the tile. - // Otherwise, hunter timers will never disappear after a trap is dismantled - if (object.getId() == ObjectID.YOUNG_TREE_8732 || object.getId() == ObjectID.YOUNG_TREE_8990 || - object.getId() == ObjectID.YOUNG_TREE_9000 || object.getId() == ObjectID.YOUNG_TREE_9341) - { - containsYoungTree = true; - } - } - } - - if (!containsAnything || containsYoungTree) - { - it.remove(); - log.debug("Trap removed from personal trap collection, {} left", traps.size()); - } - else if (containsBoulder) // For traps like deadfalls. This is different because when the trap is gone, there is still a GameObject (boulder) - { - it.remove(); - log.debug("Special trap removed from personal trap collection, {} left", traps.size()); - - // Case we have notifications enabled and the action was not manual, throw notification - if (config.maniacalMonkeyNotify() && trap.getObjectId() == ObjectID.MONKEY_TRAP && - !trap.getState().equals(HunterTrap.State.FULL) && !trap.getState().equals(HunterTrap.State.OPEN)) - { - notifier.notify("The monkey escaped."); - } - } - } - - lastTickLocalPlayerLocation = client.getLocalPlayer().getWorldLocation(); - } - - @Subscribe - public void onConfigChanged(ConfigChanged event) - { - if (event.getGroup().equals("hunterplugin")) - { - overlay.updateConfig(); - } - } -} +/* + * Copyright (c) 2017, Robin Weymans + * 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.hunter; + +import com.google.inject.Provides; +import java.time.Instant; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; +import javax.inject.Inject; +import lombok.Getter; +import lombok.extern.slf4j.Slf4j; +import net.runelite.api.Client; +import net.runelite.api.GameObject; +import net.runelite.api.ObjectID; +import net.runelite.api.Player; +import net.runelite.api.Tile; +import net.runelite.api.coords.Direction; +import net.runelite.api.coords.LocalPoint; +import net.runelite.api.coords.WorldPoint; +import net.runelite.api.events.ConfigChanged; +import net.runelite.api.events.GameObjectSpawned; +import net.runelite.api.events.GameTick; +import net.runelite.client.Notifier; +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.ui.overlay.OverlayManager; + +@Slf4j +@PluginDescriptor( + name = "Hunter", + description = "Show the state of your traps", + tags = {"overlay", "skilling", "timers"} +) +public class HunterPlugin extends Plugin +{ + @Inject + private Client client; + + @Inject + private OverlayManager overlayManager; + + @Inject + private TrapOverlay overlay; + + @Inject + private Notifier notifier; + + @Inject + private HunterConfig config; + + @Getter + private final Map traps = new HashMap<>(); + + @Getter + private Instant lastActionTime = Instant.ofEpochMilli(0); + + private WorldPoint lastTickLocalPlayerLocation; + + @Provides + HunterConfig provideConfig(ConfigManager configManager) + { + return configManager.getConfig(HunterConfig.class); + } + + @Override + protected void startUp() + { + overlayManager.add(overlay); + overlay.updateConfig(); + } + + @Override + protected void shutDown() throws Exception + { + overlayManager.remove(overlay); + lastActionTime = Instant.ofEpochMilli(0); + traps.clear(); + } + + @Subscribe + public void onGameObjectSpawned(GameObjectSpawned event) + { + final GameObject gameObject = event.getGameObject(); + final WorldPoint trapLocation = gameObject.getWorldLocation(); + final HunterTrap myTrap = traps.get(trapLocation); + final Player localPlayer = client.getLocalPlayer(); + + switch (gameObject.getId()) + { + /* + * ------------------------------------------------------------------------------ + * Placing traps + * ------------------------------------------------------------------------------ + */ + case ObjectID.DEADFALL: // Deadfall trap placed + if (localPlayer.getWorldLocation().distanceTo(trapLocation) <= 2) + { + log.debug("Trap placed by \"{}\" on {}", localPlayer.getName(), trapLocation); + traps.put(trapLocation, new HunterTrap(gameObject)); + lastActionTime = Instant.now(); + } + break; + + case ObjectID.MONKEY_TRAP: // Maniacal monkey trap placed + // If player is right next to "object" trap assume that player placed the trap + if (localPlayer.getWorldLocation().distanceTo(trapLocation) <= 2) + { + log.debug("Trap placed by \"{}\" on {}", localPlayer.getName(), trapLocation); + traps.put(trapLocation, new HunterTrap(gameObject)); + lastActionTime = Instant.now(); + } + break; + + case ObjectID.MAGIC_BOX: // Imp box placed + case ObjectID.BOX_TRAP_9380: // Box trap placed + case ObjectID.BIRD_SNARE_9345: // Bird snare placed + // If the player is on that tile, assume he is the one that placed the trap + // Note that a player can move and set up a trap in the same tick, and this + // event runs after the player movement has been updated, so we need to + // compare to the trap location to the last location of the player. + if (lastTickLocalPlayerLocation != null + && trapLocation.distanceTo(lastTickLocalPlayerLocation) == 0) + { + log.debug("Trap placed by \"{}\" on {}", localPlayer.getName(), localPlayer.getWorldLocation()); + traps.put(trapLocation, new HunterTrap(gameObject)); + lastActionTime = Instant.now(); + } + break; + + case ObjectID.NET_TRAP_9343: // Net trap placed at green sallys + case ObjectID.NET_TRAP: // Net trap placed at orange sallys + case ObjectID.NET_TRAP_8992: // Net trap placed at red sallys + case ObjectID.NET_TRAP_9002: // Net trap placed at black sallys + if (lastTickLocalPlayerLocation != null + && trapLocation.distanceTo(lastTickLocalPlayerLocation) == 0) + { + // Net traps facing to the north and east must have their tile translated. + // As otherwise, the wrong tile is stored. + Direction trapOrientation = gameObject.getOrientation().getNearestDirection(); + WorldPoint translatedTrapLocation = trapLocation; + + switch (trapOrientation) + { + case NORTH: + translatedTrapLocation = trapLocation.dy(1); + break; + case EAST: + translatedTrapLocation = trapLocation.dx(1); + break; + } + + log.debug("Trap placed by \"{}\" on {}", localPlayer.getName(), translatedTrapLocation); + traps.put(translatedTrapLocation, new HunterTrap(gameObject)); + lastActionTime = Instant.now(); + } + break; + + /* + * ------------------------------------------------------------------------------ + * Catching stuff + * ------------------------------------------------------------------------------ + */ + case ObjectID.MAGIC_BOX_19226: // Imp caught + case ObjectID.SHAKING_BOX: // Black chinchompa caught + case ObjectID.SHAKING_BOX_9382: // Grey chinchompa caught + case ObjectID.SHAKING_BOX_9383: // Red chinchompa caught + case ObjectID.BOULDER_20648: // Prickly kebbit caught + case ObjectID.BOULDER_20649: // Sabre-tooth kebbit caught + case ObjectID.BOULDER_20650: // Barb-tailed kebbit caught + case ObjectID.BOULDER_20651: // Wild kebbit caught + case ObjectID.BIRD_SNARE_9373: // Crimson swift caught + case ObjectID.BIRD_SNARE_9375: // Cerulean twitch caught + case ObjectID.BIRD_SNARE_9377: // Golden warbler caught + case ObjectID.BIRD_SNARE_9379: // Copper longtail caught + case ObjectID.BIRD_SNARE_9348: // Tropical wagtail caught + case ObjectID.NET_TRAP_9004: // Green sally caught + case ObjectID.NET_TRAP_8986: // Red sally caught + case ObjectID.NET_TRAP_8734: // Orange sally caught + case ObjectID.NET_TRAP_8996: // Black sally caught + case ObjectID.LARGE_BOULDER_28830: // Maniacal monkey tail obtained + case ObjectID.LARGE_BOULDER_28831: // Maniacal monkey tail obtained + if (myTrap != null) + { + myTrap.setState(HunterTrap.State.FULL); + myTrap.resetTimer(); + lastActionTime = Instant.now(); + + if (config.maniacalMonkeyNotify() && myTrap.getObjectId() == ObjectID.MONKEY_TRAP) + { + notifier.notify("You've caught part of a monkey's tail."); + } + } + + break; + /* + * ------------------------------------------------------------------------------ + * Failed catch + * ------------------------------------------------------------------------------ + */ + case ObjectID.MAGIC_BOX_FAILED: //Empty imp box + case ObjectID.BOX_TRAP_9385: //Empty box trap + case ObjectID.BIRD_SNARE: //Empty box trap + if (myTrap != null) + { + myTrap.setState(HunterTrap.State.EMPTY); + myTrap.resetTimer(); + lastActionTime = Instant.now(); + } + + break; + /* + * ------------------------------------------------------------------------------ + * Transitions + * ------------------------------------------------------------------------------ + */ + // Imp entering box + case ObjectID.MAGIC_BOX_19225: + + // Black chin shaking box + case ObjectID.BOX_TRAP: + case ObjectID.BOX_TRAP_2026: + case ObjectID.BOX_TRAP_2028: + case ObjectID.BOX_TRAP_2029: + + // Red chin shaking box + case ObjectID.BOX_TRAP_9381: + case ObjectID.BOX_TRAP_9390: + case ObjectID.BOX_TRAP_9391: + case ObjectID.BOX_TRAP_9392: + case ObjectID.BOX_TRAP_9393: + + // Grey chin shaking box + case ObjectID.BOX_TRAP_9386: + case ObjectID.BOX_TRAP_9387: + case ObjectID.BOX_TRAP_9388: + + // Bird traps + case ObjectID.BIRD_SNARE_9346: + case ObjectID.BIRD_SNARE_9347: + case ObjectID.BIRD_SNARE_9349: + case ObjectID.BIRD_SNARE_9374: + case ObjectID.BIRD_SNARE_9376: + case ObjectID.BIRD_SNARE_9378: + + // Deadfall trap + case ObjectID.DEADFALL_19218: + case ObjectID.DEADFALL_19851: + case ObjectID.DEADFALL_20128: + case ObjectID.DEADFALL_20129: + case ObjectID.DEADFALL_20130: + case ObjectID.DEADFALL_20131: + + // Net trap + case ObjectID.NET_TRAP_9003: + case ObjectID.NET_TRAP_9005: + case ObjectID.NET_TRAP_8972: + case ObjectID.NET_TRAP_8974: + case ObjectID.NET_TRAP_8985: + case ObjectID.NET_TRAP_8987: + case ObjectID.NET_TRAP_8993: + case ObjectID.NET_TRAP_8997: + + // Maniacal monkey boulder trap + case ObjectID.MONKEY_TRAP_28828: + case ObjectID.MONKEY_TRAP_28829: + if (myTrap != null) + { + myTrap.setState(HunterTrap.State.TRANSITION); + } + break; + } + } + + /** + * Iterates over all the traps that were placed by the local player and + * checks if the trap is still there. If the trap is gone, it removes + * the trap from the local players trap collection. + */ + @Subscribe + public void onGameTick(GameTick event) + { + // Check if all traps are still there, and remove the ones that are not. + Iterator> it = traps.entrySet().iterator(); + Tile[][][] tiles = client.getScene().getTiles(); + + Instant expire = Instant.now().minus(HunterTrap.TRAP_TIME.multipliedBy(2)); + + while (it.hasNext()) + { + Map.Entry entry = it.next(); + HunterTrap trap = entry.getValue(); + WorldPoint world = entry.getKey(); + LocalPoint local = LocalPoint.fromWorld(client, world); + + // Not within the client's viewport + if (local == null) + { + // Cull very old traps + if (trap.getPlacedOn().isBefore(expire)) + { + log.debug("Trap removed from personal trap collection due to timeout, {} left", traps.size()); + it.remove(); + continue; + } + continue; + } + + Tile tile = tiles[world.getPlane()][local.getSceneX()][local.getSceneY()]; + GameObject[] objects = tile.getGameObjects(); + + boolean containsBoulder = false; + boolean containsAnything = false; + boolean containsYoungTree = false; + for (GameObject object : objects) + { + if (object != null) + { + containsAnything = true; + if (object.getId() == ObjectID.BOULDER_19215 || object.getId() == ObjectID.LARGE_BOULDER) + { + containsBoulder = true; + break; + } + + // Check for young trees (used while catching salamanders) in the tile. + // Otherwise, hunter timers will never disappear after a trap is dismantled + if (object.getId() == ObjectID.YOUNG_TREE_8732 || object.getId() == ObjectID.YOUNG_TREE_8990 || + object.getId() == ObjectID.YOUNG_TREE_9000 || object.getId() == ObjectID.YOUNG_TREE_9341) + { + containsYoungTree = true; + } + } + } + + if (!containsAnything || containsYoungTree) + { + it.remove(); + log.debug("Trap removed from personal trap collection, {} left", traps.size()); + } + else if (containsBoulder) // For traps like deadfalls. This is different because when the trap is gone, there is still a GameObject (boulder) + { + it.remove(); + log.debug("Special trap removed from personal trap collection, {} left", traps.size()); + + // Case we have notifications enabled and the action was not manual, throw notification + if (config.maniacalMonkeyNotify() && trap.getObjectId() == ObjectID.MONKEY_TRAP && + !trap.getState().equals(HunterTrap.State.FULL) && !trap.getState().equals(HunterTrap.State.OPEN)) + { + notifier.notify("The monkey escaped."); + } + } + } + + lastTickLocalPlayerLocation = client.getLocalPlayer().getWorldLocation(); + } + + @Subscribe + public void onConfigChanged(ConfigChanged event) + { + if (event.getGroup().equals("hunterplugin")) + { + overlay.updateConfig(); + } + } +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/hunter/TrapOverlay.java b/runelite-client/src/main/java/net/runelite/client/plugins/hunter/TrapOverlay.java index 1e0f23b358..ed9038693d 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/hunter/TrapOverlay.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/hunter/TrapOverlay.java @@ -1,189 +1,189 @@ -/* - * Copyright (c) 2017, Robin Weymans - * 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.hunter; - -import java.awt.Color; -import java.awt.Dimension; -import java.awt.Graphics2D; -import java.util.Map; -import javax.inject.Inject; -import net.runelite.api.Client; -import net.runelite.api.Perspective; -import net.runelite.api.coords.LocalPoint; -import net.runelite.api.coords.WorldPoint; -import net.runelite.client.ui.overlay.Overlay; -import net.runelite.client.ui.overlay.OverlayLayer; -import net.runelite.client.ui.overlay.OverlayPosition; -import net.runelite.client.ui.overlay.components.ProgressPieComponent; - -/** - * Represents the overlay that shows timers on traps that are placed by the - * player. - */ -public class TrapOverlay extends Overlay -{ - /** - * The timer is low when only 25% is left. - */ - private static final double TIMER_LOW = 0.25; // When the timer is under a quarter left, if turns red. - - private final Client client; - private final HunterPlugin plugin; - private final HunterConfig config; - - private Color colorOpen, colorOpenBorder; - private Color colorEmpty, colorEmptyBorder; - private Color colorFull, colorFullBorder; - private Color colorTrans, colorTransBorder; - - @Inject - TrapOverlay(Client client, HunterPlugin plugin, HunterConfig config) - { - setPosition(OverlayPosition.DYNAMIC); - setLayer(OverlayLayer.ABOVE_SCENE); - this.plugin = plugin; - this.config = config; - this.client = client; - } - - @Override - public Dimension render(Graphics2D graphics) - { - drawTraps(graphics); - return null; - } - - /** - * Updates the timer colors. - */ - public void updateConfig() - { - colorEmptyBorder = config.getEmptyTrapColor(); - colorEmpty = new Color(colorEmptyBorder.getRed(), colorEmptyBorder.getGreen(), colorEmptyBorder.getBlue(), 100); - colorFullBorder = config.getFullTrapColor(); - colorFull = new Color(colorFullBorder.getRed(), colorFullBorder.getGreen(), colorFullBorder.getBlue(), 100); - colorOpenBorder = config.getOpenTrapColor(); - colorOpen = new Color(colorOpenBorder.getRed(), colorOpenBorder.getGreen(), colorOpenBorder.getBlue(), 100); - colorTransBorder = config.getTransTrapColor(); - colorTrans = new Color(colorTransBorder.getRed(), colorTransBorder.getGreen(), colorTransBorder.getBlue(), 100); - } - - /** - * Iterates over all the traps that were placed by the local player, and - * draws a circle or a timer on the trap, depending on the trap state. - * - * @param graphics - */ - private void drawTraps(Graphics2D graphics) - { - for (Map.Entry entry : plugin.getTraps().entrySet()) - { - HunterTrap trap = entry.getValue(); - - switch (trap.getState()) - { - case OPEN: - drawTimerOnTrap(graphics, trap, colorOpen, colorOpenBorder, colorEmpty, colorOpenBorder); - break; - case EMPTY: - drawTimerOnTrap(graphics, trap, colorEmpty, colorEmptyBorder, colorEmpty, colorEmptyBorder); - break; - case FULL: - drawTimerOnTrap(graphics, trap, colorFull, colorFullBorder, colorFull, colorFullBorder); - break; - case TRANSITION: - drawCircleOnTrap(graphics, trap, colorTrans, colorTransBorder); - break; - } - } - } - - /** - * Draws a timer on a given trap. - * - * @param graphics - * @param trap The trap on which the timer needs to be drawn - * @param fill The fill color of the timer - * @param border The border color of the timer - * @param fillTimeLow The fill color of the timer when it is low - * @param borderTimeLow The border color of the timer when it is low - */ - private void drawTimerOnTrap(Graphics2D graphics, HunterTrap trap, Color fill, Color border, Color fillTimeLow, Color borderTimeLow) - { - if (trap.getWorldLocation().getPlane() != client.getPlane()) - { - return; - } - LocalPoint localLoc = LocalPoint.fromWorld(client, trap.getWorldLocation()); - if (localLoc == null) - { - return; - } - net.runelite.api.Point loc = Perspective.localToCanvas(client, localLoc, client.getPlane()); - - if (loc == null) - { - return; - } - - double timeLeft = 1 - trap.getTrapTimeRelative(); - - ProgressPieComponent pie = new ProgressPieComponent(); - pie.setFill(timeLeft > TIMER_LOW ? fill : fillTimeLow); - pie.setBorderColor(timeLeft > TIMER_LOW ? border : borderTimeLow); - pie.setPosition(loc); - pie.setProgress(timeLeft); - pie.render(graphics); - } - - /** - * Draws a timer on a given trap. - * - * @param graphics - * @param trap The trap on which the timer needs to be drawn - * @param fill The fill color of the timer - * @param border The border color of the timer - */ - private void drawCircleOnTrap(Graphics2D graphics, HunterTrap trap, Color fill, Color border) - { - if (trap.getWorldLocation().getPlane() != client.getPlane()) - { - return; - } - LocalPoint localLoc = LocalPoint.fromWorld(client, trap.getWorldLocation()); - if (localLoc == null) - { - return; - } - net.runelite.api.Point loc = Perspective.localToCanvas(client, localLoc, client.getPlane()); - - ProgressPieComponent pie = new ProgressPieComponent(); - pie.setFill(fill); - pie.setBorderColor(border); - pie.setPosition(loc); - pie.setProgress(1); - pie.render(graphics); - } -} +/* + * Copyright (c) 2017, Robin Weymans + * 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.hunter; + +import java.awt.Color; +import java.awt.Dimension; +import java.awt.Graphics2D; +import java.util.Map; +import javax.inject.Inject; +import net.runelite.api.Client; +import net.runelite.api.Perspective; +import net.runelite.api.coords.LocalPoint; +import net.runelite.api.coords.WorldPoint; +import net.runelite.client.ui.overlay.Overlay; +import net.runelite.client.ui.overlay.OverlayLayer; +import net.runelite.client.ui.overlay.OverlayPosition; +import net.runelite.client.ui.overlay.components.ProgressPieComponent; + +/** + * Represents the overlay that shows timers on traps that are placed by the + * player. + */ +public class TrapOverlay extends Overlay +{ + /** + * The timer is low when only 25% is left. + */ + private static final double TIMER_LOW = 0.25; // When the timer is under a quarter left, if turns red. + + private final Client client; + private final HunterPlugin plugin; + private final HunterConfig config; + + private Color colorOpen, colorOpenBorder; + private Color colorEmpty, colorEmptyBorder; + private Color colorFull, colorFullBorder; + private Color colorTrans, colorTransBorder; + + @Inject + TrapOverlay(Client client, HunterPlugin plugin, HunterConfig config) + { + setPosition(OverlayPosition.DYNAMIC); + setLayer(OverlayLayer.ABOVE_SCENE); + this.plugin = plugin; + this.config = config; + this.client = client; + } + + @Override + public Dimension render(Graphics2D graphics) + { + drawTraps(graphics); + return null; + } + + /** + * Updates the timer colors. + */ + public void updateConfig() + { + colorEmptyBorder = config.getEmptyTrapColor(); + colorEmpty = new Color(colorEmptyBorder.getRed(), colorEmptyBorder.getGreen(), colorEmptyBorder.getBlue(), 100); + colorFullBorder = config.getFullTrapColor(); + colorFull = new Color(colorFullBorder.getRed(), colorFullBorder.getGreen(), colorFullBorder.getBlue(), 100); + colorOpenBorder = config.getOpenTrapColor(); + colorOpen = new Color(colorOpenBorder.getRed(), colorOpenBorder.getGreen(), colorOpenBorder.getBlue(), 100); + colorTransBorder = config.getTransTrapColor(); + colorTrans = new Color(colorTransBorder.getRed(), colorTransBorder.getGreen(), colorTransBorder.getBlue(), 100); + } + + /** + * Iterates over all the traps that were placed by the local player, and + * draws a circle or a timer on the trap, depending on the trap state. + * + * @param graphics + */ + private void drawTraps(Graphics2D graphics) + { + for (Map.Entry entry : plugin.getTraps().entrySet()) + { + HunterTrap trap = entry.getValue(); + + switch (trap.getState()) + { + case OPEN: + drawTimerOnTrap(graphics, trap, colorOpen, colorOpenBorder, colorEmpty, colorOpenBorder); + break; + case EMPTY: + drawTimerOnTrap(graphics, trap, colorEmpty, colorEmptyBorder, colorEmpty, colorEmptyBorder); + break; + case FULL: + drawTimerOnTrap(graphics, trap, colorFull, colorFullBorder, colorFull, colorFullBorder); + break; + case TRANSITION: + drawCircleOnTrap(graphics, trap, colorTrans, colorTransBorder); + break; + } + } + } + + /** + * Draws a timer on a given trap. + * + * @param graphics + * @param trap The trap on which the timer needs to be drawn + * @param fill The fill color of the timer + * @param border The border color of the timer + * @param fillTimeLow The fill color of the timer when it is low + * @param borderTimeLow The border color of the timer when it is low + */ + private void drawTimerOnTrap(Graphics2D graphics, HunterTrap trap, Color fill, Color border, Color fillTimeLow, Color borderTimeLow) + { + if (trap.getWorldLocation().getPlane() != client.getPlane()) + { + return; + } + LocalPoint localLoc = LocalPoint.fromWorld(client, trap.getWorldLocation()); + if (localLoc == null) + { + return; + } + net.runelite.api.Point loc = Perspective.localToCanvas(client, localLoc, client.getPlane()); + + if (loc == null) + { + return; + } + + double timeLeft = 1 - trap.getTrapTimeRelative(); + + ProgressPieComponent pie = new ProgressPieComponent(); + pie.setFill(timeLeft > TIMER_LOW ? fill : fillTimeLow); + pie.setBorderColor(timeLeft > TIMER_LOW ? border : borderTimeLow); + pie.setPosition(loc); + pie.setProgress(timeLeft); + pie.render(graphics); + } + + /** + * Draws a timer on a given trap. + * + * @param graphics + * @param trap The trap on which the timer needs to be drawn + * @param fill The fill color of the timer + * @param border The border color of the timer + */ + private void drawCircleOnTrap(Graphics2D graphics, HunterTrap trap, Color fill, Color border) + { + if (trap.getWorldLocation().getPlane() != client.getPlane()) + { + return; + } + LocalPoint localLoc = LocalPoint.fromWorld(client, trap.getWorldLocation()); + if (localLoc == null) + { + return; + } + net.runelite.api.Point loc = Perspective.localToCanvas(client, localLoc, client.getPlane()); + + ProgressPieComponent pie = new ProgressPieComponent(); + pie.setFill(fill); + pie.setBorderColor(border); + pie.setPosition(loc); + pie.setProgress(1); + pie.render(graphics); + } +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/hydra/HydraPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/hydra/HydraPlugin.java index 49c94a2fa1..d290452237 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/hydra/HydraPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/hydra/HydraPlugin.java @@ -36,7 +36,6 @@ import net.runelite.api.events.NpcDespawned; import net.runelite.api.events.NpcSpawned; import net.runelite.client.config.ConfigManager; import net.runelite.client.eventbus.Subscribe; -import net.runelite.client.game.SpriteManager; import net.runelite.client.plugins.Plugin; import net.runelite.client.plugins.PluginDescriptor; import net.runelite.client.plugins.PluginType; diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/idlenotifier/IdleNotifierPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/idlenotifier/IdleNotifierPlugin.java index 38b56f8505..accdc1d1d2 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/idlenotifier/IdleNotifierPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/idlenotifier/IdleNotifierPlugin.java @@ -26,8 +26,7 @@ package net.runelite.client.plugins.idlenotifier; import com.google.inject.Provides; - -import java.awt.*; +import java.awt.TrayIcon; import java.time.Duration; import java.time.Instant; import java.util.Arrays; @@ -36,7 +35,93 @@ import java.util.List; import javax.inject.Inject; import net.runelite.api.Actor; import net.runelite.api.AnimationID; -import static net.runelite.api.AnimationID.*; +import static net.runelite.api.AnimationID.COOKING_FIRE; +import static net.runelite.api.AnimationID.COOKING_RANGE; +import static net.runelite.api.AnimationID.COOKING_WINE; +import static net.runelite.api.AnimationID.CRAFTING_BATTLESTAVES; +import static net.runelite.api.AnimationID.CRAFTING_GLASSBLOWING; +import static net.runelite.api.AnimationID.CRAFTING_LEATHER; +import static net.runelite.api.AnimationID.CRAFTING_POTTERS_WHEEL; +import static net.runelite.api.AnimationID.CRAFTING_POTTERY_OVEN; +import static net.runelite.api.AnimationID.CRAFTING_SPINNING; +import static net.runelite.api.AnimationID.DENSE_ESSENCE_CHIPPING; +import static net.runelite.api.AnimationID.DENSE_ESSENCE_CHISELING; +import static net.runelite.api.AnimationID.FARMING_MIX_ULTRACOMPOST; +import static net.runelite.api.AnimationID.FISHING_CRUSHING_INFERNAL_EELS; +import static net.runelite.api.AnimationID.FISHING_CUTTING_SACRED_EELS; +import static net.runelite.api.AnimationID.FLETCHING_BOW_CUTTING; +import static net.runelite.api.AnimationID.FLETCHING_STRING_MAGIC_LONGBOW; +import static net.runelite.api.AnimationID.FLETCHING_STRING_MAGIC_SHORTBOW; +import static net.runelite.api.AnimationID.FLETCHING_STRING_MAPLE_LONGBOW; +import static net.runelite.api.AnimationID.FLETCHING_STRING_MAPLE_SHORTBOW; +import static net.runelite.api.AnimationID.FLETCHING_STRING_NORMAL_LONGBOW; +import static net.runelite.api.AnimationID.FLETCHING_STRING_NORMAL_SHORTBOW; +import static net.runelite.api.AnimationID.FLETCHING_STRING_OAK_LONGBOW; +import static net.runelite.api.AnimationID.FLETCHING_STRING_OAK_SHORTBOW; +import static net.runelite.api.AnimationID.FLETCHING_STRING_WILLOW_LONGBOW; +import static net.runelite.api.AnimationID.FLETCHING_STRING_WILLOW_SHORTBOW; +import static net.runelite.api.AnimationID.FLETCHING_STRING_YEW_LONGBOW; +import static net.runelite.api.AnimationID.FLETCHING_STRING_YEW_SHORTBOW; +import static net.runelite.api.AnimationID.GEM_CUTTING_AMETHYST; +import static net.runelite.api.AnimationID.GEM_CUTTING_DIAMOND; +import static net.runelite.api.AnimationID.GEM_CUTTING_EMERALD; +import static net.runelite.api.AnimationID.GEM_CUTTING_JADE; +import static net.runelite.api.AnimationID.GEM_CUTTING_OPAL; +import static net.runelite.api.AnimationID.GEM_CUTTING_REDTOPAZ; +import static net.runelite.api.AnimationID.GEM_CUTTING_RUBY; +import static net.runelite.api.AnimationID.GEM_CUTTING_SAPPHIRE; +import static net.runelite.api.AnimationID.HERBLORE_MAKE_TAR; +import static net.runelite.api.AnimationID.HERBLORE_PESTLE_AND_MORTAR; +import static net.runelite.api.AnimationID.HERBLORE_POTIONMAKING; +import static net.runelite.api.AnimationID.HOME_MAKE_TABLET; +import static net.runelite.api.AnimationID.IDLE; +import static net.runelite.api.AnimationID.MAGIC_CHARGING_ORBS; +import static net.runelite.api.AnimationID.MAGIC_ENCHANTING_AMULET_1; +import static net.runelite.api.AnimationID.MAGIC_ENCHANTING_AMULET_2; +import static net.runelite.api.AnimationID.MAGIC_ENCHANTING_AMULET_3; +import static net.runelite.api.AnimationID.MAGIC_ENCHANTING_JEWELRY; +import static net.runelite.api.AnimationID.MAGIC_LUNAR_PLANK_MAKE; +import static net.runelite.api.AnimationID.MAGIC_LUNAR_SHARED; +import static net.runelite.api.AnimationID.MAGIC_LUNAR_STRING_JEWELRY; +import static net.runelite.api.AnimationID.MAGIC_MAKE_TABLET; +import static net.runelite.api.AnimationID.MINING_3A_PICKAXE; +import static net.runelite.api.AnimationID.MINING_ADAMANT_PICKAXE; +import static net.runelite.api.AnimationID.MINING_BLACK_PICKAXE; +import static net.runelite.api.AnimationID.MINING_BRONZE_PICKAXE; +import static net.runelite.api.AnimationID.MINING_DRAGON_PICKAXE; +import static net.runelite.api.AnimationID.MINING_DRAGON_PICKAXE_ORN; +import static net.runelite.api.AnimationID.MINING_INFERNAL_PICKAXE; +import static net.runelite.api.AnimationID.MINING_IRON_PICKAXE; +import static net.runelite.api.AnimationID.MINING_MITHRIL_PICKAXE; +import static net.runelite.api.AnimationID.MINING_MOTHERLODE_3A; +import static net.runelite.api.AnimationID.MINING_MOTHERLODE_ADAMANT; +import static net.runelite.api.AnimationID.MINING_MOTHERLODE_BLACK; +import static net.runelite.api.AnimationID.MINING_MOTHERLODE_BRONZE; +import static net.runelite.api.AnimationID.MINING_MOTHERLODE_DRAGON; +import static net.runelite.api.AnimationID.MINING_MOTHERLODE_DRAGON_ORN; +import static net.runelite.api.AnimationID.MINING_MOTHERLODE_INFERNAL; +import static net.runelite.api.AnimationID.MINING_MOTHERLODE_IRON; +import static net.runelite.api.AnimationID.MINING_MOTHERLODE_MITHRIL; +import static net.runelite.api.AnimationID.MINING_MOTHERLODE_RUNE; +import static net.runelite.api.AnimationID.MINING_MOTHERLODE_STEEL; +import static net.runelite.api.AnimationID.MINING_RUNE_PICKAXE; +import static net.runelite.api.AnimationID.MINING_STEEL_PICKAXE; +import static net.runelite.api.AnimationID.PISCARILIUS_CRANE_REPAIR; +import static net.runelite.api.AnimationID.SAND_COLLECTION; +import static net.runelite.api.AnimationID.SMITHING_ANVIL; +import static net.runelite.api.AnimationID.SMITHING_CANNONBALL; +import static net.runelite.api.AnimationID.SMITHING_SMELTING; +import static net.runelite.api.AnimationID.USING_GILDED_ALTAR; +import static net.runelite.api.AnimationID.WOODCUTTING_3A_AXE; +import static net.runelite.api.AnimationID.WOODCUTTING_ADAMANT; +import static net.runelite.api.AnimationID.WOODCUTTING_BLACK; +import static net.runelite.api.AnimationID.WOODCUTTING_BRONZE; +import static net.runelite.api.AnimationID.WOODCUTTING_DRAGON; +import static net.runelite.api.AnimationID.WOODCUTTING_INFERNAL; +import static net.runelite.api.AnimationID.WOODCUTTING_IRON; +import static net.runelite.api.AnimationID.WOODCUTTING_MITHRIL; +import static net.runelite.api.AnimationID.WOODCUTTING_RUNE; +import static net.runelite.api.AnimationID.WOODCUTTING_STEEL; import net.runelite.api.Client; import net.runelite.api.Constants; import net.runelite.api.GameState; @@ -143,11 +228,11 @@ public class IdleNotifierPlugin extends Plugin case WOODCUTTING_DRAGON: case WOODCUTTING_INFERNAL: case WOODCUTTING_3A_AXE: - /* Cooking(Fire, Range) */ + /* Cooking(Fire, Range) */ case COOKING_FIRE: case COOKING_RANGE: case COOKING_WINE: - /* Crafting(Gem Cutting, Glassblowing, Spinning, Battlestaves, Pottery) */ + /* Crafting(Gem Cutting, Glassblowing, Spinning, Battlestaves, Pottery) */ case GEM_CUTTING_OPAL: case GEM_CUTTING_JADE: case GEM_CUTTING_REDTOPAZ: @@ -162,7 +247,7 @@ public class IdleNotifierPlugin extends Plugin case CRAFTING_LEATHER: case CRAFTING_POTTERS_WHEEL: case CRAFTING_POTTERY_OVEN: - /* Fletching(Cutting, Stringing) */ + /* Fletching(Cutting, Stringing) */ case FLETCHING_BOW_CUTTING: case FLETCHING_STRING_NORMAL_SHORTBOW: case FLETCHING_STRING_OAK_SHORTBOW: @@ -176,14 +261,14 @@ public class IdleNotifierPlugin extends Plugin case FLETCHING_STRING_MAPLE_LONGBOW: case FLETCHING_STRING_YEW_LONGBOW: case FLETCHING_STRING_MAGIC_LONGBOW: - /* Smithing(Anvil, Furnace, Cannonballs */ + /* Smithing(Anvil, Furnace, Cannonballs */ case SMITHING_ANVIL: case SMITHING_SMELTING: case SMITHING_CANNONBALL: - /* Fishing */ + /* Fishing */ case FISHING_CRUSHING_INFERNAL_EELS: case FISHING_CUTTING_SACRED_EELS: - /* Mining(Normal) */ + /* Mining(Normal) */ case MINING_BRONZE_PICKAXE: case MINING_IRON_PICKAXE: case MINING_STEEL_PICKAXE: @@ -197,7 +282,7 @@ public class IdleNotifierPlugin extends Plugin case MINING_3A_PICKAXE: case DENSE_ESSENCE_CHIPPING: case DENSE_ESSENCE_CHISELING: - /* Mining(Motherlode) */ + /* Mining(Motherlode) */ case MINING_MOTHERLODE_BRONZE: case MINING_MOTHERLODE_IRON: case MINING_MOTHERLODE_STEEL: @@ -209,11 +294,11 @@ public class IdleNotifierPlugin extends Plugin case MINING_MOTHERLODE_DRAGON_ORN: case MINING_MOTHERLODE_INFERNAL: case MINING_MOTHERLODE_3A: - /* Herblore */ + /* Herblore */ case HERBLORE_PESTLE_AND_MORTAR: case HERBLORE_POTIONMAKING: case HERBLORE_MAKE_TAR: - /* Magic */ + /* Magic */ case MAGIC_CHARGING_ORBS: case MAGIC_LUNAR_PLANK_MAKE: case MAGIC_LUNAR_STRING_JEWELRY: @@ -222,11 +307,11 @@ public class IdleNotifierPlugin extends Plugin case MAGIC_ENCHANTING_AMULET_1: case MAGIC_ENCHANTING_AMULET_2: case MAGIC_ENCHANTING_AMULET_3: - /* Prayer */ + /* Prayer */ case USING_GILDED_ALTAR: - /* Farming */ + /* Farming */ case FARMING_MIX_ULTRACOMPOST: - /* Misc */ + /* Misc */ case PISCARILIUS_CRANE_REPAIR: case HOME_MAKE_TABLET: case SAND_COLLECTION: diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/implings/ImplingsConfig.java b/runelite-client/src/main/java/net/runelite/client/plugins/implings/ImplingsConfig.java index f2c8352680..386284a874 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/implings/ImplingsConfig.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/implings/ImplingsConfig.java @@ -30,7 +30,6 @@ import net.runelite.client.config.ConfigGroup; import net.runelite.client.config.ConfigItem; /** - * * @author robin */ @ConfigGroup("implings") @@ -312,10 +311,10 @@ public interface ImplingsConfig extends Config } @ConfigItem( - position = 26, - keyName = "spawnColorDynamic", - name = "Impling dynamic spawn color", - description = "Text color for dynamic impling spawns in Puro Puro" + position = 26, + keyName = "spawnColorDynamic", + name = "Impling dynamic spawn color", + description = "Text color for dynamic impling spawns in Puro Puro" ) default Color getDynamicSpawnColor() { diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/implings/ImplingsOverlay.java b/runelite-client/src/main/java/net/runelite/client/plugins/implings/ImplingsOverlay.java index aaba9e0851..27df5aef14 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/implings/ImplingsOverlay.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/implings/ImplingsOverlay.java @@ -35,8 +35,8 @@ import net.runelite.api.Actor; import net.runelite.api.Client; import net.runelite.api.NPC; import net.runelite.api.NPCComposition; -import net.runelite.api.Point; import net.runelite.api.Perspective; +import net.runelite.api.Point; import net.runelite.api.coords.LocalPoint; import net.runelite.api.coords.WorldPoint; import net.runelite.client.ui.overlay.Overlay; @@ -100,7 +100,7 @@ public class ImplingsOverlay extends Overlay //Draw dynamic spawns Map dynamicSpawns = plugin.getDynamicSpawns(); - for (Map.Entry dynamicSpawn : dynamicSpawns.entrySet()) + for (Map.Entry dynamicSpawn : dynamicSpawns.entrySet()) { drawDynamicSpawn(graphics, dynamicSpawn.getKey(), dynamicSpawn.getValue(), config.getDynamicSpawnColor()); diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/info/InfoPanel.java b/runelite-client/src/main/java/net/runelite/client/plugins/info/InfoPanel.java index a697f332d2..d9d93d8f23 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/info/InfoPanel.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/info/InfoPanel.java @@ -1,312 +1,311 @@ -/* - * Copyright (c) 2018 Abex - * Copyright (c) 2018, Psikoi - * 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.info; - -import com.google.common.base.MoreObjects; -import com.google.inject.Inject; -import java.awt.BorderLayout; -import java.awt.Color; -import java.awt.Cursor; -import java.awt.Font; -import java.awt.GridLayout; -import java.awt.event.MouseAdapter; -import java.awt.event.MouseEvent; -import java.util.concurrent.ScheduledExecutorService; -import javax.annotation.Nullable; -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.client.RuneLite; -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; -import net.runelite.client.ui.FontManager; -import net.runelite.client.ui.PluginPanel; -import net.runelite.client.util.ImageUtil; -import net.runelite.client.util.LinkBrowser; - -@Singleton -public class InfoPanel extends PluginPanel -{ - private static final String RUNELITE_LOGIN = "https://runelite_login/"; - - private static final ImageIcon ARROW_RIGHT_ICON; - private static final ImageIcon GITHUB_ICON; - 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 - private Client client; - - @Inject - private RuneLiteProperties runeLiteProperties; - - @Inject - private EventBus eventBus; - - @Inject - private SessionManager sessionManager; - - @Inject - private ScheduledExecutorService executor; - - @Inject - private ConfigManager configManager; - - static - { - ARROW_RIGHT_ICON = new ImageIcon(ImageUtil.getResourceStreamFromClass(InfoPanel.class, "/util/arrow_right.png")); - GITHUB_ICON = new ImageIcon(ImageUtil.getResourceStreamFromClass(InfoPanel.class, "github_icon.png")); - 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() - { - setLayout(new BorderLayout()); - setBackground(ColorScheme.DARK_GRAY_COLOR); - setBorder(new EmptyBorder(10, 10, 10, 10)); - - JPanel versionPanel = new JPanel(); - versionPanel.setBackground(ColorScheme.DARKER_GRAY_COLOR); - versionPanel.setBorder(new EmptyBorder(10, 10, 10, 10)); - versionPanel.setLayout(new GridLayout(0, 1)); - - final Font smallFont = FontManager.getRunescapeSmallFont(); - - JLabel version = new JLabel(htmlLabel("RuneLite version: ", runeLiteProperties.getVersion())); - version.setFont(smallFont); - - JLabel revision = new JLabel(); - revision.setFont(smallFont); - - String engineVer = "Unknown"; - if (client != null) - { - engineVer = String.format("Rev %d", client.getRevision()); - } - - revision.setText(htmlLabel("Oldschool revision: ", engineVer)); - - JLabel launcher = new JLabel(htmlLabel("Launcher version: ", MoreObjects - .firstNonNull(RuneLiteProperties.getLauncherVersion(), "Unknown"))); - launcher.setFont(smallFont); - - loggedLabel.setForeground(ColorScheme.LIGHT_GRAY_COLOR); - loggedLabel.setFont(smallFont); - - emailLabel.setForeground(Color.WHITE); - emailLabel.setFont(smallFont); - emailLabel.enableAutoLinkHandler(false); - emailLabel.addHyperlinkListener(e -> - { - if (HyperlinkEvent.EventType.ACTIVATED.equals(e.getEventType()) && e.getURL() != null) - { - if (e.getURL().toString().equals(RUNELITE_LOGIN)) - { - executor.execute(sessionManager::login); - } - } - }); - - versionPanel.add(version); - versionPanel.add(revision); - versionPanel.add(launcher); - versionPanel.add(Box.createGlue()); - versionPanel.add(loggedLabel); - versionPanel.add(emailLabel); - - actionsContainer = new JPanel(); - actionsContainer.setBorder(new EmptyBorder(10, 0, 0, 0)); - 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, "License info", "for distribution", "https://github.com/runelite-extended/runelite/blob/master/LICENSE")); - actionsContainer.add(buildLinkPanel(DISCORD_ICON, "Talk to us on our", "discord server", "https://discord.gg/s2fzu5U")); - actionsContainer.add(buildLinkPanel(PATREON_ICON, "Patreon to support", "the RuneLite devs", runeLiteProperties.getPatreonLink())); -/* actionsContainer.add(buildLinkPanel(WIKI_ICON, "Information about", "RuneLite and plugins", runeLiteProperties.getWikiLink()));*/ - - add(versionPanel, BorderLayout.NORTH); - add(actionsContainer, BorderLayout.CENTER); - - updateLoggedIn(); - eventBus.register(this); - } - - /** - * 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); - container.setLayout(new BorderLayout()); - container.setBorder(new EmptyBorder(10, 10, 10, 10)); - - final Color hoverColor = ColorScheme.DARKER_GRAY_HOVER_COLOR; - final Color pressedColor = ColorScheme.DARKER_GRAY_COLOR.brighter(); - - JLabel iconLabel = new JLabel(icon); - container.add(iconLabel, BorderLayout.WEST); - - JPanel textContainer = new JPanel(); - textContainer.setBackground(ColorScheme.DARKER_GRAY_COLOR); - textContainer.setLayout(new GridLayout(2, 1)); - textContainer.setBorder(new EmptyBorder(5, 10, 5, 10)); - - container.addMouseListener(new MouseAdapter() - { - @Override - public void mousePressed(MouseEvent mouseEvent) - { - container.setBackground(pressedColor); - textContainer.setBackground(pressedColor); - } - - @Override - public void mouseReleased(MouseEvent e) - { - callback.run(); - container.setBackground(hoverColor); - textContainer.setBackground(hoverColor); - } - - @Override - public void mouseEntered(MouseEvent e) - { - container.setBackground(hoverColor); - textContainer.setBackground(hoverColor); - container.setCursor(new Cursor(Cursor.HAND_CURSOR)); - } - - @Override - public void mouseExited(MouseEvent e) - { - container.setBackground(ColorScheme.DARKER_GRAY_COLOR); - textContainer.setBackground(ColorScheme.DARKER_GRAY_COLOR); - container.setCursor(new Cursor(Cursor.DEFAULT_CURSOR)); - } - }); - - JLabel topLine = new JLabel(topText); - topLine.setForeground(Color.WHITE); - topLine.setFont(FontManager.getRunescapeSmallFont()); - - JLabel bottomLine = new JLabel(bottomText); - bottomLine.setForeground(Color.WHITE); - bottomLine.setFont(FontManager.getRunescapeSmallFont()); - - textContainer.add(topLine); - textContainer.add(bottomLine); - - container.add(textContainer, BorderLayout.CENTER); - - JLabel arrowLabel = new JLabel(ARROW_RIGHT_ICON); - container.add(arrowLabel, BorderLayout.EAST); - - return container; - } - - private void updateLoggedIn() - { - final String name = sessionManager.getAccountSession() != null - ? sessionManager.getAccountSession().getUsername() - : null; - - if (name != null) - { - emailLabel.setContentType("text/plain"); - emailLabel.setText(name); - loggedLabel.setText("Logged in as"); - actionsContainer.add(syncPanel, 0); - } - else - { - //emailLabel.setContentType("text/html"); - //emailLabel.setText("Login to sync settings to the cloud."); - //loggedLabel.setText("Not logged in"); - actionsContainer.remove(syncPanel); - } - } - - private static String htmlLabel(String key, String value) - { - return "" + key + "" + value + ""; - } - - @Subscribe - public void onSessionOpen(SessionOpen sessionOpen) - { - updateLoggedIn(); - } - - @Subscribe - public void onSessionClose(SessionClose e) - { - updateLoggedIn(); - } -} +/* + * Copyright (c) 2018 Abex + * Copyright (c) 2018, Psikoi + * 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.info; + +import com.google.common.base.MoreObjects; +import com.google.inject.Inject; +import java.awt.BorderLayout; +import java.awt.Color; +import java.awt.Cursor; +import java.awt.Font; +import java.awt.GridLayout; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import java.util.concurrent.ScheduledExecutorService; +import javax.annotation.Nullable; +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.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.events.SessionClose; +import net.runelite.client.events.SessionOpen; +import net.runelite.client.ui.ColorScheme; +import net.runelite.client.ui.FontManager; +import net.runelite.client.ui.PluginPanel; +import net.runelite.client.util.ImageUtil; +import net.runelite.client.util.LinkBrowser; + +@Singleton +public class InfoPanel extends PluginPanel +{ + private static final String RUNELITE_LOGIN = "https://runelite_login/"; + + private static final ImageIcon ARROW_RIGHT_ICON; + private static final ImageIcon GITHUB_ICON; + 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 + private Client client; + + @Inject + private RuneLiteProperties runeLiteProperties; + + @Inject + private EventBus eventBus; + + @Inject + private SessionManager sessionManager; + + @Inject + private ScheduledExecutorService executor; + + @Inject + private ConfigManager configManager; + + static + { + ARROW_RIGHT_ICON = new ImageIcon(ImageUtil.getResourceStreamFromClass(InfoPanel.class, "/util/arrow_right.png")); + GITHUB_ICON = new ImageIcon(ImageUtil.getResourceStreamFromClass(InfoPanel.class, "github_icon.png")); + 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() + { + setLayout(new BorderLayout()); + setBackground(ColorScheme.DARK_GRAY_COLOR); + setBorder(new EmptyBorder(10, 10, 10, 10)); + + JPanel versionPanel = new JPanel(); + versionPanel.setBackground(ColorScheme.DARKER_GRAY_COLOR); + versionPanel.setBorder(new EmptyBorder(10, 10, 10, 10)); + versionPanel.setLayout(new GridLayout(0, 1)); + + final Font smallFont = FontManager.getRunescapeSmallFont(); + + JLabel version = new JLabel(htmlLabel("RuneLite version: ", runeLiteProperties.getVersion())); + version.setFont(smallFont); + + JLabel revision = new JLabel(); + revision.setFont(smallFont); + + String engineVer = "Unknown"; + if (client != null) + { + engineVer = String.format("Rev %d", client.getRevision()); + } + + revision.setText(htmlLabel("Oldschool revision: ", engineVer)); + + JLabel launcher = new JLabel(htmlLabel("Launcher version: ", MoreObjects + .firstNonNull(RuneLiteProperties.getLauncherVersion(), "Unknown"))); + launcher.setFont(smallFont); + + loggedLabel.setForeground(ColorScheme.LIGHT_GRAY_COLOR); + loggedLabel.setFont(smallFont); + + emailLabel.setForeground(Color.WHITE); + emailLabel.setFont(smallFont); + emailLabel.enableAutoLinkHandler(false); + emailLabel.addHyperlinkListener(e -> + { + if (HyperlinkEvent.EventType.ACTIVATED.equals(e.getEventType()) && e.getURL() != null) + { + if (e.getURL().toString().equals(RUNELITE_LOGIN)) + { + executor.execute(sessionManager::login); + } + } + }); + + versionPanel.add(version); + versionPanel.add(revision); + versionPanel.add(launcher); + versionPanel.add(Box.createGlue()); + versionPanel.add(loggedLabel); + versionPanel.add(emailLabel); + + actionsContainer = new JPanel(); + actionsContainer.setBorder(new EmptyBorder(10, 0, 0, 0)); + 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, "License info", "for distribution", "https://github.com/runelite-extended/runelite/blob/master/LICENSE")); + actionsContainer.add(buildLinkPanel(DISCORD_ICON, "Talk to us on our", "discord server", "https://discord.gg/s2fzu5U")); + actionsContainer.add(buildLinkPanel(PATREON_ICON, "Patreon to support", "the RuneLite devs", runeLiteProperties.getPatreonLink())); + /* actionsContainer.add(buildLinkPanel(WIKI_ICON, "Information about", "RuneLite and plugins", runeLiteProperties.getWikiLink()));*/ + + add(versionPanel, BorderLayout.NORTH); + add(actionsContainer, BorderLayout.CENTER); + + updateLoggedIn(); + eventBus.register(this); + } + + /** + * 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); + container.setLayout(new BorderLayout()); + container.setBorder(new EmptyBorder(10, 10, 10, 10)); + + final Color hoverColor = ColorScheme.DARKER_GRAY_HOVER_COLOR; + final Color pressedColor = ColorScheme.DARKER_GRAY_COLOR.brighter(); + + JLabel iconLabel = new JLabel(icon); + container.add(iconLabel, BorderLayout.WEST); + + JPanel textContainer = new JPanel(); + textContainer.setBackground(ColorScheme.DARKER_GRAY_COLOR); + textContainer.setLayout(new GridLayout(2, 1)); + textContainer.setBorder(new EmptyBorder(5, 10, 5, 10)); + + container.addMouseListener(new MouseAdapter() + { + @Override + public void mousePressed(MouseEvent mouseEvent) + { + container.setBackground(pressedColor); + textContainer.setBackground(pressedColor); + } + + @Override + public void mouseReleased(MouseEvent e) + { + callback.run(); + container.setBackground(hoverColor); + textContainer.setBackground(hoverColor); + } + + @Override + public void mouseEntered(MouseEvent e) + { + container.setBackground(hoverColor); + textContainer.setBackground(hoverColor); + container.setCursor(new Cursor(Cursor.HAND_CURSOR)); + } + + @Override + public void mouseExited(MouseEvent e) + { + container.setBackground(ColorScheme.DARKER_GRAY_COLOR); + textContainer.setBackground(ColorScheme.DARKER_GRAY_COLOR); + container.setCursor(new Cursor(Cursor.DEFAULT_CURSOR)); + } + }); + + JLabel topLine = new JLabel(topText); + topLine.setForeground(Color.WHITE); + topLine.setFont(FontManager.getRunescapeSmallFont()); + + JLabel bottomLine = new JLabel(bottomText); + bottomLine.setForeground(Color.WHITE); + bottomLine.setFont(FontManager.getRunescapeSmallFont()); + + textContainer.add(topLine); + textContainer.add(bottomLine); + + container.add(textContainer, BorderLayout.CENTER); + + JLabel arrowLabel = new JLabel(ARROW_RIGHT_ICON); + container.add(arrowLabel, BorderLayout.EAST); + + return container; + } + + private void updateLoggedIn() + { + final String name = sessionManager.getAccountSession() != null + ? sessionManager.getAccountSession().getUsername() + : null; + + if (name != null) + { + emailLabel.setContentType("text/plain"); + emailLabel.setText(name); + loggedLabel.setText("Logged in as"); + actionsContainer.add(syncPanel, 0); + } + else + { + //emailLabel.setContentType("text/html"); + //emailLabel.setText("Login to sync settings to the cloud."); + //loggedLabel.setText("Not logged in"); + actionsContainer.remove(syncPanel); + } + } + + private static String htmlLabel(String key, String value) + { + return "" + key + "" + value + ""; + } + + @Subscribe + public void onSessionOpen(SessionOpen sessionOpen) + { + updateLoggedIn(); + } + + @Subscribe + public void onSessionClose(SessionClose e) + { + updateLoggedIn(); + } +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/info/InfoPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/info/InfoPlugin.java index f986a28ffa..40c502631c 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/info/InfoPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/info/InfoPlugin.java @@ -1,70 +1,70 @@ -/* - * Copyright (c) 2018 Abex - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package net.runelite.client.plugins.info; - -import java.awt.image.BufferedImage; -import javax.inject.Inject; -import net.runelite.client.plugins.Plugin; -import net.runelite.client.plugins.PluginDescriptor; -import net.runelite.client.ui.NavigationButton; -import net.runelite.client.ui.ClientToolbar; -import net.runelite.client.util.ImageUtil; - -@PluginDescriptor( - name = "Info Panel", - description = "Enable the Info panel", - loadWhenOutdated = true -) -public class InfoPlugin extends Plugin -{ - @Inject - private ClientToolbar clientToolbar; - - private NavigationButton navButton; - - @Override - protected void startUp() throws Exception - { - final InfoPanel panel = injector.getInstance(InfoPanel.class); - panel.init(); - - final BufferedImage icon = ImageUtil.getResourceStreamFromClass(getClass(), "info_icon.png"); - - navButton = NavigationButton.builder() - .tooltip("Info") - .icon(icon) - .priority(9) - .panel(panel) - .build(); - - clientToolbar.addNavigation(navButton); - } - - @Override - protected void shutDown() - { - clientToolbar.removeNavigation(navButton); - } -} +/* + * Copyright (c) 2018 Abex + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package net.runelite.client.plugins.info; + +import java.awt.image.BufferedImage; +import javax.inject.Inject; +import net.runelite.client.plugins.Plugin; +import net.runelite.client.plugins.PluginDescriptor; +import net.runelite.client.ui.ClientToolbar; +import net.runelite.client.ui.NavigationButton; +import net.runelite.client.util.ImageUtil; + +@PluginDescriptor( + name = "Info Panel", + description = "Enable the Info panel", + loadWhenOutdated = true +) +public class InfoPlugin extends Plugin +{ + @Inject + private ClientToolbar clientToolbar; + + private NavigationButton navButton; + + @Override + protected void startUp() throws Exception + { + final InfoPanel panel = injector.getInstance(InfoPanel.class); + panel.init(); + + final BufferedImage icon = ImageUtil.getResourceStreamFromClass(getClass(), "info_icon.png"); + + navButton = NavigationButton.builder() + .tooltip("Info") + .icon(icon) + .priority(9) + .panel(panel) + .build(); + + clientToolbar.addNavigation(navButton); + } + + @Override + protected void shutDown() + { + clientToolbar.removeNavigation(navButton); + } +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/instancemap/InstanceMapOverlay.java b/runelite-client/src/main/java/net/runelite/client/plugins/instancemap/InstanceMapOverlay.java index 3e44e6d4b8..c25ecf6771 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/instancemap/InstanceMapOverlay.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/instancemap/InstanceMapOverlay.java @@ -1,272 +1,272 @@ -/* - * Copyright (c) 2017, Adam - * 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.instancemap; - -import java.awt.Color; -import java.awt.Dimension; -import java.awt.Graphics2D; -import java.awt.Rectangle; -import java.awt.image.BufferedImage; -import javax.inject.Inject; -import javax.inject.Singleton; -import lombok.Getter; -import lombok.Setter; -import net.runelite.api.Client; -import net.runelite.api.Player; -import net.runelite.api.SpritePixels; -import net.runelite.api.Tile; -import net.runelite.api.coords.LocalPoint; -import net.runelite.api.events.GameStateChanged; -import net.runelite.client.game.SpriteManager; -import net.runelite.client.ui.overlay.Overlay; -import net.runelite.client.ui.overlay.OverlayLayer; -import net.runelite.client.ui.overlay.OverlayPosition; -import net.runelite.client.ui.overlay.OverlayPriority; -import net.runelite.client.ui.overlay.components.BackgroundComponent; -import static net.runelite.api.SpriteID.WINDOW_CLOSE_BUTTON_RED_X; -import static net.runelite.api.SpriteID.WINDOW_CLOSE_BUTTON_RED_X_HOVERED; - -@Singleton -class InstanceMapOverlay extends Overlay -{ - /** - * The size of tiles on the map. The way the client renders requires - * this value to be 4. Changing this will break the method for rendering - * complex tiles - */ - static final int TILE_SIZE = 4; - - /** - * The size of the player's position marker on the map - */ - private static final int PLAYER_MARKER_SIZE = 4; - - private static final int MAX_PLANE = 3; - private static final int MIN_PLANE = 0; - - /** - * The plane to render on the instance map. When the map is opened this - * defaults to the current plane. The ascend and descend buttons raise - * and lower this This is used to render parts of an instance below or - * above the local player's current plane. - */ - private int viewedPlane = 0; - - private final Client client; - private final SpriteManager spriteManager; - - /** - * Saved image of the scene, no reason to draw the whole thing every - * frame. - */ - private volatile BufferedImage mapImage; - private volatile boolean showMap = false; - private final BackgroundComponent backgroundComponent = new BackgroundComponent(); - - @Setter - private boolean isCloseButtonHovered; - @Getter - private Rectangle closeButtonBounds; - private BufferedImage closeButtonImage; - private BufferedImage closeButtonHoveredImage; - - @Inject - InstanceMapOverlay(Client client, SpriteManager spriteManager) - { - this.client = client; - this.spriteManager = spriteManager; - setPriority(OverlayPriority.HIGH); - setPosition(OverlayPosition.TOP_LEFT); - setLayer(OverlayLayer.ABOVE_WIDGETS); - backgroundComponent.setFill(false); - } - - public boolean isMapShown() - { - return showMap; - } - - /** - * Setter for showing the map. When the map is set to show, the map is - * re-rendered - * - * @param show Whether or not the map should be shown. - */ - public synchronized void setShowMap(boolean show) - { - showMap = show; - if (showMap) - { - //When we open the map show the current plane - viewedPlane = client.getPlane(); - } - mapImage = null; - } - - /** - * Increases the viewed plane. The maximum viewedPlane is 3 - */ - public synchronized void onAscend() - { - if (viewedPlane >= MAX_PLANE) - { - return; - } - - viewedPlane++;//Increment plane - mapImage = null; - } - - /** - * Decreases the viewed plane. The minimum viewedPlane is 0 - */ - public synchronized void onDescend() - { - if (viewedPlane <= MIN_PLANE) - { - return; - } - - viewedPlane--; - mapImage = null; - } - - @Override - public Dimension render(Graphics2D graphics) - { - if (!showMap) - { - return null; - } - - // avoid locking on fast path by creating a local ref - BufferedImage image = mapImage; - - if (image == null) - { - BufferedImage closeButton = getCloseButtonImage(); - - SpritePixels map = client.drawInstanceMap(viewedPlane); - image = minimapToBufferedImage(map); - synchronized (this) - { - if (showMap) - { - mapImage = image; - } - } - - closeButtonBounds = new Rectangle(image.getWidth() - closeButton.getWidth() - 5, 6, - closeButton.getWidth(), closeButton.getHeight()); - } - - graphics.drawImage(image, 0, 0, null); - backgroundComponent.setRectangle(new Rectangle(0, 0, image.getWidth(), image.getHeight())); - backgroundComponent.render(graphics); - - if (client.getPlane() == viewedPlane)//If we are not viewing the plane we are on, don't show player's position - { - drawPlayerDot(graphics, client.getLocalPlayer(), Color.white, Color.black); - } - - graphics.drawImage(isCloseButtonHovered ? getCloseButtonHoveredImage() : getCloseButtonImage(), - (int) closeButtonBounds.getX(), (int) closeButtonBounds.getY(), null); - - return new Dimension(image.getWidth(), image.getHeight()); - } - - /** - * Get the files for the current viewed plane - * - * @return - */ - private Tile[][] getTiles() - { - Tile[][][] sceneTiles = client.getScene().getTiles(); - return sceneTiles[viewedPlane]; - } - - /** - * Draws the players position as a dot on the map. - * - * @param graphics graphics to be drawn to - */ - private void drawPlayerDot(Graphics2D graphics, Player player, - Color dotColor, Color outlineColor) - { - LocalPoint playerLoc = player.getLocalLocation(); - - Tile[][] tiles = getTiles(); - int tileX = playerLoc.getSceneX(); - int tileY = (tiles[0].length - 1) - playerLoc.getSceneY(); // flip the y value - - int x = tileX * TILE_SIZE; - int y = tileY * TILE_SIZE; - graphics.setColor(dotColor); - graphics.fillRect(x, y, PLAYER_MARKER_SIZE, PLAYER_MARKER_SIZE);//draw the players point on the map - graphics.setColor(outlineColor); - graphics.drawRect(x, y, PLAYER_MARKER_SIZE, PLAYER_MARKER_SIZE);//outline - } - - /** - * Handles game state changes and re-draws the map - * - * @param event The game state change event - */ - public void onGameStateChange(GameStateChanged event) - { - mapImage = null; - } - - private static BufferedImage minimapToBufferedImage(SpritePixels spritePixels) - { - int width = spritePixels.getWidth(); - int height = spritePixels.getHeight(); - int[] pixels = spritePixels.getPixels(); - BufferedImage img = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB); - img.setRGB(0, 0, width, height, pixels, 0, width); - // 24624 / 512 and 24624 % 512 are both 48 - img = img.getSubimage(48, 48, TILE_SIZE * 104, TILE_SIZE * 104); - return img; - } - - private BufferedImage getCloseButtonImage() - { - if (closeButtonImage == null) - { - closeButtonImage = spriteManager.getSprite(WINDOW_CLOSE_BUTTON_RED_X, 0); - } - return closeButtonImage; - } - - private BufferedImage getCloseButtonHoveredImage() - { - if (closeButtonHoveredImage == null) - { - closeButtonHoveredImage = spriteManager.getSprite(WINDOW_CLOSE_BUTTON_RED_X_HOVERED, 0); - } - return closeButtonHoveredImage; - } -} +/* + * Copyright (c) 2017, Adam + * 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.instancemap; + +import java.awt.Color; +import java.awt.Dimension; +import java.awt.Graphics2D; +import java.awt.Rectangle; +import java.awt.image.BufferedImage; +import javax.inject.Inject; +import javax.inject.Singleton; +import lombok.Getter; +import lombok.Setter; +import net.runelite.api.Client; +import net.runelite.api.Player; +import static net.runelite.api.SpriteID.WINDOW_CLOSE_BUTTON_RED_X; +import static net.runelite.api.SpriteID.WINDOW_CLOSE_BUTTON_RED_X_HOVERED; +import net.runelite.api.SpritePixels; +import net.runelite.api.Tile; +import net.runelite.api.coords.LocalPoint; +import net.runelite.api.events.GameStateChanged; +import net.runelite.client.game.SpriteManager; +import net.runelite.client.ui.overlay.Overlay; +import net.runelite.client.ui.overlay.OverlayLayer; +import net.runelite.client.ui.overlay.OverlayPosition; +import net.runelite.client.ui.overlay.OverlayPriority; +import net.runelite.client.ui.overlay.components.BackgroundComponent; + +@Singleton +class InstanceMapOverlay extends Overlay +{ + /** + * The size of tiles on the map. The way the client renders requires + * this value to be 4. Changing this will break the method for rendering + * complex tiles + */ + static final int TILE_SIZE = 4; + + /** + * The size of the player's position marker on the map + */ + private static final int PLAYER_MARKER_SIZE = 4; + + private static final int MAX_PLANE = 3; + private static final int MIN_PLANE = 0; + + /** + * The plane to render on the instance map. When the map is opened this + * defaults to the current plane. The ascend and descend buttons raise + * and lower this This is used to render parts of an instance below or + * above the local player's current plane. + */ + private int viewedPlane = 0; + + private final Client client; + private final SpriteManager spriteManager; + + /** + * Saved image of the scene, no reason to draw the whole thing every + * frame. + */ + private volatile BufferedImage mapImage; + private volatile boolean showMap = false; + private final BackgroundComponent backgroundComponent = new BackgroundComponent(); + + @Setter + private boolean isCloseButtonHovered; + @Getter + private Rectangle closeButtonBounds; + private BufferedImage closeButtonImage; + private BufferedImage closeButtonHoveredImage; + + @Inject + InstanceMapOverlay(Client client, SpriteManager spriteManager) + { + this.client = client; + this.spriteManager = spriteManager; + setPriority(OverlayPriority.HIGH); + setPosition(OverlayPosition.TOP_LEFT); + setLayer(OverlayLayer.ABOVE_WIDGETS); + backgroundComponent.setFill(false); + } + + public boolean isMapShown() + { + return showMap; + } + + /** + * Setter for showing the map. When the map is set to show, the map is + * re-rendered + * + * @param show Whether or not the map should be shown. + */ + public synchronized void setShowMap(boolean show) + { + showMap = show; + if (showMap) + { + //When we open the map show the current plane + viewedPlane = client.getPlane(); + } + mapImage = null; + } + + /** + * Increases the viewed plane. The maximum viewedPlane is 3 + */ + public synchronized void onAscend() + { + if (viewedPlane >= MAX_PLANE) + { + return; + } + + viewedPlane++;//Increment plane + mapImage = null; + } + + /** + * Decreases the viewed plane. The minimum viewedPlane is 0 + */ + public synchronized void onDescend() + { + if (viewedPlane <= MIN_PLANE) + { + return; + } + + viewedPlane--; + mapImage = null; + } + + @Override + public Dimension render(Graphics2D graphics) + { + if (!showMap) + { + return null; + } + + // avoid locking on fast path by creating a local ref + BufferedImage image = mapImage; + + if (image == null) + { + BufferedImage closeButton = getCloseButtonImage(); + + SpritePixels map = client.drawInstanceMap(viewedPlane); + image = minimapToBufferedImage(map); + synchronized (this) + { + if (showMap) + { + mapImage = image; + } + } + + closeButtonBounds = new Rectangle(image.getWidth() - closeButton.getWidth() - 5, 6, + closeButton.getWidth(), closeButton.getHeight()); + } + + graphics.drawImage(image, 0, 0, null); + backgroundComponent.setRectangle(new Rectangle(0, 0, image.getWidth(), image.getHeight())); + backgroundComponent.render(graphics); + + if (client.getPlane() == viewedPlane)//If we are not viewing the plane we are on, don't show player's position + { + drawPlayerDot(graphics, client.getLocalPlayer(), Color.white, Color.black); + } + + graphics.drawImage(isCloseButtonHovered ? getCloseButtonHoveredImage() : getCloseButtonImage(), + (int) closeButtonBounds.getX(), (int) closeButtonBounds.getY(), null); + + return new Dimension(image.getWidth(), image.getHeight()); + } + + /** + * Get the files for the current viewed plane + * + * @return + */ + private Tile[][] getTiles() + { + Tile[][][] sceneTiles = client.getScene().getTiles(); + return sceneTiles[viewedPlane]; + } + + /** + * Draws the players position as a dot on the map. + * + * @param graphics graphics to be drawn to + */ + private void drawPlayerDot(Graphics2D graphics, Player player, + Color dotColor, Color outlineColor) + { + LocalPoint playerLoc = player.getLocalLocation(); + + Tile[][] tiles = getTiles(); + int tileX = playerLoc.getSceneX(); + int tileY = (tiles[0].length - 1) - playerLoc.getSceneY(); // flip the y value + + int x = tileX * TILE_SIZE; + int y = tileY * TILE_SIZE; + graphics.setColor(dotColor); + graphics.fillRect(x, y, PLAYER_MARKER_SIZE, PLAYER_MARKER_SIZE);//draw the players point on the map + graphics.setColor(outlineColor); + graphics.drawRect(x, y, PLAYER_MARKER_SIZE, PLAYER_MARKER_SIZE);//outline + } + + /** + * Handles game state changes and re-draws the map + * + * @param event The game state change event + */ + public void onGameStateChange(GameStateChanged event) + { + mapImage = null; + } + + private static BufferedImage minimapToBufferedImage(SpritePixels spritePixels) + { + int width = spritePixels.getWidth(); + int height = spritePixels.getHeight(); + int[] pixels = spritePixels.getPixels(); + BufferedImage img = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB); + img.setRGB(0, 0, width, height, pixels, 0, width); + // 24624 / 512 and 24624 % 512 are both 48 + img = img.getSubimage(48, 48, TILE_SIZE * 104, TILE_SIZE * 104); + return img; + } + + private BufferedImage getCloseButtonImage() + { + if (closeButtonImage == null) + { + closeButtonImage = spriteManager.getSprite(WINDOW_CLOSE_BUTTON_RED_X, 0); + } + return closeButtonImage; + } + + private BufferedImage getCloseButtonHoveredImage() + { + if (closeButtonHoveredImage == null) + { + closeButtonHoveredImage = spriteManager.getSprite(WINDOW_CLOSE_BUTTON_RED_X_HOVERED, 0); + } + return closeButtonHoveredImage; + } +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/interfacestyles/SpriteOverride.java b/runelite-client/src/main/java/net/runelite/client/plugins/interfacestyles/SpriteOverride.java index 3907a42e10..1b360aba55 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/interfacestyles/SpriteOverride.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/interfacestyles/SpriteOverride.java @@ -1,150 +1,150 @@ -/* - * Copyright (c) 2018, Lotto - * Copyright (c) 2018, Raqes - * 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.interfacestyles; - -import lombok.Getter; -import net.runelite.api.SpriteID; -import static net.runelite.client.plugins.interfacestyles.Skin.AROUND_2005; -import static net.runelite.client.plugins.interfacestyles.Skin.AROUND_2010; - -@Getter -enum SpriteOverride -{ - TAB_COMBAT(SpriteID.TAB_COMBAT, AROUND_2005, AROUND_2010), - TAB_STATS(SpriteID.TAB_STATS, AROUND_2005, AROUND_2010), - TAB_QUESTS(SpriteID.TAB_QUESTS, AROUND_2005), - TAB_QUESTS_PURPLE_KOUREND_1299(SpriteID.TAB_QUESTS_PURPLE_KOUREND, AROUND_2005), - TAB_QUESTS_RED_MINIGAMES(SpriteID.TAB_QUESTS_RED_MINIGAMES, AROUND_2005), - TAB_QUESTS_GREEN_ACHIEVEMENT_DIARIES(SpriteID.TAB_QUESTS_GREEN_ACHIEVEMENT_DIARIES, AROUND_2005), - TAB_INVENTORY(SpriteID.TAB_INVENTORY, AROUND_2005, AROUND_2010), - TAB_EQUIPMENT(SpriteID.TAB_EQUIPMENT, AROUND_2005, AROUND_2010), - TAB_PRAYER(SpriteID.TAB_PRAYER, AROUND_2005, AROUND_2010), - TAB_MAGIC(SpriteID.TAB_MAGIC, AROUND_2005, AROUND_2010), - TAB_MAGIC_SPELLBOOK_ANCIENT_MAGICKS(SpriteID.TAB_MAGIC_SPELLBOOK_ANCIENT_MAGICKS, AROUND_2005), - TAB_MAGIC_SPELLBOOK_LUNAR(SpriteID.TAB_MAGIC_SPELLBOOK_LUNAR, AROUND_2005), - TAB_MAGIC_SPELLBOOK_ARCEUUS(SpriteID.TAB_MAGIC_SPELLBOOK_ARCEUUS, AROUND_2005), - TAB_CLAN_CHAT(SpriteID.TAB_CLAN_CHAT, AROUND_2005, AROUND_2010), - TAB_FRIENDS(SpriteID.TAB_FRIENDS, AROUND_2005, AROUND_2010), - TAB_IGNORES(SpriteID.TAB_IGNORES, AROUND_2005, AROUND_2010), - TAB_LOGOUT(SpriteID.TAB_LOGOUT, AROUND_2005, AROUND_2010), - TAB_OPTIONS(SpriteID.TAB_OPTIONS, AROUND_2005, AROUND_2010), - TAB_EMOTES(SpriteID.TAB_EMOTES, AROUND_2005, AROUND_2010), - TAB_MUSIC(SpriteID.TAB_MUSIC, AROUND_2005, AROUND_2010), - TAB_CHATBOX(SpriteID.CHATBOX, AROUND_2005), - - SKILL_ATTACK(SpriteID.SKILL_ATTACK, AROUND_2010), - SKILL_STRENGTH(SpriteID.SKILL_STRENGTH, AROUND_2010), - SKILL_DEFENCE(SpriteID.SKILL_DEFENCE, AROUND_2010), - SKILL_RANGED(SpriteID.SKILL_RANGED, AROUND_2010), - SKILL_PRAYER(SpriteID.SKILL_PRAYER, AROUND_2005, AROUND_2010), - SKILL_MAGIC(SpriteID.SKILL_MAGIC, AROUND_2010), - SKILL_HITPOINTS(SpriteID.SKILL_HITPOINTS, AROUND_2010), - SKILL_AGILITY(SpriteID.SKILL_AGILITY, AROUND_2010), - SKILL_HERBLORE(SpriteID.SKILL_HERBLORE, AROUND_2010), - SKILL_THIEVING(SpriteID.SKILL_THIEVING, AROUND_2010), - SKILL_CRAFTING(SpriteID.SKILL_CRAFTING, AROUND_2010), - SKILL_FLETCHING(SpriteID.SKILL_FLETCHING, AROUND_2010), - SKILL_MINING(SpriteID.SKILL_MINING, AROUND_2010), - SKILL_SMITHING(SpriteID.SKILL_SMITHING, AROUND_2010), - SKILL_FISHING(SpriteID.SKILL_FISHING, AROUND_2010), - SKILL_COOKING(SpriteID.SKILL_COOKING, AROUND_2010), - SKILL_FIREMAKING(SpriteID.SKILL_FIREMAKING, AROUND_2010), - SKILL_WOODCUTTING(SpriteID.SKILL_WOODCUTTING, AROUND_2010), - SKILL_RUNECRAFT(SpriteID.SKILL_RUNECRAFT, AROUND_2010), - SKILL_SLAYER(SpriteID.SKILL_SLAYER, AROUND_2010), - SKILL_HUNTER(SpriteID.SKILL_HUNTER, AROUND_2010), - SKILL_CONSTRUCTION(SpriteID.SKILL_CONSTRUCTION, AROUND_2010), - - COMPASS(SpriteID.COMPASS_TEXTURE, AROUND_2005), - WINDOW_CLOSE_BUTTON_RED_X(SpriteID.WINDOW_CLOSE_BUTTON_RED_X, AROUND_2010), - WINDOW_CLOSE_BUTTON_RED_X_HOVERED(SpriteID.WINDOW_CLOSE_BUTTON_RED_X_HOVERED, AROUND_2010), - WINDOW_CLOSE_BUTTON_BROWN_X(SpriteID.WINDOW_CLOSE_BUTTON_BROWN_X, AROUND_2010), - WINDOW_CLOSE_BUTTON_BROWN_X_HOVERED(SpriteID.WINDOW_CLOSE_BUTTON_BROWN_X_HOVERED, AROUND_2010), - MINIMAP_ORB_FRAME(SpriteID.MINIMAP_ORB_FRAME, AROUND_2010), - MINIMAP_ORB_FRAME_HOVERED(SpriteID.MINIMAP_ORB_FRAME_HOVERED, AROUND_2010), - MINIMAP_ORB_XP(SpriteID.MINIMAP_ORB_XP, AROUND_2010), - MINIMAP_ORB_XP_ACTIVATED(SpriteID.MINIMAP_ORB_XP_ACTIVATED, AROUND_2010), - MINIMAP_ORB_XP_HOVERED(SpriteID.MINIMAP_ORB_XP_HOVERED, AROUND_2010), - MINIMAP_ORB_XP_ACTIVATED_HOVERED(SpriteID.MINIMAP_ORB_XP_ACTIVATED_HOVERED, AROUND_2010), - MINIMAP_ORB_WORLD_MAP_FRAME(SpriteID.MINIMAP_ORB_WORLD_MAP_FRAME, AROUND_2010), - MINIMAP_ORB_WORLD_MAP_PLANET(SpriteID.MINIMAP_ORB_WORLD_MAP_PLANET, AROUND_2010), - - //CHATBOX(SpriteID.CHATBOX, AROUND_2005), - CHATBOX_BUTTONS_BACKGROUND_STONES(SpriteID.CHATBOX_BUTTONS_BACKGROUND_STONES, AROUND_2005), - CHATBOX_BUTTON(SpriteID.CHATBOX_BUTTON, AROUND_2005), - CHATBOX_BUTTON_HOVERED(SpriteID.CHATBOX_BUTTON_HOVERED, AROUND_2005), - CHATBOX_BUTTON_NEW_MESSAGES( SpriteID.CHATBOX_BUTTON_NEW_MESSAGES, AROUND_2005), - CHATBOX_BUTTON_SELECTED(SpriteID.CHATBOX_BUTTON_SELECTED, AROUND_2005), - CHATBOX_BUTTON_SELECTED_HOVERED(SpriteID.CHATBOX_BUTTON_SELECTED_HOVERED, AROUND_2005), - CHATBOX_REPORT_BUTTON(SpriteID.CHATBOX_REPORT_BUTTON, AROUND_2005), - CHATBOX_REPORT_BUTTON_HOVERED(SpriteID.CHATBOX_REPORT_BUTTON_HOVERED, AROUND_2005), - - SCROLLBAR_ARROW_UP(SpriteID.SCROLLBAR_ARROW_UP, AROUND_2005), - SCROLLBAR_ARROW_DOWN(SpriteID.SCROLLBAR_ARROW_DOWN, AROUND_2005), - SCROLLBAR_THUMB_TOP(SpriteID.SCROLLBAR_THUMB_TOP, AROUND_2005), - SCROLLBAR_THUMB_MIDDLE(SpriteID.SCROLLBAR_THUMB_MIDDLE, AROUND_2005), - SCROLLBAR_THUMB_BOTTOM(SpriteID.SCROLLBAR_THUMB_BOTTOM, AROUND_2005), - SCROLLBAR_THUMB_MIDDLE_DARK(SpriteID.SCROLLBAR_THUMB_MIDDLE_DARK, AROUND_2005), - - TAB_STONE_TOP_LEFT_SELECTED(SpriteID.TAB_STONE_TOP_LEFT_SELECTED, AROUND_2010), - TAB_STONE_TOP_RIGHT_SELECTED(SpriteID.TAB_STONE_TOP_RIGHT_SELECTED, AROUND_2010), - TAB_STONE_BOTTOM_LEFT_SELECTED(SpriteID.TAB_STONE_BOTTOM_LEFT_SELECTED, AROUND_2010), - TAB_STONE_BOTTOM_RIGHT_SELECTED(SpriteID.TAB_STONE_BOTTOM_RIGHT_SELECTED, AROUND_2010), - TAB_STONE_MIDDLE_SELECTED(SpriteID.TAB_STONE_MIDDLE_SELECTED, AROUND_2010), - - FIXED_MODE_SIDE_PANEL_BACKGROUND(SpriteID.FIXED_MODE_SIDE_PANEL_BACKGROUND, AROUND_2005), - FIXED_MODE_TABS_ROW_BOTTOM(SpriteID.FIXED_MODE_TABS_ROW_BOTTOM, AROUND_2005, AROUND_2010), - - OLD_SCHOOl_MODE_SIDE_PANEL_EDGE_LEFT_UPPER(SpriteID.OLD_SCHOOl_MODE_SIDE_PANEL_EDGE_LEFT_UPPER, AROUND_2005, AROUND_2010), - OLD_SCHOOl_MODE_SIDE_PANEL_EDGE_LEFT_LOWER(SpriteID.OLD_SCHOOl_MODE_SIDE_PANEL_EDGE_LEFT_LOWER, AROUND_2005, AROUND_2010), - OLD_SCHOOl_MODE_SIDE_PANEL_EDGE_RIGHT(SpriteID.OLD_SCHOOl_MODE_SIDE_PANEL_EDGE_RIGHT, AROUND_2005, AROUND_2010), - - FIXED_MODE_TABS_TOP_ROW(SpriteID.FIXED_MODE_TABS_TOP_ROW, AROUND_2005, AROUND_2010), - FIXED_MODE_MINIMAP_LEFT_EDGE(SpriteID.FIXED_MODE_MINIMAP_LEFT_EDGE, AROUND_2005, AROUND_2010), - FIXED_MODE_MINIMAP_RIGHT_EDGE(SpriteID.FIXED_MODE_MINIMAP_RIGHT_EDGE, AROUND_2005, AROUND_2010), - FIXED_MODE_WINDOW_FRAME_EDGE_TOP(SpriteID.FIXED_MODE_WINDOW_FRAME_EDGE_TOP, AROUND_2005, AROUND_2010), - FIXED_MODE_MINIMAP_AND_COMPASS_FRAME(SpriteID.FIXED_MODE_MINIMAP_AND_COMPASS_FRAME, AROUND_2005, AROUND_2010), - FIXED_MODE_MINIMAP_FRAME_BOTTOM(SpriteID.FIXED_MODE_MINIMAP_FRAME_BOTTOM, AROUND_2005), - FIXED_MODE_TOP_RIGHT_CORNER(SpriteID.FIXED_MODE_TOP_RIGHT_CORNER, AROUND_2005), - - RESIZEABLE_MODE_TABS_TOP_ROW(SpriteID.RESIZEABLE_MODE_TABS_TOP_ROW, AROUND_2010), - RESIZEABLE_MODE_TABS_BOTTOM_ROW(SpriteID.RESIZEABLE_MODE_TABS_BOTTOM_ROW, AROUND_2010), - RESIZEABLE_MODE_SIDE_PANEL_EDGE_LEFT(SpriteID.RESIZEABLE_MODE_SIDE_PANEL_EDGE_LEFT, AROUND_2010), - RESIZEABLE_MODE_SIDE_PANEL_EDGE_RIGHT(SpriteID.RESIZEABLE_MODE_SIDE_PANEL_EDGE_RIGHT, AROUND_2010), - RESIZEABLE_MODE_MINIMAP_AND_COMPASS_FRAME(SpriteID.RESIZEABLE_MODE_MINIMAP_AND_COMPASS_FRAME, AROUND_2010), - RESIZEABLE_MODE_TAB_STONE_MIDDLE(SpriteID.RESIZEABLE_MODE_TAB_STONE_MIDDLE, AROUND_2010), - RESIZEABLE_MODE_TAB_STONE_MIDDLE_SELECTED(SpriteID.RESIZEABLE_MODE_TAB_STONE_MIDDLE_SELECTED, AROUND_2010); - - private int spriteID; - private Skin[] skin; - - SpriteOverride(int spriteID, Skin... skin) - { - this.spriteID = spriteID; - this.skin = skin; - } +/* + * Copyright (c) 2018, Lotto + * Copyright (c) 2018, Raqes + * 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.interfacestyles; + +import lombok.Getter; +import net.runelite.api.SpriteID; +import static net.runelite.client.plugins.interfacestyles.Skin.AROUND_2005; +import static net.runelite.client.plugins.interfacestyles.Skin.AROUND_2010; + +@Getter +enum SpriteOverride +{ + TAB_COMBAT(SpriteID.TAB_COMBAT, AROUND_2005, AROUND_2010), + TAB_STATS(SpriteID.TAB_STATS, AROUND_2005, AROUND_2010), + TAB_QUESTS(SpriteID.TAB_QUESTS, AROUND_2005), + TAB_QUESTS_PURPLE_KOUREND_1299(SpriteID.TAB_QUESTS_PURPLE_KOUREND, AROUND_2005), + TAB_QUESTS_RED_MINIGAMES(SpriteID.TAB_QUESTS_RED_MINIGAMES, AROUND_2005), + TAB_QUESTS_GREEN_ACHIEVEMENT_DIARIES(SpriteID.TAB_QUESTS_GREEN_ACHIEVEMENT_DIARIES, AROUND_2005), + TAB_INVENTORY(SpriteID.TAB_INVENTORY, AROUND_2005, AROUND_2010), + TAB_EQUIPMENT(SpriteID.TAB_EQUIPMENT, AROUND_2005, AROUND_2010), + TAB_PRAYER(SpriteID.TAB_PRAYER, AROUND_2005, AROUND_2010), + TAB_MAGIC(SpriteID.TAB_MAGIC, AROUND_2005, AROUND_2010), + TAB_MAGIC_SPELLBOOK_ANCIENT_MAGICKS(SpriteID.TAB_MAGIC_SPELLBOOK_ANCIENT_MAGICKS, AROUND_2005), + TAB_MAGIC_SPELLBOOK_LUNAR(SpriteID.TAB_MAGIC_SPELLBOOK_LUNAR, AROUND_2005), + TAB_MAGIC_SPELLBOOK_ARCEUUS(SpriteID.TAB_MAGIC_SPELLBOOK_ARCEUUS, AROUND_2005), + TAB_CLAN_CHAT(SpriteID.TAB_CLAN_CHAT, AROUND_2005, AROUND_2010), + TAB_FRIENDS(SpriteID.TAB_FRIENDS, AROUND_2005, AROUND_2010), + TAB_IGNORES(SpriteID.TAB_IGNORES, AROUND_2005, AROUND_2010), + TAB_LOGOUT(SpriteID.TAB_LOGOUT, AROUND_2005, AROUND_2010), + TAB_OPTIONS(SpriteID.TAB_OPTIONS, AROUND_2005, AROUND_2010), + TAB_EMOTES(SpriteID.TAB_EMOTES, AROUND_2005, AROUND_2010), + TAB_MUSIC(SpriteID.TAB_MUSIC, AROUND_2005, AROUND_2010), + TAB_CHATBOX(SpriteID.CHATBOX, AROUND_2005), + + SKILL_ATTACK(SpriteID.SKILL_ATTACK, AROUND_2010), + SKILL_STRENGTH(SpriteID.SKILL_STRENGTH, AROUND_2010), + SKILL_DEFENCE(SpriteID.SKILL_DEFENCE, AROUND_2010), + SKILL_RANGED(SpriteID.SKILL_RANGED, AROUND_2010), + SKILL_PRAYER(SpriteID.SKILL_PRAYER, AROUND_2005, AROUND_2010), + SKILL_MAGIC(SpriteID.SKILL_MAGIC, AROUND_2010), + SKILL_HITPOINTS(SpriteID.SKILL_HITPOINTS, AROUND_2010), + SKILL_AGILITY(SpriteID.SKILL_AGILITY, AROUND_2010), + SKILL_HERBLORE(SpriteID.SKILL_HERBLORE, AROUND_2010), + SKILL_THIEVING(SpriteID.SKILL_THIEVING, AROUND_2010), + SKILL_CRAFTING(SpriteID.SKILL_CRAFTING, AROUND_2010), + SKILL_FLETCHING(SpriteID.SKILL_FLETCHING, AROUND_2010), + SKILL_MINING(SpriteID.SKILL_MINING, AROUND_2010), + SKILL_SMITHING(SpriteID.SKILL_SMITHING, AROUND_2010), + SKILL_FISHING(SpriteID.SKILL_FISHING, AROUND_2010), + SKILL_COOKING(SpriteID.SKILL_COOKING, AROUND_2010), + SKILL_FIREMAKING(SpriteID.SKILL_FIREMAKING, AROUND_2010), + SKILL_WOODCUTTING(SpriteID.SKILL_WOODCUTTING, AROUND_2010), + SKILL_RUNECRAFT(SpriteID.SKILL_RUNECRAFT, AROUND_2010), + SKILL_SLAYER(SpriteID.SKILL_SLAYER, AROUND_2010), + SKILL_HUNTER(SpriteID.SKILL_HUNTER, AROUND_2010), + SKILL_CONSTRUCTION(SpriteID.SKILL_CONSTRUCTION, AROUND_2010), + + COMPASS(SpriteID.COMPASS_TEXTURE, AROUND_2005), + WINDOW_CLOSE_BUTTON_RED_X(SpriteID.WINDOW_CLOSE_BUTTON_RED_X, AROUND_2010), + WINDOW_CLOSE_BUTTON_RED_X_HOVERED(SpriteID.WINDOW_CLOSE_BUTTON_RED_X_HOVERED, AROUND_2010), + WINDOW_CLOSE_BUTTON_BROWN_X(SpriteID.WINDOW_CLOSE_BUTTON_BROWN_X, AROUND_2010), + WINDOW_CLOSE_BUTTON_BROWN_X_HOVERED(SpriteID.WINDOW_CLOSE_BUTTON_BROWN_X_HOVERED, AROUND_2010), + MINIMAP_ORB_FRAME(SpriteID.MINIMAP_ORB_FRAME, AROUND_2010), + MINIMAP_ORB_FRAME_HOVERED(SpriteID.MINIMAP_ORB_FRAME_HOVERED, AROUND_2010), + MINIMAP_ORB_XP(SpriteID.MINIMAP_ORB_XP, AROUND_2010), + MINIMAP_ORB_XP_ACTIVATED(SpriteID.MINIMAP_ORB_XP_ACTIVATED, AROUND_2010), + MINIMAP_ORB_XP_HOVERED(SpriteID.MINIMAP_ORB_XP_HOVERED, AROUND_2010), + MINIMAP_ORB_XP_ACTIVATED_HOVERED(SpriteID.MINIMAP_ORB_XP_ACTIVATED_HOVERED, AROUND_2010), + MINIMAP_ORB_WORLD_MAP_FRAME(SpriteID.MINIMAP_ORB_WORLD_MAP_FRAME, AROUND_2010), + MINIMAP_ORB_WORLD_MAP_PLANET(SpriteID.MINIMAP_ORB_WORLD_MAP_PLANET, AROUND_2010), + + //CHATBOX(SpriteID.CHATBOX, AROUND_2005), + CHATBOX_BUTTONS_BACKGROUND_STONES(SpriteID.CHATBOX_BUTTONS_BACKGROUND_STONES, AROUND_2005), + CHATBOX_BUTTON(SpriteID.CHATBOX_BUTTON, AROUND_2005), + CHATBOX_BUTTON_HOVERED(SpriteID.CHATBOX_BUTTON_HOVERED, AROUND_2005), + CHATBOX_BUTTON_NEW_MESSAGES(SpriteID.CHATBOX_BUTTON_NEW_MESSAGES, AROUND_2005), + CHATBOX_BUTTON_SELECTED(SpriteID.CHATBOX_BUTTON_SELECTED, AROUND_2005), + CHATBOX_BUTTON_SELECTED_HOVERED(SpriteID.CHATBOX_BUTTON_SELECTED_HOVERED, AROUND_2005), + CHATBOX_REPORT_BUTTON(SpriteID.CHATBOX_REPORT_BUTTON, AROUND_2005), + CHATBOX_REPORT_BUTTON_HOVERED(SpriteID.CHATBOX_REPORT_BUTTON_HOVERED, AROUND_2005), + + SCROLLBAR_ARROW_UP(SpriteID.SCROLLBAR_ARROW_UP, AROUND_2005), + SCROLLBAR_ARROW_DOWN(SpriteID.SCROLLBAR_ARROW_DOWN, AROUND_2005), + SCROLLBAR_THUMB_TOP(SpriteID.SCROLLBAR_THUMB_TOP, AROUND_2005), + SCROLLBAR_THUMB_MIDDLE(SpriteID.SCROLLBAR_THUMB_MIDDLE, AROUND_2005), + SCROLLBAR_THUMB_BOTTOM(SpriteID.SCROLLBAR_THUMB_BOTTOM, AROUND_2005), + SCROLLBAR_THUMB_MIDDLE_DARK(SpriteID.SCROLLBAR_THUMB_MIDDLE_DARK, AROUND_2005), + + TAB_STONE_TOP_LEFT_SELECTED(SpriteID.TAB_STONE_TOP_LEFT_SELECTED, AROUND_2010), + TAB_STONE_TOP_RIGHT_SELECTED(SpriteID.TAB_STONE_TOP_RIGHT_SELECTED, AROUND_2010), + TAB_STONE_BOTTOM_LEFT_SELECTED(SpriteID.TAB_STONE_BOTTOM_LEFT_SELECTED, AROUND_2010), + TAB_STONE_BOTTOM_RIGHT_SELECTED(SpriteID.TAB_STONE_BOTTOM_RIGHT_SELECTED, AROUND_2010), + TAB_STONE_MIDDLE_SELECTED(SpriteID.TAB_STONE_MIDDLE_SELECTED, AROUND_2010), + + FIXED_MODE_SIDE_PANEL_BACKGROUND(SpriteID.FIXED_MODE_SIDE_PANEL_BACKGROUND, AROUND_2005), + FIXED_MODE_TABS_ROW_BOTTOM(SpriteID.FIXED_MODE_TABS_ROW_BOTTOM, AROUND_2005, AROUND_2010), + + OLD_SCHOOl_MODE_SIDE_PANEL_EDGE_LEFT_UPPER(SpriteID.OLD_SCHOOl_MODE_SIDE_PANEL_EDGE_LEFT_UPPER, AROUND_2005, AROUND_2010), + OLD_SCHOOl_MODE_SIDE_PANEL_EDGE_LEFT_LOWER(SpriteID.OLD_SCHOOl_MODE_SIDE_PANEL_EDGE_LEFT_LOWER, AROUND_2005, AROUND_2010), + OLD_SCHOOl_MODE_SIDE_PANEL_EDGE_RIGHT(SpriteID.OLD_SCHOOl_MODE_SIDE_PANEL_EDGE_RIGHT, AROUND_2005, AROUND_2010), + + FIXED_MODE_TABS_TOP_ROW(SpriteID.FIXED_MODE_TABS_TOP_ROW, AROUND_2005, AROUND_2010), + FIXED_MODE_MINIMAP_LEFT_EDGE(SpriteID.FIXED_MODE_MINIMAP_LEFT_EDGE, AROUND_2005, AROUND_2010), + FIXED_MODE_MINIMAP_RIGHT_EDGE(SpriteID.FIXED_MODE_MINIMAP_RIGHT_EDGE, AROUND_2005, AROUND_2010), + FIXED_MODE_WINDOW_FRAME_EDGE_TOP(SpriteID.FIXED_MODE_WINDOW_FRAME_EDGE_TOP, AROUND_2005, AROUND_2010), + FIXED_MODE_MINIMAP_AND_COMPASS_FRAME(SpriteID.FIXED_MODE_MINIMAP_AND_COMPASS_FRAME, AROUND_2005, AROUND_2010), + FIXED_MODE_MINIMAP_FRAME_BOTTOM(SpriteID.FIXED_MODE_MINIMAP_FRAME_BOTTOM, AROUND_2005), + FIXED_MODE_TOP_RIGHT_CORNER(SpriteID.FIXED_MODE_TOP_RIGHT_CORNER, AROUND_2005), + + RESIZEABLE_MODE_TABS_TOP_ROW(SpriteID.RESIZEABLE_MODE_TABS_TOP_ROW, AROUND_2010), + RESIZEABLE_MODE_TABS_BOTTOM_ROW(SpriteID.RESIZEABLE_MODE_TABS_BOTTOM_ROW, AROUND_2010), + RESIZEABLE_MODE_SIDE_PANEL_EDGE_LEFT(SpriteID.RESIZEABLE_MODE_SIDE_PANEL_EDGE_LEFT, AROUND_2010), + RESIZEABLE_MODE_SIDE_PANEL_EDGE_RIGHT(SpriteID.RESIZEABLE_MODE_SIDE_PANEL_EDGE_RIGHT, AROUND_2010), + RESIZEABLE_MODE_MINIMAP_AND_COMPASS_FRAME(SpriteID.RESIZEABLE_MODE_MINIMAP_AND_COMPASS_FRAME, AROUND_2010), + RESIZEABLE_MODE_TAB_STONE_MIDDLE(SpriteID.RESIZEABLE_MODE_TAB_STONE_MIDDLE, AROUND_2010), + RESIZEABLE_MODE_TAB_STONE_MIDDLE_SELECTED(SpriteID.RESIZEABLE_MODE_TAB_STONE_MIDDLE_SELECTED, AROUND_2010); + + private int spriteID; + private Skin[] skin; + + SpriteOverride(int spriteID, Skin... skin) + { + this.spriteID = spriteID; + this.skin = skin; + } } \ No newline at end of file diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/interfacestyles/WidgetOverride.java b/runelite-client/src/main/java/net/runelite/client/plugins/interfacestyles/WidgetOverride.java index 46997704a5..89019477ca 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/interfacestyles/WidgetOverride.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/interfacestyles/WidgetOverride.java @@ -1,56 +1,56 @@ -/* - * Copyright (c) 2018, Lotto - * Copyright (c) 2018, Raqes - * 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.interfacestyles; - -import lombok.Getter; -import net.runelite.api.widgets.WidgetInfo; - -@Getter -enum WidgetOverride -{ - FIXED_CORNER_TOP_LEFT_2005(Skin.AROUND_2005, "1026", WidgetInfo.FIXED_VIEWPORT_COMBAT_TAB), - FIXED_CORNER_TOP_RIGHT_2005(Skin.AROUND_2005, "1027", WidgetInfo.FIXED_VIEWPORT_MAGIC_TAB), - FIXED_CORNER_BOTTOM_LEFT_2005(Skin.AROUND_2005, "1028", WidgetInfo.FIXED_VIEWPORT_CLAN_CHAT_TAB), - FIXED_CORNER_BOTTOM_RIGHT_2005(Skin.AROUND_2005, "1029", WidgetInfo.FIXED_VIEWPORT_MUSIC_TAB), - FIXED_TOP_LEFT_2005(Skin.AROUND_2005, "1030_top_left", WidgetInfo.FIXED_VIEWPORT_STATS_TAB, WidgetInfo.FIXED_VIEWPORT_QUESTS_TAB), - FIXED_TOP_RIGHT_2005(Skin.AROUND_2005, "1030_top_right", WidgetInfo.FIXED_VIEWPORT_EQUIPMENT_TAB, WidgetInfo.FIXED_VIEWPORT_PRAYER_TAB), - FIXED_TOP_MIDDLE_2005(Skin.AROUND_2005, "1030_top_middle", WidgetInfo.FIXED_VIEWPORT_INVENTORY_TAB), - FIXED_BOTTOM_LEFT_2005(Skin.AROUND_2005, "1030_bottom_left", WidgetInfo.FIXED_VIEWPORT_FRIENDS_TAB, WidgetInfo.FIXED_VIEWPORT_IGNORES_TAB), - FIXED_BOTTOM_RIGHT_2005(Skin.AROUND_2005, "1030_bottom_middle", WidgetInfo.FIXED_VIEWPORT_LOGOUT_TAB), - FIXED_BOTTOM_MIDDLE_2005(Skin.AROUND_2005, "1030_bottom_right", WidgetInfo.FIXED_VIEWPORT_OPTIONS_TAB, WidgetInfo.FIXED_VIEWPORT_EMOTES_TAB); - - private Skin skin; - private String name; - private WidgetInfo[] widgetInfo; - - WidgetOverride(Skin skin, String name, WidgetInfo... widgetInfo) - { - this.skin = skin; - this.name = name; - this.widgetInfo = widgetInfo; - } +/* + * Copyright (c) 2018, Lotto + * Copyright (c) 2018, Raqes + * 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.interfacestyles; + +import lombok.Getter; +import net.runelite.api.widgets.WidgetInfo; + +@Getter +enum WidgetOverride +{ + FIXED_CORNER_TOP_LEFT_2005(Skin.AROUND_2005, "1026", WidgetInfo.FIXED_VIEWPORT_COMBAT_TAB), + FIXED_CORNER_TOP_RIGHT_2005(Skin.AROUND_2005, "1027", WidgetInfo.FIXED_VIEWPORT_MAGIC_TAB), + FIXED_CORNER_BOTTOM_LEFT_2005(Skin.AROUND_2005, "1028", WidgetInfo.FIXED_VIEWPORT_CLAN_CHAT_TAB), + FIXED_CORNER_BOTTOM_RIGHT_2005(Skin.AROUND_2005, "1029", WidgetInfo.FIXED_VIEWPORT_MUSIC_TAB), + FIXED_TOP_LEFT_2005(Skin.AROUND_2005, "1030_top_left", WidgetInfo.FIXED_VIEWPORT_STATS_TAB, WidgetInfo.FIXED_VIEWPORT_QUESTS_TAB), + FIXED_TOP_RIGHT_2005(Skin.AROUND_2005, "1030_top_right", WidgetInfo.FIXED_VIEWPORT_EQUIPMENT_TAB, WidgetInfo.FIXED_VIEWPORT_PRAYER_TAB), + FIXED_TOP_MIDDLE_2005(Skin.AROUND_2005, "1030_top_middle", WidgetInfo.FIXED_VIEWPORT_INVENTORY_TAB), + FIXED_BOTTOM_LEFT_2005(Skin.AROUND_2005, "1030_bottom_left", WidgetInfo.FIXED_VIEWPORT_FRIENDS_TAB, WidgetInfo.FIXED_VIEWPORT_IGNORES_TAB), + FIXED_BOTTOM_RIGHT_2005(Skin.AROUND_2005, "1030_bottom_middle", WidgetInfo.FIXED_VIEWPORT_LOGOUT_TAB), + FIXED_BOTTOM_MIDDLE_2005(Skin.AROUND_2005, "1030_bottom_right", WidgetInfo.FIXED_VIEWPORT_OPTIONS_TAB, WidgetInfo.FIXED_VIEWPORT_EMOTES_TAB); + + private Skin skin; + private String name; + private WidgetInfo[] widgetInfo; + + WidgetOverride(Skin skin, String name, WidgetInfo... widgetInfo) + { + this.skin = skin; + this.name = name; + this.widgetInfo = widgetInfo; + } } \ No newline at end of file diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/inventoryviewer/InventoryViewerConfig.java b/runelite-client/src/main/java/net/runelite/client/plugins/inventoryviewer/InventoryViewerConfig.java index 38ff6d6e3d..8cefffc1de 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/inventoryviewer/InventoryViewerConfig.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/inventoryviewer/InventoryViewerConfig.java @@ -1,63 +1,63 @@ -/* - * Copyright (c) 2019 Hydrox6 - * 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.inventoryviewer; - -import net.runelite.client.config.Config; -import net.runelite.client.config.ConfigGroup; -import net.runelite.client.config.ConfigItem; - -@ConfigGroup(InventoryViewerPlugin.CONFIG_GROUP_KEY) -public interface InventoryViewerConfig extends Config -{ - @ConfigItem( - keyName = "viewerMode", - name = "Mode", - description = "The mode to display the inventory viewer with" - ) - default InventoryViewerMode viewerMode() - { - return InventoryViewerMode.FULL; - } - - @ConfigItem( - keyName = "showFreeSlots", - name = "Show Free Slots", - description = "Whether to show a label with the free slots in the inventory" - ) - default boolean showFreeSlots() - { - return false; - } - - @ConfigItem( - keyName = "hideWhenInvOpen", - name = "Hide when inventory is open", - description = "Hide the inventory viewer when the player's inventory is open" - ) - default boolean hideWhenInvOpen() - { - return false; - } -} +/* + * Copyright (c) 2019 Hydrox6 + * 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.inventoryviewer; + +import net.runelite.client.config.Config; +import net.runelite.client.config.ConfigGroup; +import net.runelite.client.config.ConfigItem; + +@ConfigGroup(InventoryViewerPlugin.CONFIG_GROUP_KEY) +public interface InventoryViewerConfig extends Config +{ + @ConfigItem( + keyName = "viewerMode", + name = "Mode", + description = "The mode to display the inventory viewer with" + ) + default InventoryViewerMode viewerMode() + { + return InventoryViewerMode.FULL; + } + + @ConfigItem( + keyName = "showFreeSlots", + name = "Show Free Slots", + description = "Whether to show a label with the free slots in the inventory" + ) + default boolean showFreeSlots() + { + return false; + } + + @ConfigItem( + keyName = "hideWhenInvOpen", + name = "Hide when inventory is open", + description = "Hide the inventory viewer when the player's inventory is open" + ) + default boolean hideWhenInvOpen() + { + return false; + } +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/inventoryviewer/InventoryViewerOverlay.java b/runelite-client/src/main/java/net/runelite/client/plugins/inventoryviewer/InventoryViewerOverlay.java index 7a2941158a..d5dd3de6eb 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/inventoryviewer/InventoryViewerOverlay.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/inventoryviewer/InventoryViewerOverlay.java @@ -73,18 +73,18 @@ class InventoryViewerOverlay extends Overlay inventoryComponent.setOrientation(ComponentOrientation.HORIZONTAL); inventoryComponent.setBackgroundColor(null); inventoryComponent.setBorder(new Rectangle( - 0, - ComponentConstants.STANDARD_BORDER, - 0, - ComponentConstants.STANDARD_BORDER)); + 0, + ComponentConstants.STANDARD_BORDER, + 0, + ComponentConstants.STANDARD_BORDER)); wrapperComponent.setOrientation(ComponentOrientation.HORIZONTAL); wrapperComponent.setWrapping(2); wrapperComponent.setBorder(new Rectangle( - ComponentConstants.STANDARD_BORDER * 2, - ComponentConstants.STANDARD_BORDER, - ComponentConstants.STANDARD_BORDER * 2, - ComponentConstants.STANDARD_BORDER)); + ComponentConstants.STANDARD_BORDER * 2, + ComponentConstants.STANDARD_BORDER, + ComponentConstants.STANDARD_BORDER * 2, + ComponentConstants.STANDARD_BORDER)); this.itemManager = itemManager; this.client = client; @@ -95,7 +95,7 @@ class InventoryViewerOverlay extends Overlay public Dimension render(Graphics2D graphics) { if (config.hideWhenInvOpen() - && client.getVar(VarClientInt.PLAYER_INVENTORY_OPENED) == 3) + && client.getVar(VarClientInt.PLAYER_INVENTORY_OPENED) == 3) { return null; } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/itemcharges/ItemChargePlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/itemcharges/ItemChargePlugin.java index 2e0e61ae8e..823a6678b6 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/itemcharges/ItemChargePlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/itemcharges/ItemChargePlugin.java @@ -647,7 +647,7 @@ public class ItemChargePlugin extends Plugin return false; } - final ItemChargeInfobox i = (ItemChargeInfobox)t; + final ItemChargeInfobox i = (ItemChargeInfobox) t; return i.getItem() == item && i.getSlot() == slot; }); } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/itemcharges/ItemWithCharge.java b/runelite-client/src/main/java/net/runelite/client/plugins/itemcharges/ItemWithCharge.java index f696097817..2f2fe76469 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/itemcharges/ItemWithCharge.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/itemcharges/ItemWithCharge.java @@ -29,7 +29,133 @@ import java.util.Map; import javax.annotation.Nullable; import lombok.AllArgsConstructor; import lombok.Getter; -import static net.runelite.api.ItemID.*; +import static net.runelite.api.ItemID.ABYSSAL_BRACELET1; +import static net.runelite.api.ItemID.ABYSSAL_BRACELET2; +import static net.runelite.api.ItemID.ABYSSAL_BRACELET3; +import static net.runelite.api.ItemID.ABYSSAL_BRACELET4; +import static net.runelite.api.ItemID.ABYSSAL_BRACELET5; +import static net.runelite.api.ItemID.AMULET_OF_GLORY1; +import static net.runelite.api.ItemID.AMULET_OF_GLORY2; +import static net.runelite.api.ItemID.AMULET_OF_GLORY3; +import static net.runelite.api.ItemID.AMULET_OF_GLORY4; +import static net.runelite.api.ItemID.AMULET_OF_GLORY5; +import static net.runelite.api.ItemID.AMULET_OF_GLORY6; +import static net.runelite.api.ItemID.AMULET_OF_GLORY_T1; +import static net.runelite.api.ItemID.AMULET_OF_GLORY_T2; +import static net.runelite.api.ItemID.AMULET_OF_GLORY_T3; +import static net.runelite.api.ItemID.AMULET_OF_GLORY_T4; +import static net.runelite.api.ItemID.AMULET_OF_GLORY_T5; +import static net.runelite.api.ItemID.AMULET_OF_GLORY_T6; +import static net.runelite.api.ItemID.BURNING_AMULET1; +import static net.runelite.api.ItemID.BURNING_AMULET2; +import static net.runelite.api.ItemID.BURNING_AMULET3; +import static net.runelite.api.ItemID.BURNING_AMULET4; +import static net.runelite.api.ItemID.BURNING_AMULET5; +import static net.runelite.api.ItemID.COMBAT_BRACELET1; +import static net.runelite.api.ItemID.COMBAT_BRACELET2; +import static net.runelite.api.ItemID.COMBAT_BRACELET3; +import static net.runelite.api.ItemID.COMBAT_BRACELET4; +import static net.runelite.api.ItemID.COMBAT_BRACELET5; +import static net.runelite.api.ItemID.COMBAT_BRACELET6; +import static net.runelite.api.ItemID.DIGSITE_PENDANT_1; +import static net.runelite.api.ItemID.DIGSITE_PENDANT_2; +import static net.runelite.api.ItemID.DIGSITE_PENDANT_3; +import static net.runelite.api.ItemID.DIGSITE_PENDANT_4; +import static net.runelite.api.ItemID.DIGSITE_PENDANT_5; +import static net.runelite.api.ItemID.ENCHANTED_LYRE1; +import static net.runelite.api.ItemID.ENCHANTED_LYRE2; +import static net.runelite.api.ItemID.ENCHANTED_LYRE3; +import static net.runelite.api.ItemID.ENCHANTED_LYRE4; +import static net.runelite.api.ItemID.ENCHANTED_LYRE5; +import static net.runelite.api.ItemID.FUNGICIDE_SPRAY_0; +import static net.runelite.api.ItemID.FUNGICIDE_SPRAY_1; +import static net.runelite.api.ItemID.FUNGICIDE_SPRAY_10; +import static net.runelite.api.ItemID.FUNGICIDE_SPRAY_2; +import static net.runelite.api.ItemID.FUNGICIDE_SPRAY_3; +import static net.runelite.api.ItemID.FUNGICIDE_SPRAY_4; +import static net.runelite.api.ItemID.FUNGICIDE_SPRAY_5; +import static net.runelite.api.ItemID.FUNGICIDE_SPRAY_6; +import static net.runelite.api.ItemID.FUNGICIDE_SPRAY_7; +import static net.runelite.api.ItemID.FUNGICIDE_SPRAY_8; +import static net.runelite.api.ItemID.FUNGICIDE_SPRAY_9; +import static net.runelite.api.ItemID.GAMES_NECKLACE1; +import static net.runelite.api.ItemID.GAMES_NECKLACE2; +import static net.runelite.api.ItemID.GAMES_NECKLACE3; +import static net.runelite.api.ItemID.GAMES_NECKLACE4; +import static net.runelite.api.ItemID.GAMES_NECKLACE5; +import static net.runelite.api.ItemID.GAMES_NECKLACE6; +import static net.runelite.api.ItemID.GAMES_NECKLACE7; +import static net.runelite.api.ItemID.GAMES_NECKLACE8; +import static net.runelite.api.ItemID.IMPINABOX1; +import static net.runelite.api.ItemID.IMPINABOX2; +import static net.runelite.api.ItemID.NECKLACE_OF_PASSAGE1; +import static net.runelite.api.ItemID.NECKLACE_OF_PASSAGE2; +import static net.runelite.api.ItemID.NECKLACE_OF_PASSAGE3; +import static net.runelite.api.ItemID.NECKLACE_OF_PASSAGE4; +import static net.runelite.api.ItemID.NECKLACE_OF_PASSAGE5; +import static net.runelite.api.ItemID.OGRE_BELLOWS; +import static net.runelite.api.ItemID.OGRE_BELLOWS_1; +import static net.runelite.api.ItemID.OGRE_BELLOWS_2; +import static net.runelite.api.ItemID.OGRE_BELLOWS_3; +import static net.runelite.api.ItemID.PHARAOHS_SCEPTRE_1; +import static net.runelite.api.ItemID.PHARAOHS_SCEPTRE_2; +import static net.runelite.api.ItemID.PHARAOHS_SCEPTRE_3; +import static net.runelite.api.ItemID.PHARAOHS_SCEPTRE_4; +import static net.runelite.api.ItemID.PHARAOHS_SCEPTRE_5; +import static net.runelite.api.ItemID.PHARAOHS_SCEPTRE_6; +import static net.runelite.api.ItemID.PHARAOHS_SCEPTRE_7; +import static net.runelite.api.ItemID.PHARAOHS_SCEPTRE_8; +import static net.runelite.api.ItemID.RING_OF_DUELING1; +import static net.runelite.api.ItemID.RING_OF_DUELING2; +import static net.runelite.api.ItemID.RING_OF_DUELING3; +import static net.runelite.api.ItemID.RING_OF_DUELING4; +import static net.runelite.api.ItemID.RING_OF_DUELING5; +import static net.runelite.api.ItemID.RING_OF_DUELING6; +import static net.runelite.api.ItemID.RING_OF_DUELING7; +import static net.runelite.api.ItemID.RING_OF_DUELING8; +import static net.runelite.api.ItemID.RING_OF_RETURNING1; +import static net.runelite.api.ItemID.RING_OF_RETURNING2; +import static net.runelite.api.ItemID.RING_OF_RETURNING3; +import static net.runelite.api.ItemID.RING_OF_RETURNING4; +import static net.runelite.api.ItemID.RING_OF_RETURNING5; +import static net.runelite.api.ItemID.RING_OF_WEALTH_1; +import static net.runelite.api.ItemID.RING_OF_WEALTH_2; +import static net.runelite.api.ItemID.RING_OF_WEALTH_3; +import static net.runelite.api.ItemID.RING_OF_WEALTH_4; +import static net.runelite.api.ItemID.RING_OF_WEALTH_5; +import static net.runelite.api.ItemID.SKILLS_NECKLACE1; +import static net.runelite.api.ItemID.SKILLS_NECKLACE2; +import static net.runelite.api.ItemID.SKILLS_NECKLACE3; +import static net.runelite.api.ItemID.SKILLS_NECKLACE4; +import static net.runelite.api.ItemID.SKILLS_NECKLACE5; +import static net.runelite.api.ItemID.SKILLS_NECKLACE6; +import static net.runelite.api.ItemID.SLAYER_RING_1; +import static net.runelite.api.ItemID.SLAYER_RING_2; +import static net.runelite.api.ItemID.SLAYER_RING_3; +import static net.runelite.api.ItemID.SLAYER_RING_4; +import static net.runelite.api.ItemID.SLAYER_RING_5; +import static net.runelite.api.ItemID.SLAYER_RING_6; +import static net.runelite.api.ItemID.SLAYER_RING_7; +import static net.runelite.api.ItemID.SLAYER_RING_8; +import static net.runelite.api.ItemID.TELEPORT_CRYSTAL_1; +import static net.runelite.api.ItemID.TELEPORT_CRYSTAL_2; +import static net.runelite.api.ItemID.TELEPORT_CRYSTAL_3; +import static net.runelite.api.ItemID.TELEPORT_CRYSTAL_4; +import static net.runelite.api.ItemID.TELEPORT_CRYSTAL_5; +import static net.runelite.api.ItemID.WATERING_CAN; +import static net.runelite.api.ItemID.WATERING_CAN1; +import static net.runelite.api.ItemID.WATERING_CAN2; +import static net.runelite.api.ItemID.WATERING_CAN3; +import static net.runelite.api.ItemID.WATERING_CAN4; +import static net.runelite.api.ItemID.WATERING_CAN5; +import static net.runelite.api.ItemID.WATERING_CAN6; +import static net.runelite.api.ItemID.WATERING_CAN7; +import static net.runelite.api.ItemID.WATERING_CAN8; +import static net.runelite.api.ItemID.WATERSKIN0; +import static net.runelite.api.ItemID.WATERSKIN1; +import static net.runelite.api.ItemID.WATERSKIN2; +import static net.runelite.api.ItemID.WATERSKIN3; +import static net.runelite.api.ItemID.WATERSKIN4; import static net.runelite.client.plugins.itemcharges.ItemChargeType.ABYSSAL_BRACELET; import static net.runelite.client.plugins.itemcharges.ItemChargeType.BELLOWS; import static net.runelite.client.plugins.itemcharges.ItemChargeType.FUNGICIDE_SPRAY; diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/itemidentification/ItemIdentification.java b/runelite-client/src/main/java/net/runelite/client/plugins/itemidentification/ItemIdentification.java index 622ab1c04e..d2e9913bbf 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/itemidentification/ItemIdentification.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/itemidentification/ItemIdentification.java @@ -46,7 +46,7 @@ enum ItemIdentification DWARF_WEED_SEED(Type.SEED, "Dwarf", "D", ItemID.DWARF_WEED_SEED), TORSTOL_SEED(Type.SEED, "Torstol", "TOR", ItemID.TORSTOL_SEED), POISON_IVY_SEED(Type.SEED, "Ivy", "I", ItemID.POISON_IVY_SEED), - WHITEBERRY_SEED( Type.SEED, "White", "W", ItemID.WHITEBERRY_SEED), + WHITEBERRY_SEED(Type.SEED, "White", "W", ItemID.WHITEBERRY_SEED), //Herbs GUAM(Type.HERB, "Guam", "G", ItemID.GUAM_LEAF, ItemID.GRIMY_GUAM_LEAF), @@ -92,7 +92,7 @@ enum ItemIdentification final String shortName; final int[] itemIDs; - ItemIdentification(Type type, String medName, String shortName, int ... ids) + ItemIdentification(Type type, String medName, String shortName, int... ids) { this.type = type; this.medName = medName; diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/itemstats/BoostedStatBoost.java b/runelite-client/src/main/java/net/runelite/client/plugins/itemstats/BoostedStatBoost.java index e44c2490ac..c6335672ca 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/itemstats/BoostedStatBoost.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/itemstats/BoostedStatBoost.java @@ -1,51 +1,51 @@ -/* - * Copyright (c) 2016-2018, Adam - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package net.runelite.client.plugins.itemstats; - -import net.runelite.client.plugins.itemstats.delta.DeltaCalculator; -import net.runelite.client.plugins.itemstats.stats.Stat; -import net.runelite.api.Client; - -/** - * A stat boost using the current boosted (or drained) stat. - */ -public class BoostedStatBoost extends StatBoost -{ - private final DeltaCalculator deltaCalculator; - - public BoostedStatBoost(Stat stat, boolean boost, DeltaCalculator deltaCalculator) - { - super(stat, boost); - this.deltaCalculator = deltaCalculator; - } - - @Override - public int heals(Client client) - { - int value = getStat().getValue(client); - return deltaCalculator.calculateDelta(value); - } - -} +/* + * Copyright (c) 2016-2018, Adam + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package net.runelite.client.plugins.itemstats; + +import net.runelite.api.Client; +import net.runelite.client.plugins.itemstats.delta.DeltaCalculator; +import net.runelite.client.plugins.itemstats.stats.Stat; + +/** + * A stat boost using the current boosted (or drained) stat. + */ +public class BoostedStatBoost extends StatBoost +{ + private final DeltaCalculator deltaCalculator; + + public BoostedStatBoost(Stat stat, boolean boost, DeltaCalculator deltaCalculator) + { + super(stat, boost); + this.deltaCalculator = deltaCalculator; + } + + @Override + public int heals(Client client) + { + int value = getStat().getValue(client); + return deltaCalculator.calculateDelta(value); + } + +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/itemstats/Food.java b/runelite-client/src/main/java/net/runelite/client/plugins/itemstats/Food.java index ff3f3fb702..57281769c0 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/itemstats/Food.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/itemstats/Food.java @@ -1,45 +1,45 @@ -/* - * Copyright (c) 2016-2018, Adam - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package net.runelite.client.plugins.itemstats; - -import net.runelite.client.plugins.itemstats.delta.DeltaCalculator; -import net.runelite.api.Client; - -public class Food extends FoodBase -{ - private final DeltaCalculator p; - - public Food(DeltaCalculator p) - { - this.p = p; - } - - @Override - public int heals(Client client) - { - return p.calculateDelta(getStat().getMaximum(client)); - } - -} +/* + * Copyright (c) 2016-2018, Adam + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package net.runelite.client.plugins.itemstats; + +import net.runelite.api.Client; +import net.runelite.client.plugins.itemstats.delta.DeltaCalculator; + +public class Food extends FoodBase +{ + private final DeltaCalculator p; + + public Food(DeltaCalculator p) + { + this.p = p; + } + + @Override + public int heals(Client client) + { + return p.calculateDelta(getStat().getMaximum(client)); + } + +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/itemstats/ItemStatChanges.java b/runelite-client/src/main/java/net/runelite/client/plugins/itemstats/ItemStatChanges.java index bcce08ffe5..c03da92e0f 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/itemstats/ItemStatChanges.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/itemstats/ItemStatChanges.java @@ -30,15 +30,424 @@ import java.util.HashMap; import java.util.HashSet; import java.util.Map; import lombok.extern.slf4j.Slf4j; -import static net.runelite.api.ItemID.*; -import static net.runelite.client.plugins.itemstats.Builders.*; +import static net.runelite.api.ItemID.ADMIRAL_PIE; +import static net.runelite.api.ItemID.AGILITY_POTION1; +import static net.runelite.api.ItemID.AGILITY_POTION2; +import static net.runelite.api.ItemID.AGILITY_POTION3; +import static net.runelite.api.ItemID.AGILITY_POTION4; +import static net.runelite.api.ItemID.ANCHOVIES; +import static net.runelite.api.ItemID.ANCHOVY_PIZZA; +import static net.runelite.api.ItemID.ANGLERFISH; +import static net.runelite.api.ItemID.APPLE_PIE; +import static net.runelite.api.ItemID.ATTACK_POTION1; +import static net.runelite.api.ItemID.ATTACK_POTION2; +import static net.runelite.api.ItemID.ATTACK_POTION3; +import static net.runelite.api.ItemID.ATTACK_POTION4; +import static net.runelite.api.ItemID.AUTUMN_SQIRKJUICE; +import static net.runelite.api.ItemID.BAGUETTE; +import static net.runelite.api.ItemID.BAKED_POTATO; +import static net.runelite.api.ItemID.BANANA; +import static net.runelite.api.ItemID.BANDAGES; +import static net.runelite.api.ItemID.BASS; +import static net.runelite.api.ItemID.BASTION_POTION1; +import static net.runelite.api.ItemID.BASTION_POTION2; +import static net.runelite.api.ItemID.BASTION_POTION3; +import static net.runelite.api.ItemID.BASTION_POTION4; +import static net.runelite.api.ItemID.BATTLEMAGE_POTION1; +import static net.runelite.api.ItemID.BATTLEMAGE_POTION2; +import static net.runelite.api.ItemID.BATTLEMAGE_POTION3; +import static net.runelite.api.ItemID.BATTLEMAGE_POTION4; +import static net.runelite.api.ItemID.BAT_SHISH; +import static net.runelite.api.ItemID.BOTANICAL_PIE; +import static net.runelite.api.ItemID.BOTTLE_OF_WINE; +import static net.runelite.api.ItemID.BRAWK_FISH_3; +import static net.runelite.api.ItemID.BREAD; +import static net.runelite.api.ItemID.CABBAGE; +import static net.runelite.api.ItemID.CABBAGE_1967; +import static net.runelite.api.ItemID.CAKE; +import static net.runelite.api.ItemID.CAVE_EEL; +import static net.runelite.api.ItemID.CAVIAR; +import static net.runelite.api.ItemID.CHEESE; +import static net.runelite.api.ItemID.CHEESETOM_BATTA; +import static net.runelite.api.ItemID.CHILLI_CON_CARNE; +import static net.runelite.api.ItemID.CHILLI_POTATO; +import static net.runelite.api.ItemID.CHOCCHIP_CRUNCHIES; +import static net.runelite.api.ItemID.CHOCICE; +import static net.runelite.api.ItemID.CHOCOLATEY_MILK; +import static net.runelite.api.ItemID.CHOCOLATE_BAR; +import static net.runelite.api.ItemID.CHOCOLATE_BOMB; +import static net.runelite.api.ItemID.CHOCOLATE_CAKE; +import static net.runelite.api.ItemID.CHOCOLATE_SLICE; +import static net.runelite.api.ItemID.CHOC_SATURDAY; +import static net.runelite.api.ItemID.CHOPPED_ONION; +import static net.runelite.api.ItemID.CHOPPED_TOMATO; +import static net.runelite.api.ItemID.CHOPPED_TUNA; +import static net.runelite.api.ItemID.COATED_FROGS_LEGS; +import static net.runelite.api.ItemID.COD; +import static net.runelite.api.ItemID.COMBAT_POTION1; +import static net.runelite.api.ItemID.COMBAT_POTION2; +import static net.runelite.api.ItemID.COMBAT_POTION3; +import static net.runelite.api.ItemID.COMBAT_POTION4; +import static net.runelite.api.ItemID.COOKED_CHICKEN; +import static net.runelite.api.ItemID.COOKED_CHOMPY; +import static net.runelite.api.ItemID.COOKED_CRAB_MEAT; +import static net.runelite.api.ItemID.COOKED_FISHCAKE; +import static net.runelite.api.ItemID.COOKED_JUBBLY; +import static net.runelite.api.ItemID.COOKED_KARAMBWAN; +import static net.runelite.api.ItemID.COOKED_MEAT; +import static net.runelite.api.ItemID.COOKED_RABBIT; +import static net.runelite.api.ItemID.COOKED_SLIMY_EEL; +import static net.runelite.api.ItemID.COOKED_SWEETCORN; +import static net.runelite.api.ItemID.CURRY; +import static net.runelite.api.ItemID.DARK_CRAB; +import static net.runelite.api.ItemID.DEFENCE_POTION1; +import static net.runelite.api.ItemID.DEFENCE_POTION2; +import static net.runelite.api.ItemID.DEFENCE_POTION3; +import static net.runelite.api.ItemID.DEFENCE_POTION4; +import static net.runelite.api.ItemID.DRUNK_DRAGON; +import static net.runelite.api.ItemID.DWELLBERRIES; +import static net.runelite.api.ItemID.EASTER_EGG; +import static net.runelite.api.ItemID.EDIBLE_SEAWEED; +import static net.runelite.api.ItemID.EEL_SUSHI; +import static net.runelite.api.ItemID.EGG_AND_TOMATO; +import static net.runelite.api.ItemID.EGG_POTATO; +import static net.runelite.api.ItemID.ELDER_1; +import static net.runelite.api.ItemID.ELDER_1_20921; +import static net.runelite.api.ItemID.ELDER_2; +import static net.runelite.api.ItemID.ELDER_2_20922; +import static net.runelite.api.ItemID.ELDER_3; +import static net.runelite.api.ItemID.ELDER_3_20923; +import static net.runelite.api.ItemID.ELDER_4; +import static net.runelite.api.ItemID.ELDER_4_20924; +import static net.runelite.api.ItemID.ELDER_POTION_1; +import static net.runelite.api.ItemID.ELDER_POTION_2; +import static net.runelite.api.ItemID.ELDER_POTION_3; +import static net.runelite.api.ItemID.ELDER_POTION_4; +import static net.runelite.api.ItemID.ENERGY_POTION1; +import static net.runelite.api.ItemID.ENERGY_POTION2; +import static net.runelite.api.ItemID.ENERGY_POTION3; +import static net.runelite.api.ItemID.ENERGY_POTION4; +import static net.runelite.api.ItemID.FAT_SNAIL_MEAT; +import static net.runelite.api.ItemID.FIELD_RATION; +import static net.runelite.api.ItemID.FILLETS; +import static net.runelite.api.ItemID.FINGERS; +import static net.runelite.api.ItemID.FISHING_POTION1; +import static net.runelite.api.ItemID.FISHING_POTION2; +import static net.runelite.api.ItemID.FISHING_POTION3; +import static net.runelite.api.ItemID.FISHING_POTION4; +import static net.runelite.api.ItemID.FISH_PIE; +import static net.runelite.api.ItemID.FRIED_MUSHROOMS; +import static net.runelite.api.ItemID.FRIED_ONIONS; +import static net.runelite.api.ItemID.FROGBURGER; +import static net.runelite.api.ItemID.FROGSPAWN_GUMBO; +import static net.runelite.api.ItemID.FROG_SPAWN; +import static net.runelite.api.ItemID.FRUIT_BATTA; +import static net.runelite.api.ItemID.FRUIT_BLAST; +import static net.runelite.api.ItemID.GARDEN_PIE; +import static net.runelite.api.ItemID.GIANT_CARP; +import static net.runelite.api.ItemID.GIRAL_BAT_2; +import static net.runelite.api.ItemID.GOUT_TUBER; +import static net.runelite.api.ItemID.GREEN_GLOOP_SOUP; +import static net.runelite.api.ItemID.GRUBS__LA_MODE; +import static net.runelite.api.ItemID.GUANIC_BAT_0; +import static net.runelite.api.ItemID.GUTHIX_REST1; +import static net.runelite.api.ItemID.GUTHIX_REST2; +import static net.runelite.api.ItemID.GUTHIX_REST3; +import static net.runelite.api.ItemID.GUTHIX_REST4; +import static net.runelite.api.ItemID.HALF_AN_ADMIRAL_PIE; +import static net.runelite.api.ItemID.HALF_AN_APPLE_PIE; +import static net.runelite.api.ItemID.HALF_A_BOTANICAL_PIE; +import static net.runelite.api.ItemID.HALF_A_FISH_PIE; +import static net.runelite.api.ItemID.HALF_A_GARDEN_PIE; +import static net.runelite.api.ItemID.HALF_A_MEAT_PIE; +import static net.runelite.api.ItemID.HALF_A_MUSHROOM_PIE; +import static net.runelite.api.ItemID.HALF_A_REDBERRY_PIE; +import static net.runelite.api.ItemID.HALF_A_SUMMER_PIE; +import static net.runelite.api.ItemID.HALF_A_WILD_PIE; +import static net.runelite.api.ItemID.HERRING; +import static net.runelite.api.ItemID.HUNTER_POTION1; +import static net.runelite.api.ItemID.HUNTER_POTION2; +import static net.runelite.api.ItemID.HUNTER_POTION3; +import static net.runelite.api.ItemID.HUNTER_POTION4; +import static net.runelite.api.ItemID.IMBUED_HEART; +import static net.runelite.api.ItemID.JANGERBERRIES; +import static net.runelite.api.ItemID.JUG_OF_WINE; +import static net.runelite.api.ItemID.KODAI_1; +import static net.runelite.api.ItemID.KODAI_1_20945; +import static net.runelite.api.ItemID.KODAI_2; +import static net.runelite.api.ItemID.KODAI_2_20946; +import static net.runelite.api.ItemID.KODAI_3; +import static net.runelite.api.ItemID.KODAI_3_20947; +import static net.runelite.api.ItemID.KODAI_4; +import static net.runelite.api.ItemID.KODAI_4_20948; +import static net.runelite.api.ItemID.KODAI_POTION_1; +import static net.runelite.api.ItemID.KODAI_POTION_2; +import static net.runelite.api.ItemID.KODAI_POTION_3; +import static net.runelite.api.ItemID.KODAI_POTION_4; +import static net.runelite.api.ItemID.KRYKET_BAT_4; +import static net.runelite.api.ItemID.KYREN_FISH_6; +import static net.runelite.api.ItemID.LAVA_EEL; +import static net.runelite.api.ItemID.LECKISH_FISH_2; +import static net.runelite.api.ItemID.LEMON; +import static net.runelite.api.ItemID.LEMON_CHUNKS; +import static net.runelite.api.ItemID.LEMON_SLICES; +import static net.runelite.api.ItemID.LIME; +import static net.runelite.api.ItemID.LIME_CHUNKS; +import static net.runelite.api.ItemID.LIME_SLICES; +import static net.runelite.api.ItemID.LOACH; +import static net.runelite.api.ItemID.LOBSTER; +import static net.runelite.api.ItemID.MACKEREL; +import static net.runelite.api.ItemID.MAGIC_ESSENCE1; +import static net.runelite.api.ItemID.MAGIC_ESSENCE2; +import static net.runelite.api.ItemID.MAGIC_ESSENCE3; +import static net.runelite.api.ItemID.MAGIC_ESSENCE4; +import static net.runelite.api.ItemID.MAGIC_POTION1; +import static net.runelite.api.ItemID.MAGIC_POTION2; +import static net.runelite.api.ItemID.MAGIC_POTION3; +import static net.runelite.api.ItemID.MAGIC_POTION4; +import static net.runelite.api.ItemID.MANTA_RAY; +import static net.runelite.api.ItemID.MEAT_PIE; +import static net.runelite.api.ItemID.MEAT_PIZZA; +import static net.runelite.api.ItemID.MINT_CAKE; +import static net.runelite.api.ItemID.MONKFISH; +import static net.runelite.api.ItemID.MOONLIGHT_MEAD; +import static net.runelite.api.ItemID.MURNG_BAT_5; +import static net.runelite.api.ItemID.MUSHROOMS; +import static net.runelite.api.ItemID.MUSHROOM_PIE; +import static net.runelite.api.ItemID.MUSHROOM_POTATO; +import static net.runelite.api.ItemID.MUSHROOM__ONION; +import static net.runelite.api.ItemID.MYCIL_FISH_4; +import static net.runelite.api.ItemID.ONION; +import static net.runelite.api.ItemID.ORANGE; +import static net.runelite.api.ItemID.ORANGE_CHUNKS; +import static net.runelite.api.ItemID.ORANGE_SLICES; +import static net.runelite.api.ItemID.OVERLOAD_1; +import static net.runelite.api.ItemID.OVERLOAD_1_20985; +import static net.runelite.api.ItemID.OVERLOAD_1_20989; +import static net.runelite.api.ItemID.OVERLOAD_1_20993; +import static net.runelite.api.ItemID.OVERLOAD_2; +import static net.runelite.api.ItemID.OVERLOAD_2_20986; +import static net.runelite.api.ItemID.OVERLOAD_2_20990; +import static net.runelite.api.ItemID.OVERLOAD_2_20994; +import static net.runelite.api.ItemID.OVERLOAD_3; +import static net.runelite.api.ItemID.OVERLOAD_3_20987; +import static net.runelite.api.ItemID.OVERLOAD_3_20991; +import static net.runelite.api.ItemID.OVERLOAD_3_20995; +import static net.runelite.api.ItemID.OVERLOAD_4; +import static net.runelite.api.ItemID.OVERLOAD_4_20988; +import static net.runelite.api.ItemID.OVERLOAD_4_20992; +import static net.runelite.api.ItemID.OVERLOAD_4_20996; +import static net.runelite.api.ItemID.PAPAYA_FRUIT; +import static net.runelite.api.ItemID.PEACH; +import static net.runelite.api.ItemID.PHLUXIA_BAT_3; +import static net.runelite.api.ItemID.PIKE; +import static net.runelite.api.ItemID.PINEAPPLE_CHUNKS; +import static net.runelite.api.ItemID.PINEAPPLE_PIZZA; +import static net.runelite.api.ItemID.PINEAPPLE_PUNCH; +import static net.runelite.api.ItemID.PINEAPPLE_RING; +import static net.runelite.api.ItemID.PLAIN_PIZZA; +import static net.runelite.api.ItemID.POISON_KARAMBWAN; +import static net.runelite.api.ItemID.POTATO; +import static net.runelite.api.ItemID.POTATO_WITH_BUTTER; +import static net.runelite.api.ItemID.POTATO_WITH_CHEESE; +import static net.runelite.api.ItemID.POT_OF_CREAM; +import static net.runelite.api.ItemID.PRAEL_BAT_1; +import static net.runelite.api.ItemID.PRAYER_POTION1; +import static net.runelite.api.ItemID.PRAYER_POTION2; +import static net.runelite.api.ItemID.PRAYER_POTION3; +import static net.runelite.api.ItemID.PRAYER_POTION4; +import static net.runelite.api.ItemID.PREMADE_CHOC_BOMB; +import static net.runelite.api.ItemID.PREMADE_CHOC_SDY; +import static net.runelite.api.ItemID.PREMADE_CH_CRUNCH; +import static net.runelite.api.ItemID.PREMADE_CT_BATTA; +import static net.runelite.api.ItemID.PREMADE_DR_DRAGON; +import static net.runelite.api.ItemID.PREMADE_FRT_BATTA; +import static net.runelite.api.ItemID.PREMADE_FR_BLAST; +import static net.runelite.api.ItemID.PREMADE_P_PUNCH; +import static net.runelite.api.ItemID.PREMADE_SGG; +import static net.runelite.api.ItemID.PREMADE_SY_CRUNCH; +import static net.runelite.api.ItemID.PREMADE_TD_BATTA; +import static net.runelite.api.ItemID.PREMADE_TD_CRUNCH; +import static net.runelite.api.ItemID.PREMADE_TTL; +import static net.runelite.api.ItemID.PREMADE_VEG_BALL; +import static net.runelite.api.ItemID.PREMADE_VEG_BATTA; +import static net.runelite.api.ItemID.PREMADE_WIZ_BLZD; +import static net.runelite.api.ItemID.PREMADE_WM_BATTA; +import static net.runelite.api.ItemID.PREMADE_WM_CRUN; +import static net.runelite.api.ItemID.PREMADE_WORM_HOLE; +import static net.runelite.api.ItemID.PSYKK_BAT_6; +import static net.runelite.api.ItemID.PUMPKIN; +import static net.runelite.api.ItemID.PURPLE_SWEETS_10476; +import static net.runelite.api.ItemID.PYSK_FISH_0; +import static net.runelite.api.ItemID.RAINBOW_FISH; +import static net.runelite.api.ItemID.RANGING_POTION1; +import static net.runelite.api.ItemID.RANGING_POTION2; +import static net.runelite.api.ItemID.RANGING_POTION3; +import static net.runelite.api.ItemID.RANGING_POTION4; +import static net.runelite.api.ItemID.REDBERRY_PIE; +import static net.runelite.api.ItemID.RESTORE_POTION1; +import static net.runelite.api.ItemID.RESTORE_POTION2; +import static net.runelite.api.ItemID.RESTORE_POTION3; +import static net.runelite.api.ItemID.RESTORE_POTION4; +import static net.runelite.api.ItemID.REVITALISATION_1_20957; +import static net.runelite.api.ItemID.REVITALISATION_2_20958; +import static net.runelite.api.ItemID.REVITALISATION_3_20959; +import static net.runelite.api.ItemID.REVITALISATION_4_20960; +import static net.runelite.api.ItemID.ROAST_BEAST_MEAT; +import static net.runelite.api.ItemID.ROAST_BIRD_MEAT; +import static net.runelite.api.ItemID.ROAST_FROG; +import static net.runelite.api.ItemID.ROAST_RABBIT; +import static net.runelite.api.ItemID.ROE; +import static net.runelite.api.ItemID.ROLL; +import static net.runelite.api.ItemID.ROQED_FISH_5; +import static net.runelite.api.ItemID.SALMON; +import static net.runelite.api.ItemID.SANFEW_SERUM1; +import static net.runelite.api.ItemID.SANFEW_SERUM2; +import static net.runelite.api.ItemID.SANFEW_SERUM3; +import static net.runelite.api.ItemID.SANFEW_SERUM4; +import static net.runelite.api.ItemID.SARADOMIN_BREW1; +import static net.runelite.api.ItemID.SARADOMIN_BREW2; +import static net.runelite.api.ItemID.SARADOMIN_BREW3; +import static net.runelite.api.ItemID.SARADOMIN_BREW4; +import static net.runelite.api.ItemID.SARDINE; +import static net.runelite.api.ItemID.SEA_TURTLE; +import static net.runelite.api.ItemID.SHARK; +import static net.runelite.api.ItemID.SHORT_GREEN_GUY; +import static net.runelite.api.ItemID.SHRIMPS; +import static net.runelite.api.ItemID.SLICED_BANANA; +import static net.runelite.api.ItemID.SLICE_OF_CAKE; +import static net.runelite.api.ItemID.SPICY_CRUNCHIES; +import static net.runelite.api.ItemID.SPICY_SAUCE; +import static net.runelite.api.ItemID.SPICY_STEW; +import static net.runelite.api.ItemID.SPINACH_ROLL; +import static net.runelite.api.ItemID.SPRING_SQIRKJUICE; +import static net.runelite.api.ItemID.SQUARE_SANDWICH; +import static net.runelite.api.ItemID.STAMINA_POTION1; +import static net.runelite.api.ItemID.STAMINA_POTION2; +import static net.runelite.api.ItemID.STAMINA_POTION3; +import static net.runelite.api.ItemID.STAMINA_POTION4; +import static net.runelite.api.ItemID.STEW; +import static net.runelite.api.ItemID.STRANGE_FRUIT; +import static net.runelite.api.ItemID.STRAWBERRY; +import static net.runelite.api.ItemID.STRENGTH_POTION1; +import static net.runelite.api.ItemID.STRENGTH_POTION2; +import static net.runelite.api.ItemID.STRENGTH_POTION3; +import static net.runelite.api.ItemID.STRENGTH_POTION4; +import static net.runelite.api.ItemID.STUFFED_SNAKE; +import static net.runelite.api.ItemID.SUMMER_PIE; +import static net.runelite.api.ItemID.SUMMER_SQIRKJUICE; +import static net.runelite.api.ItemID.SUPER_ATTACK1; +import static net.runelite.api.ItemID.SUPER_ATTACK2; +import static net.runelite.api.ItemID.SUPER_ATTACK3; +import static net.runelite.api.ItemID.SUPER_ATTACK4; +import static net.runelite.api.ItemID.SUPER_COMBAT_POTION1; +import static net.runelite.api.ItemID.SUPER_COMBAT_POTION2; +import static net.runelite.api.ItemID.SUPER_COMBAT_POTION3; +import static net.runelite.api.ItemID.SUPER_COMBAT_POTION4; +import static net.runelite.api.ItemID.SUPER_DEFENCE1; +import static net.runelite.api.ItemID.SUPER_DEFENCE2; +import static net.runelite.api.ItemID.SUPER_DEFENCE3; +import static net.runelite.api.ItemID.SUPER_DEFENCE4; +import static net.runelite.api.ItemID.SUPER_ENERGY1; +import static net.runelite.api.ItemID.SUPER_ENERGY2; +import static net.runelite.api.ItemID.SUPER_ENERGY3; +import static net.runelite.api.ItemID.SUPER_ENERGY4; +import static net.runelite.api.ItemID.SUPER_MAGIC_POTION_1; +import static net.runelite.api.ItemID.SUPER_MAGIC_POTION_2; +import static net.runelite.api.ItemID.SUPER_MAGIC_POTION_3; +import static net.runelite.api.ItemID.SUPER_MAGIC_POTION_4; +import static net.runelite.api.ItemID.SUPER_RANGING_1; +import static net.runelite.api.ItemID.SUPER_RANGING_2; +import static net.runelite.api.ItemID.SUPER_RANGING_3; +import static net.runelite.api.ItemID.SUPER_RANGING_4; +import static net.runelite.api.ItemID.SUPER_RESTORE1; +import static net.runelite.api.ItemID.SUPER_RESTORE2; +import static net.runelite.api.ItemID.SUPER_RESTORE3; +import static net.runelite.api.ItemID.SUPER_RESTORE4; +import static net.runelite.api.ItemID.SUPER_STRENGTH1; +import static net.runelite.api.ItemID.SUPER_STRENGTH2; +import static net.runelite.api.ItemID.SUPER_STRENGTH3; +import static net.runelite.api.ItemID.SUPER_STRENGTH4; +import static net.runelite.api.ItemID.SUPHI_FISH_1; +import static net.runelite.api.ItemID.SWEETCORN_7088; +import static net.runelite.api.ItemID.SWORDFISH; +import static net.runelite.api.ItemID.TANGLED_TOADS_LEGS; +import static net.runelite.api.ItemID.THIN_SNAIL_MEAT; +import static net.runelite.api.ItemID.TOAD_BATTA; +import static net.runelite.api.ItemID.TOAD_CRUNCHIES; +import static net.runelite.api.ItemID.TOMATO; +import static net.runelite.api.ItemID.TRIANGLE_SANDWICH; +import static net.runelite.api.ItemID.TROUT; +import static net.runelite.api.ItemID.TUNA; +import static net.runelite.api.ItemID.TUNA_AND_CORN; +import static net.runelite.api.ItemID.TUNA_POTATO; +import static net.runelite.api.ItemID.TWISTED_1; +import static net.runelite.api.ItemID.TWISTED_1_20933; +import static net.runelite.api.ItemID.TWISTED_2; +import static net.runelite.api.ItemID.TWISTED_2_20934; +import static net.runelite.api.ItemID.TWISTED_3; +import static net.runelite.api.ItemID.TWISTED_3_20935; +import static net.runelite.api.ItemID.TWISTED_4; +import static net.runelite.api.ItemID.TWISTED_4_20936; +import static net.runelite.api.ItemID.TWISTED_POTION_1; +import static net.runelite.api.ItemID.TWISTED_POTION_2; +import static net.runelite.api.ItemID.TWISTED_POTION_3; +import static net.runelite.api.ItemID.TWISTED_POTION_4; +import static net.runelite.api.ItemID.UGTHANKI_KEBAB; +import static net.runelite.api.ItemID.UGTHANKI_KEBAB_1885; +import static net.runelite.api.ItemID.VEGETABLE_BATTA; +import static net.runelite.api.ItemID.VEG_BALL; +import static net.runelite.api.ItemID.WATERMELON_SLICE; +import static net.runelite.api.ItemID.WHITE_TREE_FRUIT; +import static net.runelite.api.ItemID.WILD_PIE; +import static net.runelite.api.ItemID.WINTER_SQIRKJUICE; +import static net.runelite.api.ItemID.WIZARD_BLIZZARD; +import static net.runelite.api.ItemID.WORM_BATTA; +import static net.runelite.api.ItemID.WORM_CRUNCHIES; +import static net.runelite.api.ItemID.WORM_HOLE; +import static net.runelite.api.ItemID.XERICS_AID_1_20981; +import static net.runelite.api.ItemID.XERICS_AID_2_20982; +import static net.runelite.api.ItemID.XERICS_AID_3_20983; +import static net.runelite.api.ItemID.XERICS_AID_4_20984; +import static net.runelite.api.ItemID.ZAMORAK_BREW1; +import static net.runelite.api.ItemID.ZAMORAK_BREW2; +import static net.runelite.api.ItemID.ZAMORAK_BREW3; +import static net.runelite.api.ItemID.ZAMORAK_BREW4; +import static net.runelite.api.ItemID._12_ANCHOVY_PIZZA; +import static net.runelite.api.ItemID._12_MEAT_PIZZA; +import static net.runelite.api.ItemID._12_PINEAPPLE_PIZZA; +import static net.runelite.api.ItemID._12_PLAIN_PIZZA; +import static net.runelite.api.ItemID._23_CAKE; +import static net.runelite.api.ItemID._23_CHOCOLATE_CAKE; +import static net.runelite.client.plugins.itemstats.Builders.boost; +import static net.runelite.client.plugins.itemstats.Builders.combo; +import static net.runelite.client.plugins.itemstats.Builders.dec; +import static net.runelite.client.plugins.itemstats.Builders.food; +import static net.runelite.client.plugins.itemstats.Builders.heal; +import static net.runelite.client.plugins.itemstats.Builders.perc; +import static net.runelite.client.plugins.itemstats.Builders.range; import net.runelite.client.plugins.itemstats.food.Anglerfish; import net.runelite.client.plugins.itemstats.potions.PrayerPotion; import net.runelite.client.plugins.itemstats.potions.SaradominBrew; import net.runelite.client.plugins.itemstats.potions.SuperRestore; import net.runelite.client.plugins.itemstats.special.CastleWarsBandage; import net.runelite.client.plugins.itemstats.special.SpicyStew; -import static net.runelite.client.plugins.itemstats.stats.Stats.*; +import static net.runelite.client.plugins.itemstats.stats.Stats.AGILITY; +import static net.runelite.client.plugins.itemstats.stats.Stats.ATTACK; +import static net.runelite.client.plugins.itemstats.stats.Stats.CRAFTING; +import static net.runelite.client.plugins.itemstats.stats.Stats.DEFENCE; +import static net.runelite.client.plugins.itemstats.stats.Stats.FARMING; +import static net.runelite.client.plugins.itemstats.stats.Stats.FISHING; +import static net.runelite.client.plugins.itemstats.stats.Stats.HERBLORE; +import static net.runelite.client.plugins.itemstats.stats.Stats.HITPOINTS; +import static net.runelite.client.plugins.itemstats.stats.Stats.HUNTER; +import static net.runelite.client.plugins.itemstats.stats.Stats.MAGIC; +import static net.runelite.client.plugins.itemstats.stats.Stats.PRAYER; +import static net.runelite.client.plugins.itemstats.stats.Stats.RANGED; +import static net.runelite.client.plugins.itemstats.stats.Stats.RUN_ENERGY; +import static net.runelite.client.plugins.itemstats.stats.Stats.SLAYER; +import static net.runelite.client.plugins.itemstats.stats.Stats.STRENGTH; +import static net.runelite.client.plugins.itemstats.stats.Stats.THIEVING; @Singleton @Slf4j @@ -54,8 +463,8 @@ public class ItemStatChanges add(food(-5), POISON_KARAMBWAN); add(food(1), POTATO, ONION, CABBAGE, POT_OF_CREAM, CHOPPED_ONION, ANCHOVIES); add(food(2), TOMATO, CHOPPED_TOMATO, BANANA, SLICED_BANANA, ORANGE, ORANGE_SLICES, ORANGE_CHUNKS, - PINEAPPLE_RING, PINEAPPLE_CHUNKS, SPICY_SAUCE, CHEESE, SPINACH_ROLL, LEMON, LEMON_CHUNKS, LEMON_SLICES, - LIME, LIME_CHUNKS, LIME_SLICES, DWELLBERRIES); + PINEAPPLE_RING, PINEAPPLE_CHUNKS, SPICY_SAUCE, CHEESE, SPINACH_ROLL, LEMON, LEMON_CHUNKS, LEMON_SLICES, + LIME, LIME_CHUNKS, LIME_SLICES, DWELLBERRIES); add(food(3), SHRIMPS, COOKED_MEAT, COOKED_CHICKEN, ROE, CHOCOLATE_BAR); add(food(4), SARDINE, CAKE, _23_CAKE, SLICE_OF_CAKE, CHOCOLATEY_MILK, BAKED_POTATO, EDIBLE_SEAWEED, MOONLIGHT_MEAD); add(food(5), BREAD, HERRING, CHOCOLATE_CAKE, _23_CHOCOLATE_CAKE, CHOCOLATE_SLICE, COOKED_RABBIT, CHILLI_CON_CARNE, @@ -95,7 +504,7 @@ public class ItemStatChanges // Dorgeshuun Cuisine add(food(2), BAT_SHISH, COATED_FROGS_LEGS, FILLETS, FINGERS, FROGBURGER, FROGSPAWN_GUMBO, GREEN_GLOOP_SOUP, - GRUBS__LA_MODE, MUSHROOMS, ROAST_FROG); + GRUBS__LA_MODE, MUSHROOMS, ROAST_FROG); add(food(3), LOACH); add(range(food(3), food(6)), FROG_SPAWN); add(range(food(6), food(10)), COOKED_SLIMY_EEL); diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/itemstats/ItemStatConfig.java b/runelite-client/src/main/java/net/runelite/client/plugins/itemstats/ItemStatConfig.java index 3c7d586a86..6b99641473 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/itemstats/ItemStatConfig.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/itemstats/ItemStatConfig.java @@ -1,149 +1,150 @@ -/* - * Copyright (c) 2018 Abex - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package net.runelite.client.plugins.itemstats; - -import java.awt.Color; -import net.runelite.client.config.Config; -import net.runelite.client.config.ConfigGroup; -import net.runelite.client.config.ConfigItem; - -@ConfigGroup("itemstat") -public interface ItemStatConfig extends Config -{ - @ConfigItem( - keyName = "consumableStats", - name = "Enable consumable stats", - description = "Enables tooltips for consumable items (food, boosts)" - ) - default boolean consumableStats() - { - return true; - } - - @ConfigItem( - keyName = "equipmentStats", - name = "Enable equipment stats", - description = "Enables tooltips for equipment items (combat bonuses, weight, prayer bonuses)" - ) - default boolean equipmentStats() - { - return true; - } - - @ConfigItem( - keyName = "geStats", - name = "Enable GE item information", - description = "Shows an item information panel when buying items in the GE" - ) - default boolean geStats() - { - return true; - } - - @ConfigItem( - keyName = "relative", - name = "Show Relative", - description = "Show relative stat change in tooltip" - ) - default boolean relative() - { - return true; - } - - @ConfigItem( - keyName = "absolute", - name = "Show Absolute", - description = "Show absolute stat change in tooltip" - ) - default boolean absolute() - { - return true; - } - - @ConfigItem( - keyName = "theoretical", - name = "Show Theoretical", - description = "Show theoretical stat change in tooltip" - ) - default boolean theoretical() - { - return false; - } - - @ConfigItem( - keyName = "colorBetterUncapped", - name = "Better (Uncapped)", - description = "Color to show when the stat change is fully consumed", - position = 10 - ) - default Color colorBetterUncapped() - { - return new Color(0x33EE33); - } - - @ConfigItem( - keyName = "colorBetterSomecapped", - name = "Better (Some capped)", - description = "Color to show when some stat changes are capped, but some ar not", - position = 11 - ) - default Color colorBetterSomeCapped() - { - return new Color(0x9CEE33); - } - - - @ConfigItem( - keyName = "colorBetterCapped", - name = "Better (Capped)", - description = "Color to show when the stat change is positive, but not fully consumed", - position = 12 - ) - default Color colorBetterCapped() - { - return new Color(0xEEEE33); - } - @ConfigItem( - keyName = "colorNoChange", - name = "No change", - description = "Color to show when there is no change", - position = 13 - ) - default Color colorNoChange() - { - return new Color(0xEEEEEE); - } - - @ConfigItem( - keyName = "colorWorse", - name = "Worse", - description = "Color to show when the stat goes down", - position = 14 - ) - default Color colorWorse() - { - return new Color(0xEE3333); - } -} +/* + * Copyright (c) 2018 Abex + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package net.runelite.client.plugins.itemstats; + +import java.awt.Color; +import net.runelite.client.config.Config; +import net.runelite.client.config.ConfigGroup; +import net.runelite.client.config.ConfigItem; + +@ConfigGroup("itemstat") +public interface ItemStatConfig extends Config +{ + @ConfigItem( + keyName = "consumableStats", + name = "Enable consumable stats", + description = "Enables tooltips for consumable items (food, boosts)" + ) + default boolean consumableStats() + { + return true; + } + + @ConfigItem( + keyName = "equipmentStats", + name = "Enable equipment stats", + description = "Enables tooltips for equipment items (combat bonuses, weight, prayer bonuses)" + ) + default boolean equipmentStats() + { + return true; + } + + @ConfigItem( + keyName = "geStats", + name = "Enable GE item information", + description = "Shows an item information panel when buying items in the GE" + ) + default boolean geStats() + { + return true; + } + + @ConfigItem( + keyName = "relative", + name = "Show Relative", + description = "Show relative stat change in tooltip" + ) + default boolean relative() + { + return true; + } + + @ConfigItem( + keyName = "absolute", + name = "Show Absolute", + description = "Show absolute stat change in tooltip" + ) + default boolean absolute() + { + return true; + } + + @ConfigItem( + keyName = "theoretical", + name = "Show Theoretical", + description = "Show theoretical stat change in tooltip" + ) + default boolean theoretical() + { + return false; + } + + @ConfigItem( + keyName = "colorBetterUncapped", + name = "Better (Uncapped)", + description = "Color to show when the stat change is fully consumed", + position = 10 + ) + default Color colorBetterUncapped() + { + return new Color(0x33EE33); + } + + @ConfigItem( + keyName = "colorBetterSomecapped", + name = "Better (Some capped)", + description = "Color to show when some stat changes are capped, but some ar not", + position = 11 + ) + default Color colorBetterSomeCapped() + { + return new Color(0x9CEE33); + } + + + @ConfigItem( + keyName = "colorBetterCapped", + name = "Better (Capped)", + description = "Color to show when the stat change is positive, but not fully consumed", + position = 12 + ) + default Color colorBetterCapped() + { + return new Color(0xEEEE33); + } + + @ConfigItem( + keyName = "colorNoChange", + name = "No change", + description = "Color to show when there is no change", + position = 13 + ) + default Color colorNoChange() + { + return new Color(0xEEEEEE); + } + + @ConfigItem( + keyName = "colorWorse", + name = "Worse", + description = "Color to show when the stat goes down", + position = 14 + ) + default Color colorWorse() + { + return new Color(0xEE3333); + } +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/itemstats/ItemStatOverlay.java b/runelite-client/src/main/java/net/runelite/client/plugins/itemstats/ItemStatOverlay.java index 206ab6fc13..c7105b474b 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/itemstats/ItemStatOverlay.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/itemstats/ItemStatOverlay.java @@ -1,291 +1,291 @@ -/* - * Copyright (c) 2018 Abex - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package net.runelite.client.plugins.itemstats; - -import com.google.inject.Inject; -import java.awt.Color; -import java.awt.Dimension; -import java.awt.Graphics2D; -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.MenuEntry; -import net.runelite.api.widgets.Widget; -import net.runelite.api.widgets.WidgetInfo; -import net.runelite.client.game.ItemManager; -import net.runelite.client.ui.JagexColors; -import net.runelite.client.ui.overlay.Overlay; -import net.runelite.client.ui.overlay.tooltip.Tooltip; -import net.runelite.client.ui.overlay.tooltip.TooltipManager; -import net.runelite.client.util.ColorUtil; -import net.runelite.http.api.item.ItemEquipmentStats; -import net.runelite.http.api.item.ItemStats; - -public class ItemStatOverlay extends Overlay -{ - // Unarmed attack speed is 6 - private static final ItemStats UNARMED = new ItemStats(false, true, 0, - ItemEquipmentStats.builder() - .aspeed(6) - .build()); - - @Inject - private Client client; - - @Inject - private ItemManager itemManager; - - @Inject - private TooltipManager tooltipManager; - - @Inject - private ItemStatChanges statChanges; - - @Inject - private ItemStatConfig config; - - @Override - public Dimension render(Graphics2D graphics) - { - if (client.isMenuOpen() || (!config.relative() && !config.absolute() && !config.theoretical())) - { - return null; - } - - final MenuEntry[] menu = client.getMenuEntries(); - final int menuSize = menu.length; - - if (menuSize <= 0) - { - return null; - } - - final MenuEntry entry = menu[menuSize - 1]; - final int group = WidgetInfo.TO_GROUP(entry.getParam1()); - final int child = WidgetInfo.TO_CHILD(entry.getParam1()); - final Widget widget = client.getWidget(group, child); - - if (widget == null || (group != WidgetInfo.INVENTORY.getGroupId() && - group != WidgetInfo.EQUIPMENT.getGroupId() && - group != WidgetInfo.EQUIPMENT_INVENTORY_ITEMS_CONTAINER.getGroupId())) - { - return null; - } - - int itemId = entry.getIdentifier(); - - if (group == WidgetInfo.EQUIPMENT.getGroupId()) - { - final Widget widgetItem = widget.getChild(1); - if (widgetItem != null) - { - itemId = widgetItem.getItemId(); - } - } - else if (group == WidgetInfo.EQUIPMENT_INVENTORY_ITEMS_CONTAINER.getGroupId()) - { - final Widget widgetItem = widget.getChild(entry.getParam0()); - if (widgetItem != null) - { - itemId = widgetItem.getItemId(); - } - } - - if (config.consumableStats()) - { - final Effect change = statChanges.get(itemId); - if (change != null) - { - final StringBuilder b = new StringBuilder(); - final StatsChanges statsChanges = change.calculate(client); - - for (final StatChange c : statsChanges.getStatChanges()) - { - b.append(buildStatChangeString(c)); - } - - final String tooltip = b.toString(); - - if (!tooltip.isEmpty()) - { - tooltipManager.add(new Tooltip(tooltip)); - } - } - } - - if (config.equipmentStats()) - { - final ItemStats stats = itemManager.getItemStats(itemId, false); - - if (stats != null) - { - final String tooltip = buildStatBonusString(stats); - - if (!tooltip.isEmpty()) - { - tooltipManager.add(new Tooltip(tooltip)); - } - } - } - - return null; - } - - private String getChangeString( - final String label, - final double value, - final boolean inverse, - final boolean showPercent) - { - final Color plus = Positivity.getColor(config, Positivity.BETTER_UNCAPPED); - final Color minus = Positivity.getColor(config, Positivity.WORSE); - - if (value == 0) - { - return ""; - } - - final Color color; - - if (inverse) - { - color = value > 0 ? minus : plus; - } - else - { - color = value > 0 ? plus : minus; - } - - final String prefix = value > 0 ? "+" : ""; - final String suffix = showPercent ? "%" : ""; - final String valueString = (int)value == value ? String.valueOf((int)value) : String.valueOf(value); - return label + ": " + ColorUtil.wrapWithColorTag(prefix + valueString + suffix, color) + "
"; - } - - private String buildStatBonusString(ItemStats s) - { - final StringBuilder b = new StringBuilder(); - b.append(getChangeString("Weight", s.getWeight(), true, false)); - - ItemStats other = null; - final ItemEquipmentStats currentEquipment = s.getEquipment(); - - ItemContainer c = client.getItemContainer(InventoryID.EQUIPMENT); - if (s.isEquipable() && currentEquipment != null && c != null) - { - final Item[] items = c.getItems(); - final int slot = currentEquipment.getSlot(); - - if (slot != -1 && slot < items.length) - { - final Item item = items[slot]; - if (item != null) - { - other = itemManager.getItemStats(item.getId(), false); - } - } - - if (other == null && slot == EquipmentInventorySlot.WEAPON.getSlotIdx()) - { - // Unarmed - other = UNARMED; - } - } - - final ItemStats subtracted = s.subtract(other); - final ItemEquipmentStats e = subtracted.getEquipment(); - - if (subtracted.isEquipable() && e != null) - { - b.append(getChangeString("Prayer", e.getPrayer(), false, false)); - b.append(getChangeString("Speed", e.getAspeed(), true, false)); - b.append(getChangeString("Melee Str", e.getStr(), false, false)); - b.append(getChangeString("Range Str", e.getRstr(), false, false)); - b.append(getChangeString("Magic Dmg", e.getMdmg(), false, true)); - - if (e.getAstab() != 0 || e.getAslash() != 0 || e.getAcrush() != 0 || e.getAmagic() != 0 || e.getArange() != 0) - { - b.append(ColorUtil.wrapWithColorTag("Attack Bonus
", JagexColors.MENU_TARGET)); - b.append(getChangeString("Stab", e.getAstab(), false, false)); - b.append(getChangeString("Slash", e.getAslash(), false, false)); - b.append(getChangeString("Crush", e.getAcrush(), false, false)); - b.append(getChangeString("Magic", e.getAmagic(), false, false)); - b.append(getChangeString("Range", e.getArange(), false, false)); - } - - if (e.getDstab() != 0 || e.getDslash() != 0 || e.getDcrush() != 0 || e.getDmagic() != 0 || e.getDrange() != 0) - { - b.append(ColorUtil.wrapWithColorTag("Defence Bonus
", JagexColors.MENU_TARGET)); - b.append(getChangeString("Stab", e.getDstab(), false, false)); - b.append(getChangeString("Slash", e.getDslash(), false, false)); - b.append(getChangeString("Crush", e.getDcrush(), false, false)); - b.append(getChangeString("Magic", e.getDmagic(), false, false)); - b.append(getChangeString("Range", e.getDrange(), false, false)); - } - } - - return b.toString(); - } - - private String buildStatChangeString(StatChange c) - { - StringBuilder b = new StringBuilder(); - b.append(ColorUtil.colorTag(Positivity.getColor(config, c.getPositivity()))); - - if (config.relative()) - { - b.append(c.getFormattedRelative()); - } - - if (config.theoretical()) - { - if (config.relative()) - { - b.append("/"); - } - b.append(c.getFormattedTheoretical()); - } - - if (config.absolute() && (config.relative() || config.theoretical())) - { - b.append(" ("); - } - if (config.absolute()) - { - b.append(c.getAbsolute()); - } - - if (config.absolute() && (config.relative() || config.theoretical())) - { - b.append(")"); - } - b.append(" ").append(c.getStat().getName()); - b.append("
"); - - return b.toString(); - } -} +/* + * Copyright (c) 2018 Abex + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package net.runelite.client.plugins.itemstats; + +import com.google.inject.Inject; +import java.awt.Color; +import java.awt.Dimension; +import java.awt.Graphics2D; +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.MenuEntry; +import net.runelite.api.widgets.Widget; +import net.runelite.api.widgets.WidgetInfo; +import net.runelite.client.game.ItemManager; +import net.runelite.client.ui.JagexColors; +import net.runelite.client.ui.overlay.Overlay; +import net.runelite.client.ui.overlay.tooltip.Tooltip; +import net.runelite.client.ui.overlay.tooltip.TooltipManager; +import net.runelite.client.util.ColorUtil; +import net.runelite.http.api.item.ItemEquipmentStats; +import net.runelite.http.api.item.ItemStats; + +public class ItemStatOverlay extends Overlay +{ + // Unarmed attack speed is 6 + private static final ItemStats UNARMED = new ItemStats(false, true, 0, + ItemEquipmentStats.builder() + .aspeed(6) + .build()); + + @Inject + private Client client; + + @Inject + private ItemManager itemManager; + + @Inject + private TooltipManager tooltipManager; + + @Inject + private ItemStatChanges statChanges; + + @Inject + private ItemStatConfig config; + + @Override + public Dimension render(Graphics2D graphics) + { + if (client.isMenuOpen() || (!config.relative() && !config.absolute() && !config.theoretical())) + { + return null; + } + + final MenuEntry[] menu = client.getMenuEntries(); + final int menuSize = menu.length; + + if (menuSize <= 0) + { + return null; + } + + final MenuEntry entry = menu[menuSize - 1]; + final int group = WidgetInfo.TO_GROUP(entry.getParam1()); + final int child = WidgetInfo.TO_CHILD(entry.getParam1()); + final Widget widget = client.getWidget(group, child); + + if (widget == null || (group != WidgetInfo.INVENTORY.getGroupId() && + group != WidgetInfo.EQUIPMENT.getGroupId() && + group != WidgetInfo.EQUIPMENT_INVENTORY_ITEMS_CONTAINER.getGroupId())) + { + return null; + } + + int itemId = entry.getIdentifier(); + + if (group == WidgetInfo.EQUIPMENT.getGroupId()) + { + final Widget widgetItem = widget.getChild(1); + if (widgetItem != null) + { + itemId = widgetItem.getItemId(); + } + } + else if (group == WidgetInfo.EQUIPMENT_INVENTORY_ITEMS_CONTAINER.getGroupId()) + { + final Widget widgetItem = widget.getChild(entry.getParam0()); + if (widgetItem != null) + { + itemId = widgetItem.getItemId(); + } + } + + if (config.consumableStats()) + { + final Effect change = statChanges.get(itemId); + if (change != null) + { + final StringBuilder b = new StringBuilder(); + final StatsChanges statsChanges = change.calculate(client); + + for (final StatChange c : statsChanges.getStatChanges()) + { + b.append(buildStatChangeString(c)); + } + + final String tooltip = b.toString(); + + if (!tooltip.isEmpty()) + { + tooltipManager.add(new Tooltip(tooltip)); + } + } + } + + if (config.equipmentStats()) + { + final ItemStats stats = itemManager.getItemStats(itemId, false); + + if (stats != null) + { + final String tooltip = buildStatBonusString(stats); + + if (!tooltip.isEmpty()) + { + tooltipManager.add(new Tooltip(tooltip)); + } + } + } + + return null; + } + + private String getChangeString( + final String label, + final double value, + final boolean inverse, + final boolean showPercent) + { + final Color plus = Positivity.getColor(config, Positivity.BETTER_UNCAPPED); + final Color minus = Positivity.getColor(config, Positivity.WORSE); + + if (value == 0) + { + return ""; + } + + final Color color; + + if (inverse) + { + color = value > 0 ? minus : plus; + } + else + { + color = value > 0 ? plus : minus; + } + + final String prefix = value > 0 ? "+" : ""; + final String suffix = showPercent ? "%" : ""; + final String valueString = (int) value == value ? String.valueOf((int) value) : String.valueOf(value); + return label + ": " + ColorUtil.wrapWithColorTag(prefix + valueString + suffix, color) + "
"; + } + + private String buildStatBonusString(ItemStats s) + { + final StringBuilder b = new StringBuilder(); + b.append(getChangeString("Weight", s.getWeight(), true, false)); + + ItemStats other = null; + final ItemEquipmentStats currentEquipment = s.getEquipment(); + + ItemContainer c = client.getItemContainer(InventoryID.EQUIPMENT); + if (s.isEquipable() && currentEquipment != null && c != null) + { + final Item[] items = c.getItems(); + final int slot = currentEquipment.getSlot(); + + if (slot != -1 && slot < items.length) + { + final Item item = items[slot]; + if (item != null) + { + other = itemManager.getItemStats(item.getId(), false); + } + } + + if (other == null && slot == EquipmentInventorySlot.WEAPON.getSlotIdx()) + { + // Unarmed + other = UNARMED; + } + } + + final ItemStats subtracted = s.subtract(other); + final ItemEquipmentStats e = subtracted.getEquipment(); + + if (subtracted.isEquipable() && e != null) + { + b.append(getChangeString("Prayer", e.getPrayer(), false, false)); + b.append(getChangeString("Speed", e.getAspeed(), true, false)); + b.append(getChangeString("Melee Str", e.getStr(), false, false)); + b.append(getChangeString("Range Str", e.getRstr(), false, false)); + b.append(getChangeString("Magic Dmg", e.getMdmg(), false, true)); + + if (e.getAstab() != 0 || e.getAslash() != 0 || e.getAcrush() != 0 || e.getAmagic() != 0 || e.getArange() != 0) + { + b.append(ColorUtil.wrapWithColorTag("Attack Bonus
", JagexColors.MENU_TARGET)); + b.append(getChangeString("Stab", e.getAstab(), false, false)); + b.append(getChangeString("Slash", e.getAslash(), false, false)); + b.append(getChangeString("Crush", e.getAcrush(), false, false)); + b.append(getChangeString("Magic", e.getAmagic(), false, false)); + b.append(getChangeString("Range", e.getArange(), false, false)); + } + + if (e.getDstab() != 0 || e.getDslash() != 0 || e.getDcrush() != 0 || e.getDmagic() != 0 || e.getDrange() != 0) + { + b.append(ColorUtil.wrapWithColorTag("Defence Bonus
", JagexColors.MENU_TARGET)); + b.append(getChangeString("Stab", e.getDstab(), false, false)); + b.append(getChangeString("Slash", e.getDslash(), false, false)); + b.append(getChangeString("Crush", e.getDcrush(), false, false)); + b.append(getChangeString("Magic", e.getDmagic(), false, false)); + b.append(getChangeString("Range", e.getDrange(), false, false)); + } + } + + return b.toString(); + } + + private String buildStatChangeString(StatChange c) + { + StringBuilder b = new StringBuilder(); + b.append(ColorUtil.colorTag(Positivity.getColor(config, c.getPositivity()))); + + if (config.relative()) + { + b.append(c.getFormattedRelative()); + } + + if (config.theoretical()) + { + if (config.relative()) + { + b.append("/"); + } + b.append(c.getFormattedTheoretical()); + } + + if (config.absolute() && (config.relative() || config.theoretical())) + { + b.append(" ("); + } + if (config.absolute()) + { + b.append(c.getAbsolute()); + } + + if (config.absolute() && (config.relative() || config.theoretical())) + { + b.append(")"); + } + b.append(" ").append(c.getStat().getName()); + b.append("
"); + + return b.toString(); + } +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/itemstats/ItemStatPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/itemstats/ItemStatPlugin.java index d8facce32a..d38b28dccc 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/itemstats/ItemStatPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/itemstats/ItemStatPlugin.java @@ -1,437 +1,437 @@ -/* - * Copyright (c) 2018 Abex - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package net.runelite.client.plugins.itemstats; - -import com.google.common.collect.ImmutableList; -import com.google.common.collect.ImmutableMap; -import com.google.common.collect.ImmutableSet; -import com.google.inject.Binder; -import com.google.inject.Inject; -import com.google.inject.Provides; -import java.awt.FontMetrics; -import java.util.List; -import java.util.Map; -import java.util.Set; -import net.runelite.api.Client; -import net.runelite.api.FontID; -import net.runelite.api.InventoryID; -import net.runelite.api.Item; -import net.runelite.api.ItemContainer; -import net.runelite.api.ItemID; -import net.runelite.api.SpriteID; -import net.runelite.api.VarPlayer; -import net.runelite.api.Varbits; -import net.runelite.api.events.ConfigChanged; -import net.runelite.api.events.GameTick; -import net.runelite.api.events.ScriptCallbackEvent; -import net.runelite.api.events.VarbitChanged; -import net.runelite.api.widgets.JavaScriptCallback; -import net.runelite.api.widgets.Widget; -import net.runelite.api.widgets.WidgetInfo; -import net.runelite.api.widgets.WidgetTextAlignment; -import net.runelite.api.widgets.WidgetType; -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.plugins.Plugin; -import net.runelite.client.plugins.PluginDescriptor; -import net.runelite.client.ui.FontManager; -import net.runelite.client.ui.JagexColors; -import net.runelite.client.ui.overlay.OverlayManager; -import net.runelite.client.util.StackFormatter; -import net.runelite.http.api.item.ItemEquipmentStats; -import net.runelite.http.api.item.ItemStats; - -@PluginDescriptor( - name = "Item Stats", - description = "Show information about food and potion effects", - tags = {"food", "inventory", "overlay", "potion"} -) -public class ItemStatPlugin extends Plugin -{ - private static final int ORANGE_TEXT = JagexColors.DARK_ORANGE_INTERFACE_TEXT.getRGB(); - private static final int YELLOW_TEXT = JagexColors.YELLOW_INTERFACE_TEXT.getRGB(); - private static final int TEXT_HEIGHT = 11; - - @Inject - private OverlayManager overlayManager; - - @Inject - private ItemStatOverlay overlay; - - @Inject - private Client client; - - @Inject - private ItemManager itemManager; - - @Inject - private ItemStatConfig config; - - @Inject - private ClientThread clientThread; - - private Widget itemInformationTitle; - - @Provides - ItemStatConfig getConfig(ConfigManager configManager) - { - return configManager.getConfig(ItemStatConfig.class); - } - - @Override - public void configure(Binder binder) - { - binder.bind(ItemStatChangesService.class).to(ItemStatChangesServiceImpl.class); - } - - @Override - protected void startUp() throws Exception - { - overlayManager.add(overlay); - } - - @Override - protected void shutDown() throws Exception - { - overlayManager.remove(overlay); - clientThread.invokeLater(this::resetGEInventory); - } - - @Subscribe - public void onConfigChanged(ConfigChanged event) - { - if (event.getKey().equals("geStats")) - { - clientThread.invokeLater(this::resetGEInventory); - } - } - - @Subscribe - public void onGameTick(GameTick event) - { - if (itemInformationTitle != null && config.geStats() - && (client.getWidget(WidgetInfo.GRAND_EXCHANGE_WINDOW_CONTAINER) == null - || client.getWidget(WidgetInfo.GRAND_EXCHANGE_WINDOW_CONTAINER).isHidden())) - { - resetGEInventory(); - } - } - - @Subscribe - public void onVarbitChanged(VarbitChanged event) - { - if (client.getVar(VarPlayer.CURRENT_GE_ITEM) == -1 && config.geStats()) - { - resetGEInventory(); - } - } - - @Subscribe - public void onScriptCallbackEvent(ScriptCallbackEvent event) - { - if (event.getEventName().equals("geBuilt") && config.geStats()) - { - int currentGeItem = client.getVar(VarPlayer.CURRENT_GE_ITEM); - if (currentGeItem != -1 && client.getVar(Varbits.GE_OFFER_CREATION_TYPE) == 0) - { - createItemInformation(currentGeItem); - } - } - } - - private void createItemInformation(int id) - { - final ItemStats itemStats = itemManager.getItemStats(id, false); - - if (itemStats == null || !itemStats.isEquipable()) - { - return; - } - - final ItemEquipmentStats equipmentStats = itemStats.getEquipment(); - - if (equipmentStats == null) - { - return; - } - - final Widget geInv = client.getWidget(WidgetInfo.GRAND_EXCHANGE_INVENTORY_ITEMS_CONTAINER); - - if (geInv == null) - { - return; - } - - final Widget invContainer = getInventoryContainer(); - - if (invContainer == null) - { - return; - } - - invContainer.deleteAllChildren(); - geInv.setHidden(true); - - int yPos = 0; - - final FontMetrics smallFM = client.getCanvas().getFontMetrics(FontManager.getRunescapeSmallFont()); - - // HEADER - - itemInformationTitle = createText(invContainer, "Item Information", FontID.BOLD_12, ORANGE_TEXT, - 8, 8, invContainer.getWidth(), 16); - itemInformationTitle.setYTextAlignment(WidgetTextAlignment.CENTER); - - Widget closeButton = invContainer.createChild(-1, WidgetType.GRAPHIC); - closeButton.setOriginalY(8); - closeButton.setOriginalX(invContainer.getWidth() - 24); - closeButton.setOriginalHeight(16); - closeButton.setOriginalWidth(16); - closeButton.setSpriteId(SpriteID.BOTTOM_LINE_MODE_WINDOW_CLOSE_BUTTON_SMALL); - closeButton.setAction(0, "Close"); - closeButton.setOnMouseOverListener((JavaScriptCallback) (ev) -> - { - closeButton.setSpriteId(SpriteID.BOTTOM_LINE_MODE_WINDOW_CLOSE_BUTTON_SMALL_HOVERED); - }); - closeButton.setOnMouseLeaveListener((JavaScriptCallback) (ev) -> - { - closeButton.setSpriteId(SpriteID.BOTTOM_LINE_MODE_WINDOW_CLOSE_BUTTON_SMALL); - }); - closeButton.setOnOpListener((JavaScriptCallback) (ev) -> resetGEInventory()); - closeButton.setHasListener(true); - closeButton.revalidate(); - - yPos += 15; - - createSeparator(invContainer, yPos); - - // ICON AND TITLE - - yPos += 25; - - Widget icon = invContainer.createChild(-1, WidgetType.GRAPHIC); - icon.setOriginalX(8); - icon.setOriginalY(yPos); - icon.setOriginalWidth(36); - icon.setOriginalHeight(32); - icon.setItemId(id); - icon.setItemQuantityMode(0); - icon.setBorderType(1); - icon.revalidate(); - - Widget itemName = createText(invContainer, itemManager.getItemComposition(id).getName(), FontID.PLAIN_12, ORANGE_TEXT, - 50, yPos, invContainer.getWidth() - 40, 30); - itemName.setYTextAlignment(WidgetTextAlignment.CENTER); - - yPos += 20; - - createSeparator(invContainer, yPos); - - // STATS HEADER - - yPos += 25; - - createText(invContainer, "Attack", FontID.PLAIN_11, ORANGE_TEXT, 5, yPos, 50, -1); - - int defenceXPos = invContainer.getWidth() - (smallFM.stringWidth("Defence") + 5); - createText(invContainer, "Defence", FontID.PLAIN_11, ORANGE_TEXT, defenceXPos, yPos, 50, -1); - - // STYLE BONUSES - - final Set stats = ImmutableSet.of( - "Stab", - "Slash", - "Crush", - "Magic", - "Ranged" - ); - - final List attackStats = ImmutableList.of( - equipmentStats.getAstab(), - equipmentStats.getAslash(), - equipmentStats.getAcrush(), - equipmentStats.getAmagic(), - equipmentStats.getArange() - ); - - final List defenceStats = ImmutableList.of( - equipmentStats.getDstab(), - equipmentStats.getDslash(), - equipmentStats.getDcrush(), - equipmentStats.getDmagic(), - equipmentStats.getDrange() - ); - - int index = 0; - - for (final String stat : stats) - { - yPos += TEXT_HEIGHT + 2; - - // Style label - final Widget styleText = createText(invContainer, stat, FontID.PLAIN_11, ORANGE_TEXT, - 0, yPos, invContainer.getWidth(), -1); - styleText.setXTextAlignment(WidgetTextAlignment.CENTER); - - // Attack bonus - createText(invContainer, attackStats.get(index).toString(), FontID.PLAIN_11, YELLOW_TEXT, - 5, yPos, 50, -1); - - // Defence bonus - final int defenceX = invContainer.getWidth() - (smallFM.stringWidth(defenceStats.get(index).toString()) + 5); - createText(invContainer, defenceStats.get(index).toString(), FontID.PLAIN_11, YELLOW_TEXT, - defenceX, yPos, 50, -1); - - index++; - } - - // MISC BONUSES - - yPos += TEXT_HEIGHT + 8; - - final Map miscStats = ImmutableMap.of( - "Strength", equipmentStats.getStr(), - "Ranged Strength", equipmentStats.getRstr(), - "Magic Damage", equipmentStats.getMdmg(), - "Prayer Bonus", equipmentStats.getPrayer() - ); - - for (final Map.Entry miscStat : miscStats.entrySet()) - { - final String name = miscStat.getKey(); - final String value = miscStat.getValue().toString(); - - // Stat label - createText(invContainer, name, FontID.PLAIN_11, ORANGE_TEXT, 5, yPos, 50, -1); - - // Stat bonus - int valueXPos = invContainer.getWidth() - (smallFM.stringWidth(value) + 5); - createText(invContainer, value, FontID.PLAIN_11, YELLOW_TEXT, valueXPos, yPos, 50, -1); - - yPos += TEXT_HEIGHT + 2; - } - - // COINS - - createSeparator(invContainer, invContainer.getHeight() - 40); - - final String coinText = "You have " + StackFormatter.quantityToRSStackSize(getCurrentGP()) - + (getCurrentGP() == 1 ? " coin." : " coins."); - - final Widget coinWidget = createText(invContainer, coinText, FontID.PLAIN_12, ORANGE_TEXT, - 0, invContainer.getHeight() - 18, invContainer.getWidth(), -1); - - coinWidget.setXTextAlignment(WidgetTextAlignment.CENTER); - } - - private static Widget createText(Widget parent, String text, int fontId, int textColor, - int x, int y, int width, int height) - { - final Widget widget = parent.createChild(-1, WidgetType.TEXT); - widget.setText(text); - widget.setFontId(fontId); - widget.setTextColor(textColor); - widget.setTextShadowed(true); - widget.setOriginalHeight(height == -1 ? TEXT_HEIGHT : height); - widget.setOriginalWidth(width); - widget.setOriginalY(y); - widget.setOriginalX(x); - widget.revalidate(); - return widget; - } - - private static void createSeparator(Widget parent, int y) - { - Widget separator = parent.createChild(-1, WidgetType.GRAPHIC); - separator.setOriginalWidth(parent.getWidth()); - separator.setOriginalY(y); - separator.setOriginalHeight(32); - separator.setSpriteId(SpriteID.UNKNOWN_BORDER_EDGE_HORIZONTAL_995); - separator.revalidate(); - } - - private void resetGEInventory() - { - final Widget invContainer = getInventoryContainer(); - - if (invContainer == null) - { - return; - } - - if (itemInformationTitle != null && invContainer.getChild(0) == itemInformationTitle) - { - invContainer.deleteAllChildren(); - itemInformationTitle = null; - } - - final Widget geInv = client.getWidget(WidgetInfo.GRAND_EXCHANGE_INVENTORY_ITEMS_CONTAINER); - if (geInv != null) - { - geInv.setHidden(false); - } - } - - private int getCurrentGP() - { - final ItemContainer inventory = client.getItemContainer(InventoryID.INVENTORY); - - if (inventory == null) - { - return 0; - } - - for (final Item item : inventory.getItems()) - { - if (item.getId() == ItemID.COINS_995) - { - return item.getQuantity(); - } - } - - return 0; - } - - private Widget getInventoryContainer() - { - if (client.isResized()) - { - if (client.getVar(Varbits.SIDE_PANELS) == 1) - { - return client.getWidget(WidgetInfo.RESIZABLE_VIEWPORT_BOTTOM_LINE_INVENTORY_CONTAINER); - } - else - { - return client.getWidget(WidgetInfo.RESIZABLE_VIEWPORT_INVENTORY_CONTAINER); - } - } - else - { - return client.getWidget(WidgetInfo.FIXED_VIEWPORT_INVENTORY_CONTAINER); - } - } -} +/* + * Copyright (c) 2018 Abex + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package net.runelite.client.plugins.itemstats; + +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableMap; +import com.google.common.collect.ImmutableSet; +import com.google.inject.Binder; +import com.google.inject.Inject; +import com.google.inject.Provides; +import java.awt.FontMetrics; +import java.util.List; +import java.util.Map; +import java.util.Set; +import net.runelite.api.Client; +import net.runelite.api.FontID; +import net.runelite.api.InventoryID; +import net.runelite.api.Item; +import net.runelite.api.ItemContainer; +import net.runelite.api.ItemID; +import net.runelite.api.SpriteID; +import net.runelite.api.VarPlayer; +import net.runelite.api.Varbits; +import net.runelite.api.events.ConfigChanged; +import net.runelite.api.events.GameTick; +import net.runelite.api.events.ScriptCallbackEvent; +import net.runelite.api.events.VarbitChanged; +import net.runelite.api.widgets.JavaScriptCallback; +import net.runelite.api.widgets.Widget; +import net.runelite.api.widgets.WidgetInfo; +import net.runelite.api.widgets.WidgetTextAlignment; +import net.runelite.api.widgets.WidgetType; +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.plugins.Plugin; +import net.runelite.client.plugins.PluginDescriptor; +import net.runelite.client.ui.FontManager; +import net.runelite.client.ui.JagexColors; +import net.runelite.client.ui.overlay.OverlayManager; +import net.runelite.client.util.StackFormatter; +import net.runelite.http.api.item.ItemEquipmentStats; +import net.runelite.http.api.item.ItemStats; + +@PluginDescriptor( + name = "Item Stats", + description = "Show information about food and potion effects", + tags = {"food", "inventory", "overlay", "potion"} +) +public class ItemStatPlugin extends Plugin +{ + private static final int ORANGE_TEXT = JagexColors.DARK_ORANGE_INTERFACE_TEXT.getRGB(); + private static final int YELLOW_TEXT = JagexColors.YELLOW_INTERFACE_TEXT.getRGB(); + private static final int TEXT_HEIGHT = 11; + + @Inject + private OverlayManager overlayManager; + + @Inject + private ItemStatOverlay overlay; + + @Inject + private Client client; + + @Inject + private ItemManager itemManager; + + @Inject + private ItemStatConfig config; + + @Inject + private ClientThread clientThread; + + private Widget itemInformationTitle; + + @Provides + ItemStatConfig getConfig(ConfigManager configManager) + { + return configManager.getConfig(ItemStatConfig.class); + } + + @Override + public void configure(Binder binder) + { + binder.bind(ItemStatChangesService.class).to(ItemStatChangesServiceImpl.class); + } + + @Override + protected void startUp() throws Exception + { + overlayManager.add(overlay); + } + + @Override + protected void shutDown() throws Exception + { + overlayManager.remove(overlay); + clientThread.invokeLater(this::resetGEInventory); + } + + @Subscribe + public void onConfigChanged(ConfigChanged event) + { + if (event.getKey().equals("geStats")) + { + clientThread.invokeLater(this::resetGEInventory); + } + } + + @Subscribe + public void onGameTick(GameTick event) + { + if (itemInformationTitle != null && config.geStats() + && (client.getWidget(WidgetInfo.GRAND_EXCHANGE_WINDOW_CONTAINER) == null + || client.getWidget(WidgetInfo.GRAND_EXCHANGE_WINDOW_CONTAINER).isHidden())) + { + resetGEInventory(); + } + } + + @Subscribe + public void onVarbitChanged(VarbitChanged event) + { + if (client.getVar(VarPlayer.CURRENT_GE_ITEM) == -1 && config.geStats()) + { + resetGEInventory(); + } + } + + @Subscribe + public void onScriptCallbackEvent(ScriptCallbackEvent event) + { + if (event.getEventName().equals("geBuilt") && config.geStats()) + { + int currentGeItem = client.getVar(VarPlayer.CURRENT_GE_ITEM); + if (currentGeItem != -1 && client.getVar(Varbits.GE_OFFER_CREATION_TYPE) == 0) + { + createItemInformation(currentGeItem); + } + } + } + + private void createItemInformation(int id) + { + final ItemStats itemStats = itemManager.getItemStats(id, false); + + if (itemStats == null || !itemStats.isEquipable()) + { + return; + } + + final ItemEquipmentStats equipmentStats = itemStats.getEquipment(); + + if (equipmentStats == null) + { + return; + } + + final Widget geInv = client.getWidget(WidgetInfo.GRAND_EXCHANGE_INVENTORY_ITEMS_CONTAINER); + + if (geInv == null) + { + return; + } + + final Widget invContainer = getInventoryContainer(); + + if (invContainer == null) + { + return; + } + + invContainer.deleteAllChildren(); + geInv.setHidden(true); + + int yPos = 0; + + final FontMetrics smallFM = client.getCanvas().getFontMetrics(FontManager.getRunescapeSmallFont()); + + // HEADER + + itemInformationTitle = createText(invContainer, "Item Information", FontID.BOLD_12, ORANGE_TEXT, + 8, 8, invContainer.getWidth(), 16); + itemInformationTitle.setYTextAlignment(WidgetTextAlignment.CENTER); + + Widget closeButton = invContainer.createChild(-1, WidgetType.GRAPHIC); + closeButton.setOriginalY(8); + closeButton.setOriginalX(invContainer.getWidth() - 24); + closeButton.setOriginalHeight(16); + closeButton.setOriginalWidth(16); + closeButton.setSpriteId(SpriteID.BOTTOM_LINE_MODE_WINDOW_CLOSE_BUTTON_SMALL); + closeButton.setAction(0, "Close"); + closeButton.setOnMouseOverListener((JavaScriptCallback) (ev) -> + { + closeButton.setSpriteId(SpriteID.BOTTOM_LINE_MODE_WINDOW_CLOSE_BUTTON_SMALL_HOVERED); + }); + closeButton.setOnMouseLeaveListener((JavaScriptCallback) (ev) -> + { + closeButton.setSpriteId(SpriteID.BOTTOM_LINE_MODE_WINDOW_CLOSE_BUTTON_SMALL); + }); + closeButton.setOnOpListener((JavaScriptCallback) (ev) -> resetGEInventory()); + closeButton.setHasListener(true); + closeButton.revalidate(); + + yPos += 15; + + createSeparator(invContainer, yPos); + + // ICON AND TITLE + + yPos += 25; + + Widget icon = invContainer.createChild(-1, WidgetType.GRAPHIC); + icon.setOriginalX(8); + icon.setOriginalY(yPos); + icon.setOriginalWidth(36); + icon.setOriginalHeight(32); + icon.setItemId(id); + icon.setItemQuantityMode(0); + icon.setBorderType(1); + icon.revalidate(); + + Widget itemName = createText(invContainer, itemManager.getItemComposition(id).getName(), FontID.PLAIN_12, ORANGE_TEXT, + 50, yPos, invContainer.getWidth() - 40, 30); + itemName.setYTextAlignment(WidgetTextAlignment.CENTER); + + yPos += 20; + + createSeparator(invContainer, yPos); + + // STATS HEADER + + yPos += 25; + + createText(invContainer, "Attack", FontID.PLAIN_11, ORANGE_TEXT, 5, yPos, 50, -1); + + int defenceXPos = invContainer.getWidth() - (smallFM.stringWidth("Defence") + 5); + createText(invContainer, "Defence", FontID.PLAIN_11, ORANGE_TEXT, defenceXPos, yPos, 50, -1); + + // STYLE BONUSES + + final Set stats = ImmutableSet.of( + "Stab", + "Slash", + "Crush", + "Magic", + "Ranged" + ); + + final List attackStats = ImmutableList.of( + equipmentStats.getAstab(), + equipmentStats.getAslash(), + equipmentStats.getAcrush(), + equipmentStats.getAmagic(), + equipmentStats.getArange() + ); + + final List defenceStats = ImmutableList.of( + equipmentStats.getDstab(), + equipmentStats.getDslash(), + equipmentStats.getDcrush(), + equipmentStats.getDmagic(), + equipmentStats.getDrange() + ); + + int index = 0; + + for (final String stat : stats) + { + yPos += TEXT_HEIGHT + 2; + + // Style label + final Widget styleText = createText(invContainer, stat, FontID.PLAIN_11, ORANGE_TEXT, + 0, yPos, invContainer.getWidth(), -1); + styleText.setXTextAlignment(WidgetTextAlignment.CENTER); + + // Attack bonus + createText(invContainer, attackStats.get(index).toString(), FontID.PLAIN_11, YELLOW_TEXT, + 5, yPos, 50, -1); + + // Defence bonus + final int defenceX = invContainer.getWidth() - (smallFM.stringWidth(defenceStats.get(index).toString()) + 5); + createText(invContainer, defenceStats.get(index).toString(), FontID.PLAIN_11, YELLOW_TEXT, + defenceX, yPos, 50, -1); + + index++; + } + + // MISC BONUSES + + yPos += TEXT_HEIGHT + 8; + + final Map miscStats = ImmutableMap.of( + "Strength", equipmentStats.getStr(), + "Ranged Strength", equipmentStats.getRstr(), + "Magic Damage", equipmentStats.getMdmg(), + "Prayer Bonus", equipmentStats.getPrayer() + ); + + for (final Map.Entry miscStat : miscStats.entrySet()) + { + final String name = miscStat.getKey(); + final String value = miscStat.getValue().toString(); + + // Stat label + createText(invContainer, name, FontID.PLAIN_11, ORANGE_TEXT, 5, yPos, 50, -1); + + // Stat bonus + int valueXPos = invContainer.getWidth() - (smallFM.stringWidth(value) + 5); + createText(invContainer, value, FontID.PLAIN_11, YELLOW_TEXT, valueXPos, yPos, 50, -1); + + yPos += TEXT_HEIGHT + 2; + } + + // COINS + + createSeparator(invContainer, invContainer.getHeight() - 40); + + final String coinText = "You have " + StackFormatter.quantityToRSStackSize(getCurrentGP()) + + (getCurrentGP() == 1 ? " coin." : " coins."); + + final Widget coinWidget = createText(invContainer, coinText, FontID.PLAIN_12, ORANGE_TEXT, + 0, invContainer.getHeight() - 18, invContainer.getWidth(), -1); + + coinWidget.setXTextAlignment(WidgetTextAlignment.CENTER); + } + + private static Widget createText(Widget parent, String text, int fontId, int textColor, + int x, int y, int width, int height) + { + final Widget widget = parent.createChild(-1, WidgetType.TEXT); + widget.setText(text); + widget.setFontId(fontId); + widget.setTextColor(textColor); + widget.setTextShadowed(true); + widget.setOriginalHeight(height == -1 ? TEXT_HEIGHT : height); + widget.setOriginalWidth(width); + widget.setOriginalY(y); + widget.setOriginalX(x); + widget.revalidate(); + return widget; + } + + private static void createSeparator(Widget parent, int y) + { + Widget separator = parent.createChild(-1, WidgetType.GRAPHIC); + separator.setOriginalWidth(parent.getWidth()); + separator.setOriginalY(y); + separator.setOriginalHeight(32); + separator.setSpriteId(SpriteID.UNKNOWN_BORDER_EDGE_HORIZONTAL_995); + separator.revalidate(); + } + + private void resetGEInventory() + { + final Widget invContainer = getInventoryContainer(); + + if (invContainer == null) + { + return; + } + + if (itemInformationTitle != null && invContainer.getChild(0) == itemInformationTitle) + { + invContainer.deleteAllChildren(); + itemInformationTitle = null; + } + + final Widget geInv = client.getWidget(WidgetInfo.GRAND_EXCHANGE_INVENTORY_ITEMS_CONTAINER); + if (geInv != null) + { + geInv.setHidden(false); + } + } + + private int getCurrentGP() + { + final ItemContainer inventory = client.getItemContainer(InventoryID.INVENTORY); + + if (inventory == null) + { + return 0; + } + + for (final Item item : inventory.getItems()) + { + if (item.getId() == ItemID.COINS_995) + { + return item.getQuantity(); + } + } + + return 0; + } + + private Widget getInventoryContainer() + { + if (client.isResized()) + { + if (client.getVar(Varbits.SIDE_PANELS) == 1) + { + return client.getWidget(WidgetInfo.RESIZABLE_VIEWPORT_BOTTOM_LINE_INVENTORY_CONTAINER); + } + else + { + return client.getWidget(WidgetInfo.RESIZABLE_VIEWPORT_INVENTORY_CONTAINER); + } + } + else + { + return client.getWidget(WidgetInfo.FIXED_VIEWPORT_INVENTORY_CONTAINER); + } + } +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/itemstats/SimpleStatBoost.java b/runelite-client/src/main/java/net/runelite/client/plugins/itemstats/SimpleStatBoost.java index 5eef493983..617f930c95 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/itemstats/SimpleStatBoost.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/itemstats/SimpleStatBoost.java @@ -1,51 +1,51 @@ -/* - * Copyright (c) 2016-2018, Adam - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package net.runelite.client.plugins.itemstats; - -import net.runelite.client.plugins.itemstats.delta.DeltaCalculator; -import net.runelite.client.plugins.itemstats.stats.Stat; -import net.runelite.api.Client; - -/** - * A stat boost using the real stat level. Eg, non-boosted. - */ -public class SimpleStatBoost extends StatBoost -{ - private final DeltaCalculator deltaCalculator; - - public SimpleStatBoost(Stat stat, boolean boost, DeltaCalculator deltaCalculator) - { - super(stat, boost); - this.deltaCalculator = deltaCalculator; - } - - @Override - public int heals(Client client) - { - int max = getStat().getMaximum(client); - return deltaCalculator.calculateDelta(max); - } - -} +/* + * Copyright (c) 2016-2018, Adam + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package net.runelite.client.plugins.itemstats; + +import net.runelite.api.Client; +import net.runelite.client.plugins.itemstats.delta.DeltaCalculator; +import net.runelite.client.plugins.itemstats.stats.Stat; + +/** + * A stat boost using the real stat level. Eg, non-boosted. + */ +public class SimpleStatBoost extends StatBoost +{ + private final DeltaCalculator deltaCalculator; + + public SimpleStatBoost(Stat stat, boolean boost, DeltaCalculator deltaCalculator) + { + super(stat, boost); + this.deltaCalculator = deltaCalculator; + } + + @Override + public int heals(Client client) + { + int max = getStat().getMaximum(client); + return deltaCalculator.calculateDelta(max); + } + +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/itemstats/StatBoost.java b/runelite-client/src/main/java/net/runelite/client/plugins/itemstats/StatBoost.java index cc5f7797f2..f6316dac55 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/itemstats/StatBoost.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/itemstats/StatBoost.java @@ -1,96 +1,96 @@ -/* - * Copyright (c) 2016-2018, Adam - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package net.runelite.client.plugins.itemstats; - -import lombok.Getter; -import lombok.Setter; -import net.runelite.client.plugins.itemstats.stats.Stat; -import net.runelite.api.Client; - -public abstract class StatBoost extends SingleEffect -{ - @Getter - @Setter - private Stat stat; - @Getter - @Setter - private boolean boost; - - public StatBoost(Stat stat, boolean boost) - { - this.stat = stat; - this.boost = boost; - } - - public abstract int heals(Client client); - - @Override - public StatChange effect(Client client) - { - int value = stat.getValue(client); - int max = stat.getMaximum(client); - - boolean hitCap = false; - - int calcedDelta = heals(client); - if (boost && calcedDelta > 0) - { - max += calcedDelta; - } - if (value > max) - { - max = value; - } - int newValue = value + calcedDelta; - if (newValue > max) - { - newValue = max; - hitCap = true; - } - if (newValue < 0) - { - newValue = 0; - } - int delta = newValue - value; - StatChange out = new StatChange(); - out.setStat(stat); - if (delta > 0) - { - out.setPositivity(hitCap ? Positivity.BETTER_CAPPED : Positivity.BETTER_UNCAPPED); - } - else if (delta == 0) - { - out.setPositivity(Positivity.NO_CHANGE); - } - else - { - out.setPositivity(Positivity.WORSE); - } - out.setAbsolute(newValue); - out.setRelative(delta); - out.setTheoretical(calcedDelta); - return out; - } -} +/* + * Copyright (c) 2016-2018, Adam + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package net.runelite.client.plugins.itemstats; + +import lombok.Getter; +import lombok.Setter; +import net.runelite.api.Client; +import net.runelite.client.plugins.itemstats.stats.Stat; + +public abstract class StatBoost extends SingleEffect +{ + @Getter + @Setter + private Stat stat; + @Getter + @Setter + private boolean boost; + + public StatBoost(Stat stat, boolean boost) + { + this.stat = stat; + this.boost = boost; + } + + public abstract int heals(Client client); + + @Override + public StatChange effect(Client client) + { + int value = stat.getValue(client); + int max = stat.getMaximum(client); + + boolean hitCap = false; + + int calcedDelta = heals(client); + if (boost && calcedDelta > 0) + { + max += calcedDelta; + } + if (value > max) + { + max = value; + } + int newValue = value + calcedDelta; + if (newValue > max) + { + newValue = max; + hitCap = true; + } + if (newValue < 0) + { + newValue = 0; + } + int delta = newValue - value; + StatChange out = new StatChange(); + out.setStat(stat); + if (delta > 0) + { + out.setPositivity(hitCap ? Positivity.BETTER_CAPPED : Positivity.BETTER_UNCAPPED); + } + else if (delta == 0) + { + out.setPositivity(Positivity.NO_CHANGE); + } + else + { + out.setPositivity(Positivity.WORSE); + } + out.setAbsolute(newValue); + out.setRelative(delta); + out.setTheoretical(calcedDelta); + return out; + } +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/itemstats/potions/SaradominBrew.java b/runelite-client/src/main/java/net/runelite/client/plugins/itemstats/potions/SaradominBrew.java index 74a13531f2..ea6f4364fe 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/itemstats/potions/SaradominBrew.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/itemstats/potions/SaradominBrew.java @@ -1,79 +1,84 @@ -/* - * Copyright (c) 2016-2018, Adam - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package net.runelite.client.plugins.itemstats.potions; - -import java.util.Comparator; -import java.util.stream.Stream; -import lombok.RequiredArgsConstructor; -import net.runelite.api.Client; -import static net.runelite.client.plugins.itemstats.Builders.perc; -import net.runelite.client.plugins.itemstats.Effect; -import net.runelite.client.plugins.itemstats.SimpleStatBoost; -import net.runelite.client.plugins.itemstats.BoostedStatBoost; -import net.runelite.client.plugins.itemstats.stats.Stat; -import net.runelite.client.plugins.itemstats.StatChange; -import static net.runelite.client.plugins.itemstats.stats.Stats.*; -import net.runelite.client.plugins.itemstats.StatsChanges; - -@RequiredArgsConstructor -public class SaradominBrew implements Effect -{ - private static final Stat[] saradominBrewStats = new Stat[] - { - ATTACK, STRENGTH, RANGED, MAGIC - }; - - private final double percH; //percentage heal - private final double percD; //percentage defence boost - private final double percSD; //percentage stat drain - private final int deltaB; //delta boosted - private final int deltaR; //delta reduced - - @Override - public StatsChanges calculate(Client client) - { - StatsChanges changes = new StatsChanges(0); - SimpleStatBoost hitpoints = new SimpleStatBoost(HITPOINTS, true, perc(percH, deltaB)); - SimpleStatBoost defence = new SimpleStatBoost(DEFENCE, true, perc(percD, deltaB)); - BoostedStatBoost calc = new BoostedStatBoost(null, false, perc(percSD, -deltaR)); - changes.setStatChanges(Stream.concat( - Stream.of(hitpoints.effect(client)), - Stream.concat( - Stream.of(defence.effect(client)), - Stream.of(saradominBrewStats) - .filter(stat -> 1 < stat.getValue(client)) - .map(stat -> - { - calc.setStat(stat); - return calc.effect(client); - }) - ) - ).toArray(StatChange[]::new)); - changes.setPositivity(Stream.of(changes.getStatChanges()) - .map(sc -> sc.getPositivity()) - .max(Comparator.comparing(Enum::ordinal)).get()); - return changes; - } +/* + * Copyright (c) 2016-2018, Adam + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package net.runelite.client.plugins.itemstats.potions; + +import java.util.Comparator; +import java.util.stream.Stream; +import lombok.RequiredArgsConstructor; +import net.runelite.api.Client; +import net.runelite.client.plugins.itemstats.BoostedStatBoost; +import static net.runelite.client.plugins.itemstats.Builders.perc; +import net.runelite.client.plugins.itemstats.Effect; +import net.runelite.client.plugins.itemstats.SimpleStatBoost; +import net.runelite.client.plugins.itemstats.StatChange; +import net.runelite.client.plugins.itemstats.StatsChanges; +import net.runelite.client.plugins.itemstats.stats.Stat; +import static net.runelite.client.plugins.itemstats.stats.Stats.ATTACK; +import static net.runelite.client.plugins.itemstats.stats.Stats.DEFENCE; +import static net.runelite.client.plugins.itemstats.stats.Stats.HITPOINTS; +import static net.runelite.client.plugins.itemstats.stats.Stats.MAGIC; +import static net.runelite.client.plugins.itemstats.stats.Stats.RANGED; +import static net.runelite.client.plugins.itemstats.stats.Stats.STRENGTH; + +@RequiredArgsConstructor +public class SaradominBrew implements Effect +{ + private static final Stat[] saradominBrewStats = new Stat[] + { + ATTACK, STRENGTH, RANGED, MAGIC + }; + + private final double percH; //percentage heal + private final double percD; //percentage defence boost + private final double percSD; //percentage stat drain + private final int deltaB; //delta boosted + private final int deltaR; //delta reduced + + @Override + public StatsChanges calculate(Client client) + { + StatsChanges changes = new StatsChanges(0); + SimpleStatBoost hitpoints = new SimpleStatBoost(HITPOINTS, true, perc(percH, deltaB)); + SimpleStatBoost defence = new SimpleStatBoost(DEFENCE, true, perc(percD, deltaB)); + BoostedStatBoost calc = new BoostedStatBoost(null, false, perc(percSD, -deltaR)); + changes.setStatChanges(Stream.concat( + Stream.of(hitpoints.effect(client)), + Stream.concat( + Stream.of(defence.effect(client)), + Stream.of(saradominBrewStats) + .filter(stat -> 1 < stat.getValue(client)) + .map(stat -> + { + calc.setStat(stat); + return calc.effect(client); + }) + ) + ).toArray(StatChange[]::new)); + changes.setPositivity(Stream.of(changes.getStatChanges()) + .map(sc -> sc.getPositivity()) + .max(Comparator.comparing(Enum::ordinal)).get()); + return changes; + } } \ No newline at end of file diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/itemstats/potions/SuperRestore.java b/runelite-client/src/main/java/net/runelite/client/plugins/itemstats/potions/SuperRestore.java index b63cd0c2c9..c3e06e2c28 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/itemstats/potions/SuperRestore.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/itemstats/potions/SuperRestore.java @@ -1,74 +1,94 @@ -/* - * Copyright (c) 2016-2018, Adam - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package net.runelite.client.plugins.itemstats.potions; - -import java.util.Comparator; -import java.util.stream.Stream; -import lombok.RequiredArgsConstructor; -import net.runelite.api.Client; -import static net.runelite.client.plugins.itemstats.Builders.perc; -import net.runelite.client.plugins.itemstats.Effect; -import net.runelite.client.plugins.itemstats.SimpleStatBoost; -import net.runelite.client.plugins.itemstats.stats.Stat; -import net.runelite.client.plugins.itemstats.StatChange; -import static net.runelite.client.plugins.itemstats.stats.Stats.*; -import net.runelite.client.plugins.itemstats.StatsChanges; - -@RequiredArgsConstructor -public class SuperRestore implements Effect -{ - private static final Stat[] superRestoreStats = new Stat[] - { - ATTACK, DEFENCE, STRENGTH, RANGED, MAGIC, COOKING, - WOODCUTTING, FLETCHING, FISHING, FIREMAKING, CRAFTING, SMITHING, MINING, - HERBLORE, AGILITY, THIEVING, SLAYER, FARMING, RUNECRAFT, HUNTER, - CONSTRUCTION - }; - - private final double percR; //percentage restored - private final int delta; - - @Override - public StatsChanges calculate(Client client) - { - StatsChanges changes = new StatsChanges(0); - - SimpleStatBoost calc = new SimpleStatBoost(null, false, perc(percR, delta)); - PrayerPotion prayer = new PrayerPotion(delta); - changes.setStatChanges(Stream.concat( - Stream.of(prayer.effect(client)), - Stream.of(superRestoreStats) - .filter(stat -> stat.getValue(client) < stat.getMaximum(client)) - .map(stat -> - { - calc.setStat(stat); - return calc.effect(client); - }) - ).toArray(StatChange[]::new)); - changes.setPositivity(Stream.of(changes.getStatChanges()).map(sc -> sc.getPositivity()).max(Comparator.comparing(Enum::ordinal)).get()); - return changes; - } - -} +/* + * Copyright (c) 2016-2018, Adam + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package net.runelite.client.plugins.itemstats.potions; + +import java.util.Comparator; +import java.util.stream.Stream; +import lombok.RequiredArgsConstructor; +import net.runelite.api.Client; +import static net.runelite.client.plugins.itemstats.Builders.perc; +import net.runelite.client.plugins.itemstats.Effect; +import net.runelite.client.plugins.itemstats.SimpleStatBoost; +import net.runelite.client.plugins.itemstats.StatChange; +import net.runelite.client.plugins.itemstats.StatsChanges; +import net.runelite.client.plugins.itemstats.stats.Stat; +import static net.runelite.client.plugins.itemstats.stats.Stats.AGILITY; +import static net.runelite.client.plugins.itemstats.stats.Stats.ATTACK; +import static net.runelite.client.plugins.itemstats.stats.Stats.CONSTRUCTION; +import static net.runelite.client.plugins.itemstats.stats.Stats.COOKING; +import static net.runelite.client.plugins.itemstats.stats.Stats.CRAFTING; +import static net.runelite.client.plugins.itemstats.stats.Stats.DEFENCE; +import static net.runelite.client.plugins.itemstats.stats.Stats.FARMING; +import static net.runelite.client.plugins.itemstats.stats.Stats.FIREMAKING; +import static net.runelite.client.plugins.itemstats.stats.Stats.FISHING; +import static net.runelite.client.plugins.itemstats.stats.Stats.FLETCHING; +import static net.runelite.client.plugins.itemstats.stats.Stats.HERBLORE; +import static net.runelite.client.plugins.itemstats.stats.Stats.HUNTER; +import static net.runelite.client.plugins.itemstats.stats.Stats.MAGIC; +import static net.runelite.client.plugins.itemstats.stats.Stats.MINING; +import static net.runelite.client.plugins.itemstats.stats.Stats.RANGED; +import static net.runelite.client.plugins.itemstats.stats.Stats.RUNECRAFT; +import static net.runelite.client.plugins.itemstats.stats.Stats.SLAYER; +import static net.runelite.client.plugins.itemstats.stats.Stats.SMITHING; +import static net.runelite.client.plugins.itemstats.stats.Stats.STRENGTH; +import static net.runelite.client.plugins.itemstats.stats.Stats.THIEVING; +import static net.runelite.client.plugins.itemstats.stats.Stats.WOODCUTTING; + +@RequiredArgsConstructor +public class SuperRestore implements Effect +{ + private static final Stat[] superRestoreStats = new Stat[] + { + ATTACK, DEFENCE, STRENGTH, RANGED, MAGIC, COOKING, + WOODCUTTING, FLETCHING, FISHING, FIREMAKING, CRAFTING, SMITHING, MINING, + HERBLORE, AGILITY, THIEVING, SLAYER, FARMING, RUNECRAFT, HUNTER, + CONSTRUCTION + }; + + private final double percR; //percentage restored + private final int delta; + + @Override + public StatsChanges calculate(Client client) + { + StatsChanges changes = new StatsChanges(0); + + SimpleStatBoost calc = new SimpleStatBoost(null, false, perc(percR, delta)); + PrayerPotion prayer = new PrayerPotion(delta); + changes.setStatChanges(Stream.concat( + Stream.of(prayer.effect(client)), + Stream.of(superRestoreStats) + .filter(stat -> stat.getValue(client) < stat.getMaximum(client)) + .map(stat -> + { + calc.setStat(stat); + return calc.effect(client); + }) + ).toArray(StatChange[]::new)); + changes.setPositivity(Stream.of(changes.getStatChanges()).map(sc -> sc.getPositivity()).max(Comparator.comparing(Enum::ordinal)).get()); + return changes; + } + +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/itemstats/special/CastleWarsBandage.java b/runelite-client/src/main/java/net/runelite/client/plugins/itemstats/special/CastleWarsBandage.java index e66f9ed709..ea7f9e0985 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/itemstats/special/CastleWarsBandage.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/itemstats/special/CastleWarsBandage.java @@ -1,85 +1,85 @@ -/* - * Copyright (c) 2019, Giovds - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package net.runelite.client.plugins.itemstats.special; - -import com.google.common.collect.ImmutableSet; -import java.util.Comparator; -import java.util.stream.Stream; -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 static net.runelite.client.plugins.itemstats.Builders.heal; -import static net.runelite.client.plugins.itemstats.Builders.perc; -import net.runelite.client.plugins.itemstats.Effect; -import net.runelite.client.plugins.itemstats.StatChange; -import net.runelite.client.plugins.itemstats.StatsChanges; -import static net.runelite.client.plugins.itemstats.stats.Stats.HITPOINTS; -import static net.runelite.client.plugins.itemstats.stats.Stats.RUN_ENERGY; - -public class CastleWarsBandage implements Effect -{ - private static final ImmutableSet BRACELETS = ImmutableSet.of( - ItemID.CASTLE_WARS_BRACELET1, ItemID.CASTLE_WARS_BRACELET2, ItemID.CASTLE_WARS_BRACELET3 - ); - - private static final double BASE_HP_PERC = .10; - private static final double BRACELET_HP_PERC = .50; - - @Override - public StatsChanges calculate(Client client) - { - final ItemContainer equipmentContainer = client.getItemContainer(InventoryID.EQUIPMENT); - final double percH = hasBracelet(equipmentContainer) ? BRACELET_HP_PERC : BASE_HP_PERC; - final StatChange hitPoints = heal(HITPOINTS, perc(percH, 0)).effect(client); - final StatChange runEnergy = heal(RUN_ENERGY, 30).effect(client); - final StatsChanges changes = new StatsChanges(2); - changes.setStatChanges(new StatChange[]{hitPoints, runEnergy}); - changes.setPositivity(Stream.of(changes.getStatChanges()) - .map(StatChange::getPositivity) - .max(Comparator.comparing(Enum::ordinal)).get()); - - return changes; - } - - private boolean hasBracelet(ItemContainer equipmentContainer) - { - if (equipmentContainer == null) - { - return false; - } - - final Item[] equipment = equipmentContainer.getItems(); - - if (equipment.length > EquipmentInventorySlot.GLOVES.getSlotIdx()) - { - return BRACELETS.contains(equipment[EquipmentInventorySlot.GLOVES.getSlotIdx()].getId()); - } - - return false; - } +/* + * Copyright (c) 2019, Giovds + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package net.runelite.client.plugins.itemstats.special; + +import com.google.common.collect.ImmutableSet; +import java.util.Comparator; +import java.util.stream.Stream; +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 static net.runelite.client.plugins.itemstats.Builders.heal; +import static net.runelite.client.plugins.itemstats.Builders.perc; +import net.runelite.client.plugins.itemstats.Effect; +import net.runelite.client.plugins.itemstats.StatChange; +import net.runelite.client.plugins.itemstats.StatsChanges; +import static net.runelite.client.plugins.itemstats.stats.Stats.HITPOINTS; +import static net.runelite.client.plugins.itemstats.stats.Stats.RUN_ENERGY; + +public class CastleWarsBandage implements Effect +{ + private static final ImmutableSet BRACELETS = ImmutableSet.of( + ItemID.CASTLE_WARS_BRACELET1, ItemID.CASTLE_WARS_BRACELET2, ItemID.CASTLE_WARS_BRACELET3 + ); + + private static final double BASE_HP_PERC = .10; + private static final double BRACELET_HP_PERC = .50; + + @Override + public StatsChanges calculate(Client client) + { + final ItemContainer equipmentContainer = client.getItemContainer(InventoryID.EQUIPMENT); + final double percH = hasBracelet(equipmentContainer) ? BRACELET_HP_PERC : BASE_HP_PERC; + final StatChange hitPoints = heal(HITPOINTS, perc(percH, 0)).effect(client); + final StatChange runEnergy = heal(RUN_ENERGY, 30).effect(client); + final StatsChanges changes = new StatsChanges(2); + changes.setStatChanges(new StatChange[]{hitPoints, runEnergy}); + changes.setPositivity(Stream.of(changes.getStatChanges()) + .map(StatChange::getPositivity) + .max(Comparator.comparing(Enum::ordinal)).get()); + + return changes; + } + + private boolean hasBracelet(ItemContainer equipmentContainer) + { + if (equipmentContainer == null) + { + return false; + } + + final Item[] equipment = equipmentContainer.getItems(); + + if (equipment.length > EquipmentInventorySlot.GLOVES.getSlotIdx()) + { + return BRACELETS.contains(equipment[EquipmentInventorySlot.GLOVES.getSlotIdx()].getId()); + } + + return false; + } } \ No newline at end of file diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/itemstats/special/SpicyStew.java b/runelite-client/src/main/java/net/runelite/client/plugins/itemstats/special/SpicyStew.java index 7eee548751..2a10b63489 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/itemstats/special/SpicyStew.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/itemstats/special/SpicyStew.java @@ -1,161 +1,165 @@ -/* - * Copyright (c) 2018, Adam - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package net.runelite.client.plugins.itemstats.special; - -import java.util.ArrayList; -import java.util.List; -import net.runelite.api.Client; -import net.runelite.api.Varbits; -import net.runelite.client.plugins.itemstats.*; -import net.runelite.client.plugins.itemstats.stats.Stat; -import net.runelite.client.plugins.itemstats.stats.Stats; - -public class SpicyStew implements Effect -{ - - @Override - public StatsChanges calculate(Client client) - { - /* - * Spice boosts listed in the colour order of [Spicy stew -> Smell] - */ - int redBoost = spiceBoostOf(client.getVar(Varbits.SPICY_STEW_RED_SPICES)); - int yellowBoost = spiceBoostOf(client.getVar(Varbits.SPICY_STEW_YELLOW_SPICES)); - int orangeBoost = spiceBoostOf(client.getVar(Varbits.SPICY_STEW_ORANGE_SPICES)); - int brownBoost = spiceBoostOf(client.getVar(Varbits.SPICY_STEW_BROWN_SPICES)); - - List changes = new ArrayList<>(); - - /* - * Red spices: Attack, Strength, Defence, Ranged, Magic - */ - if (redBoost > 0) - { - changes.add(statChangeOf(Stats.ATTACK, redBoost, client)); - changes.add(statChangeOf(Stats.STRENGTH, redBoost, client)); - changes.add(statChangeOf(Stats.DEFENCE, redBoost, client)); - changes.add(statChangeOf(Stats.RANGED, redBoost, client)); - changes.add(statChangeOf(Stats.MAGIC, redBoost, client)); - } - - /* - * Yellow spices: Prayer, Agility, Thieving, Slayer, Hunter - */ - if (yellowBoost > 0) - { - changes.add(statChangeOf(Stats.PRAYER, yellowBoost, client)); - changes.add(statChangeOf(Stats.AGILITY, yellowBoost, client)); - changes.add(statChangeOf(Stats.THIEVING, yellowBoost, client)); - changes.add(statChangeOf(Stats.SLAYER, yellowBoost, client)); - changes.add(statChangeOf(Stats.HUNTER, yellowBoost, client)); - } - - /* - * Orange spices: Smithing, Cooking, Crafting, Firemaking, Fletching, Runecraft, Construction - */ - if (orangeBoost > 0) - { - changes.add(statChangeOf(Stats.SMITHING, orangeBoost, client)); - changes.add(statChangeOf(Stats.COOKING, orangeBoost, client)); - changes.add(statChangeOf(Stats.CRAFTING, orangeBoost, client)); - changes.add(statChangeOf(Stats.FIREMAKING, orangeBoost, client)); - changes.add(statChangeOf(Stats.FLETCHING, orangeBoost, client)); - changes.add(statChangeOf(Stats.RUNECRAFT, orangeBoost, client)); - changes.add(statChangeOf(Stats.CONSTRUCTION, orangeBoost, client)); - } - - /* - * Brown spices: Mining, Herblore, Fishing, Woodcutting, Farming - */ - if (brownBoost > 0) - { - changes.add(statChangeOf(Stats.MINING, brownBoost, client)); - changes.add(statChangeOf(Stats.HERBLORE, brownBoost, client)); - changes.add(statChangeOf(Stats.FISHING, brownBoost, client)); - changes.add(statChangeOf(Stats.WOODCUTTING, brownBoost, client)); - changes.add(statChangeOf(Stats.FARMING, brownBoost, client)); - } - - StatsChanges changesReturn = new StatsChanges(4); - changesReturn.setStatChanges(changes.toArray(new StatChange[changes.size()])); - - return changesReturn; - } - - /** - * Calculate the potential boost that a spice currently offers, - * based on its number of doses in the stew. - * - * @param spiceDoses Number of doses between 0 and 3. - * @return Either 0, +1, +3, or +5. - */ - private static int spiceBoostOf(int spiceDoses) - { - return Math.max(0, (spiceDoses * 2) - 1); - } - - /** - * Calculate the fields of a stat change tooltip row. - * - * @param stat Stat that the spice boost affects. - * @param spiceBoost Potential spice boost before capping. - * @param client Client API, needed to check current stat values. - * @return StatChange object with all required values. - */ - private static StatChange statChangeOf(Stat stat, int spiceBoost, Client client) - { - int currentValue = stat.getValue(client); - int currentBase = stat.getMaximum(client); - - int currentBoost = currentValue - currentBase; // Can be negative - int spiceBoostCapped = (currentBoost <= 0) ? spiceBoost : Math.max(0, spiceBoost - currentBoost); - - final RangeStatChange change = new RangeStatChange(); - change.setStat(stat); - change.setMinRelative(-spiceBoost); - change.setRelative(spiceBoostCapped); - change.setMinTheoretical(-spiceBoost); - change.setTheoretical(spiceBoost); - change.setMinAbsolute(Math.max(-spiceBoost, -currentValue)); - change.setAbsolute(stat.getValue(client) + spiceBoostCapped); - - Positivity positivity; - if (spiceBoostCapped == 0) - { - positivity = Positivity.NO_CHANGE; - } - else if (spiceBoost > spiceBoostCapped) - { - positivity = Positivity.BETTER_CAPPED; - } - else - { - positivity = Positivity.BETTER_UNCAPPED; - } - change.setPositivity(positivity); - - return change; - } -} +/* + * Copyright (c) 2018, Adam + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package net.runelite.client.plugins.itemstats.special; + +import java.util.ArrayList; +import java.util.List; +import net.runelite.api.Client; +import net.runelite.api.Varbits; +import net.runelite.client.plugins.itemstats.Effect; +import net.runelite.client.plugins.itemstats.Positivity; +import net.runelite.client.plugins.itemstats.RangeStatChange; +import net.runelite.client.plugins.itemstats.StatChange; +import net.runelite.client.plugins.itemstats.StatsChanges; +import net.runelite.client.plugins.itemstats.stats.Stat; +import net.runelite.client.plugins.itemstats.stats.Stats; + +public class SpicyStew implements Effect +{ + + @Override + public StatsChanges calculate(Client client) + { + /* + * Spice boosts listed in the colour order of [Spicy stew -> Smell] + */ + int redBoost = spiceBoostOf(client.getVar(Varbits.SPICY_STEW_RED_SPICES)); + int yellowBoost = spiceBoostOf(client.getVar(Varbits.SPICY_STEW_YELLOW_SPICES)); + int orangeBoost = spiceBoostOf(client.getVar(Varbits.SPICY_STEW_ORANGE_SPICES)); + int brownBoost = spiceBoostOf(client.getVar(Varbits.SPICY_STEW_BROWN_SPICES)); + + List changes = new ArrayList<>(); + + /* + * Red spices: Attack, Strength, Defence, Ranged, Magic + */ + if (redBoost > 0) + { + changes.add(statChangeOf(Stats.ATTACK, redBoost, client)); + changes.add(statChangeOf(Stats.STRENGTH, redBoost, client)); + changes.add(statChangeOf(Stats.DEFENCE, redBoost, client)); + changes.add(statChangeOf(Stats.RANGED, redBoost, client)); + changes.add(statChangeOf(Stats.MAGIC, redBoost, client)); + } + + /* + * Yellow spices: Prayer, Agility, Thieving, Slayer, Hunter + */ + if (yellowBoost > 0) + { + changes.add(statChangeOf(Stats.PRAYER, yellowBoost, client)); + changes.add(statChangeOf(Stats.AGILITY, yellowBoost, client)); + changes.add(statChangeOf(Stats.THIEVING, yellowBoost, client)); + changes.add(statChangeOf(Stats.SLAYER, yellowBoost, client)); + changes.add(statChangeOf(Stats.HUNTER, yellowBoost, client)); + } + + /* + * Orange spices: Smithing, Cooking, Crafting, Firemaking, Fletching, Runecraft, Construction + */ + if (orangeBoost > 0) + { + changes.add(statChangeOf(Stats.SMITHING, orangeBoost, client)); + changes.add(statChangeOf(Stats.COOKING, orangeBoost, client)); + changes.add(statChangeOf(Stats.CRAFTING, orangeBoost, client)); + changes.add(statChangeOf(Stats.FIREMAKING, orangeBoost, client)); + changes.add(statChangeOf(Stats.FLETCHING, orangeBoost, client)); + changes.add(statChangeOf(Stats.RUNECRAFT, orangeBoost, client)); + changes.add(statChangeOf(Stats.CONSTRUCTION, orangeBoost, client)); + } + + /* + * Brown spices: Mining, Herblore, Fishing, Woodcutting, Farming + */ + if (brownBoost > 0) + { + changes.add(statChangeOf(Stats.MINING, brownBoost, client)); + changes.add(statChangeOf(Stats.HERBLORE, brownBoost, client)); + changes.add(statChangeOf(Stats.FISHING, brownBoost, client)); + changes.add(statChangeOf(Stats.WOODCUTTING, brownBoost, client)); + changes.add(statChangeOf(Stats.FARMING, brownBoost, client)); + } + + StatsChanges changesReturn = new StatsChanges(4); + changesReturn.setStatChanges(changes.toArray(new StatChange[changes.size()])); + + return changesReturn; + } + + /** + * Calculate the potential boost that a spice currently offers, + * based on its number of doses in the stew. + * + * @param spiceDoses Number of doses between 0 and 3. + * @return Either 0, +1, +3, or +5. + */ + private static int spiceBoostOf(int spiceDoses) + { + return Math.max(0, (spiceDoses * 2) - 1); + } + + /** + * Calculate the fields of a stat change tooltip row. + * + * @param stat Stat that the spice boost affects. + * @param spiceBoost Potential spice boost before capping. + * @param client Client API, needed to check current stat values. + * @return StatChange object with all required values. + */ + private static StatChange statChangeOf(Stat stat, int spiceBoost, Client client) + { + int currentValue = stat.getValue(client); + int currentBase = stat.getMaximum(client); + + int currentBoost = currentValue - currentBase; // Can be negative + int spiceBoostCapped = (currentBoost <= 0) ? spiceBoost : Math.max(0, spiceBoost - currentBoost); + + final RangeStatChange change = new RangeStatChange(); + change.setStat(stat); + change.setMinRelative(-spiceBoost); + change.setRelative(spiceBoostCapped); + change.setMinTheoretical(-spiceBoost); + change.setTheoretical(spiceBoost); + change.setMinAbsolute(Math.max(-spiceBoost, -currentValue)); + change.setAbsolute(stat.getValue(client) + spiceBoostCapped); + + Positivity positivity; + if (spiceBoostCapped == 0) + { + positivity = Positivity.NO_CHANGE; + } + else if (spiceBoost > spiceBoostCapped) + { + positivity = Positivity.BETTER_CAPPED; + } + else + { + positivity = Positivity.BETTER_UNCAPPED; + } + change.setPositivity(positivity); + + return change; + } +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/itemstats/stats/Stat.java b/runelite-client/src/main/java/net/runelite/client/plugins/itemstats/stats/Stat.java index be7b2ff4d8..a67ab22d58 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/itemstats/stats/Stat.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/itemstats/stats/Stat.java @@ -1,58 +1,59 @@ -/* - * Copyright (c) 2018 Abex - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package net.runelite.client.plugins.itemstats.stats; - -import net.runelite.api.Client; -import net.runelite.api.Skill; - -/** - * Abstract stat of a player. - * This includes {@link Skill}s and other player variables, such as RUN_ENERGY. - * @see Stats - */ -public abstract class Stat -{ - private final String name; - - Stat(String name) - { - this.name = name; - } - - public String getName() - { - return name; - } - - /** - * Get the current stat value including any boosts or damage. - */ - public abstract int getValue(Client client); - - /** - * Get the base stat maximum, ie. the bottom half of the stat fraction. - */ - public abstract int getMaximum(Client client); -} +/* + * Copyright (c) 2018 Abex + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package net.runelite.client.plugins.itemstats.stats; + +import net.runelite.api.Client; +import net.runelite.api.Skill; + +/** + * Abstract stat of a player. + * This includes {@link Skill}s and other player variables, such as RUN_ENERGY. + * + * @see Stats + */ +public abstract class Stat +{ + private final String name; + + Stat(String name) + { + this.name = name; + } + + public String getName() + { + return name; + } + + /** + * Get the current stat value including any boosts or damage. + */ + public abstract int getValue(Client client); + + /** + * Get the base stat maximum, ie. the bottom half of the stat fraction. + */ + public abstract int getMaximum(Client client); +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/keptondeath/ActuallyTradeableItem.java b/runelite-client/src/main/java/net/runelite/client/plugins/keptondeath/ActuallyTradeableItem.java index 8f9dddd40b..91d4ef671c 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/keptondeath/ActuallyTradeableItem.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/keptondeath/ActuallyTradeableItem.java @@ -1,87 +1,221 @@ -/* - * Copyright (c) 2018, 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.keptondeath; - -import java.util.HashSet; -import static net.runelite.api.ItemID.*; - -/** - * Certain items aren't tradeable via the GE but can be traded between players. - * The {@link net.runelite.api.ItemComposition}'s `isTradeable` value is based on GE trade-ability so we need - * to account for these items. These items should only be kept if protected based on item value. - */ -public enum ActuallyTradeableItem -{ - // Item Packs - RUNE_PACKS(AIR_RUNE_PACK, WATER_RUNE_PACK, EARTH_RUNE_PACK, FIRE_RUNE_PACK, CHAOS_RUNE_PACK, MIND_RUNE_PACK), - TZHAAR_PACKS(TZHAAR_AIR_RUNE_PACK, TZHAAR_WATER_RUNE_PACK, TZHAAR_EARTH_RUNE_PACK, TZHAAR_FIRE_RUNE_PACK), - OTHER_PACKS(BASKET_PACK, FEATHER_PACK, PLANT_POT_PACK, SACK_PACK, UNFINISHED_BROAD_BOLT_PACK), - // Equipment - BLACK_MASK(BLACK_MASK_1, BLACK_MASK_2, BLACK_MASK_3, BLACK_MASK_4, BLACK_MASK_5, BLACK_MASK_6, BLACK_MASK_7, BLACK_MASK_8, BLACK_MASK_9), - SATCHELS(BLACK_SATCHEL, GOLD_SATCHEL, GREEN_SATCHEL, PLAIN_SATCHEL, RED_SATCHEL, RUNE_SATCHEL), - FIRE_ARROWS(BRONZE_FIRE_ARROWS, IRON_FIRE_ARROWS, STEEL_FIRE_ARROWS, MITHRIL_FIRE_ARROWS, ADAMANT_FIRE_ARROWS, RUNE_FIRE_ARROWS, AMETHYST_FIRE_ARROWS, DRAGON_FIRE_ARROWS), - FIRE_ARROWS_2(BRONZE_FIRE_ARROWS_942, IRON_FIRE_ARROWS_2533, STEEL_FIRE_ARROWS_2535, MITHRIL_FIRE_ARROWS_2537, ADAMANT_FIRE_ARROWS_2539, RUNE_FIRE_ARROWS_2541, AMETHYST_FIRE_ARROWS_21330, DRAGON_FIRE_ARROWS_11222), - // Food Items - HALF_A(HALF_A_GARDEN_PIE, HALF_A_MEAT_PIE, HALF_A_MUSHROOM_PIE, HALF_A_REDBERRY_PIE, HALF_A_BOTANICAL_PIE, HALF_A_FISH_PIE, HALF_A_SUMMER_PIE, HALF_A_WILD_PIE, HALF_AN_ADMIRAL_PIE, HALF_AN_APPLE_PIE), - PIZZA(_12_ANCHOVY_PIZZA, _12_MEAT_PIZZA, _12_PINEAPPLE_PIZZA, _12_PLAIN_PIZZA), - CAKES(CAKE, _23_CAKE, SLICE_OF_CAKE, CHOCOLATE_CAKE, _23_CHOCOLATE_CAKE, CHOCOLATE_SLICE), - BASKETS(APPLES1, APPLES2, APPLES3, APPLES4, BANANAS1, BANANAS2, BANANAS3, BANANAS4, ORANGES1, ORANGES2, ORANGES3, ORANGES4, STRAWBERRIES1, STRAWBERRIES2, STRAWBERRIES3, STRAWBERRIES4, TOMATOES1, TOMATOES2, TOMATOES3, TOMATOES4), - // Charged Jewelery - BURNING_AMULET(BURNING_AMULET1, BURNING_AMULET2, BURNING_AMULET3, BURNING_AMULET4), - NECKLACE_OF_PASSAGE(NECKLACE_OF_PASSAGE1, NECKLACE_OF_PASSAGE2, NECKLACE_OF_PASSAGE3, NECKLACE_OF_PASSAGE4), - RING_OF_DUELING(RING_OF_DUELING1, RING_OF_DUELING2, RING_OF_DUELING3, RING_OF_DUELING4, RING_OF_DUELING5, RING_OF_DUELING6, RING_OF_DUELING7), - GAMES_NECKLACE(GAMES_NECKLACE1, GAMES_NECKLACE2, GAMES_NECKLACE3, GAMES_NECKLACE4, GAMES_NECKLACE5, GAMES_NECKLACE6, GAMES_NECKLACE7), - COMBAT_BRACELET(COMBAT_BRACELET1, COMBAT_BRACELET2, COMBAT_BRACELET3, COMBAT_BRACELET5), - RING_OF_WEALTH(RING_OF_WEALTH_I, RING_OF_WEALTH_1, RING_OF_WEALTH_I1, RING_OF_WEALTH_2, RING_OF_WEALTH_I2, RING_OF_WEALTH_3, RING_OF_WEALTH_I3, RING_OF_WEALTH_4, RING_OF_WEALTH_I4, RING_OF_WEALTH_I5), - AMULET_OF_GLORY(AMULET_OF_GLORY1, AMULET_OF_GLORY2, AMULET_OF_GLORY3, AMULET_OF_GLORY5), - AMULET_OF_GLORY_T(AMULET_OF_GLORY_T1, AMULET_OF_GLORY_T2, AMULET_OF_GLORY_T3, AMULET_OF_GLORY_T5), - SKILLS_NECKLACE(SKILLS_NECKLACE1, SKILLS_NECKLACE2, SKILLS_NECKLACE3, SKILLS_NECKLACE5), - ; - - private final int[] ids; - - private static final HashSet ID_SET; - static - { - ID_SET = new HashSet<>(); - for (ActuallyTradeableItem p : values()) - { - for (int id : p.ids) - { - ID_SET.add(id); - } - } - } - - ActuallyTradeableItem(int... ids) - { - this.ids = ids; - } - - public static Boolean check(int id) - { - return ID_SET.contains(id); - } -} +/* + * Copyright (c) 2018, 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.keptondeath; + +import java.util.HashSet; +import static net.runelite.api.ItemID.ADAMANT_FIRE_ARROWS; +import static net.runelite.api.ItemID.ADAMANT_FIRE_ARROWS_2539; +import static net.runelite.api.ItemID.AIR_RUNE_PACK; +import static net.runelite.api.ItemID.AMETHYST_FIRE_ARROWS; +import static net.runelite.api.ItemID.AMETHYST_FIRE_ARROWS_21330; +import static net.runelite.api.ItemID.AMULET_OF_GLORY1; +import static net.runelite.api.ItemID.AMULET_OF_GLORY2; +import static net.runelite.api.ItemID.AMULET_OF_GLORY3; +import static net.runelite.api.ItemID.AMULET_OF_GLORY5; +import static net.runelite.api.ItemID.AMULET_OF_GLORY_T1; +import static net.runelite.api.ItemID.AMULET_OF_GLORY_T2; +import static net.runelite.api.ItemID.AMULET_OF_GLORY_T3; +import static net.runelite.api.ItemID.AMULET_OF_GLORY_T5; +import static net.runelite.api.ItemID.APPLES1; +import static net.runelite.api.ItemID.APPLES2; +import static net.runelite.api.ItemID.APPLES3; +import static net.runelite.api.ItemID.APPLES4; +import static net.runelite.api.ItemID.BANANAS1; +import static net.runelite.api.ItemID.BANANAS2; +import static net.runelite.api.ItemID.BANANAS3; +import static net.runelite.api.ItemID.BANANAS4; +import static net.runelite.api.ItemID.BASKET_PACK; +import static net.runelite.api.ItemID.BLACK_MASK_1; +import static net.runelite.api.ItemID.BLACK_MASK_2; +import static net.runelite.api.ItemID.BLACK_MASK_3; +import static net.runelite.api.ItemID.BLACK_MASK_4; +import static net.runelite.api.ItemID.BLACK_MASK_5; +import static net.runelite.api.ItemID.BLACK_MASK_6; +import static net.runelite.api.ItemID.BLACK_MASK_7; +import static net.runelite.api.ItemID.BLACK_MASK_8; +import static net.runelite.api.ItemID.BLACK_MASK_9; +import static net.runelite.api.ItemID.BLACK_SATCHEL; +import static net.runelite.api.ItemID.BRONZE_FIRE_ARROWS; +import static net.runelite.api.ItemID.BRONZE_FIRE_ARROWS_942; +import static net.runelite.api.ItemID.BURNING_AMULET1; +import static net.runelite.api.ItemID.BURNING_AMULET2; +import static net.runelite.api.ItemID.BURNING_AMULET3; +import static net.runelite.api.ItemID.BURNING_AMULET4; +import static net.runelite.api.ItemID.CAKE; +import static net.runelite.api.ItemID.CHAOS_RUNE_PACK; +import static net.runelite.api.ItemID.CHOCOLATE_CAKE; +import static net.runelite.api.ItemID.CHOCOLATE_SLICE; +import static net.runelite.api.ItemID.COMBAT_BRACELET1; +import static net.runelite.api.ItemID.COMBAT_BRACELET2; +import static net.runelite.api.ItemID.COMBAT_BRACELET3; +import static net.runelite.api.ItemID.COMBAT_BRACELET5; +import static net.runelite.api.ItemID.DRAGON_FIRE_ARROWS; +import static net.runelite.api.ItemID.DRAGON_FIRE_ARROWS_11222; +import static net.runelite.api.ItemID.EARTH_RUNE_PACK; +import static net.runelite.api.ItemID.FEATHER_PACK; +import static net.runelite.api.ItemID.FIRE_RUNE_PACK; +import static net.runelite.api.ItemID.GAMES_NECKLACE1; +import static net.runelite.api.ItemID.GAMES_NECKLACE2; +import static net.runelite.api.ItemID.GAMES_NECKLACE3; +import static net.runelite.api.ItemID.GAMES_NECKLACE4; +import static net.runelite.api.ItemID.GAMES_NECKLACE5; +import static net.runelite.api.ItemID.GAMES_NECKLACE6; +import static net.runelite.api.ItemID.GAMES_NECKLACE7; +import static net.runelite.api.ItemID.GOLD_SATCHEL; +import static net.runelite.api.ItemID.GREEN_SATCHEL; +import static net.runelite.api.ItemID.HALF_AN_ADMIRAL_PIE; +import static net.runelite.api.ItemID.HALF_AN_APPLE_PIE; +import static net.runelite.api.ItemID.HALF_A_BOTANICAL_PIE; +import static net.runelite.api.ItemID.HALF_A_FISH_PIE; +import static net.runelite.api.ItemID.HALF_A_GARDEN_PIE; +import static net.runelite.api.ItemID.HALF_A_MEAT_PIE; +import static net.runelite.api.ItemID.HALF_A_MUSHROOM_PIE; +import static net.runelite.api.ItemID.HALF_A_REDBERRY_PIE; +import static net.runelite.api.ItemID.HALF_A_SUMMER_PIE; +import static net.runelite.api.ItemID.HALF_A_WILD_PIE; +import static net.runelite.api.ItemID.IRON_FIRE_ARROWS; +import static net.runelite.api.ItemID.IRON_FIRE_ARROWS_2533; +import static net.runelite.api.ItemID.MIND_RUNE_PACK; +import static net.runelite.api.ItemID.MITHRIL_FIRE_ARROWS; +import static net.runelite.api.ItemID.MITHRIL_FIRE_ARROWS_2537; +import static net.runelite.api.ItemID.NECKLACE_OF_PASSAGE1; +import static net.runelite.api.ItemID.NECKLACE_OF_PASSAGE2; +import static net.runelite.api.ItemID.NECKLACE_OF_PASSAGE3; +import static net.runelite.api.ItemID.NECKLACE_OF_PASSAGE4; +import static net.runelite.api.ItemID.ORANGES1; +import static net.runelite.api.ItemID.ORANGES2; +import static net.runelite.api.ItemID.ORANGES3; +import static net.runelite.api.ItemID.ORANGES4; +import static net.runelite.api.ItemID.PLAIN_SATCHEL; +import static net.runelite.api.ItemID.PLANT_POT_PACK; +import static net.runelite.api.ItemID.RED_SATCHEL; +import static net.runelite.api.ItemID.RING_OF_DUELING1; +import static net.runelite.api.ItemID.RING_OF_DUELING2; +import static net.runelite.api.ItemID.RING_OF_DUELING3; +import static net.runelite.api.ItemID.RING_OF_DUELING4; +import static net.runelite.api.ItemID.RING_OF_DUELING5; +import static net.runelite.api.ItemID.RING_OF_DUELING6; +import static net.runelite.api.ItemID.RING_OF_DUELING7; +import static net.runelite.api.ItemID.RING_OF_WEALTH_1; +import static net.runelite.api.ItemID.RING_OF_WEALTH_2; +import static net.runelite.api.ItemID.RING_OF_WEALTH_3; +import static net.runelite.api.ItemID.RING_OF_WEALTH_4; +import static net.runelite.api.ItemID.RING_OF_WEALTH_I; +import static net.runelite.api.ItemID.RING_OF_WEALTH_I1; +import static net.runelite.api.ItemID.RING_OF_WEALTH_I2; +import static net.runelite.api.ItemID.RING_OF_WEALTH_I3; +import static net.runelite.api.ItemID.RING_OF_WEALTH_I4; +import static net.runelite.api.ItemID.RING_OF_WEALTH_I5; +import static net.runelite.api.ItemID.RUNE_FIRE_ARROWS; +import static net.runelite.api.ItemID.RUNE_FIRE_ARROWS_2541; +import static net.runelite.api.ItemID.RUNE_SATCHEL; +import static net.runelite.api.ItemID.SACK_PACK; +import static net.runelite.api.ItemID.SKILLS_NECKLACE1; +import static net.runelite.api.ItemID.SKILLS_NECKLACE2; +import static net.runelite.api.ItemID.SKILLS_NECKLACE3; +import static net.runelite.api.ItemID.SKILLS_NECKLACE5; +import static net.runelite.api.ItemID.SLICE_OF_CAKE; +import static net.runelite.api.ItemID.STEEL_FIRE_ARROWS; +import static net.runelite.api.ItemID.STEEL_FIRE_ARROWS_2535; +import static net.runelite.api.ItemID.STRAWBERRIES1; +import static net.runelite.api.ItemID.STRAWBERRIES2; +import static net.runelite.api.ItemID.STRAWBERRIES3; +import static net.runelite.api.ItemID.STRAWBERRIES4; +import static net.runelite.api.ItemID.TOMATOES1; +import static net.runelite.api.ItemID.TOMATOES2; +import static net.runelite.api.ItemID.TOMATOES3; +import static net.runelite.api.ItemID.TOMATOES4; +import static net.runelite.api.ItemID.TZHAAR_AIR_RUNE_PACK; +import static net.runelite.api.ItemID.TZHAAR_EARTH_RUNE_PACK; +import static net.runelite.api.ItemID.TZHAAR_FIRE_RUNE_PACK; +import static net.runelite.api.ItemID.TZHAAR_WATER_RUNE_PACK; +import static net.runelite.api.ItemID.UNFINISHED_BROAD_BOLT_PACK; +import static net.runelite.api.ItemID.WATER_RUNE_PACK; +import static net.runelite.api.ItemID._12_ANCHOVY_PIZZA; +import static net.runelite.api.ItemID._12_MEAT_PIZZA; +import static net.runelite.api.ItemID._12_PINEAPPLE_PIZZA; +import static net.runelite.api.ItemID._12_PLAIN_PIZZA; +import static net.runelite.api.ItemID._23_CAKE; +import static net.runelite.api.ItemID._23_CHOCOLATE_CAKE; + +/** + * Certain items aren't tradeable via the GE but can be traded between players. + * The {@link net.runelite.api.ItemComposition}'s `isTradeable` value is based on GE trade-ability so we need + * to account for these items. These items should only be kept if protected based on item value. + */ +public enum ActuallyTradeableItem +{ + // Item Packs + RUNE_PACKS(AIR_RUNE_PACK, WATER_RUNE_PACK, EARTH_RUNE_PACK, FIRE_RUNE_PACK, CHAOS_RUNE_PACK, MIND_RUNE_PACK), + TZHAAR_PACKS(TZHAAR_AIR_RUNE_PACK, TZHAAR_WATER_RUNE_PACK, TZHAAR_EARTH_RUNE_PACK, TZHAAR_FIRE_RUNE_PACK), + OTHER_PACKS(BASKET_PACK, FEATHER_PACK, PLANT_POT_PACK, SACK_PACK, UNFINISHED_BROAD_BOLT_PACK), + // Equipment + BLACK_MASK(BLACK_MASK_1, BLACK_MASK_2, BLACK_MASK_3, BLACK_MASK_4, BLACK_MASK_5, BLACK_MASK_6, BLACK_MASK_7, BLACK_MASK_8, BLACK_MASK_9), + SATCHELS(BLACK_SATCHEL, GOLD_SATCHEL, GREEN_SATCHEL, PLAIN_SATCHEL, RED_SATCHEL, RUNE_SATCHEL), + FIRE_ARROWS(BRONZE_FIRE_ARROWS, IRON_FIRE_ARROWS, STEEL_FIRE_ARROWS, MITHRIL_FIRE_ARROWS, ADAMANT_FIRE_ARROWS, RUNE_FIRE_ARROWS, AMETHYST_FIRE_ARROWS, DRAGON_FIRE_ARROWS), + FIRE_ARROWS_2(BRONZE_FIRE_ARROWS_942, IRON_FIRE_ARROWS_2533, STEEL_FIRE_ARROWS_2535, MITHRIL_FIRE_ARROWS_2537, ADAMANT_FIRE_ARROWS_2539, RUNE_FIRE_ARROWS_2541, AMETHYST_FIRE_ARROWS_21330, DRAGON_FIRE_ARROWS_11222), + // Food Items + HALF_A(HALF_A_GARDEN_PIE, HALF_A_MEAT_PIE, HALF_A_MUSHROOM_PIE, HALF_A_REDBERRY_PIE, HALF_A_BOTANICAL_PIE, HALF_A_FISH_PIE, HALF_A_SUMMER_PIE, HALF_A_WILD_PIE, HALF_AN_ADMIRAL_PIE, HALF_AN_APPLE_PIE), + PIZZA(_12_ANCHOVY_PIZZA, _12_MEAT_PIZZA, _12_PINEAPPLE_PIZZA, _12_PLAIN_PIZZA), + CAKES(CAKE, _23_CAKE, SLICE_OF_CAKE, CHOCOLATE_CAKE, _23_CHOCOLATE_CAKE, CHOCOLATE_SLICE), + BASKETS(APPLES1, APPLES2, APPLES3, APPLES4, BANANAS1, BANANAS2, BANANAS3, BANANAS4, ORANGES1, ORANGES2, ORANGES3, ORANGES4, STRAWBERRIES1, STRAWBERRIES2, STRAWBERRIES3, STRAWBERRIES4, TOMATOES1, TOMATOES2, TOMATOES3, TOMATOES4), + // Charged Jewelery + BURNING_AMULET(BURNING_AMULET1, BURNING_AMULET2, BURNING_AMULET3, BURNING_AMULET4), + NECKLACE_OF_PASSAGE(NECKLACE_OF_PASSAGE1, NECKLACE_OF_PASSAGE2, NECKLACE_OF_PASSAGE3, NECKLACE_OF_PASSAGE4), + RING_OF_DUELING(RING_OF_DUELING1, RING_OF_DUELING2, RING_OF_DUELING3, RING_OF_DUELING4, RING_OF_DUELING5, RING_OF_DUELING6, RING_OF_DUELING7), + GAMES_NECKLACE(GAMES_NECKLACE1, GAMES_NECKLACE2, GAMES_NECKLACE3, GAMES_NECKLACE4, GAMES_NECKLACE5, GAMES_NECKLACE6, GAMES_NECKLACE7), + COMBAT_BRACELET(COMBAT_BRACELET1, COMBAT_BRACELET2, COMBAT_BRACELET3, COMBAT_BRACELET5), + RING_OF_WEALTH(RING_OF_WEALTH_I, RING_OF_WEALTH_1, RING_OF_WEALTH_I1, RING_OF_WEALTH_2, RING_OF_WEALTH_I2, RING_OF_WEALTH_3, RING_OF_WEALTH_I3, RING_OF_WEALTH_4, RING_OF_WEALTH_I4, RING_OF_WEALTH_I5), + AMULET_OF_GLORY(AMULET_OF_GLORY1, AMULET_OF_GLORY2, AMULET_OF_GLORY3, AMULET_OF_GLORY5), + AMULET_OF_GLORY_T(AMULET_OF_GLORY_T1, AMULET_OF_GLORY_T2, AMULET_OF_GLORY_T3, AMULET_OF_GLORY_T5), + SKILLS_NECKLACE(SKILLS_NECKLACE1, SKILLS_NECKLACE2, SKILLS_NECKLACE3, SKILLS_NECKLACE5), + ; + + private final int[] ids; + + private static final HashSet ID_SET; + + static + { + ID_SET = new HashSet<>(); + for (ActuallyTradeableItem p : values()) + { + for (int id : p.ids) + { + ID_SET.add(id); + } + } + } + + ActuallyTradeableItem(int... ids) + { + this.ids = ids; + } + + public static Boolean check(int id) + { + return ID_SET.contains(id); + } +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/keptondeath/AlwaysLostItem.java b/runelite-client/src/main/java/net/runelite/client/plugins/keptondeath/AlwaysLostItem.java index 02a8e26df0..32c5e568fc 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/keptondeath/AlwaysLostItem.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/keptondeath/AlwaysLostItem.java @@ -1,69 +1,70 @@ -/* - * Copyright (c) 2018, 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.keptondeath; - -import com.google.common.collect.ImmutableMap; -import lombok.Getter; -import net.runelite.api.ItemID; - -/** - * Certain Items receive a white outline by Jagex as they are always lost on death. This is sometimes incorrectly - * added to Items by Jagex as the item is actually kept in non-pvp areas of the game, such as the Rune Pouch. - * - * The white outline will be added to these items when they are lost on death. - */ -public enum AlwaysLostItem -{ - RUNE_POUCH(ItemID.RUNE_POUCH, true), - LOOTING_BAG(ItemID.LOOTING_BAG, false), - LOOTING_BAG_22586(ItemID.LOOTING_BAG_22586, false), - CLUE_BOX(ItemID.CLUE_BOX, false); - - private final int itemID; - @Getter - private final boolean kept; - - private static final ImmutableMap ID_MAP; - static - { - ImmutableMap.Builder map = ImmutableMap.builder(); - for (AlwaysLostItem p : values()) - { - map.put(p.itemID, p); - } - ID_MAP = map.build(); - } - - AlwaysLostItem(int itemID, boolean kept) - { - this.itemID = itemID; - this.kept = kept; - } - - public static AlwaysLostItem getByItemID(int itemID) - { - return ID_MAP.get(itemID); - } -} +/* + * Copyright (c) 2018, 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.keptondeath; + +import com.google.common.collect.ImmutableMap; +import lombok.Getter; +import net.runelite.api.ItemID; + +/** + * Certain Items receive a white outline by Jagex as they are always lost on death. This is sometimes incorrectly + * added to Items by Jagex as the item is actually kept in non-pvp areas of the game, such as the Rune Pouch. + *

+ * The white outline will be added to these items when they are lost on death. + */ +public enum AlwaysLostItem +{ + RUNE_POUCH(ItemID.RUNE_POUCH, true), + LOOTING_BAG(ItemID.LOOTING_BAG, false), + LOOTING_BAG_22586(ItemID.LOOTING_BAG_22586, false), + CLUE_BOX(ItemID.CLUE_BOX, false); + + private final int itemID; + @Getter + private final boolean kept; + + private static final ImmutableMap ID_MAP; + + static + { + ImmutableMap.Builder map = ImmutableMap.builder(); + for (AlwaysLostItem p : values()) + { + map.put(p.itemID, p); + } + ID_MAP = map.build(); + } + + AlwaysLostItem(int itemID, boolean kept) + { + this.itemID = itemID; + this.kept = kept; + } + + public static AlwaysLostItem getByItemID(int itemID) + { + return ID_MAP.get(itemID); + } +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/keptondeath/BrokenOnDeathItem.java b/runelite-client/src/main/java/net/runelite/client/plugins/keptondeath/BrokenOnDeathItem.java index bcb629f89e..fba75bddb2 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/keptondeath/BrokenOnDeathItem.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/keptondeath/BrokenOnDeathItem.java @@ -1,112 +1,113 @@ -/* - * Copyright (c) 2018, 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.keptondeath; - -import java.util.HashSet; -import net.runelite.api.ItemID; - -/** - * Some non tradeable items are kept on death inside low level wilderness (1-20) but are turned into a broken variant. - * - * The non-broken variant will be shown inside the interface. - */ -public enum BrokenOnDeathItem -{ - // Capes - FIRE_CAPE(ItemID.FIRE_CAPE), - FIRE_MAX_CAPE(ItemID.FIRE_MAX_CAPE), - INFERNAL_CAPE(ItemID.INFERNAL_CAPE), - INFERNAL_MAX_CAPE(ItemID.INFERNAL_MAX_CAPE), - AVAS_ASSEMBLER(ItemID.AVAS_ASSEMBLER), - ASSEMBLER_MAX_CAPE(ItemID.ASSEMBLER_MAX_CAPE), - - // Defenders - BRONZE_DEFENDER(ItemID.BRONZE_DEFENDER), - IRON_DEFENDER(ItemID.IRON_DEFENDER), - STEEL_DEFENDER(ItemID.STEEL_DEFENDER), - BLACK_DEFENDER(ItemID.BLACK_DEFENDER), - MITHRIL_DEFENDER(ItemID.MITHRIL_DEFENDER), - ADAMANT_DEFENDER(ItemID.ADAMANT_DEFENDER), - RUNE_DEFENDER(ItemID.RUNE_DEFENDER), - DRAGON_DEFENDER(ItemID.DRAGON_DEFENDER), - AVERNIC_DEFENDER(ItemID.AVERNIC_DEFENDER), - - // Void - VOID_MAGE_HELM(ItemID.VOID_MAGE_HELM), - VOID_RANGER_HELM(ItemID.VOID_RANGER_HELM), - VOID_MELEE_HELM(ItemID.VOID_MELEE_HELM), - VOID_KNIGHT_TOP(ItemID.VOID_KNIGHT_TOP), - VOID_KNIGHT_ROBE(ItemID.VOID_KNIGHT_ROBE), - VOID_KNIGHT_GLOVES(ItemID.VOID_KNIGHT_GLOVES), - VOID_KNIGHT_MACE(ItemID.VOID_KNIGHT_MACE), - ELITE_VOID_TOP(ItemID.ELITE_VOID_TOP), - ELITE_VOID_ROBE(ItemID.ELITE_VOID_ROBE), - - // Barb Assault - FIGHTER_HAT(ItemID.FIGHTER_HAT), - RANGER_HAT(ItemID.RANGER_HAT), - HEALER_HAT(ItemID.HEALER_HAT), - FIGHTER_TORSO(ItemID.FIGHTER_TORSO), - PENANCE_SKIRT(ItemID.PENANCE_SKIRT), - - // Castle Wars - SARADOMIN_HALO(ItemID.SARADOMIN_HALO), - ZAMORAK_HALO(ItemID.ZAMORAK_HALO), - GUTHIX_HALO(ItemID.GUTHIX_HALO), - DECORATIVE_MAGIC_HAT(ItemID.DECORATIVE_ARMOUR_11898), - DECORATIVE_MAGIC_ROBE_TOP(ItemID.DECORATIVE_ARMOUR_11896), - DECORATIVE_MAGIC_ROBE_LEGS(ItemID.DECORATIVE_ARMOUR_11897), - DECORATIVE_RANGE_TOP(ItemID.DECORATIVE_ARMOUR_11899), - DECORATIVE_RANGE_BOTTOM(ItemID.DECORATIVE_ARMOUR_11900), - DECORATIVE_RANGE_QUIVER(ItemID.DECORATIVE_ARMOUR_11901), - GOLD_DECORATIVE_HELM(ItemID.DECORATIVE_HELM_4511), - GOLD_DECORATIVE_BODY(ItemID.DECORATIVE_ARMOUR_4509), - GOLD_DECORATIVE_LEGS(ItemID.DECORATIVE_ARMOUR_4510), - GOLD_DECORATIVE_SKIRT(ItemID.DECORATIVE_ARMOUR_11895), - GOLD_DECORATIVE_SHIELD(ItemID.DECORATIVE_SHIELD_4512), - GOLD_DECORATIVE_SWORD(ItemID.DECORATIVE_SWORD_4508); - - private final int itemID; - - private static final HashSet ID_SET; - static - { - ID_SET = new HashSet<>(); - for (BrokenOnDeathItem p : values()) - { - ID_SET.add(p.itemID); - } - } - - BrokenOnDeathItem(int itemID) - { - this.itemID = itemID; - } - - public static boolean check(int itemID) - { - return ID_SET.contains(itemID); - } -} +/* + * Copyright (c) 2018, 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.keptondeath; + +import java.util.HashSet; +import net.runelite.api.ItemID; + +/** + * Some non tradeable items are kept on death inside low level wilderness (1-20) but are turned into a broken variant. + *

+ * The non-broken variant will be shown inside the interface. + */ +public enum BrokenOnDeathItem +{ + // Capes + FIRE_CAPE(ItemID.FIRE_CAPE), + FIRE_MAX_CAPE(ItemID.FIRE_MAX_CAPE), + INFERNAL_CAPE(ItemID.INFERNAL_CAPE), + INFERNAL_MAX_CAPE(ItemID.INFERNAL_MAX_CAPE), + AVAS_ASSEMBLER(ItemID.AVAS_ASSEMBLER), + ASSEMBLER_MAX_CAPE(ItemID.ASSEMBLER_MAX_CAPE), + + // Defenders + BRONZE_DEFENDER(ItemID.BRONZE_DEFENDER), + IRON_DEFENDER(ItemID.IRON_DEFENDER), + STEEL_DEFENDER(ItemID.STEEL_DEFENDER), + BLACK_DEFENDER(ItemID.BLACK_DEFENDER), + MITHRIL_DEFENDER(ItemID.MITHRIL_DEFENDER), + ADAMANT_DEFENDER(ItemID.ADAMANT_DEFENDER), + RUNE_DEFENDER(ItemID.RUNE_DEFENDER), + DRAGON_DEFENDER(ItemID.DRAGON_DEFENDER), + AVERNIC_DEFENDER(ItemID.AVERNIC_DEFENDER), + + // Void + VOID_MAGE_HELM(ItemID.VOID_MAGE_HELM), + VOID_RANGER_HELM(ItemID.VOID_RANGER_HELM), + VOID_MELEE_HELM(ItemID.VOID_MELEE_HELM), + VOID_KNIGHT_TOP(ItemID.VOID_KNIGHT_TOP), + VOID_KNIGHT_ROBE(ItemID.VOID_KNIGHT_ROBE), + VOID_KNIGHT_GLOVES(ItemID.VOID_KNIGHT_GLOVES), + VOID_KNIGHT_MACE(ItemID.VOID_KNIGHT_MACE), + ELITE_VOID_TOP(ItemID.ELITE_VOID_TOP), + ELITE_VOID_ROBE(ItemID.ELITE_VOID_ROBE), + + // Barb Assault + FIGHTER_HAT(ItemID.FIGHTER_HAT), + RANGER_HAT(ItemID.RANGER_HAT), + HEALER_HAT(ItemID.HEALER_HAT), + FIGHTER_TORSO(ItemID.FIGHTER_TORSO), + PENANCE_SKIRT(ItemID.PENANCE_SKIRT), + + // Castle Wars + SARADOMIN_HALO(ItemID.SARADOMIN_HALO), + ZAMORAK_HALO(ItemID.ZAMORAK_HALO), + GUTHIX_HALO(ItemID.GUTHIX_HALO), + DECORATIVE_MAGIC_HAT(ItemID.DECORATIVE_ARMOUR_11898), + DECORATIVE_MAGIC_ROBE_TOP(ItemID.DECORATIVE_ARMOUR_11896), + DECORATIVE_MAGIC_ROBE_LEGS(ItemID.DECORATIVE_ARMOUR_11897), + DECORATIVE_RANGE_TOP(ItemID.DECORATIVE_ARMOUR_11899), + DECORATIVE_RANGE_BOTTOM(ItemID.DECORATIVE_ARMOUR_11900), + DECORATIVE_RANGE_QUIVER(ItemID.DECORATIVE_ARMOUR_11901), + GOLD_DECORATIVE_HELM(ItemID.DECORATIVE_HELM_4511), + GOLD_DECORATIVE_BODY(ItemID.DECORATIVE_ARMOUR_4509), + GOLD_DECORATIVE_LEGS(ItemID.DECORATIVE_ARMOUR_4510), + GOLD_DECORATIVE_SKIRT(ItemID.DECORATIVE_ARMOUR_11895), + GOLD_DECORATIVE_SHIELD(ItemID.DECORATIVE_SHIELD_4512), + GOLD_DECORATIVE_SWORD(ItemID.DECORATIVE_SWORD_4508); + + private final int itemID; + + private static final HashSet ID_SET; + + static + { + ID_SET = new HashSet<>(); + for (BrokenOnDeathItem p : values()) + { + ID_SET.add(p.itemID); + } + } + + BrokenOnDeathItem(int itemID) + { + this.itemID = itemID; + } + + public static boolean check(int itemID) + { + return ID_SET.contains(itemID); + } +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/keptondeath/KeptOnDeathPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/keptondeath/KeptOnDeathPlugin.java index ba38a6b615..0ffb3f0861 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/keptondeath/KeptOnDeathPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/keptondeath/KeptOnDeathPlugin.java @@ -1,598 +1,599 @@ -/* - * Copyright (c) 2018, 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.keptondeath; - -import java.text.DecimalFormat; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.EnumSet; -import java.util.LinkedHashMap; -import java.util.List; -import javax.inject.Inject; -import lombok.Getter; -import lombok.extern.slf4j.Slf4j; -import net.runelite.api.Client; -import net.runelite.api.FontID; -import net.runelite.api.InventoryID; -import net.runelite.api.Item; -import net.runelite.api.ItemComposition; -import net.runelite.api.ItemContainer; -import net.runelite.api.ItemID; -import net.runelite.api.ScriptID; -import net.runelite.api.SkullIcon; -import net.runelite.api.SpriteID; -import net.runelite.api.Varbits; -import net.runelite.api.WorldType; -import net.runelite.api.events.ScriptCallbackEvent; -import net.runelite.api.vars.AccountType; -import net.runelite.api.widgets.Widget; -import net.runelite.api.widgets.WidgetInfo; -import net.runelite.api.widgets.WidgetType; -import net.runelite.client.eventbus.Subscribe; -import net.runelite.client.game.ItemManager; -import net.runelite.client.game.ItemVariationMapping; -import net.runelite.client.plugins.Plugin; -import net.runelite.client.plugins.PluginDescriptor; -import net.runelite.client.plugins.PluginType; - -@PluginDescriptor( - name = "Kept on Death", - description = "Reworks the Items Kept on Death interface to be more accurate", - enabledByDefault = false, - type = PluginType.UTILITY -) -@Slf4j -public class KeptOnDeathPlugin extends Plugin -{ - // Handles Clicking on items in Kept on Death Interface - private static final int SCRIPT_ID = ScriptID.KEPT_LOST_ITEM_EXAMINE; - private static final double HIGH_ALCH = 0.6; - - // Item Container helpers - private static final int MAX_ROW_ITEMS = 8; - private static final int STARTING_X = 5; - private static final int STARTING_Y = 25; - private static final int X_INCREMENT = 40; - private static final int Y_INCREMENT = 38; - private static final int ORIGINAL_WIDTH = 36; - private static final int ORIGINAL_HEIGHT = 32; - private static final int ORIGINAL_LOST_HEIGHT = 209; - private static final int ORIGINAL_LOST_Y = 107; - - // Information panel text helpers - private static final DecimalFormat NUMBER_FORMAT = new DecimalFormat("#,###"); - private static final String MAX_KEPT_ITEMS_FORMAT = "Max items kept on death :

~ %s ~"; - private static final String ACTION_TEXT = "Item: %s"; - private static final String DEFAULT = "3 items protected by default"; - private static final String IS_SKULLED = "PK skull -3"; - private static final String PROTECTING_ITEM = "Protect Item prayer +1"; - private static final String ACTUAL = "Actually protecting %s items"; - private static final String WHITE_OUTLINE = "Items with a white outline will always be lost."; - private static final String CHANGED_MECHANICS = "Untradeable items are kept on death in non-pvp scenarios."; - private static final String NON_PVP = "You will have 1 hour to retrieve your lost items."; - private static final String LINE_BREAK = "
"; - private static final String UIM_DEFAULT = "You are an UIM which means 0 items are protected by default"; - private static final int ORIGINAL_INFO_HEIGHT = 183; - private static final int FONT_COLOR = 0xFF981F; - - // Button Names and Images - private static final String PROTECT_ITEM_BUTTON_NAME = "Protect Item Prayer"; - private static final String SKULLED_BUTTON_NAME = "Skulled"; - private static final String LOW_WILDY_BUTTON_NAME = "Low Wildy (1-20)"; - private static final String DEEP_WILDY_BUTTON_NAME = "Deep Wildy (21+)"; - private static final int PROTECT_ITEM_SPRITE_ID = SpriteID.PRAYER_PROTECT_ITEM; - private static final int SKULL_SPRITE_ID = SpriteID.PLAYER_KILLER_SKULL_523; - private static final int SWORD_SPRITE_ID = SpriteID.MULTI_COMBAT_ZONE_CROSSED_SWORDS; - private static final int SKULL_2_SPRITE_ID = SpriteID.FIGHT_PITS_WINNER_SKULL_RED; - - @Inject - private Client client; - - @Inject - private ItemManager itemManager; - - @Getter - private boolean widgetVisible = false; - - private LinkedHashMap buttonMap = new LinkedHashMap<>(); - private boolean isSkulled = false; - private boolean protectingItem = false; - private boolean hasAlwaysLost = false; - private int wildyLevel = -1; - - @Subscribe - protected void onScriptCallbackEvent(ScriptCallbackEvent event) - { - if (event.getEventName().equals("deathKeepBuild")) - { - // The script in charge of building the Items Kept on Death interface has finished running. - // Make all necessary changes now. - - // Players inside Safe Areas (POH/Clan Wars) & playing DMM see the default interface - if (isInSafeArea() || client.getWorldType().contains(WorldType.DEADMAN)) - { - return; - } - - syncSettings(); - createWidgetButtons(); - recreateItemsKeptOnDeathWidget(); - } - } - - // Sync user settings - private void syncSettings() - { - SkullIcon s = client.getLocalPlayer().getSkullIcon(); - // Ultimate iron men deaths are treated like they are always skulled - isSkulled = (s != null && s.equals(SkullIcon.SKULL)) || isUltimateIronman(); - protectingItem = client.getVar(Varbits.PRAYER_PROTECT_ITEM) == 1; - syncCurrentWildyLevel(); - } - - private void syncCurrentWildyLevel() - { - if (client.getVar(Varbits.IN_WILDERNESS) != 1) - { - // if they are in a PvP world and not in a safe zone act like in lvl 1 wildy - if (isInPvpWorld() && !isInPvPSafeZone()) - { - wildyLevel = 1; - return; - } - wildyLevel = -1; - return; - } - - int y = client.getLocalPlayer().getWorldLocation().getY(); - - // Credits to atomicint_#5069 (Discord) - int underLevel = ((y - 9920) / 8) + 1; - int upperLevel = ((y - 3520) / 8) + 1; - wildyLevel = (y > 6400 ? underLevel : upperLevel); - } - - private boolean isInPvpWorld() - { - EnumSet world = client.getWorldType(); - return world.contains(WorldType.PVP) || world.contains(WorldType.HIGH_RISK); - } - - private boolean isInPvPSafeZone() - { - Widget w = client.getWidget(WidgetInfo.PVP_WORLD_SAFE_ZONE); - return w != null && !w.isHidden(); - } - - private boolean isInSafeArea() - { - Widget w = client.getWidget(WidgetInfo.ITEMS_KEPT_SAFE_ZONE_CONTAINER); - return w != null && !w.isHidden(); - } - - private boolean isUltimateIronman() - { - return client.getAccountType().equals(AccountType.ULTIMATE_IRONMAN); - } - - private int getDefaultItemsKept() - { - int count = isSkulled ? 0 : 3; - - if (protectingItem) - { - count++; - } - - return count; - } - - private void recreateItemsKeptOnDeathWidget() - { - // Text flags based on items should be reset everytime the widget is recreated - hasAlwaysLost = false; - - Widget lost = client.getWidget(WidgetInfo.ITEMS_LOST_ON_DEATH_CONTAINER); - Widget kept = client.getWidget(WidgetInfo.ITEMS_KEPT_ON_DEATH_CONTAINER); - if (lost != null && kept != null) - { - // Grab all items on player and sort by price. - List items = new ArrayList<>(); - ItemContainer inventory = client.getItemContainer(InventoryID.INVENTORY); - Item[] inv = inventory == null ? new Item[0] : inventory.getItems(); - ItemContainer equipment = client.getItemContainer(InventoryID.EQUIPMENT); - Item[] equip = equipment == null ? new Item[0] : equipment.getItems(); - Collections.addAll(items, inv); - Collections.addAll(items, equip); - // Sort by item price - items.sort((o1, o2) -> - { - int o1ID = ItemVariationMapping.map(itemManager.canonicalize(o1.getId())); - int o2ID = ItemVariationMapping.map(itemManager.canonicalize(o2.getId())); - ItemComposition c1 = itemManager.getItemComposition(o1ID); - ItemComposition c2 = itemManager.getItemComposition(o2ID); - int exchangePrice1 = c1.isTradeable() ? itemManager.getItemPrice(c1.getId()) : c1.getPrice(); - int exchangePrice2 = c2.isTradeable() ? itemManager.getItemPrice(c2.getId()) : c2.getPrice(); - return exchangePrice2 - exchangePrice1; - }); - - int keepCount = getDefaultItemsKept(); - - List keptItems = new ArrayList<>(); - List lostItems = new ArrayList<>(); - for (Item i : items) - { - int id = i.getId(); - if (id == -1) - { - continue; - } - - ItemComposition c = itemManager.getItemComposition(i.getId()); - Widget itemWidget = createItemWidget(i.getQuantity(), c); - - // Bonds are always kept and do not count towards the limit. - if (id == ItemID.OLD_SCHOOL_BOND || id == ItemID.OLD_SCHOOL_BOND_UNTRADEABLE) - { - keptItems.add(itemWidget); - continue; - } - - // Certain items are always lost on death and have a white outline which we need to readd - AlwaysLostItem item = AlwaysLostItem.getByItemID(i.getId()); - if (item != null) - { - // Some of these items are kept on death (outside wildy), like the Rune pouch. Ignore them - if (!item.isKept() || wildyLevel > 0) - { - itemWidget.setOnOpListener(SCRIPT_ID, 0, i.getQuantity(), c.getName()); - itemWidget.setBorderType(2); - lostItems.add(itemWidget); - hasAlwaysLost = true; - continue; - } - } - - // Keep most valuable items regardless of trade-ability. - if (keepCount > 0) - { - if (i.getQuantity() > keepCount) - { - keptItems.add(createItemWidget(keepCount, c)); - itemWidget.setItemQuantity(i.getQuantity() - keepCount); - keepCount = 0; - } - else - { - keptItems.add(itemWidget); - keepCount -= i.getQuantity(); - continue; - } - } - - - if (!checkTradeable(i.getId(), c) && wildyLevel < 21) - { - // Certain items are turned into broken variants inside the wilderness. - if (BrokenOnDeathItem.check(i.getId())) - { - keptItems.add(itemWidget); - continue; - } - - // Ignore all non tradeables in wildy except for the above case(s). - if (wildyLevel > 0) - { - lostItems.add(itemWidget); - continue; - } - - keptItems.add(itemWidget); - } - else - { - itemWidget.setOnOpListener(SCRIPT_ID, 0, i.getQuantity(), c.getName()); - lostItems.add(itemWidget); - } - } - - int rows = keptItems.size() > MAX_ROW_ITEMS ? keptItems.size() / MAX_ROW_ITEMS : 0; - // Adjust items lost container position if new rows were added to kept items container - lost.setOriginalY(ORIGINAL_LOST_Y + (rows * Y_INCREMENT)); - lost.setOriginalHeight(ORIGINAL_LOST_HEIGHT - (rows * Y_INCREMENT)); - setWidgetChildren(kept, keptItems); - setWidgetChildren(lost, lostItems); - - updateKeptWidgetInfoText(); - } - } - - /** - * Wrapper for widget.setChildren() but updates the child index and original positions - * Used for Items Kept and Lost containers - * - * @param parent Widget to override children - * @param widgets Children to set on parent - */ - private void setWidgetChildren(Widget parent, List widgets) - { - Widget[] children = parent.getChildren(); - if (children == null) - { - // Create a child so we can copy the returned Widget[] and avoid hn casting issues from creating a new Widget[] - parent.createChild(0, WidgetType.GRAPHIC); - children = parent.getChildren(); - } - Widget[] itemsArray = Arrays.copyOf(children, widgets.size()); - - int parentId = parent.getId(); - int startingIndex = 0; - for (Widget w : widgets) - { - int originalX = STARTING_X + ((startingIndex % MAX_ROW_ITEMS) * X_INCREMENT); - int originalY = STARTING_Y + ((startingIndex / MAX_ROW_ITEMS) * Y_INCREMENT); - - w.setParentId(parentId); - w.setId(parentId); - w.setIndex(startingIndex); - - w.setOriginalX(originalX); - w.setOriginalY(originalY); - w.revalidate(); - - itemsArray[startingIndex] = w; - startingIndex++; - } - - parent.setChildren(itemsArray); - parent.revalidate(); - } - - /** - * Creates the text to be displayed in the right side of the interface based on current selections - */ - private String getUpdatedInfoText() - { - String textToAdd = DEFAULT; - - if (isUltimateIronman()) - { - textToAdd = UIM_DEFAULT; - } - else - { - if (isSkulled) - { - textToAdd += LINE_BREAK + IS_SKULLED; - } - - if (protectingItem) - { - textToAdd += LINE_BREAK + PROTECTING_ITEM; - } - - textToAdd += LINE_BREAK + String.format(ACTUAL, getDefaultItemsKept()); - } - - - if (wildyLevel < 1) - { - textToAdd += LINE_BREAK + LINE_BREAK + NON_PVP; - } - - if (hasAlwaysLost) - { - textToAdd += LINE_BREAK + LINE_BREAK + WHITE_OUTLINE; - } - - textToAdd += LINE_BREAK + LINE_BREAK + CHANGED_MECHANICS; - - return textToAdd; - } - - /** - * Corrects the Information panel based on the item containers - */ - private void updateKeptWidgetInfoText() - { - // Add Information text widget - createNewTextWidget(); - - // Update Items lost total value - Widget lost = client.getWidget(WidgetInfo.ITEMS_LOST_ON_DEATH_CONTAINER); - double total = 0; - for (Widget w : lost.getChildren()) - { - if (w.getItemId() == -1) - { - continue; - } - double price = itemManager.getItemPrice(w.getItemId()); - if (price == 0) - { - // Default to alch price - price = itemManager.getItemComposition(w.getItemId()).getPrice() * HIGH_ALCH; - } - total += price; - } - Widget lostValue = client.getWidget(WidgetInfo.ITEMS_LOST_VALUE); - lostValue.setText(NUMBER_FORMAT.format(total) + " gp"); - - // Update Max items kept - Widget kept = client.getWidget(WidgetInfo.ITEMS_KEPT_ON_DEATH_CONTAINER); - Widget max = client.getWidget(WidgetInfo.ITEMS_KEPT_MAX); - max.setText(String.format(MAX_KEPT_ITEMS_FORMAT, kept.getChildren().length)); - } - - // isTradeable checks if they are traded on the grand exchange, some items are trade-able but not via GE - private boolean checkTradeable(int id, ItemComposition c) - { - // If the item is a note check the unnoted variants trade ability - if (c.getNote() != -1) - { - return checkTradeable(c.getLinkedNoteId(), itemManager.getItemComposition(c.getLinkedNoteId())); - } - - switch (id) - { - case ItemID.COINS_995: - case ItemID.PLATINUM_TOKEN: - return true; - default: - if (ActuallyTradeableItem.check(id)) - { - return true; - } - } - - return c.isTradeable(); - } - - private void createNewTextWidget() - { - // The text use to be put inside this container but since we can't create LAYER widgets - // We needed to edit this to be a layer for adding buttons - Widget old = client.getWidget(WidgetInfo.ITEMS_KEPT_INFORMATION_CONTAINER); - - // Update the existing TEXT container if it exists. It should be the last child of the old text widget - // client.getWidget() seems to not find indexed child widgets - Widget[] children = old.getChildren(); - if (children != null && children.length > 0) - { - Widget x = old.getChild(children.length - 1); - if (x.getId() == WidgetInfo.ITEMS_KEPT_CUSTOM_TEXT_CONTAINER.getId()) - { - x.setText(getUpdatedInfoText()); - x.revalidate(); - return; - } - } - - Widget w = old.createChild(-1, WidgetType.TEXT); - // Position under buttons taking remaining space - w.setOriginalWidth(old.getOriginalWidth()); - w.setOriginalHeight(ORIGINAL_INFO_HEIGHT - old.getOriginalHeight()); - w.setOriginalY(old.getOriginalHeight()); - - w.setFontId(FontID.PLAIN_11); - w.setTextShadowed(true); - w.setTextColor(FONT_COLOR); - - w.setText(getUpdatedInfoText()); - w.setId(WidgetInfo.ITEMS_KEPT_CUSTOM_TEXT_CONTAINER.getId()); - w.revalidate(); - - // Need to reset height so text is visible? - old.setOriginalHeight(ORIGINAL_INFO_HEIGHT); - old.revalidate(); - } - - private void createWidgetButtons() - { - buttonMap.clear(); - - // Ultimate Iron men are always skulled and can't use the protect item prayer - if (!isUltimateIronman()) - { - createButton(PROTECT_ITEM_BUTTON_NAME, PROTECT_ITEM_SPRITE_ID, protectingItem); - createButton(SKULLED_BUTTON_NAME, SKULL_SPRITE_ID, isSkulled); - } - createButton(LOW_WILDY_BUTTON_NAME, SWORD_SPRITE_ID, wildyLevel > 0 && wildyLevel <= 20); - createButton(DEEP_WILDY_BUTTON_NAME, SKULL_2_SPRITE_ID, wildyLevel > 20); - - Widget parent = client.getWidget(WidgetInfo.ITEMS_KEPT_INFORMATION_CONTAINER); - parent.setType(WidgetType.LAYER); - parent.revalidate(); - WidgetButton.addButtonsToContainerWidget(parent, buttonMap.values()); - } - - private void createButton(String name, int spriteID, boolean startingFlag) - { - WidgetButton button = new WidgetButton(name, spriteID, startingFlag, this::buttonCallback, client); - buttonMap.put(name, button); - } - - private void buttonCallback(String name, boolean selected) - { - log.debug("Clicked Widget Button {}. New value: {}", name, selected); - switch (name) - { - case PROTECT_ITEM_BUTTON_NAME: - protectingItem = selected; - break; - case SKULLED_BUTTON_NAME: - isSkulled = selected; - break; - case LOW_WILDY_BUTTON_NAME: - if (!selected) - { - syncCurrentWildyLevel(); - break; - } - wildyLevel = 1; - buttonMap.get(DEEP_WILDY_BUTTON_NAME).setSelected(false); - break; - case DEEP_WILDY_BUTTON_NAME: - if (!selected) - { - syncCurrentWildyLevel(); - break; - } - wildyLevel = 21; - buttonMap.get(LOW_WILDY_BUTTON_NAME).setSelected(false); - break; - default: - log.warn("Unhandled Button Name: {}", name); - return; - } - - recreateItemsKeptOnDeathWidget(); - } - - /** - * Creates an Item Widget for use inside the Kept on Death Interface - * @param qty Amount of item - * @param c Items Composition - * @return - */ - private Widget createItemWidget(int qty, ItemComposition c) - { - Widget itemWidget = client.createWidget(); - itemWidget.setType(WidgetType.GRAPHIC); - itemWidget.setItemId(c.getId()); - itemWidget.setItemQuantity(qty); - itemWidget.setHasListener(true); - itemWidget.setIsIf3(true); - itemWidget.setOriginalWidth(ORIGINAL_WIDTH); - itemWidget.setOriginalHeight(ORIGINAL_HEIGHT); - itemWidget.setBorderType(1); - - itemWidget.setAction(1, String.format(ACTION_TEXT, c.getName())); - itemWidget.setOnOpListener(SCRIPT_ID, 1, qty, c.getName()); - - return itemWidget; - } +/* + * Copyright (c) 2018, 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.keptondeath; + +import java.text.DecimalFormat; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.EnumSet; +import java.util.LinkedHashMap; +import java.util.List; +import javax.inject.Inject; +import lombok.Getter; +import lombok.extern.slf4j.Slf4j; +import net.runelite.api.Client; +import net.runelite.api.FontID; +import net.runelite.api.InventoryID; +import net.runelite.api.Item; +import net.runelite.api.ItemComposition; +import net.runelite.api.ItemContainer; +import net.runelite.api.ItemID; +import net.runelite.api.ScriptID; +import net.runelite.api.SkullIcon; +import net.runelite.api.SpriteID; +import net.runelite.api.Varbits; +import net.runelite.api.WorldType; +import net.runelite.api.events.ScriptCallbackEvent; +import net.runelite.api.vars.AccountType; +import net.runelite.api.widgets.Widget; +import net.runelite.api.widgets.WidgetInfo; +import net.runelite.api.widgets.WidgetType; +import net.runelite.client.eventbus.Subscribe; +import net.runelite.client.game.ItemManager; +import net.runelite.client.game.ItemVariationMapping; +import net.runelite.client.plugins.Plugin; +import net.runelite.client.plugins.PluginDescriptor; +import net.runelite.client.plugins.PluginType; + +@PluginDescriptor( + name = "Kept on Death", + description = "Reworks the Items Kept on Death interface to be more accurate", + enabledByDefault = false, + type = PluginType.UTILITY +) +@Slf4j +public class KeptOnDeathPlugin extends Plugin +{ + // Handles Clicking on items in Kept on Death Interface + private static final int SCRIPT_ID = ScriptID.KEPT_LOST_ITEM_EXAMINE; + private static final double HIGH_ALCH = 0.6; + + // Item Container helpers + private static final int MAX_ROW_ITEMS = 8; + private static final int STARTING_X = 5; + private static final int STARTING_Y = 25; + private static final int X_INCREMENT = 40; + private static final int Y_INCREMENT = 38; + private static final int ORIGINAL_WIDTH = 36; + private static final int ORIGINAL_HEIGHT = 32; + private static final int ORIGINAL_LOST_HEIGHT = 209; + private static final int ORIGINAL_LOST_Y = 107; + + // Information panel text helpers + private static final DecimalFormat NUMBER_FORMAT = new DecimalFormat("#,###"); + private static final String MAX_KEPT_ITEMS_FORMAT = "Max items kept on death :

~ %s ~"; + private static final String ACTION_TEXT = "Item: %s"; + private static final String DEFAULT = "3 items protected by default"; + private static final String IS_SKULLED = "PK skull -3"; + private static final String PROTECTING_ITEM = "Protect Item prayer +1"; + private static final String ACTUAL = "Actually protecting %s items"; + private static final String WHITE_OUTLINE = "Items with a white outline will always be lost."; + private static final String CHANGED_MECHANICS = "Untradeable items are kept on death in non-pvp scenarios."; + private static final String NON_PVP = "You will have 1 hour to retrieve your lost items."; + private static final String LINE_BREAK = "
"; + private static final String UIM_DEFAULT = "You are an UIM which means 0 items are protected by default"; + private static final int ORIGINAL_INFO_HEIGHT = 183; + private static final int FONT_COLOR = 0xFF981F; + + // Button Names and Images + private static final String PROTECT_ITEM_BUTTON_NAME = "Protect Item Prayer"; + private static final String SKULLED_BUTTON_NAME = "Skulled"; + private static final String LOW_WILDY_BUTTON_NAME = "Low Wildy (1-20)"; + private static final String DEEP_WILDY_BUTTON_NAME = "Deep Wildy (21+)"; + private static final int PROTECT_ITEM_SPRITE_ID = SpriteID.PRAYER_PROTECT_ITEM; + private static final int SKULL_SPRITE_ID = SpriteID.PLAYER_KILLER_SKULL_523; + private static final int SWORD_SPRITE_ID = SpriteID.MULTI_COMBAT_ZONE_CROSSED_SWORDS; + private static final int SKULL_2_SPRITE_ID = SpriteID.FIGHT_PITS_WINNER_SKULL_RED; + + @Inject + private Client client; + + @Inject + private ItemManager itemManager; + + @Getter + private boolean widgetVisible = false; + + private LinkedHashMap buttonMap = new LinkedHashMap<>(); + private boolean isSkulled = false; + private boolean protectingItem = false; + private boolean hasAlwaysLost = false; + private int wildyLevel = -1; + + @Subscribe + protected void onScriptCallbackEvent(ScriptCallbackEvent event) + { + if (event.getEventName().equals("deathKeepBuild")) + { + // The script in charge of building the Items Kept on Death interface has finished running. + // Make all necessary changes now. + + // Players inside Safe Areas (POH/Clan Wars) & playing DMM see the default interface + if (isInSafeArea() || client.getWorldType().contains(WorldType.DEADMAN)) + { + return; + } + + syncSettings(); + createWidgetButtons(); + recreateItemsKeptOnDeathWidget(); + } + } + + // Sync user settings + private void syncSettings() + { + SkullIcon s = client.getLocalPlayer().getSkullIcon(); + // Ultimate iron men deaths are treated like they are always skulled + isSkulled = (s != null && s.equals(SkullIcon.SKULL)) || isUltimateIronman(); + protectingItem = client.getVar(Varbits.PRAYER_PROTECT_ITEM) == 1; + syncCurrentWildyLevel(); + } + + private void syncCurrentWildyLevel() + { + if (client.getVar(Varbits.IN_WILDERNESS) != 1) + { + // if they are in a PvP world and not in a safe zone act like in lvl 1 wildy + if (isInPvpWorld() && !isInPvPSafeZone()) + { + wildyLevel = 1; + return; + } + wildyLevel = -1; + return; + } + + int y = client.getLocalPlayer().getWorldLocation().getY(); + + // Credits to atomicint_#5069 (Discord) + int underLevel = ((y - 9920) / 8) + 1; + int upperLevel = ((y - 3520) / 8) + 1; + wildyLevel = (y > 6400 ? underLevel : upperLevel); + } + + private boolean isInPvpWorld() + { + EnumSet world = client.getWorldType(); + return world.contains(WorldType.PVP) || world.contains(WorldType.HIGH_RISK); + } + + private boolean isInPvPSafeZone() + { + Widget w = client.getWidget(WidgetInfo.PVP_WORLD_SAFE_ZONE); + return w != null && !w.isHidden(); + } + + private boolean isInSafeArea() + { + Widget w = client.getWidget(WidgetInfo.ITEMS_KEPT_SAFE_ZONE_CONTAINER); + return w != null && !w.isHidden(); + } + + private boolean isUltimateIronman() + { + return client.getAccountType().equals(AccountType.ULTIMATE_IRONMAN); + } + + private int getDefaultItemsKept() + { + int count = isSkulled ? 0 : 3; + + if (protectingItem) + { + count++; + } + + return count; + } + + private void recreateItemsKeptOnDeathWidget() + { + // Text flags based on items should be reset everytime the widget is recreated + hasAlwaysLost = false; + + Widget lost = client.getWidget(WidgetInfo.ITEMS_LOST_ON_DEATH_CONTAINER); + Widget kept = client.getWidget(WidgetInfo.ITEMS_KEPT_ON_DEATH_CONTAINER); + if (lost != null && kept != null) + { + // Grab all items on player and sort by price. + List items = new ArrayList<>(); + ItemContainer inventory = client.getItemContainer(InventoryID.INVENTORY); + Item[] inv = inventory == null ? new Item[0] : inventory.getItems(); + ItemContainer equipment = client.getItemContainer(InventoryID.EQUIPMENT); + Item[] equip = equipment == null ? new Item[0] : equipment.getItems(); + Collections.addAll(items, inv); + Collections.addAll(items, equip); + // Sort by item price + items.sort((o1, o2) -> + { + int o1ID = ItemVariationMapping.map(itemManager.canonicalize(o1.getId())); + int o2ID = ItemVariationMapping.map(itemManager.canonicalize(o2.getId())); + ItemComposition c1 = itemManager.getItemComposition(o1ID); + ItemComposition c2 = itemManager.getItemComposition(o2ID); + int exchangePrice1 = c1.isTradeable() ? itemManager.getItemPrice(c1.getId()) : c1.getPrice(); + int exchangePrice2 = c2.isTradeable() ? itemManager.getItemPrice(c2.getId()) : c2.getPrice(); + return exchangePrice2 - exchangePrice1; + }); + + int keepCount = getDefaultItemsKept(); + + List keptItems = new ArrayList<>(); + List lostItems = new ArrayList<>(); + for (Item i : items) + { + int id = i.getId(); + if (id == -1) + { + continue; + } + + ItemComposition c = itemManager.getItemComposition(i.getId()); + Widget itemWidget = createItemWidget(i.getQuantity(), c); + + // Bonds are always kept and do not count towards the limit. + if (id == ItemID.OLD_SCHOOL_BOND || id == ItemID.OLD_SCHOOL_BOND_UNTRADEABLE) + { + keptItems.add(itemWidget); + continue; + } + + // Certain items are always lost on death and have a white outline which we need to readd + AlwaysLostItem item = AlwaysLostItem.getByItemID(i.getId()); + if (item != null) + { + // Some of these items are kept on death (outside wildy), like the Rune pouch. Ignore them + if (!item.isKept() || wildyLevel > 0) + { + itemWidget.setOnOpListener(SCRIPT_ID, 0, i.getQuantity(), c.getName()); + itemWidget.setBorderType(2); + lostItems.add(itemWidget); + hasAlwaysLost = true; + continue; + } + } + + // Keep most valuable items regardless of trade-ability. + if (keepCount > 0) + { + if (i.getQuantity() > keepCount) + { + keptItems.add(createItemWidget(keepCount, c)); + itemWidget.setItemQuantity(i.getQuantity() - keepCount); + keepCount = 0; + } + else + { + keptItems.add(itemWidget); + keepCount -= i.getQuantity(); + continue; + } + } + + + if (!checkTradeable(i.getId(), c) && wildyLevel < 21) + { + // Certain items are turned into broken variants inside the wilderness. + if (BrokenOnDeathItem.check(i.getId())) + { + keptItems.add(itemWidget); + continue; + } + + // Ignore all non tradeables in wildy except for the above case(s). + if (wildyLevel > 0) + { + lostItems.add(itemWidget); + continue; + } + + keptItems.add(itemWidget); + } + else + { + itemWidget.setOnOpListener(SCRIPT_ID, 0, i.getQuantity(), c.getName()); + lostItems.add(itemWidget); + } + } + + int rows = keptItems.size() > MAX_ROW_ITEMS ? keptItems.size() / MAX_ROW_ITEMS : 0; + // Adjust items lost container position if new rows were added to kept items container + lost.setOriginalY(ORIGINAL_LOST_Y + (rows * Y_INCREMENT)); + lost.setOriginalHeight(ORIGINAL_LOST_HEIGHT - (rows * Y_INCREMENT)); + setWidgetChildren(kept, keptItems); + setWidgetChildren(lost, lostItems); + + updateKeptWidgetInfoText(); + } + } + + /** + * Wrapper for widget.setChildren() but updates the child index and original positions + * Used for Items Kept and Lost containers + * + * @param parent Widget to override children + * @param widgets Children to set on parent + */ + private void setWidgetChildren(Widget parent, List widgets) + { + Widget[] children = parent.getChildren(); + if (children == null) + { + // Create a child so we can copy the returned Widget[] and avoid hn casting issues from creating a new Widget[] + parent.createChild(0, WidgetType.GRAPHIC); + children = parent.getChildren(); + } + Widget[] itemsArray = Arrays.copyOf(children, widgets.size()); + + int parentId = parent.getId(); + int startingIndex = 0; + for (Widget w : widgets) + { + int originalX = STARTING_X + ((startingIndex % MAX_ROW_ITEMS) * X_INCREMENT); + int originalY = STARTING_Y + ((startingIndex / MAX_ROW_ITEMS) * Y_INCREMENT); + + w.setParentId(parentId); + w.setId(parentId); + w.setIndex(startingIndex); + + w.setOriginalX(originalX); + w.setOriginalY(originalY); + w.revalidate(); + + itemsArray[startingIndex] = w; + startingIndex++; + } + + parent.setChildren(itemsArray); + parent.revalidate(); + } + + /** + * Creates the text to be displayed in the right side of the interface based on current selections + */ + private String getUpdatedInfoText() + { + String textToAdd = DEFAULT; + + if (isUltimateIronman()) + { + textToAdd = UIM_DEFAULT; + } + else + { + if (isSkulled) + { + textToAdd += LINE_BREAK + IS_SKULLED; + } + + if (protectingItem) + { + textToAdd += LINE_BREAK + PROTECTING_ITEM; + } + + textToAdd += LINE_BREAK + String.format(ACTUAL, getDefaultItemsKept()); + } + + + if (wildyLevel < 1) + { + textToAdd += LINE_BREAK + LINE_BREAK + NON_PVP; + } + + if (hasAlwaysLost) + { + textToAdd += LINE_BREAK + LINE_BREAK + WHITE_OUTLINE; + } + + textToAdd += LINE_BREAK + LINE_BREAK + CHANGED_MECHANICS; + + return textToAdd; + } + + /** + * Corrects the Information panel based on the item containers + */ + private void updateKeptWidgetInfoText() + { + // Add Information text widget + createNewTextWidget(); + + // Update Items lost total value + Widget lost = client.getWidget(WidgetInfo.ITEMS_LOST_ON_DEATH_CONTAINER); + double total = 0; + for (Widget w : lost.getChildren()) + { + if (w.getItemId() == -1) + { + continue; + } + double price = itemManager.getItemPrice(w.getItemId()); + if (price == 0) + { + // Default to alch price + price = itemManager.getItemComposition(w.getItemId()).getPrice() * HIGH_ALCH; + } + total += price; + } + Widget lostValue = client.getWidget(WidgetInfo.ITEMS_LOST_VALUE); + lostValue.setText(NUMBER_FORMAT.format(total) + " gp"); + + // Update Max items kept + Widget kept = client.getWidget(WidgetInfo.ITEMS_KEPT_ON_DEATH_CONTAINER); + Widget max = client.getWidget(WidgetInfo.ITEMS_KEPT_MAX); + max.setText(String.format(MAX_KEPT_ITEMS_FORMAT, kept.getChildren().length)); + } + + // isTradeable checks if they are traded on the grand exchange, some items are trade-able but not via GE + private boolean checkTradeable(int id, ItemComposition c) + { + // If the item is a note check the unnoted variants trade ability + if (c.getNote() != -1) + { + return checkTradeable(c.getLinkedNoteId(), itemManager.getItemComposition(c.getLinkedNoteId())); + } + + switch (id) + { + case ItemID.COINS_995: + case ItemID.PLATINUM_TOKEN: + return true; + default: + if (ActuallyTradeableItem.check(id)) + { + return true; + } + } + + return c.isTradeable(); + } + + private void createNewTextWidget() + { + // The text use to be put inside this container but since we can't create LAYER widgets + // We needed to edit this to be a layer for adding buttons + Widget old = client.getWidget(WidgetInfo.ITEMS_KEPT_INFORMATION_CONTAINER); + + // Update the existing TEXT container if it exists. It should be the last child of the old text widget + // client.getWidget() seems to not find indexed child widgets + Widget[] children = old.getChildren(); + if (children != null && children.length > 0) + { + Widget x = old.getChild(children.length - 1); + if (x.getId() == WidgetInfo.ITEMS_KEPT_CUSTOM_TEXT_CONTAINER.getId()) + { + x.setText(getUpdatedInfoText()); + x.revalidate(); + return; + } + } + + Widget w = old.createChild(-1, WidgetType.TEXT); + // Position under buttons taking remaining space + w.setOriginalWidth(old.getOriginalWidth()); + w.setOriginalHeight(ORIGINAL_INFO_HEIGHT - old.getOriginalHeight()); + w.setOriginalY(old.getOriginalHeight()); + + w.setFontId(FontID.PLAIN_11); + w.setTextShadowed(true); + w.setTextColor(FONT_COLOR); + + w.setText(getUpdatedInfoText()); + w.setId(WidgetInfo.ITEMS_KEPT_CUSTOM_TEXT_CONTAINER.getId()); + w.revalidate(); + + // Need to reset height so text is visible? + old.setOriginalHeight(ORIGINAL_INFO_HEIGHT); + old.revalidate(); + } + + private void createWidgetButtons() + { + buttonMap.clear(); + + // Ultimate Iron men are always skulled and can't use the protect item prayer + if (!isUltimateIronman()) + { + createButton(PROTECT_ITEM_BUTTON_NAME, PROTECT_ITEM_SPRITE_ID, protectingItem); + createButton(SKULLED_BUTTON_NAME, SKULL_SPRITE_ID, isSkulled); + } + createButton(LOW_WILDY_BUTTON_NAME, SWORD_SPRITE_ID, wildyLevel > 0 && wildyLevel <= 20); + createButton(DEEP_WILDY_BUTTON_NAME, SKULL_2_SPRITE_ID, wildyLevel > 20); + + Widget parent = client.getWidget(WidgetInfo.ITEMS_KEPT_INFORMATION_CONTAINER); + parent.setType(WidgetType.LAYER); + parent.revalidate(); + WidgetButton.addButtonsToContainerWidget(parent, buttonMap.values()); + } + + private void createButton(String name, int spriteID, boolean startingFlag) + { + WidgetButton button = new WidgetButton(name, spriteID, startingFlag, this::buttonCallback, client); + buttonMap.put(name, button); + } + + private void buttonCallback(String name, boolean selected) + { + log.debug("Clicked Widget Button {}. New value: {}", name, selected); + switch (name) + { + case PROTECT_ITEM_BUTTON_NAME: + protectingItem = selected; + break; + case SKULLED_BUTTON_NAME: + isSkulled = selected; + break; + case LOW_WILDY_BUTTON_NAME: + if (!selected) + { + syncCurrentWildyLevel(); + break; + } + wildyLevel = 1; + buttonMap.get(DEEP_WILDY_BUTTON_NAME).setSelected(false); + break; + case DEEP_WILDY_BUTTON_NAME: + if (!selected) + { + syncCurrentWildyLevel(); + break; + } + wildyLevel = 21; + buttonMap.get(LOW_WILDY_BUTTON_NAME).setSelected(false); + break; + default: + log.warn("Unhandled Button Name: {}", name); + return; + } + + recreateItemsKeptOnDeathWidget(); + } + + /** + * Creates an Item Widget for use inside the Kept on Death Interface + * + * @param qty Amount of item + * @param c Items Composition + * @return + */ + private Widget createItemWidget(int qty, ItemComposition c) + { + Widget itemWidget = client.createWidget(); + itemWidget.setType(WidgetType.GRAPHIC); + itemWidget.setItemId(c.getId()); + itemWidget.setItemQuantity(qty); + itemWidget.setHasListener(true); + itemWidget.setIsIf3(true); + itemWidget.setOriginalWidth(ORIGINAL_WIDTH); + itemWidget.setOriginalHeight(ORIGINAL_HEIGHT); + itemWidget.setBorderType(1); + + itemWidget.setAction(1, String.format(ACTION_TEXT, c.getName())); + itemWidget.setOnOpListener(SCRIPT_ID, 1, qty, c.getName()); + + return itemWidget; + } } \ No newline at end of file diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/keptondeath/WidgetButton.java b/runelite-client/src/main/java/net/runelite/client/plugins/keptondeath/WidgetButton.java index 6385faf8aa..1a13b233a1 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/keptondeath/WidgetButton.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/keptondeath/WidgetButton.java @@ -1,175 +1,176 @@ -/* - * Copyright (c) 2018, 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.keptondeath; - -import java.util.Arrays; -import java.util.Collection; -import lombok.Getter; -import lombok.extern.slf4j.Slf4j; -import net.runelite.api.Client; -import net.runelite.api.SpriteID; -import net.runelite.api.widgets.JavaScriptCallback; -import net.runelite.api.widgets.Widget; -import net.runelite.api.widgets.WidgetType; - -@Slf4j -public class WidgetButton -{ - private static final int ICON_HEIGHT = 26; - private static final int ICON_WIDTH = 26; - private static final int BACKGROUND_HEIGHT = 32; - private static final int BACKGROUND_WIDTH = 32; - private static final int PADDING = 5; - private static final int ICON_PADDING = (BACKGROUND_HEIGHT - ICON_HEIGHT) / 2; - - private static final int BACKGROUND_SPRITE_ID = SpriteID.EQUIPMENT_SLOT_TILE; - private static final int SELECTED_BACKGROUND_SPRITE_ID = SpriteID.EQUIPMENT_SLOT_SELECTED; - - public interface WidgetButtonCallback - { - void run(String name, boolean newState); - } - - private String name; - private int spriteID; - @Getter - private Widget icon; - @Getter - private Widget background; - private boolean selected; - private WidgetButtonCallback callback; - - WidgetButton(String name, int spriteID, boolean selectedStartState, WidgetButtonCallback callback, Client client) - { - this.name = name; - this.spriteID = spriteID; - this.selected = selectedStartState; - this.callback = callback; - createBackgroundWidget(client); - createIconWidget(client); - } - - private void createBackgroundWidget(Client client) - { - background = createWidget(client); - background.setOriginalWidth(BACKGROUND_WIDTH); - background.setOriginalHeight(BACKGROUND_HEIGHT); - syncBackgroundSprite(); - } - - private void createIconWidget(Client client) - { - icon = createWidget(client); - icon.setAction(1, "Toggle:"); - icon.setOnOpListener((JavaScriptCallback) ev -> onButtonClicked()); - icon.setHasListener(true); - icon.setSpriteId(spriteID); - } - - private Widget createWidget(Client client) - { - Widget w = client.createWidget(); - w.setType(WidgetType.GRAPHIC); - w.setOriginalWidth(ICON_WIDTH); - w.setOriginalHeight(ICON_HEIGHT); - w.setName("" + this.name); - w.setIsIf3(true); - return w; - } - - public void setSelected(boolean selected) - { - this.selected = selected; - syncBackgroundSprite(); - } - - private void syncBackgroundSprite() - { - background.setSpriteId(selected ? SELECTED_BACKGROUND_SPRITE_ID : BACKGROUND_SPRITE_ID); - } - - /** - * Adds the collection of WidgetButtons to the container overriding any existing children. - * @param container Widget to add buttons too - * @param buttons buttons to add - */ - static void addButtonsToContainerWidget(Widget container, Collection buttons) - { - Widget[] children = container.getChildren(); - if (children == null) - { - // Create a child so we can copy the returned Widget[] and avoid hn casting issues from creating a new Widget[] - container.createChild(0, WidgetType.GRAPHIC); - children = container.getChildren(); - } - // Each button has two widgets, Icon and Background - Widget[] itemsArray = Arrays.copyOf(children, buttons.size() * 2); - int parentId = container.getId(); - - int xIncrement = BACKGROUND_WIDTH + PADDING; - int yIncrement = BACKGROUND_HEIGHT + PADDING; - int maxRowItems = container.getWidth() / xIncrement; - // Ensure at least 1 button per row - maxRowItems = maxRowItems < 1 ? 1 : maxRowItems; - - int startingIndex = 0; - for (WidgetButton w : buttons) - { - int originalX = (((startingIndex / 2) % maxRowItems) * xIncrement); - int originalY = (((startingIndex / 2) / maxRowItems) * yIncrement); - Widget background = updateWidgetPosition(w.getBackground(), parentId, startingIndex, originalX, originalY); - itemsArray[startingIndex] = background; - startingIndex++; - // Icon must be padded to center inside image - Widget icon = updateWidgetPosition(w.getIcon(), parentId, startingIndex, originalX + ICON_PADDING, originalY + ICON_PADDING); - itemsArray[startingIndex] = icon; - startingIndex++; - } - - int rows = 1 + (buttons.size() > maxRowItems ? buttons.size() / maxRowItems : 0); - container.setOriginalHeight(yIncrement * rows); - container.setChildren(itemsArray); - container.revalidate(); - } - - private static Widget updateWidgetPosition(Widget w, int id, int index, int originalX, int originalY) - { - w.setParentId(id); - w.setId(id); - w.setIndex(index); - - w.setOriginalX(originalX); - w.setOriginalY(originalY); - w.revalidate(); - - return w; - } - - private void onButtonClicked() - { - setSelected(!selected); - callback.run(name, selected); - } -} +/* + * Copyright (c) 2018, 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.keptondeath; + +import java.util.Arrays; +import java.util.Collection; +import lombok.Getter; +import lombok.extern.slf4j.Slf4j; +import net.runelite.api.Client; +import net.runelite.api.SpriteID; +import net.runelite.api.widgets.JavaScriptCallback; +import net.runelite.api.widgets.Widget; +import net.runelite.api.widgets.WidgetType; + +@Slf4j +public class WidgetButton +{ + private static final int ICON_HEIGHT = 26; + private static final int ICON_WIDTH = 26; + private static final int BACKGROUND_HEIGHT = 32; + private static final int BACKGROUND_WIDTH = 32; + private static final int PADDING = 5; + private static final int ICON_PADDING = (BACKGROUND_HEIGHT - ICON_HEIGHT) / 2; + + private static final int BACKGROUND_SPRITE_ID = SpriteID.EQUIPMENT_SLOT_TILE; + private static final int SELECTED_BACKGROUND_SPRITE_ID = SpriteID.EQUIPMENT_SLOT_SELECTED; + + public interface WidgetButtonCallback + { + void run(String name, boolean newState); + } + + private String name; + private int spriteID; + @Getter + private Widget icon; + @Getter + private Widget background; + private boolean selected; + private WidgetButtonCallback callback; + + WidgetButton(String name, int spriteID, boolean selectedStartState, WidgetButtonCallback callback, Client client) + { + this.name = name; + this.spriteID = spriteID; + this.selected = selectedStartState; + this.callback = callback; + createBackgroundWidget(client); + createIconWidget(client); + } + + private void createBackgroundWidget(Client client) + { + background = createWidget(client); + background.setOriginalWidth(BACKGROUND_WIDTH); + background.setOriginalHeight(BACKGROUND_HEIGHT); + syncBackgroundSprite(); + } + + private void createIconWidget(Client client) + { + icon = createWidget(client); + icon.setAction(1, "Toggle:"); + icon.setOnOpListener((JavaScriptCallback) ev -> onButtonClicked()); + icon.setHasListener(true); + icon.setSpriteId(spriteID); + } + + private Widget createWidget(Client client) + { + Widget w = client.createWidget(); + w.setType(WidgetType.GRAPHIC); + w.setOriginalWidth(ICON_WIDTH); + w.setOriginalHeight(ICON_HEIGHT); + w.setName("" + this.name); + w.setIsIf3(true); + return w; + } + + public void setSelected(boolean selected) + { + this.selected = selected; + syncBackgroundSprite(); + } + + private void syncBackgroundSprite() + { + background.setSpriteId(selected ? SELECTED_BACKGROUND_SPRITE_ID : BACKGROUND_SPRITE_ID); + } + + /** + * Adds the collection of WidgetButtons to the container overriding any existing children. + * + * @param container Widget to add buttons too + * @param buttons buttons to add + */ + static void addButtonsToContainerWidget(Widget container, Collection buttons) + { + Widget[] children = container.getChildren(); + if (children == null) + { + // Create a child so we can copy the returned Widget[] and avoid hn casting issues from creating a new Widget[] + container.createChild(0, WidgetType.GRAPHIC); + children = container.getChildren(); + } + // Each button has two widgets, Icon and Background + Widget[] itemsArray = Arrays.copyOf(children, buttons.size() * 2); + int parentId = container.getId(); + + int xIncrement = BACKGROUND_WIDTH + PADDING; + int yIncrement = BACKGROUND_HEIGHT + PADDING; + int maxRowItems = container.getWidth() / xIncrement; + // Ensure at least 1 button per row + maxRowItems = maxRowItems < 1 ? 1 : maxRowItems; + + int startingIndex = 0; + for (WidgetButton w : buttons) + { + int originalX = (((startingIndex / 2) % maxRowItems) * xIncrement); + int originalY = (((startingIndex / 2) / maxRowItems) * yIncrement); + Widget background = updateWidgetPosition(w.getBackground(), parentId, startingIndex, originalX, originalY); + itemsArray[startingIndex] = background; + startingIndex++; + // Icon must be padded to center inside image + Widget icon = updateWidgetPosition(w.getIcon(), parentId, startingIndex, originalX + ICON_PADDING, originalY + ICON_PADDING); + itemsArray[startingIndex] = icon; + startingIndex++; + } + + int rows = 1 + (buttons.size() > maxRowItems ? buttons.size() / maxRowItems : 0); + container.setOriginalHeight(yIncrement * rows); + container.setChildren(itemsArray); + container.revalidate(); + } + + private static Widget updateWidgetPosition(Widget w, int id, int index, int originalX, int originalY) + { + w.setParentId(id); + w.setId(id); + w.setIndex(index); + + w.setOriginalX(originalX); + w.setOriginalY(originalY); + w.revalidate(); + + return w; + } + + private void onButtonClicked() + { + setSelected(!selected); + callback.run(name, selected); + } +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/kourendlibrary/Library.java b/runelite-client/src/main/java/net/runelite/client/plugins/kourendlibrary/Library.java index 02618031db..79bd7f4889 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/kourendlibrary/Library.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/kourendlibrary/Library.java @@ -1,800 +1,824 @@ -/* - * Copyright (c) 2018 Abex - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package net.runelite.client.plugins.kourendlibrary; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.stream.IntStream; -import javax.inject.Singleton; -import lombok.Getter; -import lombok.extern.slf4j.Slf4j; -import net.runelite.api.coords.WorldPoint; - -import static net.runelite.client.plugins.kourendlibrary.Book.*; - -/** - * Library represents a instance of the Kourend/Arceuus House library. - *

- * The library changes the locations of it's books every 60-90 minutes. - * Of the 554 bookcases in the library, only 346 of them can ever have books. - * 6 of the bookcases in the south-west corner of the top floor are duplicated. - * These 6 bookcases are not handled 100% correctly due to their low chance - * of being used to train the predictor. - *

- * Each of the 352 bookcase slots "Bookcase"s has an index which is used to - * place the book inside of them. The game chooses one of the 5 sequences and a - * bookcase starting index, then places a book from the sequence into every 13th - * bookcase, by index. Each sequence contains 26 Books, consisting of 16 books - * and 10 dark manuscripts. You can only get one dark manuscript at a time, though - * they are all placed into shelves. - */ -@Singleton -@Slf4j -class Library -{ - private final Map byPoint = new HashMap<>(); - private final Map> byLevel = new HashMap<>(); - private final List byIndex = new ArrayList<>(); - - private final List> sequences = populateSequences(); - - private final int step; - - @Getter - private SolvedState state; - - @Getter - private Book customerBook; - - @Getter - private LibraryCustomer customer; - - Library() - { - populateBooks(); - step = byIndex.size() / Book.values().length; - reset(); - } - - synchronized List getBookcasesOnLevel(int z) - { - return Collections.unmodifiableList(byLevel.get(z)); - } - - synchronized List getBookcases() - { - return Collections.unmodifiableList(byIndex); - } - - void setCustomer(LibraryCustomer customer, Book book) - { - this.customer = customer; - this.customerBook = book; - } - - synchronized void reset() - { - state = SolvedState.NO_DATA; - for (Bookcase b : byIndex) - { - b.clearBook(); - b.getPossibleBooks().clear(); - } - log.info("Library is now reset"); - } - - synchronized void mark(WorldPoint loc, Book book) - { - Bookcase bookcase = byPoint.get(loc); - if (bookcase == null) - { - log.debug("Requested non-existent bookcase at {}", loc); - return; - } - - if (bookcase.isBookSet()) - { - // Bookcase is set from a previous mark - // Check for a mismatch, unless it is now null and had a dark manuscript - if (book != bookcase.getBook() && !(book == null && bookcase.getBook().isDarkManuscript())) - { - reset(); - } - } - else if (state != SolvedState.NO_DATA) - { - // We know all of the possible things in this shelf. - if (book != null) - { - // Check to see if our guess is wrong - if (!bookcase.getPossibleBooks().contains(book)) - { - reset(); - } - } - } - - // Everything is known, nothing to do - if (state == SolvedState.COMPLETE) - { - return; - } - - log.info("Setting bookcase {} to {}", bookcase.getIndex(), book); - for (; ; ) - { - bookcase.setBook(book); - - // Basing the sequences on null is not supported, though possible - if (book == null) - { - return; - } - - // This is one of the 6 bookcases with 2 ids. Not fully supported. - if (bookcase.getIndex().size() != 1) - { - return; - } - - int bookcaseIndex = bookcase.getIndex().get(0); - - state = SolvedState.INCOMPLETE; - - // Map each sequence to the number of bookcases that match the sequence - // return 0 if it is a mismatch. - // Keep in mind that Bookcases with dark manuscripts may be set to null. - int[] certainty = sequences.stream().mapToInt(sequence -> - { - int zero = getBookcaseZeroIndexForSequenceWithBook(sequence, bookcaseIndex, book); - - int found = 0; - for (int i = 0; i < byIndex.size(); i++) - { - int ai = (i + zero) % byIndex.size(); - Bookcase iBookcase = byIndex.get(ai); - if (i % step == 0) - { - int seqI = i / step; - if (iBookcase.isBookSet() && seqI < sequence.size()) - { - Book seqBook = sequence.get(seqI); - boolean isSeqManuscript = seqBook == null || seqBook.isDarkManuscript(); - if (!((isSeqManuscript && iBookcase.getBook() == null) || (iBookcase.getBook() == seqBook))) - { - log.debug("Bailing @ i={} ai={} {}; {} != {}", i, ai, iBookcase.getIndex(), iBookcase.getBook(), seqBook); - found = 0; - break; - } - found++; - } - } - else - { - // Only bail if this isn't a double bookcase - if (iBookcase.isBookSet() && iBookcase.getBook() != null && iBookcase.getIndex().size() == 1) - { - log.debug("Bailing @ i={} ai={} {}; {} is set", i, ai, iBookcase.getIndex(), iBookcase.getBook()); - found = 0; - break; - } - } - } - return found; - }).toArray(); - log.info("Certainty is now {}", certainty); - - for (Bookcase b : byIndex) - { - b.getPossibleBooks().clear(); - } - - // Write the most likely sequences onto the bookcases - int max = IntStream.of(certainty).max().getAsInt(); - - // We have books set, but 0 sequences match, Something is wrong, reset. - if (max == 0) - { - reset(); - continue; - } - - IntStream.range(0, sequences.size()) - .filter(i -> certainty[i] == max) - .forEach(isequence -> - { - List sequence = sequences.get(isequence); - int zero = getBookcaseZeroIndexForSequenceWithBook(sequence, bookcaseIndex, book); - - for (int i = 0; i < byIndex.size(); i++) - { - int ai = (i + zero) % byIndex.size(); - Bookcase iBookcase = byIndex.get(ai); - if (iBookcase.getBook() == null) - { - int iseq = i / step; - if (i % step == 0 && iseq < sequence.size()) - { - Book seqBook = sequence.get(iseq); - iBookcase.getPossibleBooks().add(seqBook); - } - } - } - }); - if (IntStream.range(0, certainty.length).filter(i -> certainty[i] == max).count() == 1) - { - state = SolvedState.COMPLETE; - } - return; - } - } - - /** - * Find the bookcase index that is index zero in the sequence, identifying by the book in bookcase - */ - private int getBookcaseZeroIndexForSequenceWithBook(List sequences, int bookcaseIndex, Book book) - { - int bookSequence = sequences.indexOf(book); - assert bookSequence >= 0; - - bookcaseIndex -= step * bookSequence; - for (; bookcaseIndex < 0; ) - { - bookcaseIndex += byIndex.size(); - } - return bookcaseIndex; - } - - private List> populateSequences() - { - List> books = Arrays.asList( - Arrays.asList( - DARK_MANUSCRIPT_13516, - KILLING_OF_A_KING, - DARK_MANUSCRIPT_13520, - IDEOLOGY_OF_DARKNESS, - RADAS_JOURNEY, - TRANSVERGENCE_THEORY, - TRISTESSAS_TRAGEDY, - DARK_MANUSCRIPT_13523, - DARK_MANUSCRIPT_13521, - RADAS_CENSUS, - TREACHERY_OF_ROYALTY, - HOSIDIUS_LETTER, - DARK_MANUSCRIPT_13519, - RICKTORS_DIARY_7, - DARK_MANUSCRIPT_13514, - EATHRAM_RADA_EXTRACT, - DARK_MANUSCRIPT_13522, - VARLAMORE_ENVOY, - WINTERTODT_PARABLE, - TWILL_ACCORD, - DARK_MANUSCRIPT_13515, - BYRNES_CORONATION_SPEECH, - DARK_MANUSCRIPT_13517, - SOUL_JOURNEY, - DARK_MANUSCRIPT_13518, - TRANSPORTATION_INCANTATIONS - ), - Arrays.asList( - DARK_MANUSCRIPT_13516, - KILLING_OF_A_KING, - DARK_MANUSCRIPT_13520, - IDEOLOGY_OF_DARKNESS, - RADAS_JOURNEY, - TRANSVERGENCE_THEORY, - TRISTESSAS_TRAGEDY, - DARK_MANUSCRIPT_13523, - DARK_MANUSCRIPT_13521, - RADAS_CENSUS, - TREACHERY_OF_ROYALTY, - HOSIDIUS_LETTER, - VARLAMORE_ENVOY, - DARK_MANUSCRIPT_13519, - RICKTORS_DIARY_7, - DARK_MANUSCRIPT_13514, - EATHRAM_RADA_EXTRACT, - DARK_MANUSCRIPT_13522, - SOUL_JOURNEY, - WINTERTODT_PARABLE, - TWILL_ACCORD, - DARK_MANUSCRIPT_13515, - BYRNES_CORONATION_SPEECH, - DARK_MANUSCRIPT_13517, - DARK_MANUSCRIPT_13518, - TRANSPORTATION_INCANTATIONS - ), - Arrays.asList( - RICKTORS_DIARY_7, - VARLAMORE_ENVOY, - DARK_MANUSCRIPT_13514, - EATHRAM_RADA_EXTRACT, - IDEOLOGY_OF_DARKNESS, - DARK_MANUSCRIPT_13516, - DARK_MANUSCRIPT_13521, - RADAS_CENSUS, - DARK_MANUSCRIPT_13515, - KILLING_OF_A_KING, - DARK_MANUSCRIPT_13520, - TREACHERY_OF_ROYALTY, - HOSIDIUS_LETTER, - DARK_MANUSCRIPT_13519, - BYRNES_CORONATION_SPEECH, - DARK_MANUSCRIPT_13517, - SOUL_JOURNEY, - DARK_MANUSCRIPT_13522, - WINTERTODT_PARABLE, - TWILL_ACCORD, - RADAS_JOURNEY, - TRANSVERGENCE_THEORY, - TRISTESSAS_TRAGEDY, - DARK_MANUSCRIPT_13523, - DARK_MANUSCRIPT_13518, - TRANSPORTATION_INCANTATIONS - ), - Arrays.asList( - RADAS_CENSUS, - DARK_MANUSCRIPT_13522, - RICKTORS_DIARY_7, - DARK_MANUSCRIPT_13514, - EATHRAM_RADA_EXTRACT, - DARK_MANUSCRIPT_13516, - KILLING_OF_A_KING, - DARK_MANUSCRIPT_13520, - HOSIDIUS_LETTER, - DARK_MANUSCRIPT_13519, - DARK_MANUSCRIPT_13521, - WINTERTODT_PARABLE, - TWILL_ACCORD, - DARK_MANUSCRIPT_13515, - BYRNES_CORONATION_SPEECH, - DARK_MANUSCRIPT_13517, - IDEOLOGY_OF_DARKNESS, - RADAS_JOURNEY, - TRANSVERGENCE_THEORY, - TRISTESSAS_TRAGEDY, - DARK_MANUSCRIPT_13523, - TREACHERY_OF_ROYALTY, - DARK_MANUSCRIPT_13518, - TRANSPORTATION_INCANTATIONS, - SOUL_JOURNEY, - VARLAMORE_ENVOY - ), - Arrays.asList( - RADAS_CENSUS, - TRANSVERGENCE_THEORY, - TREACHERY_OF_ROYALTY, - RADAS_JOURNEY, - KILLING_OF_A_KING, - DARK_MANUSCRIPT_13520, - VARLAMORE_ENVOY, - DARK_MANUSCRIPT_13522, - BYRNES_CORONATION_SPEECH, - DARK_MANUSCRIPT_13517, - HOSIDIUS_LETTER, - DARK_MANUSCRIPT_13516, - DARK_MANUSCRIPT_13519, - TRISTESSAS_TRAGEDY, - DARK_MANUSCRIPT_13523, - DARK_MANUSCRIPT_13521, - RICKTORS_DIARY_7, - DARK_MANUSCRIPT_13514, - IDEOLOGY_OF_DARKNESS, - WINTERTODT_PARABLE, - TWILL_ACCORD, - SOUL_JOURNEY, - DARK_MANUSCRIPT_13515, - EATHRAM_RADA_EXTRACT, - DARK_MANUSCRIPT_13518, - TRANSPORTATION_INCANTATIONS - ) - ); - - for (int i = 0; i < books.size(); i++) - { - assert new HashSet<>(books.get(i)).size() == books.get(i).size(); - books.set(i, Collections.unmodifiableList(books.get(i))); - } - return Collections.unmodifiableList(books); - } - - private void add(int x, int y, int z, int i) - { - // 'i' is added as a parameter for readability - WorldPoint p = new WorldPoint(x, y, z); - Bookcase b = byPoint.get(p); - if (b == null) - { - b = new Bookcase(p); - byPoint.put(p, b); - byLevel.computeIfAbsent(z, a -> new ArrayList<>()).add(b); - } - b.getIndex().add(i); - assert i == byIndex.size(); - byIndex.add(b); - } - - private void populateBooks() - { - add(1626, 3795, 0, 0); - add(1625, 3793, 0, 1); - add(1623, 3793, 0, 2); - add(1620, 3792, 0, 3); - add(1624, 3792, 0, 4); - add(1626, 3788, 0, 5); - add(1626, 3787, 0, 6); - add(1624, 3784, 0, 7); - add(1623, 3784, 0, 8); - add(1621, 3784, 0, 9); - add(1615, 3785, 0, 10); - add(1615, 3788, 0, 11); - add(1615, 3790, 0, 12); - add(1614, 3790, 0, 13); - add(1614, 3788, 0, 14); - add(1614, 3786, 0, 15); - add(1612, 3784, 0, 16); - add(1610, 3784, 0, 17); - add(1609, 3784, 0, 18); - add(1607, 3786, 0, 19); - add(1607, 3789, 0, 20); - add(1607, 3795, 0, 21); - add(1607, 3796, 0, 22); - add(1607, 3799, 0, 23); - add(1610, 3801, 0, 24); - add(1612, 3801, 0, 25); - add(1618, 3801, 0, 26); - add(1620, 3801, 0, 27); - add(1620, 3814, 0, 28); - add(1618, 3814, 0, 29); - add(1617, 3814, 0, 30); - add(1615, 3816, 0, 31); - add(1615, 3817, 0, 32); - add(1615, 3820, 0, 33); - add(1614, 3820, 0, 34); - add(1614, 3817, 0, 35); - add(1614, 3816, 0, 36); - add(1612, 3814, 0, 37); - add(1610, 3814, 0, 38); - add(1607, 3816, 0, 39); - add(1607, 3817, 0, 40); - add(1607, 3820, 0, 41); - add(1607, 3826, 0, 42); - add(1607, 3828, 0, 43); - add(1609, 3831, 0, 44); - add(1612, 3831, 0, 45); - add(1614, 3831, 0, 46); - add(1619, 3831, 0, 47); - add(1621, 3831, 0, 48); - add(1624, 3831, 0, 49); - add(1626, 3829, 0, 50); - add(1626, 3827, 0, 51); - add(1624, 3823, 0, 52); - add(1622, 3823, 0, 53); - add(1620, 3823, 0, 54); - add(1621, 3822, 0, 55); - add(1624, 3822, 0, 56); - add(1626, 3820, 0, 57); - add(1639, 3821, 0, 58); - add(1639, 3822, 0, 59); - add(1639, 3827, 0, 60); - add(1639, 3829, 0, 61); - add(1642, 3831, 0, 62); - add(1645, 3831, 0, 63); - add(1646, 3829, 0, 64); - add(1646, 3827, 0, 65); - add(1646, 3826, 0, 66); - add(1647, 3827, 0, 67); - add(1647, 3829, 0, 68); - add(1647, 3830, 0, 69); - add(1652, 3831, 0, 70); - add(1653, 3831, 0, 71); - add(1656, 3831, 0, 72); - add(1658, 3829, 0, 73); - add(1658, 3826, 0, 74); - add(1658, 3825, 0, 75); - add(1658, 3820, 0, 76); - add(1658, 3819, 0, 77); - add(1658, 3816, 0, 78); - add(1655, 3814, 0, 79); - add(1654, 3814, 0, 80); - add(1651, 3817, 0, 81); - add(1651, 3819, 0, 82); - add(1651, 3820, 0, 83); - add(1650, 3821, 0, 84); - add(1650, 3819, 0, 85); - add(1650, 3816, 0, 86); - add(1648, 3814, 0, 87); - add(1646, 3814, 0, 88); - add(1645, 3814, 0, 89); - add(1607, 3820, 1, 90); - add(1607, 3821, 1, 91); - add(1609, 3822, 1, 92); - add(1612, 3823, 1, 93); - add(1611, 3823, 1, 94); - add(1607, 3824, 1, 95); - add(1607, 3825, 1, 96); - add(1607, 3827, 1, 97); - add(1611, 3831, 1, 98); - add(1612, 3831, 1, 99); - add(1613, 3831, 1, 100); - add(1617, 3831, 1, 101); - add(1618, 3831, 1, 102); - add(1620, 3831, 1, 103); - add(1624, 3831, 1, 104); - add(1624, 3829, 1, 105); - add(1624, 3825, 1, 106); - add(1624, 3824, 1, 107); - add(1624, 3819, 1, 108); - add(1624, 3817, 1, 109); - add(1623, 3816, 1, 110); - add(1621, 3816, 1, 111); - add(1617, 3816, 1, 112); - add(1616, 3816, 1, 113); - add(1611, 3816, 1, 114); - add(1609, 3816, 1, 115); - add(1620, 3820, 1, 116); - add(1620, 3822, 1, 117); - add(1620, 3824, 1, 118); - add(1620, 3825, 1, 119); - add(1620, 3827, 1, 120); - add(1621, 3826, 1, 121); - add(1621, 3822, 1, 122); - add(1621, 3820, 1, 123); - add(1607, 3788, 1, 124); - add(1607, 3789, 1, 125); - add(1609, 3790, 1, 126); - add(1611, 3790, 1, 127); - add(1613, 3790, 1, 128); - add(1614, 3789, 1, 129); - add(1615, 3788, 1, 130); - add(1615, 3790, 1, 131); - add(1614, 3791, 1, 132); - add(1613, 3791, 1, 133); - add(1610, 3791, 1, 134); - add(1609, 3791, 1, 135); - add(1608, 3791, 1, 136); - add(1607, 3793, 1, 137); - add(1607, 3794, 1, 138); - add(1608, 3799, 1, 139); - add(1610, 3799, 1, 140); - add(1615, 3799, 1, 141); - add(1616, 3799, 1, 142); - add(1621, 3799, 1, 143); - add(1623, 3799, 1, 144); - add(1624, 3798, 1, 145); - add(1624, 3796, 1, 146); - add(1624, 3792, 1, 147); - add(1624, 3791, 1, 148); - add(1623, 3789, 1, 149); - add(1621, 3789, 1, 150); - add(1620, 3788, 1, 151); - add(1621, 3788, 1, 152); - add(1624, 3787, 1, 153); - add(1624, 3786, 1, 154); - add(1619, 3784, 1, 155); - add(1618, 3784, 1, 156); - add(1616, 3784, 1, 157); - add(1612, 3784, 1, 158); - add(1611, 3784, 1, 159); - add(1625, 3801, 1, 160); - add(1625, 3802, 1, 161); - add(1625, 3803, 1, 162); - add(1625, 3804, 1, 163); - add(1625, 3806, 1, 164); - add(1625, 3807, 1, 165); - add(1625, 3808, 1, 166); - add(1625, 3809, 1, 167); - add(1625, 3811, 1, 168); - add(1625, 3812, 1, 169); - add(1625, 3813, 1, 170); - add(1625, 3814, 1, 171); - add(1626, 3815, 1, 172); - add(1627, 3815, 1, 173); - add(1631, 3815, 1, 174); - add(1632, 3815, 1, 175); - add(1633, 3815, 1, 176); - add(1634, 3815, 1, 177); - add(1638, 3815, 1, 178); - add(1639, 3815, 1, 179); - add(1640, 3814, 1, 180); - add(1640, 3813, 1, 181); - add(1640, 3803, 1, 182); - add(1640, 3802, 1, 183); - add(1640, 3801, 1, 184); - add(1639, 3800, 1, 185); - add(1638, 3800, 1, 186); - add(1634, 3800, 1, 187); - add(1633, 3800, 1, 188); - add(1632, 3800, 1, 189); - add(1631, 3800, 1, 190); - add(1627, 3800, 1, 191); - add(1626, 3800, 1, 192); - add(1641, 3817, 1, 193); - add(1641, 3818, 1, 194); - add(1641, 3819, 1, 195); - add(1641, 3824, 1, 196); - add(1641, 3825, 1, 197); - add(1641, 3829, 1, 198); - add(1645, 3831, 1, 199); - add(1646, 3831, 1, 200); - add(1647, 3831, 1, 201); - add(1648, 3831, 1, 202); - add(1649, 3830, 1, 203); - add(1649, 3828, 1, 204); - add(1650, 3829, 1, 205); - add(1652, 3831, 1, 206); - add(1653, 3831, 1, 207); - add(1658, 3827, 1, 208); - add(1658, 3826, 1, 209); - add(1658, 3823, 1, 210); - add(1658, 3822, 1, 211); - add(1658, 3821, 1, 212); - add(1658, 3820, 1, 213); - add(1656, 3816, 1, 214); - add(1655, 3816, 1, 215); - add(1651, 3816, 1, 216); - add(1649, 3816, 1, 217); - add(1648, 3816, 1, 218); - add(1644, 3816, 1, 219); - add(1643, 3816, 1, 220); - add(1607, 3785, 2, 221); - add(1607, 3786, 2, 222); - add(1607, 3796, 2, 223); - add(1607, 3797, 2, 224); - add(1608, 3799, 2, 225); - add(1610, 3799, 2, 226); - add(1611, 3799, 2, 227); - add(1618, 3799, 2, 228); - add(1621, 3799, 2, 229); - add(1624, 3797, 2, 230); - add(1624, 3795, 2, 231); - add(1624, 3794, 2, 232); - add(1624, 3792, 2, 233); - add(1623, 3791, 2, 234); - add(1622, 3791, 2, 235); - add(1618, 3792, 2, 236); - add(1618, 3793, 2, 237); - add(1618, 3794, 2, 238); - add(1617, 3793, 2, 239); - add(1617, 3792, 2, 240); - add(1618, 3790, 2, 241); - add(1620, 3790, 2, 242); - add(1622, 3790, 2, 243); - add(1624, 3789, 2, 244); - add(1624, 3788, 2, 245); - add(1624, 3786, 2, 246); - add(1624, 3785, 2, 247); - add(1623, 3784, 2, 248); - add(1621, 3784, 2, 249); - add(1611, 3784, 2, 250); - add(1609, 3784, 2, 251); - add(1612, 3789, 2, 252); - add(1612, 3791, 2, 253); - add(1612, 3794, 2, 254); - add(1613, 3793, 2, 255); - add(1613, 3792, 2, 256); - add(1613, 3791, 2, 257); - add(1617, 3791, 2, 258); - add(1617, 3793, 2, 259); - add(1618, 3794, 2, 260); - add(1618, 3792, 2, 261); - add(1619, 3791, 2, 262); - add(1623, 3791, 2, 263); - add(1623, 3790, 2, 264); - add(1622, 3790, 2, 265); - add(1619, 3790, 2, 266); - add(1611, 3816, 2, 267); - add(1610, 3816, 2, 268); - add(1609, 3816, 2, 269); - add(1607, 3817, 2, 270); - add(1607, 3819, 2, 271); - add(1607, 3829, 2, 272); - add(1608, 3831, 2, 273); - add(1610, 3831, 2, 274); - add(1611, 3831, 2, 275); - add(1622, 3831, 2, 276); - add(1623, 3831, 2, 277); - add(1624, 3829, 2, 278); - add(1624, 3828, 2, 279); - add(1624, 3821, 2, 280); - add(1624, 3819, 2, 281); - add(1622, 3816, 2, 282); - add(1620, 3816, 2, 283); - add(1618, 3816, 2, 284); - add(1615, 3821, 2, 285); - add(1617, 3821, 2, 286); - add(1619, 3822, 2, 287); - add(1619, 3824, 2, 288); - add(1618, 3826, 2, 289); - add(1617, 3826, 2, 290); - add(1615, 3827, 2, 291); - add(1616, 3827, 2, 292); - add(1618, 3827, 2, 293); - add(1620, 3826, 2, 294); - add(1620, 3824, 2, 295); - add(1620, 3822, 2, 296); - add(1620, 3821, 2, 297); - add(1619, 3820, 2, 298); - add(1617, 3820, 2, 299); - add(1615, 3820, 2, 300); - add(1641, 3818, 2, 301); - add(1641, 3820, 2, 302); - add(1641, 3821, 2, 303); - add(1641, 3829, 2, 304); - add(1643, 3831, 2, 305); - add(1644, 3831, 2, 306); - add(1654, 3831, 2, 307); - add(1656, 3831, 2, 308); - add(1658, 3830, 2, 309); - add(1658, 3828, 2, 310); - add(1658, 3818, 2, 311); - add(1658, 3817, 2, 312); - add(1656, 3816, 2, 313); - add(1655, 3816, 2, 314); - add(1652, 3816, 2, 315); - add(1648, 3817, 2, 316); - add(1648, 3819, 2, 317); - add(1648, 3821, 2, 318); - add(1649, 3823, 2, 319); - add(1650, 3823, 2, 320); - add(1652, 3823, 2, 321); - add(1654, 3822, 2, 322); - add(1654, 3820, 2, 323); - add(1655, 3820, 2, 324); - add(1655, 3821, 2, 325); - add(1655, 3823, 2, 326); - add(1653, 3824, 2, 327); - add(1652, 3824, 2, 328); - add(1649, 3824, 2, 329); - add(1648, 3824, 2, 330); - add(1647, 3822, 2, 331); - add(1647, 3820, 2, 332); - add(1647, 3818, 2, 333); - add(1645, 3816, 2, 334); - add(1644, 3816, 2, 335); - add(1625, 3802, 2, 336); - add(1625, 3804, 2, 337); - add(1625, 3811, 2, 338); - add(1625, 3812, 2, 339); - add(1627, 3815, 2, 340); - add(1628, 3815, 2, 341); - add(1635, 3815, 2, 342); - add(1637, 3815, 2, 343); - add(1638, 3815, 2, 344); - add(1640, 3813, 2, 345); - add(1640, 3811, 2, 346); - add(1640, 3810, 2, 347); - add(1638, 3800, 2, 348); - add(1632, 3800, 2, 349); - add(1630, 3800, 2, 350); - add(1629, 3800, 2, 351); - add(1627, 3800, 2, 352); - } +/* + * Copyright (c) 2018 Abex + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package net.runelite.client.plugins.kourendlibrary; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.stream.IntStream; +import javax.inject.Singleton; +import lombok.Getter; +import lombok.extern.slf4j.Slf4j; +import net.runelite.api.coords.WorldPoint; +import static net.runelite.client.plugins.kourendlibrary.Book.BYRNES_CORONATION_SPEECH; +import static net.runelite.client.plugins.kourendlibrary.Book.DARK_MANUSCRIPT_13514; +import static net.runelite.client.plugins.kourendlibrary.Book.DARK_MANUSCRIPT_13515; +import static net.runelite.client.plugins.kourendlibrary.Book.DARK_MANUSCRIPT_13516; +import static net.runelite.client.plugins.kourendlibrary.Book.DARK_MANUSCRIPT_13517; +import static net.runelite.client.plugins.kourendlibrary.Book.DARK_MANUSCRIPT_13518; +import static net.runelite.client.plugins.kourendlibrary.Book.DARK_MANUSCRIPT_13519; +import static net.runelite.client.plugins.kourendlibrary.Book.DARK_MANUSCRIPT_13520; +import static net.runelite.client.plugins.kourendlibrary.Book.DARK_MANUSCRIPT_13521; +import static net.runelite.client.plugins.kourendlibrary.Book.DARK_MANUSCRIPT_13522; +import static net.runelite.client.plugins.kourendlibrary.Book.DARK_MANUSCRIPT_13523; +import static net.runelite.client.plugins.kourendlibrary.Book.EATHRAM_RADA_EXTRACT; +import static net.runelite.client.plugins.kourendlibrary.Book.HOSIDIUS_LETTER; +import static net.runelite.client.plugins.kourendlibrary.Book.IDEOLOGY_OF_DARKNESS; +import static net.runelite.client.plugins.kourendlibrary.Book.KILLING_OF_A_KING; +import static net.runelite.client.plugins.kourendlibrary.Book.RADAS_CENSUS; +import static net.runelite.client.plugins.kourendlibrary.Book.RADAS_JOURNEY; +import static net.runelite.client.plugins.kourendlibrary.Book.RICKTORS_DIARY_7; +import static net.runelite.client.plugins.kourendlibrary.Book.SOUL_JOURNEY; +import static net.runelite.client.plugins.kourendlibrary.Book.TRANSPORTATION_INCANTATIONS; +import static net.runelite.client.plugins.kourendlibrary.Book.TRANSVERGENCE_THEORY; +import static net.runelite.client.plugins.kourendlibrary.Book.TREACHERY_OF_ROYALTY; +import static net.runelite.client.plugins.kourendlibrary.Book.TRISTESSAS_TRAGEDY; +import static net.runelite.client.plugins.kourendlibrary.Book.TWILL_ACCORD; +import static net.runelite.client.plugins.kourendlibrary.Book.VARLAMORE_ENVOY; +import static net.runelite.client.plugins.kourendlibrary.Book.WINTERTODT_PARABLE; + +/** + * Library represents a instance of the Kourend/Arceuus House library. + *

+ * The library changes the locations of it's books every 60-90 minutes. + * Of the 554 bookcases in the library, only 346 of them can ever have books. + * 6 of the bookcases in the south-west corner of the top floor are duplicated. + * These 6 bookcases are not handled 100% correctly due to their low chance + * of being used to train the predictor. + *

+ * Each of the 352 bookcase slots "Bookcase"s has an index which is used to + * place the book inside of them. The game chooses one of the 5 sequences and a + * bookcase starting index, then places a book from the sequence into every 13th + * bookcase, by index. Each sequence contains 26 Books, consisting of 16 books + * and 10 dark manuscripts. You can only get one dark manuscript at a time, though + * they are all placed into shelves. + */ +@Singleton +@Slf4j +class Library +{ + private final Map byPoint = new HashMap<>(); + private final Map> byLevel = new HashMap<>(); + private final List byIndex = new ArrayList<>(); + + private final List> sequences = populateSequences(); + + private final int step; + + @Getter + private SolvedState state; + + @Getter + private Book customerBook; + + @Getter + private LibraryCustomer customer; + + Library() + { + populateBooks(); + step = byIndex.size() / Book.values().length; + reset(); + } + + synchronized List getBookcasesOnLevel(int z) + { + return Collections.unmodifiableList(byLevel.get(z)); + } + + synchronized List getBookcases() + { + return Collections.unmodifiableList(byIndex); + } + + void setCustomer(LibraryCustomer customer, Book book) + { + this.customer = customer; + this.customerBook = book; + } + + synchronized void reset() + { + state = SolvedState.NO_DATA; + for (Bookcase b : byIndex) + { + b.clearBook(); + b.getPossibleBooks().clear(); + } + log.info("Library is now reset"); + } + + synchronized void mark(WorldPoint loc, Book book) + { + Bookcase bookcase = byPoint.get(loc); + if (bookcase == null) + { + log.debug("Requested non-existent bookcase at {}", loc); + return; + } + + if (bookcase.isBookSet()) + { + // Bookcase is set from a previous mark + // Check for a mismatch, unless it is now null and had a dark manuscript + if (book != bookcase.getBook() && !(book == null && bookcase.getBook().isDarkManuscript())) + { + reset(); + } + } + else if (state != SolvedState.NO_DATA) + { + // We know all of the possible things in this shelf. + if (book != null) + { + // Check to see if our guess is wrong + if (!bookcase.getPossibleBooks().contains(book)) + { + reset(); + } + } + } + + // Everything is known, nothing to do + if (state == SolvedState.COMPLETE) + { + return; + } + + log.info("Setting bookcase {} to {}", bookcase.getIndex(), book); + for (; ; ) + { + bookcase.setBook(book); + + // Basing the sequences on null is not supported, though possible + if (book == null) + { + return; + } + + // This is one of the 6 bookcases with 2 ids. Not fully supported. + if (bookcase.getIndex().size() != 1) + { + return; + } + + int bookcaseIndex = bookcase.getIndex().get(0); + + state = SolvedState.INCOMPLETE; + + // Map each sequence to the number of bookcases that match the sequence + // return 0 if it is a mismatch. + // Keep in mind that Bookcases with dark manuscripts may be set to null. + int[] certainty = sequences.stream().mapToInt(sequence -> + { + int zero = getBookcaseZeroIndexForSequenceWithBook(sequence, bookcaseIndex, book); + + int found = 0; + for (int i = 0; i < byIndex.size(); i++) + { + int ai = (i + zero) % byIndex.size(); + Bookcase iBookcase = byIndex.get(ai); + if (i % step == 0) + { + int seqI = i / step; + if (iBookcase.isBookSet() && seqI < sequence.size()) + { + Book seqBook = sequence.get(seqI); + boolean isSeqManuscript = seqBook == null || seqBook.isDarkManuscript(); + if (!((isSeqManuscript && iBookcase.getBook() == null) || (iBookcase.getBook() == seqBook))) + { + log.debug("Bailing @ i={} ai={} {}; {} != {}", i, ai, iBookcase.getIndex(), iBookcase.getBook(), seqBook); + found = 0; + break; + } + found++; + } + } + else + { + // Only bail if this isn't a double bookcase + if (iBookcase.isBookSet() && iBookcase.getBook() != null && iBookcase.getIndex().size() == 1) + { + log.debug("Bailing @ i={} ai={} {}; {} is set", i, ai, iBookcase.getIndex(), iBookcase.getBook()); + found = 0; + break; + } + } + } + return found; + }).toArray(); + log.info("Certainty is now {}", certainty); + + for (Bookcase b : byIndex) + { + b.getPossibleBooks().clear(); + } + + // Write the most likely sequences onto the bookcases + int max = IntStream.of(certainty).max().getAsInt(); + + // We have books set, but 0 sequences match, Something is wrong, reset. + if (max == 0) + { + reset(); + continue; + } + + IntStream.range(0, sequences.size()) + .filter(i -> certainty[i] == max) + .forEach(isequence -> + { + List sequence = sequences.get(isequence); + int zero = getBookcaseZeroIndexForSequenceWithBook(sequence, bookcaseIndex, book); + + for (int i = 0; i < byIndex.size(); i++) + { + int ai = (i + zero) % byIndex.size(); + Bookcase iBookcase = byIndex.get(ai); + if (iBookcase.getBook() == null) + { + int iseq = i / step; + if (i % step == 0 && iseq < sequence.size()) + { + Book seqBook = sequence.get(iseq); + iBookcase.getPossibleBooks().add(seqBook); + } + } + } + }); + if (IntStream.range(0, certainty.length).filter(i -> certainty[i] == max).count() == 1) + { + state = SolvedState.COMPLETE; + } + return; + } + } + + /** + * Find the bookcase index that is index zero in the sequence, identifying by the book in bookcase + */ + private int getBookcaseZeroIndexForSequenceWithBook(List sequences, int bookcaseIndex, Book book) + { + int bookSequence = sequences.indexOf(book); + assert bookSequence >= 0; + + bookcaseIndex -= step * bookSequence; + for (; bookcaseIndex < 0; ) + { + bookcaseIndex += byIndex.size(); + } + return bookcaseIndex; + } + + private List> populateSequences() + { + List> books = Arrays.asList( + Arrays.asList( + DARK_MANUSCRIPT_13516, + KILLING_OF_A_KING, + DARK_MANUSCRIPT_13520, + IDEOLOGY_OF_DARKNESS, + RADAS_JOURNEY, + TRANSVERGENCE_THEORY, + TRISTESSAS_TRAGEDY, + DARK_MANUSCRIPT_13523, + DARK_MANUSCRIPT_13521, + RADAS_CENSUS, + TREACHERY_OF_ROYALTY, + HOSIDIUS_LETTER, + DARK_MANUSCRIPT_13519, + RICKTORS_DIARY_7, + DARK_MANUSCRIPT_13514, + EATHRAM_RADA_EXTRACT, + DARK_MANUSCRIPT_13522, + VARLAMORE_ENVOY, + WINTERTODT_PARABLE, + TWILL_ACCORD, + DARK_MANUSCRIPT_13515, + BYRNES_CORONATION_SPEECH, + DARK_MANUSCRIPT_13517, + SOUL_JOURNEY, + DARK_MANUSCRIPT_13518, + TRANSPORTATION_INCANTATIONS + ), + Arrays.asList( + DARK_MANUSCRIPT_13516, + KILLING_OF_A_KING, + DARK_MANUSCRIPT_13520, + IDEOLOGY_OF_DARKNESS, + RADAS_JOURNEY, + TRANSVERGENCE_THEORY, + TRISTESSAS_TRAGEDY, + DARK_MANUSCRIPT_13523, + DARK_MANUSCRIPT_13521, + RADAS_CENSUS, + TREACHERY_OF_ROYALTY, + HOSIDIUS_LETTER, + VARLAMORE_ENVOY, + DARK_MANUSCRIPT_13519, + RICKTORS_DIARY_7, + DARK_MANUSCRIPT_13514, + EATHRAM_RADA_EXTRACT, + DARK_MANUSCRIPT_13522, + SOUL_JOURNEY, + WINTERTODT_PARABLE, + TWILL_ACCORD, + DARK_MANUSCRIPT_13515, + BYRNES_CORONATION_SPEECH, + DARK_MANUSCRIPT_13517, + DARK_MANUSCRIPT_13518, + TRANSPORTATION_INCANTATIONS + ), + Arrays.asList( + RICKTORS_DIARY_7, + VARLAMORE_ENVOY, + DARK_MANUSCRIPT_13514, + EATHRAM_RADA_EXTRACT, + IDEOLOGY_OF_DARKNESS, + DARK_MANUSCRIPT_13516, + DARK_MANUSCRIPT_13521, + RADAS_CENSUS, + DARK_MANUSCRIPT_13515, + KILLING_OF_A_KING, + DARK_MANUSCRIPT_13520, + TREACHERY_OF_ROYALTY, + HOSIDIUS_LETTER, + DARK_MANUSCRIPT_13519, + BYRNES_CORONATION_SPEECH, + DARK_MANUSCRIPT_13517, + SOUL_JOURNEY, + DARK_MANUSCRIPT_13522, + WINTERTODT_PARABLE, + TWILL_ACCORD, + RADAS_JOURNEY, + TRANSVERGENCE_THEORY, + TRISTESSAS_TRAGEDY, + DARK_MANUSCRIPT_13523, + DARK_MANUSCRIPT_13518, + TRANSPORTATION_INCANTATIONS + ), + Arrays.asList( + RADAS_CENSUS, + DARK_MANUSCRIPT_13522, + RICKTORS_DIARY_7, + DARK_MANUSCRIPT_13514, + EATHRAM_RADA_EXTRACT, + DARK_MANUSCRIPT_13516, + KILLING_OF_A_KING, + DARK_MANUSCRIPT_13520, + HOSIDIUS_LETTER, + DARK_MANUSCRIPT_13519, + DARK_MANUSCRIPT_13521, + WINTERTODT_PARABLE, + TWILL_ACCORD, + DARK_MANUSCRIPT_13515, + BYRNES_CORONATION_SPEECH, + DARK_MANUSCRIPT_13517, + IDEOLOGY_OF_DARKNESS, + RADAS_JOURNEY, + TRANSVERGENCE_THEORY, + TRISTESSAS_TRAGEDY, + DARK_MANUSCRIPT_13523, + TREACHERY_OF_ROYALTY, + DARK_MANUSCRIPT_13518, + TRANSPORTATION_INCANTATIONS, + SOUL_JOURNEY, + VARLAMORE_ENVOY + ), + Arrays.asList( + RADAS_CENSUS, + TRANSVERGENCE_THEORY, + TREACHERY_OF_ROYALTY, + RADAS_JOURNEY, + KILLING_OF_A_KING, + DARK_MANUSCRIPT_13520, + VARLAMORE_ENVOY, + DARK_MANUSCRIPT_13522, + BYRNES_CORONATION_SPEECH, + DARK_MANUSCRIPT_13517, + HOSIDIUS_LETTER, + DARK_MANUSCRIPT_13516, + DARK_MANUSCRIPT_13519, + TRISTESSAS_TRAGEDY, + DARK_MANUSCRIPT_13523, + DARK_MANUSCRIPT_13521, + RICKTORS_DIARY_7, + DARK_MANUSCRIPT_13514, + IDEOLOGY_OF_DARKNESS, + WINTERTODT_PARABLE, + TWILL_ACCORD, + SOUL_JOURNEY, + DARK_MANUSCRIPT_13515, + EATHRAM_RADA_EXTRACT, + DARK_MANUSCRIPT_13518, + TRANSPORTATION_INCANTATIONS + ) + ); + + for (int i = 0; i < books.size(); i++) + { + assert new HashSet<>(books.get(i)).size() == books.get(i).size(); + books.set(i, Collections.unmodifiableList(books.get(i))); + } + return Collections.unmodifiableList(books); + } + + private void add(int x, int y, int z, int i) + { + // 'i' is added as a parameter for readability + WorldPoint p = new WorldPoint(x, y, z); + Bookcase b = byPoint.get(p); + if (b == null) + { + b = new Bookcase(p); + byPoint.put(p, b); + byLevel.computeIfAbsent(z, a -> new ArrayList<>()).add(b); + } + b.getIndex().add(i); + assert i == byIndex.size(); + byIndex.add(b); + } + + private void populateBooks() + { + add(1626, 3795, 0, 0); + add(1625, 3793, 0, 1); + add(1623, 3793, 0, 2); + add(1620, 3792, 0, 3); + add(1624, 3792, 0, 4); + add(1626, 3788, 0, 5); + add(1626, 3787, 0, 6); + add(1624, 3784, 0, 7); + add(1623, 3784, 0, 8); + add(1621, 3784, 0, 9); + add(1615, 3785, 0, 10); + add(1615, 3788, 0, 11); + add(1615, 3790, 0, 12); + add(1614, 3790, 0, 13); + add(1614, 3788, 0, 14); + add(1614, 3786, 0, 15); + add(1612, 3784, 0, 16); + add(1610, 3784, 0, 17); + add(1609, 3784, 0, 18); + add(1607, 3786, 0, 19); + add(1607, 3789, 0, 20); + add(1607, 3795, 0, 21); + add(1607, 3796, 0, 22); + add(1607, 3799, 0, 23); + add(1610, 3801, 0, 24); + add(1612, 3801, 0, 25); + add(1618, 3801, 0, 26); + add(1620, 3801, 0, 27); + add(1620, 3814, 0, 28); + add(1618, 3814, 0, 29); + add(1617, 3814, 0, 30); + add(1615, 3816, 0, 31); + add(1615, 3817, 0, 32); + add(1615, 3820, 0, 33); + add(1614, 3820, 0, 34); + add(1614, 3817, 0, 35); + add(1614, 3816, 0, 36); + add(1612, 3814, 0, 37); + add(1610, 3814, 0, 38); + add(1607, 3816, 0, 39); + add(1607, 3817, 0, 40); + add(1607, 3820, 0, 41); + add(1607, 3826, 0, 42); + add(1607, 3828, 0, 43); + add(1609, 3831, 0, 44); + add(1612, 3831, 0, 45); + add(1614, 3831, 0, 46); + add(1619, 3831, 0, 47); + add(1621, 3831, 0, 48); + add(1624, 3831, 0, 49); + add(1626, 3829, 0, 50); + add(1626, 3827, 0, 51); + add(1624, 3823, 0, 52); + add(1622, 3823, 0, 53); + add(1620, 3823, 0, 54); + add(1621, 3822, 0, 55); + add(1624, 3822, 0, 56); + add(1626, 3820, 0, 57); + add(1639, 3821, 0, 58); + add(1639, 3822, 0, 59); + add(1639, 3827, 0, 60); + add(1639, 3829, 0, 61); + add(1642, 3831, 0, 62); + add(1645, 3831, 0, 63); + add(1646, 3829, 0, 64); + add(1646, 3827, 0, 65); + add(1646, 3826, 0, 66); + add(1647, 3827, 0, 67); + add(1647, 3829, 0, 68); + add(1647, 3830, 0, 69); + add(1652, 3831, 0, 70); + add(1653, 3831, 0, 71); + add(1656, 3831, 0, 72); + add(1658, 3829, 0, 73); + add(1658, 3826, 0, 74); + add(1658, 3825, 0, 75); + add(1658, 3820, 0, 76); + add(1658, 3819, 0, 77); + add(1658, 3816, 0, 78); + add(1655, 3814, 0, 79); + add(1654, 3814, 0, 80); + add(1651, 3817, 0, 81); + add(1651, 3819, 0, 82); + add(1651, 3820, 0, 83); + add(1650, 3821, 0, 84); + add(1650, 3819, 0, 85); + add(1650, 3816, 0, 86); + add(1648, 3814, 0, 87); + add(1646, 3814, 0, 88); + add(1645, 3814, 0, 89); + add(1607, 3820, 1, 90); + add(1607, 3821, 1, 91); + add(1609, 3822, 1, 92); + add(1612, 3823, 1, 93); + add(1611, 3823, 1, 94); + add(1607, 3824, 1, 95); + add(1607, 3825, 1, 96); + add(1607, 3827, 1, 97); + add(1611, 3831, 1, 98); + add(1612, 3831, 1, 99); + add(1613, 3831, 1, 100); + add(1617, 3831, 1, 101); + add(1618, 3831, 1, 102); + add(1620, 3831, 1, 103); + add(1624, 3831, 1, 104); + add(1624, 3829, 1, 105); + add(1624, 3825, 1, 106); + add(1624, 3824, 1, 107); + add(1624, 3819, 1, 108); + add(1624, 3817, 1, 109); + add(1623, 3816, 1, 110); + add(1621, 3816, 1, 111); + add(1617, 3816, 1, 112); + add(1616, 3816, 1, 113); + add(1611, 3816, 1, 114); + add(1609, 3816, 1, 115); + add(1620, 3820, 1, 116); + add(1620, 3822, 1, 117); + add(1620, 3824, 1, 118); + add(1620, 3825, 1, 119); + add(1620, 3827, 1, 120); + add(1621, 3826, 1, 121); + add(1621, 3822, 1, 122); + add(1621, 3820, 1, 123); + add(1607, 3788, 1, 124); + add(1607, 3789, 1, 125); + add(1609, 3790, 1, 126); + add(1611, 3790, 1, 127); + add(1613, 3790, 1, 128); + add(1614, 3789, 1, 129); + add(1615, 3788, 1, 130); + add(1615, 3790, 1, 131); + add(1614, 3791, 1, 132); + add(1613, 3791, 1, 133); + add(1610, 3791, 1, 134); + add(1609, 3791, 1, 135); + add(1608, 3791, 1, 136); + add(1607, 3793, 1, 137); + add(1607, 3794, 1, 138); + add(1608, 3799, 1, 139); + add(1610, 3799, 1, 140); + add(1615, 3799, 1, 141); + add(1616, 3799, 1, 142); + add(1621, 3799, 1, 143); + add(1623, 3799, 1, 144); + add(1624, 3798, 1, 145); + add(1624, 3796, 1, 146); + add(1624, 3792, 1, 147); + add(1624, 3791, 1, 148); + add(1623, 3789, 1, 149); + add(1621, 3789, 1, 150); + add(1620, 3788, 1, 151); + add(1621, 3788, 1, 152); + add(1624, 3787, 1, 153); + add(1624, 3786, 1, 154); + add(1619, 3784, 1, 155); + add(1618, 3784, 1, 156); + add(1616, 3784, 1, 157); + add(1612, 3784, 1, 158); + add(1611, 3784, 1, 159); + add(1625, 3801, 1, 160); + add(1625, 3802, 1, 161); + add(1625, 3803, 1, 162); + add(1625, 3804, 1, 163); + add(1625, 3806, 1, 164); + add(1625, 3807, 1, 165); + add(1625, 3808, 1, 166); + add(1625, 3809, 1, 167); + add(1625, 3811, 1, 168); + add(1625, 3812, 1, 169); + add(1625, 3813, 1, 170); + add(1625, 3814, 1, 171); + add(1626, 3815, 1, 172); + add(1627, 3815, 1, 173); + add(1631, 3815, 1, 174); + add(1632, 3815, 1, 175); + add(1633, 3815, 1, 176); + add(1634, 3815, 1, 177); + add(1638, 3815, 1, 178); + add(1639, 3815, 1, 179); + add(1640, 3814, 1, 180); + add(1640, 3813, 1, 181); + add(1640, 3803, 1, 182); + add(1640, 3802, 1, 183); + add(1640, 3801, 1, 184); + add(1639, 3800, 1, 185); + add(1638, 3800, 1, 186); + add(1634, 3800, 1, 187); + add(1633, 3800, 1, 188); + add(1632, 3800, 1, 189); + add(1631, 3800, 1, 190); + add(1627, 3800, 1, 191); + add(1626, 3800, 1, 192); + add(1641, 3817, 1, 193); + add(1641, 3818, 1, 194); + add(1641, 3819, 1, 195); + add(1641, 3824, 1, 196); + add(1641, 3825, 1, 197); + add(1641, 3829, 1, 198); + add(1645, 3831, 1, 199); + add(1646, 3831, 1, 200); + add(1647, 3831, 1, 201); + add(1648, 3831, 1, 202); + add(1649, 3830, 1, 203); + add(1649, 3828, 1, 204); + add(1650, 3829, 1, 205); + add(1652, 3831, 1, 206); + add(1653, 3831, 1, 207); + add(1658, 3827, 1, 208); + add(1658, 3826, 1, 209); + add(1658, 3823, 1, 210); + add(1658, 3822, 1, 211); + add(1658, 3821, 1, 212); + add(1658, 3820, 1, 213); + add(1656, 3816, 1, 214); + add(1655, 3816, 1, 215); + add(1651, 3816, 1, 216); + add(1649, 3816, 1, 217); + add(1648, 3816, 1, 218); + add(1644, 3816, 1, 219); + add(1643, 3816, 1, 220); + add(1607, 3785, 2, 221); + add(1607, 3786, 2, 222); + add(1607, 3796, 2, 223); + add(1607, 3797, 2, 224); + add(1608, 3799, 2, 225); + add(1610, 3799, 2, 226); + add(1611, 3799, 2, 227); + add(1618, 3799, 2, 228); + add(1621, 3799, 2, 229); + add(1624, 3797, 2, 230); + add(1624, 3795, 2, 231); + add(1624, 3794, 2, 232); + add(1624, 3792, 2, 233); + add(1623, 3791, 2, 234); + add(1622, 3791, 2, 235); + add(1618, 3792, 2, 236); + add(1618, 3793, 2, 237); + add(1618, 3794, 2, 238); + add(1617, 3793, 2, 239); + add(1617, 3792, 2, 240); + add(1618, 3790, 2, 241); + add(1620, 3790, 2, 242); + add(1622, 3790, 2, 243); + add(1624, 3789, 2, 244); + add(1624, 3788, 2, 245); + add(1624, 3786, 2, 246); + add(1624, 3785, 2, 247); + add(1623, 3784, 2, 248); + add(1621, 3784, 2, 249); + add(1611, 3784, 2, 250); + add(1609, 3784, 2, 251); + add(1612, 3789, 2, 252); + add(1612, 3791, 2, 253); + add(1612, 3794, 2, 254); + add(1613, 3793, 2, 255); + add(1613, 3792, 2, 256); + add(1613, 3791, 2, 257); + add(1617, 3791, 2, 258); + add(1617, 3793, 2, 259); + add(1618, 3794, 2, 260); + add(1618, 3792, 2, 261); + add(1619, 3791, 2, 262); + add(1623, 3791, 2, 263); + add(1623, 3790, 2, 264); + add(1622, 3790, 2, 265); + add(1619, 3790, 2, 266); + add(1611, 3816, 2, 267); + add(1610, 3816, 2, 268); + add(1609, 3816, 2, 269); + add(1607, 3817, 2, 270); + add(1607, 3819, 2, 271); + add(1607, 3829, 2, 272); + add(1608, 3831, 2, 273); + add(1610, 3831, 2, 274); + add(1611, 3831, 2, 275); + add(1622, 3831, 2, 276); + add(1623, 3831, 2, 277); + add(1624, 3829, 2, 278); + add(1624, 3828, 2, 279); + add(1624, 3821, 2, 280); + add(1624, 3819, 2, 281); + add(1622, 3816, 2, 282); + add(1620, 3816, 2, 283); + add(1618, 3816, 2, 284); + add(1615, 3821, 2, 285); + add(1617, 3821, 2, 286); + add(1619, 3822, 2, 287); + add(1619, 3824, 2, 288); + add(1618, 3826, 2, 289); + add(1617, 3826, 2, 290); + add(1615, 3827, 2, 291); + add(1616, 3827, 2, 292); + add(1618, 3827, 2, 293); + add(1620, 3826, 2, 294); + add(1620, 3824, 2, 295); + add(1620, 3822, 2, 296); + add(1620, 3821, 2, 297); + add(1619, 3820, 2, 298); + add(1617, 3820, 2, 299); + add(1615, 3820, 2, 300); + add(1641, 3818, 2, 301); + add(1641, 3820, 2, 302); + add(1641, 3821, 2, 303); + add(1641, 3829, 2, 304); + add(1643, 3831, 2, 305); + add(1644, 3831, 2, 306); + add(1654, 3831, 2, 307); + add(1656, 3831, 2, 308); + add(1658, 3830, 2, 309); + add(1658, 3828, 2, 310); + add(1658, 3818, 2, 311); + add(1658, 3817, 2, 312); + add(1656, 3816, 2, 313); + add(1655, 3816, 2, 314); + add(1652, 3816, 2, 315); + add(1648, 3817, 2, 316); + add(1648, 3819, 2, 317); + add(1648, 3821, 2, 318); + add(1649, 3823, 2, 319); + add(1650, 3823, 2, 320); + add(1652, 3823, 2, 321); + add(1654, 3822, 2, 322); + add(1654, 3820, 2, 323); + add(1655, 3820, 2, 324); + add(1655, 3821, 2, 325); + add(1655, 3823, 2, 326); + add(1653, 3824, 2, 327); + add(1652, 3824, 2, 328); + add(1649, 3824, 2, 329); + add(1648, 3824, 2, 330); + add(1647, 3822, 2, 331); + add(1647, 3820, 2, 332); + add(1647, 3818, 2, 333); + add(1645, 3816, 2, 334); + add(1644, 3816, 2, 335); + add(1625, 3802, 2, 336); + add(1625, 3804, 2, 337); + add(1625, 3811, 2, 338); + add(1625, 3812, 2, 339); + add(1627, 3815, 2, 340); + add(1628, 3815, 2, 341); + add(1635, 3815, 2, 342); + add(1637, 3815, 2, 343); + add(1638, 3815, 2, 344); + add(1640, 3813, 2, 345); + add(1640, 3811, 2, 346); + add(1640, 3810, 2, 347); + add(1638, 3800, 2, 348); + add(1632, 3800, 2, 349); + add(1630, 3800, 2, 350); + add(1629, 3800, 2, 351); + add(1627, 3800, 2, 352); + } } \ No newline at end of file diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/kourendlibrary/LibraryCustomer.java b/runelite-client/src/main/java/net/runelite/client/plugins/kourendlibrary/LibraryCustomer.java index 229ed37efe..cb3655cf34 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/kourendlibrary/LibraryCustomer.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/kourendlibrary/LibraryCustomer.java @@ -1,67 +1,66 @@ -/* - * Copyright (c) 2018 Abex - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package net.runelite.client.plugins.kourendlibrary; - -import java.util.HashMap; -import java.util.Map; -import lombok.Getter; - -import net.runelite.api.NpcID; - -enum LibraryCustomer -{ - VILLIA(NpcID.VILLIA, "Villia"), - PROFESSOR_GRACKLEBONE(NpcID.PROFESSOR_GRACKLEBONE, "Prof. Gracklebone"), - SAM(NpcID.SAM_7049, "Sam"); - - @Getter - private final int id; - - @Getter - private final String name; - - private static final Map byId = buildIdMap(); - - LibraryCustomer(int id, String name) - { - this.id = id; - this.name = name; - } - - static LibraryCustomer getById(int id) - { - return byId.get(id); - } - - private static Map buildIdMap() - { - Map byId = new HashMap<>(); - for (LibraryCustomer c : values()) - { - byId.put(c.id, c); - } - return byId; - } -} +/* + * Copyright (c) 2018 Abex + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package net.runelite.client.plugins.kourendlibrary; + +import java.util.HashMap; +import java.util.Map; +import lombok.Getter; +import net.runelite.api.NpcID; + +enum LibraryCustomer +{ + VILLIA(NpcID.VILLIA, "Villia"), + PROFESSOR_GRACKLEBONE(NpcID.PROFESSOR_GRACKLEBONE, "Prof. Gracklebone"), + SAM(NpcID.SAM_7049, "Sam"); + + @Getter + private final int id; + + @Getter + private final String name; + + private static final Map byId = buildIdMap(); + + LibraryCustomer(int id, String name) + { + this.id = id; + this.name = name; + } + + static LibraryCustomer getById(int id) + { + return byId.get(id); + } + + private static Map buildIdMap() + { + Map byId = new HashMap<>(); + for (LibraryCustomer c : values()) + { + byId.put(c.id, c); + } + return byId; + } +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/kourendlibrary/SolvedState.java b/runelite-client/src/main/java/net/runelite/client/plugins/kourendlibrary/SolvedState.java index c12f74fd25..0f05e80f4e 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/kourendlibrary/SolvedState.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/kourendlibrary/SolvedState.java @@ -1,32 +1,32 @@ -/* - * Copyright (c) 2018 Abex - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package net.runelite.client.plugins.kourendlibrary; - -enum SolvedState -{ - NO_DATA, - INCOMPLETE, - COMPLETE; -} +/* + * Copyright (c) 2018 Abex + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package net.runelite.client.plugins.kourendlibrary; + +enum SolvedState +{ + NO_DATA, + INCOMPLETE, + COMPLETE +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/lizardmenshaman/LizardmenShamanConfig.java b/runelite-client/src/main/java/net/runelite/client/plugins/lizardmenshaman/LizardmenShamanConfig.java index 96f671a295..128f179c3e 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/lizardmenshaman/LizardmenShamanConfig.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/lizardmenshaman/LizardmenShamanConfig.java @@ -1,56 +1,55 @@ -/* - * Copyright (c) 2018, https://runelitepl.us - * 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.lizardmenshaman; - -import net.runelite.client.config.Config; -import net.runelite.client.config.Config; -import net.runelite.client.config.ConfigGroup; -import net.runelite.client.config.ConfigItem; - -@ConfigGroup("shaman") -public interface LizardmenShamanConfig extends Config -{ - @ConfigItem( - position = 1, - keyName = "showTimer", - name = "Show timer", - description = "Display timer till for lizardman shaman spawns." - ) - default boolean showTimer() - { - return true; - } - - @ConfigItem( - position = 2, - keyName = "notifyOnSpawn", - name = "Notify on spawn", - description = "Notify user when lizardman summons spawns." - ) - default boolean notifyOnSpawn() - { - return true; - } -} +/* + * Copyright (c) 2018, https://runelitepl.us + * 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.lizardmenshaman; + +import net.runelite.client.config.Config; +import net.runelite.client.config.ConfigGroup; +import net.runelite.client.config.ConfigItem; + +@ConfigGroup("shaman") +public interface LizardmenShamanConfig extends Config +{ + @ConfigItem( + position = 1, + keyName = "showTimer", + name = "Show timer", + description = "Display timer till for lizardman shaman spawns." + ) + default boolean showTimer() + { + return true; + } + + @ConfigItem( + position = 2, + keyName = "notifyOnSpawn", + name = "Notify on spawn", + description = "Notify user when lizardman summons spawns." + ) + default boolean notifyOnSpawn() + { + return true; + } +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/lizardmenshaman/LizardmenShamanPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/lizardmenshaman/LizardmenShamanPlugin.java index 6813e54e92..dee9d1d5cd 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/lizardmenshaman/LizardmenShamanPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/lizardmenshaman/LizardmenShamanPlugin.java @@ -1,118 +1,117 @@ -/* - * Copyright (c) 2018, https://runelitepl.us - * 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.lizardmenshaman; - -import com.google.common.eventbus.Subscribe; -import com.google.inject.Provides; -import javax.inject.Inject; -import lombok.AccessLevel; -import lombok.Getter; -import lombok.extern.slf4j.Slf4j; -import net.runelite.api.Actor; -import net.runelite.api.Client; -import net.runelite.api.coords.LocalPoint; -import net.runelite.api.events.AnimationChanged; -import net.runelite.client.Notifier; -import net.runelite.client.config.ConfigManager; -import net.runelite.client.plugins.Plugin; -import net.runelite.client.plugins.PluginDescriptor; -import java.util.HashMap; -import java.util.Map; - -import net.runelite.client.plugins.PluginType; -import net.runelite.client.ui.overlay.OverlayManager; - -@PluginDescriptor( - name = "Lizard Shamans", - description = "Configures timer for lizardmen shaman spawns.", - enabledByDefault = false, - tags = {"shaman", "lizard", "lizardmen"}, - type = PluginType.PVM -) -@Slf4j -public class LizardmenShamanPlugin extends Plugin -{ - private static final String SHAMAN = "Lizardman shaman"; - private static final String MESSAGE = "A Lizardman shaman has summoned his spawn!"; - - @Getter(AccessLevel.PACKAGE) - private final Map spawns = new HashMap<>(); - - @Inject - private OverlayManager overlayManager; - - @Inject - private ShamanSpawnOverlay overlay; - - @Inject - private LizardmenShamanConfig config; - - @Inject - private Notifier notifier; - - @Inject - private Client client; - - @Provides - LizardmenShamanConfig getConfig(ConfigManager configManager) - { - return configManager.getConfig(LizardmenShamanConfig.class); - } - - @Override - protected void startUp() throws Exception - { - overlayManager.add(overlay); - } - - @Override - protected void shutDown() throws Exception - { - overlayManager.remove(overlay); - spawns.clear(); - } - - @Subscribe - public void onAnimationChanged(AnimationChanged event) - { - Actor actor = event.getActor(); - if (actor == null || actor.getName() == null) - { - return; - } - else if (actor.getName().equals(SHAMAN) && actor.getAnimation() == 7157) - { - if (config.showTimer()) - { - spawns.put(event.getActor().getLocalLocation(), new LizardmenShamanSpawn(8.4, null)); - } - - if (config.notifyOnSpawn()) - { - notifier.notify(MESSAGE); - } - } - } -} +/* + * Copyright (c) 2018, https://runelitepl.us + * 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.lizardmenshaman; + +import com.google.common.eventbus.Subscribe; +import com.google.inject.Provides; +import java.util.HashMap; +import java.util.Map; +import javax.inject.Inject; +import lombok.AccessLevel; +import lombok.Getter; +import lombok.extern.slf4j.Slf4j; +import net.runelite.api.Actor; +import net.runelite.api.Client; +import net.runelite.api.coords.LocalPoint; +import net.runelite.api.events.AnimationChanged; +import net.runelite.client.Notifier; +import net.runelite.client.config.ConfigManager; +import net.runelite.client.plugins.Plugin; +import net.runelite.client.plugins.PluginDescriptor; +import net.runelite.client.plugins.PluginType; +import net.runelite.client.ui.overlay.OverlayManager; + +@PluginDescriptor( + name = "Lizard Shamans", + description = "Configures timer for lizardmen shaman spawns.", + enabledByDefault = false, + tags = {"shaman", "lizard", "lizardmen"}, + type = PluginType.PVM +) +@Slf4j +public class LizardmenShamanPlugin extends Plugin +{ + private static final String SHAMAN = "Lizardman shaman"; + private static final String MESSAGE = "A Lizardman shaman has summoned his spawn!"; + + @Getter(AccessLevel.PACKAGE) + private final Map spawns = new HashMap<>(); + + @Inject + private OverlayManager overlayManager; + + @Inject + private ShamanSpawnOverlay overlay; + + @Inject + private LizardmenShamanConfig config; + + @Inject + private Notifier notifier; + + @Inject + private Client client; + + @Provides + LizardmenShamanConfig getConfig(ConfigManager configManager) + { + return configManager.getConfig(LizardmenShamanConfig.class); + } + + @Override + protected void startUp() throws Exception + { + overlayManager.add(overlay); + } + + @Override + protected void shutDown() throws Exception + { + overlayManager.remove(overlay); + spawns.clear(); + } + + @Subscribe + public void onAnimationChanged(AnimationChanged event) + { + Actor actor = event.getActor(); + if (actor == null || actor.getName() == null) + { + return; + } + else if (actor.getName().equals(SHAMAN) && actor.getAnimation() == 7157) + { + if (config.showTimer()) + { + spawns.put(event.getActor().getLocalLocation(), new LizardmenShamanSpawn(8.4, null)); + } + + if (config.notifyOnSpawn()) + { + notifier.notify(MESSAGE); + } + } + } +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/lizardmenshaman/ShamanSpawnOverlay.java b/runelite-client/src/main/java/net/runelite/client/plugins/lizardmenshaman/ShamanSpawnOverlay.java index 8bd71ac3ca..479b063bb3 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/lizardmenshaman/ShamanSpawnOverlay.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/lizardmenshaman/ShamanSpawnOverlay.java @@ -1,114 +1,115 @@ -/* - * Copyright (c) 2018, https://runelitepl.us - * 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.lizardmenshaman; - -import java.awt.Color; -import java.awt.Dimension; -import java.awt.Graphics2D; -import java.time.Duration; -import java.time.Instant; -import javax.inject.Inject; -import net.runelite.api.Client; -import net.runelite.api.Perspective; -import net.runelite.api.Point; -import net.runelite.client.ui.overlay.Overlay; -import net.runelite.client.ui.overlay.OverlayLayer; -import net.runelite.client.ui.overlay.OverlayPosition; -import net.runelite.client.ui.overlay.components.ProgressPieComponent; - -class ShamanSpawnOverlay extends Overlay -{ - private final Client client; - private final LizardmenShamanPlugin plugin; - - @Inject - private ShamanSpawnOverlay(Client client, LizardmenShamanPlugin plugin) - { - setPosition(OverlayPosition.DYNAMIC); - setLayer(OverlayLayer.ABOVE_SCENE); - this.client = client; - this.plugin = plugin; - } - @Override - public Dimension render(Graphics2D graphics) - { - plugin.getSpawns().forEach((localPoint, spawn) -> - { - final Instant now = Instant.now(); - final long startCountdown = Duration.between(spawn.getStart(), now).getSeconds(); - final double certainSec = spawn.getCountdownTimer() - startCountdown; - - if (certainSec <= 0) - { - if (spawn.getEnd() == null) - { - spawn.setEnd(Instant.now()); - } - } - - final ProgressPieComponent pieComponent = new ProgressPieComponent(); - final Point loc = Perspective.localToCanvas(client, localPoint, client.getPlane()); - - if (loc == null || certainSec < 0) - { - return; - } - - pieComponent.setPosition(loc); - pieComponent.setProgress(certainSec / spawn.getCountdownTimer()); - if (certainSec > 4.8) - { - pieComponent.setFill(Color.GREEN); - pieComponent.setBorderColor(Color.GREEN); - pieComponent.render(graphics); - } - else if (certainSec > 3.6) - { - pieComponent.setFill(Color.YELLOW); - pieComponent.setBorderColor(Color.YELLOW); - pieComponent.render(graphics); - } - else if (certainSec > 2.4) - { - pieComponent.setFill(Color.ORANGE); - pieComponent.setBorderColor(Color.ORANGE); - pieComponent.render(graphics); - } - else if (certainSec > 1.2) - { - pieComponent.setFill(new Color(255, 140, 0)); - pieComponent.setBorderColor(new Color(255, 140, 0)); - pieComponent.render(graphics); - } - else - { - pieComponent.setFill(Color.RED); - pieComponent.setBorderColor(Color.RED); - pieComponent.render(graphics); - } - }); - return null; - } -} +/* + * Copyright (c) 2018, https://runelitepl.us + * 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.lizardmenshaman; + +import java.awt.Color; +import java.awt.Dimension; +import java.awt.Graphics2D; +import java.time.Duration; +import java.time.Instant; +import javax.inject.Inject; +import net.runelite.api.Client; +import net.runelite.api.Perspective; +import net.runelite.api.Point; +import net.runelite.client.ui.overlay.Overlay; +import net.runelite.client.ui.overlay.OverlayLayer; +import net.runelite.client.ui.overlay.OverlayPosition; +import net.runelite.client.ui.overlay.components.ProgressPieComponent; + +class ShamanSpawnOverlay extends Overlay +{ + private final Client client; + private final LizardmenShamanPlugin plugin; + + @Inject + private ShamanSpawnOverlay(Client client, LizardmenShamanPlugin plugin) + { + setPosition(OverlayPosition.DYNAMIC); + setLayer(OverlayLayer.ABOVE_SCENE); + this.client = client; + this.plugin = plugin; + } + + @Override + public Dimension render(Graphics2D graphics) + { + plugin.getSpawns().forEach((localPoint, spawn) -> + { + final Instant now = Instant.now(); + final long startCountdown = Duration.between(spawn.getStart(), now).getSeconds(); + final double certainSec = spawn.getCountdownTimer() - startCountdown; + + if (certainSec <= 0) + { + if (spawn.getEnd() == null) + { + spawn.setEnd(Instant.now()); + } + } + + final ProgressPieComponent pieComponent = new ProgressPieComponent(); + final Point loc = Perspective.localToCanvas(client, localPoint, client.getPlane()); + + if (loc == null || certainSec < 0) + { + return; + } + + pieComponent.setPosition(loc); + pieComponent.setProgress(certainSec / spawn.getCountdownTimer()); + if (certainSec > 4.8) + { + pieComponent.setFill(Color.GREEN); + pieComponent.setBorderColor(Color.GREEN); + pieComponent.render(graphics); + } + else if (certainSec > 3.6) + { + pieComponent.setFill(Color.YELLOW); + pieComponent.setBorderColor(Color.YELLOW); + pieComponent.render(graphics); + } + else if (certainSec > 2.4) + { + pieComponent.setFill(Color.ORANGE); + pieComponent.setBorderColor(Color.ORANGE); + pieComponent.render(graphics); + } + else if (certainSec > 1.2) + { + pieComponent.setFill(new Color(255, 140, 0)); + pieComponent.setBorderColor(new Color(255, 140, 0)); + pieComponent.render(graphics); + } + else + { + pieComponent.setFill(Color.RED); + pieComponent.setBorderColor(Color.RED); + pieComponent.render(graphics); + } + }); + return null; + } +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/loginscreen/LoginScreenPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/loginscreen/LoginScreenPlugin.java index 4da52e1492..aaa99cc0a9 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/loginscreen/LoginScreenPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/loginscreen/LoginScreenPlugin.java @@ -1,209 +1,209 @@ -/* - * Copyright (c) 2017, Seth - * 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.loginscreen; - -import com.google.common.base.Strings; -import com.google.inject.Provides; -import java.awt.Toolkit; -import java.awt.datatransfer.DataFlavor; -import java.awt.datatransfer.UnsupportedFlavorException; -import java.awt.event.KeyEvent; -import java.io.IOException; -import javax.inject.Inject; -import lombok.extern.slf4j.Slf4j; -import net.runelite.api.Client; -import net.runelite.api.GameState; -import net.runelite.api.events.GameStateChanged; -import net.runelite.client.events.SessionOpen; -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.OSType; - -@PluginDescriptor( - name = "Login Screen", - description = "Provides various enhancements for login screen" -) -@Slf4j -public class LoginScreenPlugin extends Plugin implements KeyListener -{ - private static final int MAX_USERNAME_LENGTH = 254; - private static final int MAX_PASSWORD_LENGTH = 20; - - @Inject - private Client client; - - @Inject - private LoginScreenConfig config; - - @Inject - private KeyManager keyManager; - - private String usernameCache; - - @Override - protected void startUp() throws Exception - { - applyUsername(); - keyManager.registerKeyListener(this); - } - - @Override - protected void shutDown() throws Exception - { - if (config.syncUsername()) - { - client.getPreferences().setRememberedUsername(usernameCache); - } - - keyManager.unregisterKeyListener(this); - } - - @Provides - LoginScreenConfig getConfig(ConfigManager configManager) - { - return configManager.getConfig(LoginScreenConfig.class); - } - - @Subscribe - public void onGameStateChanged(GameStateChanged event) - { - if (!config.syncUsername()) - { - return; - } - - if (event.getGameState() == GameState.LOGIN_SCREEN) - { - applyUsername(); - } - else if (event.getGameState() == GameState.LOGGED_IN) - { - String username = ""; - - if (client.getPreferences().getRememberedUsername() != null) - { - username = client.getUsername(); - } - - if (config.username().equals(username)) - { - return; - } - - log.debug("Saving username: {}", username); - config.username(username); - } - } - - @Subscribe - public void onSessionOpen(SessionOpen event) - { - // configuation for the account is available now, so update the username - applyUsername(); - } - - private void applyUsername() - { - if (!config.syncUsername()) - { - return; - } - - GameState gameState = client.getGameState(); - if (gameState == GameState.LOGIN_SCREEN) - { - String username = config.username(); - - if (Strings.isNullOrEmpty(username)) - { - return; - } - - // Save it only once - if (usernameCache == null) - { - usernameCache = client.getPreferences().getRememberedUsername(); - } - - client.getPreferences().setRememberedUsername(username); - } - } - - @Override - public void keyTyped(KeyEvent e) - { - } - - @Override - public void keyPressed(KeyEvent e) - { - if (!config.pasteEnabled() || client.getGameState() != GameState.LOGIN_SCREEN) - { - return; - } - - // enable pasting on macOS with the Command (meta) key - boolean isModifierDown = OSType.getOSType() == OSType.MacOS ? e.isMetaDown() : e.isControlDown(); - - if (e.getKeyCode() == KeyEvent.VK_V && isModifierDown) - { - try - { - final String data = Toolkit - .getDefaultToolkit() - .getSystemClipboard() - .getData(DataFlavor.stringFlavor) - .toString() - .trim(); - - // 0 is username, 1 is password - if (client.getCurrentLoginField() == 0) - { - // Truncate data to maximum username length if necessary - client.setUsername(data.substring(0, Math.min(data.length(), MAX_USERNAME_LENGTH))); - } - else - { - // Truncate data to maximum password length if necessary - client.setPassword(data.substring(0, Math.min(data.length(), MAX_PASSWORD_LENGTH))); - } - } - catch (UnsupportedFlavorException | IOException ex) - { - log.warn("failed to fetch clipboard data", ex); - } - } - } - - @Override - public void keyReleased(KeyEvent e) - { - - } +/* + * Copyright (c) 2017, Seth + * 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.loginscreen; + +import com.google.common.base.Strings; +import com.google.inject.Provides; +import java.awt.Toolkit; +import java.awt.datatransfer.DataFlavor; +import java.awt.datatransfer.UnsupportedFlavorException; +import java.awt.event.KeyEvent; +import java.io.IOException; +import javax.inject.Inject; +import lombok.extern.slf4j.Slf4j; +import net.runelite.api.Client; +import net.runelite.api.GameState; +import net.runelite.api.events.GameStateChanged; +import net.runelite.client.config.ConfigManager; +import net.runelite.client.eventbus.Subscribe; +import net.runelite.client.events.SessionOpen; +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.OSType; + +@PluginDescriptor( + name = "Login Screen", + description = "Provides various enhancements for login screen" +) +@Slf4j +public class LoginScreenPlugin extends Plugin implements KeyListener +{ + private static final int MAX_USERNAME_LENGTH = 254; + private static final int MAX_PASSWORD_LENGTH = 20; + + @Inject + private Client client; + + @Inject + private LoginScreenConfig config; + + @Inject + private KeyManager keyManager; + + private String usernameCache; + + @Override + protected void startUp() throws Exception + { + applyUsername(); + keyManager.registerKeyListener(this); + } + + @Override + protected void shutDown() throws Exception + { + if (config.syncUsername()) + { + client.getPreferences().setRememberedUsername(usernameCache); + } + + keyManager.unregisterKeyListener(this); + } + + @Provides + LoginScreenConfig getConfig(ConfigManager configManager) + { + return configManager.getConfig(LoginScreenConfig.class); + } + + @Subscribe + public void onGameStateChanged(GameStateChanged event) + { + if (!config.syncUsername()) + { + return; + } + + if (event.getGameState() == GameState.LOGIN_SCREEN) + { + applyUsername(); + } + else if (event.getGameState() == GameState.LOGGED_IN) + { + String username = ""; + + if (client.getPreferences().getRememberedUsername() != null) + { + username = client.getUsername(); + } + + if (config.username().equals(username)) + { + return; + } + + log.debug("Saving username: {}", username); + config.username(username); + } + } + + @Subscribe + public void onSessionOpen(SessionOpen event) + { + // configuation for the account is available now, so update the username + applyUsername(); + } + + private void applyUsername() + { + if (!config.syncUsername()) + { + return; + } + + GameState gameState = client.getGameState(); + if (gameState == GameState.LOGIN_SCREEN) + { + String username = config.username(); + + if (Strings.isNullOrEmpty(username)) + { + return; + } + + // Save it only once + if (usernameCache == null) + { + usernameCache = client.getPreferences().getRememberedUsername(); + } + + client.getPreferences().setRememberedUsername(username); + } + } + + @Override + public void keyTyped(KeyEvent e) + { + } + + @Override + public void keyPressed(KeyEvent e) + { + if (!config.pasteEnabled() || client.getGameState() != GameState.LOGIN_SCREEN) + { + return; + } + + // enable pasting on macOS with the Command (meta) key + boolean isModifierDown = OSType.getOSType() == OSType.MacOS ? e.isMetaDown() : e.isControlDown(); + + if (e.getKeyCode() == KeyEvent.VK_V && isModifierDown) + { + try + { + final String data = Toolkit + .getDefaultToolkit() + .getSystemClipboard() + .getData(DataFlavor.stringFlavor) + .toString() + .trim(); + + // 0 is username, 1 is password + if (client.getCurrentLoginField() == 0) + { + // Truncate data to maximum username length if necessary + client.setUsername(data.substring(0, Math.min(data.length(), MAX_USERNAME_LENGTH))); + } + else + { + // Truncate data to maximum password length if necessary + client.setPassword(data.substring(0, Math.min(data.length(), MAX_PASSWORD_LENGTH))); + } + } + catch (UnsupportedFlavorException | IOException ex) + { + log.warn("failed to fetch clipboard data", ex); + } + } + } + + @Override + public void keyReleased(KeyEvent e) + { + + } } \ No newline at end of file diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/lootassist/LootAssistPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/lootassist/LootAssistPlugin.java index 5583bab542..77b4affd86 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/lootassist/LootAssistPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/lootassist/LootAssistPlugin.java @@ -5,7 +5,6 @@ import java.util.concurrent.ConcurrentHashMap; import javax.inject.Inject; import net.runelite.api.Actor; import net.runelite.api.AnimationID; -import net.runelite.api.Client; import net.runelite.api.Player; import net.runelite.api.coords.WorldPoint; import net.runelite.api.events.AnimationChanged; diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/lootassist/LootPile.java b/runelite-client/src/main/java/net/runelite/client/plugins/lootassist/LootPile.java index 4e2e5125d0..32fa145088 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/lootassist/LootPile.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/lootassist/LootPile.java @@ -2,7 +2,6 @@ package net.runelite.client.plugins.lootassist; import lombok.Getter; import lombok.Setter; -import net.runelite.api.coords.LocalPoint; import net.runelite.api.coords.WorldPoint; class LootPile diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/lootingbagviewer/LootingBagViewerOverlay.java b/runelite-client/src/main/java/net/runelite/client/plugins/lootingbagviewer/LootingBagViewerOverlay.java index 4b66517489..461e752386 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/lootingbagviewer/LootingBagViewerOverlay.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/lootingbagviewer/LootingBagViewerOverlay.java @@ -25,6 +25,11 @@ package net.runelite.client.plugins.lootingbagviewer; +import java.awt.Dimension; +import java.awt.Graphics2D; +import java.awt.Point; +import java.awt.image.BufferedImage; +import javax.inject.Inject; import net.runelite.api.Client; import net.runelite.api.InventoryID; import net.runelite.api.Item; @@ -36,10 +41,6 @@ import net.runelite.client.ui.overlay.components.ComponentOrientation; import net.runelite.client.ui.overlay.components.ImageComponent; import net.runelite.client.ui.overlay.components.PanelComponent; -import javax.inject.Inject; -import java.awt.*; -import java.awt.image.BufferedImage; - class LootingBagViewerOverlay extends Overlay { private static final int INVENTORY_SIZE = 28; @@ -72,7 +73,8 @@ class LootingBagViewerOverlay extends Overlay { if (itemContainer == null) { - if(client.getItemContainer(InventoryID.LOOTING_BAG) != null) { + if (client.getItemContainer(InventoryID.LOOTING_BAG) != null) + { itemContainer = client.getItemContainer(InventoryID.LOOTING_BAG); if (itemContainer != null) { @@ -81,7 +83,7 @@ class LootingBagViewerOverlay extends Overlay } return null; } - else if(items != null && client.getItemContainer(InventoryID.LOOTING_BAG) != null) + else if (items != null && client.getItemContainer(InventoryID.LOOTING_BAG) != null) { itemContainer = client.getItemContainer(InventoryID.LOOTING_BAG); if (itemContainer != null) diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/lootingbagviewer/LootingBagViewerPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/lootingbagviewer/LootingBagViewerPlugin.java index ea5922af3f..51f40a8739 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/lootingbagviewer/LootingBagViewerPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/lootingbagviewer/LootingBagViewerPlugin.java @@ -1,61 +1,60 @@ -/* - * Copyright (c) 2018 AWPH-I - * 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.lootingbagviewer; - -import net.runelite.client.plugins.Plugin; -import net.runelite.client.plugins.PluginDescriptor; -import net.runelite.client.plugins.PluginType; -import net.runelite.client.ui.overlay.OverlayManager; - -import javax.inject.Inject; - -@PluginDescriptor( - name = "PvP Looting Bag Viewer", - description = "Add an overlay showing the contents of your looting bag", - tags = {"alternate", "items", "overlay", "second"}, - type = PluginType.PVP, - enabledByDefault = false -) -public class LootingBagViewerPlugin extends Plugin -{ - @Inject - private net.runelite.client.plugins.lootingbagviewer.LootingBagViewerOverlay overlay; - - @Inject - private OverlayManager overlayManager; - - @Override - public void startUp() - { - overlayManager.add(overlay); - } - - @Override - public void shutDown() - { - overlayManager.remove(overlay); - } -} +/* + * Copyright (c) 2018 AWPH-I + * 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.lootingbagviewer; + +import javax.inject.Inject; +import net.runelite.client.plugins.Plugin; +import net.runelite.client.plugins.PluginDescriptor; +import net.runelite.client.plugins.PluginType; +import net.runelite.client.ui.overlay.OverlayManager; + +@PluginDescriptor( + name = "PvP Looting Bag Viewer", + description = "Add an overlay showing the contents of your looting bag", + tags = {"alternate", "items", "overlay", "second"}, + type = PluginType.PVP, + enabledByDefault = false +) +public class LootingBagViewerPlugin extends Plugin +{ + @Inject + private net.runelite.client.plugins.lootingbagviewer.LootingBagViewerOverlay overlay; + + @Inject + private OverlayManager overlayManager; + + @Override + public void startUp() + { + overlayManager.add(overlay); + } + + @Override + public void shutDown() + { + overlayManager.remove(overlay); + } +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/loottracker/LootTrackerConfig.java b/runelite-client/src/main/java/net/runelite/client/plugins/loottracker/LootTrackerConfig.java index c2f355d7f9..597dcfddf9 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/loottracker/LootTrackerConfig.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/loottracker/LootTrackerConfig.java @@ -60,9 +60,9 @@ public interface LootTrackerConfig extends Config } @ConfigItem( - keyName = "chestLootChat", - name = "Show chest loot value in chat", - description = "Show the value of items from CoX/ToB/Barrows chests in chat" + keyName = "chestLootChat", + name = "Show chest loot value in chat", + description = "Show the value of items from CoX/ToB/Barrows chests in chat" ) default boolean chestLootChat() { diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/loottracker/LootTrackerPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/loottracker/LootTrackerPlugin.java index f561a87a25..77c151bfc4 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/loottracker/LootTrackerPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/loottracker/LootTrackerPlugin.java @@ -51,8 +51,8 @@ import lombok.Getter; import lombok.extern.slf4j.Slf4j; import net.runelite.api.ChatMessageType; import net.runelite.api.Client; -import net.runelite.api.Item; import net.runelite.api.InventoryID; +import net.runelite.api.Item; import net.runelite.api.ItemComposition; import net.runelite.api.ItemContainer; import net.runelite.api.NPC; @@ -121,7 +121,7 @@ public class LootTrackerPlugin extends Plugin @Inject private ItemManager itemManager; - + @Inject private ChatMessageManager chatMessageManager; @@ -372,16 +372,16 @@ public class LootTrackerPlugin extends Plugin } final ChatMessageBuilder message = new ChatMessageBuilder() - .append(ChatColorType.HIGHLIGHT) - .append("Your loot is worth around ") - .append(StackFormatter.formatNumber(chestPrice)) - .append(" coins.") - .append(ChatColorType.NORMAL); + .append(ChatColorType.HIGHLIGHT) + .append("Your loot is worth around ") + .append(StackFormatter.formatNumber(chestPrice)) + .append(" coins.") + .append(ChatColorType.NORMAL); chatMessageManager.queue(QueuedMessage.builder() - .type(ChatMessageType.ITEM_EXAMINE) - .runeLiteFormattedMessage(message.build()) - .build()); + .type(ChatMessageType.ITEM_EXAMINE) + .runeLiteFormattedMessage(message.build()) + .build()); } // Convert container items to array of ItemStack @@ -489,7 +489,7 @@ public class LootTrackerPlugin extends Plugin { inventorySnapshot = HashMultiset.create(); Arrays.stream(itemContainer.getItems()) - .forEach(item -> inventorySnapshot.add(item.getId(), item.getQuantity())); + .forEach(item -> inventorySnapshot.add(item.getId(), item.getQuantity())); } } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/loottracker/LootTrackerRecord.java b/runelite-client/src/main/java/net/runelite/client/plugins/loottracker/LootTrackerRecord.java index 0d75ec70c3..df03f7a75b 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/loottracker/LootTrackerRecord.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/loottracker/LootTrackerRecord.java @@ -1,51 +1,52 @@ -/* - * Copyright (c) 2018, Psikoi - * 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.loottracker; - -import lombok.Value; - -@Value -class LootTrackerRecord -{ - private final String title; - private final String subTitle; - private final LootTrackerItem[] items; - private final long timestamp; - - /** - * Checks if this record matches specified id - * @param id other record id - * @return true if match is made - */ - boolean matches(final String id) - { - if (id == null) - { - return true; - } - - return title.equals(id); - } +/* + * Copyright (c) 2018, Psikoi + * 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.loottracker; + +import lombok.Value; + +@Value +class LootTrackerRecord +{ + private final String title; + private final String subTitle; + private final LootTrackerItem[] items; + private final long timestamp; + + /** + * Checks if this record matches specified id + * + * @param id other record id + * @return true if match is made + */ + boolean matches(final String id) + { + if (id == null) + { + return true; + } + + return title.equals(id); + } } \ No newline at end of file diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/maxhit/MaxHitPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/maxhit/MaxHitPlugin.java index e9632d1454..88f321cbd5 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/maxhit/MaxHitPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/maxhit/MaxHitPlugin.java @@ -1,139 +1,138 @@ -/* - * Copyright (c) 2019, Bartvollebregt - * 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.maxhit; - -import net.runelite.api.Client; -import net.runelite.api.InventoryID; -import net.runelite.api.Item; -import net.runelite.api.ItemContainer; -import net.runelite.api.events.ConfigChanged; -import net.runelite.api.events.ItemContainerChanged; -import net.runelite.api.events.VarbitChanged; -import net.runelite.api.widgets.Widget; -import net.runelite.api.widgets.WidgetInfo; -import net.runelite.client.eventbus.Subscribe; -import net.runelite.client.plugins.Plugin; -import net.runelite.client.plugins.PluginDescriptor; -import net.runelite.client.plugins.PluginType; -import net.runelite.client.plugins.maxhit.calculators.MagicMaxHitCalculator; -import net.runelite.client.plugins.maxhit.calculators.MeleeMaxHitCalculator; -import net.runelite.client.plugins.maxhit.calculators.RangeMaxHitCalculator; - -import javax.inject.Inject; - -@PluginDescriptor( - name = "Max Hit", - description = "Max Hit Calculator", - type = PluginType.UTILITY, - enabledByDefault = false -) -public class MaxHitPlugin extends Plugin -{ - - @Inject - private Client client; - - @Subscribe - public void onItemContainerChanged(final ItemContainerChanged event) - { - this.updateMaxHitWidget(); - } - - @Subscribe - public void onConfigChanged(final ConfigChanged event) - { - this.updateMaxHitWidget(); - } - - @Subscribe - public void onVarbitChanged(VarbitChanged event) - { - this.updateMaxHitWidget(); - } - - private void updateMaxHitWidget() - { - Widget equipmentStats = client.getWidget(WidgetInfo.EQUIPMENT_INVENTORY_ITEMS_CONTAINER); - - ItemContainer equipmentContainer = client.getItemContainer(InventoryID.EQUIPMENT); - Item[] equipedItems = new Item[14]; - - if (equipmentStats != null && !equipmentStats.isHidden()) - { - if (equipmentContainer != null) - { - equipedItems = equipmentContainer.getItems(); - } - - MeleeMaxHitCalculator meleeMaxHitCalculator = new MeleeMaxHitCalculator(this.client, equipedItems); - RangeMaxHitCalculator rangeMaxHitCalculator = new RangeMaxHitCalculator(this.client, equipedItems); - MagicMaxHitCalculator magicMaxHitCalculator = new MagicMaxHitCalculator(this.client, equipedItems); - - MaxHit maxHit = new MaxHit(meleeMaxHitCalculator.getMaxHit(), rangeMaxHitCalculator.getMaxHit(), magicMaxHitCalculator.getMaxHit()); - this.setWidgetMaxHit(maxHit); - } - } - - private void setWidgetMaxHit(MaxHit maxhit) - { - Widget equipYourCharacter = client.getWidget(WidgetInfo.EQUIP_YOUR_CHARACTER); - String maxHitText = "Melee Max Hit: " + maxhit.getMaxMeleeHit(); - maxHitText += "
Range Max Hit: " + maxhit.getMaxRangeHit(); - maxHitText += "
Magic Max Hit: " + maxhit.getMaxMagicHit(); - - - equipYourCharacter.setText(maxHitText); - } - - private class MaxHit - { - private final double maxMeleeHit; - private final double maxRangeHit; - private final double maxMagicHit; - - MaxHit(double maxMeleeHit, double maxRangeHit, double maxMagicHit) - { - this.maxMeleeHit = maxMeleeHit; - this.maxRangeHit = maxRangeHit; - this.maxMagicHit = maxMagicHit; - } - - double getMaxMeleeHit() - { - return maxMeleeHit; - } - - double getMaxRangeHit() - { - return maxRangeHit; - } - - double getMaxMagicHit() - { - return maxMagicHit; - } - } - -} +/* + * Copyright (c) 2019, Bartvollebregt + * 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.maxhit; + +import javax.inject.Inject; +import net.runelite.api.Client; +import net.runelite.api.InventoryID; +import net.runelite.api.Item; +import net.runelite.api.ItemContainer; +import net.runelite.api.events.ConfigChanged; +import net.runelite.api.events.ItemContainerChanged; +import net.runelite.api.events.VarbitChanged; +import net.runelite.api.widgets.Widget; +import net.runelite.api.widgets.WidgetInfo; +import net.runelite.client.eventbus.Subscribe; +import net.runelite.client.plugins.Plugin; +import net.runelite.client.plugins.PluginDescriptor; +import net.runelite.client.plugins.PluginType; +import net.runelite.client.plugins.maxhit.calculators.MagicMaxHitCalculator; +import net.runelite.client.plugins.maxhit.calculators.MeleeMaxHitCalculator; +import net.runelite.client.plugins.maxhit.calculators.RangeMaxHitCalculator; + +@PluginDescriptor( + name = "Max Hit", + description = "Max Hit Calculator", + type = PluginType.UTILITY, + enabledByDefault = false +) +public class MaxHitPlugin extends Plugin +{ + + @Inject + private Client client; + + @Subscribe + public void onItemContainerChanged(final ItemContainerChanged event) + { + this.updateMaxHitWidget(); + } + + @Subscribe + public void onConfigChanged(final ConfigChanged event) + { + this.updateMaxHitWidget(); + } + + @Subscribe + public void onVarbitChanged(VarbitChanged event) + { + this.updateMaxHitWidget(); + } + + private void updateMaxHitWidget() + { + Widget equipmentStats = client.getWidget(WidgetInfo.EQUIPMENT_INVENTORY_ITEMS_CONTAINER); + + ItemContainer equipmentContainer = client.getItemContainer(InventoryID.EQUIPMENT); + Item[] equipedItems = new Item[14]; + + if (equipmentStats != null && !equipmentStats.isHidden()) + { + if (equipmentContainer != null) + { + equipedItems = equipmentContainer.getItems(); + } + + MeleeMaxHitCalculator meleeMaxHitCalculator = new MeleeMaxHitCalculator(this.client, equipedItems); + RangeMaxHitCalculator rangeMaxHitCalculator = new RangeMaxHitCalculator(this.client, equipedItems); + MagicMaxHitCalculator magicMaxHitCalculator = new MagicMaxHitCalculator(this.client, equipedItems); + + MaxHit maxHit = new MaxHit(meleeMaxHitCalculator.getMaxHit(), rangeMaxHitCalculator.getMaxHit(), magicMaxHitCalculator.getMaxHit()); + this.setWidgetMaxHit(maxHit); + } + } + + private void setWidgetMaxHit(MaxHit maxhit) + { + Widget equipYourCharacter = client.getWidget(WidgetInfo.EQUIP_YOUR_CHARACTER); + String maxHitText = "Melee Max Hit: " + maxhit.getMaxMeleeHit(); + maxHitText += "
Range Max Hit: " + maxhit.getMaxRangeHit(); + maxHitText += "
Magic Max Hit: " + maxhit.getMaxMagicHit(); + + + equipYourCharacter.setText(maxHitText); + } + + private class MaxHit + { + private final double maxMeleeHit; + private final double maxRangeHit; + private final double maxMagicHit; + + MaxHit(double maxMeleeHit, double maxRangeHit, double maxMagicHit) + { + this.maxMeleeHit = maxMeleeHit; + this.maxRangeHit = maxRangeHit; + this.maxMagicHit = maxMagicHit; + } + + double getMaxMeleeHit() + { + return maxMeleeHit; + } + + double getMaxRangeHit() + { + return maxRangeHit; + } + + double getMaxMagicHit() + { + return maxMagicHit; + } + } + +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/maxhit/attackstyle/WeaponType.java b/runelite-client/src/main/java/net/runelite/client/plugins/maxhit/attackstyle/WeaponType.java index 97ed177f27..a3c30d7dd2 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/maxhit/attackstyle/WeaponType.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/maxhit/attackstyle/WeaponType.java @@ -1,89 +1,97 @@ -/* - * Copyright (c) 2019, Bartvollebregt - * 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.maxhit.attackstyle; - -import java.util.HashMap; -import java.util.Map; - -import static net.runelite.client.plugins.maxhit.attackstyle.AttackStyle.*; - -public enum WeaponType -{ - TYPE_0(ACCURATE, AGGRESSIVE, null, DEFENSIVE), - TYPE_1(ACCURATE, AGGRESSIVE, AGGRESSIVE, DEFENSIVE), - TYPE_2(ACCURATE, AGGRESSIVE, null, DEFENSIVE), - TYPE_3(ACCURATERANGING, RANGING, null, LONGRANGE), - TYPE_4(ACCURATE, AGGRESSIVE, CONTROLLED, DEFENSIVE), - TYPE_5(ACCURATERANGING, RANGING, null, LONGRANGE), - TYPE_6(AGGRESSIVE, RANGING, DEFENSIVE_CASTING, null), - TYPE_7(ACCURATERANGING, RANGING, null, LONGRANGE), - TYPE_8(OTHER, AGGRESSIVE, null, null), - TYPE_9(ACCURATE, AGGRESSIVE, CONTROLLED, DEFENSIVE), - TYPE_10(ACCURATE, AGGRESSIVE, AGGRESSIVE, DEFENSIVE), - TYPE_11(ACCURATE, AGGRESSIVE, AGGRESSIVE, DEFENSIVE), - TYPE_12(CONTROLLED, AGGRESSIVE, null, DEFENSIVE), - TYPE_13(ACCURATE, AGGRESSIVE, null, DEFENSIVE), - TYPE_14(ACCURATE, AGGRESSIVE, AGGRESSIVE, DEFENSIVE), - TYPE_15(CONTROLLED, CONTROLLED, CONTROLLED, DEFENSIVE), - TYPE_16(ACCURATE, AGGRESSIVE, CONTROLLED, DEFENSIVE), - TYPE_17(ACCURATE, AGGRESSIVE, AGGRESSIVE, DEFENSIVE), - TYPE_18(ACCURATE, AGGRESSIVE, null, DEFENSIVE, CASTING, DEFENSIVE_CASTING), - TYPE_19(ACCURATERANGING, RANGING, null, LONGRANGE), - TYPE_20(ACCURATE, CONTROLLED, null, DEFENSIVE), - TYPE_21(ACCURATE, AGGRESSIVE, null, DEFENSIVE, CASTING, DEFENSIVE_CASTING), - TYPE_22(ACCURATE, AGGRESSIVE, AGGRESSIVE, DEFENSIVE), - TYPE_23(CASTING, CASTING, null, DEFENSIVE_CASTING), - TYPE_24(ACCURATE, AGGRESSIVE, CONTROLLED, DEFENSIVE), - TYPE_25(CONTROLLED, AGGRESSIVE, null, DEFENSIVE), - TYPE_26(AGGRESSIVE, AGGRESSIVE, null, AGGRESSIVE), - TYPE_27(ACCURATE, null, null, OTHER); - - private static final Map weaponTypes = new HashMap<>(); - - static - { - for (WeaponType weaponType : values()) - { - weaponTypes.put(weaponType.ordinal(), weaponType); - } - } - - private final AttackStyle[] attackStyles; - - WeaponType(AttackStyle... attackStyles) - { - this.attackStyles = attackStyles; - } - - public static WeaponType getWeaponType(int id) - { - return weaponTypes.get(id); - } - - public AttackStyle[] getAttackStyles() - { - return attackStyles; - } -} +/* + * Copyright (c) 2019, Bartvollebregt + * 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.maxhit.attackstyle; + +import java.util.HashMap; +import java.util.Map; +import static net.runelite.client.plugins.maxhit.attackstyle.AttackStyle.ACCURATE; +import static net.runelite.client.plugins.maxhit.attackstyle.AttackStyle.ACCURATERANGING; +import static net.runelite.client.plugins.maxhit.attackstyle.AttackStyle.AGGRESSIVE; +import static net.runelite.client.plugins.maxhit.attackstyle.AttackStyle.CASTING; +import static net.runelite.client.plugins.maxhit.attackstyle.AttackStyle.CONTROLLED; +import static net.runelite.client.plugins.maxhit.attackstyle.AttackStyle.DEFENSIVE; +import static net.runelite.client.plugins.maxhit.attackstyle.AttackStyle.DEFENSIVE_CASTING; +import static net.runelite.client.plugins.maxhit.attackstyle.AttackStyle.LONGRANGE; +import static net.runelite.client.plugins.maxhit.attackstyle.AttackStyle.OTHER; +import static net.runelite.client.plugins.maxhit.attackstyle.AttackStyle.RANGING; + +public enum WeaponType +{ + TYPE_0(ACCURATE, AGGRESSIVE, null, DEFENSIVE), + TYPE_1(ACCURATE, AGGRESSIVE, AGGRESSIVE, DEFENSIVE), + TYPE_2(ACCURATE, AGGRESSIVE, null, DEFENSIVE), + TYPE_3(ACCURATERANGING, RANGING, null, LONGRANGE), + TYPE_4(ACCURATE, AGGRESSIVE, CONTROLLED, DEFENSIVE), + TYPE_5(ACCURATERANGING, RANGING, null, LONGRANGE), + TYPE_6(AGGRESSIVE, RANGING, DEFENSIVE_CASTING, null), + TYPE_7(ACCURATERANGING, RANGING, null, LONGRANGE), + TYPE_8(OTHER, AGGRESSIVE, null, null), + TYPE_9(ACCURATE, AGGRESSIVE, CONTROLLED, DEFENSIVE), + TYPE_10(ACCURATE, AGGRESSIVE, AGGRESSIVE, DEFENSIVE), + TYPE_11(ACCURATE, AGGRESSIVE, AGGRESSIVE, DEFENSIVE), + TYPE_12(CONTROLLED, AGGRESSIVE, null, DEFENSIVE), + TYPE_13(ACCURATE, AGGRESSIVE, null, DEFENSIVE), + TYPE_14(ACCURATE, AGGRESSIVE, AGGRESSIVE, DEFENSIVE), + TYPE_15(CONTROLLED, CONTROLLED, CONTROLLED, DEFENSIVE), + TYPE_16(ACCURATE, AGGRESSIVE, CONTROLLED, DEFENSIVE), + TYPE_17(ACCURATE, AGGRESSIVE, AGGRESSIVE, DEFENSIVE), + TYPE_18(ACCURATE, AGGRESSIVE, null, DEFENSIVE, CASTING, DEFENSIVE_CASTING), + TYPE_19(ACCURATERANGING, RANGING, null, LONGRANGE), + TYPE_20(ACCURATE, CONTROLLED, null, DEFENSIVE), + TYPE_21(ACCURATE, AGGRESSIVE, null, DEFENSIVE, CASTING, DEFENSIVE_CASTING), + TYPE_22(ACCURATE, AGGRESSIVE, AGGRESSIVE, DEFENSIVE), + TYPE_23(CASTING, CASTING, null, DEFENSIVE_CASTING), + TYPE_24(ACCURATE, AGGRESSIVE, CONTROLLED, DEFENSIVE), + TYPE_25(CONTROLLED, AGGRESSIVE, null, DEFENSIVE), + TYPE_26(AGGRESSIVE, AGGRESSIVE, null, AGGRESSIVE), + TYPE_27(ACCURATE, null, null, OTHER); + + private static final Map weaponTypes = new HashMap<>(); + + static + { + for (WeaponType weaponType : values()) + { + weaponTypes.put(weaponType.ordinal(), weaponType); + } + } + + private final AttackStyle[] attackStyles; + + WeaponType(AttackStyle... attackStyles) + { + this.attackStyles = attackStyles; + } + + public static WeaponType getWeaponType(int id) + { + return weaponTypes.get(id); + } + + public AttackStyle[] getAttackStyles() + { + return attackStyles; + } +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/maxhit/calculators/MaxHitCalculator.java b/runelite-client/src/main/java/net/runelite/client/plugins/maxhit/calculators/MaxHitCalculator.java index 95cc98a266..d23ad088e1 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/maxhit/calculators/MaxHitCalculator.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/maxhit/calculators/MaxHitCalculator.java @@ -1,178 +1,177 @@ -/* - * Copyright (c) 2019, Bartvollebregt - * 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.maxhit.calculators; - -import net.runelite.api.Client; -import net.runelite.api.Item; -import net.runelite.api.VarPlayer; -import net.runelite.api.Varbits; -import net.runelite.api.widgets.Widget; -import net.runelite.client.plugins.maxhit.attackstyle.AttackStyle; -import net.runelite.client.plugins.maxhit.attackstyle.WeaponType; -import net.runelite.client.plugins.maxhit.config.CustomFormulaConfig; -import net.runelite.client.plugins.maxhit.config.EquipmentBonusConfig; -import net.runelite.client.plugins.maxhit.config.PrayerBonusConfig; -import net.runelite.client.plugins.maxhit.equipment.EquipmentHelper; -import net.runelite.client.plugins.maxhit.equipment.EquipmentItemset; - -import java.util.ArrayList; -import java.util.function.BiFunction; - -public abstract class MaxHitCalculator -{ - - final Client client; - private final CombatMethod combatMethod; - private final Item[] equipedItems; - int baseDamage = 0; - - MaxHitCalculator(Client client, CombatMethod combatMethod, Item[] equipedItems) - { - this.client = client; - this.combatMethod = combatMethod; - this.equipedItems = equipedItems; - } - - protected abstract String getSkillStrengthText(String equipmentText); - - abstract Widget equipmentSkillPower(); - - public abstract double getCurrentSkillPower(); - - AttackStyle getAttackStyle() - { - int equippedWeaponTypeId = client.getVar(Varbits.EQUIPPED_WEAPON_TYPE); - int attackStyleId = client.getVar(VarPlayer.ATTACK_STYLE); - - AttackStyle[] attackStyles = WeaponType.getWeaponType(equippedWeaponTypeId).getAttackStyles(); - - if (attackStyleId < attackStyles.length) - { - AttackStyle attackStyle = attackStyles[attackStyleId]; - if (attackStyle != null) - { - return attackStyle; - } - } - - return AttackStyle.OTHER; - } - - double getPrayerBonus() - { - double bonus = 1; - for (PrayerBonusConfig prayerBonus : PrayerBonusConfig.values()) - { - boolean prayerActive = client.getVar(prayerBonus.getPrayerVarbit()) == 1; - boolean sameCombatMethod = prayerBonus.getCombatMethod() == this.combatMethod; - if (prayerActive && sameCombatMethod) - { - bonus += prayerBonus.getStrengthBonus(); - } - } - return bonus; - } - - double applyEquipmentBonus(double maxhit, EquipmentBonusConfig.BonusType bonusType) - { - double bonus = 1; - ArrayList addList = new ArrayList<>(); - - ArrayList equipmentBonuses = EquipmentBonusConfig.getBonusByType(bonusType); - - for (EquipmentBonusConfig equipmentBonus : equipmentBonuses) - { - EquipmentItemset itemSet = equipmentBonus.getItemset(); - boolean wearsSet = EquipmentHelper.wearsItemSet(this.equipedItems, itemSet); - if (wearsSet && equipmentBonus.meetsRequirements(this.client)) - { - if (equipmentBonus.getOperation() == EquipmentBonusConfig.Operation.MULTIPLY) - { - bonus += equipmentBonus.getBonus(this.combatMethod); - } - else if (equipmentBonus.getOperation() == EquipmentBonusConfig.Operation.ADD) - { - addList.add(equipmentBonus.getBonus(this.combatMethod)); - } - } - } - - maxhit *= bonus; - - maxhit = maxhit + addList.stream().reduce(0.0, Double::sum); - - return maxhit; - } - - public double getMaxHit() - { - BiFunction customFormula = this.getCustomFormula(); - if (customFormula != null) - { - return customFormula.apply(this.client, this); - } - - return this.calculate(); - } - - private BiFunction getCustomFormula() - { - for (CustomFormulaConfig customFormula : CustomFormulaConfig.values()) - { - if (this.combatMethod != customFormula.getRequiredCombatMethod()) - { - continue; - } - - boolean meetsRequirements = customFormula.getRequirements().stream().allMatch(requirement -> requirement.meetsRequirements(this.client)); - - if (meetsRequirements) - { - return customFormula.getCustomFormula(); - } - } - - return null; - } - - public abstract double calculate(); - - public void setBaseDamage(int baseDamage) - { - this.baseDamage = baseDamage; - } - - double getSkillStrength() - { - return Double.parseDouble(this.getSkillStrengthText(this.equipmentSkillPower().getText())); - } - - public enum CombatMethod - { - MELEE, - RANGE, - MAGIC - } -} +/* + * Copyright (c) 2019, Bartvollebregt + * 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.maxhit.calculators; + +import java.util.ArrayList; +import java.util.function.BiFunction; +import net.runelite.api.Client; +import net.runelite.api.Item; +import net.runelite.api.VarPlayer; +import net.runelite.api.Varbits; +import net.runelite.api.widgets.Widget; +import net.runelite.client.plugins.maxhit.attackstyle.AttackStyle; +import net.runelite.client.plugins.maxhit.attackstyle.WeaponType; +import net.runelite.client.plugins.maxhit.config.CustomFormulaConfig; +import net.runelite.client.plugins.maxhit.config.EquipmentBonusConfig; +import net.runelite.client.plugins.maxhit.config.PrayerBonusConfig; +import net.runelite.client.plugins.maxhit.equipment.EquipmentHelper; +import net.runelite.client.plugins.maxhit.equipment.EquipmentItemset; + +public abstract class MaxHitCalculator +{ + + final Client client; + private final CombatMethod combatMethod; + private final Item[] equipedItems; + int baseDamage = 0; + + MaxHitCalculator(Client client, CombatMethod combatMethod, Item[] equipedItems) + { + this.client = client; + this.combatMethod = combatMethod; + this.equipedItems = equipedItems; + } + + protected abstract String getSkillStrengthText(String equipmentText); + + abstract Widget equipmentSkillPower(); + + public abstract double getCurrentSkillPower(); + + AttackStyle getAttackStyle() + { + int equippedWeaponTypeId = client.getVar(Varbits.EQUIPPED_WEAPON_TYPE); + int attackStyleId = client.getVar(VarPlayer.ATTACK_STYLE); + + AttackStyle[] attackStyles = WeaponType.getWeaponType(equippedWeaponTypeId).getAttackStyles(); + + if (attackStyleId < attackStyles.length) + { + AttackStyle attackStyle = attackStyles[attackStyleId]; + if (attackStyle != null) + { + return attackStyle; + } + } + + return AttackStyle.OTHER; + } + + double getPrayerBonus() + { + double bonus = 1; + for (PrayerBonusConfig prayerBonus : PrayerBonusConfig.values()) + { + boolean prayerActive = client.getVar(prayerBonus.getPrayerVarbit()) == 1; + boolean sameCombatMethod = prayerBonus.getCombatMethod() == this.combatMethod; + if (prayerActive && sameCombatMethod) + { + bonus += prayerBonus.getStrengthBonus(); + } + } + return bonus; + } + + double applyEquipmentBonus(double maxhit, EquipmentBonusConfig.BonusType bonusType) + { + double bonus = 1; + ArrayList addList = new ArrayList<>(); + + ArrayList equipmentBonuses = EquipmentBonusConfig.getBonusByType(bonusType); + + for (EquipmentBonusConfig equipmentBonus : equipmentBonuses) + { + EquipmentItemset itemSet = equipmentBonus.getItemset(); + boolean wearsSet = EquipmentHelper.wearsItemSet(this.equipedItems, itemSet); + if (wearsSet && equipmentBonus.meetsRequirements(this.client)) + { + if (equipmentBonus.getOperation() == EquipmentBonusConfig.Operation.MULTIPLY) + { + bonus += equipmentBonus.getBonus(this.combatMethod); + } + else if (equipmentBonus.getOperation() == EquipmentBonusConfig.Operation.ADD) + { + addList.add(equipmentBonus.getBonus(this.combatMethod)); + } + } + } + + maxhit *= bonus; + + maxhit = maxhit + addList.stream().reduce(0.0, Double::sum); + + return maxhit; + } + + public double getMaxHit() + { + BiFunction customFormula = this.getCustomFormula(); + if (customFormula != null) + { + return customFormula.apply(this.client, this); + } + + return this.calculate(); + } + + private BiFunction getCustomFormula() + { + for (CustomFormulaConfig customFormula : CustomFormulaConfig.values()) + { + if (this.combatMethod != customFormula.getRequiredCombatMethod()) + { + continue; + } + + boolean meetsRequirements = customFormula.getRequirements().stream().allMatch(requirement -> requirement.meetsRequirements(this.client)); + + if (meetsRequirements) + { + return customFormula.getCustomFormula(); + } + } + + return null; + } + + public abstract double calculate(); + + public void setBaseDamage(int baseDamage) + { + this.baseDamage = baseDamage; + } + + double getSkillStrength() + { + return Double.parseDouble(this.getSkillStrengthText(this.equipmentSkillPower().getText())); + } + + public enum CombatMethod + { + MELEE, + RANGE, + MAGIC + } +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/maxhit/config/CustomFormulaConfig.java b/runelite-client/src/main/java/net/runelite/client/plugins/maxhit/config/CustomFormulaConfig.java index b050af543d..3e7ccaef47 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/maxhit/config/CustomFormulaConfig.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/maxhit/config/CustomFormulaConfig.java @@ -1,233 +1,232 @@ -/* - * Copyright (c) 2019, Bartvollebregt - * 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.maxhit.config; - -import net.runelite.api.Client; -import net.runelite.api.EquipmentInventorySlot; -import net.runelite.api.ItemID; -import net.runelite.api.Skill; -import net.runelite.client.plugins.maxhit.calculators.MaxHitCalculator; -import net.runelite.client.plugins.maxhit.equipment.EquipmentItemset; -import net.runelite.client.plugins.maxhit.equipment.EquipmentSlotItem; -import net.runelite.client.plugins.maxhit.requirements.EquipmentItemRequirement; -import net.runelite.client.plugins.maxhit.requirements.EquipmentItemSetRequirement; -import net.runelite.client.plugins.maxhit.requirements.Requirement; -import net.runelite.client.plugins.maxhit.requirements.SpellRequirement; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.function.BiFunction; - -public enum CustomFormulaConfig -{ - - MAGIC_DART( - MaxHitCalculator.CombatMethod.MAGIC, - new ArrayList<>(Arrays.asList( - new EquipmentItemRequirement(new EquipmentSlotItem(EquipmentInventorySlot.WEAPON, new ArrayList<>(Arrays.asList( - ItemID.SLAYERS_STAFF, - ItemID.SLAYERS_STAFF_E - )))), - new SpellRequirement(SpellBaseDamageConfig.MAGIC_DART) - )), - (client, calculator) -> - { - int magicLevel = client.getBoostedSkillLevel(Skill.MAGIC); - return Math.floor((magicLevel / 10.0) + 10.0); - } - ), - - TRIDENT_OF_SEAS( - MaxHitCalculator.CombatMethod.MAGIC, - new ArrayList<>(Collections.singletonList( - new EquipmentItemRequirement(new EquipmentSlotItem(EquipmentInventorySlot.WEAPON, new ArrayList<>(Arrays.asList( - ItemID.TRIDENT_OF_THE_SEAS_FULL, - ItemID.TRIDENT_OF_THE_SEAS, - ItemID.TRIDENT_OF_THE_SEAS_E - )))) - )), - (client, calculator) -> - { - int magicLevel = client.getBoostedSkillLevel(Skill.MAGIC); - - int baseDamage = (int) Math.floor(magicLevel / 3.0) - 5; - calculator.setBaseDamage(baseDamage); - - return calculator.calculate(); - } - ), - - TRIDENT_OF_SWAMP( - MaxHitCalculator.CombatMethod.MAGIC, - new ArrayList<>(Collections.singletonList( - new EquipmentItemRequirement(new EquipmentSlotItem(EquipmentInventorySlot.WEAPON, new ArrayList<>(Arrays.asList( - ItemID.TRIDENT_OF_THE_SWAMP, - ItemID.TRIDENT_OF_THE_SWAMP_E - )))) - )), - (client, calculator) -> - { - int magicLevel = client.getBoostedSkillLevel(Skill.MAGIC); - - int baseDamage = (int) Math.floor(magicLevel / 3.0) - 2; - calculator.setBaseDamage(baseDamage); - - return calculator.calculate(); - } - ), - - SWAMP_LIZARD( - MaxHitCalculator.CombatMethod.MAGIC, - new ArrayList<>(Collections.singletonList( - new EquipmentItemRequirement(new EquipmentSlotItem(EquipmentInventorySlot.WEAPON, new ArrayList<>(Collections.singletonList( - ItemID.SWAMP_LIZARD - )))) - )), - (client, calculator) -> - { - int magicLevel = client.getBoostedSkillLevel(Skill.MAGIC); - return Math.floor(0.5 + magicLevel * (64.0 + 56.0) / 640.0); - } - ), - - ORANGE_SALAMANDER( - MaxHitCalculator.CombatMethod.MAGIC, - new ArrayList<>(Collections.singletonList( - new EquipmentItemRequirement(new EquipmentSlotItem(EquipmentInventorySlot.WEAPON, new ArrayList<>(Collections.singletonList( - ItemID.ORANGE_SALAMANDER - )))) - )), - (client, calculator) -> - { - int magicLevel = client.getBoostedSkillLevel(Skill.MAGIC); - return Math.floor(0.5 + magicLevel * (64.0 + 59.0) / 640.0); - } - ), - - RED_SALAMANDER( - MaxHitCalculator.CombatMethod.MAGIC, - new ArrayList<>(Collections.singletonList( - new EquipmentItemRequirement(new EquipmentSlotItem(EquipmentInventorySlot.WEAPON, new ArrayList<>(Collections.singletonList( - ItemID.RED_SALAMANDER - )))) - )), - (client, calculator) -> - { - int magicLevel = client.getBoostedSkillLevel(Skill.MAGIC); - return Math.floor(0.5 + magicLevel * (64.0 + 77.0) / 640.0); - } - ), - - BLACK_SALAMANDER( - MaxHitCalculator.CombatMethod.MAGIC, - new ArrayList<>(Collections.singletonList( - new EquipmentItemRequirement(new EquipmentSlotItem(EquipmentInventorySlot.WEAPON, new ArrayList<>(Collections.singletonList( - ItemID.BLACK_SALAMANDER - )))) - )), - (client, calculator) -> - { - int magicLevel = client.getBoostedSkillLevel(Skill.MAGIC); - return Math.floor(0.5 + magicLevel * (64.0 + 92.0) / 640.0); - } - ), - - DHAROK( - MaxHitCalculator.CombatMethod.MELEE, - new ArrayList<>(Collections.singletonList(new EquipmentItemSetRequirement(new EquipmentItemset(Arrays.asList( - new EquipmentSlotItem(EquipmentInventorySlot.HEAD, new ArrayList<>(Arrays.asList( - ItemID.DHAROKS_HELM, - ItemID.DHAROKS_HELM_100, - ItemID.DHAROKS_HELM_75, - ItemID.DHAROKS_HELM_50, - ItemID.DHAROKS_HELM_25, - ItemID.DHAROKS_HELM_0 - ))), - new EquipmentSlotItem(EquipmentInventorySlot.BODY, new ArrayList<>(Arrays.asList( - ItemID.DHAROKS_PLATEBODY, - ItemID.DHAROKS_PLATEBODY_100, - ItemID.DHAROKS_PLATEBODY_75, - ItemID.DHAROKS_PLATEBODY_50, - ItemID.DHAROKS_PLATEBODY_25, - ItemID.DHAROKS_PLATEBODY_0 - ))), - new EquipmentSlotItem(EquipmentInventorySlot.LEGS, new ArrayList<>(Arrays.asList( - ItemID.DHAROKS_PLATELEGS, - ItemID.DHAROKS_PLATELEGS_100, - ItemID.DHAROKS_PLATELEGS_75, - ItemID.DHAROKS_PLATELEGS_50, - ItemID.DHAROKS_PLATELEGS_25, - ItemID.DHAROKS_PLATELEGS_0 - ))), - new EquipmentSlotItem(EquipmentInventorySlot.WEAPON, new ArrayList<>(Arrays.asList( - ItemID.DHAROKS_GREATAXE, - ItemID.DHAROKS_GREATAXE_100, - ItemID.DHAROKS_GREATAXE_75, - ItemID.DHAROKS_GREATAXE_50, - ItemID.DHAROKS_GREATAXE_25, - ItemID.DHAROKS_GREATAXE_0 - ))) - ))))), - (client, calculator) -> - { - int currentHP = client.getBoostedSkillLevel(Skill.HITPOINTS); - int maxHP = client.getRealSkillLevel(Skill.HITPOINTS); - int lostHP = maxHP - currentHP; - - double initialMaxHit = calculator.calculate(); - - double multiplier = (1.0 + ((lostHP / 100.0) * (maxHP / 100.0))); - - return Math.floor(initialMaxHit * multiplier); - } - ); - - private final MaxHitCalculator.CombatMethod requiredCombatMethod; - private final ArrayList requirements; - private final BiFunction customFormula; - - CustomFormulaConfig(MaxHitCalculator.CombatMethod requiredCombatMethod, ArrayList requirements, BiFunction customFormula) - { - this.requiredCombatMethod = requiredCombatMethod; - this.requirements = requirements; - this.customFormula = customFormula; - } - - public MaxHitCalculator.CombatMethod getRequiredCombatMethod() - { - return requiredCombatMethod; - } - - public BiFunction getCustomFormula() - { - return customFormula; - } - - public ArrayList getRequirements() - { - return this.requirements; - } -} +/* + * Copyright (c) 2019, Bartvollebregt + * 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.maxhit.config; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.function.BiFunction; +import net.runelite.api.Client; +import net.runelite.api.EquipmentInventorySlot; +import net.runelite.api.ItemID; +import net.runelite.api.Skill; +import net.runelite.client.plugins.maxhit.calculators.MaxHitCalculator; +import net.runelite.client.plugins.maxhit.equipment.EquipmentItemset; +import net.runelite.client.plugins.maxhit.equipment.EquipmentSlotItem; +import net.runelite.client.plugins.maxhit.requirements.EquipmentItemRequirement; +import net.runelite.client.plugins.maxhit.requirements.EquipmentItemSetRequirement; +import net.runelite.client.plugins.maxhit.requirements.Requirement; +import net.runelite.client.plugins.maxhit.requirements.SpellRequirement; + +public enum CustomFormulaConfig +{ + + MAGIC_DART( + MaxHitCalculator.CombatMethod.MAGIC, + new ArrayList<>(Arrays.asList( + new EquipmentItemRequirement(new EquipmentSlotItem(EquipmentInventorySlot.WEAPON, new ArrayList<>(Arrays.asList( + ItemID.SLAYERS_STAFF, + ItemID.SLAYERS_STAFF_E + )))), + new SpellRequirement(SpellBaseDamageConfig.MAGIC_DART) + )), + (client, calculator) -> + { + int magicLevel = client.getBoostedSkillLevel(Skill.MAGIC); + return Math.floor((magicLevel / 10.0) + 10.0); + } + ), + + TRIDENT_OF_SEAS( + MaxHitCalculator.CombatMethod.MAGIC, + new ArrayList<>(Collections.singletonList( + new EquipmentItemRequirement(new EquipmentSlotItem(EquipmentInventorySlot.WEAPON, new ArrayList<>(Arrays.asList( + ItemID.TRIDENT_OF_THE_SEAS_FULL, + ItemID.TRIDENT_OF_THE_SEAS, + ItemID.TRIDENT_OF_THE_SEAS_E + )))) + )), + (client, calculator) -> + { + int magicLevel = client.getBoostedSkillLevel(Skill.MAGIC); + + int baseDamage = (int) Math.floor(magicLevel / 3.0) - 5; + calculator.setBaseDamage(baseDamage); + + return calculator.calculate(); + } + ), + + TRIDENT_OF_SWAMP( + MaxHitCalculator.CombatMethod.MAGIC, + new ArrayList<>(Collections.singletonList( + new EquipmentItemRequirement(new EquipmentSlotItem(EquipmentInventorySlot.WEAPON, new ArrayList<>(Arrays.asList( + ItemID.TRIDENT_OF_THE_SWAMP, + ItemID.TRIDENT_OF_THE_SWAMP_E + )))) + )), + (client, calculator) -> + { + int magicLevel = client.getBoostedSkillLevel(Skill.MAGIC); + + int baseDamage = (int) Math.floor(magicLevel / 3.0) - 2; + calculator.setBaseDamage(baseDamage); + + return calculator.calculate(); + } + ), + + SWAMP_LIZARD( + MaxHitCalculator.CombatMethod.MAGIC, + new ArrayList<>(Collections.singletonList( + new EquipmentItemRequirement(new EquipmentSlotItem(EquipmentInventorySlot.WEAPON, new ArrayList<>(Collections.singletonList( + ItemID.SWAMP_LIZARD + )))) + )), + (client, calculator) -> + { + int magicLevel = client.getBoostedSkillLevel(Skill.MAGIC); + return Math.floor(0.5 + magicLevel * (64.0 + 56.0) / 640.0); + } + ), + + ORANGE_SALAMANDER( + MaxHitCalculator.CombatMethod.MAGIC, + new ArrayList<>(Collections.singletonList( + new EquipmentItemRequirement(new EquipmentSlotItem(EquipmentInventorySlot.WEAPON, new ArrayList<>(Collections.singletonList( + ItemID.ORANGE_SALAMANDER + )))) + )), + (client, calculator) -> + { + int magicLevel = client.getBoostedSkillLevel(Skill.MAGIC); + return Math.floor(0.5 + magicLevel * (64.0 + 59.0) / 640.0); + } + ), + + RED_SALAMANDER( + MaxHitCalculator.CombatMethod.MAGIC, + new ArrayList<>(Collections.singletonList( + new EquipmentItemRequirement(new EquipmentSlotItem(EquipmentInventorySlot.WEAPON, new ArrayList<>(Collections.singletonList( + ItemID.RED_SALAMANDER + )))) + )), + (client, calculator) -> + { + int magicLevel = client.getBoostedSkillLevel(Skill.MAGIC); + return Math.floor(0.5 + magicLevel * (64.0 + 77.0) / 640.0); + } + ), + + BLACK_SALAMANDER( + MaxHitCalculator.CombatMethod.MAGIC, + new ArrayList<>(Collections.singletonList( + new EquipmentItemRequirement(new EquipmentSlotItem(EquipmentInventorySlot.WEAPON, new ArrayList<>(Collections.singletonList( + ItemID.BLACK_SALAMANDER + )))) + )), + (client, calculator) -> + { + int magicLevel = client.getBoostedSkillLevel(Skill.MAGIC); + return Math.floor(0.5 + magicLevel * (64.0 + 92.0) / 640.0); + } + ), + + DHAROK( + MaxHitCalculator.CombatMethod.MELEE, + new ArrayList<>(Collections.singletonList(new EquipmentItemSetRequirement(new EquipmentItemset(Arrays.asList( + new EquipmentSlotItem(EquipmentInventorySlot.HEAD, new ArrayList<>(Arrays.asList( + ItemID.DHAROKS_HELM, + ItemID.DHAROKS_HELM_100, + ItemID.DHAROKS_HELM_75, + ItemID.DHAROKS_HELM_50, + ItemID.DHAROKS_HELM_25, + ItemID.DHAROKS_HELM_0 + ))), + new EquipmentSlotItem(EquipmentInventorySlot.BODY, new ArrayList<>(Arrays.asList( + ItemID.DHAROKS_PLATEBODY, + ItemID.DHAROKS_PLATEBODY_100, + ItemID.DHAROKS_PLATEBODY_75, + ItemID.DHAROKS_PLATEBODY_50, + ItemID.DHAROKS_PLATEBODY_25, + ItemID.DHAROKS_PLATEBODY_0 + ))), + new EquipmentSlotItem(EquipmentInventorySlot.LEGS, new ArrayList<>(Arrays.asList( + ItemID.DHAROKS_PLATELEGS, + ItemID.DHAROKS_PLATELEGS_100, + ItemID.DHAROKS_PLATELEGS_75, + ItemID.DHAROKS_PLATELEGS_50, + ItemID.DHAROKS_PLATELEGS_25, + ItemID.DHAROKS_PLATELEGS_0 + ))), + new EquipmentSlotItem(EquipmentInventorySlot.WEAPON, new ArrayList<>(Arrays.asList( + ItemID.DHAROKS_GREATAXE, + ItemID.DHAROKS_GREATAXE_100, + ItemID.DHAROKS_GREATAXE_75, + ItemID.DHAROKS_GREATAXE_50, + ItemID.DHAROKS_GREATAXE_25, + ItemID.DHAROKS_GREATAXE_0 + ))) + ))))), + (client, calculator) -> + { + int currentHP = client.getBoostedSkillLevel(Skill.HITPOINTS); + int maxHP = client.getRealSkillLevel(Skill.HITPOINTS); + int lostHP = maxHP - currentHP; + + double initialMaxHit = calculator.calculate(); + + double multiplier = (1.0 + ((lostHP / 100.0) * (maxHP / 100.0))); + + return Math.floor(initialMaxHit * multiplier); + } + ); + + private final MaxHitCalculator.CombatMethod requiredCombatMethod; + private final ArrayList requirements; + private final BiFunction customFormula; + + CustomFormulaConfig(MaxHitCalculator.CombatMethod requiredCombatMethod, ArrayList requirements, BiFunction customFormula) + { + this.requiredCombatMethod = requiredCombatMethod; + this.requirements = requirements; + this.customFormula = customFormula; + } + + public MaxHitCalculator.CombatMethod getRequiredCombatMethod() + { + return requiredCombatMethod; + } + + public BiFunction getCustomFormula() + { + return customFormula; + } + + public ArrayList getRequirements() + { + return this.requirements; + } +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/maxhit/config/EquipmentBonusConfig.java b/runelite-client/src/main/java/net/runelite/client/plugins/maxhit/config/EquipmentBonusConfig.java index fce5816c64..dd3bd31268 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/maxhit/config/EquipmentBonusConfig.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/maxhit/config/EquipmentBonusConfig.java @@ -1,418 +1,424 @@ -/* - * Copyright (c) 2019, Bartvollebregt - * 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.maxhit.config; - -import net.runelite.api.Client; -import net.runelite.api.EquipmentInventorySlot; -import net.runelite.api.ItemID; -import net.runelite.client.plugins.maxhit.calculators.MaxHitCalculator; -import net.runelite.client.plugins.maxhit.equipment.EquipmentCombatBonus; -import net.runelite.client.plugins.maxhit.equipment.EquipmentItemset; -import net.runelite.client.plugins.maxhit.equipment.EquipmentSlotItem; -import net.runelite.client.plugins.maxhit.requirements.AutocastSpellRequirement; -import net.runelite.client.plugins.maxhit.requirements.Requirement; -import net.runelite.client.plugins.maxhit.requirements.SpellBookRequirement; - -import java.util.*; - - -public enum EquipmentBonusConfig -{ - - /* - * Slayer bonus items - */ - BLACKMASK(BonusType.SLAYER, new EquipmentItemset(Collections.singletonList( - new EquipmentSlotItem(EquipmentInventorySlot.HEAD, new ArrayList<>(Arrays.asList( - ItemID.BLACK_MASK_10, - ItemID.BLACK_MASK_9, - ItemID.BLACK_MASK_8, - ItemID.BLACK_MASK_7, - ItemID.BLACK_MASK_6, - ItemID.BLACK_MASK_5, - ItemID.BLACK_MASK_4, - ItemID.BLACK_MASK_3, - ItemID.BLACK_MASK_2, - ItemID.BLACK_MASK_1, - ItemID.BLACK_MASK - ))) - )), new EquipmentCombatBonus(((7.0 / 6.0) - 1), 0, 0)), - - SLAYERHELM(BonusType.SLAYER, new EquipmentItemset(Collections.singletonList( - new EquipmentSlotItem(EquipmentInventorySlot.HEAD, new ArrayList<>(Arrays.asList( - ItemID.SLAYER_HELMET, - ItemID.BLACK_SLAYER_HELMET, - ItemID.GREEN_SLAYER_HELMET, - ItemID.RED_SLAYER_HELMET, - ItemID.PURPLE_SLAYER_HELMET, - ItemID.TURQUOISE_SLAYER_HELMET, - ItemID.HYDRA_SLAYER_HELMET - ))) - )), new EquipmentCombatBonus(((7.0 / 6.0) - 1), 0, 0)), - - BLACKMASKI(BonusType.SLAYER, new EquipmentItemset(Collections.singletonList( - new EquipmentSlotItem(EquipmentInventorySlot.HEAD, new ArrayList<>(Arrays.asList( - ItemID.BLACK_MASK_10_I, - ItemID.BLACK_MASK_9_I, - ItemID.BLACK_MASK_8_I, - ItemID.BLACK_MASK_7_I, - ItemID.BLACK_MASK_6_I, - ItemID.BLACK_MASK_5_I, - ItemID.BLACK_MASK_4_I, - ItemID.BLACK_MASK_3_I, - ItemID.BLACK_MASK_2_I, - ItemID.BLACK_MASK_1_I, - ItemID.BLACK_MASK_I - ))) - )), new EquipmentCombatBonus(((7.0 / 6.0) - 1), 0.15, 0.15)), - - SLAYERHELMI(BonusType.SLAYER, new EquipmentItemset(Collections.singletonList( - new EquipmentSlotItem(EquipmentInventorySlot.HEAD, new ArrayList<>(Arrays.asList( - ItemID.SLAYER_HELMET_I, - ItemID.BLACK_SLAYER_HELMET_I, - ItemID.GREEN_SLAYER_HELMET_I, - ItemID.RED_SLAYER_HELMET_I, - ItemID.PURPLE_SLAYER_HELMET_I, - ItemID.TURQUOISE_SLAYER_HELMET_I, - ItemID.HYDRA_SLAYER_HELMET_I - ))) - )), new EquipmentCombatBonus(((7.0 / 6.0) - 1), 0.15, 0.15)), - - /* - * Void bonus items - * */ - MELEEVOID(BonusType.VOID_KNIGHT, new EquipmentItemset(Arrays.asList( - new EquipmentSlotItem(EquipmentInventorySlot.HEAD, new ArrayList<>(Arrays.asList( - ItemID.VOID_MELEE_HELM, - ItemID.VOID_MELEE_HELM_11676 - ))), - new EquipmentSlotItem(EquipmentInventorySlot.BODY, new ArrayList<>(Arrays.asList( - ItemID.VOID_KNIGHT_TOP, - ItemID.VOID_KNIGHT_TOP_10611 - ))), - new EquipmentSlotItem(EquipmentInventorySlot.LEGS, new ArrayList<>(Collections.singletonList( - ItemID.VOID_KNIGHT_ROBE - ))), - new EquipmentSlotItem(EquipmentInventorySlot.GLOVES, new ArrayList<>(Collections.singletonList( - ItemID.VOID_KNIGHT_GLOVES - ))) - )), new EquipmentCombatBonus(0.1, 0, 0)), - - RANGERVOID(BonusType.VOID_KNIGHT, new EquipmentItemset(Arrays.asList( - new EquipmentSlotItem(EquipmentInventorySlot.HEAD, new ArrayList<>(Arrays.asList( - ItemID.VOID_RANGER_HELM, - ItemID.VOID_RANGER_HELM_11675 - ))), - new EquipmentSlotItem(EquipmentInventorySlot.BODY, new ArrayList<>(Arrays.asList( - ItemID.VOID_KNIGHT_TOP, - ItemID.VOID_KNIGHT_TOP_10611 - ))), - new EquipmentSlotItem(EquipmentInventorySlot.LEGS, new ArrayList<>(Collections.singletonList( - ItemID.VOID_KNIGHT_ROBE - ))), - new EquipmentSlotItem(EquipmentInventorySlot.GLOVES, new ArrayList<>(Collections.singletonList( - ItemID.VOID_KNIGHT_GLOVES - ))) - )), new EquipmentCombatBonus(0, 0.1, 0)), - - - ELITEMELEERVOID(BonusType.VOID_KNIGHT, new EquipmentItemset(Arrays.asList( - new EquipmentSlotItem(EquipmentInventorySlot.HEAD, new ArrayList<>(Arrays.asList( - ItemID.VOID_MELEE_HELM, - ItemID.VOID_MELEE_HELM_11676 - ))), - new EquipmentSlotItem(EquipmentInventorySlot.BODY, new ArrayList<>(Collections.singletonList( - ItemID.ELITE_VOID_TOP - ))), - new EquipmentSlotItem(EquipmentInventorySlot.LEGS, new ArrayList<>(Collections.singletonList( - ItemID.ELITE_VOID_ROBE - ))), - new EquipmentSlotItem(EquipmentInventorySlot.GLOVES, new ArrayList<>(Collections.singletonList( - ItemID.VOID_KNIGHT_GLOVES - ))) - )), new EquipmentCombatBonus(0.125, 0, 0)), - - - ELITERANGERVOID(BonusType.VOID_KNIGHT, new EquipmentItemset(Arrays.asList( - new EquipmentSlotItem(EquipmentInventorySlot.HEAD, new ArrayList<>(Arrays.asList( - ItemID.VOID_RANGER_HELM, - ItemID.VOID_RANGER_HELM_11675 - ))), - new EquipmentSlotItem(EquipmentInventorySlot.BODY, new ArrayList<>(Collections.singletonList( - ItemID.ELITE_VOID_TOP - ))), - new EquipmentSlotItem(EquipmentInventorySlot.LEGS, new ArrayList<>(Collections.singletonList( - ItemID.ELITE_VOID_ROBE - ))), - new EquipmentSlotItem(EquipmentInventorySlot.GLOVES, new ArrayList<>(Collections.singletonList( - ItemID.VOID_KNIGHT_GLOVES - ))) - )), new EquipmentCombatBonus(0, 0.125, 0)), - - ELITEMAGICVOID(BonusType.EQUIPMENT, new EquipmentItemset(Arrays.asList( - new EquipmentSlotItem(EquipmentInventorySlot.HEAD, new ArrayList<>(Arrays.asList( - ItemID.VOID_MAGE_HELM, - ItemID.VOID_MAGE_HELM_11674 - ))), - new EquipmentSlotItem(EquipmentInventorySlot.BODY, new ArrayList<>(Collections.singletonList( - ItemID.ELITE_VOID_TOP - ))), - new EquipmentSlotItem(EquipmentInventorySlot.LEGS, new ArrayList<>(Collections.singletonList( - ItemID.ELITE_VOID_ROBE - ))), - new EquipmentSlotItem(EquipmentInventorySlot.GLOVES, new ArrayList<>(Collections.singletonList( - ItemID.VOID_KNIGHT_GLOVES - ))) - )), new EquipmentCombatBonus(0, 0, 0.025)), - - /* - * Special Melee Equipment - * */ - OBISIDIAN(BonusType.SPECIAL, new EquipmentItemset(Arrays.asList( - new EquipmentSlotItem(EquipmentInventorySlot.HEAD, new ArrayList<>(Collections.singletonList( - ItemID.OBSIDIAN_HELMET - ))), - new EquipmentSlotItem(EquipmentInventorySlot.BODY, new ArrayList<>(Collections.singletonList( - ItemID.OBSIDIAN_PLATEBODY - ))), - new EquipmentSlotItem(EquipmentInventorySlot.LEGS, new ArrayList<>(Collections.singletonList( - ItemID.OBSIDIAN_PLATELEGS - ))), - new EquipmentSlotItem(EquipmentInventorySlot.WEAPON, new ArrayList<>(Arrays.asList( - ItemID.TOKTZXILAK, - ItemID.TOKTZXILEK, - ItemID.TZHAARKETEM, - ItemID.TZHAARKETOM, - ItemID.TOKTZXILAK_20554 - ))) - )), new EquipmentCombatBonus(0.1, 0, 0)), - - BERSERKERNECKLACE(BonusType.SPECIAL, new EquipmentItemset(Arrays.asList( - new EquipmentSlotItem(EquipmentInventorySlot.AMULET, new ArrayList<>(Collections.singletonList(ItemID.BERSERKER_NECKLACE))), - new EquipmentSlotItem(EquipmentInventorySlot.WEAPON, new ArrayList<>(Arrays.asList( - ItemID.TOKTZXILAK, - ItemID.TOKTZXILEK, - ItemID.TZHAARKETEM, - ItemID.TZHAARKETOM, - ItemID.TOKTZXILAK_20554 - ))) - )), new EquipmentCombatBonus(0.2, 0, 0)), - - - /* - * Magic Equipment - */ - ANCESTRAL_HAT(BonusType.EQUIPMENT, new EquipmentItemset(Collections.singletonList( - new EquipmentSlotItem(EquipmentInventorySlot.HEAD, new ArrayList<>(Collections.singletonList( - ItemID.ANCESTRAL_HAT - ))) - )), new EquipmentCombatBonus(0, 0, 0.02)), - - ANCESTRAL_ROBE_TOP(BonusType.EQUIPMENT, new EquipmentItemset(Collections.singletonList( - new EquipmentSlotItem(EquipmentInventorySlot.BODY, new ArrayList<>(Collections.singletonList( - ItemID.ANCESTRAL_ROBE_TOP - ))) - )), new EquipmentCombatBonus(0, 0, 0.02)), - - ANCESTRAL_ROBE_BOTTOM(BonusType.EQUIPMENT, new EquipmentItemset(Collections.singletonList( - new EquipmentSlotItem(EquipmentInventorySlot.LEGS, new ArrayList<>(Collections.singletonList( - ItemID.ANCESTRAL_ROBE_BOTTOM - ))) - )), new EquipmentCombatBonus(0, 0, 0.02)), - - IMBUED_GOD_CAPE(BonusType.EQUIPMENT, new EquipmentItemset(Collections.singletonList( - new EquipmentSlotItem(EquipmentInventorySlot.CAPE, new ArrayList<>(Arrays.asList( - ItemID.IMBUED_SARADOMIN_MAX_CAPE, - ItemID.IMBUED_SARADOMIN_CAPE, - ItemID.IMBUED_ZAMORAK_MAX_CAPE, - ItemID.IMBUED_ZAMORAK_CAPE, - ItemID.IMBUED_GUTHIX_MAX_CAPE, - ItemID.IMBUED_GUTHIX_CAPE - ))) - )), new EquipmentCombatBonus(0, 0, 0.02)), - - KODAI_WAND(BonusType.EQUIPMENT, new EquipmentItemset(Collections.singletonList( - new EquipmentSlotItem(EquipmentInventorySlot.WEAPON, new ArrayList<>(Collections.singletonList( - ItemID.KODAI_WAND - ))) - )), new EquipmentCombatBonus(0, 0, 0.15)), - - OCCULT_NECKLACE(BonusType.EQUIPMENT, new EquipmentItemset(Collections.singletonList( - new EquipmentSlotItem(EquipmentInventorySlot.AMULET, new ArrayList<>(Arrays.asList( - ItemID.OCCULT_NECKLACE, - ItemID.OCCULT_NECKLACE_OR - ))) - )), new EquipmentCombatBonus(0, 0, 0.10)), - - STAFF_OF_THE_DEAD(BonusType.EQUIPMENT, new EquipmentItemset(Collections.singletonList( - new EquipmentSlotItem(EquipmentInventorySlot.WEAPON, new ArrayList<>(Arrays.asList( - ItemID.STAFF_OF_THE_DEAD, - ItemID.TOXIC_STAFF_OF_THE_DEAD, - ItemID.STAFF_OF_LIGHT - ))) - )), new EquipmentCombatBonus(0, 0, 0.15)), - - TORMENTED_BRACELET(BonusType.EQUIPMENT, new EquipmentItemset(Collections.singletonList( - new EquipmentSlotItem(EquipmentInventorySlot.GLOVES, new ArrayList<>(Collections.singletonList( - ItemID.TORMENTED_BRACELET - ))) - )), new EquipmentCombatBonus(0, 0, 0.05)), - - SMOKE_STAFF(BonusType.EQUIPMENT, new EquipmentItemset(Collections.singletonList( - new EquipmentSlotItem(EquipmentInventorySlot.WEAPON, new ArrayList<>(Arrays.asList( - ItemID.SMOKE_BATTLESTAFF, - ItemID.MYSTIC_SMOKE_STAFF - ))) - )), new EquipmentCombatBonus(0, 0, 0.10), Collections.singletonList(new SpellBookRequirement(SpellBaseDamageConfig.SpellBook.NORMAL))), - - - /* - * Special magic bonusses - * */ - - CHAOS_GAUNTLETS(BonusType.SPECIAL, new EquipmentItemset(Collections.singletonList( - new EquipmentSlotItem(EquipmentInventorySlot.GLOVES, new ArrayList<>(Collections.singletonList( - ItemID.CHAOS_GAUNTLETS - ))))), - new EquipmentCombatBonus(0, 0, 3), - Collections.singletonList( - new AutocastSpellRequirement(new ArrayList<>(Arrays.asList( - SpellBaseDamageConfig.AIR_BOLT, - SpellBaseDamageConfig.WATER_BOLT, - SpellBaseDamageConfig.EARTH_BOLT, - SpellBaseDamageConfig.FIRE_BOLT - ))) - ), - Operation.ADD - ), - - TOME_OF_FIRE(BonusType.MAGIC_SPECIAL, new EquipmentItemset(Collections.singletonList( - new EquipmentSlotItem(EquipmentInventorySlot.SHIELD, new ArrayList<>(Collections.singletonList( - ItemID.TOME_OF_FIRE - ))))), - new EquipmentCombatBonus(0, 0, 0.5), - Collections.singletonList( - new AutocastSpellRequirement(new ArrayList<>(Arrays.asList( - SpellBaseDamageConfig.FIRE_BLAST, - SpellBaseDamageConfig.FIRE_BOLT, - SpellBaseDamageConfig.FIRE_STRIKE, - SpellBaseDamageConfig.FIRE_SURGE, - SpellBaseDamageConfig.FIRE_WAVE - ))) - ) - ); - - - private static final Map> bonusTypes = new HashMap<>(); - - static - { - for (EquipmentBonusConfig equipmentBonus : values()) - { - BonusType bonusType = equipmentBonus.bonusType; - if (!bonusTypes.containsKey(bonusType)) - { - bonusTypes.put(bonusType, new ArrayList<>()); - } - ArrayList list = bonusTypes.get(bonusType); - list.add(equipmentBonus); - bonusTypes.put(bonusType, list); - } - } - - private final EquipmentItemset itemset; - private BonusType bonusType; - private EquipmentCombatBonus equipmentCombatBonus; - private List requirements = new ArrayList<>(); - private Operation operation = Operation.MULTIPLY; - EquipmentBonusConfig(BonusType bonusType, EquipmentItemset itemset, EquipmentCombatBonus equipmentCombatBonus) - { - this.bonusType = bonusType; - this.itemset = itemset; - this.equipmentCombatBonus = equipmentCombatBonus; - } - EquipmentBonusConfig(BonusType bonusType, EquipmentItemset itemset, EquipmentCombatBonus equipmentCombatBonus, List requirements) - { - this.bonusType = bonusType; - this.itemset = itemset; - this.equipmentCombatBonus = equipmentCombatBonus; - this.requirements = requirements; - } - - EquipmentBonusConfig(BonusType bonusType, EquipmentItemset itemset, EquipmentCombatBonus equipmentCombatBonus, List requirements, Operation operation) - { - this.bonusType = bonusType; - this.itemset = itemset; - this.equipmentCombatBonus = equipmentCombatBonus; - this.requirements = requirements; - this.operation = operation; - } - - public static ArrayList getBonusByType(BonusType bonusType) - { - if (!bonusTypes.containsKey(bonusType)) - { - return new ArrayList<>(); - } - return bonusTypes.get(bonusType); - } - - public EquipmentItemset getItemset() - { - return itemset; - } - - public Operation getOperation() - { - return operation; - } - - public double getBonus(MaxHitCalculator.CombatMethod combatMethod) - { - return this.equipmentCombatBonus.getCombatBonus(combatMethod); - } - - public boolean meetsRequirements(Client client) - { - return requirements.stream().allMatch(requirement -> requirement.meetsRequirements(client)); - } - - public enum BonusType - { - EQUIPMENT, - SLAYER, - VOID_KNIGHT, - SPECIAL, - MAGIC_SPECIAL - } - - public enum Operation - { - ADD, - MULTIPLY - } - -} - +/* + * Copyright (c) 2019, Bartvollebregt + * 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.maxhit.config; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import net.runelite.api.Client; +import net.runelite.api.EquipmentInventorySlot; +import net.runelite.api.ItemID; +import net.runelite.client.plugins.maxhit.calculators.MaxHitCalculator; +import net.runelite.client.plugins.maxhit.equipment.EquipmentCombatBonus; +import net.runelite.client.plugins.maxhit.equipment.EquipmentItemset; +import net.runelite.client.plugins.maxhit.equipment.EquipmentSlotItem; +import net.runelite.client.plugins.maxhit.requirements.AutocastSpellRequirement; +import net.runelite.client.plugins.maxhit.requirements.Requirement; +import net.runelite.client.plugins.maxhit.requirements.SpellBookRequirement; + + +public enum EquipmentBonusConfig +{ + + /* + * Slayer bonus items + */ + BLACKMASK(BonusType.SLAYER, new EquipmentItemset(Collections.singletonList( + new EquipmentSlotItem(EquipmentInventorySlot.HEAD, new ArrayList<>(Arrays.asList( + ItemID.BLACK_MASK_10, + ItemID.BLACK_MASK_9, + ItemID.BLACK_MASK_8, + ItemID.BLACK_MASK_7, + ItemID.BLACK_MASK_6, + ItemID.BLACK_MASK_5, + ItemID.BLACK_MASK_4, + ItemID.BLACK_MASK_3, + ItemID.BLACK_MASK_2, + ItemID.BLACK_MASK_1, + ItemID.BLACK_MASK + ))) + )), new EquipmentCombatBonus(((7.0 / 6.0) - 1), 0, 0)), + + SLAYERHELM(BonusType.SLAYER, new EquipmentItemset(Collections.singletonList( + new EquipmentSlotItem(EquipmentInventorySlot.HEAD, new ArrayList<>(Arrays.asList( + ItemID.SLAYER_HELMET, + ItemID.BLACK_SLAYER_HELMET, + ItemID.GREEN_SLAYER_HELMET, + ItemID.RED_SLAYER_HELMET, + ItemID.PURPLE_SLAYER_HELMET, + ItemID.TURQUOISE_SLAYER_HELMET, + ItemID.HYDRA_SLAYER_HELMET + ))) + )), new EquipmentCombatBonus(((7.0 / 6.0) - 1), 0, 0)), + + BLACKMASKI(BonusType.SLAYER, new EquipmentItemset(Collections.singletonList( + new EquipmentSlotItem(EquipmentInventorySlot.HEAD, new ArrayList<>(Arrays.asList( + ItemID.BLACK_MASK_10_I, + ItemID.BLACK_MASK_9_I, + ItemID.BLACK_MASK_8_I, + ItemID.BLACK_MASK_7_I, + ItemID.BLACK_MASK_6_I, + ItemID.BLACK_MASK_5_I, + ItemID.BLACK_MASK_4_I, + ItemID.BLACK_MASK_3_I, + ItemID.BLACK_MASK_2_I, + ItemID.BLACK_MASK_1_I, + ItemID.BLACK_MASK_I + ))) + )), new EquipmentCombatBonus(((7.0 / 6.0) - 1), 0.15, 0.15)), + + SLAYERHELMI(BonusType.SLAYER, new EquipmentItemset(Collections.singletonList( + new EquipmentSlotItem(EquipmentInventorySlot.HEAD, new ArrayList<>(Arrays.asList( + ItemID.SLAYER_HELMET_I, + ItemID.BLACK_SLAYER_HELMET_I, + ItemID.GREEN_SLAYER_HELMET_I, + ItemID.RED_SLAYER_HELMET_I, + ItemID.PURPLE_SLAYER_HELMET_I, + ItemID.TURQUOISE_SLAYER_HELMET_I, + ItemID.HYDRA_SLAYER_HELMET_I + ))) + )), new EquipmentCombatBonus(((7.0 / 6.0) - 1), 0.15, 0.15)), + + /* + * Void bonus items + * */ + MELEEVOID(BonusType.VOID_KNIGHT, new EquipmentItemset(Arrays.asList( + new EquipmentSlotItem(EquipmentInventorySlot.HEAD, new ArrayList<>(Arrays.asList( + ItemID.VOID_MELEE_HELM, + ItemID.VOID_MELEE_HELM_11676 + ))), + new EquipmentSlotItem(EquipmentInventorySlot.BODY, new ArrayList<>(Arrays.asList( + ItemID.VOID_KNIGHT_TOP, + ItemID.VOID_KNIGHT_TOP_10611 + ))), + new EquipmentSlotItem(EquipmentInventorySlot.LEGS, new ArrayList<>(Collections.singletonList( + ItemID.VOID_KNIGHT_ROBE + ))), + new EquipmentSlotItem(EquipmentInventorySlot.GLOVES, new ArrayList<>(Collections.singletonList( + ItemID.VOID_KNIGHT_GLOVES + ))) + )), new EquipmentCombatBonus(0.1, 0, 0)), + + RANGERVOID(BonusType.VOID_KNIGHT, new EquipmentItemset(Arrays.asList( + new EquipmentSlotItem(EquipmentInventorySlot.HEAD, new ArrayList<>(Arrays.asList( + ItemID.VOID_RANGER_HELM, + ItemID.VOID_RANGER_HELM_11675 + ))), + new EquipmentSlotItem(EquipmentInventorySlot.BODY, new ArrayList<>(Arrays.asList( + ItemID.VOID_KNIGHT_TOP, + ItemID.VOID_KNIGHT_TOP_10611 + ))), + new EquipmentSlotItem(EquipmentInventorySlot.LEGS, new ArrayList<>(Collections.singletonList( + ItemID.VOID_KNIGHT_ROBE + ))), + new EquipmentSlotItem(EquipmentInventorySlot.GLOVES, new ArrayList<>(Collections.singletonList( + ItemID.VOID_KNIGHT_GLOVES + ))) + )), new EquipmentCombatBonus(0, 0.1, 0)), + + + ELITEMELEERVOID(BonusType.VOID_KNIGHT, new EquipmentItemset(Arrays.asList( + new EquipmentSlotItem(EquipmentInventorySlot.HEAD, new ArrayList<>(Arrays.asList( + ItemID.VOID_MELEE_HELM, + ItemID.VOID_MELEE_HELM_11676 + ))), + new EquipmentSlotItem(EquipmentInventorySlot.BODY, new ArrayList<>(Collections.singletonList( + ItemID.ELITE_VOID_TOP + ))), + new EquipmentSlotItem(EquipmentInventorySlot.LEGS, new ArrayList<>(Collections.singletonList( + ItemID.ELITE_VOID_ROBE + ))), + new EquipmentSlotItem(EquipmentInventorySlot.GLOVES, new ArrayList<>(Collections.singletonList( + ItemID.VOID_KNIGHT_GLOVES + ))) + )), new EquipmentCombatBonus(0.125, 0, 0)), + + + ELITERANGERVOID(BonusType.VOID_KNIGHT, new EquipmentItemset(Arrays.asList( + new EquipmentSlotItem(EquipmentInventorySlot.HEAD, new ArrayList<>(Arrays.asList( + ItemID.VOID_RANGER_HELM, + ItemID.VOID_RANGER_HELM_11675 + ))), + new EquipmentSlotItem(EquipmentInventorySlot.BODY, new ArrayList<>(Collections.singletonList( + ItemID.ELITE_VOID_TOP + ))), + new EquipmentSlotItem(EquipmentInventorySlot.LEGS, new ArrayList<>(Collections.singletonList( + ItemID.ELITE_VOID_ROBE + ))), + new EquipmentSlotItem(EquipmentInventorySlot.GLOVES, new ArrayList<>(Collections.singletonList( + ItemID.VOID_KNIGHT_GLOVES + ))) + )), new EquipmentCombatBonus(0, 0.125, 0)), + + ELITEMAGICVOID(BonusType.EQUIPMENT, new EquipmentItemset(Arrays.asList( + new EquipmentSlotItem(EquipmentInventorySlot.HEAD, new ArrayList<>(Arrays.asList( + ItemID.VOID_MAGE_HELM, + ItemID.VOID_MAGE_HELM_11674 + ))), + new EquipmentSlotItem(EquipmentInventorySlot.BODY, new ArrayList<>(Collections.singletonList( + ItemID.ELITE_VOID_TOP + ))), + new EquipmentSlotItem(EquipmentInventorySlot.LEGS, new ArrayList<>(Collections.singletonList( + ItemID.ELITE_VOID_ROBE + ))), + new EquipmentSlotItem(EquipmentInventorySlot.GLOVES, new ArrayList<>(Collections.singletonList( + ItemID.VOID_KNIGHT_GLOVES + ))) + )), new EquipmentCombatBonus(0, 0, 0.025)), + + /* + * Special Melee Equipment + * */ + OBISIDIAN(BonusType.SPECIAL, new EquipmentItemset(Arrays.asList( + new EquipmentSlotItem(EquipmentInventorySlot.HEAD, new ArrayList<>(Collections.singletonList( + ItemID.OBSIDIAN_HELMET + ))), + new EquipmentSlotItem(EquipmentInventorySlot.BODY, new ArrayList<>(Collections.singletonList( + ItemID.OBSIDIAN_PLATEBODY + ))), + new EquipmentSlotItem(EquipmentInventorySlot.LEGS, new ArrayList<>(Collections.singletonList( + ItemID.OBSIDIAN_PLATELEGS + ))), + new EquipmentSlotItem(EquipmentInventorySlot.WEAPON, new ArrayList<>(Arrays.asList( + ItemID.TOKTZXILAK, + ItemID.TOKTZXILEK, + ItemID.TZHAARKETEM, + ItemID.TZHAARKETOM, + ItemID.TOKTZXILAK_20554 + ))) + )), new EquipmentCombatBonus(0.1, 0, 0)), + + BERSERKERNECKLACE(BonusType.SPECIAL, new EquipmentItemset(Arrays.asList( + new EquipmentSlotItem(EquipmentInventorySlot.AMULET, new ArrayList<>(Collections.singletonList(ItemID.BERSERKER_NECKLACE))), + new EquipmentSlotItem(EquipmentInventorySlot.WEAPON, new ArrayList<>(Arrays.asList( + ItemID.TOKTZXILAK, + ItemID.TOKTZXILEK, + ItemID.TZHAARKETEM, + ItemID.TZHAARKETOM, + ItemID.TOKTZXILAK_20554 + ))) + )), new EquipmentCombatBonus(0.2, 0, 0)), + + + /* + * Magic Equipment + */ + ANCESTRAL_HAT(BonusType.EQUIPMENT, new EquipmentItemset(Collections.singletonList( + new EquipmentSlotItem(EquipmentInventorySlot.HEAD, new ArrayList<>(Collections.singletonList( + ItemID.ANCESTRAL_HAT + ))) + )), new EquipmentCombatBonus(0, 0, 0.02)), + + ANCESTRAL_ROBE_TOP(BonusType.EQUIPMENT, new EquipmentItemset(Collections.singletonList( + new EquipmentSlotItem(EquipmentInventorySlot.BODY, new ArrayList<>(Collections.singletonList( + ItemID.ANCESTRAL_ROBE_TOP + ))) + )), new EquipmentCombatBonus(0, 0, 0.02)), + + ANCESTRAL_ROBE_BOTTOM(BonusType.EQUIPMENT, new EquipmentItemset(Collections.singletonList( + new EquipmentSlotItem(EquipmentInventorySlot.LEGS, new ArrayList<>(Collections.singletonList( + ItemID.ANCESTRAL_ROBE_BOTTOM + ))) + )), new EquipmentCombatBonus(0, 0, 0.02)), + + IMBUED_GOD_CAPE(BonusType.EQUIPMENT, new EquipmentItemset(Collections.singletonList( + new EquipmentSlotItem(EquipmentInventorySlot.CAPE, new ArrayList<>(Arrays.asList( + ItemID.IMBUED_SARADOMIN_MAX_CAPE, + ItemID.IMBUED_SARADOMIN_CAPE, + ItemID.IMBUED_ZAMORAK_MAX_CAPE, + ItemID.IMBUED_ZAMORAK_CAPE, + ItemID.IMBUED_GUTHIX_MAX_CAPE, + ItemID.IMBUED_GUTHIX_CAPE + ))) + )), new EquipmentCombatBonus(0, 0, 0.02)), + + KODAI_WAND(BonusType.EQUIPMENT, new EquipmentItemset(Collections.singletonList( + new EquipmentSlotItem(EquipmentInventorySlot.WEAPON, new ArrayList<>(Collections.singletonList( + ItemID.KODAI_WAND + ))) + )), new EquipmentCombatBonus(0, 0, 0.15)), + + OCCULT_NECKLACE(BonusType.EQUIPMENT, new EquipmentItemset(Collections.singletonList( + new EquipmentSlotItem(EquipmentInventorySlot.AMULET, new ArrayList<>(Arrays.asList( + ItemID.OCCULT_NECKLACE, + ItemID.OCCULT_NECKLACE_OR + ))) + )), new EquipmentCombatBonus(0, 0, 0.10)), + + STAFF_OF_THE_DEAD(BonusType.EQUIPMENT, new EquipmentItemset(Collections.singletonList( + new EquipmentSlotItem(EquipmentInventorySlot.WEAPON, new ArrayList<>(Arrays.asList( + ItemID.STAFF_OF_THE_DEAD, + ItemID.TOXIC_STAFF_OF_THE_DEAD, + ItemID.STAFF_OF_LIGHT + ))) + )), new EquipmentCombatBonus(0, 0, 0.15)), + + TORMENTED_BRACELET(BonusType.EQUIPMENT, new EquipmentItemset(Collections.singletonList( + new EquipmentSlotItem(EquipmentInventorySlot.GLOVES, new ArrayList<>(Collections.singletonList( + ItemID.TORMENTED_BRACELET + ))) + )), new EquipmentCombatBonus(0, 0, 0.05)), + + SMOKE_STAFF(BonusType.EQUIPMENT, new EquipmentItemset(Collections.singletonList( + new EquipmentSlotItem(EquipmentInventorySlot.WEAPON, new ArrayList<>(Arrays.asList( + ItemID.SMOKE_BATTLESTAFF, + ItemID.MYSTIC_SMOKE_STAFF + ))) + )), new EquipmentCombatBonus(0, 0, 0.10), Collections.singletonList(new SpellBookRequirement(SpellBaseDamageConfig.SpellBook.NORMAL))), + + + /* + * Special magic bonusses + * */ + + CHAOS_GAUNTLETS(BonusType.SPECIAL, new EquipmentItemset(Collections.singletonList( + new EquipmentSlotItem(EquipmentInventorySlot.GLOVES, new ArrayList<>(Collections.singletonList( + ItemID.CHAOS_GAUNTLETS + ))))), + new EquipmentCombatBonus(0, 0, 3), + Collections.singletonList( + new AutocastSpellRequirement(new ArrayList<>(Arrays.asList( + SpellBaseDamageConfig.AIR_BOLT, + SpellBaseDamageConfig.WATER_BOLT, + SpellBaseDamageConfig.EARTH_BOLT, + SpellBaseDamageConfig.FIRE_BOLT + ))) + ), + Operation.ADD + ), + + TOME_OF_FIRE(BonusType.MAGIC_SPECIAL, new EquipmentItemset(Collections.singletonList( + new EquipmentSlotItem(EquipmentInventorySlot.SHIELD, new ArrayList<>(Collections.singletonList( + ItemID.TOME_OF_FIRE + ))))), + new EquipmentCombatBonus(0, 0, 0.5), + Collections.singletonList( + new AutocastSpellRequirement(new ArrayList<>(Arrays.asList( + SpellBaseDamageConfig.FIRE_BLAST, + SpellBaseDamageConfig.FIRE_BOLT, + SpellBaseDamageConfig.FIRE_STRIKE, + SpellBaseDamageConfig.FIRE_SURGE, + SpellBaseDamageConfig.FIRE_WAVE + ))) + ) + ); + + + private static final Map> bonusTypes = new HashMap<>(); + + static + { + for (EquipmentBonusConfig equipmentBonus : values()) + { + BonusType bonusType = equipmentBonus.bonusType; + if (!bonusTypes.containsKey(bonusType)) + { + bonusTypes.put(bonusType, new ArrayList<>()); + } + ArrayList list = bonusTypes.get(bonusType); + list.add(equipmentBonus); + bonusTypes.put(bonusType, list); + } + } + + private final EquipmentItemset itemset; + private BonusType bonusType; + private EquipmentCombatBonus equipmentCombatBonus; + private List requirements = new ArrayList<>(); + private Operation operation = Operation.MULTIPLY; + + EquipmentBonusConfig(BonusType bonusType, EquipmentItemset itemset, EquipmentCombatBonus equipmentCombatBonus) + { + this.bonusType = bonusType; + this.itemset = itemset; + this.equipmentCombatBonus = equipmentCombatBonus; + } + + EquipmentBonusConfig(BonusType bonusType, EquipmentItemset itemset, EquipmentCombatBonus equipmentCombatBonus, List requirements) + { + this.bonusType = bonusType; + this.itemset = itemset; + this.equipmentCombatBonus = equipmentCombatBonus; + this.requirements = requirements; + } + + EquipmentBonusConfig(BonusType bonusType, EquipmentItemset itemset, EquipmentCombatBonus equipmentCombatBonus, List requirements, Operation operation) + { + this.bonusType = bonusType; + this.itemset = itemset; + this.equipmentCombatBonus = equipmentCombatBonus; + this.requirements = requirements; + this.operation = operation; + } + + public static ArrayList getBonusByType(BonusType bonusType) + { + if (!bonusTypes.containsKey(bonusType)) + { + return new ArrayList<>(); + } + return bonusTypes.get(bonusType); + } + + public EquipmentItemset getItemset() + { + return itemset; + } + + public Operation getOperation() + { + return operation; + } + + public double getBonus(MaxHitCalculator.CombatMethod combatMethod) + { + return this.equipmentCombatBonus.getCombatBonus(combatMethod); + } + + public boolean meetsRequirements(Client client) + { + return requirements.stream().allMatch(requirement -> requirement.meetsRequirements(client)); + } + + public enum BonusType + { + EQUIPMENT, + SLAYER, + VOID_KNIGHT, + SPECIAL, + MAGIC_SPECIAL + } + + public enum Operation + { + ADD, + MULTIPLY + } + +} + diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/maxhit/equipment/EquipmentSlotItem.java b/runelite-client/src/main/java/net/runelite/client/plugins/maxhit/equipment/EquipmentSlotItem.java index dbc44b3a53..2f4fb844b3 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/maxhit/equipment/EquipmentSlotItem.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/maxhit/equipment/EquipmentSlotItem.java @@ -1,51 +1,50 @@ -/* - * Copyright (c) 2019, Bartvollebregt - * 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.maxhit.equipment; - -import net.runelite.api.EquipmentInventorySlot; - -import java.util.ArrayList; - -public class EquipmentSlotItem -{ - private final EquipmentInventorySlot equipmentSlot; - private final ArrayList itemIds; - - public EquipmentSlotItem(EquipmentInventorySlot equipmentSlot, ArrayList itemIds) - { - this.equipmentSlot = equipmentSlot; - this.itemIds = itemIds; - } - - public ArrayList getItems() - { - return this.itemIds; - } - - public EquipmentInventorySlot getEquipmentSlot() - { - return this.equipmentSlot; - } -} +/* + * Copyright (c) 2019, Bartvollebregt + * 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.maxhit.equipment; + +import java.util.ArrayList; +import net.runelite.api.EquipmentInventorySlot; + +public class EquipmentSlotItem +{ + private final EquipmentInventorySlot equipmentSlot; + private final ArrayList itemIds; + + public EquipmentSlotItem(EquipmentInventorySlot equipmentSlot, ArrayList itemIds) + { + this.equipmentSlot = equipmentSlot; + this.itemIds = itemIds; + } + + public ArrayList getItems() + { + return this.itemIds; + } + + public EquipmentInventorySlot getEquipmentSlot() + { + return this.equipmentSlot; + } +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/maxhit/requirements/AutocastSpellRequirement.java b/runelite-client/src/main/java/net/runelite/client/plugins/maxhit/requirements/AutocastSpellRequirement.java index 988e459631..f7a0162cf8 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/maxhit/requirements/AutocastSpellRequirement.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/maxhit/requirements/AutocastSpellRequirement.java @@ -1,58 +1,57 @@ -/* - * Copyright (c) 2019, Bartvollebregt - * 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.maxhit.requirements; - -import net.runelite.api.Client; -import net.runelite.api.Varbits; -import net.runelite.client.plugins.maxhit.config.SpellBaseDamageConfig; - -import java.util.ArrayList; - -public class AutocastSpellRequirement implements Requirement -{ - - private final ArrayList autocastSpells; - - public AutocastSpellRequirement(ArrayList autocastSpells) - { - this.autocastSpells = autocastSpells; - } - - @Override - public boolean meetsRequirements(Client client) - { - int autoCastSpellId = client.getVar(Varbits.AUTO_CAST_SPELL); - - if (autoCastSpellId == 0) - { - - return false; - - } - - return this.autocastSpells.stream().anyMatch(spell -> spell.getSpellID() == autoCastSpellId); - - } -} +/* + * Copyright (c) 2019, Bartvollebregt + * 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.maxhit.requirements; + +import java.util.ArrayList; +import net.runelite.api.Client; +import net.runelite.api.Varbits; +import net.runelite.client.plugins.maxhit.config.SpellBaseDamageConfig; + +public class AutocastSpellRequirement implements Requirement +{ + + private final ArrayList autocastSpells; + + public AutocastSpellRequirement(ArrayList autocastSpells) + { + this.autocastSpells = autocastSpells; + } + + @Override + public boolean meetsRequirements(Client client) + { + int autoCastSpellId = client.getVar(Varbits.AUTO_CAST_SPELL); + + if (autoCastSpellId == 0) + { + + return false; + + } + + return this.autocastSpells.stream().anyMatch(spell -> spell.getSpellID() == autoCastSpellId); + + } +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/menuentryswapper/MenuEntrySwapperConfig.java b/runelite-client/src/main/java/net/runelite/client/plugins/menuentryswapper/MenuEntrySwapperConfig.java index a7bc841eb9..fbfe53c822 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/menuentryswapper/MenuEntrySwapperConfig.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/menuentryswapper/MenuEntrySwapperConfig.java @@ -100,7 +100,7 @@ public interface MenuEntrySwapperConfig extends Config ) default boolean swapContract() { - return true; + return true; } @ConfigItem( @@ -123,7 +123,7 @@ public interface MenuEntrySwapperConfig extends Config return true; } - @ConfigItem( + @ConfigItem( keyName = "swapDarkMage", name = "Repairs", description = "Swap Talk-to with Repairs for Dark Mage" @@ -282,14 +282,14 @@ public interface MenuEntrySwapperConfig extends Config { return true; } - + @ConfigItem( keyName = "rockCake", name = "Rock Cake Guzzle", description = "Enables Left Click Guzzle to Rock Cake" ) - default boolean rockCake() - { + default boolean rockCake() + { return false; } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/menuentryswapper/MenuEntrySwapperPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/menuentryswapper/MenuEntrySwapperPlugin.java index da2c02260f..0308323471 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/menuentryswapper/MenuEntrySwapperPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/menuentryswapper/MenuEntrySwapperPlugin.java @@ -363,7 +363,7 @@ public class MenuEntrySwapperPlugin extends Plugin final int eventId = event.getIdentifier(); final String option = Text.removeTags(event.getOption()).toLowerCase(); final String target = Text.removeTags(event.getTarget()).toLowerCase(); - final NPC hintArrowNpc = client.getHintArrowNpc(); + final NPC hintArrowNpc = client.getHintArrowNpc(); if (hintArrowNpc != null && hintArrowNpc.getIndex() == eventId @@ -451,32 +451,32 @@ public class MenuEntrySwapperPlugin extends Plugin swap(client, "quick-travel", option, target, true); } } - + else if (config.swapTravel() && option.equals("pass") && target.equals("energy barrier")) { swap(client, "pay-toll(2-ecto)", option, target, true); } - + else if (config.swapTravel() && option.equals("open") && target.equals("gate")) { swap(client, "pay-toll(10gp)", option, target, true); } - + else if (config.swapTravel() && option.equals("inspect") && target.equals("trapdoor")) { swap(client, "travel", option, target, true); } - + else if (config.swapHarpoon() && option.equals("cage")) { swap(client, "harpoon", option, target, true); } - + else if (config.swapHarpoon() && (option.equals("big net") || option.equals("net"))) { swap(client, "harpoon", option, target, true); } - + else if (config.swapHomePortal() != HouseMode.ENTER && option.equals("enter")) { switch (config.swapHomePortal()) @@ -504,76 +504,76 @@ public class MenuEntrySwapperPlugin extends Plugin swap(client, "configure", option, target, false); } } - + else if (config.swapFairyRing() == FairyRingMode.ZANARIS && option.equals("tree")) { swap(client, "zanaris", option, target, false); } - + else if (config.swapBoxTrap() && (option.equals("check") || option.equals("dismantle"))) { swap(client, "reset", option, target, true); } - + else if (config.swapBoxTrap() && option.equals("take")) { swap(client, "lay", option, target, true); } - + else if (config.swapChase() && option.equals("pick-up")) { swap(client, "chase", option, target, true); } - + else if (config.swapBirdhouseEmpty() && option.equals("interact") && target.contains("birdhouse")) { swap(client, "empty", option, target, true); } - + else if (config.swapQuick() && option.equals("ring")) { swap(client, "quick-start", option, target, true); } - + else if (config.swapQuick() && option.equals("pass")) { swap(client, "quick-pass", option, target, true); swap(client, "quick pass", option, target, true); } - + else if (config.swapQuick() && option.equals("open")) { swap(client, "quick-open", option, target, true); } - + else if (config.swapAdmire() && option.equals("admire")) { swap(client, "teleport", option, target, true); swap(client, "spellbook", option, target, true); swap(client, "perks", option, target, true); } - + else if (config.swapPrivate() && option.equals("shared")) { swap(client, "private", option, target, true); } - + else if (config.swapPick() && option.equals("pick")) { swap(client, "pick-lots", option, target, true); } - + else if (config.swapRogueschests() && target.contains("chest")) { swap(client, "search for traps", option, target, true); } - + else if (config.rockCake() && option.equals("eat")) { swap(client, "guzzle", option, target, true); } - - + + else if (config.shiftClickCustomization() && shiftModifier && !option.equals("use")) { Integer customOption = getSwapConfig(eventId); @@ -583,7 +583,7 @@ public class MenuEntrySwapperPlugin extends Plugin swap(client, "use", option, target, true); } } - + // Put all item-related swapping after shift-click else if (config.swapTeleportItem() && option.equals("wear")) { diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/menumodifier/MenuModifierConfig.java b/runelite-client/src/main/java/net/runelite/client/plugins/menumodifier/MenuModifierConfig.java index beef23cfd2..b67d393a3d 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/menumodifier/MenuModifierConfig.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/menumodifier/MenuModifierConfig.java @@ -31,37 +31,49 @@ import net.runelite.client.config.ConfigItem; @ConfigGroup("menumodifier") public interface MenuModifierConfig extends Config { - @ConfigItem( - position = 0, + @ConfigItem( + position = 0, keyName = "hideExamine", name = "Hide Examine", description = "Hides the 'examine' option from the right click menu" ) - default boolean hideExamine() { return true; } + default boolean hideExamine() + { + return true; + } - @ConfigItem( - position = 1, + @ConfigItem( + position = 1, keyName = "hideTradeWith", name = "Hide Trade With", description = "Hides the 'trade with' option from the right click menu" ) - default boolean hideTradeWith() { return true; } + default boolean hideTradeWith() + { + return true; + } - @ConfigItem( - position = 2, + @ConfigItem( + position = 2, keyName = "hideReport", name = "Hide Report", description = "Hides the 'report' option from the right click menu" ) - default boolean hideReport() { return true; } + default boolean hideReport() + { + return true; + } - @ConfigItem( - position = 3, + @ConfigItem( + position = 3, keyName = "hideLookup", name = "Hide Lookup", description = "Hides the 'lookup' option from the right click menu" ) - default boolean hideLookup() { return true; } + default boolean hideLookup() + { + return true; + } @ConfigItem( position = 4, @@ -69,7 +81,10 @@ public interface MenuModifierConfig extends Config name = "Hide Net", description = "Hides the 'net' option from the right click menu" ) - default boolean hideNet() { return true; } + default boolean hideNet() + { + return true; + } @ConfigItem( position = 5, @@ -77,5 +92,8 @@ public interface MenuModifierConfig extends Config name = "Hide Bait", description = "Hides the 'Bait' option from the right click menu" ) - default boolean hideBait() { return true; } + default boolean hideBait() + { + return true; + } } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/mining/MiningOverlay.java b/runelite-client/src/main/java/net/runelite/client/plugins/mining/MiningOverlay.java index 55a4997509..fb93301723 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/mining/MiningOverlay.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/mining/MiningOverlay.java @@ -1,122 +1,130 @@ -/* - * Copyright (c) 2018, Seth - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package net.runelite.client.plugins.mining; - -import com.google.common.collect.ImmutableSet; -import net.runelite.api.Client; -import net.runelite.client.plugins.mining.MiningConfig; -import net.runelite.client.ui.overlay.Overlay; -import net.runelite.client.ui.overlay.OverlayPosition; -import net.runelite.client.ui.overlay.components.LineComponent; -import net.runelite.client.ui.overlay.components.PanelComponent; -import net.runelite.client.ui.overlay.components.TitleComponent; - -import javax.inject.Inject; -import java.awt.*; -import java.time.Duration; -import java.time.Instant; -import java.util.Set; - -import static net.runelite.api.AnimationID.*; - -class MiningOverlay extends Overlay -{ - private static final Set MINING_ANIMATION_IDS = ImmutableSet.of( - MINING_MOTHERLODE_BRONZE, MINING_MOTHERLODE_IRON, MINING_MOTHERLODE_STEEL, - MINING_MOTHERLODE_BLACK, MINING_MOTHERLODE_MITHRIL, MINING_MOTHERLODE_ADAMANT, - MINING_MOTHERLODE_RUNE, MINING_MOTHERLODE_DRAGON, MINING_MOTHERLODE_DRAGON_ORN, - MINING_MOTHERLODE_INFERNAL - ); - - private final Client client; - private final MiningPlugin plugin; - private final MiningConfig config; - private final PanelComponent panelComponent = new PanelComponent(); - - @Inject - MiningOverlay(Client client, MiningPlugin plugin, MiningConfig config) - { - setPosition(OverlayPosition.TOP_LEFT); - this.client = client; - this.plugin = plugin; - this.config = config; - } - - @Override - public Dimension render(Graphics2D graphics) - { - if (!plugin.isInMlm() || !config.showMiningStats()) - { - return null; - } - - MiningSession session = plugin.getSession(); - - if (session.getLastPayDirtMined() == null) - { - return null; - } - - Duration statTimeout = Duration.ofMinutes(config.statTimeout()); - Duration sinceCut = Duration.between(session.getLastPayDirtMined(), Instant.now()); - - if (sinceCut.compareTo(statTimeout) >= 0) - { - return null; - } - - panelComponent.getChildren().clear(); - - if (config.showMiningState()) - { - if (MINING_ANIMATION_IDS.contains(client.getLocalPlayer().getAnimation())) - { - panelComponent.getChildren().add(TitleComponent.builder() - .text("Mining") - .color(Color.GREEN) - .build()); - } - else - { - panelComponent.getChildren().add(TitleComponent.builder() - .text("NOT mining") - .color(Color.RED) - .build()); - } - } - - panelComponent.getChildren().add(LineComponent.builder() - .left("Pay-dirt mined:") - .right(Integer.toString(session.getTotalMined())) - .build()); - - panelComponent.getChildren().add(LineComponent.builder() - .left("Pay-dirt/hr:") - .right(session.getRecentMined() > 2 ? Integer.toString(session.getPerHour()) : "") - .build()); - - return panelComponent.render(graphics); - } -} +/* + * Copyright (c) 2018, Seth + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package net.runelite.client.plugins.mining; + +import com.google.common.collect.ImmutableSet; +import java.awt.Color; +import java.awt.Dimension; +import java.awt.Graphics2D; +import java.time.Duration; +import java.time.Instant; +import java.util.Set; +import javax.inject.Inject; +import static net.runelite.api.AnimationID.MINING_MOTHERLODE_ADAMANT; +import static net.runelite.api.AnimationID.MINING_MOTHERLODE_BLACK; +import static net.runelite.api.AnimationID.MINING_MOTHERLODE_BRONZE; +import static net.runelite.api.AnimationID.MINING_MOTHERLODE_DRAGON; +import static net.runelite.api.AnimationID.MINING_MOTHERLODE_DRAGON_ORN; +import static net.runelite.api.AnimationID.MINING_MOTHERLODE_INFERNAL; +import static net.runelite.api.AnimationID.MINING_MOTHERLODE_IRON; +import static net.runelite.api.AnimationID.MINING_MOTHERLODE_MITHRIL; +import static net.runelite.api.AnimationID.MINING_MOTHERLODE_RUNE; +import static net.runelite.api.AnimationID.MINING_MOTHERLODE_STEEL; +import net.runelite.api.Client; +import net.runelite.client.ui.overlay.Overlay; +import net.runelite.client.ui.overlay.OverlayPosition; +import net.runelite.client.ui.overlay.components.LineComponent; +import net.runelite.client.ui.overlay.components.PanelComponent; +import net.runelite.client.ui.overlay.components.TitleComponent; + +class MiningOverlay extends Overlay +{ + private static final Set MINING_ANIMATION_IDS = ImmutableSet.of( + MINING_MOTHERLODE_BRONZE, MINING_MOTHERLODE_IRON, MINING_MOTHERLODE_STEEL, + MINING_MOTHERLODE_BLACK, MINING_MOTHERLODE_MITHRIL, MINING_MOTHERLODE_ADAMANT, + MINING_MOTHERLODE_RUNE, MINING_MOTHERLODE_DRAGON, MINING_MOTHERLODE_DRAGON_ORN, + MINING_MOTHERLODE_INFERNAL + ); + + private final Client client; + private final MiningPlugin plugin; + private final MiningConfig config; + private final PanelComponent panelComponent = new PanelComponent(); + + @Inject + MiningOverlay(Client client, MiningPlugin plugin, MiningConfig config) + { + setPosition(OverlayPosition.TOP_LEFT); + this.client = client; + this.plugin = plugin; + this.config = config; + } + + @Override + public Dimension render(Graphics2D graphics) + { + if (!plugin.isInMlm() || !config.showMiningStats()) + { + return null; + } + + MiningSession session = plugin.getSession(); + + if (session.getLastPayDirtMined() == null) + { + return null; + } + + Duration statTimeout = Duration.ofMinutes(config.statTimeout()); + Duration sinceCut = Duration.between(session.getLastPayDirtMined(), Instant.now()); + + if (sinceCut.compareTo(statTimeout) >= 0) + { + return null; + } + + panelComponent.getChildren().clear(); + + if (config.showMiningState()) + { + if (MINING_ANIMATION_IDS.contains(client.getLocalPlayer().getAnimation())) + { + panelComponent.getChildren().add(TitleComponent.builder() + .text("Mining") + .color(Color.GREEN) + .build()); + } + else + { + panelComponent.getChildren().add(TitleComponent.builder() + .text("NOT mining") + .color(Color.RED) + .build()); + } + } + + panelComponent.getChildren().add(LineComponent.builder() + .left("Pay-dirt mined:") + .right(Integer.toString(session.getTotalMined())) + .build()); + + panelComponent.getChildren().add(LineComponent.builder() + .left("Pay-dirt/hr:") + .right(session.getRecentMined() > 2 ? Integer.toString(session.getPerHour()) : "") + .build()); + + return panelComponent.render(graphics); + } +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/mining/MiningPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/mining/MiningPlugin.java index e8f0691f8d..d8aec0d7a5 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/mining/MiningPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/mining/MiningPlugin.java @@ -28,25 +28,33 @@ package net.runelite.client.plugins.mining; import com.google.common.collect.ImmutableSet; import com.google.inject.Provides; +import java.time.temporal.ChronoUnit; +import java.util.HashSet; +import java.util.Set; +import javax.inject.Inject; import lombok.AccessLevel; import lombok.Getter; -import net.runelite.api.*; -import net.runelite.api.events.*; +import net.runelite.api.Client; +import net.runelite.api.GameObject; +import net.runelite.api.GameState; +import net.runelite.api.ItemID; +import static net.runelite.api.ObjectID.ORE_VEIN_26661; +import static net.runelite.api.ObjectID.ORE_VEIN_26662; +import static net.runelite.api.ObjectID.ORE_VEIN_26663; +import static net.runelite.api.ObjectID.ORE_VEIN_26664; +import net.runelite.api.WallObject; +import net.runelite.api.events.GameObjectChanged; +import net.runelite.api.events.GameObjectDespawned; +import net.runelite.api.events.GameObjectSpawned; +import net.runelite.api.events.GameStateChanged; import net.runelite.client.callback.ClientThread; import net.runelite.client.config.ConfigManager; import net.runelite.client.eventbus.Subscribe; import net.runelite.client.plugins.Plugin; import net.runelite.client.plugins.PluginDescriptor; import net.runelite.client.plugins.PluginType; -import net.runelite.client.plugins.mining.MiningConfig; import net.runelite.client.task.Schedule; import net.runelite.client.ui.overlay.OverlayManager; -import javax.inject.Inject; -import java.time.temporal.ChronoUnit; -import java.util.HashSet; -import java.util.Set; - -import static net.runelite.api.ObjectID.*; @PluginDescriptor( name = "Mining", @@ -60,13 +68,13 @@ public class MiningPlugin extends Plugin private static final Set MOTHERLODE_MAP_REGIONS = ImmutableSet.of(14679, 14680, 14681, 14935, 14936, 14937, 15191, 15192, 15193); private static final Set MINE_SPOTS = ImmutableSet.of(ORE_VEIN_26661, ORE_VEIN_26662, ORE_VEIN_26663, ORE_VEIN_26664); private static final Set MLM_ORE_TYPES = ImmutableSet.of(ItemID.RUNITE_ORE, ItemID.ADAMANTITE_ORE, - ItemID.MITHRIL_ORE, ItemID.GOLD_ORE, ItemID.COAL, ItemID.GOLDEN_NUGGET); + ItemID.MITHRIL_ORE, ItemID.GOLD_ORE, ItemID.COAL, ItemID.GOLDEN_NUGGET); private static final Set MINING_ROCKS = ImmutableSet.of( - // another website says depleted rocks are 7468, 7469 - // website says stoney 2902, 2962, 2963, 2964, - 2231, 2257, 2584, 2704, 3722, 3723, 3748, 3790, 3791, 3803, 3804, 3805, 3806, 3807, 3808, 4437, 4438, 4676, 6669, 6670, 6671, 6672, 6673, 7453, 7454, 7455, 7456, 7457, 7458, 7459, 7460, 7461, 7462, 7463, 7464, 7467, 7470, 7484, 7485, 7486, 7487, 7488, 7489, 7490, 7491, 7492, 7493, 7494, 7495, 8727, 8828, 8829, 8830, 10079, 10080, 10081, 11441, 11924, 12590, 15127, 15128, 15213, 16464, 16514, 16515, 16521, 16522, 16523, 16524, 16534, 16535, 16545, 16549, 16550, 16998, 16999, 17042, 17043, 17064, 17065, 18817, 18840, 18952, 18953, 18954, 18961, 19849, 19969, 19970, 19971, 19972, 19973, 22665, 22667, 23280, 23281, 23640, 24146, 24147, 24148, 24557, 26873, 26874, 27984, 27985, 27987, 27988, 28596, 28597, 28752, 28753, 28890 - //2090, 2091, 2092, 2093, 2094, 2095, 2096, 2097, 2098, 2099, 2100, 2101, 2102, 2103, 2104, 2105, 2106, 2107, 2108, 2109, 2110, 2111, 2119, 2120, 2121, 2122, 2123, 2124, 2125, 2126, 2127, 2128, 2129, 2130, 2131, 2132, 2133, 2134, 2135, 2136, 2137, 2138, 2139, 2140, 2231, 2257, 2328, 3042, 3043, 3722, 3723, 3748, 3790, 3791, 3803, 3804, 4676, 6943, 6944, 6945, 6946, 6947, 6948, 9296, 9297, 9303, 9304, 9305, 9306, 9316, 9317, 9331, 9332, 9335, 9336, 9708, 9709, 9710, 9711, 9712, 9713, 9714, 9715, 9716, 9717, 9718, 9719, 9720, 9721, 9722, 9723, 9724, 9725, 9726, 9727, 9728, 9729, 9730, 9731, 9732, 9733, 9734, 9735, 9736, 9737, 10583, 10584, 10585, 10586, 10587, 10944, 10945, 10946, 10947, 10948, 10949, 11165, 11166, 11167, 11168, 11169, 11170, 11171, 11172, 11173, 11174, 11175, 11176, 11177, 11178, 11179, 11180, 11181, 11182, 11183, 11184, 11185, 11186, 11187, 11188, 11189, 11190, 11191, 11192, 11193, 11194, 11195, 11424, 11425, 11426, 11427, 11428, 11429, 11430, 11431, 11432, 11433, 11434, 11435, 11436, 11437, 11438, 11439, 11440, 11441, 11442, 11443, 11444, 11552, 11553, 11554, 11555, 11556, 11557, 11915, 11916, 11917, 11918, 11919, 11920, 11921, 11922, 11923, 11924, 11925, 11926, 11927, 11928, 11929, 11930, 11931, 11932, 11933, 11934, 11935, 11936, 11937, 11938, 11939, 11940, 11941, 11942, 11943, 11944, 11945, 11946, 11947, 11948, 11949, 11950, 11951, 11952, 11953, 11954, 11955, 11956, 11957, 11958, 11959, 11960, 11961, 11962, 11963, 11964, 11965 - //968, 1480, 1855, 4043, 4487, 7533, 9716, 21250, 1997, 2581, 2582, 2694, 2695, 2696, 2697, 2835, 2836, 2837, 2901, 2965, 3339, 3364, 4526, 4552, 4553, 4554, 4555, 4556, 4557, 4558, 4887, 5604, 5605, 5606, 5844, 5845, 5896, 5985, 5987, 6622, 6623, 6707, 6708, 6709, 7466, 8725, 8726, 8950, 8951, 8952, 9031, 9032, 10036, 10782, 10783, 10784, 10785, 10786, 10787, 10788, 11097, 11098, 11182, 11183, 11424, 11425, 12564, 12565, 12566, 12567, 12588, 12589, 12774, 14814, 14815, 14816, 14817, 15198, 15199, 15217, 15218, 15219, 15410, 15536, 15537, 16077, 16078, 16079, 16080, 16115, 16136, 16284, 16303, 17350, 17351, 17352, 17353, 17354, 17355, 17356, 17357, 17358, 17364, 17365, 17366, 17679, 17958, 17959, 17960, 17970, 17971, 17972, 18871, 18872, 18873, 19131, 21571, 21572, 21573, 22549, 22550, 22551, 23124, 23125, 23126, 23127, 23165, 23976, 23977, 23978, 23979, 23980, 23981, 24693, 24694, 24695, 24696, 24697, 24698, 24699, 24700, 24701, 24781, 25158, 25159, 25160, 25422, 25423, 26372, 26373, 26376, 26377, 26850, 26856, 28580, 29102, 29883, 29884, 29885, 30344, 30519, 30521, 30522, 30857, 30858, 31045, 31781, 31782, 31783, 31784, 31785, 31786, 31787, 31788, 31789 + // another website says depleted rocks are 7468, 7469 + // website says stoney 2902, 2962, 2963, 2964, + 2231, 2257, 2584, 2704, 3722, 3723, 3748, 3790, 3791, 3803, 3804, 3805, 3806, 3807, 3808, 4437, 4438, 4676, 6669, 6670, 6671, 6672, 6673, 7453, 7454, 7455, 7456, 7457, 7458, 7459, 7460, 7461, 7462, 7463, 7464, 7467, 7470, 7484, 7485, 7486, 7487, 7488, 7489, 7490, 7491, 7492, 7493, 7494, 7495, 8727, 8828, 8829, 8830, 10079, 10080, 10081, 11441, 11924, 12590, 15127, 15128, 15213, 16464, 16514, 16515, 16521, 16522, 16523, 16524, 16534, 16535, 16545, 16549, 16550, 16998, 16999, 17042, 17043, 17064, 17065, 18817, 18840, 18952, 18953, 18954, 18961, 19849, 19969, 19970, 19971, 19972, 19973, 22665, 22667, 23280, 23281, 23640, 24146, 24147, 24148, 24557, 26873, 26874, 27984, 27985, 27987, 27988, 28596, 28597, 28752, 28753, 28890 + //2090, 2091, 2092, 2093, 2094, 2095, 2096, 2097, 2098, 2099, 2100, 2101, 2102, 2103, 2104, 2105, 2106, 2107, 2108, 2109, 2110, 2111, 2119, 2120, 2121, 2122, 2123, 2124, 2125, 2126, 2127, 2128, 2129, 2130, 2131, 2132, 2133, 2134, 2135, 2136, 2137, 2138, 2139, 2140, 2231, 2257, 2328, 3042, 3043, 3722, 3723, 3748, 3790, 3791, 3803, 3804, 4676, 6943, 6944, 6945, 6946, 6947, 6948, 9296, 9297, 9303, 9304, 9305, 9306, 9316, 9317, 9331, 9332, 9335, 9336, 9708, 9709, 9710, 9711, 9712, 9713, 9714, 9715, 9716, 9717, 9718, 9719, 9720, 9721, 9722, 9723, 9724, 9725, 9726, 9727, 9728, 9729, 9730, 9731, 9732, 9733, 9734, 9735, 9736, 9737, 10583, 10584, 10585, 10586, 10587, 10944, 10945, 10946, 10947, 10948, 10949, 11165, 11166, 11167, 11168, 11169, 11170, 11171, 11172, 11173, 11174, 11175, 11176, 11177, 11178, 11179, 11180, 11181, 11182, 11183, 11184, 11185, 11186, 11187, 11188, 11189, 11190, 11191, 11192, 11193, 11194, 11195, 11424, 11425, 11426, 11427, 11428, 11429, 11430, 11431, 11432, 11433, 11434, 11435, 11436, 11437, 11438, 11439, 11440, 11441, 11442, 11443, 11444, 11552, 11553, 11554, 11555, 11556, 11557, 11915, 11916, 11917, 11918, 11919, 11920, 11921, 11922, 11923, 11924, 11925, 11926, 11927, 11928, 11929, 11930, 11931, 11932, 11933, 11934, 11935, 11936, 11937, 11938, 11939, 11940, 11941, 11942, 11943, 11944, 11945, 11946, 11947, 11948, 11949, 11950, 11951, 11952, 11953, 11954, 11955, 11956, 11957, 11958, 11959, 11960, 11961, 11962, 11963, 11964, 11965 + //968, 1480, 1855, 4043, 4487, 7533, 9716, 21250, 1997, 2581, 2582, 2694, 2695, 2696, 2697, 2835, 2836, 2837, 2901, 2965, 3339, 3364, 4526, 4552, 4553, 4554, 4555, 4556, 4557, 4558, 4887, 5604, 5605, 5606, 5844, 5845, 5896, 5985, 5987, 6622, 6623, 6707, 6708, 6709, 7466, 8725, 8726, 8950, 8951, 8952, 9031, 9032, 10036, 10782, 10783, 10784, 10785, 10786, 10787, 10788, 11097, 11098, 11182, 11183, 11424, 11425, 12564, 12565, 12566, 12567, 12588, 12589, 12774, 14814, 14815, 14816, 14817, 15198, 15199, 15217, 15218, 15219, 15410, 15536, 15537, 16077, 16078, 16079, 16080, 16115, 16136, 16284, 16303, 17350, 17351, 17352, 17353, 17354, 17355, 17356, 17357, 17358, 17364, 17365, 17366, 17679, 17958, 17959, 17960, 17970, 17971, 17972, 18871, 18872, 18873, 19131, 21571, 21572, 21573, 22549, 22550, 22551, 23124, 23125, 23126, 23127, 23165, 23976, 23977, 23978, 23979, 23980, 23981, 24693, 24694, 24695, 24696, 24697, 24698, 24699, 24700, 24701, 24781, 25158, 25159, 25160, 25422, 25423, 26372, 26373, 26376, 26377, 26850, 26856, 28580, 29102, 29883, 29884, 29885, 30344, 30519, 30521, 30522, 30857, 30858, 31045, 31781, 31782, 31783, 31784, 31785, 31786, 31787, 31788, 31789 ); private static final int MAX_INVENTORY_SIZE = 28; diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/mining/MiningRocksOverlay.java b/runelite-client/src/main/java/net/runelite/client/plugins/mining/MiningRocksOverlay.java index 25408b5a13..daff203b28 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/mining/MiningRocksOverlay.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/mining/MiningRocksOverlay.java @@ -1,110 +1,115 @@ -/* - * Copyright (c) 2018, Seth - * Copyright (c) 2018, Adam - * Copyright (c) 2018, Lars - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package net.runelite.client.plugins.mining; - -import net.runelite.api.Point; -import net.runelite.api.*; -import net.runelite.api.coords.LocalPoint; -import net.runelite.client.game.SkillIconManager; -import net.runelite.client.plugins.mining.MiningConfig; -import net.runelite.client.ui.overlay.Overlay; -import net.runelite.client.ui.overlay.OverlayLayer; -import net.runelite.client.ui.overlay.OverlayPosition; -import net.runelite.client.ui.overlay.OverlayUtil; - -import javax.inject.Inject; -import java.awt.*; -import java.awt.image.BufferedImage; - -class MiningRocksOverlay extends Overlay -{ - private static final int MAX_DISTANCE = 2350; - - private final Client client; - private final MiningPlugin plugin; - private final MiningConfig config; - - private final BufferedImage miningIcon; - - @Inject - MiningRocksOverlay(Client client, MiningPlugin plugin, MiningConfig config, SkillIconManager iconManager) - { - setPosition(OverlayPosition.DYNAMIC); - setLayer(OverlayLayer.ABOVE_SCENE); - this.client = client; - this.plugin = plugin; - this.config = config; - - miningIcon = iconManager.getSkillImage(Skill.MINING); - } - - @Override - public Dimension render(Graphics2D graphics) - { - Player local = client.getLocalPlayer(); - - renderTiles(graphics, local); - - return null; - } - - private void renderTiles(Graphics2D graphics, Player local) - { - LocalPoint localLocation = local.getLocalLocation(); - - if (config.showMiningRocks()) { - for (GameObject rock : plugin.getRocks()) { - - LocalPoint location = rock.getLocalLocation(); - if (localLocation.distanceTo(location) <= MAX_DISTANCE) { - renderMiningRock(graphics, rock); - } - } - } - - } - - private void renderMiningRock(Graphics2D graphics, GameObject rock) - { - Point canvasLoc = Perspective.getCanvasImageLocation(client, rock.getLocalLocation(), miningIcon, 0); - if (canvasLoc != null) - { - graphics.drawImage(miningIcon, canvasLoc.getX(), canvasLoc.getY(), null); - } - } - -// private void renderMiningRockSquare(Graphics2D graphics, GameObject rock) -// { -// Polygon poly = Perspective.getCanvasTilePoly(client, rock.getLocalLocation()); -// -// if (poly != null) -// { -// OverlayUtil.renderPolygon(graphics, poly, Color.red); -// } -// } - -} +/* + * Copyright (c) 2018, Seth + * Copyright (c) 2018, Adam + * Copyright (c) 2018, Lars + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package net.runelite.client.plugins.mining; + +import java.awt.Dimension; +import java.awt.Graphics2D; +import java.awt.image.BufferedImage; +import javax.inject.Inject; +import net.runelite.api.Client; +import net.runelite.api.GameObject; +import net.runelite.api.Perspective; +import net.runelite.api.Player; +import net.runelite.api.Point; +import net.runelite.api.Skill; +import net.runelite.api.coords.LocalPoint; +import net.runelite.client.game.SkillIconManager; +import net.runelite.client.ui.overlay.Overlay; +import net.runelite.client.ui.overlay.OverlayLayer; +import net.runelite.client.ui.overlay.OverlayPosition; + +class MiningRocksOverlay extends Overlay +{ + private static final int MAX_DISTANCE = 2350; + + private final Client client; + private final MiningPlugin plugin; + private final MiningConfig config; + + private final BufferedImage miningIcon; + + @Inject + MiningRocksOverlay(Client client, MiningPlugin plugin, MiningConfig config, SkillIconManager iconManager) + { + setPosition(OverlayPosition.DYNAMIC); + setLayer(OverlayLayer.ABOVE_SCENE); + this.client = client; + this.plugin = plugin; + this.config = config; + + miningIcon = iconManager.getSkillImage(Skill.MINING); + } + + @Override + public Dimension render(Graphics2D graphics) + { + Player local = client.getLocalPlayer(); + + renderTiles(graphics, local); + + return null; + } + + private void renderTiles(Graphics2D graphics, Player local) + { + LocalPoint localLocation = local.getLocalLocation(); + + if (config.showMiningRocks()) + { + for (GameObject rock : plugin.getRocks()) + { + + LocalPoint location = rock.getLocalLocation(); + if (localLocation.distanceTo(location) <= MAX_DISTANCE) + { + renderMiningRock(graphics, rock); + } + } + } + + } + + private void renderMiningRock(Graphics2D graphics, GameObject rock) + { + Point canvasLoc = Perspective.getCanvasImageLocation(client, rock.getLocalLocation(), miningIcon, 0); + if (canvasLoc != null) + { + graphics.drawImage(miningIcon, canvasLoc.getX(), canvasLoc.getY(), null); + } + } + +// private void renderMiningRockSquare(Graphics2D graphics, GameObject rock) +// { +// Polygon poly = Perspective.getCanvasTilePoly(client, rock.getLocalLocation()); +// +// if (poly != null) +// { +// OverlayUtil.renderPolygon(graphics, poly, Color.red); +// } +// } + +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/mining/MiningSession.java b/runelite-client/src/main/java/net/runelite/client/plugins/mining/MiningSession.java index 890e2453b7..fbe975f630 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/mining/MiningSession.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/mining/MiningSession.java @@ -1,140 +1,139 @@ -/* - * Copyright (c) 2018, Seth - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package net.runelite.client.plugins.mining; - -import lombok.AccessLevel; -import lombok.Getter; -import lombok.extern.slf4j.Slf4j; -import net.runelite.api.ItemID; - -import java.time.Duration; -import java.time.Instant; - -@Slf4j -public class MiningSession -{ - private static final Duration HOUR = Duration.ofHours(1); - - private int perHour; - - private Instant lastPayDirtMined; - private int totalMined; - - private Instant recentPayDirtMined; - private int recentMined; - - @Getter(AccessLevel.PACKAGE) - private Instant lastGemFound; - - @Getter(AccessLevel.PACKAGE) - private int diamondsFound; - - @Getter(AccessLevel.PACKAGE) - private int rubiesFound; - - @Getter(AccessLevel.PACKAGE) - private int emeraldsFound; - - @Getter(AccessLevel.PACKAGE) - private int sapphiresFound; - - public void incrementGemFound(int gemID) - { - lastGemFound = Instant.now(); - - switch (gemID) - { - case ItemID.UNCUT_DIAMOND: - diamondsFound++; - break; - - case ItemID.UNCUT_RUBY: - rubiesFound++; - break; - - case ItemID.UNCUT_EMERALD: - emeraldsFound++; - break; - - case ItemID.UNCUT_SAPPHIRE: - sapphiresFound++; - break; - - default: - log.error("Invalid gem type specified. The gem count will not be incremented."); - } - } - - public void incrementPayDirtMined() - { - Instant now = Instant.now(); - - lastPayDirtMined = now; - ++totalMined; - - if (recentMined == 0) - { - recentPayDirtMined = now; - } - ++recentMined; - - Duration timeSinceStart = Duration.between(recentPayDirtMined, now); - if (!timeSinceStart.isZero()) - { - perHour = (int) ((double) recentMined * (double) HOUR.toMillis() / (double) timeSinceStart.toMillis()); - } - } - - public void resetRecent() - { - recentPayDirtMined = null; - recentMined = 0; - } - - public int getPerHour() - { - return perHour; - } - - public Instant getLastPayDirtMined() - { - return lastPayDirtMined; - } - - public int getTotalMined() - { - return totalMined; - } - - public Instant getRecentPayDirtMined() - { - return recentPayDirtMined; - } - - public int getRecentMined() - { - return recentMined; - } -} +/* + * Copyright (c) 2018, Seth + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package net.runelite.client.plugins.mining; + +import java.time.Duration; +import java.time.Instant; +import lombok.AccessLevel; +import lombok.Getter; +import lombok.extern.slf4j.Slf4j; +import net.runelite.api.ItemID; + +@Slf4j +public class MiningSession +{ + private static final Duration HOUR = Duration.ofHours(1); + + private int perHour; + + private Instant lastPayDirtMined; + private int totalMined; + + private Instant recentPayDirtMined; + private int recentMined; + + @Getter(AccessLevel.PACKAGE) + private Instant lastGemFound; + + @Getter(AccessLevel.PACKAGE) + private int diamondsFound; + + @Getter(AccessLevel.PACKAGE) + private int rubiesFound; + + @Getter(AccessLevel.PACKAGE) + private int emeraldsFound; + + @Getter(AccessLevel.PACKAGE) + private int sapphiresFound; + + public void incrementGemFound(int gemID) + { + lastGemFound = Instant.now(); + + switch (gemID) + { + case ItemID.UNCUT_DIAMOND: + diamondsFound++; + break; + + case ItemID.UNCUT_RUBY: + rubiesFound++; + break; + + case ItemID.UNCUT_EMERALD: + emeraldsFound++; + break; + + case ItemID.UNCUT_SAPPHIRE: + sapphiresFound++; + break; + + default: + log.error("Invalid gem type specified. The gem count will not be incremented."); + } + } + + public void incrementPayDirtMined() + { + Instant now = Instant.now(); + + lastPayDirtMined = now; + ++totalMined; + + if (recentMined == 0) + { + recentPayDirtMined = now; + } + ++recentMined; + + Duration timeSinceStart = Duration.between(recentPayDirtMined, now); + if (!timeSinceStart.isZero()) + { + perHour = (int) ((double) recentMined * (double) HOUR.toMillis() / (double) timeSinceStart.toMillis()); + } + } + + public void resetRecent() + { + recentPayDirtMined = null; + recentMined = 0; + } + + public int getPerHour() + { + return perHour; + } + + public Instant getLastPayDirtMined() + { + return lastPayDirtMined; + } + + public int getTotalMined() + { + return totalMined; + } + + public Instant getRecentPayDirtMined() + { + return recentPayDirtMined; + } + + public int getRecentMined() + { + return recentMined; + } +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/motherlode/MotherlodeOverlay.java b/runelite-client/src/main/java/net/runelite/client/plugins/motherlode/MotherlodeOverlay.java index 8a2ad81cdf..d1811106c9 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/motherlode/MotherlodeOverlay.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/motherlode/MotherlodeOverlay.java @@ -1,124 +1,133 @@ -/* - * Copyright (c) 2018, Seth - * 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.motherlode; - -import com.google.common.collect.ImmutableSet; -import java.awt.Color; -import java.awt.Dimension; -import java.awt.Graphics2D; -import java.time.Duration; -import java.time.Instant; -import java.util.Set; -import javax.inject.Inject; -import static net.runelite.api.AnimationID.*; -import net.runelite.api.Client; -import net.runelite.client.ui.overlay.Overlay; -import net.runelite.client.ui.overlay.OverlayPosition; -import net.runelite.client.ui.overlay.components.LineComponent; -import net.runelite.client.ui.overlay.components.PanelComponent; -import net.runelite.client.ui.overlay.components.TitleComponent; - -class MotherlodeOverlay extends Overlay -{ - private static final Set MINING_ANIMATION_IDS = ImmutableSet.of( - MINING_MOTHERLODE_BRONZE, MINING_MOTHERLODE_IRON, MINING_MOTHERLODE_STEEL, - MINING_MOTHERLODE_BLACK, MINING_MOTHERLODE_MITHRIL, MINING_MOTHERLODE_ADAMANT, - MINING_MOTHERLODE_RUNE, MINING_MOTHERLODE_DRAGON, MINING_MOTHERLODE_DRAGON_ORN, - MINING_MOTHERLODE_INFERNAL - ); - - private final Client client; - private final MotherlodePlugin plugin; - private final MotherlodeSession motherlodeSession; - private final MotherlodeConfig config; - private final PanelComponent panelComponent = new PanelComponent(); - - @Inject - MotherlodeOverlay(Client client, MotherlodePlugin plugin, MotherlodeSession motherlodeSession, MotherlodeConfig config) - { - super(plugin); - setPosition(OverlayPosition.TOP_LEFT); - this.client = client; - this.plugin = plugin; - this.motherlodeSession = motherlodeSession; - this.config = config; - } - - @Override - public Dimension render(Graphics2D graphics) - { - if (!plugin.isInMlm() || !config.showMiningStats()) - { - return null; - } - - MotherlodeSession session = motherlodeSession; - - if (session.getLastPayDirtMined() == null) - { - return null; - } - - Duration statTimeout = Duration.ofMinutes(config.statTimeout()); - Duration sinceCut = Duration.between(session.getLastPayDirtMined(), Instant.now()); - - if (sinceCut.compareTo(statTimeout) >= 0) - { - return null; - } - - panelComponent.getChildren().clear(); - - if (config.showMiningState()) - { - if (MINING_ANIMATION_IDS.contains(client.getLocalPlayer().getAnimation())) - { - panelComponent.getChildren().add(TitleComponent.builder() - .text("Mining") - .color(Color.GREEN) - .build()); - } - else - { - panelComponent.getChildren().add(TitleComponent.builder() - .text("NOT mining") - .color(Color.RED) - .build()); - } - } - - panelComponent.getChildren().add(LineComponent.builder() - .left("Pay-dirt mined:") - .right(Integer.toString(session.getTotalMined())) - .build()); - - panelComponent.getChildren().add(LineComponent.builder() - .left("Pay-dirt/hr:") - .right(session.getRecentMined() > 2 ? Integer.toString(session.getPerHour()) : "") - .build()); - - return panelComponent.render(graphics); - } -} +/* + * Copyright (c) 2018, Seth + * 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.motherlode; + +import com.google.common.collect.ImmutableSet; +import java.awt.Color; +import java.awt.Dimension; +import java.awt.Graphics2D; +import java.time.Duration; +import java.time.Instant; +import java.util.Set; +import javax.inject.Inject; +import static net.runelite.api.AnimationID.MINING_MOTHERLODE_ADAMANT; +import static net.runelite.api.AnimationID.MINING_MOTHERLODE_BLACK; +import static net.runelite.api.AnimationID.MINING_MOTHERLODE_BRONZE; +import static net.runelite.api.AnimationID.MINING_MOTHERLODE_DRAGON; +import static net.runelite.api.AnimationID.MINING_MOTHERLODE_DRAGON_ORN; +import static net.runelite.api.AnimationID.MINING_MOTHERLODE_INFERNAL; +import static net.runelite.api.AnimationID.MINING_MOTHERLODE_IRON; +import static net.runelite.api.AnimationID.MINING_MOTHERLODE_MITHRIL; +import static net.runelite.api.AnimationID.MINING_MOTHERLODE_RUNE; +import static net.runelite.api.AnimationID.MINING_MOTHERLODE_STEEL; +import net.runelite.api.Client; +import net.runelite.client.ui.overlay.Overlay; +import net.runelite.client.ui.overlay.OverlayPosition; +import net.runelite.client.ui.overlay.components.LineComponent; +import net.runelite.client.ui.overlay.components.PanelComponent; +import net.runelite.client.ui.overlay.components.TitleComponent; + +class MotherlodeOverlay extends Overlay +{ + private static final Set MINING_ANIMATION_IDS = ImmutableSet.of( + MINING_MOTHERLODE_BRONZE, MINING_MOTHERLODE_IRON, MINING_MOTHERLODE_STEEL, + MINING_MOTHERLODE_BLACK, MINING_MOTHERLODE_MITHRIL, MINING_MOTHERLODE_ADAMANT, + MINING_MOTHERLODE_RUNE, MINING_MOTHERLODE_DRAGON, MINING_MOTHERLODE_DRAGON_ORN, + MINING_MOTHERLODE_INFERNAL + ); + + private final Client client; + private final MotherlodePlugin plugin; + private final MotherlodeSession motherlodeSession; + private final MotherlodeConfig config; + private final PanelComponent panelComponent = new PanelComponent(); + + @Inject + MotherlodeOverlay(Client client, MotherlodePlugin plugin, MotherlodeSession motherlodeSession, MotherlodeConfig config) + { + super(plugin); + setPosition(OverlayPosition.TOP_LEFT); + this.client = client; + this.plugin = plugin; + this.motherlodeSession = motherlodeSession; + this.config = config; + } + + @Override + public Dimension render(Graphics2D graphics) + { + if (!plugin.isInMlm() || !config.showMiningStats()) + { + return null; + } + + MotherlodeSession session = motherlodeSession; + + if (session.getLastPayDirtMined() == null) + { + return null; + } + + Duration statTimeout = Duration.ofMinutes(config.statTimeout()); + Duration sinceCut = Duration.between(session.getLastPayDirtMined(), Instant.now()); + + if (sinceCut.compareTo(statTimeout) >= 0) + { + return null; + } + + panelComponent.getChildren().clear(); + + if (config.showMiningState()) + { + if (MINING_ANIMATION_IDS.contains(client.getLocalPlayer().getAnimation())) + { + panelComponent.getChildren().add(TitleComponent.builder() + .text("Mining") + .color(Color.GREEN) + .build()); + } + else + { + panelComponent.getChildren().add(TitleComponent.builder() + .text("NOT mining") + .color(Color.RED) + .build()); + } + } + + panelComponent.getChildren().add(LineComponent.builder() + .left("Pay-dirt mined:") + .right(Integer.toString(session.getTotalMined())) + .build()); + + panelComponent.getChildren().add(LineComponent.builder() + .left("Pay-dirt/hr:") + .right(session.getRecentMined() > 2 ? Integer.toString(session.getPerHour()) : "") + .build()); + + return panelComponent.render(graphics); + } +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/motherlode/MotherlodeRocksOverlay.java b/runelite-client/src/main/java/net/runelite/client/plugins/motherlode/MotherlodeRocksOverlay.java index e49ae1006d..e80b967168 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/motherlode/MotherlodeRocksOverlay.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/motherlode/MotherlodeRocksOverlay.java @@ -1,142 +1,140 @@ -/* - * Copyright (c) 2018, Seth - * Copyright (c) 2018, Adam - * Copyright (c) 2018, Lars - * 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.motherlode; - -import java.awt.Color; -import java.awt.Dimension; -import java.awt.Graphics2D; -import java.awt.Polygon; -import java.awt.image.BufferedImage; -import javax.inject.Inject; - -import ch.qos.logback.core.net.SyslogOutputStream; -import net.runelite.api.Client; -import net.runelite.api.GameObject; -import net.runelite.api.Perspective; -import net.runelite.api.Player; -import net.runelite.api.Point; -import net.runelite.api.Skill; -import net.runelite.api.WallObject; -import net.runelite.api.coords.LocalPoint; -import net.runelite.client.game.SkillIconManager; -import net.runelite.client.ui.overlay.Overlay; -import net.runelite.client.ui.overlay.OverlayLayer; -import net.runelite.client.ui.overlay.OverlayPosition; -import net.runelite.client.ui.overlay.OverlayUtil; - -class MotherlodeRocksOverlay extends Overlay -{ - private static final int MAX_DISTANCE = 2350; - - private final Client client; - private final MotherlodePlugin plugin; - private final MotherlodeConfig config; - - private final BufferedImage miningIcon; - - @Inject - MotherlodeRocksOverlay(Client client, MotherlodePlugin plugin, MotherlodeConfig config, SkillIconManager iconManager) - { - setPosition(OverlayPosition.DYNAMIC); - setLayer(OverlayLayer.ABOVE_SCENE); - this.client = client; - this.plugin = plugin; - this.config = config; - - miningIcon = iconManager.getSkillImage(Skill.MINING); - } - - @Override - public Dimension render(Graphics2D graphics) - { - if ((!config.showVeins() && !config.showRockFalls()) || !plugin.isInMlm()) - { - return null; - } - - Player local = client.getLocalPlayer(); - - renderTiles(graphics, local); - - return null; - } - - private void renderTiles(Graphics2D graphics, Player local) - { - LocalPoint localLocation = local.getLocalLocation(); - - if (config.showVeins()) - { - for (WallObject vein : plugin.getVeins()) - { - LocalPoint location = vein.getLocalLocation(); - if (localLocation.distanceTo(location) <= MAX_DISTANCE) - { - // Only draw veins on the same level - if (plugin.isUpstairs(localLocation) == plugin.isUpstairs(vein.getLocalLocation())) - { - renderVein(graphics, vein); - } - } - } - } - - if (config.showRockFalls()) - { - for (GameObject rock : plugin.getRocks()) - { - LocalPoint location = rock.getLocalLocation(); - if (localLocation.distanceTo(location) <= MAX_DISTANCE) - { - plugin.checkMining(); - renderRock(graphics, rock); - } - } - } - - } - - private void renderVein(Graphics2D graphics, WallObject vein) - { - Point canvasLoc = Perspective.getCanvasImageLocation(client, vein.getLocalLocation(), miningIcon, 150); - - if (canvasLoc != null) - { - graphics.drawImage(miningIcon, canvasLoc.getX(), canvasLoc.getY(), null); - } - } - - private void renderRock(Graphics2D graphics, GameObject rock) - { - Polygon poly = Perspective.getCanvasTilePoly(client, rock.getLocalLocation()); - - if (poly != null) - { - OverlayUtil.renderPolygon(graphics, poly, Color.red); - } - } -} +/* + * Copyright (c) 2018, Seth + * Copyright (c) 2018, Adam + * Copyright (c) 2018, Lars + * 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.motherlode; + +import java.awt.Color; +import java.awt.Dimension; +import java.awt.Graphics2D; +import java.awt.Polygon; +import java.awt.image.BufferedImage; +import javax.inject.Inject; +import net.runelite.api.Client; +import net.runelite.api.GameObject; +import net.runelite.api.Perspective; +import net.runelite.api.Player; +import net.runelite.api.Point; +import net.runelite.api.Skill; +import net.runelite.api.WallObject; +import net.runelite.api.coords.LocalPoint; +import net.runelite.client.game.SkillIconManager; +import net.runelite.client.ui.overlay.Overlay; +import net.runelite.client.ui.overlay.OverlayLayer; +import net.runelite.client.ui.overlay.OverlayPosition; +import net.runelite.client.ui.overlay.OverlayUtil; + +class MotherlodeRocksOverlay extends Overlay +{ + private static final int MAX_DISTANCE = 2350; + + private final Client client; + private final MotherlodePlugin plugin; + private final MotherlodeConfig config; + + private final BufferedImage miningIcon; + + @Inject + MotherlodeRocksOverlay(Client client, MotherlodePlugin plugin, MotherlodeConfig config, SkillIconManager iconManager) + { + setPosition(OverlayPosition.DYNAMIC); + setLayer(OverlayLayer.ABOVE_SCENE); + this.client = client; + this.plugin = plugin; + this.config = config; + + miningIcon = iconManager.getSkillImage(Skill.MINING); + } + + @Override + public Dimension render(Graphics2D graphics) + { + if ((!config.showVeins() && !config.showRockFalls()) || !plugin.isInMlm()) + { + return null; + } + + Player local = client.getLocalPlayer(); + + renderTiles(graphics, local); + + return null; + } + + private void renderTiles(Graphics2D graphics, Player local) + { + LocalPoint localLocation = local.getLocalLocation(); + + if (config.showVeins()) + { + for (WallObject vein : plugin.getVeins()) + { + LocalPoint location = vein.getLocalLocation(); + if (localLocation.distanceTo(location) <= MAX_DISTANCE) + { + // Only draw veins on the same level + if (plugin.isUpstairs(localLocation) == plugin.isUpstairs(vein.getLocalLocation())) + { + renderVein(graphics, vein); + } + } + } + } + + if (config.showRockFalls()) + { + for (GameObject rock : plugin.getRocks()) + { + LocalPoint location = rock.getLocalLocation(); + if (localLocation.distanceTo(location) <= MAX_DISTANCE) + { + plugin.checkMining(); + renderRock(graphics, rock); + } + } + } + + } + + private void renderVein(Graphics2D graphics, WallObject vein) + { + Point canvasLoc = Perspective.getCanvasImageLocation(client, vein.getLocalLocation(), miningIcon, 150); + + if (canvasLoc != null) + { + graphics.drawImage(miningIcon, canvasLoc.getX(), canvasLoc.getY(), null); + } + } + + private void renderRock(Graphics2D graphics, GameObject rock) + { + Polygon poly = Perspective.getCanvasTilePoly(client, rock.getLocalLocation()); + + if (poly != null) + { + OverlayUtil.renderPolygon(graphics, poly, Color.red); + } + } +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/mta/graveyard/GraveyardRoom.java b/runelite-client/src/main/java/net/runelite/client/plugins/mta/graveyard/GraveyardRoom.java index aa4d16c738..8d823f40e8 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/mta/graveyard/GraveyardRoom.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/mta/graveyard/GraveyardRoom.java @@ -60,7 +60,7 @@ public class GraveyardRoom extends MTARoom @Inject private GraveyardRoom(MTAConfig config, Client client, MTAPlugin plugin, - ItemManager itemManager, InfoBoxManager infoBoxManager) + ItemManager itemManager, InfoBoxManager infoBoxManager) { super(config); this.client = client; diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/mta/telekinetic/TelekineticRoom.java b/runelite-client/src/main/java/net/runelite/client/plugins/mta/telekinetic/TelekineticRoom.java index 96d7847321..99ea9b777a 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/mta/telekinetic/TelekineticRoom.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/mta/telekinetic/TelekineticRoom.java @@ -134,8 +134,8 @@ public class TelekineticRoom extends MTARoom public void onGameTick(GameTick event) { if (!config.telekinetic() - || !inside() - || client.getGameState() != GameState.LOGGED_IN) + || !inside() + || client.getGameState() != GameState.LOGGED_IN) { maze = null; moves.clear(); @@ -374,7 +374,7 @@ public class TelekineticRoom extends MTARoom WorldPoint nghbWorld = WorldPoint.fromLocal(client, neighbour); if (!nghbWorld.equals(next) - && !closed.contains(nghbWorld)) + && !closed.contains(nghbWorld)) { int score = scores.get(next) + 1; @@ -426,10 +426,10 @@ public class TelekineticRoom extends MTARoom private LocalPoint[] neighbours(LocalPoint point) { return new LocalPoint[] - { - neighbour(point, Direction.NORTH), neighbour(point, Direction.SOUTH), - neighbour(point, Direction.EAST), neighbour(point, Direction.WEST) - }; + { + neighbour(point, Direction.NORTH), neighbour(point, Direction.SOUTH), + neighbour(point, Direction.EAST), neighbour(point, Direction.WEST) + }; } private LocalPoint neighbour(LocalPoint point, Direction direction) diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/multiindicators/MapLocations.java b/runelite-client/src/main/java/net/runelite/client/plugins/multiindicators/MapLocations.java index 09cdabf83f..61c1474cbc 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/multiindicators/MapLocations.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/multiindicators/MapLocations.java @@ -1,3479 +1,3479 @@ -/* - * Copyright (c) 2018, Woox - * 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.multiindicators; - -import java.awt.Polygon; -import java.awt.Rectangle; -import java.awt.Shape; -import java.awt.geom.Area; -import java.util.ArrayList; -import java.util.List; -import net.runelite.api.Constants; - -public class MapLocations -{ - private static final List[] MULTICOMBAT = new List[Constants.MAX_Z]; - private static final List[] NOT_MULTICOMBAT = new List[Constants.MAX_Z]; - private static final List[] ROUGH_WILDERNESS = new List[Constants.MAX_Z]; - private static final List[] DEADMAN_SAFE_ZONES = new List[Constants.MAX_Z]; - private static final List[] PVP_WORLD_SAFE_ZONES = new List[Constants.MAX_Z]; - - private static Area getArea(List shapes) - { - Area area = new Area(); - for (Shape shape : shapes) - { - area.add(new Area(shape)); - } - return area; - } - - private static Area getArea(List shapes, Rectangle view) - { - Area area = new Area(); - for (Shape shape : shapes) - { - if (shape.intersects(view)) - { - area.add(new Area(shape)); - } - } - return area; - } - - public static Area getMulticombat(int plane) - { - Area area = getArea(MULTICOMBAT[plane]); - area.subtract(getArea(NOT_MULTICOMBAT[plane])); - return area; - } - - public static Area getMulticombat(Rectangle view, int plane) - { - Area area = getArea(MULTICOMBAT[plane], view); - area.subtract(getArea(NOT_MULTICOMBAT[plane], view)); - return area; - } - - public static Area getRoughWilderness(int plane) - { - return getArea(ROUGH_WILDERNESS[plane]); - } - - public static Area getRoughWilderness(Rectangle view, int plane) - { - return getArea(ROUGH_WILDERNESS[plane], view); - } - - public static Area getDeadmanSafeZones(int plane) - { - return getArea(DEADMAN_SAFE_ZONES[plane]); - } - - public static Area getDeadmanSafeZones(Rectangle view, int plane) - { - return getArea(DEADMAN_SAFE_ZONES[plane], view); - } - - public static Area getPvpSafeZones(int plane) - { - return getArea(PVP_WORLD_SAFE_ZONES[plane]); - } - - public static Area getPvpSafeZones(Rectangle view, int plane) - { - return getArea(PVP_WORLD_SAFE_ZONES[plane], view); - } - - static - { - for (int i = 0; i < MULTICOMBAT.length; i++) - { - MULTICOMBAT[i] = new ArrayList<>(); - } - for (int i = 0; i < NOT_MULTICOMBAT.length; i++) - { - NOT_MULTICOMBAT[i] = new ArrayList<>(); - } - for (int i = 0; i < ROUGH_WILDERNESS.length; i++) - { - ROUGH_WILDERNESS[i] = new ArrayList<>(); - } - for (int i = 0; i < DEADMAN_SAFE_ZONES.length; i++) - { - DEADMAN_SAFE_ZONES[i] = new ArrayList<>(); - } - for (int i = 0; i < PVP_WORLD_SAFE_ZONES.length; i++) - { - PVP_WORLD_SAFE_ZONES[i] = new ArrayList<>(); - } - - defineMulticombatAreas(); - defineDeadmanSafeZones(); - definePvpSafeZones(); - defineWilderness(); - } - - private static void defineMulticombatAreas() - { - // Main Wilderness - addPolygonOnPlane(MULTICOMBAT, 0, - 3200, 3968, - 3392, 3968, - 3392, 3840, - 3328, 3840, - 3328, 3520, - 3136, 3520, - 3136, 3648, - 3192, 3648, - 3192, 3752, - 3152, 3752, - 3152, 3840, - 3136, 3840, - 3136, 3872, - 3112, 3872, - 3112, 3880, - 3072, 3880, - 3072, 3896, - 3048, 3896, - 3048, 3872, - 3056, 3872, - 3056, 3864, - 3048, 3864, - 3048, 3856, - 3008, 3856, - 3008, 3904, - 3200, 3904); - - // South of wildy agility training arena - addPolygonOnPlane(MULTICOMBAT, 0, - 2984, 3928, - 3008, 3928, - 3008, 3912, - 2984, 3912); - - // Wildy zamorak temple - addPolygonOnPlane(MULTICOMBAT, 0, - 2944, 3832, - 2960, 3832, - 2960, 3816, - 2944, 3816); - - // Wildy bandit camp - addPolygonOnPlane(MULTICOMBAT, 0, - 3008, 3712, - 3072, 3712, - 3072, 3600, - 3008, 3600); - - // Chaos temple north of Falador - addPolygonOnPlane(MULTICOMBAT, 0, - 2928, 3520, - 2944, 3520, - 2944, 3512, - 2928, 3512); - - // Burthorpe - addPolygonOnPlane(MULTICOMBAT, 0, - 2880, 3544, - 2904, 3544, - 2904, 3520, - 2880, 3520); - - // White Wolf Mountain - addPolygonOnPlane(MULTICOMBAT, 0, - 2880, 3520, - 2816, 3520, - 2816, 3456, - 2880, 3456); - - // Death Plateu - addPolygonOnPlane(MULTICOMBAT, 0, - 2848, 3608, - 2880, 3608, - 2880, 3600, - 2848, 3600); - - // Trollheim/Godwars - addPolygonOnPlane(MULTICOMBAT, 0, - 2880, 3776, - 2912, 3776, - 2912, 3696, - 2920, 3696, - 2920, 3688, - 2896, 3688, - 2896, 3696, - 2880, 3696, - 2880, 3728, - 2888, 3728, - 2888, 3744, - 2880, 3744); - - // Northen Rellekka - addPolygonOnPlane(MULTICOMBAT, 0, - 2656, 3736, - 2704, 3736, - 2704, 3728, - 2712, 3728, - 2712, 3736, - 2736, 3736, - 2736, 3712, - 2656, 3712); - - // Northen Fremennik Isles - addPolygonOnPlane(MULTICOMBAT, 0, - 2304, 3904, - 2432, 3904, - 2432, 3840, - 2368, 3840, - 2368, 3816, - 2352, 3816, - 2352, 3824, - 2304, 3824); - - // Pirates Cove - addPolygonOnPlane(MULTICOMBAT, 0, - 2176, 3840, - 2240, 3840, - 2240, 3776, - 2176, 3776); - - // Lunar Isle - addPolygonOnPlane(MULTICOMBAT, 0, - 2048, 3968, - 2176, 3968, - 2176, 3840, - 2048, 3840); - - // Piscatoris Fishing Colony - addPolygonOnPlane(MULTICOMBAT, 0, - 2304, 3712, - 2368, 3712, - 2368, 3648, - 2304, 3648); - - // Ranging Guild - addPolygonOnPlane(MULTICOMBAT, 0, - 2656, 3448, - 2680, 3448, - 2680, 3440, - 2688, 3440, - 2688, 3416, - 2680, 3416, - 2680, 3408, - 2656, 3408, - 2656, 3416, - 2648, 3416, - 2648, 3440, - 2656, 3440); - - // Necromancer house, southeast of Ardy - addPolygonOnPlane(MULTICOMBAT, 0, - 2656, 3256, - 2680, 3256, - 2680, 3216, - 2664, 3216, - 2664, 3232, - 2656, 3232); - - // Battlefield noth of Tree Gnome Village - addPolygonOnPlane(MULTICOMBAT, 0, - 2504, 3248, - 2544, 3248, - 2544, 3232, - 2552, 3232, - 2552, 3208, - 2504, 3208); - - // Castle Wars - addPolygonOnPlane(MULTICOMBAT, 0, - 2368, 3136, - 2432, 3136, - 2432, 3072, - 2368, 3072); - - // Jiggig - addPolygonOnPlane(MULTICOMBAT, 0, - 2456, 3056, - 2496, 3056, - 2496, 3032, - 2456, 3032); - - // East feldip hills, near rantz - addPolygonOnPlane(MULTICOMBAT, 0, - 2648, 2976, - 2656, 2976, - 2656, 2952, - 2648, 2952); - - // Ape Atoll - addPolygonOnPlane(MULTICOMBAT, 0, - 2688, 2816, - 2816, 2816, - 2816, 2688, - 2688, 2688); - - // Pest Control - addPolygonOnPlane(MULTICOMBAT, 0, - 2624, 2624, - 2688, 2624, - 2688, 2560, - 2624, 2560); - - // Desert Bandit Camp - addPolygonOnPlane(MULTICOMBAT, 0, - 3152, 3000, - 3192, 3000, - 3192, 2960, - 3152, 2960); - - // Al Kharid - addPolygonOnPlane(MULTICOMBAT, 0, - 3264, 3200, - 3328, 3200, - 3328, 3136, - 3264, 3136); - - // Wizards Tower - addPolygonOnPlane(MULTICOMBAT, 0, - 3094, 3176, - 3126, 3176, - 3126, 3144, - 3094, 3144); - - // Draynor Village - addPolygonOnPlane(MULTICOMBAT, 0, - 3112, 3264, - 3136, 3264, - 3136, 3232, - 3104, 3232, - 3104, 3256, - 3112, 3256); - - // Falador - addPolygonOnPlane(MULTICOMBAT, 0, - 2944, 3456, - 3008, 3456, - 3008, 3328, - 3016, 3328, - 3016, 3304, - 2944, 3304); - - // Southwest fally castle isn't multicombat downstairs - addPolygonOnPlane(NOT_MULTICOMBAT, 0, - 2968, 3336, - 2968, 3328, - 2960, 3328, - 2960, 3336); - - // Barbarian Village - addPolygonOnPlane(MULTICOMBAT, 0, - 3072, 3456, - 3136, 3456, - 3136, 3392, - 3048, 3392, - 3048, 3408, - 3056, 3408, - 3056, 3440, - 3064, 3440, - 3064, 3448, - 3072, 3448); - - // Ammoniate crabs at northwest fossil island - addPolygonOnPlane(MULTICOMBAT, 0, - 3648, 3885, - 3663, 3885, - 3663, 3882, - 3664, 3882, - 3664, 3872, - 3663, 3872, - 3663, 3868, - 3648, 3868); - - // Ammoniate crabs at north fossil island - addPolygonOnPlane(MULTICOMBAT, 0, - 3680, 3904, - 3744, 3904, - 3744, 3856, - 3756, 3856, - 3756, 3852, - 3755, 3852, - 3755, 3851, - 3754, 3851, - 3754, 3850, - 3751, 3850, - 3751, 3849, - 3750, 3849, - 3750, 3848, - 3749, 3848, - 3749, 3847, - 3748, 3847, - 3748, 3846, - 3747, 3846, - 3747, 3845, - 3746, 3845, - 3746, 3844, - 3742, 3844, - 3742, 3845, - 3740, 3845, - 3740, 3844, - 3732, 3844, - 3732, 3843, - 3730, 3843, - 3730, 3842, - 3724, 3842, - 3724, 3843, - 3717, 3843, - 3717, 3842, - 3712, 3842, - 3712, 3846, - 3710, 3846, - 3710, 3847, - 3709, 3847, - 3709, 3848, - 3708, 3848, - 3708, 3859, - 3709, 3859, - 3709, 3860, - 3710, 3860, - 3710, 3861, - 3712, 3861, - 3712, 3866, - 3713, 3866, - 3713, 3870, - 3714, 3870, - 3714, 3873, - 3713, 3873, - 3713, 3876, - 3712, 3876, - 3712, 3881, - 3710, 3881, - 3710, 3888, - 3712, 3888, - 3712, 3890, - 3714, 3890, - 3714, 3891, - 3716, 3891, - 3716, 3892, - 3717, 3892, - 3717, 3893, - 3716, 3893, - 3716, 3894, - 3714, 3894, - 3714, 3895, - 3713, 3895, - 3713, 3896, - 3712, 3896, - 3712, 3897, - 3705, 3897, - 3705, 3898, - 3704, 3898, - 3704, 3899, - 3692, 3899, - 3692, 3898, - 3688, 3898, - 3688, 3897, - 3686, 3897, - 3686, 3896, - 3680, 3896); - - // Zeah, southwest of Wintertodt, snowy area with ice giants and wolves - addPolygonOnPlane(MULTICOMBAT, 0, - 1540, 3898, - 1543, 3898, - 1543, 3901, - 1546, 3901, - 1546, 3903, - 1547, 3903, - 1547, 3904, - 1550, 3904, - 1550, 3903, - 1553, 3903, - 1553, 3904, - 1559, 3904, - 1559, 3902, - 1564, 3902, - 1564, 3903, - 1565, 3903, - 1565, 3904, - 1568, 3904, - 1568, 3903, - 1569, 3903, - 1569, 3902, - 1570, 3902, - 1570, 3901, - 1573, 3901, - 1573, 3898, - 1577, 3898, - 1577, 3899, - 1578, 3899, - 1578, 3902, - 1579, 3902, - 1579, 3903, - 1584, 3903, - 1584, 3902, - 1586, 3902, - 1586, 3901, - 1590, 3901, - 1590, 3891, - 1588, 3891, - 1588, 3887, - 1572, 3887, - 1572, 3872, - 1567, 3872, - 1567, 3868, - 1563, 3868, - 1563, 3867, - 1558, 3867, - 1558, 3868, - 1557, 3868, - 1557, 3870, - 1549, 3870, - 1549, 3874, - 1545, 3874, - 1545, 3876, - 1543, 3876, - 1543, 3877, - 1542, 3877, - 1542, 3879, - 1541, 3879, - 1541, 3882, - 1539, 3882, - 1539, 3887, - 1540, 3887, - 1540, 3888, - 1539, 3888, - 1539, 3894, - 1540, 3894); - - // Zeah arceuus area - addPolygonOnPlane(MULTICOMBAT, 0, - 1664, 3776, - 1664, 3785, - 1667, 3785, - 1667, 3805, - 1671, 3805, - 1671, 3811, - 1675, 3811, - 1675, 3819, - 1690, 3819, - 1690, 3814, - 1695, 3814, - 1695, 3806, - 1719, 3806, - 1719, 3787, - 1725, 3787, - 1725, 3778, - 1711, 3778, - 1711, 3776); - - // Arceuus teletab-making house - addPolygonOnPlane(MULTICOMBAT, 0, - 1667, 3772, - 1679, 3772, - 1679, 3775, - 1691, 3775, - 1691, 3761, - 1679, 3761, - 1679, 3764, - 1667, 3764); - // Next house east - addPolygonOnPlane(MULTICOMBAT, 0, - 1696, 3775, - 1708, 3775, - 1708, 3763, - 1696, 3763); - // Next house east - addPolygonOnPlane(MULTICOMBAT, 0, - 1713, 3775, - 1727, 3775, - 1727, 3763, - 1724, 3763, - 1724, 3752, - 1716, 3752, - 1716, 3763, - 1713, 3763); - // Arceuus rune shop house - addPolygonOnPlane(MULTICOMBAT, 0, - 1716, 3750, - 1728, 3750, - 1728, 3736, - 1716, 3736); - // Arceuus general store house - addPolygonOnPlane(MULTICOMBAT, 0, - 1717, 3732, - 1725, 3732, - 1725, 3715, - 1715, 3715, - 1715, 3725, - 1717, 3725); - // Arceuus pub - addPolygonOnPlane(MULTICOMBAT, 0, - 1683, 3732, - 1691, 3732, - 1691, 3725, - 1697, 3725, - 1697, 3730, - 1703, 3730, - 1703, 3712, - 1683, 3712); - // Arceuus staff store - addPolygonOnPlane(MULTICOMBAT, 0, - 1664, 3732, - 1676, 3732, - 1676, 3720, - 1664, 3720); - // Next house to the west - addPolygonOnPlane(MULTICOMBAT, 0, - 1647, 3738, - 1655, 3738, - 1655, 3726, - 1658, 3726, - 1658, 3714, - 1644, 3714, - 1644, 3726, - 1647, 3726); - // Next house to the north - addPolygonOnPlane(MULTICOMBAT, 0, - 1647, 3762, - 1657, 3762, - 1657, 3752, - 1655, 3752, - 1655, 3745, - 1647, 3745); - - // Arceuus house magic trees - addPolygonOnPlane(MULTICOMBAT, 0, - 1682, 3755, - 1692, 3755, - 1692, 3745, - 1690, 3745, - 1690, 3738, - 1682, 3738); - // West of that ^ - addPolygonOnPlane(MULTICOMBAT, 0, - 1667, 3756, - 1675, 3756, - 1675, 3740, - 1665, 3740, - 1665, 3746, - 1667, 3746); - - // This one goes through western piscarilius, northen hosidius - // and southwestern arceuus - addPolygonOnPlane(MULTICOMBAT, 0, - 1728, 3808, - 1792, 3808, - 1792, 3764, - 1856, 3764, - 1856, 3712, - 1792, 3712, - 1792, 3648, - 1664, 3648, - 1664, 3706, - 1665, 3706, - 1665, 3705, - 1668, 3705, - 1668, 3706, - 1671, 3706, - 1671, 3705, - 1675, 3705, - 1675, 3704, - 1683, 3704, - 1683, 3701, - 1684, 3701, - 1684, 3700, - 1686, 3700, - 1686, 3702, - 1687, 3702, - 1687, 3700, - 1688, 3700, - 1688, 3701, - 1690, 3701, - 1690, 3703, - 1689, 3703, - 1689, 3704, - 1690, 3704, - 1690, 3705, - 1704, 3705, - 1704, 3707, - 1706, 3707, - 1706, 3712, - 1711, 3712, - 1711, 3711, - 1710, 3711, - 1710, 3710, - 1712, 3710, - 1712, 3707, - 1728, 3707); - - // Kourend castle - addPolygonOnPlane(MULTICOMBAT, 0, - 1614, 3691, - 1619, 3691, - 1619, 3690, - 1620, 3690, - 1620, 3689, - 1653, 3689, - 1653, 3690, - 1654, 3690, - 1654, 3691, - 1657, 3691, - 1657, 3690, - 1658, 3690, - 1658, 3689, - 1659, 3689, - 1659, 3686, - 1658, 3686, - 1658, 3685, - 1657, 3685, - 1657, 3662, - 1658, 3662, - 1658, 3661, - 1659, 3661, - 1659, 3658, - 1658, 3658, - 1658, 3657, - 1657, 3657, - 1657, 3656, - 1654, 3656, - 1654, 3657, - 1653, 3657, - 1653, 3658, - 1620, 3658, - 1620, 3657, - 1619, 3657, - 1619, 3656, - 1614, 3656, - 1614, 3657, - 1613, 3657, - 1613, 3661, - 1612, 3661, - 1612, 3662, - 1611, 3662, - 1611, 3663, - 1600, 3663, - 1600, 3662, - 1599, 3662, - 1599, 3661, - 1594, 3661, - 1594, 3662, - 1593, 3662, - 1593, 3685, - 1594, 3685, - 1594, 3686, - 1599, 3686, - 1599, 3685, - 1600, 3685, - 1600, 3684, - 1611, 3684, - 1611, 3685, - 1612, 3685, - 1612, 3686, - 1613, 3686, - 1613, 3690, - 1614, 3690); - - // Western hosidius area, including woodcutting guild and western sand crabs - addPolygonOnPlane(MULTICOMBAT, 0, - 1650, 3648, - 1664, 3648, - 1664, 3520, - 1689, 3520, - 1689, 3496, - 1707, 3496, - 1707, 3485, - 1708, 3485, - 1708, 3484, - 1710, 3484, - 1710, 3483, - 1713, 3483, - 1713, 3482, - 1720, 3482, - 1720, 3481, - 1721, 3481, - 1721, 3480, - 1722, 3480, - 1722, 3479, - 1723, 3479, - 1723, 3478, - 1724, 3478, - 1724, 3477, - 1726, 3477, - 1726, 3476, - 1728, 3476, - 1728, 3472, - 1708, 3472, - 1708, 3456, - 1600, 3456, - 1600, 3584, - 1608, 3584, - 1608, 3616, - 1650, 3616); - - // Hosidius sand crabs - addPolygonOnPlane(MULTICOMBAT, 0, - 1740, 3478, - 1741, 3478, - 1741, 3479, - 1745, 3479, - 1745, 3480, - 1751, 3480, - 1751, 3479, - 1752, 3479, - 1752, 3478, - 1753, 3478, - 1753, 3477, - 1755, 3477, - 1755, 3476, - 1757, 3476, - 1757, 3475, - 1758, 3475, - 1758, 3474, - 1759, 3474, - 1759, 3473, - 1779, 3473, - 1779, 3474, - 1781, 3474, - 1781, 3475, - 1786, 3475, - 1786, 3476, - 1800, 3476, - 1800, 3475, - 1805, 3475, - 1805, 3474, - 1807, 3474, - 1807, 3473, - 1808, 3473, - 1808, 3472, - 1810, 3472, - 1810, 3471, - 1833, 3471, - 1833, 3470, - 1834, 3470, - 1834, 3469, - 1852, 3469, - 1852, 3449, - 1792, 3449, - 1792, 3424, - 1800, 3424, - 1800, 3449, - 1800, 3400, - 1728, 3400, - 1728, 3462, - 1729, 3462, - 1729, 3466, - 1730, 3466, - 1730, 3469, - 1731, 3469, - 1731, 3470, - 1732, 3470, - 1732, 3471, - 1733, 3471, - 1733, 3473, - 1734, 3473, - 1734, 3474, - 1736, 3474, - 1736, 3475, - 1737, 3475, - 1737, 3476, - 1738, 3476, - 1738, 3477, - 1740, 3477); - - // Apparently there is a 1x1 single zone on the sand crab island - addPolygonOnPlane(NOT_MULTICOMBAT, 0, - 1777, 3416, - 1777, 3417, - 1778, 3417, - 1778, 3416); - - // Eastern hosidius area - addPolygonOnPlane(MULTICOMBAT, 0, - 1834, 3584, - 1888, 3584, - 1888, 3528, - 1856, 3528, - 1856, 3520, - 1834, 3520, - 1834, 3522, - 1833, 3522, - 1833, 3535, - 1834, 3535, - 1834, 3538, - 1835, 3538, - 1835, 3539, - 1836, 3539, - 1836, 3540, - 1837, 3540, - 1837, 3541, - 1838, 3541, - 1838, 3542, - 1840, 3542, - 1840, 3543, - 1841, 3543, - 1841, 3545, - 1842, 3545, - 1842, 3546, - 1844, 3546, - 1844, 3547, - 1845, 3547, - 1845, 3548, - 1851, 3548, - 1851, 3551, - 1853, 3551, - 1853, 3563, - 1851, 3563, - 1851, 3566, - 1847, 3566, - 1847, 3567, - 1845, 3567, - 1845, 3568, - 1844, 3568, - 1844, 3569, - 1843, 3569, - 1843, 3571, - 1842, 3571, - 1842, 3573, - 1841, 3573, - 1841, 3574, - 1840, 3574, - 1840, 3575, - 1839, 3575, - 1839, 3576, - 1838, 3576, - 1838, 3577, - 1837, 3577, - 1837, 3578, - 1836, 3578, - 1836, 3579, - 1835, 3579, - 1835, 3581, - 1834, 3581); - - // Eastern hosidius area also has a 1x1 multi area - addPolygonOnPlane(MULTICOMBAT, 0, - 1849, 3563, - 1849, 3564, - 1850, 3564, - 1850, 3563); - - // Hosidius cows/chickens/pigs - addPolygonOnPlane(MULTICOMBAT, 0, - 1792, 3513, - 1802, 3513, - 1802, 3520, - 1810, 3520, - 1810, 3513, - 1816, 3513, - 1816, 3512, - 1836, 3512, - 1836, 3494, - 1796, 3494, - 1796, 3495, - 1792, 3495); - - // Hosidius southeast of tithe farm - addPolygonOnPlane(MULTICOMBAT, 0, - 1777, 3597, - 1794, 3597, - 1794, 3561, - 1777, 3561, - 1777, 3591, - 1779, 3591, - 1779, 3592, - 1777, 3592); - - // West of shayzien house - addPolygonOnPlane(MULTICOMBAT, 0, - 1408, 3584, - 1408, 3582, - 1486, 3582, - 1486, 3568, - 1528, 3568, - 1528, 3520, - 1408, 3520, - 1408, 3464, - 1380, 3464, - 1380, 3486, - 1377, 3486, - 1377, 3488, - 1373, 3488, - 1373, 3492, - 1364, 3492, - 1364, 3512, - 1358, 3512, - 1358, 3520, - 1356, 3520, - 1356, 3532, - 1358, 3532, - 1358, 3540, - 1359, 3540, - 1359, 3542, - 1360, 3542, - 1360, 3557, - 1356, 3557, - 1356, 3560, - 1351, 3560, - 1351, 3570, - 1354, 3570, - 1354, 3581, - 1346, 3581, - 1346, 3584); - - // South of chambers of xeric - addPolygonOnPlane(MULTICOMBAT, 0, - 1261, 3489, - 1259, 3489, - 1259, 3488, - 1255, 3488, - 1255, 3487, - 1243, 3487, - 1243, 3490, - 1234, 3490, - 1234, 3480, - 1192, 3480, - 1192, 3568, - 1209, 3568, - 1209, 3548, - 1215, 3548, - 1215, 3544, - 1217, 3544, - 1217, 3536, - 1235, 3536, - 1235, 3532, - 1249, 3532, - 1249, 3525, - 1248, 3525, - 1248, 3517, - 1254, 3517, - 1254, 3513, - 1274, 3513, - 1274, 3510, - 1296, 3510, - 1296, 3511, - 1300, 3511, - 1300, 3501, - 1287, 3501, - 1287, 3490, - 1280, 3490, - 1280, 3489, - 1264, 3489, - 1264, 3490, - 1261, 3490); - - // Lizardman shamans - addPolygonOnPlane(MULTICOMBAT, 0, - 1416, 3728, - 1456, 3728, - 1456, 3688, - 1416, 3688); - - // Other lizardman area at shayzien (west side) - addPolygonOnPlane(MULTICOMBAT, 0, - 1472, 3712, - 1510, 3712, - 1510, 3702, - 1509, 3702, - 1509, 3701, - 1506, 3701, - 1506, 3696, - 1500, 3696, - 1500, 3680, - 1472, 3680); - - // Other lizardman area at shayzien (east side) - addPolygonOnPlane(MULTICOMBAT, 0, - 1538, 3704, - 1560, 3704, - 1560, 3672, - 1538, 3672); - - // Lovakengj house - addPolygonOnPlane(MULTICOMBAT, 0, - 1600, 3712, - 1472, 3712, - 1472, 3840, - 1547, 3840, - 1547, 3816, - 1556, 3816, - 1556, 3809, - 1562, 3809, - 1562, 3800, - 1568, 3800, - 1568, 3793, - 1571, 3793, - 1571, 3816, - 1571, 3776, - 1600, 3776); - - // Shayzien house - addPolygonOnPlane(MULTICOMBAT, 0, - 1475, 3587, - 1475, 3641, - 1534, 3641, - 1534, 3587); - - // Shayzien house bank is non-multi - addPolygonOnPlane(NOT_MULTICOMBAT, 0, - 1495, 3622, - 1515, 3622, - 1515, 3612, - 1495, 3612); - - // Shayzien house general store - addPolygonOnPlane(MULTICOMBAT, 0, - 1539, 3640, - 1551, 3640, - 1551, 3621, - 1539, 3621); - - // Kourend woodland barbarian area - addPolygonOnPlane(MULTICOMBAT, 0, - 1572, 3442, - 1591, 3442, - 1591, 3424, - 1572, 3424); - - // Catacombs - addPolygonTo(MULTICOMBAT, - 1600, 9984, - 1600, 10067, - 1628, 10067, - 1628, 10070, - 1639, 10070, - 1639, 10112, - 1730, 10112, - 1730, 9984); - - // Zeah dungeon with sand crabs - addPolygonTo(MULTICOMBAT, - 1632, 9792, - 1632, 9856, - 1728, 9856, - 1728, 9792); - - // Waterbirth island near the doors where people use rune throwing axes - addPolygonTo(MULTICOMBAT, - 2536, 10136, - 2536, 10152, - 2552, 10152, - 2552, 10136); - - // Waterbirth island dungeon, on the path to dks - addPolygonTo(MULTICOMBAT, - 1792, 4352, - 1792, 4416, - 1984, 4416, - 1984, 4352); - - // Dagannoths in lighthouse - addPolygonTo(MULTICOMBAT, - 2496, 10048, - 2560, 10048, - 2560, 9984, - 2496, 9984); - - // Dagannoth kings (DKs) including slayer only dks - addPolygonTo(MULTICOMBAT, - 2944, 4352, - 2944, 4480, - 2880, 4480, - 2880, 4352); - - // White wolf mountain dungeon at ice queen - addPolygonTo(MULTICOMBAT, - 2856, 9928, - 2856, 9968, - 2880, 9968, - 2880, 9928); - - // Kharazi jungle dungeon (in dragon slayer 2 quest) - addPolygonTo(MULTICOMBAT, - 2816, 9296, - 2880, 9296, - 2880, 9216, - 2816, 9216); - - // Tzhaar, fight pits and inferno area - addPolygonTo(MULTICOMBAT, - 2368, 5184, - 2560, 5184, - 2560, 5056, - 2368, 5056); - - // Smoke devils - addPolygonTo(MULTICOMBAT, - 2432, 9408, - 2344, 9408, - 2344, 9472, - 2432, 9472); - - // Kraken - addPolygonTo(MULTICOMBAT, - 2270, 10045, - 2291, 10045, - 2291, 10022, - 2270, 10022); - - // Giant mole - addPolygonTo(MULTICOMBAT, - 1728, 5240, - 1792, 5240, - 1792, 5120, - 1728, 5120); - - // Godwars dungeon - addPolygonTo(MULTICOMBAT, - 2816, 5376, - 2944, 5376, - 2944, 5248, - 2816, 5248); - - // Desert treasure shadow diamond area - addPolygonTo(MULTICOMBAT, - 2752, 5064, - 2728, 5064, - 2728, 5088, - 2720, 5088, - 2720, 5096, - 2712, 5096, - 2712, 5112, - 2736, 5112, - 2736, 5120, - 2752, 5120); - - // Kalphite slayer area - addPolygonTo(MULTICOMBAT, - 3264, 9544, - 3344, 9544, - 3344, 9472, - 3264, 9472); - - // Normal kalphite area including kalphite queen - addPolygonTo(MULTICOMBAT, - 3456, 9536, - 3520, 9536, - 3520, 9472, - 3456, 9472); - - // Tarns lair - addPolygonTo(MULTICOMBAT, - 3136, 4664, - 3200, 4664, - 3200, 4544, - 3136, 4544); - - // Haunted mine boss area - addPolygonTo(MULTICOMBAT, - 2752, 4416, - 2752, 4480, - 2816, 4480, - 2816, 4416); - - // Entrance to dorgesh kaan - addPolygonTo(MULTICOMBAT, - 3328, 9600, - 3312, 9600, - 3312, 9640, - 3304, 9640, - 3304, 9664, - 3328, 9664); - - // Hammerspikes hangout in dwarven mines - addPolygonTo(MULTICOMBAT, - 2960, 9824, - 2976, 9824, - 2976, 9800, - 2960, 9800); - - // Fremennik isles dungeon - addPolygonTo(MULTICOMBAT, - 2432, 10304, - 2432, 10240, - 2368, 10240, - 2368, 10304); - - // Varrock sewers - addPolygonTo(MULTICOMBAT, - 3152, 9920, - 3288, 9920, - 3288, 9856, - 3152, 9856); - - // Stronghold of security 1st floor - addPolygonTo(MULTICOMBAT, - 1856, 5248, - 1920, 5248, - 1920, 5184, - 1856, 5184); - - // Corp cave - addPolygonTo(MULTICOMBAT, - 2960, 4400, - 3000, 4400, - 3000, 4368, - 2960, 4368); - - // ZMI altar area - addPolygonTo(MULTICOMBAT, - 3008, 5632, - 3072, 5632, - 3072, 5568, - 3008, 5568); - - // Dragon slayer 2 zeah underground puzzle - addPolygonTo(MULTICOMBAT, - 1472, 9984, - 1536, 9984, - 1536, 9920, - 1472, 9920); - - // Wildy revenant caves - addPolygonTo(MULTICOMBAT, - 3136, 10062, - 3136, 10240, - 3236, 10240, - 3236, 10229, - 3264, 10229, - 3264, 10048, - 3208, 10048, - 3208, 10062); - - // King black dragon (Kbd) - addPolygonTo(MULTICOMBAT, - 2240, 4672, - 2240, 4736, - 2304, 4736, - 2304, 4672); - - // Scorpia - addPolygonTo(MULTICOMBAT, - 3248, 10352, - 3248, 10328, - 3216, 10328, - 3216, 10352); - - // Inside mage bank - addPolygonTo(MULTICOMBAT, - 2496, 4672, - 2496, 4736, - 2560, 4736, - 2560, 4672); - - // Wildy godwars dungeon - addPolygonTo(MULTICOMBAT, - 3072, 10112, - 3008, 10112, - 3008, 10176, - 3048, 10176, - 3048, 10152, - 3056, 10152, - 3056, 10144, - 3064, 10144, - 3064, 10136, - 3072, 10136); - - // Enchanted valley - addPolygonTo(MULTICOMBAT, - 3008, 4480, - 3008, 4544, - 3072, 4544, - 3072, 4480); - - // Zulrah - addPolygonTo(MULTICOMBAT, - 2256, 3080, - 2280, 3080, - 2280, 3064, - 2256, 3064); - - // Abyssal sire and abyss - addPolygonTo(MULTICOMBAT, - 3008, 4736, - 2944, 4736, - 2944, 4864, - 3136, 4864, - 3136, 4736, - 3072, 4736, - 3072, 4800, - 3008, 4800); - } - - private static void defineDeadmanSafeZones() - { - // Varrock - addPolygonOnPlane(DEADMAN_SAFE_ZONES, 0, - 3182, 3382, - 3182, 3399, - 3174, 3399, - 3174, 3448, - 3198, 3448, - 3198, 3449, - 3197, 3449, - 3197, 3450, - 3196, 3450, - 3196, 3451, - 3195, 3451, - 3195, 3452, - 3194, 3452, - 3194, 3453, - 3193, 3453, - 3193, 3454, - 3192, 3454, - 3192, 3455, - 3191, 3455, - 3191, 3456, - 3190, 3456, - 3190, 3457, - 3185, 3457, - 3185, 3463, - 3186, 3463, - 3186, 3464, - 3187, 3464, - 3187, 3467, - 3167, 3467, - 3167, 3468, - 3163, 3468, - 3163, 3467, - 3142, 3467, - 3142, 3468, - 3141, 3468, - 3141, 3469, - 3140, 3469, - 3140, 3470, - 3139, 3470, - 3139, 3471, - 3138, 3471, - 3138, 3484, - 3139, 3484, - 3139, 3485, - 3140, 3485, - 3140, 3486, - 3141, 3486, - 3141, 3491, - 3140, 3491, - 3140, 3492, - 3139, 3492, - 3139, 3493, - 3138, 3493, - 3138, 3515, - 3139, 3515, - 3139, 3516, - 3140, 3516, - 3140, 3517, - 3141, 3517, - 3141, 3518, - 3160, 3518, - 3160, 3517, - 3161, 3517, - 3161, 3516, - 3162, 3516, - 3162, 3515, - 3167, 3515, - 3167, 3516, - 3168, 3516, - 3168, 3517, - 3169, 3517, - 3169, 3518, - 3191, 3518, - 3191, 3517, - 3192, 3517, - 3192, 3516, - 3193, 3516, - 3193, 3515, - 3194, 3515, - 3194, 3514, - 3195, 3514, - 3195, 3513, - 3196, 3513, - 3196, 3512, - 3197, 3512, - 3197, 3511, - 3198, 3511, - 3198, 3510, - 3199, 3510, - 3199, 3509, - 3200, 3509, - 3200, 3508, - 3230, 3508, - 3230, 3507, - 3231, 3507, - 3231, 3506, - 3232, 3506, - 3232, 3505, - 3233, 3505, - 3233, 3504, - 3234, 3504, - 3234, 3503, - 3235, 3503, - 3235, 3502, - 3252, 3502, - 3252, 3496, - 3253, 3496, - 3253, 3495, - 3254, 3495, - 3254, 3494, - 3255, 3494, - 3255, 3493, - 3263, 3493, - 3263, 3472, - 3264, 3472, - 3264, 3471, - 3265, 3471, - 3265, 3470, - 3266, 3470, - 3266, 3469, - 3267, 3469, - 3267, 3468, - 3268, 3468, - 3268, 3467, - 3269, 3467, - 3269, 3466, - 3270, 3466, - 3270, 3465, - 3271, 3465, - 3271, 3437, - 3274, 3437, - 3274, 3424, - 3277, 3424, - 3277, 3420, - 3274, 3420, - 3274, 3411, - 3275, 3411, - 3275, 3410, - 3276, 3410, - 3276, 3409, - 3277, 3409, - 3277, 3408, - 3288, 3408, - 3288, 3391, - 3289, 3391, - 3289, 3385, - 3290, 3385, - 3290, 3378, - 3289, 3378, - 3289, 3377, - 3288, 3377, - 3288, 3376, - 3265, 3376, - 3265, 3380, - 3253, 3380, - 3253, 3382, - 3245, 3382, - 3245, 3380, - 3242, 3380, - 3242, 3382, - 3239, 3382, - 3239, 3381, - 3209, 3381, - 3209, 3382, - 3282, 3382); - - // Lumbridge - addPolygonOnPlane(DEADMAN_SAFE_ZONES, 0, - 3201, 3257, - 3213, 3257, - 3213, 3264, - 3233, 3264, - 3233, 3257, - 3235, 3257, - 3235, 3241, - 3237, 3241, - 3237, 3237, - 3239, 3237, - 3239, 3231, - 3243, 3231, - 3243, 3220, - 3253, 3220, - 3253, 3217, - 3256, 3217, - 3256, 3212, - 3259, 3212, - 3259, 3190, - 3247, 3190, - 3247, 3191, - 3238, 3191, - 3238, 3195, - 3230, 3195, - 3230, 3201, - 3228, 3201, - 3228, 3202, - 3227, 3202, - 3227, 3205, - 3228, 3205, - 3228, 3207, - 3225, 3207, - 3225, 3206, - 3224, 3206, - 3224, 3205, - 3223, 3205, - 3223, 3204, - 3222, 3204, - 3222, 3203, - 3215, 3203, - 3215, 3202, - 3214, 3202, - 3214, 3201, - 3203, 3201, - 3203, 3202, - 3202, 3202, - 3202, 3203, - 3201, 3203, - 3201, 3217, - 3199, 3217, - 3199, 3220, - 3201, 3220); - - // Falador - addPolygonOnPlane(DEADMAN_SAFE_ZONES, 0, - 2986, 3395, - 2986, 3394, - 2987, 3394, - 2987, 3393, - 2996, 3393, - 2996, 3394, - 3002, 3394, - 3002, 3395, - 3009, 3395, - 3009, 3394, - 3010, 3394, - 3010, 3393, - 3011, 3393, - 3011, 3392, - 3021, 3392, - 3021, 3391, - 3022, 3391, - 3022, 3390, - 3041, 3390, - 3041, 3389, - 3047, 3389, - 3047, 3390, - 3062, 3390, - 3062, 3389, - 3063, 3389, - 3063, 3388, - 3064, 3388, - 3064, 3387, - 3065, 3387, - 3065, 3386, - 3066, 3386, - 3066, 3368, - 3065, 3368, - 3065, 3367, - 3064, 3367, - 3064, 3366, - 3063, 3366, - 3063, 3365, - 3062, 3365, - 3062, 3364, - 3061, 3364, - 3061, 3363, - 3060, 3363, - 3060, 3331, - 3061, 3331, - 3061, 3328, - 3058, 3328, - 3058, 3329, - 3025, 3329, - 3025, 3328, - 3024, 3328, - 3024, 3327, - 3016, 3327, - 3016, 3326, - 3015, 3326, - 3015, 3325, - 3014, 3325, - 3014, 3324, - 3013, 3324, - 3013, 3323, - 3008, 3323, - 3008, 3324, - 3006, 3324, - 3006, 3323, - 3002, 3323, - 3002, 3322, - 3001, 3322, - 3001, 3321, - 3000, 3321, - 3000, 3320, - 2999, 3320, - 2999, 3319, - 2998, 3319, - 2998, 3318, - 2997, 3318, - 2997, 3317, - 2996, 3317, - 2996, 3316, - 2992, 3316, - 2992, 3315, - 2991, 3315, - 2991, 3314, - 2990, 3314, - 2990, 3313, - 2989, 3313, - 2989, 3312, - 2988, 3312, - 2988, 3311, - 2987, 3311, - 2987, 3310, - 2986, 3310, - 2986, 3309, - 2966, 3309, - 2966, 3310, - 2956, 3310, - 2956, 3311, - 2941, 3311, - 2941, 3312, - 2940, 3312, - 2940, 3320, - 2936, 3320, - 2936, 3354, - 2937, 3354, - 2937, 3357, - 2936, 3357, - 2936, 3389, - 2937, 3389, - 2937, 3390, - 2938, 3390, - 2938, 3391, - 2939, 3391, - 2939, 3392, - 2940, 3392, - 2940, 3393, - 2943, 3393, - 2943, 3394, - 2944, 3394, - 2944, 3395, - 2950, 3395, - 2950, 3394, - 2956, 3394, - 2956, 3395); - - // Port phasmatys - addPolygonOnPlane(DEADMAN_SAFE_ZONES, 0, - 3650, 3456, - 3650, 3472, - 3651, 3472, - 3651, 3473, - 3652, 3473, - 3652, 3474, - 3653, 3474, - 3653, 3507, - 3654, 3507, - 3654, 3508, - 3668, 3508, - 3668, 3509, - 3669, 3509, - 3669, 3510, - 3670, 3510, - 3670, 3511, - 3671, 3511, - 3671, 3512, - 3672, 3512, - 3672, 3513, - 3673, 3513, - 3673, 3514, - 3674, 3514, - 3674, 3515, - 3675, 3515, - 3675, 3516, - 3676, 3516, - 3676, 3517, - 3687, 3517, - 3687, 3494, - 3690, 3494, - 3690, 3493, - 3696, 3493, - 3696, 3482, - 3699, 3482, - 3699, 3481, - 3712, 3481, - 3712, 3456); - - // Sophanem - addPolygonOnPlane(DEADMAN_SAFE_ZONES, 0, - 3274, 2752, - 3274, 2784, - 3277, 2784, - 3277, 2786, - 3274, 2786, - 3274, 2789, - 3272, 2789, - 3272, 2810, - 3322, 2810, - 3322, 2752); - - // Ardy - addPolygonOnPlane(DEADMAN_SAFE_ZONES, 0, - 2560, 3256, - 2560, 3264, - 2559, 3264, - 2559, 3328, - 2560, 3328, - 2560, 3339, - 2561, 3339, - 2561, 3340, - 2562, 3340, - 2562, 3341, - 2563, 3341, - 2563, 3342, - 2616, 3342, - 2616, 3341, - 2617, 3341, - 2617, 3340, - 2669, 3340, - 2669, 3339, - 2670, 3339, - 2670, 3338, - 2671, 3338, - 2671, 3337, - 2672, 3337, - 2672, 3336, - 2673, 3336, - 2673, 3335, - 2674, 3335, - 2674, 3334, - 2683, 3334, - 2683, 3333, - 2684, 3333, - 2684, 3332, - 2685, 3332, - 2685, 3331, - 2686, 3331, - 2686, 3330, - 2687, 3330, - 2687, 3329, - 2688, 3329, - 2688, 3264, - 2638, 3264, - 2638, 3263, - 2625, 3263, - 2625, 3264, - 2611, 3264, - 2611, 3257, - 2602, 3257, - 2602, 3264, - 2587, 3264, - 2587, 3263, - 2586, 3263, - 2586, 3262, - 2584, 3262, - 2584, 3261, - 2583, 3261, - 2583, 3260, - 2582, 3260, - 2582, 3259, - 2581, 3259, - 2581, 3258, - 2572, 3258, - 2572, 3260, - 2571, 3260, - 2571, 3261, - 2566, 3261, - 2566, 3260, - 2565, 3260, - 2565, 3259, - 2564, 3259, - 2564, 3256); - - // Yanille - addPolygonOnPlane(DEADMAN_SAFE_ZONES, 0, - 2613, 3103, - 2614, 3103, - 2614, 3102, - 2615, 3102, - 2615, 3101, - 2616, 3101, - 2616, 3100, - 2617, 3100, - 2617, 3099, - 2618, 3099, - 2618, 3098, - 2619, 3098, - 2619, 3097, - 2620, 3097, - 2620, 3075, - 2590, 3075, - 2590, 3074, - 2589, 3074, - 2589, 3073, - 2584, 3073, - 2584, 3074, - 2583, 3074, - 2583, 3075, - 2543, 3075, - 2543, 3076, - 2542, 3076, - 2542, 3077, - 2539, 3077, - 2539, 3107, - 2542, 3107, - 2542, 3108, - 2543, 3108, - 2543, 3109, - 2608, 3109, - 2608, 3108, - 2609, 3108, - 2609, 3107, - 2610, 3107, - 2610, 3106, - 2611, 3106, - 2611, 3105, - 2612, 3105, - 2612, 3104, - 2613, 3104); - - // Gnome stronghold - addPolygonOnPlane(DEADMAN_SAFE_ZONES, 0, - 2495, 3439, - 2494, 3439, - 2494, 3432, - 2495, 3432, - 2495, 3431, - 2496, 3431, - 2496, 3430, - 2497, 3430, - 2497, 3429, - 2498, 3429, - 2498, 3417, - 2497, 3417, - 2497, 3416, - 2496, 3416, - 2496, 3412, - 2495, 3412, - 2495, 3408, - 2494, 3408, - 2494, 3404, - 2495, 3404, - 2495, 3403, - 2496, 3403, - 2496, 3402, - 2497, 3402, - 2497, 3401, - 2498, 3401, - 2498, 3400, - 2499, 3400, - 2499, 3399, - 2500, 3399, - 2500, 3398, - 2501, 3398, - 2501, 3397, - 2502, 3397, - 2502, 3396, - 2506, 3396, - 2506, 3391, - 2502, 3391, - 2502, 3390, - 2492, 3390, - 2492, 3391, - 2489, 3391, - 2489, 3390, - 2488, 3390, - 2488, 3389, - 2485, 3389, - 2485, 3390, - 2482, 3390, - 2482, 3389, - 2476, 3389, - 2476, 3390, - 2471, 3390, - 2471, 3391, - 2468, 3391, - 2468, 3390, - 2467, 3390, - 2467, 3389, - 2466, 3389, - 2466, 3385, - 2465, 3385, - 2465, 3384, - 2458, 3384, - 2458, 3385, - 2457, 3385, - 2457, 3389, - 2456, 3389, - 2456, 3390, - 2455, 3390, - 2455, 3391, - 2450, 3391, - 2450, 3390, - 2446, 3390, - 2446, 3391, - 2443, 3391, - 2443, 3390, - 2442, 3390, - 2442, 3389, - 2440, 3389, - 2440, 3388, - 2434, 3388, - 2434, 3389, - 2433, 3389, - 2433, 3390, - 2432, 3390, - 2432, 3391, - 2428, 3391, - 2428, 3392, - 2427, 3392, - 2427, 3393, - 2420, 3393, - 2420, 3394, - 2419, 3394, - 2419, 3395, - 2418, 3395, - 2418, 3396, - 2417, 3396, - 2417, 3397, - 2416, 3397, - 2416, 3399, - 2415, 3399, - 2415, 3400, - 2414, 3400, - 2414, 3408, - 2413, 3408, - 2413, 3409, - 2412, 3409, - 2412, 3410, - 2411, 3410, - 2411, 3411, - 2410, 3411, - 2410, 3412, - 2387, 3412, - 2387, 3407, - 2383, 3407, - 2383, 3408, - 2380, 3408, - 2380, 3409, - 2379, 3409, - 2379, 3410, - 2377, 3410, - 2377, 3411, - 2376, 3411, - 2376, 3413, - 2375, 3413, - 2375, 3417, - 2374, 3417, - 2374, 3418, - 2373, 3418, - 2373, 3419, - 2372, 3419, - 2372, 3420, - 2371, 3420, - 2371, 3421, - 2370, 3421, - 2370, 3422, - 2369, 3422, - 2369, 3433, - 2370, 3433, - 2370, 3434, - 2371, 3434, - 2371, 3444, - 2372, 3444, - 2372, 3445, - 2373, 3445, - 2373, 3446, - 2374, 3446, - 2374, 3447, - 2375, 3447, - 2375, 3459, - 2376, 3459, - 2376, 3460, - 2377, 3460, - 2377, 3461, - 2378, 3461, - 2378, 3462, - 2379, 3462, - 2379, 3463, - 2380, 3463, - 2380, 3464, - 2381, 3464, - 2381, 3476, - 2379, 3476, - 2379, 3477, - 2378, 3477, - 2378, 3478, - 2377, 3478, - 2377, 3485, - 2376, 3485, - 2376, 3486, - 2375, 3486, - 2375, 3499, - 2376, 3499, - 2376, 3500, - 2377, 3500, - 2377, 3507, - 2378, 3507, - 2378, 3508, - 2379, 3508, - 2379, 3509, - 2380, 3509, - 2380, 3521, - 2382, 3521, - 2382, 3522, - 2384, 3522, - 2384, 3523, - 2393, 3523, - 2393, 3524, - 2399, 3524, - 2399, 3525, - 2404, 3525, - 2404, 3524, - 2405, 3524, - 2405, 3523, - 2407, 3523, - 2407, 3522, - 2415, 3522, - 2415, 3521, - 2425, 3521, - 2425, 3522, - 2427, 3522, - 2427, 3523, - 2430, 3523, - 2430, 3522, - 2431, 3522, - 2431, 3521, - 2432, 3521, - 2432, 3520, - 2448, 3520, - 2448, 3517, - 2454, 3517, - 2454, 3516, - 2455, 3516, - 2455, 3515, - 2456, 3515, - 2456, 3514, - 2457, 3514, - 2457, 3513, - 2460, 3513, - 2460, 3512, - 2461, 3512, - 2461, 3511, - 2465, 3511, - 2465, 3510, - 2468, 3510, - 2468, 3511, - 2472, 3511, - 2472, 3512, - 2473, 3512, - 2473, 3513, - 2475, 3513, - 2475, 3514, - 2476, 3514, - 2476, 3515, - 2477, 3515, - 2477, 3516, - 2478, 3516, - 2478, 3517, - 2483, 3517, - 2483, 3516, - 2487, 3516, - 2487, 3515, - 2488, 3515, - 2488, 3512, - 2487, 3512, - 2487, 3509, - 2488, 3509, - 2488, 3508, - 2489, 3508, - 2489, 3507, - 2491, 3507, - 2491, 3506, - 2492, 3506, - 2492, 3505, - 2493, 3505, - 2493, 3499, - 2492, 3499, - 2492, 3498, - 2491, 3498, - 2491, 3497, - 2490, 3497, - 2490, 3495, - 2491, 3495, - 2491, 3494, - 2492, 3494, - 2492, 3493, - 2493, 3493, - 2493, 3485, - 2490, 3485, - 2490, 3484, - 2489, 3484, - 2489, 3483, - 2488, 3483, - 2488, 3482, - 2487, 3482, - 2487, 3481, - 2486, 3481, - 2486, 3474, - 2488, 3474, - 2488, 3471, - 2489, 3471, - 2489, 3470, - 2490, 3470, - 2490, 3460, - 2491, 3460, - 2491, 3456, - 2496, 3456, - 2496, 3440, - 2495, 3440); - - // Rellekka - addPolygonOnPlane(DEADMAN_SAFE_ZONES, 0, - 2620, 3682, - 2624, 3682, - 2624, 3683, - 2625, 3683, - 2625, 3687, - 2629, 3687, - 2629, 3686, - 2630, 3686, - 2630, 3685, - 2632, 3685, - 2632, 3686, - 2636, 3686, - 2636, 3692, - 2645, 3692, - 2645, 3695, - 2647, 3695, - 2647, 3696, - 2649, 3696, - 2649, 3702, - 2650, 3702, - 2650, 3703, - 2651, 3703, - 2651, 3704, - 2652, 3704, - 2652, 3711, - 2653, 3711, - 2653, 3712, - 2691, 3712, - 2691, 3709, - 2692, 3709, - 2692, 3707, - 2693, 3707, - 2693, 3703, - 2692, 3703, - 2692, 3701, - 2691, 3701, - 2691, 3699, - 2690, 3699, - 2690, 3695, - 2691, 3695, - 2691, 3693, - 2692, 3693, - 2692, 3691, - 2693, 3691, - 2693, 3685, - 2692, 3685, - 2692, 3683, - 2691, 3683, - 2691, 3681, - 2690, 3681, - 2690, 3680, - 2689, 3680, - 2689, 3672, - 2690, 3672, - 2690, 3671, - 2691, 3671, - 2691, 3666, - 2690, 3666, - 2690, 3664, - 2689, 3664, - 2689, 3660, - 2690, 3660, - 2690, 3658, - 2691, 3658, - 2691, 3656, - 2692, 3656, - 2692, 3654, - 2693, 3654, - 2693, 3651, - 2692, 3651, - 2692, 3649, - 2690, 3649, - 2690, 3648, - 2688, 3648, - 2688, 3647, - 2686, 3647, - 2686, 3646, - 2673, 3646, - 2673, 3645, - 2636, 3645, - 2636, 3647, - 2627, 3647, - 2627, 3648, - 2625, 3648, - 2625, 3649, - 2624, 3649, - 2624, 3650, - 2622, 3650, - 2622, 3651, - 2620, 3651, - 2620, 3652, - 2618, 3652, - 2618, 3653, - 2616, 3653, - 2616, 3654, - 2609, 3654, - 2609, 3655, - 2607, 3655, - 2607, 3656, - 2603, 3656, - 2603, 3657, - 2602, 3657, - 2602, 3658, - 2601, 3658, - 2601, 3663, - 2602, 3663, - 2602, 3664, - 2603, 3664, - 2603, 3665, - 2604, 3665, - 2604, 3666, - 2605, 3666, - 2605, 3667, - 2606, 3667, - 2606, 3671, - 2609, 3671, - 2609, 3672, - 2610, 3672, - 2610, 3673, - 2611, 3673, - 2611, 3675, - 2612, 3675, - 2612, 3676, - 2614, 3676, - 2614, 3677, - 2616, 3677, - 2616, 3679, - 2618, 3679, - 2618, 3681, - 2620, 3681); - - // Jatizo - addPolygonOnPlane(DEADMAN_SAFE_ZONES, 0, - 2407, 3797, - 2407, 3793, - 2399, 3793, - 2399, 3792, - 2391, 3792, - 2391, 3791, - 2386, 3791, - 2386, 3796, - 2388, 3796, - 2388, 3802, - 2386, 3802, - 2386, 3807, - 2388, 3807, - 2388, 3809, - 2402, 3809, - 2402, 3819, - 2406, 3819, - 2406, 3824, - 2408, 3824, - 2408, 3826, - 2413, 3826, - 2413, 3824, - 2419, 3824, - 2419, 3826, - 2424, 3826, - 2424, 3821, - 2423, 3821, - 2423, 3798, - 2422, 3798, - 2422, 3797); - - // Neitiznot - addPolygonOnPlane(DEADMAN_SAFE_ZONES, 0, - 2329, 3812, - 2333, 3812, - 2333, 3813, - 2334, 3813, - 2334, 3814, - 2335, 3814, - 2335, 3815, - 2338, 3815, - 2338, 3816, - 2339, 3816, - 2339, 3817, - 2368, 3817, - 2368, 3776, - 2352, 3776, - 2352, 3796, - 2344, 3796, - 2344, 3795, - 2331, 3795, - 2331, 3797, - 2330, 3797, - 2330, 3798, - 2329, 3798); - - // Pest control - addPolygonOnPlane(DEADMAN_SAFE_ZONES, 0, - 2624, 2688, - 2688, 2688, - 2688, 2624, - 2624, 2624); - - // Tutorial island - addPolygonOnPlane(DEADMAN_SAFE_ZONES, 0, - 3052, 3135, - 3156, 3135, - 3156, 3057, - 3052, 3057); - - // Camelot bank - addPolygonOnPlane(DEADMAN_SAFE_ZONES, 0, - 2724, 3487, - 2724, 3490, - 2721, 3490, - 2721, 3494, - 2719, 3494, - 2719, 3497, - 2721, 3497, - 2721, 3498, - 2731, 3498, - 2731, 3490, - 2728, 3490, - 2728, 3487); - - // Catherby bank - addPolygonOnPlane(DEADMAN_SAFE_ZONES, 0, - 2806, 3438, - 2806, 3446, - 2813, 3446, - 2813, 3438); - - // Kourend castle - addPolygonOnPlane(DEADMAN_SAFE_ZONES, 0, - 1627, 3658, - 1620, 3658, - 1620, 3657, - 1619, 3657, - 1619, 3656, - 1614, 3656, - 1614, 3657, - 1613, 3657, - 1613, 3661, - 1612, 3661, - 1612, 3662, - 1611, 3662, - 1611, 3663, - 1600, 3663, - 1600, 3662, - 1599, 3662, - 1599, 3661, - 1594, 3661, - 1594, 3662, - 1593, 3662, - 1593, 3685, - 1594, 3685, - 1594, 3686, - 1599, 3686, - 1599, 3685, - 1600, 3685, - 1600, 3684, - 1611, 3684, - 1611, 3685, - 1612, 3685, - 1612, 3686, - 1613, 3686, - 1613, 3690, - 1614, 3690, - 1614, 3691, - 1619, 3691, - 1619, 3690, - 1620, 3690, - 1620, 3689, - 1630, 3689, - 1630, 3686, - 1620, 3686, - 1620, 3685, - 1619, 3685, - 1619, 3683, - 1620, 3683, - 1620, 3682, - 1621, 3682, - 1621, 3681, - 1622, 3681, - 1622, 3680, - 1623, 3680, - 1623, 3679, - 1624, 3679, - 1624, 3668, - 1623, 3668, - 1623, 3667, - 1622, 3667, - 1622, 3666, - 1621, 3666, - 1621, 3665, - 1620, 3665, - 1620, 3664, - 1619, 3664, - 1619, 3662, - 1620, 3662, - 1620, 3661, - 1627, 3661); - } - - private static void definePvpSafeZones() - { - // Grand exchange - addPolygonOnPlane(PVP_WORLD_SAFE_ZONES, 0, - 3159, 3473, - 3159, 3474, - 3157, 3474, - 3157, 3475, - 3155, 3475, - 3155, 3476, - 3153, 3476, - 3153, 3477, - 3152, 3477, - 3152, 3478, - 3151, 3478, - 3151, 3480, - 3150, 3480, - 3150, 3482, - 3149, 3482, - 3149, 3484, - 3148, 3484, - 3148, 3496, - 3149, 3496, - 3149, 3498, - 3150, 3498, - 3150, 3500, - 3151, 3500, - 3151, 3502, - 3152, 3502, - 3152, 3503, - 3153, 3503, - 3153, 3504, - 3155, 3504, - 3155, 3505, - 3157, 3505, - 3157, 3506, - 3159, 3506, - 3159, 3507, - 3171, 3507, - 3171, 3506, - 3173, 3506, - 3173, 3505, - 3175, 3505, - 3175, 3504, - 3177, 3504, - 3177, 3503, - 3178, 3503, - 3178, 3502, - 3179, 3502, - 3179, 3500, - 3180, 3500, - 3180, 3498, - 3181, 3498, - 3181, 3496, - 3182, 3496, - 3182, 3484, - 3181, 3484, - 3181, 3482, - 3180, 3482, - 3180, 3480, - 3179, 3480, - 3179, 3478, - 3178, 3478, - 3178, 3477, - 3177, 3477, - 3177, 3476, - 3175, 3476, - 3175, 3475, - 3173, 3475, - 3173, 3474, - 3171, 3474, - 3171, 3473); - - // Edgeville - addPolygonOnPlane(PVP_WORLD_SAFE_ZONES, 0, - 3091, 3488, - 3091, 3493, - 3090, 3493, - 3090, 3498, - 3091, 3498, - 3091, 3500, - 3099, 3500, - 3099, 3488); - - // Fally west bank - addPolygonOnPlane(PVP_WORLD_SAFE_ZONES, 0, - 2943, 3368, - 2943, 3374, - 2948, 3374, - 2948, 3370, - 2950, 3370, - 2950, 3366, - 2949, 3366, - 2949, 3359, - 2945, 3359, - 2945, 3362, - 2946, 3362, - 2946, 3366, - 2945, 3366, - 2945, 3368); - - // Fally east bank - addPolygonOnPlane(PVP_WORLD_SAFE_ZONES, 0, - 3009, 3353, - 3009, 3359, - 3019, 3359, - 3019, 3357, - 3022, 3357, - 3022, 3353); - - // Fally castle - addPolygonOnPlane(PVP_WORLD_SAFE_ZONES, 0, - 2964, 3354, - 2966, 3354, - 2966, 3352, - 2967, 3352, - 2967, 3349, - 2976, 3349, - 2976, 3348, - 2977, 3348, - 2977, 3347, - 2981, 3347, - 2981, 3343, - 2982, 3343, - 2982, 3339, - 2981, 3339, - 2981, 3337, - 2967, 3337, - 2967, 3330, - 2963, 3330, - 2963, 3331, - 2962, 3331, - 2962, 3332, - 2961, 3332, - 2961, 3334, - 2964, 3334, - 2964, 3335, - 2965, 3335, - 2965, 3343, - 2964, 3343, - 2964, 3344, - 2961, 3344, - 2961, 3350, - 2963, 3350, - 2963, 3352, - 2964, 3352); - - // Varrock east bank - addPolygonOnPlane(PVP_WORLD_SAFE_ZONES, 0, - 3250, 3425, - 3258, 3425, - 3258, 3416, - 3250, 3416); - - // Varrock west bank - addPolygonOnPlane(PVP_WORLD_SAFE_ZONES, 0, - 3180, 3433, - 3180, 3448, - 3191, 3448, - 3191, 3433); - - // Port phasmatys - addPolygonOnPlane(PVP_WORLD_SAFE_ZONES, 0, - 3686, 3472, - 3700, 3472, - 3700, 3461, - 3686, 3461); - - // Yanille bank - addPolygonOnPlane(PVP_WORLD_SAFE_ZONES, 0, - 2609, 3088, - 2609, 3098, - 2617, 3098, - 2617, 3088); - - // Ardy east bank - addPolygonOnPlane(PVP_WORLD_SAFE_ZONES, 0, - 2649, 3280, - 2649, 3288, - 2659, 3288, - 2659, 3280); - - // Ardy west bank - addPolygonOnPlane(PVP_WORLD_SAFE_ZONES, 0, - 2612, 3330, - 2612, 3336, - 2615, 3336, - 2615, 3335, - 2619, 3335, - 2619, 3336, - 2622, 3336, - 2622, 3330); - - // Fishing guild bank - addPolygonOnPlane(PVP_WORLD_SAFE_ZONES, 0, - 2593, 3413, - 2588, 3413, - 2588, 3418, - 2583, 3418, - 2583, 3423, - 2590, 3423, - 2590, 3420, - 2593, 3420); - - // Gnome stronghold bank near slayer cave (2nd floor) - addPolygonOnPlane(PVP_WORLD_SAFE_ZONES, 1, - 2444, 3431, - 2444, 3435, - 2448, 3435, - 2448, 3431, - 2447, 3431, - 2447, 3428, - 2449, 3428, - 2449, 3422, - 2447, 3422, - 2447, 3419, - 2448, 3419, - 2448, 3415, - 2444, 3415, - 2444, 3419, - 2445, 3419, - 2445, 3422, - 2443, 3422, - 2443, 3428, - 2445, 3428, - 2445, 3431); - - // Gnome stronghold bank in grand tree - addPolygonOnPlane(PVP_WORLD_SAFE_ZONES, 1, - 2456, 3488, - 2452, 3488, - 2452, 3486, - 2450, 3486, - 2450, 3483, - 2451, 3483, - 2451, 3478, - 2448, 3478, - 2448, 3483, - 2449, 3483, - 2449, 3486, - 2447, 3486, - 2447, 3488, - 2443, 3488, - 2443, 3487, - 2438, 3487, - 2438, 3490, - 2443, 3490, - 2443, 3489, - 2447, 3489, - 2447, 3491, - 2449, 3491, - 2449, 3494, - 2448, 3494, - 2448, 3496, - 2451, 3496, - 2451, 3494, - 2450, 3494, - 2450, 3491, - 2452, 3491, - 2452, 3489, - 2456, 3489); - - // Al kharid bank - addPolygonOnPlane(PVP_WORLD_SAFE_ZONES, 0, - 3265, 3161, - 3265, 3174, - 3273, 3174, - 3273, 3161); - - // Shantay pass bank - addPolygonOnPlane(PVP_WORLD_SAFE_ZONES, 0, - 3308, 3119, - 3308, 3125, - 3310, 3125, - 3310, 3119); - - // Nardah bank - addPolygonOnPlane(PVP_WORLD_SAFE_ZONES, 0, - 3431, 2891, - 3431, 2889, - 3427, 2889, - 3427, 2887, - 3424, 2887, - 3424, 2895, - 3431, 2895, - 3431, 2893, - 3432, 2893, - 3432, 2891); - - // Sophanem bank - addPolygonTo(PVP_WORLD_SAFE_ZONES, - 2807, 5158, - 2792, 5158, - 2792, 5175, - 2807, 5175); - - // Canifis bank - addPolygonOnPlane(PVP_WORLD_SAFE_ZONES, 0, - 3509, 3474, - 3509, 3478, - 3508, 3478, - 3508, 3483, - 3509, 3483, - 3509, 3484, - 3517, 3484, - 3517, 3477, - 3516, 3477, - 3516, 3476, - 3513, 3476, - 3513, 3474); - - // Lumbridge castle outside - addPolygonOnPlane(PVP_WORLD_SAFE_ZONES, 0, - 3216, 3209, - 3216, 3210, - 3217, 3210, - 3217, 3228, - 3216, 3228, - 3216, 3229, - 3227, 3229, - 3227, 3221, - 3230, 3221, - 3230, 3217, - 3227, 3217, - 3227, 3209); - - // Lumbridge bank upstairs - addPolygonOnPlane(PVP_WORLD_SAFE_ZONES, 2, - 3211, 3223, - 3211, 3215, - 3207, 3215, - 3207, 3223); - - // Draynor bank - addPolygonOnPlane(PVP_WORLD_SAFE_ZONES, 0, - 3098, 3240, - 3088, 3240, - 3088, 3247, - 3098, 3247); - - // Pest control bank - addPolygonOnPlane(PVP_WORLD_SAFE_ZONES, 0, - 2665, 2656, - 2670, 2656, - 2670, 2651, - 2665, 2651); - - // Shilo village bank - addPolygonOnPlane(PVP_WORLD_SAFE_ZONES, 0, - 2843, 2957, - 2846, 2957, - 2846, 2956, - 2849, 2956, - 2849, 2957, - 2850, 2957, - 2850, 2958, - 2855, 2958, - 2855, 2957, - 2856, 2957, - 2856, 2956, - 2858, 2956, - 2858, 2957, - 2862, 2957, - 2862, 2952, - 2858, 2952, - 2858, 2953, - 2856, 2953, - 2856, 2952, - 2855, 2952, - 2855, 2951, - 2850, 2951, - 2850, 2952, - 2849, 2952, - 2849, 2953, - 2847, 2953, - 2847, 2952, - 2843, 2952); - - // Legends guild bank - addPolygonOnPlane(PVP_WORLD_SAFE_ZONES, 2, - 2731, 3374, - 2731, 3383, - 2734, 3383, - 2734, 3374); - - // Legends guild middle floor - addPolygonOnPlane(PVP_WORLD_SAFE_ZONES, 1, - 2724, 3374, - 2724, 3383, - 2734, 3383, - 2734, 3382, - 2736, 3382, - 2736, 3375, - 2734, 3375, - 2734, 3374); - - // Warriors guild bank - addPolygonOnPlane(PVP_WORLD_SAFE_ZONES, 0, - 2843, 3537, - 2843, 3540, - 2841, 3540, - 2841, 3546, - 2849, 3546, - 2849, 3537, - 2847, 3537, - 2847, 3536, - 2846, 3536, - 2846, 3537); - - // Camelot bank - addPolygonOnPlane(PVP_WORLD_SAFE_ZONES, 0, - 2724, 3487, - 2724, 3490, - 2721, 3490, - 2721, 3494, - 2719, 3494, - 2719, 3497, - 2721, 3497, - 2721, 3498, - 2731, 3498, - 2731, 3490, - 2728, 3490, - 2728, 3487); - - // Camelot respawn point - addPolygonOnPlane(PVP_WORLD_SAFE_ZONES, 0, - 2761, 3483, - 2761, 3476, - 2755, 3476, - 2755, 3483); - - // Catherby bank - addPolygonOnPlane(PVP_WORLD_SAFE_ZONES, 0, - 2806, 3438, - 2806, 3446, - 2813, 3446, - 2813, 3438); - - // Barbarian outpost bank - addPolygonOnPlane(PVP_WORLD_SAFE_ZONES, 0, - 2536, 3572, - 2536, 3575, - 2538, 3575, - 2538, 3572); - - // Piscatoris bank - addPolygonOnPlane(PVP_WORLD_SAFE_ZONES, 0, - 2327, 3686, - 2327, 3694, - 2333, 3694, - 2333, 3686); - - // Lletya bank - addPolygonOnPlane(PVP_WORLD_SAFE_ZONES, 0, - 2350, 3161, - 2350, 3165, - 2351, 3165, - 2351, 3167, - 2357, 3167, - 2357, 3165, - 2356, 3165, - 2356, 3164, - 2355, 3164, - 2355, 3161); - - // Castle wars bank - addPolygonOnPlane(PVP_WORLD_SAFE_ZONES, 0, - 2446, 3087, - 2445, 3087, - 2445, 3085, - 2447, 3085, - 2447, 3081, - 2443, 3081, - 2443, 3082, - 2439, 3082, - 2439, 3081, - 2435, 3081, - 2435, 3099, - 2439, 3099, - 2439, 3098, - 2443, 3098, - 2443, 3099, - 2447, 3099, - 2447, 3095, - 2445, 3095, - 2445, 3093, - 2446, 3093); - - // Duel arena bank - addPolygonOnPlane(PVP_WORLD_SAFE_ZONES, 0, - 3380, 3267, - 3380, 3273, - 3381, 3273, - 3381, 3274, - 3385, 3274, - 3385, 3267); - - // Clan wars bank - addPolygonOnPlane(PVP_WORLD_SAFE_ZONES, 0, - 3375, 3165, - 3361, 3165, - 3361, 3173, - 3375, 3173); - - // Lumbridge cellar bank - addPolygonTo(PVP_WORLD_SAFE_ZONES, - 3218, 9622, - 3218, 9624, - 3220, 9624, - 3220, 9622); - - // Dorgesh kaan bank - addPolygonOnPlane(PVP_WORLD_SAFE_ZONES, 0, - 2709, 5348, - 2707, 5348, - 2707, 5345, - 2701, 5345, - 2701, 5347, - 2697, 5347, - 2697, 5353, - 2701, 5353, - 2701, 5355, - 2707, 5355, - 2707, 5350, - 2709, 5350); - - // Keldagrim bank - addPolygonOnPlane(PVP_WORLD_SAFE_ZONES, 0, - 2842, 10204, - 2834, 10204, - 2834, 10216, - 2842, 10216); - - // Tzhaar bank - addPolygonTo(PVP_WORLD_SAFE_ZONES, - 2438, 5176, - 2438, 5180, - 2441, 5180, - 2441, 5182, - 2449, 5182, - 2449, 5181, - 2450, 5181, - 2450, 5180, - 2452, 5180, - 2452, 5175, - 2441, 5175, - 2441, 5176); - - // Inferno bank - addPolygonTo(PVP_WORLD_SAFE_ZONES, - 2542, 5135, - 2542, 5139, - 2539, 5139, - 2539, 5140, - 2538, 5140, - 2538, 5141, - 2537, 5141, - 2537, 5144, - 2541, 5144, - 2541, 5145, - 2543, 5145, - 2543, 5144, - 2544, 5144, - 2544, 5142, - 2545, 5142, - 2545, 5135); - - // Port khazard bank - addPolygonOnPlane(PVP_WORLD_SAFE_ZONES, 0, - 2661, 3160, - 2661, 3163, - 2666, 3163, - 2666, 3160); - - // Corsair cove bank - addPolygonOnPlane(PVP_WORLD_SAFE_ZONES, 0, - 2569, 2863, - 2569, 2868, - 2572, 2868, - 2572, 2863); - - // Burgh de rott bank - addPolygonOnPlane(PVP_WORLD_SAFE_ZONES, 0, - 3495, 3210, - 3495, 3214, - 3501, 3214, - 3501, 3210); - - // Edgeville respawn point - addPolygonOnPlane(PVP_WORLD_SAFE_ZONES, 0, - 3092, 3468, - 3092, 3474, - 3098, 3474, - 3098, 3468); - - // Mage bank - addPolygonTo(PVP_WORLD_SAFE_ZONES, - 2529, 4711, - 2529, 4724, - 2548, 4724, - 2548, 4711); - - // Lunar bank - addPolygonOnPlane(PVP_WORLD_SAFE_ZONES, 0, - 2097, 3917, - 2097, 3922, - 2105, 3922, - 2105, 3917); - - // Jatizo bank - addPolygonOnPlane(PVP_WORLD_SAFE_ZONES, 0, - 2414, 3801, - 2414, 3804, - 2420, 3804, - 2420, 3801); - - // Neitiznot bank - addPolygonOnPlane(PVP_WORLD_SAFE_ZONES, 0, - 2334, 3805, - 2334, 3809, - 2340, 3809, - 2340, 3805); - - // Hosidius bank - addPolygonOnPlane(PVP_WORLD_SAFE_ZONES, 0, - 1671, 3558, - 1671, 3577, - 1682, 3577, - 1682, 3558); - - // Woodcutting guild bank - addPolygonOnPlane(PVP_WORLD_SAFE_ZONES, 0, - 1589, 3475, - 1589, 3481, - 1594, 3481, - 1594, 3475); - - // Lands end bank - addPolygonOnPlane(PVP_WORLD_SAFE_ZONES, 0, - 1508, 3415, - 1508, 3424, - 1514, 3424, - 1514, 3415); - - // Chambers of xeric bank - addPolygonOnPlane(PVP_WORLD_SAFE_ZONES, 0, - 1252, 3570, - 1252, 3574, - 1257, 3574, - 1257, 3570); - - // Arceuus bank - addPolygonOnPlane(PVP_WORLD_SAFE_ZONES, 0, - 1621, 3736, - 1621, 3754, - 1627, 3754, - 1627, 3751, - 1633, 3751, - 1633, 3754, - 1639, 3754, - 1639, 3736); - - // Piscarilius bank - addPolygonOnPlane(PVP_WORLD_SAFE_ZONES, 0, - 1794, 3784, - 1794, 3794, - 1812, 3794, - 1812, 3784); - - // Lovakengj bank southeast - addPolygonOnPlane(PVP_WORLD_SAFE_ZONES, 0, - 1518, 3735, - 1518, 3744, - 1535, 3744, - 1535, 3735); - - // Lovakenj bank west - addPolygonOnPlane(PVP_WORLD_SAFE_ZONES, 0, - 1433, 3820, - 1433, 3837, - 1442, 3837, - 1442, 3820); - - // Lovakenj sulphur mine bank - addPolygonOnPlane(PVP_WORLD_SAFE_ZONES, 0, - 1452, 3855, - 1452, 3860, - 1455, 3860, - 1455, 3855); - - // Blast mine bank southeast - addPolygonOnPlane(PVP_WORLD_SAFE_ZONES, 0, - 1500, 3856, - 1500, 3858, - 1503, 3858, - 1503, 3856); - - // Wintertodt bank - addPolygonOnPlane(PVP_WORLD_SAFE_ZONES, 0, - 1638, 3942, - 1638, 3947, - 1642, 3947, - 1642, 3942); - - // Shayzien bank - addPolygonOnPlane(PVP_WORLD_SAFE_ZONES, 0, - 1495, 3612, - 1495, 3622, - 1515, 3622, - 1515, 3612); - - // Hosidius grape farm bank - addPolygonOnPlane(PVP_WORLD_SAFE_ZONES, 0, - 1804, 3571, - 1804, 3572, - 1808, 3572, - 1808, 3571); - - // Hosidius cooking bank - addPolygonOnPlane(PVP_WORLD_SAFE_ZONES, 0, - 1652, 3605, - 1652, 3615, - 1661, 3615, - 1661, 3605); - - // Ecteria bank - addPolygonOnPlane(PVP_WORLD_SAFE_ZONES, 0, - 2618, 3893, - 2618, 3897, - 2622, 3897, - 2622, 3893); - - // Mining guild expanded area - addPolygonTo(PVP_WORLD_SAFE_ZONES, - 3018, 9733, - 3021, 9733, - 3021, 9729, - 3022, 9729, - 3022, 9728, - 3023, 9728, - 3023, 9727, - 3025, 9727, - 3025, 9726, - 3026, 9726, - 3026, 9725, - 3030, 9725, - 3030, 9726, - 3032, 9726, - 3032, 9727, - 3035, 9727, - 3035, 9726, - 3038, 9726, - 3038, 9727, - 3041, 9727, - 3041, 9728, - 3042, 9728, - 3042, 9730, - 3045, 9730, - 3045, 9727, - 3047, 9727, - 3047, 9726, - 3048, 9726, - 3048, 9724, - 3052, 9724, - 3052, 9725, - 3053, 9725, - 3053, 9726, - 3055, 9726, - 3055, 9725, - 3056, 9725, - 3056, 9723, - 3057, 9723, - 3057, 9720, - 3056, 9720, - 3056, 9719, - 3054, 9719, - 3054, 9718, - 3052, 9718, - 3052, 9717, - 3050, 9717, - 3050, 9718, - 3045, 9718, - 3045, 9716, - 3044, 9716, - 3044, 9715, - 3041, 9715, - 3041, 9714, - 3039, 9714, - 3039, 9713, - 3037, 9713, - 3037, 9714, - 3036, 9714, - 3036, 9715, - 3034, 9715, - 3034, 9716, - 3029, 9716, - 3029, 9715, - 3028, 9715, - 3028, 9714, - 3026, 9714, - 3026, 9709, - 3027, 9709, - 3027, 9708, - 3028, 9708, - 3028, 9705, - 3029, 9705, - 3029, 9701, - 3028, 9701, - 3028, 9700, - 3027, 9700, - 3027, 9699, - 3023, 9699, - 3023, 9700, - 3019, 9700, - 3019, 9701, - 3018, 9701, - 3018, 9705, - 3019, 9705, - 3019, 9707, - 3020, 9707, - 3020, 9708, - 3021, 9708, - 3021, 9709, - 3022, 9709, - 3022, 9713, - 3021, 9713, - 3021, 9714, - 3019, 9714, - 3019, 9715, - 3018, 9715, - 3018, 9717, - 3015, 9717, - 3015, 9716, - 3013, 9716, - 3013, 9717, - 3012, 9717, - 3012, 9720, - 3013, 9720, - 3013, 9721, - 3015, 9721, - 3015, 9723, - 3016, 9723, - 3016, 9727, - 3017, 9727, - 3017, 9730, - 3018, 9730); - - // Motherlode mine bank - addPolygonTo(PVP_WORLD_SAFE_ZONES, - 3760, 5671, - 3760, 5668, - 3761, 5668, - 3761, 5665, - 3760, 5665, - 3760, 5663, - 3758, 5663, - 3758, 5671); - - // Mos le harmles bank - addPolygonOnPlane(PVP_WORLD_SAFE_ZONES, 0, - 3679, 2980, - 3679, 2985, - 3681, 2985, - 3681, 2984, - 3682, 2984, - 3682, 2985, - 3684, 2985, - 3684, 2980, - 3682, 2980, - 3682, 2981, - 3681, 2981, - 3681, 2980); - - // Zanaris bank - addPolygonTo(PVP_WORLD_SAFE_ZONES, - 2388, 4454, - 2380, 4454, - 2380, 4463, - 2388, 4463); - - // Wodcuting guild bank underground - addPolygonTo(PVP_WORLD_SAFE_ZONES, - 1550, 9872, - 1550, 9874, - 1553, 9874, - 1553, 9872); - } - - private static void defineWilderness() - { - // Above ground - addPolygonTo(ROUGH_WILDERNESS, - 2944, 3523, - 3392, 3523, - 3392, 3971, - 2944, 3971); - - // Underground - addPolygonTo(ROUGH_WILDERNESS, - 2944, 9918, - 2944, 10360, - 3264, 10360, - 3264, 9918); - } - - private static void addPolygonTo(List[] shapes, int... coords) - { - Polygon poly = new Polygon(); - for (int i = 0; i < coords.length; i += 2) - { - poly.addPoint(coords[i], coords[i + 1]); - } - for (int i = 0; i < shapes.length; i++) - { - shapes[i].add(poly); - } - } - - private static void addPolygonOnPlane(List[] shapes, int plane, int... coords) - { - Polygon poly = new Polygon(); - for (int i = 0; i < coords.length; i += 2) - { - poly.addPoint(coords[i], coords[i + 1]); - } - shapes[plane].add(poly); - } - - private static void addPolygonOnPlanes(List[] shapes, int minPlane, int maxPlane, int... coords) - { - Polygon poly = new Polygon(); - for (int i = 0; i < coords.length; i += 2) - { - poly.addPoint(coords[i], coords[i + 1]); - } - for (int i = minPlane; i <= maxPlane; i++) - { - shapes[i].add(poly); - } - } +/* + * Copyright (c) 2018, Woox + * 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.multiindicators; + +import java.awt.Polygon; +import java.awt.Rectangle; +import java.awt.Shape; +import java.awt.geom.Area; +import java.util.ArrayList; +import java.util.List; +import net.runelite.api.Constants; + +public class MapLocations +{ + private static final List[] MULTICOMBAT = new List[Constants.MAX_Z]; + private static final List[] NOT_MULTICOMBAT = new List[Constants.MAX_Z]; + private static final List[] ROUGH_WILDERNESS = new List[Constants.MAX_Z]; + private static final List[] DEADMAN_SAFE_ZONES = new List[Constants.MAX_Z]; + private static final List[] PVP_WORLD_SAFE_ZONES = new List[Constants.MAX_Z]; + + private static Area getArea(List shapes) + { + Area area = new Area(); + for (Shape shape : shapes) + { + area.add(new Area(shape)); + } + return area; + } + + private static Area getArea(List shapes, Rectangle view) + { + Area area = new Area(); + for (Shape shape : shapes) + { + if (shape.intersects(view)) + { + area.add(new Area(shape)); + } + } + return area; + } + + public static Area getMulticombat(int plane) + { + Area area = getArea(MULTICOMBAT[plane]); + area.subtract(getArea(NOT_MULTICOMBAT[plane])); + return area; + } + + public static Area getMulticombat(Rectangle view, int plane) + { + Area area = getArea(MULTICOMBAT[plane], view); + area.subtract(getArea(NOT_MULTICOMBAT[plane], view)); + return area; + } + + public static Area getRoughWilderness(int plane) + { + return getArea(ROUGH_WILDERNESS[plane]); + } + + public static Area getRoughWilderness(Rectangle view, int plane) + { + return getArea(ROUGH_WILDERNESS[plane], view); + } + + public static Area getDeadmanSafeZones(int plane) + { + return getArea(DEADMAN_SAFE_ZONES[plane]); + } + + public static Area getDeadmanSafeZones(Rectangle view, int plane) + { + return getArea(DEADMAN_SAFE_ZONES[plane], view); + } + + public static Area getPvpSafeZones(int plane) + { + return getArea(PVP_WORLD_SAFE_ZONES[plane]); + } + + public static Area getPvpSafeZones(Rectangle view, int plane) + { + return getArea(PVP_WORLD_SAFE_ZONES[plane], view); + } + + static + { + for (int i = 0; i < MULTICOMBAT.length; i++) + { + MULTICOMBAT[i] = new ArrayList<>(); + } + for (int i = 0; i < NOT_MULTICOMBAT.length; i++) + { + NOT_MULTICOMBAT[i] = new ArrayList<>(); + } + for (int i = 0; i < ROUGH_WILDERNESS.length; i++) + { + ROUGH_WILDERNESS[i] = new ArrayList<>(); + } + for (int i = 0; i < DEADMAN_SAFE_ZONES.length; i++) + { + DEADMAN_SAFE_ZONES[i] = new ArrayList<>(); + } + for (int i = 0; i < PVP_WORLD_SAFE_ZONES.length; i++) + { + PVP_WORLD_SAFE_ZONES[i] = new ArrayList<>(); + } + + defineMulticombatAreas(); + defineDeadmanSafeZones(); + definePvpSafeZones(); + defineWilderness(); + } + + private static void defineMulticombatAreas() + { + // Main Wilderness + addPolygonOnPlane(MULTICOMBAT, 0, + 3200, 3968, + 3392, 3968, + 3392, 3840, + 3328, 3840, + 3328, 3520, + 3136, 3520, + 3136, 3648, + 3192, 3648, + 3192, 3752, + 3152, 3752, + 3152, 3840, + 3136, 3840, + 3136, 3872, + 3112, 3872, + 3112, 3880, + 3072, 3880, + 3072, 3896, + 3048, 3896, + 3048, 3872, + 3056, 3872, + 3056, 3864, + 3048, 3864, + 3048, 3856, + 3008, 3856, + 3008, 3904, + 3200, 3904); + + // South of wildy agility training arena + addPolygonOnPlane(MULTICOMBAT, 0, + 2984, 3928, + 3008, 3928, + 3008, 3912, + 2984, 3912); + + // Wildy zamorak temple + addPolygonOnPlane(MULTICOMBAT, 0, + 2944, 3832, + 2960, 3832, + 2960, 3816, + 2944, 3816); + + // Wildy bandit camp + addPolygonOnPlane(MULTICOMBAT, 0, + 3008, 3712, + 3072, 3712, + 3072, 3600, + 3008, 3600); + + // Chaos temple north of Falador + addPolygonOnPlane(MULTICOMBAT, 0, + 2928, 3520, + 2944, 3520, + 2944, 3512, + 2928, 3512); + + // Burthorpe + addPolygonOnPlane(MULTICOMBAT, 0, + 2880, 3544, + 2904, 3544, + 2904, 3520, + 2880, 3520); + + // White Wolf Mountain + addPolygonOnPlane(MULTICOMBAT, 0, + 2880, 3520, + 2816, 3520, + 2816, 3456, + 2880, 3456); + + // Death Plateu + addPolygonOnPlane(MULTICOMBAT, 0, + 2848, 3608, + 2880, 3608, + 2880, 3600, + 2848, 3600); + + // Trollheim/Godwars + addPolygonOnPlane(MULTICOMBAT, 0, + 2880, 3776, + 2912, 3776, + 2912, 3696, + 2920, 3696, + 2920, 3688, + 2896, 3688, + 2896, 3696, + 2880, 3696, + 2880, 3728, + 2888, 3728, + 2888, 3744, + 2880, 3744); + + // Northen Rellekka + addPolygonOnPlane(MULTICOMBAT, 0, + 2656, 3736, + 2704, 3736, + 2704, 3728, + 2712, 3728, + 2712, 3736, + 2736, 3736, + 2736, 3712, + 2656, 3712); + + // Northen Fremennik Isles + addPolygonOnPlane(MULTICOMBAT, 0, + 2304, 3904, + 2432, 3904, + 2432, 3840, + 2368, 3840, + 2368, 3816, + 2352, 3816, + 2352, 3824, + 2304, 3824); + + // Pirates Cove + addPolygonOnPlane(MULTICOMBAT, 0, + 2176, 3840, + 2240, 3840, + 2240, 3776, + 2176, 3776); + + // Lunar Isle + addPolygonOnPlane(MULTICOMBAT, 0, + 2048, 3968, + 2176, 3968, + 2176, 3840, + 2048, 3840); + + // Piscatoris Fishing Colony + addPolygonOnPlane(MULTICOMBAT, 0, + 2304, 3712, + 2368, 3712, + 2368, 3648, + 2304, 3648); + + // Ranging Guild + addPolygonOnPlane(MULTICOMBAT, 0, + 2656, 3448, + 2680, 3448, + 2680, 3440, + 2688, 3440, + 2688, 3416, + 2680, 3416, + 2680, 3408, + 2656, 3408, + 2656, 3416, + 2648, 3416, + 2648, 3440, + 2656, 3440); + + // Necromancer house, southeast of Ardy + addPolygonOnPlane(MULTICOMBAT, 0, + 2656, 3256, + 2680, 3256, + 2680, 3216, + 2664, 3216, + 2664, 3232, + 2656, 3232); + + // Battlefield noth of Tree Gnome Village + addPolygonOnPlane(MULTICOMBAT, 0, + 2504, 3248, + 2544, 3248, + 2544, 3232, + 2552, 3232, + 2552, 3208, + 2504, 3208); + + // Castle Wars + addPolygonOnPlane(MULTICOMBAT, 0, + 2368, 3136, + 2432, 3136, + 2432, 3072, + 2368, 3072); + + // Jiggig + addPolygonOnPlane(MULTICOMBAT, 0, + 2456, 3056, + 2496, 3056, + 2496, 3032, + 2456, 3032); + + // East feldip hills, near rantz + addPolygonOnPlane(MULTICOMBAT, 0, + 2648, 2976, + 2656, 2976, + 2656, 2952, + 2648, 2952); + + // Ape Atoll + addPolygonOnPlane(MULTICOMBAT, 0, + 2688, 2816, + 2816, 2816, + 2816, 2688, + 2688, 2688); + + // Pest Control + addPolygonOnPlane(MULTICOMBAT, 0, + 2624, 2624, + 2688, 2624, + 2688, 2560, + 2624, 2560); + + // Desert Bandit Camp + addPolygonOnPlane(MULTICOMBAT, 0, + 3152, 3000, + 3192, 3000, + 3192, 2960, + 3152, 2960); + + // Al Kharid + addPolygonOnPlane(MULTICOMBAT, 0, + 3264, 3200, + 3328, 3200, + 3328, 3136, + 3264, 3136); + + // Wizards Tower + addPolygonOnPlane(MULTICOMBAT, 0, + 3094, 3176, + 3126, 3176, + 3126, 3144, + 3094, 3144); + + // Draynor Village + addPolygonOnPlane(MULTICOMBAT, 0, + 3112, 3264, + 3136, 3264, + 3136, 3232, + 3104, 3232, + 3104, 3256, + 3112, 3256); + + // Falador + addPolygonOnPlane(MULTICOMBAT, 0, + 2944, 3456, + 3008, 3456, + 3008, 3328, + 3016, 3328, + 3016, 3304, + 2944, 3304); + + // Southwest fally castle isn't multicombat downstairs + addPolygonOnPlane(NOT_MULTICOMBAT, 0, + 2968, 3336, + 2968, 3328, + 2960, 3328, + 2960, 3336); + + // Barbarian Village + addPolygonOnPlane(MULTICOMBAT, 0, + 3072, 3456, + 3136, 3456, + 3136, 3392, + 3048, 3392, + 3048, 3408, + 3056, 3408, + 3056, 3440, + 3064, 3440, + 3064, 3448, + 3072, 3448); + + // Ammoniate crabs at northwest fossil island + addPolygonOnPlane(MULTICOMBAT, 0, + 3648, 3885, + 3663, 3885, + 3663, 3882, + 3664, 3882, + 3664, 3872, + 3663, 3872, + 3663, 3868, + 3648, 3868); + + // Ammoniate crabs at north fossil island + addPolygonOnPlane(MULTICOMBAT, 0, + 3680, 3904, + 3744, 3904, + 3744, 3856, + 3756, 3856, + 3756, 3852, + 3755, 3852, + 3755, 3851, + 3754, 3851, + 3754, 3850, + 3751, 3850, + 3751, 3849, + 3750, 3849, + 3750, 3848, + 3749, 3848, + 3749, 3847, + 3748, 3847, + 3748, 3846, + 3747, 3846, + 3747, 3845, + 3746, 3845, + 3746, 3844, + 3742, 3844, + 3742, 3845, + 3740, 3845, + 3740, 3844, + 3732, 3844, + 3732, 3843, + 3730, 3843, + 3730, 3842, + 3724, 3842, + 3724, 3843, + 3717, 3843, + 3717, 3842, + 3712, 3842, + 3712, 3846, + 3710, 3846, + 3710, 3847, + 3709, 3847, + 3709, 3848, + 3708, 3848, + 3708, 3859, + 3709, 3859, + 3709, 3860, + 3710, 3860, + 3710, 3861, + 3712, 3861, + 3712, 3866, + 3713, 3866, + 3713, 3870, + 3714, 3870, + 3714, 3873, + 3713, 3873, + 3713, 3876, + 3712, 3876, + 3712, 3881, + 3710, 3881, + 3710, 3888, + 3712, 3888, + 3712, 3890, + 3714, 3890, + 3714, 3891, + 3716, 3891, + 3716, 3892, + 3717, 3892, + 3717, 3893, + 3716, 3893, + 3716, 3894, + 3714, 3894, + 3714, 3895, + 3713, 3895, + 3713, 3896, + 3712, 3896, + 3712, 3897, + 3705, 3897, + 3705, 3898, + 3704, 3898, + 3704, 3899, + 3692, 3899, + 3692, 3898, + 3688, 3898, + 3688, 3897, + 3686, 3897, + 3686, 3896, + 3680, 3896); + + // Zeah, southwest of Wintertodt, snowy area with ice giants and wolves + addPolygonOnPlane(MULTICOMBAT, 0, + 1540, 3898, + 1543, 3898, + 1543, 3901, + 1546, 3901, + 1546, 3903, + 1547, 3903, + 1547, 3904, + 1550, 3904, + 1550, 3903, + 1553, 3903, + 1553, 3904, + 1559, 3904, + 1559, 3902, + 1564, 3902, + 1564, 3903, + 1565, 3903, + 1565, 3904, + 1568, 3904, + 1568, 3903, + 1569, 3903, + 1569, 3902, + 1570, 3902, + 1570, 3901, + 1573, 3901, + 1573, 3898, + 1577, 3898, + 1577, 3899, + 1578, 3899, + 1578, 3902, + 1579, 3902, + 1579, 3903, + 1584, 3903, + 1584, 3902, + 1586, 3902, + 1586, 3901, + 1590, 3901, + 1590, 3891, + 1588, 3891, + 1588, 3887, + 1572, 3887, + 1572, 3872, + 1567, 3872, + 1567, 3868, + 1563, 3868, + 1563, 3867, + 1558, 3867, + 1558, 3868, + 1557, 3868, + 1557, 3870, + 1549, 3870, + 1549, 3874, + 1545, 3874, + 1545, 3876, + 1543, 3876, + 1543, 3877, + 1542, 3877, + 1542, 3879, + 1541, 3879, + 1541, 3882, + 1539, 3882, + 1539, 3887, + 1540, 3887, + 1540, 3888, + 1539, 3888, + 1539, 3894, + 1540, 3894); + + // Zeah arceuus area + addPolygonOnPlane(MULTICOMBAT, 0, + 1664, 3776, + 1664, 3785, + 1667, 3785, + 1667, 3805, + 1671, 3805, + 1671, 3811, + 1675, 3811, + 1675, 3819, + 1690, 3819, + 1690, 3814, + 1695, 3814, + 1695, 3806, + 1719, 3806, + 1719, 3787, + 1725, 3787, + 1725, 3778, + 1711, 3778, + 1711, 3776); + + // Arceuus teletab-making house + addPolygonOnPlane(MULTICOMBAT, 0, + 1667, 3772, + 1679, 3772, + 1679, 3775, + 1691, 3775, + 1691, 3761, + 1679, 3761, + 1679, 3764, + 1667, 3764); + // Next house east + addPolygonOnPlane(MULTICOMBAT, 0, + 1696, 3775, + 1708, 3775, + 1708, 3763, + 1696, 3763); + // Next house east + addPolygonOnPlane(MULTICOMBAT, 0, + 1713, 3775, + 1727, 3775, + 1727, 3763, + 1724, 3763, + 1724, 3752, + 1716, 3752, + 1716, 3763, + 1713, 3763); + // Arceuus rune shop house + addPolygonOnPlane(MULTICOMBAT, 0, + 1716, 3750, + 1728, 3750, + 1728, 3736, + 1716, 3736); + // Arceuus general store house + addPolygonOnPlane(MULTICOMBAT, 0, + 1717, 3732, + 1725, 3732, + 1725, 3715, + 1715, 3715, + 1715, 3725, + 1717, 3725); + // Arceuus pub + addPolygonOnPlane(MULTICOMBAT, 0, + 1683, 3732, + 1691, 3732, + 1691, 3725, + 1697, 3725, + 1697, 3730, + 1703, 3730, + 1703, 3712, + 1683, 3712); + // Arceuus staff store + addPolygonOnPlane(MULTICOMBAT, 0, + 1664, 3732, + 1676, 3732, + 1676, 3720, + 1664, 3720); + // Next house to the west + addPolygonOnPlane(MULTICOMBAT, 0, + 1647, 3738, + 1655, 3738, + 1655, 3726, + 1658, 3726, + 1658, 3714, + 1644, 3714, + 1644, 3726, + 1647, 3726); + // Next house to the north + addPolygonOnPlane(MULTICOMBAT, 0, + 1647, 3762, + 1657, 3762, + 1657, 3752, + 1655, 3752, + 1655, 3745, + 1647, 3745); + + // Arceuus house magic trees + addPolygonOnPlane(MULTICOMBAT, 0, + 1682, 3755, + 1692, 3755, + 1692, 3745, + 1690, 3745, + 1690, 3738, + 1682, 3738); + // West of that ^ + addPolygonOnPlane(MULTICOMBAT, 0, + 1667, 3756, + 1675, 3756, + 1675, 3740, + 1665, 3740, + 1665, 3746, + 1667, 3746); + + // This one goes through western piscarilius, northen hosidius + // and southwestern arceuus + addPolygonOnPlane(MULTICOMBAT, 0, + 1728, 3808, + 1792, 3808, + 1792, 3764, + 1856, 3764, + 1856, 3712, + 1792, 3712, + 1792, 3648, + 1664, 3648, + 1664, 3706, + 1665, 3706, + 1665, 3705, + 1668, 3705, + 1668, 3706, + 1671, 3706, + 1671, 3705, + 1675, 3705, + 1675, 3704, + 1683, 3704, + 1683, 3701, + 1684, 3701, + 1684, 3700, + 1686, 3700, + 1686, 3702, + 1687, 3702, + 1687, 3700, + 1688, 3700, + 1688, 3701, + 1690, 3701, + 1690, 3703, + 1689, 3703, + 1689, 3704, + 1690, 3704, + 1690, 3705, + 1704, 3705, + 1704, 3707, + 1706, 3707, + 1706, 3712, + 1711, 3712, + 1711, 3711, + 1710, 3711, + 1710, 3710, + 1712, 3710, + 1712, 3707, + 1728, 3707); + + // Kourend castle + addPolygonOnPlane(MULTICOMBAT, 0, + 1614, 3691, + 1619, 3691, + 1619, 3690, + 1620, 3690, + 1620, 3689, + 1653, 3689, + 1653, 3690, + 1654, 3690, + 1654, 3691, + 1657, 3691, + 1657, 3690, + 1658, 3690, + 1658, 3689, + 1659, 3689, + 1659, 3686, + 1658, 3686, + 1658, 3685, + 1657, 3685, + 1657, 3662, + 1658, 3662, + 1658, 3661, + 1659, 3661, + 1659, 3658, + 1658, 3658, + 1658, 3657, + 1657, 3657, + 1657, 3656, + 1654, 3656, + 1654, 3657, + 1653, 3657, + 1653, 3658, + 1620, 3658, + 1620, 3657, + 1619, 3657, + 1619, 3656, + 1614, 3656, + 1614, 3657, + 1613, 3657, + 1613, 3661, + 1612, 3661, + 1612, 3662, + 1611, 3662, + 1611, 3663, + 1600, 3663, + 1600, 3662, + 1599, 3662, + 1599, 3661, + 1594, 3661, + 1594, 3662, + 1593, 3662, + 1593, 3685, + 1594, 3685, + 1594, 3686, + 1599, 3686, + 1599, 3685, + 1600, 3685, + 1600, 3684, + 1611, 3684, + 1611, 3685, + 1612, 3685, + 1612, 3686, + 1613, 3686, + 1613, 3690, + 1614, 3690); + + // Western hosidius area, including woodcutting guild and western sand crabs + addPolygonOnPlane(MULTICOMBAT, 0, + 1650, 3648, + 1664, 3648, + 1664, 3520, + 1689, 3520, + 1689, 3496, + 1707, 3496, + 1707, 3485, + 1708, 3485, + 1708, 3484, + 1710, 3484, + 1710, 3483, + 1713, 3483, + 1713, 3482, + 1720, 3482, + 1720, 3481, + 1721, 3481, + 1721, 3480, + 1722, 3480, + 1722, 3479, + 1723, 3479, + 1723, 3478, + 1724, 3478, + 1724, 3477, + 1726, 3477, + 1726, 3476, + 1728, 3476, + 1728, 3472, + 1708, 3472, + 1708, 3456, + 1600, 3456, + 1600, 3584, + 1608, 3584, + 1608, 3616, + 1650, 3616); + + // Hosidius sand crabs + addPolygonOnPlane(MULTICOMBAT, 0, + 1740, 3478, + 1741, 3478, + 1741, 3479, + 1745, 3479, + 1745, 3480, + 1751, 3480, + 1751, 3479, + 1752, 3479, + 1752, 3478, + 1753, 3478, + 1753, 3477, + 1755, 3477, + 1755, 3476, + 1757, 3476, + 1757, 3475, + 1758, 3475, + 1758, 3474, + 1759, 3474, + 1759, 3473, + 1779, 3473, + 1779, 3474, + 1781, 3474, + 1781, 3475, + 1786, 3475, + 1786, 3476, + 1800, 3476, + 1800, 3475, + 1805, 3475, + 1805, 3474, + 1807, 3474, + 1807, 3473, + 1808, 3473, + 1808, 3472, + 1810, 3472, + 1810, 3471, + 1833, 3471, + 1833, 3470, + 1834, 3470, + 1834, 3469, + 1852, 3469, + 1852, 3449, + 1792, 3449, + 1792, 3424, + 1800, 3424, + 1800, 3449, + 1800, 3400, + 1728, 3400, + 1728, 3462, + 1729, 3462, + 1729, 3466, + 1730, 3466, + 1730, 3469, + 1731, 3469, + 1731, 3470, + 1732, 3470, + 1732, 3471, + 1733, 3471, + 1733, 3473, + 1734, 3473, + 1734, 3474, + 1736, 3474, + 1736, 3475, + 1737, 3475, + 1737, 3476, + 1738, 3476, + 1738, 3477, + 1740, 3477); + + // Apparently there is a 1x1 single zone on the sand crab island + addPolygonOnPlane(NOT_MULTICOMBAT, 0, + 1777, 3416, + 1777, 3417, + 1778, 3417, + 1778, 3416); + + // Eastern hosidius area + addPolygonOnPlane(MULTICOMBAT, 0, + 1834, 3584, + 1888, 3584, + 1888, 3528, + 1856, 3528, + 1856, 3520, + 1834, 3520, + 1834, 3522, + 1833, 3522, + 1833, 3535, + 1834, 3535, + 1834, 3538, + 1835, 3538, + 1835, 3539, + 1836, 3539, + 1836, 3540, + 1837, 3540, + 1837, 3541, + 1838, 3541, + 1838, 3542, + 1840, 3542, + 1840, 3543, + 1841, 3543, + 1841, 3545, + 1842, 3545, + 1842, 3546, + 1844, 3546, + 1844, 3547, + 1845, 3547, + 1845, 3548, + 1851, 3548, + 1851, 3551, + 1853, 3551, + 1853, 3563, + 1851, 3563, + 1851, 3566, + 1847, 3566, + 1847, 3567, + 1845, 3567, + 1845, 3568, + 1844, 3568, + 1844, 3569, + 1843, 3569, + 1843, 3571, + 1842, 3571, + 1842, 3573, + 1841, 3573, + 1841, 3574, + 1840, 3574, + 1840, 3575, + 1839, 3575, + 1839, 3576, + 1838, 3576, + 1838, 3577, + 1837, 3577, + 1837, 3578, + 1836, 3578, + 1836, 3579, + 1835, 3579, + 1835, 3581, + 1834, 3581); + + // Eastern hosidius area also has a 1x1 multi area + addPolygonOnPlane(MULTICOMBAT, 0, + 1849, 3563, + 1849, 3564, + 1850, 3564, + 1850, 3563); + + // Hosidius cows/chickens/pigs + addPolygonOnPlane(MULTICOMBAT, 0, + 1792, 3513, + 1802, 3513, + 1802, 3520, + 1810, 3520, + 1810, 3513, + 1816, 3513, + 1816, 3512, + 1836, 3512, + 1836, 3494, + 1796, 3494, + 1796, 3495, + 1792, 3495); + + // Hosidius southeast of tithe farm + addPolygonOnPlane(MULTICOMBAT, 0, + 1777, 3597, + 1794, 3597, + 1794, 3561, + 1777, 3561, + 1777, 3591, + 1779, 3591, + 1779, 3592, + 1777, 3592); + + // West of shayzien house + addPolygonOnPlane(MULTICOMBAT, 0, + 1408, 3584, + 1408, 3582, + 1486, 3582, + 1486, 3568, + 1528, 3568, + 1528, 3520, + 1408, 3520, + 1408, 3464, + 1380, 3464, + 1380, 3486, + 1377, 3486, + 1377, 3488, + 1373, 3488, + 1373, 3492, + 1364, 3492, + 1364, 3512, + 1358, 3512, + 1358, 3520, + 1356, 3520, + 1356, 3532, + 1358, 3532, + 1358, 3540, + 1359, 3540, + 1359, 3542, + 1360, 3542, + 1360, 3557, + 1356, 3557, + 1356, 3560, + 1351, 3560, + 1351, 3570, + 1354, 3570, + 1354, 3581, + 1346, 3581, + 1346, 3584); + + // South of chambers of xeric + addPolygonOnPlane(MULTICOMBAT, 0, + 1261, 3489, + 1259, 3489, + 1259, 3488, + 1255, 3488, + 1255, 3487, + 1243, 3487, + 1243, 3490, + 1234, 3490, + 1234, 3480, + 1192, 3480, + 1192, 3568, + 1209, 3568, + 1209, 3548, + 1215, 3548, + 1215, 3544, + 1217, 3544, + 1217, 3536, + 1235, 3536, + 1235, 3532, + 1249, 3532, + 1249, 3525, + 1248, 3525, + 1248, 3517, + 1254, 3517, + 1254, 3513, + 1274, 3513, + 1274, 3510, + 1296, 3510, + 1296, 3511, + 1300, 3511, + 1300, 3501, + 1287, 3501, + 1287, 3490, + 1280, 3490, + 1280, 3489, + 1264, 3489, + 1264, 3490, + 1261, 3490); + + // Lizardman shamans + addPolygonOnPlane(MULTICOMBAT, 0, + 1416, 3728, + 1456, 3728, + 1456, 3688, + 1416, 3688); + + // Other lizardman area at shayzien (west side) + addPolygonOnPlane(MULTICOMBAT, 0, + 1472, 3712, + 1510, 3712, + 1510, 3702, + 1509, 3702, + 1509, 3701, + 1506, 3701, + 1506, 3696, + 1500, 3696, + 1500, 3680, + 1472, 3680); + + // Other lizardman area at shayzien (east side) + addPolygonOnPlane(MULTICOMBAT, 0, + 1538, 3704, + 1560, 3704, + 1560, 3672, + 1538, 3672); + + // Lovakengj house + addPolygonOnPlane(MULTICOMBAT, 0, + 1600, 3712, + 1472, 3712, + 1472, 3840, + 1547, 3840, + 1547, 3816, + 1556, 3816, + 1556, 3809, + 1562, 3809, + 1562, 3800, + 1568, 3800, + 1568, 3793, + 1571, 3793, + 1571, 3816, + 1571, 3776, + 1600, 3776); + + // Shayzien house + addPolygonOnPlane(MULTICOMBAT, 0, + 1475, 3587, + 1475, 3641, + 1534, 3641, + 1534, 3587); + + // Shayzien house bank is non-multi + addPolygonOnPlane(NOT_MULTICOMBAT, 0, + 1495, 3622, + 1515, 3622, + 1515, 3612, + 1495, 3612); + + // Shayzien house general store + addPolygonOnPlane(MULTICOMBAT, 0, + 1539, 3640, + 1551, 3640, + 1551, 3621, + 1539, 3621); + + // Kourend woodland barbarian area + addPolygonOnPlane(MULTICOMBAT, 0, + 1572, 3442, + 1591, 3442, + 1591, 3424, + 1572, 3424); + + // Catacombs + addPolygonTo(MULTICOMBAT, + 1600, 9984, + 1600, 10067, + 1628, 10067, + 1628, 10070, + 1639, 10070, + 1639, 10112, + 1730, 10112, + 1730, 9984); + + // Zeah dungeon with sand crabs + addPolygonTo(MULTICOMBAT, + 1632, 9792, + 1632, 9856, + 1728, 9856, + 1728, 9792); + + // Waterbirth island near the doors where people use rune throwing axes + addPolygonTo(MULTICOMBAT, + 2536, 10136, + 2536, 10152, + 2552, 10152, + 2552, 10136); + + // Waterbirth island dungeon, on the path to dks + addPolygonTo(MULTICOMBAT, + 1792, 4352, + 1792, 4416, + 1984, 4416, + 1984, 4352); + + // Dagannoths in lighthouse + addPolygonTo(MULTICOMBAT, + 2496, 10048, + 2560, 10048, + 2560, 9984, + 2496, 9984); + + // Dagannoth kings (DKs) including slayer only dks + addPolygonTo(MULTICOMBAT, + 2944, 4352, + 2944, 4480, + 2880, 4480, + 2880, 4352); + + // White wolf mountain dungeon at ice queen + addPolygonTo(MULTICOMBAT, + 2856, 9928, + 2856, 9968, + 2880, 9968, + 2880, 9928); + + // Kharazi jungle dungeon (in dragon slayer 2 quest) + addPolygonTo(MULTICOMBAT, + 2816, 9296, + 2880, 9296, + 2880, 9216, + 2816, 9216); + + // Tzhaar, fight pits and inferno area + addPolygonTo(MULTICOMBAT, + 2368, 5184, + 2560, 5184, + 2560, 5056, + 2368, 5056); + + // Smoke devils + addPolygonTo(MULTICOMBAT, + 2432, 9408, + 2344, 9408, + 2344, 9472, + 2432, 9472); + + // Kraken + addPolygonTo(MULTICOMBAT, + 2270, 10045, + 2291, 10045, + 2291, 10022, + 2270, 10022); + + // Giant mole + addPolygonTo(MULTICOMBAT, + 1728, 5240, + 1792, 5240, + 1792, 5120, + 1728, 5120); + + // Godwars dungeon + addPolygonTo(MULTICOMBAT, + 2816, 5376, + 2944, 5376, + 2944, 5248, + 2816, 5248); + + // Desert treasure shadow diamond area + addPolygonTo(MULTICOMBAT, + 2752, 5064, + 2728, 5064, + 2728, 5088, + 2720, 5088, + 2720, 5096, + 2712, 5096, + 2712, 5112, + 2736, 5112, + 2736, 5120, + 2752, 5120); + + // Kalphite slayer area + addPolygonTo(MULTICOMBAT, + 3264, 9544, + 3344, 9544, + 3344, 9472, + 3264, 9472); + + // Normal kalphite area including kalphite queen + addPolygonTo(MULTICOMBAT, + 3456, 9536, + 3520, 9536, + 3520, 9472, + 3456, 9472); + + // Tarns lair + addPolygonTo(MULTICOMBAT, + 3136, 4664, + 3200, 4664, + 3200, 4544, + 3136, 4544); + + // Haunted mine boss area + addPolygonTo(MULTICOMBAT, + 2752, 4416, + 2752, 4480, + 2816, 4480, + 2816, 4416); + + // Entrance to dorgesh kaan + addPolygonTo(MULTICOMBAT, + 3328, 9600, + 3312, 9600, + 3312, 9640, + 3304, 9640, + 3304, 9664, + 3328, 9664); + + // Hammerspikes hangout in dwarven mines + addPolygonTo(MULTICOMBAT, + 2960, 9824, + 2976, 9824, + 2976, 9800, + 2960, 9800); + + // Fremennik isles dungeon + addPolygonTo(MULTICOMBAT, + 2432, 10304, + 2432, 10240, + 2368, 10240, + 2368, 10304); + + // Varrock sewers + addPolygonTo(MULTICOMBAT, + 3152, 9920, + 3288, 9920, + 3288, 9856, + 3152, 9856); + + // Stronghold of security 1st floor + addPolygonTo(MULTICOMBAT, + 1856, 5248, + 1920, 5248, + 1920, 5184, + 1856, 5184); + + // Corp cave + addPolygonTo(MULTICOMBAT, + 2960, 4400, + 3000, 4400, + 3000, 4368, + 2960, 4368); + + // ZMI altar area + addPolygonTo(MULTICOMBAT, + 3008, 5632, + 3072, 5632, + 3072, 5568, + 3008, 5568); + + // Dragon slayer 2 zeah underground puzzle + addPolygonTo(MULTICOMBAT, + 1472, 9984, + 1536, 9984, + 1536, 9920, + 1472, 9920); + + // Wildy revenant caves + addPolygonTo(MULTICOMBAT, + 3136, 10062, + 3136, 10240, + 3236, 10240, + 3236, 10229, + 3264, 10229, + 3264, 10048, + 3208, 10048, + 3208, 10062); + + // King black dragon (Kbd) + addPolygonTo(MULTICOMBAT, + 2240, 4672, + 2240, 4736, + 2304, 4736, + 2304, 4672); + + // Scorpia + addPolygonTo(MULTICOMBAT, + 3248, 10352, + 3248, 10328, + 3216, 10328, + 3216, 10352); + + // Inside mage bank + addPolygonTo(MULTICOMBAT, + 2496, 4672, + 2496, 4736, + 2560, 4736, + 2560, 4672); + + // Wildy godwars dungeon + addPolygonTo(MULTICOMBAT, + 3072, 10112, + 3008, 10112, + 3008, 10176, + 3048, 10176, + 3048, 10152, + 3056, 10152, + 3056, 10144, + 3064, 10144, + 3064, 10136, + 3072, 10136); + + // Enchanted valley + addPolygonTo(MULTICOMBAT, + 3008, 4480, + 3008, 4544, + 3072, 4544, + 3072, 4480); + + // Zulrah + addPolygonTo(MULTICOMBAT, + 2256, 3080, + 2280, 3080, + 2280, 3064, + 2256, 3064); + + // Abyssal sire and abyss + addPolygonTo(MULTICOMBAT, + 3008, 4736, + 2944, 4736, + 2944, 4864, + 3136, 4864, + 3136, 4736, + 3072, 4736, + 3072, 4800, + 3008, 4800); + } + + private static void defineDeadmanSafeZones() + { + // Varrock + addPolygonOnPlane(DEADMAN_SAFE_ZONES, 0, + 3182, 3382, + 3182, 3399, + 3174, 3399, + 3174, 3448, + 3198, 3448, + 3198, 3449, + 3197, 3449, + 3197, 3450, + 3196, 3450, + 3196, 3451, + 3195, 3451, + 3195, 3452, + 3194, 3452, + 3194, 3453, + 3193, 3453, + 3193, 3454, + 3192, 3454, + 3192, 3455, + 3191, 3455, + 3191, 3456, + 3190, 3456, + 3190, 3457, + 3185, 3457, + 3185, 3463, + 3186, 3463, + 3186, 3464, + 3187, 3464, + 3187, 3467, + 3167, 3467, + 3167, 3468, + 3163, 3468, + 3163, 3467, + 3142, 3467, + 3142, 3468, + 3141, 3468, + 3141, 3469, + 3140, 3469, + 3140, 3470, + 3139, 3470, + 3139, 3471, + 3138, 3471, + 3138, 3484, + 3139, 3484, + 3139, 3485, + 3140, 3485, + 3140, 3486, + 3141, 3486, + 3141, 3491, + 3140, 3491, + 3140, 3492, + 3139, 3492, + 3139, 3493, + 3138, 3493, + 3138, 3515, + 3139, 3515, + 3139, 3516, + 3140, 3516, + 3140, 3517, + 3141, 3517, + 3141, 3518, + 3160, 3518, + 3160, 3517, + 3161, 3517, + 3161, 3516, + 3162, 3516, + 3162, 3515, + 3167, 3515, + 3167, 3516, + 3168, 3516, + 3168, 3517, + 3169, 3517, + 3169, 3518, + 3191, 3518, + 3191, 3517, + 3192, 3517, + 3192, 3516, + 3193, 3516, + 3193, 3515, + 3194, 3515, + 3194, 3514, + 3195, 3514, + 3195, 3513, + 3196, 3513, + 3196, 3512, + 3197, 3512, + 3197, 3511, + 3198, 3511, + 3198, 3510, + 3199, 3510, + 3199, 3509, + 3200, 3509, + 3200, 3508, + 3230, 3508, + 3230, 3507, + 3231, 3507, + 3231, 3506, + 3232, 3506, + 3232, 3505, + 3233, 3505, + 3233, 3504, + 3234, 3504, + 3234, 3503, + 3235, 3503, + 3235, 3502, + 3252, 3502, + 3252, 3496, + 3253, 3496, + 3253, 3495, + 3254, 3495, + 3254, 3494, + 3255, 3494, + 3255, 3493, + 3263, 3493, + 3263, 3472, + 3264, 3472, + 3264, 3471, + 3265, 3471, + 3265, 3470, + 3266, 3470, + 3266, 3469, + 3267, 3469, + 3267, 3468, + 3268, 3468, + 3268, 3467, + 3269, 3467, + 3269, 3466, + 3270, 3466, + 3270, 3465, + 3271, 3465, + 3271, 3437, + 3274, 3437, + 3274, 3424, + 3277, 3424, + 3277, 3420, + 3274, 3420, + 3274, 3411, + 3275, 3411, + 3275, 3410, + 3276, 3410, + 3276, 3409, + 3277, 3409, + 3277, 3408, + 3288, 3408, + 3288, 3391, + 3289, 3391, + 3289, 3385, + 3290, 3385, + 3290, 3378, + 3289, 3378, + 3289, 3377, + 3288, 3377, + 3288, 3376, + 3265, 3376, + 3265, 3380, + 3253, 3380, + 3253, 3382, + 3245, 3382, + 3245, 3380, + 3242, 3380, + 3242, 3382, + 3239, 3382, + 3239, 3381, + 3209, 3381, + 3209, 3382, + 3282, 3382); + + // Lumbridge + addPolygonOnPlane(DEADMAN_SAFE_ZONES, 0, + 3201, 3257, + 3213, 3257, + 3213, 3264, + 3233, 3264, + 3233, 3257, + 3235, 3257, + 3235, 3241, + 3237, 3241, + 3237, 3237, + 3239, 3237, + 3239, 3231, + 3243, 3231, + 3243, 3220, + 3253, 3220, + 3253, 3217, + 3256, 3217, + 3256, 3212, + 3259, 3212, + 3259, 3190, + 3247, 3190, + 3247, 3191, + 3238, 3191, + 3238, 3195, + 3230, 3195, + 3230, 3201, + 3228, 3201, + 3228, 3202, + 3227, 3202, + 3227, 3205, + 3228, 3205, + 3228, 3207, + 3225, 3207, + 3225, 3206, + 3224, 3206, + 3224, 3205, + 3223, 3205, + 3223, 3204, + 3222, 3204, + 3222, 3203, + 3215, 3203, + 3215, 3202, + 3214, 3202, + 3214, 3201, + 3203, 3201, + 3203, 3202, + 3202, 3202, + 3202, 3203, + 3201, 3203, + 3201, 3217, + 3199, 3217, + 3199, 3220, + 3201, 3220); + + // Falador + addPolygonOnPlane(DEADMAN_SAFE_ZONES, 0, + 2986, 3395, + 2986, 3394, + 2987, 3394, + 2987, 3393, + 2996, 3393, + 2996, 3394, + 3002, 3394, + 3002, 3395, + 3009, 3395, + 3009, 3394, + 3010, 3394, + 3010, 3393, + 3011, 3393, + 3011, 3392, + 3021, 3392, + 3021, 3391, + 3022, 3391, + 3022, 3390, + 3041, 3390, + 3041, 3389, + 3047, 3389, + 3047, 3390, + 3062, 3390, + 3062, 3389, + 3063, 3389, + 3063, 3388, + 3064, 3388, + 3064, 3387, + 3065, 3387, + 3065, 3386, + 3066, 3386, + 3066, 3368, + 3065, 3368, + 3065, 3367, + 3064, 3367, + 3064, 3366, + 3063, 3366, + 3063, 3365, + 3062, 3365, + 3062, 3364, + 3061, 3364, + 3061, 3363, + 3060, 3363, + 3060, 3331, + 3061, 3331, + 3061, 3328, + 3058, 3328, + 3058, 3329, + 3025, 3329, + 3025, 3328, + 3024, 3328, + 3024, 3327, + 3016, 3327, + 3016, 3326, + 3015, 3326, + 3015, 3325, + 3014, 3325, + 3014, 3324, + 3013, 3324, + 3013, 3323, + 3008, 3323, + 3008, 3324, + 3006, 3324, + 3006, 3323, + 3002, 3323, + 3002, 3322, + 3001, 3322, + 3001, 3321, + 3000, 3321, + 3000, 3320, + 2999, 3320, + 2999, 3319, + 2998, 3319, + 2998, 3318, + 2997, 3318, + 2997, 3317, + 2996, 3317, + 2996, 3316, + 2992, 3316, + 2992, 3315, + 2991, 3315, + 2991, 3314, + 2990, 3314, + 2990, 3313, + 2989, 3313, + 2989, 3312, + 2988, 3312, + 2988, 3311, + 2987, 3311, + 2987, 3310, + 2986, 3310, + 2986, 3309, + 2966, 3309, + 2966, 3310, + 2956, 3310, + 2956, 3311, + 2941, 3311, + 2941, 3312, + 2940, 3312, + 2940, 3320, + 2936, 3320, + 2936, 3354, + 2937, 3354, + 2937, 3357, + 2936, 3357, + 2936, 3389, + 2937, 3389, + 2937, 3390, + 2938, 3390, + 2938, 3391, + 2939, 3391, + 2939, 3392, + 2940, 3392, + 2940, 3393, + 2943, 3393, + 2943, 3394, + 2944, 3394, + 2944, 3395, + 2950, 3395, + 2950, 3394, + 2956, 3394, + 2956, 3395); + + // Port phasmatys + addPolygonOnPlane(DEADMAN_SAFE_ZONES, 0, + 3650, 3456, + 3650, 3472, + 3651, 3472, + 3651, 3473, + 3652, 3473, + 3652, 3474, + 3653, 3474, + 3653, 3507, + 3654, 3507, + 3654, 3508, + 3668, 3508, + 3668, 3509, + 3669, 3509, + 3669, 3510, + 3670, 3510, + 3670, 3511, + 3671, 3511, + 3671, 3512, + 3672, 3512, + 3672, 3513, + 3673, 3513, + 3673, 3514, + 3674, 3514, + 3674, 3515, + 3675, 3515, + 3675, 3516, + 3676, 3516, + 3676, 3517, + 3687, 3517, + 3687, 3494, + 3690, 3494, + 3690, 3493, + 3696, 3493, + 3696, 3482, + 3699, 3482, + 3699, 3481, + 3712, 3481, + 3712, 3456); + + // Sophanem + addPolygonOnPlane(DEADMAN_SAFE_ZONES, 0, + 3274, 2752, + 3274, 2784, + 3277, 2784, + 3277, 2786, + 3274, 2786, + 3274, 2789, + 3272, 2789, + 3272, 2810, + 3322, 2810, + 3322, 2752); + + // Ardy + addPolygonOnPlane(DEADMAN_SAFE_ZONES, 0, + 2560, 3256, + 2560, 3264, + 2559, 3264, + 2559, 3328, + 2560, 3328, + 2560, 3339, + 2561, 3339, + 2561, 3340, + 2562, 3340, + 2562, 3341, + 2563, 3341, + 2563, 3342, + 2616, 3342, + 2616, 3341, + 2617, 3341, + 2617, 3340, + 2669, 3340, + 2669, 3339, + 2670, 3339, + 2670, 3338, + 2671, 3338, + 2671, 3337, + 2672, 3337, + 2672, 3336, + 2673, 3336, + 2673, 3335, + 2674, 3335, + 2674, 3334, + 2683, 3334, + 2683, 3333, + 2684, 3333, + 2684, 3332, + 2685, 3332, + 2685, 3331, + 2686, 3331, + 2686, 3330, + 2687, 3330, + 2687, 3329, + 2688, 3329, + 2688, 3264, + 2638, 3264, + 2638, 3263, + 2625, 3263, + 2625, 3264, + 2611, 3264, + 2611, 3257, + 2602, 3257, + 2602, 3264, + 2587, 3264, + 2587, 3263, + 2586, 3263, + 2586, 3262, + 2584, 3262, + 2584, 3261, + 2583, 3261, + 2583, 3260, + 2582, 3260, + 2582, 3259, + 2581, 3259, + 2581, 3258, + 2572, 3258, + 2572, 3260, + 2571, 3260, + 2571, 3261, + 2566, 3261, + 2566, 3260, + 2565, 3260, + 2565, 3259, + 2564, 3259, + 2564, 3256); + + // Yanille + addPolygonOnPlane(DEADMAN_SAFE_ZONES, 0, + 2613, 3103, + 2614, 3103, + 2614, 3102, + 2615, 3102, + 2615, 3101, + 2616, 3101, + 2616, 3100, + 2617, 3100, + 2617, 3099, + 2618, 3099, + 2618, 3098, + 2619, 3098, + 2619, 3097, + 2620, 3097, + 2620, 3075, + 2590, 3075, + 2590, 3074, + 2589, 3074, + 2589, 3073, + 2584, 3073, + 2584, 3074, + 2583, 3074, + 2583, 3075, + 2543, 3075, + 2543, 3076, + 2542, 3076, + 2542, 3077, + 2539, 3077, + 2539, 3107, + 2542, 3107, + 2542, 3108, + 2543, 3108, + 2543, 3109, + 2608, 3109, + 2608, 3108, + 2609, 3108, + 2609, 3107, + 2610, 3107, + 2610, 3106, + 2611, 3106, + 2611, 3105, + 2612, 3105, + 2612, 3104, + 2613, 3104); + + // Gnome stronghold + addPolygonOnPlane(DEADMAN_SAFE_ZONES, 0, + 2495, 3439, + 2494, 3439, + 2494, 3432, + 2495, 3432, + 2495, 3431, + 2496, 3431, + 2496, 3430, + 2497, 3430, + 2497, 3429, + 2498, 3429, + 2498, 3417, + 2497, 3417, + 2497, 3416, + 2496, 3416, + 2496, 3412, + 2495, 3412, + 2495, 3408, + 2494, 3408, + 2494, 3404, + 2495, 3404, + 2495, 3403, + 2496, 3403, + 2496, 3402, + 2497, 3402, + 2497, 3401, + 2498, 3401, + 2498, 3400, + 2499, 3400, + 2499, 3399, + 2500, 3399, + 2500, 3398, + 2501, 3398, + 2501, 3397, + 2502, 3397, + 2502, 3396, + 2506, 3396, + 2506, 3391, + 2502, 3391, + 2502, 3390, + 2492, 3390, + 2492, 3391, + 2489, 3391, + 2489, 3390, + 2488, 3390, + 2488, 3389, + 2485, 3389, + 2485, 3390, + 2482, 3390, + 2482, 3389, + 2476, 3389, + 2476, 3390, + 2471, 3390, + 2471, 3391, + 2468, 3391, + 2468, 3390, + 2467, 3390, + 2467, 3389, + 2466, 3389, + 2466, 3385, + 2465, 3385, + 2465, 3384, + 2458, 3384, + 2458, 3385, + 2457, 3385, + 2457, 3389, + 2456, 3389, + 2456, 3390, + 2455, 3390, + 2455, 3391, + 2450, 3391, + 2450, 3390, + 2446, 3390, + 2446, 3391, + 2443, 3391, + 2443, 3390, + 2442, 3390, + 2442, 3389, + 2440, 3389, + 2440, 3388, + 2434, 3388, + 2434, 3389, + 2433, 3389, + 2433, 3390, + 2432, 3390, + 2432, 3391, + 2428, 3391, + 2428, 3392, + 2427, 3392, + 2427, 3393, + 2420, 3393, + 2420, 3394, + 2419, 3394, + 2419, 3395, + 2418, 3395, + 2418, 3396, + 2417, 3396, + 2417, 3397, + 2416, 3397, + 2416, 3399, + 2415, 3399, + 2415, 3400, + 2414, 3400, + 2414, 3408, + 2413, 3408, + 2413, 3409, + 2412, 3409, + 2412, 3410, + 2411, 3410, + 2411, 3411, + 2410, 3411, + 2410, 3412, + 2387, 3412, + 2387, 3407, + 2383, 3407, + 2383, 3408, + 2380, 3408, + 2380, 3409, + 2379, 3409, + 2379, 3410, + 2377, 3410, + 2377, 3411, + 2376, 3411, + 2376, 3413, + 2375, 3413, + 2375, 3417, + 2374, 3417, + 2374, 3418, + 2373, 3418, + 2373, 3419, + 2372, 3419, + 2372, 3420, + 2371, 3420, + 2371, 3421, + 2370, 3421, + 2370, 3422, + 2369, 3422, + 2369, 3433, + 2370, 3433, + 2370, 3434, + 2371, 3434, + 2371, 3444, + 2372, 3444, + 2372, 3445, + 2373, 3445, + 2373, 3446, + 2374, 3446, + 2374, 3447, + 2375, 3447, + 2375, 3459, + 2376, 3459, + 2376, 3460, + 2377, 3460, + 2377, 3461, + 2378, 3461, + 2378, 3462, + 2379, 3462, + 2379, 3463, + 2380, 3463, + 2380, 3464, + 2381, 3464, + 2381, 3476, + 2379, 3476, + 2379, 3477, + 2378, 3477, + 2378, 3478, + 2377, 3478, + 2377, 3485, + 2376, 3485, + 2376, 3486, + 2375, 3486, + 2375, 3499, + 2376, 3499, + 2376, 3500, + 2377, 3500, + 2377, 3507, + 2378, 3507, + 2378, 3508, + 2379, 3508, + 2379, 3509, + 2380, 3509, + 2380, 3521, + 2382, 3521, + 2382, 3522, + 2384, 3522, + 2384, 3523, + 2393, 3523, + 2393, 3524, + 2399, 3524, + 2399, 3525, + 2404, 3525, + 2404, 3524, + 2405, 3524, + 2405, 3523, + 2407, 3523, + 2407, 3522, + 2415, 3522, + 2415, 3521, + 2425, 3521, + 2425, 3522, + 2427, 3522, + 2427, 3523, + 2430, 3523, + 2430, 3522, + 2431, 3522, + 2431, 3521, + 2432, 3521, + 2432, 3520, + 2448, 3520, + 2448, 3517, + 2454, 3517, + 2454, 3516, + 2455, 3516, + 2455, 3515, + 2456, 3515, + 2456, 3514, + 2457, 3514, + 2457, 3513, + 2460, 3513, + 2460, 3512, + 2461, 3512, + 2461, 3511, + 2465, 3511, + 2465, 3510, + 2468, 3510, + 2468, 3511, + 2472, 3511, + 2472, 3512, + 2473, 3512, + 2473, 3513, + 2475, 3513, + 2475, 3514, + 2476, 3514, + 2476, 3515, + 2477, 3515, + 2477, 3516, + 2478, 3516, + 2478, 3517, + 2483, 3517, + 2483, 3516, + 2487, 3516, + 2487, 3515, + 2488, 3515, + 2488, 3512, + 2487, 3512, + 2487, 3509, + 2488, 3509, + 2488, 3508, + 2489, 3508, + 2489, 3507, + 2491, 3507, + 2491, 3506, + 2492, 3506, + 2492, 3505, + 2493, 3505, + 2493, 3499, + 2492, 3499, + 2492, 3498, + 2491, 3498, + 2491, 3497, + 2490, 3497, + 2490, 3495, + 2491, 3495, + 2491, 3494, + 2492, 3494, + 2492, 3493, + 2493, 3493, + 2493, 3485, + 2490, 3485, + 2490, 3484, + 2489, 3484, + 2489, 3483, + 2488, 3483, + 2488, 3482, + 2487, 3482, + 2487, 3481, + 2486, 3481, + 2486, 3474, + 2488, 3474, + 2488, 3471, + 2489, 3471, + 2489, 3470, + 2490, 3470, + 2490, 3460, + 2491, 3460, + 2491, 3456, + 2496, 3456, + 2496, 3440, + 2495, 3440); + + // Rellekka + addPolygonOnPlane(DEADMAN_SAFE_ZONES, 0, + 2620, 3682, + 2624, 3682, + 2624, 3683, + 2625, 3683, + 2625, 3687, + 2629, 3687, + 2629, 3686, + 2630, 3686, + 2630, 3685, + 2632, 3685, + 2632, 3686, + 2636, 3686, + 2636, 3692, + 2645, 3692, + 2645, 3695, + 2647, 3695, + 2647, 3696, + 2649, 3696, + 2649, 3702, + 2650, 3702, + 2650, 3703, + 2651, 3703, + 2651, 3704, + 2652, 3704, + 2652, 3711, + 2653, 3711, + 2653, 3712, + 2691, 3712, + 2691, 3709, + 2692, 3709, + 2692, 3707, + 2693, 3707, + 2693, 3703, + 2692, 3703, + 2692, 3701, + 2691, 3701, + 2691, 3699, + 2690, 3699, + 2690, 3695, + 2691, 3695, + 2691, 3693, + 2692, 3693, + 2692, 3691, + 2693, 3691, + 2693, 3685, + 2692, 3685, + 2692, 3683, + 2691, 3683, + 2691, 3681, + 2690, 3681, + 2690, 3680, + 2689, 3680, + 2689, 3672, + 2690, 3672, + 2690, 3671, + 2691, 3671, + 2691, 3666, + 2690, 3666, + 2690, 3664, + 2689, 3664, + 2689, 3660, + 2690, 3660, + 2690, 3658, + 2691, 3658, + 2691, 3656, + 2692, 3656, + 2692, 3654, + 2693, 3654, + 2693, 3651, + 2692, 3651, + 2692, 3649, + 2690, 3649, + 2690, 3648, + 2688, 3648, + 2688, 3647, + 2686, 3647, + 2686, 3646, + 2673, 3646, + 2673, 3645, + 2636, 3645, + 2636, 3647, + 2627, 3647, + 2627, 3648, + 2625, 3648, + 2625, 3649, + 2624, 3649, + 2624, 3650, + 2622, 3650, + 2622, 3651, + 2620, 3651, + 2620, 3652, + 2618, 3652, + 2618, 3653, + 2616, 3653, + 2616, 3654, + 2609, 3654, + 2609, 3655, + 2607, 3655, + 2607, 3656, + 2603, 3656, + 2603, 3657, + 2602, 3657, + 2602, 3658, + 2601, 3658, + 2601, 3663, + 2602, 3663, + 2602, 3664, + 2603, 3664, + 2603, 3665, + 2604, 3665, + 2604, 3666, + 2605, 3666, + 2605, 3667, + 2606, 3667, + 2606, 3671, + 2609, 3671, + 2609, 3672, + 2610, 3672, + 2610, 3673, + 2611, 3673, + 2611, 3675, + 2612, 3675, + 2612, 3676, + 2614, 3676, + 2614, 3677, + 2616, 3677, + 2616, 3679, + 2618, 3679, + 2618, 3681, + 2620, 3681); + + // Jatizo + addPolygonOnPlane(DEADMAN_SAFE_ZONES, 0, + 2407, 3797, + 2407, 3793, + 2399, 3793, + 2399, 3792, + 2391, 3792, + 2391, 3791, + 2386, 3791, + 2386, 3796, + 2388, 3796, + 2388, 3802, + 2386, 3802, + 2386, 3807, + 2388, 3807, + 2388, 3809, + 2402, 3809, + 2402, 3819, + 2406, 3819, + 2406, 3824, + 2408, 3824, + 2408, 3826, + 2413, 3826, + 2413, 3824, + 2419, 3824, + 2419, 3826, + 2424, 3826, + 2424, 3821, + 2423, 3821, + 2423, 3798, + 2422, 3798, + 2422, 3797); + + // Neitiznot + addPolygonOnPlane(DEADMAN_SAFE_ZONES, 0, + 2329, 3812, + 2333, 3812, + 2333, 3813, + 2334, 3813, + 2334, 3814, + 2335, 3814, + 2335, 3815, + 2338, 3815, + 2338, 3816, + 2339, 3816, + 2339, 3817, + 2368, 3817, + 2368, 3776, + 2352, 3776, + 2352, 3796, + 2344, 3796, + 2344, 3795, + 2331, 3795, + 2331, 3797, + 2330, 3797, + 2330, 3798, + 2329, 3798); + + // Pest control + addPolygonOnPlane(DEADMAN_SAFE_ZONES, 0, + 2624, 2688, + 2688, 2688, + 2688, 2624, + 2624, 2624); + + // Tutorial island + addPolygonOnPlane(DEADMAN_SAFE_ZONES, 0, + 3052, 3135, + 3156, 3135, + 3156, 3057, + 3052, 3057); + + // Camelot bank + addPolygonOnPlane(DEADMAN_SAFE_ZONES, 0, + 2724, 3487, + 2724, 3490, + 2721, 3490, + 2721, 3494, + 2719, 3494, + 2719, 3497, + 2721, 3497, + 2721, 3498, + 2731, 3498, + 2731, 3490, + 2728, 3490, + 2728, 3487); + + // Catherby bank + addPolygonOnPlane(DEADMAN_SAFE_ZONES, 0, + 2806, 3438, + 2806, 3446, + 2813, 3446, + 2813, 3438); + + // Kourend castle + addPolygonOnPlane(DEADMAN_SAFE_ZONES, 0, + 1627, 3658, + 1620, 3658, + 1620, 3657, + 1619, 3657, + 1619, 3656, + 1614, 3656, + 1614, 3657, + 1613, 3657, + 1613, 3661, + 1612, 3661, + 1612, 3662, + 1611, 3662, + 1611, 3663, + 1600, 3663, + 1600, 3662, + 1599, 3662, + 1599, 3661, + 1594, 3661, + 1594, 3662, + 1593, 3662, + 1593, 3685, + 1594, 3685, + 1594, 3686, + 1599, 3686, + 1599, 3685, + 1600, 3685, + 1600, 3684, + 1611, 3684, + 1611, 3685, + 1612, 3685, + 1612, 3686, + 1613, 3686, + 1613, 3690, + 1614, 3690, + 1614, 3691, + 1619, 3691, + 1619, 3690, + 1620, 3690, + 1620, 3689, + 1630, 3689, + 1630, 3686, + 1620, 3686, + 1620, 3685, + 1619, 3685, + 1619, 3683, + 1620, 3683, + 1620, 3682, + 1621, 3682, + 1621, 3681, + 1622, 3681, + 1622, 3680, + 1623, 3680, + 1623, 3679, + 1624, 3679, + 1624, 3668, + 1623, 3668, + 1623, 3667, + 1622, 3667, + 1622, 3666, + 1621, 3666, + 1621, 3665, + 1620, 3665, + 1620, 3664, + 1619, 3664, + 1619, 3662, + 1620, 3662, + 1620, 3661, + 1627, 3661); + } + + private static void definePvpSafeZones() + { + // Grand exchange + addPolygonOnPlane(PVP_WORLD_SAFE_ZONES, 0, + 3159, 3473, + 3159, 3474, + 3157, 3474, + 3157, 3475, + 3155, 3475, + 3155, 3476, + 3153, 3476, + 3153, 3477, + 3152, 3477, + 3152, 3478, + 3151, 3478, + 3151, 3480, + 3150, 3480, + 3150, 3482, + 3149, 3482, + 3149, 3484, + 3148, 3484, + 3148, 3496, + 3149, 3496, + 3149, 3498, + 3150, 3498, + 3150, 3500, + 3151, 3500, + 3151, 3502, + 3152, 3502, + 3152, 3503, + 3153, 3503, + 3153, 3504, + 3155, 3504, + 3155, 3505, + 3157, 3505, + 3157, 3506, + 3159, 3506, + 3159, 3507, + 3171, 3507, + 3171, 3506, + 3173, 3506, + 3173, 3505, + 3175, 3505, + 3175, 3504, + 3177, 3504, + 3177, 3503, + 3178, 3503, + 3178, 3502, + 3179, 3502, + 3179, 3500, + 3180, 3500, + 3180, 3498, + 3181, 3498, + 3181, 3496, + 3182, 3496, + 3182, 3484, + 3181, 3484, + 3181, 3482, + 3180, 3482, + 3180, 3480, + 3179, 3480, + 3179, 3478, + 3178, 3478, + 3178, 3477, + 3177, 3477, + 3177, 3476, + 3175, 3476, + 3175, 3475, + 3173, 3475, + 3173, 3474, + 3171, 3474, + 3171, 3473); + + // Edgeville + addPolygonOnPlane(PVP_WORLD_SAFE_ZONES, 0, + 3091, 3488, + 3091, 3493, + 3090, 3493, + 3090, 3498, + 3091, 3498, + 3091, 3500, + 3099, 3500, + 3099, 3488); + + // Fally west bank + addPolygonOnPlane(PVP_WORLD_SAFE_ZONES, 0, + 2943, 3368, + 2943, 3374, + 2948, 3374, + 2948, 3370, + 2950, 3370, + 2950, 3366, + 2949, 3366, + 2949, 3359, + 2945, 3359, + 2945, 3362, + 2946, 3362, + 2946, 3366, + 2945, 3366, + 2945, 3368); + + // Fally east bank + addPolygonOnPlane(PVP_WORLD_SAFE_ZONES, 0, + 3009, 3353, + 3009, 3359, + 3019, 3359, + 3019, 3357, + 3022, 3357, + 3022, 3353); + + // Fally castle + addPolygonOnPlane(PVP_WORLD_SAFE_ZONES, 0, + 2964, 3354, + 2966, 3354, + 2966, 3352, + 2967, 3352, + 2967, 3349, + 2976, 3349, + 2976, 3348, + 2977, 3348, + 2977, 3347, + 2981, 3347, + 2981, 3343, + 2982, 3343, + 2982, 3339, + 2981, 3339, + 2981, 3337, + 2967, 3337, + 2967, 3330, + 2963, 3330, + 2963, 3331, + 2962, 3331, + 2962, 3332, + 2961, 3332, + 2961, 3334, + 2964, 3334, + 2964, 3335, + 2965, 3335, + 2965, 3343, + 2964, 3343, + 2964, 3344, + 2961, 3344, + 2961, 3350, + 2963, 3350, + 2963, 3352, + 2964, 3352); + + // Varrock east bank + addPolygonOnPlane(PVP_WORLD_SAFE_ZONES, 0, + 3250, 3425, + 3258, 3425, + 3258, 3416, + 3250, 3416); + + // Varrock west bank + addPolygonOnPlane(PVP_WORLD_SAFE_ZONES, 0, + 3180, 3433, + 3180, 3448, + 3191, 3448, + 3191, 3433); + + // Port phasmatys + addPolygonOnPlane(PVP_WORLD_SAFE_ZONES, 0, + 3686, 3472, + 3700, 3472, + 3700, 3461, + 3686, 3461); + + // Yanille bank + addPolygonOnPlane(PVP_WORLD_SAFE_ZONES, 0, + 2609, 3088, + 2609, 3098, + 2617, 3098, + 2617, 3088); + + // Ardy east bank + addPolygonOnPlane(PVP_WORLD_SAFE_ZONES, 0, + 2649, 3280, + 2649, 3288, + 2659, 3288, + 2659, 3280); + + // Ardy west bank + addPolygonOnPlane(PVP_WORLD_SAFE_ZONES, 0, + 2612, 3330, + 2612, 3336, + 2615, 3336, + 2615, 3335, + 2619, 3335, + 2619, 3336, + 2622, 3336, + 2622, 3330); + + // Fishing guild bank + addPolygonOnPlane(PVP_WORLD_SAFE_ZONES, 0, + 2593, 3413, + 2588, 3413, + 2588, 3418, + 2583, 3418, + 2583, 3423, + 2590, 3423, + 2590, 3420, + 2593, 3420); + + // Gnome stronghold bank near slayer cave (2nd floor) + addPolygonOnPlane(PVP_WORLD_SAFE_ZONES, 1, + 2444, 3431, + 2444, 3435, + 2448, 3435, + 2448, 3431, + 2447, 3431, + 2447, 3428, + 2449, 3428, + 2449, 3422, + 2447, 3422, + 2447, 3419, + 2448, 3419, + 2448, 3415, + 2444, 3415, + 2444, 3419, + 2445, 3419, + 2445, 3422, + 2443, 3422, + 2443, 3428, + 2445, 3428, + 2445, 3431); + + // Gnome stronghold bank in grand tree + addPolygonOnPlane(PVP_WORLD_SAFE_ZONES, 1, + 2456, 3488, + 2452, 3488, + 2452, 3486, + 2450, 3486, + 2450, 3483, + 2451, 3483, + 2451, 3478, + 2448, 3478, + 2448, 3483, + 2449, 3483, + 2449, 3486, + 2447, 3486, + 2447, 3488, + 2443, 3488, + 2443, 3487, + 2438, 3487, + 2438, 3490, + 2443, 3490, + 2443, 3489, + 2447, 3489, + 2447, 3491, + 2449, 3491, + 2449, 3494, + 2448, 3494, + 2448, 3496, + 2451, 3496, + 2451, 3494, + 2450, 3494, + 2450, 3491, + 2452, 3491, + 2452, 3489, + 2456, 3489); + + // Al kharid bank + addPolygonOnPlane(PVP_WORLD_SAFE_ZONES, 0, + 3265, 3161, + 3265, 3174, + 3273, 3174, + 3273, 3161); + + // Shantay pass bank + addPolygonOnPlane(PVP_WORLD_SAFE_ZONES, 0, + 3308, 3119, + 3308, 3125, + 3310, 3125, + 3310, 3119); + + // Nardah bank + addPolygonOnPlane(PVP_WORLD_SAFE_ZONES, 0, + 3431, 2891, + 3431, 2889, + 3427, 2889, + 3427, 2887, + 3424, 2887, + 3424, 2895, + 3431, 2895, + 3431, 2893, + 3432, 2893, + 3432, 2891); + + // Sophanem bank + addPolygonTo(PVP_WORLD_SAFE_ZONES, + 2807, 5158, + 2792, 5158, + 2792, 5175, + 2807, 5175); + + // Canifis bank + addPolygonOnPlane(PVP_WORLD_SAFE_ZONES, 0, + 3509, 3474, + 3509, 3478, + 3508, 3478, + 3508, 3483, + 3509, 3483, + 3509, 3484, + 3517, 3484, + 3517, 3477, + 3516, 3477, + 3516, 3476, + 3513, 3476, + 3513, 3474); + + // Lumbridge castle outside + addPolygonOnPlane(PVP_WORLD_SAFE_ZONES, 0, + 3216, 3209, + 3216, 3210, + 3217, 3210, + 3217, 3228, + 3216, 3228, + 3216, 3229, + 3227, 3229, + 3227, 3221, + 3230, 3221, + 3230, 3217, + 3227, 3217, + 3227, 3209); + + // Lumbridge bank upstairs + addPolygonOnPlane(PVP_WORLD_SAFE_ZONES, 2, + 3211, 3223, + 3211, 3215, + 3207, 3215, + 3207, 3223); + + // Draynor bank + addPolygonOnPlane(PVP_WORLD_SAFE_ZONES, 0, + 3098, 3240, + 3088, 3240, + 3088, 3247, + 3098, 3247); + + // Pest control bank + addPolygonOnPlane(PVP_WORLD_SAFE_ZONES, 0, + 2665, 2656, + 2670, 2656, + 2670, 2651, + 2665, 2651); + + // Shilo village bank + addPolygonOnPlane(PVP_WORLD_SAFE_ZONES, 0, + 2843, 2957, + 2846, 2957, + 2846, 2956, + 2849, 2956, + 2849, 2957, + 2850, 2957, + 2850, 2958, + 2855, 2958, + 2855, 2957, + 2856, 2957, + 2856, 2956, + 2858, 2956, + 2858, 2957, + 2862, 2957, + 2862, 2952, + 2858, 2952, + 2858, 2953, + 2856, 2953, + 2856, 2952, + 2855, 2952, + 2855, 2951, + 2850, 2951, + 2850, 2952, + 2849, 2952, + 2849, 2953, + 2847, 2953, + 2847, 2952, + 2843, 2952); + + // Legends guild bank + addPolygonOnPlane(PVP_WORLD_SAFE_ZONES, 2, + 2731, 3374, + 2731, 3383, + 2734, 3383, + 2734, 3374); + + // Legends guild middle floor + addPolygonOnPlane(PVP_WORLD_SAFE_ZONES, 1, + 2724, 3374, + 2724, 3383, + 2734, 3383, + 2734, 3382, + 2736, 3382, + 2736, 3375, + 2734, 3375, + 2734, 3374); + + // Warriors guild bank + addPolygonOnPlane(PVP_WORLD_SAFE_ZONES, 0, + 2843, 3537, + 2843, 3540, + 2841, 3540, + 2841, 3546, + 2849, 3546, + 2849, 3537, + 2847, 3537, + 2847, 3536, + 2846, 3536, + 2846, 3537); + + // Camelot bank + addPolygonOnPlane(PVP_WORLD_SAFE_ZONES, 0, + 2724, 3487, + 2724, 3490, + 2721, 3490, + 2721, 3494, + 2719, 3494, + 2719, 3497, + 2721, 3497, + 2721, 3498, + 2731, 3498, + 2731, 3490, + 2728, 3490, + 2728, 3487); + + // Camelot respawn point + addPolygonOnPlane(PVP_WORLD_SAFE_ZONES, 0, + 2761, 3483, + 2761, 3476, + 2755, 3476, + 2755, 3483); + + // Catherby bank + addPolygonOnPlane(PVP_WORLD_SAFE_ZONES, 0, + 2806, 3438, + 2806, 3446, + 2813, 3446, + 2813, 3438); + + // Barbarian outpost bank + addPolygonOnPlane(PVP_WORLD_SAFE_ZONES, 0, + 2536, 3572, + 2536, 3575, + 2538, 3575, + 2538, 3572); + + // Piscatoris bank + addPolygonOnPlane(PVP_WORLD_SAFE_ZONES, 0, + 2327, 3686, + 2327, 3694, + 2333, 3694, + 2333, 3686); + + // Lletya bank + addPolygonOnPlane(PVP_WORLD_SAFE_ZONES, 0, + 2350, 3161, + 2350, 3165, + 2351, 3165, + 2351, 3167, + 2357, 3167, + 2357, 3165, + 2356, 3165, + 2356, 3164, + 2355, 3164, + 2355, 3161); + + // Castle wars bank + addPolygonOnPlane(PVP_WORLD_SAFE_ZONES, 0, + 2446, 3087, + 2445, 3087, + 2445, 3085, + 2447, 3085, + 2447, 3081, + 2443, 3081, + 2443, 3082, + 2439, 3082, + 2439, 3081, + 2435, 3081, + 2435, 3099, + 2439, 3099, + 2439, 3098, + 2443, 3098, + 2443, 3099, + 2447, 3099, + 2447, 3095, + 2445, 3095, + 2445, 3093, + 2446, 3093); + + // Duel arena bank + addPolygonOnPlane(PVP_WORLD_SAFE_ZONES, 0, + 3380, 3267, + 3380, 3273, + 3381, 3273, + 3381, 3274, + 3385, 3274, + 3385, 3267); + + // Clan wars bank + addPolygonOnPlane(PVP_WORLD_SAFE_ZONES, 0, + 3375, 3165, + 3361, 3165, + 3361, 3173, + 3375, 3173); + + // Lumbridge cellar bank + addPolygonTo(PVP_WORLD_SAFE_ZONES, + 3218, 9622, + 3218, 9624, + 3220, 9624, + 3220, 9622); + + // Dorgesh kaan bank + addPolygonOnPlane(PVP_WORLD_SAFE_ZONES, 0, + 2709, 5348, + 2707, 5348, + 2707, 5345, + 2701, 5345, + 2701, 5347, + 2697, 5347, + 2697, 5353, + 2701, 5353, + 2701, 5355, + 2707, 5355, + 2707, 5350, + 2709, 5350); + + // Keldagrim bank + addPolygonOnPlane(PVP_WORLD_SAFE_ZONES, 0, + 2842, 10204, + 2834, 10204, + 2834, 10216, + 2842, 10216); + + // Tzhaar bank + addPolygonTo(PVP_WORLD_SAFE_ZONES, + 2438, 5176, + 2438, 5180, + 2441, 5180, + 2441, 5182, + 2449, 5182, + 2449, 5181, + 2450, 5181, + 2450, 5180, + 2452, 5180, + 2452, 5175, + 2441, 5175, + 2441, 5176); + + // Inferno bank + addPolygonTo(PVP_WORLD_SAFE_ZONES, + 2542, 5135, + 2542, 5139, + 2539, 5139, + 2539, 5140, + 2538, 5140, + 2538, 5141, + 2537, 5141, + 2537, 5144, + 2541, 5144, + 2541, 5145, + 2543, 5145, + 2543, 5144, + 2544, 5144, + 2544, 5142, + 2545, 5142, + 2545, 5135); + + // Port khazard bank + addPolygonOnPlane(PVP_WORLD_SAFE_ZONES, 0, + 2661, 3160, + 2661, 3163, + 2666, 3163, + 2666, 3160); + + // Corsair cove bank + addPolygonOnPlane(PVP_WORLD_SAFE_ZONES, 0, + 2569, 2863, + 2569, 2868, + 2572, 2868, + 2572, 2863); + + // Burgh de rott bank + addPolygonOnPlane(PVP_WORLD_SAFE_ZONES, 0, + 3495, 3210, + 3495, 3214, + 3501, 3214, + 3501, 3210); + + // Edgeville respawn point + addPolygonOnPlane(PVP_WORLD_SAFE_ZONES, 0, + 3092, 3468, + 3092, 3474, + 3098, 3474, + 3098, 3468); + + // Mage bank + addPolygonTo(PVP_WORLD_SAFE_ZONES, + 2529, 4711, + 2529, 4724, + 2548, 4724, + 2548, 4711); + + // Lunar bank + addPolygonOnPlane(PVP_WORLD_SAFE_ZONES, 0, + 2097, 3917, + 2097, 3922, + 2105, 3922, + 2105, 3917); + + // Jatizo bank + addPolygonOnPlane(PVP_WORLD_SAFE_ZONES, 0, + 2414, 3801, + 2414, 3804, + 2420, 3804, + 2420, 3801); + + // Neitiznot bank + addPolygonOnPlane(PVP_WORLD_SAFE_ZONES, 0, + 2334, 3805, + 2334, 3809, + 2340, 3809, + 2340, 3805); + + // Hosidius bank + addPolygonOnPlane(PVP_WORLD_SAFE_ZONES, 0, + 1671, 3558, + 1671, 3577, + 1682, 3577, + 1682, 3558); + + // Woodcutting guild bank + addPolygonOnPlane(PVP_WORLD_SAFE_ZONES, 0, + 1589, 3475, + 1589, 3481, + 1594, 3481, + 1594, 3475); + + // Lands end bank + addPolygonOnPlane(PVP_WORLD_SAFE_ZONES, 0, + 1508, 3415, + 1508, 3424, + 1514, 3424, + 1514, 3415); + + // Chambers of xeric bank + addPolygonOnPlane(PVP_WORLD_SAFE_ZONES, 0, + 1252, 3570, + 1252, 3574, + 1257, 3574, + 1257, 3570); + + // Arceuus bank + addPolygonOnPlane(PVP_WORLD_SAFE_ZONES, 0, + 1621, 3736, + 1621, 3754, + 1627, 3754, + 1627, 3751, + 1633, 3751, + 1633, 3754, + 1639, 3754, + 1639, 3736); + + // Piscarilius bank + addPolygonOnPlane(PVP_WORLD_SAFE_ZONES, 0, + 1794, 3784, + 1794, 3794, + 1812, 3794, + 1812, 3784); + + // Lovakengj bank southeast + addPolygonOnPlane(PVP_WORLD_SAFE_ZONES, 0, + 1518, 3735, + 1518, 3744, + 1535, 3744, + 1535, 3735); + + // Lovakenj bank west + addPolygonOnPlane(PVP_WORLD_SAFE_ZONES, 0, + 1433, 3820, + 1433, 3837, + 1442, 3837, + 1442, 3820); + + // Lovakenj sulphur mine bank + addPolygonOnPlane(PVP_WORLD_SAFE_ZONES, 0, + 1452, 3855, + 1452, 3860, + 1455, 3860, + 1455, 3855); + + // Blast mine bank southeast + addPolygonOnPlane(PVP_WORLD_SAFE_ZONES, 0, + 1500, 3856, + 1500, 3858, + 1503, 3858, + 1503, 3856); + + // Wintertodt bank + addPolygonOnPlane(PVP_WORLD_SAFE_ZONES, 0, + 1638, 3942, + 1638, 3947, + 1642, 3947, + 1642, 3942); + + // Shayzien bank + addPolygonOnPlane(PVP_WORLD_SAFE_ZONES, 0, + 1495, 3612, + 1495, 3622, + 1515, 3622, + 1515, 3612); + + // Hosidius grape farm bank + addPolygonOnPlane(PVP_WORLD_SAFE_ZONES, 0, + 1804, 3571, + 1804, 3572, + 1808, 3572, + 1808, 3571); + + // Hosidius cooking bank + addPolygonOnPlane(PVP_WORLD_SAFE_ZONES, 0, + 1652, 3605, + 1652, 3615, + 1661, 3615, + 1661, 3605); + + // Ecteria bank + addPolygonOnPlane(PVP_WORLD_SAFE_ZONES, 0, + 2618, 3893, + 2618, 3897, + 2622, 3897, + 2622, 3893); + + // Mining guild expanded area + addPolygonTo(PVP_WORLD_SAFE_ZONES, + 3018, 9733, + 3021, 9733, + 3021, 9729, + 3022, 9729, + 3022, 9728, + 3023, 9728, + 3023, 9727, + 3025, 9727, + 3025, 9726, + 3026, 9726, + 3026, 9725, + 3030, 9725, + 3030, 9726, + 3032, 9726, + 3032, 9727, + 3035, 9727, + 3035, 9726, + 3038, 9726, + 3038, 9727, + 3041, 9727, + 3041, 9728, + 3042, 9728, + 3042, 9730, + 3045, 9730, + 3045, 9727, + 3047, 9727, + 3047, 9726, + 3048, 9726, + 3048, 9724, + 3052, 9724, + 3052, 9725, + 3053, 9725, + 3053, 9726, + 3055, 9726, + 3055, 9725, + 3056, 9725, + 3056, 9723, + 3057, 9723, + 3057, 9720, + 3056, 9720, + 3056, 9719, + 3054, 9719, + 3054, 9718, + 3052, 9718, + 3052, 9717, + 3050, 9717, + 3050, 9718, + 3045, 9718, + 3045, 9716, + 3044, 9716, + 3044, 9715, + 3041, 9715, + 3041, 9714, + 3039, 9714, + 3039, 9713, + 3037, 9713, + 3037, 9714, + 3036, 9714, + 3036, 9715, + 3034, 9715, + 3034, 9716, + 3029, 9716, + 3029, 9715, + 3028, 9715, + 3028, 9714, + 3026, 9714, + 3026, 9709, + 3027, 9709, + 3027, 9708, + 3028, 9708, + 3028, 9705, + 3029, 9705, + 3029, 9701, + 3028, 9701, + 3028, 9700, + 3027, 9700, + 3027, 9699, + 3023, 9699, + 3023, 9700, + 3019, 9700, + 3019, 9701, + 3018, 9701, + 3018, 9705, + 3019, 9705, + 3019, 9707, + 3020, 9707, + 3020, 9708, + 3021, 9708, + 3021, 9709, + 3022, 9709, + 3022, 9713, + 3021, 9713, + 3021, 9714, + 3019, 9714, + 3019, 9715, + 3018, 9715, + 3018, 9717, + 3015, 9717, + 3015, 9716, + 3013, 9716, + 3013, 9717, + 3012, 9717, + 3012, 9720, + 3013, 9720, + 3013, 9721, + 3015, 9721, + 3015, 9723, + 3016, 9723, + 3016, 9727, + 3017, 9727, + 3017, 9730, + 3018, 9730); + + // Motherlode mine bank + addPolygonTo(PVP_WORLD_SAFE_ZONES, + 3760, 5671, + 3760, 5668, + 3761, 5668, + 3761, 5665, + 3760, 5665, + 3760, 5663, + 3758, 5663, + 3758, 5671); + + // Mos le harmles bank + addPolygonOnPlane(PVP_WORLD_SAFE_ZONES, 0, + 3679, 2980, + 3679, 2985, + 3681, 2985, + 3681, 2984, + 3682, 2984, + 3682, 2985, + 3684, 2985, + 3684, 2980, + 3682, 2980, + 3682, 2981, + 3681, 2981, + 3681, 2980); + + // Zanaris bank + addPolygonTo(PVP_WORLD_SAFE_ZONES, + 2388, 4454, + 2380, 4454, + 2380, 4463, + 2388, 4463); + + // Wodcuting guild bank underground + addPolygonTo(PVP_WORLD_SAFE_ZONES, + 1550, 9872, + 1550, 9874, + 1553, 9874, + 1553, 9872); + } + + private static void defineWilderness() + { + // Above ground + addPolygonTo(ROUGH_WILDERNESS, + 2944, 3523, + 3392, 3523, + 3392, 3971, + 2944, 3971); + + // Underground + addPolygonTo(ROUGH_WILDERNESS, + 2944, 9918, + 2944, 10360, + 3264, 10360, + 3264, 9918); + } + + private static void addPolygonTo(List[] shapes, int... coords) + { + Polygon poly = new Polygon(); + for (int i = 0; i < coords.length; i += 2) + { + poly.addPoint(coords[i], coords[i + 1]); + } + for (int i = 0; i < shapes.length; i++) + { + shapes[i].add(poly); + } + } + + private static void addPolygonOnPlane(List[] shapes, int plane, int... coords) + { + Polygon poly = new Polygon(); + for (int i = 0; i < coords.length; i += 2) + { + poly.addPoint(coords[i], coords[i + 1]); + } + shapes[plane].add(poly); + } + + private static void addPolygonOnPlanes(List[] shapes, int minPlane, int maxPlane, int... coords) + { + Polygon poly = new Polygon(); + for (int i = 0; i < coords.length; i += 2) + { + poly.addPoint(coords[i], coords[i + 1]); + } + for (int i = minPlane; i <= maxPlane; i++) + { + shapes[i].add(poly); + } + } } \ No newline at end of file diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/multiindicators/MultiIndicatorsConfig.java b/runelite-client/src/main/java/net/runelite/client/plugins/multiindicators/MultiIndicatorsConfig.java index 0436d936ce..6101dbf3c1 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/multiindicators/MultiIndicatorsConfig.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/multiindicators/MultiIndicatorsConfig.java @@ -1,111 +1,111 @@ -/* - * Copyright (c) 2018, Woox - * 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.multiindicators; - -import java.awt.Color; -import net.runelite.client.config.Config; -import net.runelite.client.config.ConfigGroup; -import net.runelite.client.config.ConfigItem; - -@ConfigGroup("multiindicators") -public interface MultiIndicatorsConfig extends Config -{ - @ConfigItem( - keyName = "multicombatZoneVisibility", - name = "Multicombat zones", - description = "Determine where multicombat zones should be shown", - position = 1 - ) - default ZoneVisibility multicombatZoneVisibility() - { - return ZoneVisibility.SHOW_IN_PVP; - } - - @ConfigItem( - keyName = "pvpSafeZones", - name = "PvP safe zones", - description = "Show safe zones in PvP worlds", - position = 2 - ) - default boolean showPvpSafeZones() - { - return true; - } - - @ConfigItem( - keyName = "deadmanSafeZones", - name = "Deadman safe zones", - description = "Show safe zones in Deadman worlds", - position = 3 - ) - default boolean showDeadmanSafeZones() - { - return true; - } - - @ConfigItem( - keyName = "collisionDetection", - name = "Collision detection", - description = "Only show lines where they can be walked through", - position = 4 - ) - default boolean collisionDetection() - { - return false; - } - - @ConfigItem( - keyName = "showMinimapLines", - name = "Show on minimap", - description = "Show multicombat and safe zones on the minimap", - position = 5 - ) - default boolean showMinimapLines() - { - return true; - } - - @ConfigItem( - keyName = "multicombatColor", - name = "Multicombat zone color", - description = "Choose color to use for marking multicombat zones", - position = 6 - ) - default Color multicombatColor() - { - return Color.MAGENTA; - } - - @ConfigItem( - keyName = "safeZoneColor", - name = "Safe zone color", - description = "Choose color to use for marking safe zones in PvP/Deadman", - position = 7 - ) - default Color safeZoneColor() - { - return Color.GREEN; - } +/* + * Copyright (c) 2018, Woox + * 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.multiindicators; + +import java.awt.Color; +import net.runelite.client.config.Config; +import net.runelite.client.config.ConfigGroup; +import net.runelite.client.config.ConfigItem; + +@ConfigGroup("multiindicators") +public interface MultiIndicatorsConfig extends Config +{ + @ConfigItem( + keyName = "multicombatZoneVisibility", + name = "Multicombat zones", + description = "Determine where multicombat zones should be shown", + position = 1 + ) + default ZoneVisibility multicombatZoneVisibility() + { + return ZoneVisibility.SHOW_IN_PVP; + } + + @ConfigItem( + keyName = "pvpSafeZones", + name = "PvP safe zones", + description = "Show safe zones in PvP worlds", + position = 2 + ) + default boolean showPvpSafeZones() + { + return true; + } + + @ConfigItem( + keyName = "deadmanSafeZones", + name = "Deadman safe zones", + description = "Show safe zones in Deadman worlds", + position = 3 + ) + default boolean showDeadmanSafeZones() + { + return true; + } + + @ConfigItem( + keyName = "collisionDetection", + name = "Collision detection", + description = "Only show lines where they can be walked through", + position = 4 + ) + default boolean collisionDetection() + { + return false; + } + + @ConfigItem( + keyName = "showMinimapLines", + name = "Show on minimap", + description = "Show multicombat and safe zones on the minimap", + position = 5 + ) + default boolean showMinimapLines() + { + return true; + } + + @ConfigItem( + keyName = "multicombatColor", + name = "Multicombat zone color", + description = "Choose color to use for marking multicombat zones", + position = 6 + ) + default Color multicombatColor() + { + return Color.MAGENTA; + } + + @ConfigItem( + keyName = "safeZoneColor", + name = "Safe zone color", + description = "Choose color to use for marking safe zones in PvP/Deadman", + position = 7 + ) + default Color safeZoneColor() + { + return Color.GREEN; + } } \ No newline at end of file diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/multiindicators/MultiIndicatorsMinimapOverlay.java b/runelite-client/src/main/java/net/runelite/client/plugins/multiindicators/MultiIndicatorsMinimapOverlay.java index a0d87a4691..016785bfd2 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/multiindicators/MultiIndicatorsMinimapOverlay.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/multiindicators/MultiIndicatorsMinimapOverlay.java @@ -1,116 +1,116 @@ -/* - * Copyright (c) 2018, Woox - * 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.multiindicators; - -import java.awt.Color; -import java.awt.Dimension; -import java.awt.Graphics2D; -import java.awt.Rectangle; -import java.awt.geom.GeneralPath; -import javax.inject.Inject; -import net.runelite.api.Client; -import net.runelite.api.Perspective; -import net.runelite.api.Point; -import net.runelite.api.coords.LocalPoint; -import net.runelite.api.geometry.Geometry; -import net.runelite.client.ui.overlay.Overlay; -import net.runelite.client.ui.overlay.OverlayLayer; -import net.runelite.client.ui.overlay.OverlayPosition; -import net.runelite.client.ui.overlay.OverlayPriority; - -public class MultiIndicatorsMinimapOverlay extends Overlay -{ - private final static int MAX_LOCAL_DRAW_LENGTH = 20 * Perspective.LOCAL_TILE_SIZE; - - @Inject - private Client client; - - @Inject - private MultiIndicatorsPlugin plugin; - - @Inject - private MultiIndicatorsConfig config; - - @Inject - public MultiIndicatorsMinimapOverlay() - { - setPosition(OverlayPosition.DYNAMIC); - setLayer(OverlayLayer.ALWAYS_ON_TOP); - setPriority(OverlayPriority.LOW); - } - - private Color getTransparentColorVersion(Color c) - { - return new Color(c.getRed(), c.getGreen(), c.getBlue(), 192); - } - - private void renderPath(Graphics2D graphics, GeneralPath path, Color color) - { - LocalPoint playerLp = client.getLocalPlayer().getLocalLocation(); - Rectangle viewArea = new Rectangle( - playerLp.getX() - MAX_LOCAL_DRAW_LENGTH, - playerLp.getY() - MAX_LOCAL_DRAW_LENGTH, - MAX_LOCAL_DRAW_LENGTH * 2, - MAX_LOCAL_DRAW_LENGTH * 2); - - graphics.setColor(color); - - path = Geometry.clipPath(path, viewArea); - path = Geometry.filterPath(path, (p1, p2) -> - Perspective.localToMinimap(client, new LocalPoint((int)p1[0], (int)p1[1])) != null && - Perspective.localToMinimap(client, new LocalPoint((int)p2[0], (int)p2[1])) != null); - path = Geometry.transformPath(path, coords -> - { - Point point = Perspective.localToMinimap(client, new LocalPoint((int)coords[0], (int)coords[1])); - coords[0] = point.getX(); - coords[1] = point.getY(); - }); - - graphics.draw(path); - } - - @Override - public Dimension render(Graphics2D graphics) - { - if (!config.showMinimapLines()) - { - return null; - } - - GeneralPath multicombatPath = plugin.getMulticombatPathToDisplay()[client.getPlane()]; - GeneralPath pvpPath = plugin.getPvpPathToDisplay()[client.getPlane()]; - - if (config.multicombatZoneVisibility() != ZoneVisibility.HIDE && multicombatPath != null) - { - renderPath(graphics, multicombatPath, getTransparentColorVersion(config.multicombatColor())); - } - if ((config.showPvpSafeZones() || config.showDeadmanSafeZones()) && pvpPath != null) - { - renderPath(graphics, pvpPath, getTransparentColorVersion(config.safeZoneColor())); - } - - return null; - } +/* + * Copyright (c) 2018, Woox + * 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.multiindicators; + +import java.awt.Color; +import java.awt.Dimension; +import java.awt.Graphics2D; +import java.awt.Rectangle; +import java.awt.geom.GeneralPath; +import javax.inject.Inject; +import net.runelite.api.Client; +import net.runelite.api.Perspective; +import net.runelite.api.Point; +import net.runelite.api.coords.LocalPoint; +import net.runelite.api.geometry.Geometry; +import net.runelite.client.ui.overlay.Overlay; +import net.runelite.client.ui.overlay.OverlayLayer; +import net.runelite.client.ui.overlay.OverlayPosition; +import net.runelite.client.ui.overlay.OverlayPriority; + +public class MultiIndicatorsMinimapOverlay extends Overlay +{ + private final static int MAX_LOCAL_DRAW_LENGTH = 20 * Perspective.LOCAL_TILE_SIZE; + + @Inject + private Client client; + + @Inject + private MultiIndicatorsPlugin plugin; + + @Inject + private MultiIndicatorsConfig config; + + @Inject + public MultiIndicatorsMinimapOverlay() + { + setPosition(OverlayPosition.DYNAMIC); + setLayer(OverlayLayer.ALWAYS_ON_TOP); + setPriority(OverlayPriority.LOW); + } + + private Color getTransparentColorVersion(Color c) + { + return new Color(c.getRed(), c.getGreen(), c.getBlue(), 192); + } + + private void renderPath(Graphics2D graphics, GeneralPath path, Color color) + { + LocalPoint playerLp = client.getLocalPlayer().getLocalLocation(); + Rectangle viewArea = new Rectangle( + playerLp.getX() - MAX_LOCAL_DRAW_LENGTH, + playerLp.getY() - MAX_LOCAL_DRAW_LENGTH, + MAX_LOCAL_DRAW_LENGTH * 2, + MAX_LOCAL_DRAW_LENGTH * 2); + + graphics.setColor(color); + + path = Geometry.clipPath(path, viewArea); + path = Geometry.filterPath(path, (p1, p2) -> + Perspective.localToMinimap(client, new LocalPoint((int) p1[0], (int) p1[1])) != null && + Perspective.localToMinimap(client, new LocalPoint((int) p2[0], (int) p2[1])) != null); + path = Geometry.transformPath(path, coords -> + { + Point point = Perspective.localToMinimap(client, new LocalPoint((int) coords[0], (int) coords[1])); + coords[0] = point.getX(); + coords[1] = point.getY(); + }); + + graphics.draw(path); + } + + @Override + public Dimension render(Graphics2D graphics) + { + if (!config.showMinimapLines()) + { + return null; + } + + GeneralPath multicombatPath = plugin.getMulticombatPathToDisplay()[client.getPlane()]; + GeneralPath pvpPath = plugin.getPvpPathToDisplay()[client.getPlane()]; + + if (config.multicombatZoneVisibility() != ZoneVisibility.HIDE && multicombatPath != null) + { + renderPath(graphics, multicombatPath, getTransparentColorVersion(config.multicombatColor())); + } + if ((config.showPvpSafeZones() || config.showDeadmanSafeZones()) && pvpPath != null) + { + renderPath(graphics, pvpPath, getTransparentColorVersion(config.safeZoneColor())); + } + + return null; + } } \ No newline at end of file diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/multiindicators/MultiIndicatorsOverlay.java b/runelite-client/src/main/java/net/runelite/client/plugins/multiindicators/MultiIndicatorsOverlay.java index 242effb5aa..a4e4424627 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/multiindicators/MultiIndicatorsOverlay.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/multiindicators/MultiIndicatorsOverlay.java @@ -1,113 +1,113 @@ -/* - * Copyright (c) 2018, Woox - * 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.multiindicators; - -import java.awt.BasicStroke; -import java.awt.Color; -import java.awt.Dimension; -import java.awt.Graphics2D; -import java.awt.Rectangle; -import java.awt.geom.GeneralPath; -import javax.inject.Inject; -import net.runelite.api.Client; -import net.runelite.api.Perspective; -import net.runelite.api.Point; -import net.runelite.api.coords.LocalPoint; -import net.runelite.api.geometry.Geometry; -import net.runelite.client.ui.overlay.Overlay; -import net.runelite.client.ui.overlay.OverlayLayer; -import net.runelite.client.ui.overlay.OverlayPosition; -import net.runelite.client.ui.overlay.OverlayPriority; - -public class MultiIndicatorsOverlay extends Overlay -{ - private final static int MAX_LOCAL_DRAW_LENGTH = 20 * Perspective.LOCAL_TILE_SIZE; - - @Inject - private Client client; - - @Inject - private MultiIndicatorsPlugin plugin; - - @Inject - private MultiIndicatorsConfig config; - - @Inject - public MultiIndicatorsOverlay() - { - setPosition(OverlayPosition.DYNAMIC); - setLayer(OverlayLayer.ABOVE_SCENE); - setPriority(OverlayPriority.LOW); - } - - private Color getTransparentColorVersion(Color c) - { - return new Color(c.getRed(), c.getGreen(), c.getBlue(), 92); - } - - private void renderPath(Graphics2D graphics, GeneralPath path, Color color) - { - LocalPoint playerLp = client.getLocalPlayer().getLocalLocation(); - Rectangle viewArea = new Rectangle( - playerLp.getX() - MAX_LOCAL_DRAW_LENGTH, - playerLp.getY() - MAX_LOCAL_DRAW_LENGTH, - MAX_LOCAL_DRAW_LENGTH * 2, - MAX_LOCAL_DRAW_LENGTH * 2); - - graphics.setColor(color); - graphics.setStroke(new BasicStroke(2)); - - path = Geometry.clipPath(path, viewArea); - path = Geometry.filterPath(path, (p1, p2) -> - Perspective.localToCanvas(client, new LocalPoint((int)p1[0], (int)p1[1]), client.getPlane()) != null && - Perspective.localToCanvas(client, new LocalPoint((int)p2[0], (int)p2[1]), client.getPlane()) != null); - path = Geometry.transformPath(path, coords -> - { - Point point = Perspective.localToCanvas(client, new LocalPoint((int)coords[0], (int)coords[1]), client.getPlane()); - coords[0] = point.getX(); - coords[1] = point.getY(); - }); - - graphics.draw(path); - } - - @Override - public Dimension render(Graphics2D graphics) - { - GeneralPath multicombatPath = plugin.getMulticombatPathToDisplay()[client.getPlane()]; - GeneralPath pvpPath = plugin.getPvpPathToDisplay()[client.getPlane()]; - - if (config.multicombatZoneVisibility() != ZoneVisibility.HIDE && multicombatPath != null) - { - renderPath(graphics, multicombatPath, getTransparentColorVersion(config.multicombatColor())); - } - if ((config.showPvpSafeZones() || config.showDeadmanSafeZones()) && pvpPath != null) - { - renderPath(graphics, pvpPath, getTransparentColorVersion(config.safeZoneColor())); - } - - return null; - } +/* + * Copyright (c) 2018, Woox + * 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.multiindicators; + +import java.awt.BasicStroke; +import java.awt.Color; +import java.awt.Dimension; +import java.awt.Graphics2D; +import java.awt.Rectangle; +import java.awt.geom.GeneralPath; +import javax.inject.Inject; +import net.runelite.api.Client; +import net.runelite.api.Perspective; +import net.runelite.api.Point; +import net.runelite.api.coords.LocalPoint; +import net.runelite.api.geometry.Geometry; +import net.runelite.client.ui.overlay.Overlay; +import net.runelite.client.ui.overlay.OverlayLayer; +import net.runelite.client.ui.overlay.OverlayPosition; +import net.runelite.client.ui.overlay.OverlayPriority; + +public class MultiIndicatorsOverlay extends Overlay +{ + private final static int MAX_LOCAL_DRAW_LENGTH = 20 * Perspective.LOCAL_TILE_SIZE; + + @Inject + private Client client; + + @Inject + private MultiIndicatorsPlugin plugin; + + @Inject + private MultiIndicatorsConfig config; + + @Inject + public MultiIndicatorsOverlay() + { + setPosition(OverlayPosition.DYNAMIC); + setLayer(OverlayLayer.ABOVE_SCENE); + setPriority(OverlayPriority.LOW); + } + + private Color getTransparentColorVersion(Color c) + { + return new Color(c.getRed(), c.getGreen(), c.getBlue(), 92); + } + + private void renderPath(Graphics2D graphics, GeneralPath path, Color color) + { + LocalPoint playerLp = client.getLocalPlayer().getLocalLocation(); + Rectangle viewArea = new Rectangle( + playerLp.getX() - MAX_LOCAL_DRAW_LENGTH, + playerLp.getY() - MAX_LOCAL_DRAW_LENGTH, + MAX_LOCAL_DRAW_LENGTH * 2, + MAX_LOCAL_DRAW_LENGTH * 2); + + graphics.setColor(color); + graphics.setStroke(new BasicStroke(2)); + + path = Geometry.clipPath(path, viewArea); + path = Geometry.filterPath(path, (p1, p2) -> + Perspective.localToCanvas(client, new LocalPoint((int) p1[0], (int) p1[1]), client.getPlane()) != null && + Perspective.localToCanvas(client, new LocalPoint((int) p2[0], (int) p2[1]), client.getPlane()) != null); + path = Geometry.transformPath(path, coords -> + { + Point point = Perspective.localToCanvas(client, new LocalPoint((int) coords[0], (int) coords[1]), client.getPlane()); + coords[0] = point.getX(); + coords[1] = point.getY(); + }); + + graphics.draw(path); + } + + @Override + public Dimension render(Graphics2D graphics) + { + GeneralPath multicombatPath = plugin.getMulticombatPathToDisplay()[client.getPlane()]; + GeneralPath pvpPath = plugin.getPvpPathToDisplay()[client.getPlane()]; + + if (config.multicombatZoneVisibility() != ZoneVisibility.HIDE && multicombatPath != null) + { + renderPath(graphics, multicombatPath, getTransparentColorVersion(config.multicombatColor())); + } + if ((config.showPvpSafeZones() || config.showDeadmanSafeZones()) && pvpPath != null) + { + renderPath(graphics, pvpPath, getTransparentColorVersion(config.safeZoneColor())); + } + + return null; + } } \ No newline at end of file diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/multiindicators/MultiIndicatorsPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/multiindicators/MultiIndicatorsPlugin.java index 4882930ed6..c0722e00c8 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/multiindicators/MultiIndicatorsPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/multiindicators/MultiIndicatorsPlugin.java @@ -1,299 +1,299 @@ -/* - * Copyright (c) 2018, Woox - * 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.multiindicators; - -import net.runelite.client.eventbus.Subscribe; -import com.google.inject.Provides; -import java.awt.Rectangle; -import java.awt.geom.GeneralPath; -import java.util.Arrays; -import javax.inject.Inject; -import lombok.Getter; -import net.runelite.api.Client; -import net.runelite.api.Constants; -import net.runelite.api.GameState; -import net.runelite.api.ObjectComposition; -import net.runelite.api.Perspective; -import net.runelite.api.Tile; -import net.runelite.api.WallObject; -import net.runelite.api.WorldType; -import net.runelite.api.coords.LocalPoint; -import net.runelite.api.coords.WorldArea; -import net.runelite.api.coords.WorldPoint; -import net.runelite.api.events.ConfigChanged; -import net.runelite.api.events.GameStateChanged; -import net.runelite.api.geometry.Geometry; -import net.runelite.client.callback.ClientThread; -import net.runelite.client.config.ConfigManager; -import net.runelite.client.plugins.Plugin; -import net.runelite.client.plugins.PluginDescriptor; -import net.runelite.client.plugins.PluginType; -import net.runelite.client.ui.overlay.OverlayManager; - -@PluginDescriptor( - name = "Multi-Lines", - description = "Show borders of multicombat and PvP safezones", - tags = {"multicombat", "lines", "pvp", "deadman", "safezones", "bogla"}, - enabledByDefault = false, - type = PluginType.PVP -) -public class MultiIndicatorsPlugin extends Plugin -{ - @Inject - private Client client; - - @Inject - private ClientThread clientThread; - - @Inject - private MultiIndicatorsConfig config; - - @Inject - private MultiIndicatorsOverlay overlay; - - @Inject - private MultiIndicatorsMinimapOverlay minimapOverlay; - - @Inject - private OverlayManager overlayManager; - - @Getter - private GeneralPath[] multicombatPathToDisplay; - - @Getter - private GeneralPath[] pvpPathToDisplay; - - @Getter - private boolean inPvp; - - @Getter - private boolean inDeadman; - - private int currentPlane; - - @Provides - MultiIndicatorsConfig getConfig(ConfigManager configManager) - { - return configManager.getConfig(MultiIndicatorsConfig.class); - } - - @Override - protected void startUp() throws Exception - { - overlayManager.add(overlay); - overlayManager.add(minimapOverlay); - - multicombatPathToDisplay = new GeneralPath[Constants.MAX_Z]; - pvpPathToDisplay = new GeneralPath[Constants.MAX_Z]; - - clientThread.invokeLater(() -> - { - if (client.getGameState() == GameState.LOGGED_IN) - { - findLinesInScene(); - } - }); - } - - @Override - protected void shutDown() throws Exception - { - overlayManager.remove(overlay); - overlayManager.remove(minimapOverlay); - - multicombatPathToDisplay = null; - pvpPathToDisplay = null; - } - - private void transformWorldToLocal(float[] coords) - { - LocalPoint lp = LocalPoint.fromWorld(client, (int)coords[0], (int)coords[1]); - coords[0] = lp.getX() - Perspective.LOCAL_TILE_SIZE / 2; - coords[1] = lp.getY() - Perspective.LOCAL_TILE_SIZE / 2; - } - - private boolean isOpenableAt(WorldPoint wp) - { - int sceneX = wp.getX() - client.getBaseX(); - int sceneY = wp.getY() - client.getBaseY(); - - Tile tile = client.getScene().getTiles()[wp.getPlane()][sceneX][sceneY]; - if (tile == null) - { - return false; - } - - WallObject wallObject = tile.getWallObject(); - if (wallObject == null) - { - return false; - } - - ObjectComposition objectComposition = client.getObjectDefinition(wallObject.getId()); - if (objectComposition == null) - { - return false; - } - - String[] actions = objectComposition.getActions(); - if (actions == null) - { - return false; - } - - return Arrays.stream(actions).anyMatch(x -> x != null && x.toLowerCase().equals("open")); - } - - private boolean collisionFilter(float[] p1, float[] p2) - { - int x1 = (int)p1[0]; - int y1 = (int)p1[1]; - int x2 = (int)p2[0]; - int y2 = (int)p2[1]; - - if (x1 > x2) - { - int temp = x1; - x1 = x2; - x2 = temp; - } - if (y1 > y2) - { - int temp = y1; - y1 = y2; - y2 = temp; - } - int dx = x2 - x1; - int dy = y2 - y1; - WorldArea wa1 = new WorldArea(new WorldPoint( - x1, y1, currentPlane), 1, 1); - WorldArea wa2 = new WorldArea(new WorldPoint( - x1 - dy, y1 - dx, currentPlane), 1, 1); - - if (isOpenableAt(wa1.toWorldPoint()) || isOpenableAt(wa2.toWorldPoint())) - { - // When there's something with the open option (e.g. a door) on the tile, - // we assume it can be opened and walked through afterwards. Without this - // check, the line for that tile wouldn't render with collision detection - // because the collision check isn't done if collision data changes. - return true; - } - - boolean b1 = wa1.canTravelInDirection(client, -dy, -dx); - boolean b2 = wa2.canTravelInDirection(client, dy, dx); - return b1 && b2; - } - - private void findLinesInScene() - { - inDeadman = client.getWorldType().stream().anyMatch(x -> - x == WorldType.DEADMAN || x == WorldType.SEASONAL_DEADMAN); - inPvp = client.getWorldType().stream().anyMatch(x -> - x == WorldType.PVP || x == WorldType.HIGH_RISK); - - Rectangle sceneRect = new Rectangle( - client.getBaseX() + 1, client.getBaseY() + 1, - Constants.SCENE_SIZE - 2, Constants.SCENE_SIZE - 2); - - // Generate lines for multicombat zones - if (config.multicombatZoneVisibility() == ZoneVisibility.HIDE) - { - for (int i = 0; i < multicombatPathToDisplay.length; i++) - { - multicombatPathToDisplay[i] = null; - } - } - else - { - for (int i = 0; i < multicombatPathToDisplay.length; i++) - { - currentPlane = i; - - GeneralPath lines = new GeneralPath(MapLocations.getMulticombat(sceneRect, i)); - lines = Geometry.clipPath(lines, sceneRect); - if (config.multicombatZoneVisibility() == ZoneVisibility.SHOW_IN_PVP && - !isInDeadman() && !isInPvp()) - { - lines = Geometry.clipPath(lines, MapLocations.getRoughWilderness(i)); - } - lines = Geometry.splitIntoSegments(lines, 1); - if (config.collisionDetection()) - { - lines = Geometry.filterPath(lines, this::collisionFilter); - } - lines = Geometry.transformPath(lines, this::transformWorldToLocal); - multicombatPathToDisplay[i] = lines; - } - } - - // Generate safezone lines for deadman/pvp worlds - for (int i = 0; i < pvpPathToDisplay.length; i++) - { - currentPlane = i; - - GeneralPath safeZonePath = null; - if (config.showDeadmanSafeZones() && isInDeadman()) - { - safeZonePath = new GeneralPath(MapLocations.getDeadmanSafeZones(sceneRect, i)); - } - else if (config.showPvpSafeZones() && isInPvp()) - { - safeZonePath = new GeneralPath(MapLocations.getPvpSafeZones(sceneRect, i)); - } - if (safeZonePath != null) - { - safeZonePath = Geometry.clipPath(safeZonePath, sceneRect); - safeZonePath = Geometry.splitIntoSegments(safeZonePath, 1); - if (config.collisionDetection()) - { - safeZonePath = Geometry.filterPath(safeZonePath, this::collisionFilter); - } - safeZonePath = Geometry.transformPath(safeZonePath, this::transformWorldToLocal); - } - pvpPathToDisplay[i] = safeZonePath; - } - } - - @Subscribe - public void onConfigChanged(ConfigChanged event) - { - if (event.getKey().equals("collisionDetection") || - event.getKey().equals("multicombatZoneVisibility") || - event.getKey().equals("deadmanSafeZones") || - event.getKey().equals("pvpSafeZones")) - { - findLinesInScene(); - } - } - - @Subscribe - public void onGameStateChanged(GameStateChanged event) - { - if (event.getGameState() == GameState.LOGGED_IN) - { - findLinesInScene(); - } - } -} +/* + * Copyright (c) 2018, Woox + * 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.multiindicators; + +import com.google.inject.Provides; +import java.awt.Rectangle; +import java.awt.geom.GeneralPath; +import java.util.Arrays; +import javax.inject.Inject; +import lombok.Getter; +import net.runelite.api.Client; +import net.runelite.api.Constants; +import net.runelite.api.GameState; +import net.runelite.api.ObjectComposition; +import net.runelite.api.Perspective; +import net.runelite.api.Tile; +import net.runelite.api.WallObject; +import net.runelite.api.WorldType; +import net.runelite.api.coords.LocalPoint; +import net.runelite.api.coords.WorldArea; +import net.runelite.api.coords.WorldPoint; +import net.runelite.api.events.ConfigChanged; +import net.runelite.api.events.GameStateChanged; +import net.runelite.api.geometry.Geometry; +import net.runelite.client.callback.ClientThread; +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.plugins.PluginType; +import net.runelite.client.ui.overlay.OverlayManager; + +@PluginDescriptor( + name = "Multi-Lines", + description = "Show borders of multicombat and PvP safezones", + tags = {"multicombat", "lines", "pvp", "deadman", "safezones", "bogla"}, + enabledByDefault = false, + type = PluginType.PVP +) +public class MultiIndicatorsPlugin extends Plugin +{ + @Inject + private Client client; + + @Inject + private ClientThread clientThread; + + @Inject + private MultiIndicatorsConfig config; + + @Inject + private MultiIndicatorsOverlay overlay; + + @Inject + private MultiIndicatorsMinimapOverlay minimapOverlay; + + @Inject + private OverlayManager overlayManager; + + @Getter + private GeneralPath[] multicombatPathToDisplay; + + @Getter + private GeneralPath[] pvpPathToDisplay; + + @Getter + private boolean inPvp; + + @Getter + private boolean inDeadman; + + private int currentPlane; + + @Provides + MultiIndicatorsConfig getConfig(ConfigManager configManager) + { + return configManager.getConfig(MultiIndicatorsConfig.class); + } + + @Override + protected void startUp() throws Exception + { + overlayManager.add(overlay); + overlayManager.add(minimapOverlay); + + multicombatPathToDisplay = new GeneralPath[Constants.MAX_Z]; + pvpPathToDisplay = new GeneralPath[Constants.MAX_Z]; + + clientThread.invokeLater(() -> + { + if (client.getGameState() == GameState.LOGGED_IN) + { + findLinesInScene(); + } + }); + } + + @Override + protected void shutDown() throws Exception + { + overlayManager.remove(overlay); + overlayManager.remove(minimapOverlay); + + multicombatPathToDisplay = null; + pvpPathToDisplay = null; + } + + private void transformWorldToLocal(float[] coords) + { + LocalPoint lp = LocalPoint.fromWorld(client, (int) coords[0], (int) coords[1]); + coords[0] = lp.getX() - Perspective.LOCAL_TILE_SIZE / 2; + coords[1] = lp.getY() - Perspective.LOCAL_TILE_SIZE / 2; + } + + private boolean isOpenableAt(WorldPoint wp) + { + int sceneX = wp.getX() - client.getBaseX(); + int sceneY = wp.getY() - client.getBaseY(); + + Tile tile = client.getScene().getTiles()[wp.getPlane()][sceneX][sceneY]; + if (tile == null) + { + return false; + } + + WallObject wallObject = tile.getWallObject(); + if (wallObject == null) + { + return false; + } + + ObjectComposition objectComposition = client.getObjectDefinition(wallObject.getId()); + if (objectComposition == null) + { + return false; + } + + String[] actions = objectComposition.getActions(); + if (actions == null) + { + return false; + } + + return Arrays.stream(actions).anyMatch(x -> x != null && x.toLowerCase().equals("open")); + } + + private boolean collisionFilter(float[] p1, float[] p2) + { + int x1 = (int) p1[0]; + int y1 = (int) p1[1]; + int x2 = (int) p2[0]; + int y2 = (int) p2[1]; + + if (x1 > x2) + { + int temp = x1; + x1 = x2; + x2 = temp; + } + if (y1 > y2) + { + int temp = y1; + y1 = y2; + y2 = temp; + } + int dx = x2 - x1; + int dy = y2 - y1; + WorldArea wa1 = new WorldArea(new WorldPoint( + x1, y1, currentPlane), 1, 1); + WorldArea wa2 = new WorldArea(new WorldPoint( + x1 - dy, y1 - dx, currentPlane), 1, 1); + + if (isOpenableAt(wa1.toWorldPoint()) || isOpenableAt(wa2.toWorldPoint())) + { + // When there's something with the open option (e.g. a door) on the tile, + // we assume it can be opened and walked through afterwards. Without this + // check, the line for that tile wouldn't render with collision detection + // because the collision check isn't done if collision data changes. + return true; + } + + boolean b1 = wa1.canTravelInDirection(client, -dy, -dx); + boolean b2 = wa2.canTravelInDirection(client, dy, dx); + return b1 && b2; + } + + private void findLinesInScene() + { + inDeadman = client.getWorldType().stream().anyMatch(x -> + x == WorldType.DEADMAN || x == WorldType.SEASONAL_DEADMAN); + inPvp = client.getWorldType().stream().anyMatch(x -> + x == WorldType.PVP || x == WorldType.HIGH_RISK); + + Rectangle sceneRect = new Rectangle( + client.getBaseX() + 1, client.getBaseY() + 1, + Constants.SCENE_SIZE - 2, Constants.SCENE_SIZE - 2); + + // Generate lines for multicombat zones + if (config.multicombatZoneVisibility() == ZoneVisibility.HIDE) + { + for (int i = 0; i < multicombatPathToDisplay.length; i++) + { + multicombatPathToDisplay[i] = null; + } + } + else + { + for (int i = 0; i < multicombatPathToDisplay.length; i++) + { + currentPlane = i; + + GeneralPath lines = new GeneralPath(MapLocations.getMulticombat(sceneRect, i)); + lines = Geometry.clipPath(lines, sceneRect); + if (config.multicombatZoneVisibility() == ZoneVisibility.SHOW_IN_PVP && + !isInDeadman() && !isInPvp()) + { + lines = Geometry.clipPath(lines, MapLocations.getRoughWilderness(i)); + } + lines = Geometry.splitIntoSegments(lines, 1); + if (config.collisionDetection()) + { + lines = Geometry.filterPath(lines, this::collisionFilter); + } + lines = Geometry.transformPath(lines, this::transformWorldToLocal); + multicombatPathToDisplay[i] = lines; + } + } + + // Generate safezone lines for deadman/pvp worlds + for (int i = 0; i < pvpPathToDisplay.length; i++) + { + currentPlane = i; + + GeneralPath safeZonePath = null; + if (config.showDeadmanSafeZones() && isInDeadman()) + { + safeZonePath = new GeneralPath(MapLocations.getDeadmanSafeZones(sceneRect, i)); + } + else if (config.showPvpSafeZones() && isInPvp()) + { + safeZonePath = new GeneralPath(MapLocations.getPvpSafeZones(sceneRect, i)); + } + if (safeZonePath != null) + { + safeZonePath = Geometry.clipPath(safeZonePath, sceneRect); + safeZonePath = Geometry.splitIntoSegments(safeZonePath, 1); + if (config.collisionDetection()) + { + safeZonePath = Geometry.filterPath(safeZonePath, this::collisionFilter); + } + safeZonePath = Geometry.transformPath(safeZonePath, this::transformWorldToLocal); + } + pvpPathToDisplay[i] = safeZonePath; + } + } + + @Subscribe + public void onConfigChanged(ConfigChanged event) + { + if (event.getKey().equals("collisionDetection") || + event.getKey().equals("multicombatZoneVisibility") || + event.getKey().equals("deadmanSafeZones") || + event.getKey().equals("pvpSafeZones")) + { + findLinesInScene(); + } + } + + @Subscribe + public void onGameStateChanged(GameStateChanged event) + { + if (event.getGameState() == GameState.LOGGED_IN) + { + findLinesInScene(); + } + } +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/multiindicators/ZoneVisibility.java b/runelite-client/src/main/java/net/runelite/client/plugins/multiindicators/ZoneVisibility.java index 93ca7e8e26..104dce7770 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/multiindicators/ZoneVisibility.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/multiindicators/ZoneVisibility.java @@ -1,43 +1,43 @@ -/* - * Copyright (c) 2018, Woox - * 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.multiindicators; - -import lombok.RequiredArgsConstructor; - -@RequiredArgsConstructor -public enum ZoneVisibility -{ - HIDE("Hide"), - SHOW_IN_PVP("Show in PvP"), - SHOW_EVERYWHERE("Show everywhere"); - - private final String visibility; - - @Override - public String toString() - { - return visibility; - } +/* + * Copyright (c) 2018, Woox + * 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.multiindicators; + +import lombok.RequiredArgsConstructor; + +@RequiredArgsConstructor +public enum ZoneVisibility +{ + HIDE("Hide"), + SHOW_IN_PVP("Show in PvP"), + SHOW_EVERYWHERE("Show everywhere"); + + private final String visibility; + + @Override + public String toString() + { + return visibility; + } } \ No newline at end of file diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/musicmodifier/MidiFileAdjuster.java b/runelite-client/src/main/java/net/runelite/client/plugins/musicmodifier/MidiFileAdjuster.java index ee67b0a694..ea2b61252d 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/musicmodifier/MidiFileAdjuster.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/musicmodifier/MidiFileAdjuster.java @@ -1,165 +1,202 @@ -/* - * Copyright (c) 2019, Rodolfo Ruiz-Velasco - * 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.musicmodifier; - -import javax.sound.midi.*; -import java.io.IOException; - -public class MidiFileAdjuster { - - private int bankLSBValue; - private int chPosition = -1; - - private boolean customBank = false; - - public Sequence reorderTracks(Sequence sequence) throws InvalidMidiDataException, IOException { - for (Track track : sequence.getTracks()) { - for (int i = 0; i < track.size(); i++) { - MidiEvent midiEvent = track.get(i); - MidiMessage midiMessage = midiEvent.getMessage(); - - if (midiMessage instanceof ShortMessage) { - ShortMessage sm = (ShortMessage) midiMessage; - - if (sm.getChannel() < 16) { - getBankLSB(sm); - - if (i == 0 & bankLSBValue != 1) { - chPosition++; - if (chPosition == 9) { - chPosition = 10; - } - } - - if (!customBank) { - - if (sm.getChannel() == 9) { - bankLSBValue = 1; - } - - if (sm.getChannel() != 9) { - bankLSBValue = 0; - } - } - } - - if (bankLSBValue == 1) { - - int drumChannel = 9; - if (sm.getCommand() == ShortMessage.PROGRAM_CHANGE) { - sm.setMessage(ShortMessage.PROGRAM_CHANGE, drumChannel, sm.getData1(), sm.getData2()); - } - - if (sm.getCommand() == ShortMessage.CONTROL_CHANGE) { - sm.setMessage(ShortMessage.CONTROL_CHANGE, drumChannel, sm.getData1(), sm.getData2()); - } - - if (sm.getCommand() == ShortMessage.NOTE_OFF) { - sm.setMessage(ShortMessage.NOTE_OFF, drumChannel, sm.getData1(), sm.getData2()); - } - - if (sm.getCommand() == ShortMessage.NOTE_ON) { - sm.setMessage(ShortMessage.NOTE_ON, drumChannel, sm.getData1(), sm.getData2()); - } - - if (sm.getCommand() == ShortMessage.PROGRAM_CHANGE) { - sm.setMessage(ShortMessage.PROGRAM_CHANGE, drumChannel, sm.getData1(), sm.getData2()); - } - - if (sm.getCommand() == ShortMessage.CONTROL_CHANGE) { - sm.setMessage(ShortMessage.CONTROL_CHANGE, drumChannel, sm.getData1(), sm.getData2()); - } - - if (sm.getCommand() == ShortMessage.PITCH_BEND) { - sm.setMessage(ShortMessage.PITCH_BEND, drumChannel, sm.getData1(), sm.getData2()); - } - - if (sm.getCommand() == ShortMessage.CHANNEL_PRESSURE) { - sm.setMessage(ShortMessage.CHANNEL_PRESSURE, drumChannel, sm.getData1(), sm.getData2()); - } - - if (sm.getCommand() == ShortMessage.POLY_PRESSURE) { - sm.setMessage(ShortMessage.POLY_PRESSURE, drumChannel, sm.getData1(), sm.getData2()); - } - } else { - - if (sm.getCommand() == ShortMessage.PROGRAM_CHANGE) { - sm.setMessage(ShortMessage.PROGRAM_CHANGE, chPosition, sm.getData1(), sm.getData2()); - } - - if (sm.getCommand() == ShortMessage.CONTROL_CHANGE) { - sm.setMessage(ShortMessage.CONTROL_CHANGE, chPosition, sm.getData1(), sm.getData2()); - } - - if (sm.getCommand() == ShortMessage.NOTE_OFF) { - sm.setMessage(ShortMessage.NOTE_OFF, chPosition, sm.getData1(), sm.getData2()); - } - - if (sm.getCommand() == ShortMessage.NOTE_ON) { - sm.setMessage(ShortMessage.NOTE_ON, chPosition, sm.getData1(), sm.getData2()); - } - - if (sm.getCommand() == ShortMessage.PROGRAM_CHANGE) { - sm.setMessage(ShortMessage.PROGRAM_CHANGE, chPosition, sm.getData1(), sm.getData2()); - } - - if (sm.getCommand() == ShortMessage.CONTROL_CHANGE) { - sm.setMessage(ShortMessage.CONTROL_CHANGE, chPosition, sm.getData1(), sm.getData2()); - } - - if (sm.getCommand() == ShortMessage.PITCH_BEND) { - sm.setMessage(ShortMessage.PITCH_BEND, chPosition, sm.getData1(), sm.getData2()); - } - - if (sm.getCommand() == ShortMessage.CHANNEL_PRESSURE) { - sm.setMessage(ShortMessage.CHANNEL_PRESSURE, chPosition, sm.getData1(), sm.getData2()); - } - - if (sm.getCommand() == ShortMessage.POLY_PRESSURE) { - sm.setMessage(ShortMessage.POLY_PRESSURE, chPosition, sm.getData1(), sm.getData2()); - } - } - } - } - } - return sequence; - } - - private void getBankLSB(ShortMessage sm) throws InvalidMidiDataException - { - if (sm.getCommand() == ShortMessage.CONTROL_CHANGE) - { - if (sm.getData1() == 32) - { - bankLSBValue = sm.getData2(); - customBank = true; - } - if (sm.getData1() == 0) - { - sm.setMessage(sm.getCommand(), sm.getChannel(), sm.getData1(), bankLSBValue); - } - } - } -} +/* + * Copyright (c) 2019, Rodolfo Ruiz-Velasco + * 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.musicmodifier; + +import java.io.IOException; +import javax.sound.midi.InvalidMidiDataException; +import javax.sound.midi.MidiEvent; +import javax.sound.midi.MidiMessage; +import javax.sound.midi.Sequence; +import javax.sound.midi.ShortMessage; +import javax.sound.midi.Track; + +public class MidiFileAdjuster +{ + + private int bankLSBValue; + private int chPosition = -1; + + private boolean customBank = false; + + public Sequence reorderTracks(Sequence sequence) throws InvalidMidiDataException, IOException + { + for (Track track : sequence.getTracks()) + { + for (int i = 0; i < track.size(); i++) + { + MidiEvent midiEvent = track.get(i); + MidiMessage midiMessage = midiEvent.getMessage(); + + if (midiMessage instanceof ShortMessage) + { + ShortMessage sm = (ShortMessage) midiMessage; + + if (sm.getChannel() < 16) + { + getBankLSB(sm); + + if (i == 0 & bankLSBValue != 1) + { + chPosition++; + if (chPosition == 9) + { + chPosition = 10; + } + } + + if (!customBank) + { + + if (sm.getChannel() == 9) + { + bankLSBValue = 1; + } + + if (sm.getChannel() != 9) + { + bankLSBValue = 0; + } + } + } + + if (bankLSBValue == 1) + { + + int drumChannel = 9; + if (sm.getCommand() == ShortMessage.PROGRAM_CHANGE) + { + sm.setMessage(ShortMessage.PROGRAM_CHANGE, drumChannel, sm.getData1(), sm.getData2()); + } + + if (sm.getCommand() == ShortMessage.CONTROL_CHANGE) + { + sm.setMessage(ShortMessage.CONTROL_CHANGE, drumChannel, sm.getData1(), sm.getData2()); + } + + if (sm.getCommand() == ShortMessage.NOTE_OFF) + { + sm.setMessage(ShortMessage.NOTE_OFF, drumChannel, sm.getData1(), sm.getData2()); + } + + if (sm.getCommand() == ShortMessage.NOTE_ON) + { + sm.setMessage(ShortMessage.NOTE_ON, drumChannel, sm.getData1(), sm.getData2()); + } + + if (sm.getCommand() == ShortMessage.PROGRAM_CHANGE) + { + sm.setMessage(ShortMessage.PROGRAM_CHANGE, drumChannel, sm.getData1(), sm.getData2()); + } + + if (sm.getCommand() == ShortMessage.CONTROL_CHANGE) + { + sm.setMessage(ShortMessage.CONTROL_CHANGE, drumChannel, sm.getData1(), sm.getData2()); + } + + if (sm.getCommand() == ShortMessage.PITCH_BEND) + { + sm.setMessage(ShortMessage.PITCH_BEND, drumChannel, sm.getData1(), sm.getData2()); + } + + if (sm.getCommand() == ShortMessage.CHANNEL_PRESSURE) + { + sm.setMessage(ShortMessage.CHANNEL_PRESSURE, drumChannel, sm.getData1(), sm.getData2()); + } + + if (sm.getCommand() == ShortMessage.POLY_PRESSURE) + { + sm.setMessage(ShortMessage.POLY_PRESSURE, drumChannel, sm.getData1(), sm.getData2()); + } + } + else + { + + if (sm.getCommand() == ShortMessage.PROGRAM_CHANGE) + { + sm.setMessage(ShortMessage.PROGRAM_CHANGE, chPosition, sm.getData1(), sm.getData2()); + } + + if (sm.getCommand() == ShortMessage.CONTROL_CHANGE) + { + sm.setMessage(ShortMessage.CONTROL_CHANGE, chPosition, sm.getData1(), sm.getData2()); + } + + if (sm.getCommand() == ShortMessage.NOTE_OFF) + { + sm.setMessage(ShortMessage.NOTE_OFF, chPosition, sm.getData1(), sm.getData2()); + } + + if (sm.getCommand() == ShortMessage.NOTE_ON) + { + sm.setMessage(ShortMessage.NOTE_ON, chPosition, sm.getData1(), sm.getData2()); + } + + if (sm.getCommand() == ShortMessage.PROGRAM_CHANGE) + { + sm.setMessage(ShortMessage.PROGRAM_CHANGE, chPosition, sm.getData1(), sm.getData2()); + } + + if (sm.getCommand() == ShortMessage.CONTROL_CHANGE) + { + sm.setMessage(ShortMessage.CONTROL_CHANGE, chPosition, sm.getData1(), sm.getData2()); + } + + if (sm.getCommand() == ShortMessage.PITCH_BEND) + { + sm.setMessage(ShortMessage.PITCH_BEND, chPosition, sm.getData1(), sm.getData2()); + } + + if (sm.getCommand() == ShortMessage.CHANNEL_PRESSURE) + { + sm.setMessage(ShortMessage.CHANNEL_PRESSURE, chPosition, sm.getData1(), sm.getData2()); + } + + if (sm.getCommand() == ShortMessage.POLY_PRESSURE) + { + sm.setMessage(ShortMessage.POLY_PRESSURE, chPosition, sm.getData1(), sm.getData2()); + } + } + } + } + } + return sequence; + } + + private void getBankLSB(ShortMessage sm) throws InvalidMidiDataException + { + if (sm.getCommand() == ShortMessage.CONTROL_CHANGE) + { + if (sm.getData1() == 32) + { + bankLSBValue = sm.getData2(); + customBank = true; + } + if (sm.getData1() == 0) + { + sm.setMessage(sm.getCommand(), sm.getChannel(), sm.getData1(), bankLSBValue); + } + } + } +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/musicmodifier/MusicCustomizerPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/musicmodifier/MusicCustomizerPlugin.java index 009fd81bf8..91d877d303 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/musicmodifier/MusicCustomizerPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/musicmodifier/MusicCustomizerPlugin.java @@ -1,357 +1,363 @@ -/* - * Copyright (c) 2019, Rodolfo Ruiz-Velasco - * 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.musicmodifier; - -import net.runelite.api.*; -import net.runelite.api.events.GameTick; -import net.runelite.api.events.WidgetLoaded; -import net.runelite.api.widgets.*; -import net.runelite.client.callback.ClientThread; -import net.runelite.client.eventbus.Subscribe; -import net.runelite.client.game.chatbox.ChatboxPanelManager; -import net.runelite.client.game.chatbox.ChatboxTextInput; -import net.runelite.client.plugins.Plugin; -import net.runelite.client.plugins.PluginDescriptor; - -import javax.inject.Inject; -import java.io.File; -import net.runelite.client.plugins.PluginType; - -@PluginDescriptor( - name = "Music Track Customizer", - description = "Customize what track plays and how it sounds, with local files", - tags = {"music", "sound"}, - type = PluginType.UTILITY, - enabledByDefault = false -) - -public class MusicCustomizerPlugin extends Plugin -{ - - @Inject - private Client client; - - @Inject - private ChatboxPanelManager chatboxPanelManager; - - @Inject - private ClientThread clientThread; - - private RealTimeMIDIPlayer realTimeMIDIPlayer = new RealTimeMIDIPlayer(); - - private String songName = "Scape Main"; - - private ChatboxTextInput songInput; - - private Widget playlistModeButton; - - private Widget playlistBox; - - private Widget hidePlaylistButton; - - private Widget addPlaylistSongButton; - - private Widget playlistText; - - private Widget playlistSong; - - private String defaultUnlockedSongs; - - private boolean isLooping = true; - - private boolean playlistMode = false; - - private int newSongY = 34; - - private int playlistCount = 0; - - @Override - public void startUp() - { - playSong(songName); - } - - @Override - public void shutDown() - { - if (realTimeMIDIPlayer != null) - { - realTimeMIDIPlayer.stopSong(); - } - } - - @Subscribe - public void onGameTick(GameTick event) - { - try - { - if (!playlistMode) - { - String newSong = client.getWidget(WidgetInfo.MUSICTAB_CURRENT_SONG_NAME).getText(); - - if (!newSong.equals(songName)) - { - songName = newSong; - playSongFromList(songName); - } - } - } catch (NullPointerException ignored) - { - - } - - } - - private void playSong(String song) - { - File midiMusicFile = new File(System.getProperty("user.home") + "/RuneLiteAudio/MIDI Files/" + - "Music/" + song + ".mid/"); - if (realTimeMIDIPlayer.midi == null) - { - realTimeMIDIPlayer.midi = midiMusicFile; - realTimeMIDIPlayer.run(); - } - - else - { - if (realTimeMIDIPlayer.isPlaying()) - { - realTimeMIDIPlayer.stopSong(); - } - realTimeMIDIPlayer.midi = midiMusicFile; - realTimeMIDIPlayer.run(); - } - } - - @Subscribe - private void onWidgetLoaded(WidgetLoaded widgetLoaded) - { - if (widgetLoaded.getGroupId() == WidgetID.MUSICTAB_GROUP_ID) - { - Widget musicPlayerSongs = client.getWidget(WidgetInfo.MUSICTAB_ALL_SONGS); - if (musicPlayerSongs != null) - { - playlistModeButton = musicPlayerSongs.createChild(-1, WidgetType.GRAPHIC); - playlistModeButton.setSpriteId(SpriteID.RS2_TAB_MUSIC); - playlistModeButton.setOriginalWidth(32); - playlistModeButton.setOriginalHeight(32); - playlistModeButton.setXPositionMode(WidgetPositionMode.ABSOLUTE_RIGHT); - playlistModeButton.setOriginalX(0); - playlistModeButton.setOriginalY(0); - playlistModeButton.setHasListener(true); - playlistModeButton.setAction(1, "Open"); - playlistModeButton.setOnOpListener((JavaScriptCallback) e -> openPlaylist()); - playlistModeButton.setName("Playlist"); - playlistModeButton.setHidden(true); //Playlist is not enabled for this release (Unfinished). - playlistModeButton.revalidate(); - } - } - } - - private void openPlaylist() - { - playlistMode = true; - - Widget currentPlayingSong = client.getWidget(WidgetInfo.MUSICTAB_CURRENT_SONG_NAME); - Widget allInGameSongs = client.getWidget(WidgetInfo.MUSICTAB_ALL_SONGS); - Widget musicScrollbar = client.getWidget(WidgetInfo.MUSICTAB_SCROLLBAR); - allInGameSongs.setHidden(true); - musicScrollbar.setHidden(true); - - defaultUnlockedSongs = client.getWidget(WidgetInfo.MUSICTAB_UNLOCKED_SONGS).getText(); - - client.getWidget(WidgetInfo.MUSICTAB_UNLOCKED_SONGS).setText(playlistCount + " / 10"); - - playlistBox = client.getWidget(WidgetInfo.MUSICTAB_INTERFACE); - - playlistText = playlistBox.createChild(-1, WidgetType.TEXT); - playlistText.setText("Music Playlist"); - playlistText.setFontId(497); - playlistText.setXPositionMode(WidgetPositionMode.ABSOLUTE_TOP); - playlistText.setOriginalX(40); - playlistText.setOriginalY(14); - playlistText.setOriginalHeight(1); - playlistText.setOriginalWidth(1); - playlistText.setTextColor(currentPlayingSong.getTextColor()); - playlistText.revalidate(); - - hidePlaylistButton = playlistBox.createChild(-1, WidgetType.GRAPHIC); - hidePlaylistButton.setSpriteId(SpriteID.RS2_TAB_MUSIC); - hidePlaylistButton.setOriginalWidth(32); - hidePlaylistButton.setOriginalHeight(32); - hidePlaylistButton.setXPositionMode(WidgetPositionMode.ABSOLUTE_RIGHT); - hidePlaylistButton.setOriginalX(0); - hidePlaylistButton.setOriginalY(6); - hidePlaylistButton.setHasListener(true); - hidePlaylistButton.setAction(1, "Close"); - hidePlaylistButton.setOnOpListener((JavaScriptCallback) e -> closePlaylist()); - hidePlaylistButton.setName("Playlist"); - hidePlaylistButton.revalidate(); - - addPlaylistSongButton = playlistBox.createChild(-1, WidgetType.GRAPHIC); - addPlaylistSongButton.setSpriteId(SpriteID.BANK_ADD_TAB_ICON); - addPlaylistSongButton.setOriginalWidth(36); - addPlaylistSongButton.setOriginalHeight(32); - addPlaylistSongButton.setXPositionMode(WidgetPositionMode.ABSOLUTE_LEFT); - addPlaylistSongButton.setOriginalX(0); - addPlaylistSongButton.setOriginalY(6); - addPlaylistSongButton.setHasListener(true); - addPlaylistSongButton.setAction(1, "Add to"); - addPlaylistSongButton.setOnOpListener((JavaScriptCallback) e -> addSongFromInput()); - addPlaylistSongButton.setName("Playlist"); - addPlaylistSongButton.revalidate(); - - if (playlistSong != null) - { - playlistSong.setHidden(false); - } - } - - private void closePlaylist() - { - playlistMode = false; - - Widget allInGameSongs = client.getWidget(WidgetInfo.MUSICTAB_ALL_SONGS); - Widget musicScrollbar = client.getWidget(WidgetInfo.MUSICTAB_SCROLLBAR); - allInGameSongs.setHidden(false); - musicScrollbar.setHidden(false); - - client.getWidget(WidgetInfo.MUSICTAB_UNLOCKED_SONGS).setText(defaultUnlockedSongs); - playlistText.setHidden(true); - addPlaylistSongButton.setHidden(true); - hidePlaylistButton.setHidden(true); - - if (playlistSong != null) - { - playlistSong.setHidden(true); - } - } - - private void addSongFromInput() - { - addPlaylistSongButton.setAction(1, "Close search"); - addPlaylistSongButton.setOnOpListener((JavaScriptCallback) e -> closeInput()); - songInput = chatboxPanelManager.openTextInput("Please type a valid song name") - .onChanged(s -> clientThread.invokeLater(() -> updateSongs(s))) - .onClose(() -> - { - clientThread.invokeLater(() -> updateSongs(songInput.getValue())); - addPlaylistSongButton.setOnOpListener((JavaScriptCallback) e -> addSongFromInput()); - addPlaylistSongButton.setAction(1, "Add to"); - }) - .build(); - } - - private void updateSongs() - { - String song = ""; - if (chatboxIsOpen()) - { - song = songInput.getValue(); - } - updateSongs(song); - } - - private void updateSongs(String song) - { - if (playlistBox == null) - { - return; - } - - if (new File(System.getProperty("user.home") + "/RuneLiteAudio/MIDI Files/" + - "Music/" + song + ".mid/").exists()) - { - playListSongPlayer(song); - } - } - - private void playListSongPlayer(String song) - { - if (!song.equals(songName) && !chatboxIsOpen() && playlistCount < 10) - { - Widget playlistWidget = client.getWidget(WidgetInfo.MUSICTAB_INTERFACE); - playlistSong = playlistWidget.createChild(-1, WidgetType.TEXT); - playlistSong.setText(song); - playlistSong.setFontId(495); - playlistSong.setOriginalX(12); - playlistSong.setOriginalY(newSongY); - playlistSong.setOriginalWidth(120); - playlistSong.setOriginalHeight(16); - playlistSong.setTextColor(client.getWidget(WidgetInfo.MUSICTAB_CURRENT_SONG_NAME).getTextColor()); - playlistSong.setHasListener(true); - playlistSong.setAction(1, "Play"); - playlistSong.setOnOpListener((JavaScriptCallback) e -> playSongFromList(song)); - playlistSong.setName(song); - playlistSong.revalidate(); - - newSongY = newSongY + 15; - - songName = song; - - playlistCount++; - client.getWidget(WidgetInfo.MUSICTAB_UNLOCKED_SONGS).setText(playlistCount + " / 10"); - - if (playlistCount == 10) - { - addPlaylistSongButton.setHidden(true); - } - } - } - - private boolean chatboxIsOpen() - { - return songInput != null && chatboxPanelManager.getCurrentInput() == songInput; - } - - private void closeInput() - { - updateSongs(); - chatboxPanelManager.close(); - } - - private void playSongFromList(String song) - { - client.getWidget(WidgetInfo.MUSICTAB_CURRENT_SONG_NAME).setName(song); - File midiMusicFile = new File(System.getProperty("user.home") + "/RuneLiteAudio/MIDI Files/" + - "Music/" + song + ".mid/"); - - if (realTimeMIDIPlayer.midi == null) - { - realTimeMIDIPlayer.midi = midiMusicFile; - realTimeMIDIPlayer.run(); - } - - else - { - if (realTimeMIDIPlayer.isPlaying()) - { - realTimeMIDIPlayer.stopSong(); - } - realTimeMIDIPlayer.midi = midiMusicFile; - realTimeMIDIPlayer.run(); - } - } -} +/* + * Copyright (c) 2019, Rodolfo Ruiz-Velasco + * 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.musicmodifier; + +import java.io.File; +import javax.inject.Inject; +import net.runelite.api.Client; +import net.runelite.api.SpriteID; +import net.runelite.api.events.GameTick; +import net.runelite.api.events.WidgetLoaded; +import net.runelite.api.widgets.JavaScriptCallback; +import net.runelite.api.widgets.Widget; +import net.runelite.api.widgets.WidgetID; +import net.runelite.api.widgets.WidgetInfo; +import net.runelite.api.widgets.WidgetPositionMode; +import net.runelite.api.widgets.WidgetType; +import net.runelite.client.callback.ClientThread; +import net.runelite.client.eventbus.Subscribe; +import net.runelite.client.game.chatbox.ChatboxPanelManager; +import net.runelite.client.game.chatbox.ChatboxTextInput; +import net.runelite.client.plugins.Plugin; +import net.runelite.client.plugins.PluginDescriptor; +import net.runelite.client.plugins.PluginType; + +@PluginDescriptor( + name = "Music Track Customizer", + description = "Customize what track plays and how it sounds, with local files", + tags = {"music", "sound"}, + type = PluginType.UTILITY, + enabledByDefault = false +) + +public class MusicCustomizerPlugin extends Plugin +{ + + @Inject + private Client client; + + @Inject + private ChatboxPanelManager chatboxPanelManager; + + @Inject + private ClientThread clientThread; + + private RealTimeMIDIPlayer realTimeMIDIPlayer = new RealTimeMIDIPlayer(); + + private String songName = "Scape Main"; + + private ChatboxTextInput songInput; + + private Widget playlistModeButton; + + private Widget playlistBox; + + private Widget hidePlaylistButton; + + private Widget addPlaylistSongButton; + + private Widget playlistText; + + private Widget playlistSong; + + private String defaultUnlockedSongs; + + private boolean isLooping = true; + + private boolean playlistMode = false; + + private int newSongY = 34; + + private int playlistCount = 0; + + @Override + public void startUp() + { + playSong(songName); + } + + @Override + public void shutDown() + { + if (realTimeMIDIPlayer != null) + { + realTimeMIDIPlayer.stopSong(); + } + } + + @Subscribe + public void onGameTick(GameTick event) + { + try + { + if (!playlistMode) + { + String newSong = client.getWidget(WidgetInfo.MUSICTAB_CURRENT_SONG_NAME).getText(); + + if (!newSong.equals(songName)) + { + songName = newSong; + playSongFromList(songName); + } + } + } + catch (NullPointerException ignored) + { + + } + + } + + private void playSong(String song) + { + File midiMusicFile = new File(System.getProperty("user.home") + "/RuneLiteAudio/MIDI Files/" + + "Music/" + song + ".mid/"); + if (realTimeMIDIPlayer.midi == null) + { + realTimeMIDIPlayer.midi = midiMusicFile; + realTimeMIDIPlayer.run(); + } + + else + { + if (realTimeMIDIPlayer.isPlaying()) + { + realTimeMIDIPlayer.stopSong(); + } + realTimeMIDIPlayer.midi = midiMusicFile; + realTimeMIDIPlayer.run(); + } + } + + @Subscribe + private void onWidgetLoaded(WidgetLoaded widgetLoaded) + { + if (widgetLoaded.getGroupId() == WidgetID.MUSICTAB_GROUP_ID) + { + Widget musicPlayerSongs = client.getWidget(WidgetInfo.MUSICTAB_ALL_SONGS); + if (musicPlayerSongs != null) + { + playlistModeButton = musicPlayerSongs.createChild(-1, WidgetType.GRAPHIC); + playlistModeButton.setSpriteId(SpriteID.RS2_TAB_MUSIC); + playlistModeButton.setOriginalWidth(32); + playlistModeButton.setOriginalHeight(32); + playlistModeButton.setXPositionMode(WidgetPositionMode.ABSOLUTE_RIGHT); + playlistModeButton.setOriginalX(0); + playlistModeButton.setOriginalY(0); + playlistModeButton.setHasListener(true); + playlistModeButton.setAction(1, "Open"); + playlistModeButton.setOnOpListener((JavaScriptCallback) e -> openPlaylist()); + playlistModeButton.setName("Playlist"); + playlistModeButton.setHidden(true); //Playlist is not enabled for this release (Unfinished). + playlistModeButton.revalidate(); + } + } + } + + private void openPlaylist() + { + playlistMode = true; + + Widget currentPlayingSong = client.getWidget(WidgetInfo.MUSICTAB_CURRENT_SONG_NAME); + Widget allInGameSongs = client.getWidget(WidgetInfo.MUSICTAB_ALL_SONGS); + Widget musicScrollbar = client.getWidget(WidgetInfo.MUSICTAB_SCROLLBAR); + allInGameSongs.setHidden(true); + musicScrollbar.setHidden(true); + + defaultUnlockedSongs = client.getWidget(WidgetInfo.MUSICTAB_UNLOCKED_SONGS).getText(); + + client.getWidget(WidgetInfo.MUSICTAB_UNLOCKED_SONGS).setText(playlistCount + " / 10"); + + playlistBox = client.getWidget(WidgetInfo.MUSICTAB_INTERFACE); + + playlistText = playlistBox.createChild(-1, WidgetType.TEXT); + playlistText.setText("Music Playlist"); + playlistText.setFontId(497); + playlistText.setXPositionMode(WidgetPositionMode.ABSOLUTE_TOP); + playlistText.setOriginalX(40); + playlistText.setOriginalY(14); + playlistText.setOriginalHeight(1); + playlistText.setOriginalWidth(1); + playlistText.setTextColor(currentPlayingSong.getTextColor()); + playlistText.revalidate(); + + hidePlaylistButton = playlistBox.createChild(-1, WidgetType.GRAPHIC); + hidePlaylistButton.setSpriteId(SpriteID.RS2_TAB_MUSIC); + hidePlaylistButton.setOriginalWidth(32); + hidePlaylistButton.setOriginalHeight(32); + hidePlaylistButton.setXPositionMode(WidgetPositionMode.ABSOLUTE_RIGHT); + hidePlaylistButton.setOriginalX(0); + hidePlaylistButton.setOriginalY(6); + hidePlaylistButton.setHasListener(true); + hidePlaylistButton.setAction(1, "Close"); + hidePlaylistButton.setOnOpListener((JavaScriptCallback) e -> closePlaylist()); + hidePlaylistButton.setName("Playlist"); + hidePlaylistButton.revalidate(); + + addPlaylistSongButton = playlistBox.createChild(-1, WidgetType.GRAPHIC); + addPlaylistSongButton.setSpriteId(SpriteID.BANK_ADD_TAB_ICON); + addPlaylistSongButton.setOriginalWidth(36); + addPlaylistSongButton.setOriginalHeight(32); + addPlaylistSongButton.setXPositionMode(WidgetPositionMode.ABSOLUTE_LEFT); + addPlaylistSongButton.setOriginalX(0); + addPlaylistSongButton.setOriginalY(6); + addPlaylistSongButton.setHasListener(true); + addPlaylistSongButton.setAction(1, "Add to"); + addPlaylistSongButton.setOnOpListener((JavaScriptCallback) e -> addSongFromInput()); + addPlaylistSongButton.setName("Playlist"); + addPlaylistSongButton.revalidate(); + + if (playlistSong != null) + { + playlistSong.setHidden(false); + } + } + + private void closePlaylist() + { + playlistMode = false; + + Widget allInGameSongs = client.getWidget(WidgetInfo.MUSICTAB_ALL_SONGS); + Widget musicScrollbar = client.getWidget(WidgetInfo.MUSICTAB_SCROLLBAR); + allInGameSongs.setHidden(false); + musicScrollbar.setHidden(false); + + client.getWidget(WidgetInfo.MUSICTAB_UNLOCKED_SONGS).setText(defaultUnlockedSongs); + playlistText.setHidden(true); + addPlaylistSongButton.setHidden(true); + hidePlaylistButton.setHidden(true); + + if (playlistSong != null) + { + playlistSong.setHidden(true); + } + } + + private void addSongFromInput() + { + addPlaylistSongButton.setAction(1, "Close search"); + addPlaylistSongButton.setOnOpListener((JavaScriptCallback) e -> closeInput()); + songInput = chatboxPanelManager.openTextInput("Please type a valid song name") + .onChanged(s -> clientThread.invokeLater(() -> updateSongs(s))) + .onClose(() -> + { + clientThread.invokeLater(() -> updateSongs(songInput.getValue())); + addPlaylistSongButton.setOnOpListener((JavaScriptCallback) e -> addSongFromInput()); + addPlaylistSongButton.setAction(1, "Add to"); + }) + .build(); + } + + private void updateSongs() + { + String song = ""; + if (chatboxIsOpen()) + { + song = songInput.getValue(); + } + updateSongs(song); + } + + private void updateSongs(String song) + { + if (playlistBox == null) + { + return; + } + + if (new File(System.getProperty("user.home") + "/RuneLiteAudio/MIDI Files/" + + "Music/" + song + ".mid/").exists()) + { + playListSongPlayer(song); + } + } + + private void playListSongPlayer(String song) + { + if (!song.equals(songName) && !chatboxIsOpen() && playlistCount < 10) + { + Widget playlistWidget = client.getWidget(WidgetInfo.MUSICTAB_INTERFACE); + playlistSong = playlistWidget.createChild(-1, WidgetType.TEXT); + playlistSong.setText(song); + playlistSong.setFontId(495); + playlistSong.setOriginalX(12); + playlistSong.setOriginalY(newSongY); + playlistSong.setOriginalWidth(120); + playlistSong.setOriginalHeight(16); + playlistSong.setTextColor(client.getWidget(WidgetInfo.MUSICTAB_CURRENT_SONG_NAME).getTextColor()); + playlistSong.setHasListener(true); + playlistSong.setAction(1, "Play"); + playlistSong.setOnOpListener((JavaScriptCallback) e -> playSongFromList(song)); + playlistSong.setName(song); + playlistSong.revalidate(); + + newSongY = newSongY + 15; + + songName = song; + + playlistCount++; + client.getWidget(WidgetInfo.MUSICTAB_UNLOCKED_SONGS).setText(playlistCount + " / 10"); + + if (playlistCount == 10) + { + addPlaylistSongButton.setHidden(true); + } + } + } + + private boolean chatboxIsOpen() + { + return songInput != null && chatboxPanelManager.getCurrentInput() == songInput; + } + + private void closeInput() + { + updateSongs(); + chatboxPanelManager.close(); + } + + private void playSongFromList(String song) + { + client.getWidget(WidgetInfo.MUSICTAB_CURRENT_SONG_NAME).setName(song); + File midiMusicFile = new File(System.getProperty("user.home") + "/RuneLiteAudio/MIDI Files/" + + "Music/" + song + ".mid/"); + + if (realTimeMIDIPlayer.midi == null) + { + realTimeMIDIPlayer.midi = midiMusicFile; + realTimeMIDIPlayer.run(); + } + + else + { + if (realTimeMIDIPlayer.isPlaying()) + { + realTimeMIDIPlayer.stopSong(); + } + realTimeMIDIPlayer.midi = midiMusicFile; + realTimeMIDIPlayer.run(); + } + } +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/musicmodifier/RealTimeMIDIPlayer.java b/runelite-client/src/main/java/net/runelite/client/plugins/musicmodifier/RealTimeMIDIPlayer.java index 858c7465fd..6990c5cfbc 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/musicmodifier/RealTimeMIDIPlayer.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/musicmodifier/RealTimeMIDIPlayer.java @@ -1,229 +1,282 @@ -/* - * Copyright (c) 2019, Rodolfo Ruiz-Velasco - * 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.musicmodifier; - -import com.sun.media.sound.AudioSynthesizer; - -import javax.sound.midi.*; -import javax.sound.sampled.*; -import java.io.*; -import java.util.HashMap; -import java.util.Map; - -public class RealTimeMIDIPlayer implements Runnable -{ - private AudioFormat format; - - private Sequence midiSequence; - - private Soundbank soundbank; - - private SourceDataLine sdl; - - private MusicCustomizerPlugin customMusicPlugin; - - private MidiFileAdjuster adjuster; - - private Clip clip; - - public boolean looping = true; - - public File soundFont = new File(System.getProperty("user.home") + "/RuneLiteAudio/SoundFonts/" + - "RuneScape 2.sf2/"); - - public File midi; - - @Override - public void run() { - - try { - - adjuster = new MidiFileAdjuster(); //Unfinished class - - midiSequence = MidiSystem.getSequence(midi); - soundbank = MidiSystem.getSoundbank(soundFont); - init(); - } - catch (IOException | InvalidMidiDataException e) - { - e.printStackTrace(); - } - } - - public void stopSong() - { - if (sdl.isRunning()) - { - sdl.stop(); - } - } - - public static AudioSynthesizer findAudioSynthesizer() throws MidiUnavailableException - { - Synthesizer synth = MidiSystem.getSynthesizer(); - if (synth instanceof AudioSynthesizer) - return (AudioSynthesizer) synth; - - double gain = 0.8D; - - MidiDevice.Info[] infos = MidiSystem.getMidiDeviceInfo(); - MidiChannel[] channels = synth.getChannels(); - - for (int i = 0; i < channels.length; i++) - { - channels[i].controlChange(7, ((int) (channels[i].getController(7) * gain))); - } - - for (int i = 0; i < infos.length; i++) - { - MidiDevice device = MidiSystem.getMidiDevice(infos[i]); - - if (device instanceof AudioSynthesizer) - return (AudioSynthesizer) device; - } - return null; - } - - public boolean isPlaying() - { - return sdl.isActive(); - } - - public static double send(Sequence sequence, Receiver receiver) { - float divtype = sequence.getDivisionType(); - assert (sequence.getDivisionType() == Sequence.PPQ); - Track[] tracks = sequence.getTracks(); - int[] trackspos = new int[tracks.length]; - int mpq = 500000; - int seqres = sequence.getResolution(); - long lasttick = 0; - long curtime = 0; - while (true) { - MidiEvent selevent = null; - int seltrack = -1; - for (int i = 0; i < tracks.length; i++) { - int trackpos = trackspos[i]; - Track track = tracks[i]; - if (trackpos < track.size()) { - MidiEvent event = track.get(trackpos); - if (selevent == null - || event.getTick() < selevent.getTick()) { - selevent = event; - seltrack = i; - } - } - } - if (seltrack == -1) - break; - trackspos[seltrack]++; - long tick = selevent.getTick(); - if (divtype == Sequence.PPQ) - curtime += ((tick - lasttick) * mpq) / seqres; - else - curtime = (long) ((tick * 1000000.0 * divtype) / seqres); - lasttick = tick; - MidiMessage msg = selevent.getMessage(); - if (msg instanceof MetaMessage) { - if (divtype == Sequence.PPQ) - if (((MetaMessage) msg).getType() == 0x51) { - byte[] data = ((MetaMessage) msg).getData(); - mpq = ((data[0] & 0xff) << 16) - | ((data[1] & 0xff) << 8) | (data[2] & 0xff); - } - } else { - if (receiver != null) - receiver.send(msg, curtime); - } - } - return curtime / 1000000.0; - } - - public void init() { - new Thread(new Runnable() { - @Override - public void run() { - - AudioSynthesizer synth = null; - try { - synth = findAudioSynthesizer(); - format = new AudioFormat(44100, 16, 2, true, false); - - Map info = new HashMap(); - info.put("resamplerType", "sinc"); - info.put("maxPolyphony", "8192"); - AudioInputStream ais = synth.openStream(format, info); - synth.unloadAllInstruments(synth.getDefaultSoundbank()); - synth.loadAllInstruments(soundbank); - double total = send(midiSequence, synth.getReceiver()); - long length = (long) (ais.getFormat().getFrameRate() * (total + 4)); - AudioInputStream stream = new AudioInputStream(ais, format, length); - sdl = AudioSystem.getSourceDataLine(format); - sdl.open(format); - sdl.start(); - writeAudio(sdl, stream); - } catch (LineUnavailableException | MidiUnavailableException e) { - e.printStackTrace(); - } - } - }).start(); - } - - public void writeAudio(SourceDataLine sdl, AudioInputStream stream) - { - new Thread(new Runnable() { - @Override - public void run() { - - byte[] sampledAudio = new byte[1024]; - - int numBytesRead = 0; - - while (numBytesRead != -1) { - try - { - numBytesRead = stream.read(sampledAudio, 0, sampledAudio.length); - - if (numBytesRead >= 0) { - sdl.write(sampledAudio, 0, numBytesRead); - } - } - - catch (IOException e) - { - e.printStackTrace(); - } - - finally { - - if (!isPlaying() && looping) - { - this.run(); - } - } - } - } - }).start(); - } -} +/* + * Copyright (c) 2019, Rodolfo Ruiz-Velasco + * 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.musicmodifier; + +import com.sun.media.sound.AudioSynthesizer; +import java.io.File; +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; +import javax.sound.midi.InvalidMidiDataException; +import javax.sound.midi.MetaMessage; +import javax.sound.midi.MidiChannel; +import javax.sound.midi.MidiDevice; +import javax.sound.midi.MidiEvent; +import javax.sound.midi.MidiMessage; +import javax.sound.midi.MidiSystem; +import javax.sound.midi.MidiUnavailableException; +import javax.sound.midi.Receiver; +import javax.sound.midi.Sequence; +import javax.sound.midi.Soundbank; +import javax.sound.midi.Synthesizer; +import javax.sound.midi.Track; +import javax.sound.sampled.AudioFormat; +import javax.sound.sampled.AudioInputStream; +import javax.sound.sampled.AudioSystem; +import javax.sound.sampled.Clip; +import javax.sound.sampled.LineUnavailableException; +import javax.sound.sampled.SourceDataLine; + +public class RealTimeMIDIPlayer implements Runnable +{ + private AudioFormat format; + + private Sequence midiSequence; + + private Soundbank soundbank; + + private SourceDataLine sdl; + + private MusicCustomizerPlugin customMusicPlugin; + + private MidiFileAdjuster adjuster; + + private Clip clip; + + public boolean looping = true; + + public File soundFont = new File(System.getProperty("user.home") + "/RuneLiteAudio/SoundFonts/" + + "RuneScape 2.sf2/"); + + public File midi; + + @Override + public void run() + { + + try + { + + adjuster = new MidiFileAdjuster(); //Unfinished class + + midiSequence = MidiSystem.getSequence(midi); + soundbank = MidiSystem.getSoundbank(soundFont); + init(); + } + catch (IOException | InvalidMidiDataException e) + { + e.printStackTrace(); + } + } + + public void stopSong() + { + if (sdl.isRunning()) + { + sdl.stop(); + } + } + + public static AudioSynthesizer findAudioSynthesizer() throws MidiUnavailableException + { + Synthesizer synth = MidiSystem.getSynthesizer(); + if (synth instanceof AudioSynthesizer) + { + return (AudioSynthesizer) synth; + } + + double gain = 0.8D; + + MidiDevice.Info[] infos = MidiSystem.getMidiDeviceInfo(); + MidiChannel[] channels = synth.getChannels(); + + for (int i = 0; i < channels.length; i++) + { + channels[i].controlChange(7, ((int) (channels[i].getController(7) * gain))); + } + + for (int i = 0; i < infos.length; i++) + { + MidiDevice device = MidiSystem.getMidiDevice(infos[i]); + + if (device instanceof AudioSynthesizer) + { + return (AudioSynthesizer) device; + } + } + return null; + } + + public boolean isPlaying() + { + return sdl.isActive(); + } + + public static double send(Sequence sequence, Receiver receiver) + { + float divtype = sequence.getDivisionType(); + assert (sequence.getDivisionType() == Sequence.PPQ); + Track[] tracks = sequence.getTracks(); + int[] trackspos = new int[tracks.length]; + int mpq = 500000; + int seqres = sequence.getResolution(); + long lasttick = 0; + long curtime = 0; + while (true) + { + MidiEvent selevent = null; + int seltrack = -1; + for (int i = 0; i < tracks.length; i++) + { + int trackpos = trackspos[i]; + Track track = tracks[i]; + if (trackpos < track.size()) + { + MidiEvent event = track.get(trackpos); + if (selevent == null + || event.getTick() < selevent.getTick()) + { + selevent = event; + seltrack = i; + } + } + } + if (seltrack == -1) + { + break; + } + trackspos[seltrack]++; + long tick = selevent.getTick(); + if (divtype == Sequence.PPQ) + { + curtime += ((tick - lasttick) * mpq) / seqres; + } + else + { + curtime = (long) ((tick * 1000000.0 * divtype) / seqres); + } + lasttick = tick; + MidiMessage msg = selevent.getMessage(); + if (msg instanceof MetaMessage) + { + if (divtype == Sequence.PPQ) + { + if (((MetaMessage) msg).getType() == 0x51) + { + byte[] data = ((MetaMessage) msg).getData(); + mpq = ((data[0] & 0xff) << 16) + | ((data[1] & 0xff) << 8) | (data[2] & 0xff); + } + } + } + else + { + if (receiver != null) + { + receiver.send(msg, curtime); + } + } + } + return curtime / 1000000.0; + } + + public void init() + { + new Thread(new Runnable() + { + @Override + public void run() + { + + AudioSynthesizer synth = null; + try + { + synth = findAudioSynthesizer(); + format = new AudioFormat(44100, 16, 2, true, false); + + Map info = new HashMap(); + info.put("resamplerType", "sinc"); + info.put("maxPolyphony", "8192"); + AudioInputStream ais = synth.openStream(format, info); + synth.unloadAllInstruments(synth.getDefaultSoundbank()); + synth.loadAllInstruments(soundbank); + double total = send(midiSequence, synth.getReceiver()); + long length = (long) (ais.getFormat().getFrameRate() * (total + 4)); + AudioInputStream stream = new AudioInputStream(ais, format, length); + sdl = AudioSystem.getSourceDataLine(format); + sdl.open(format); + sdl.start(); + writeAudio(sdl, stream); + } + catch (LineUnavailableException | MidiUnavailableException e) + { + e.printStackTrace(); + } + } + }).start(); + } + + public void writeAudio(SourceDataLine sdl, AudioInputStream stream) + { + new Thread(new Runnable() + { + @Override + public void run() + { + + byte[] sampledAudio = new byte[1024]; + + int numBytesRead = 0; + + while (numBytesRead != -1) + { + try + { + numBytesRead = stream.read(sampledAudio, 0, sampledAudio.length); + + if (numBytesRead >= 0) + { + sdl.write(sampledAudio, 0, numBytesRead); + } + } + + catch (IOException e) + { + e.printStackTrace(); + } + + finally + { + + if (!isPlaying() && looping) + { + this.run(); + } + } + } + } + }).start(); + } +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/nightmarezone/AbsorptionCounter.java b/runelite-client/src/main/java/net/runelite/client/plugins/nightmarezone/AbsorptionCounter.java index 4671edde12..3ff04b6f10 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/nightmarezone/AbsorptionCounter.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/nightmarezone/AbsorptionCounter.java @@ -1,66 +1,66 @@ -/* - * Copyright (c) 2018, Nickolaj - * 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.nightmarezone; - -import java.awt.Color; -import java.awt.image.BufferedImage; -import lombok.Setter; -import net.runelite.client.plugins.Plugin; -import net.runelite.client.ui.overlay.infobox.Counter; - -@Setter -public class AbsorptionCounter extends Counter -{ - private int threshold; - private Color aboveThresholdColor = Color.GREEN; - private Color belowThresholdColor = Color.RED; - - AbsorptionCounter(BufferedImage image, Plugin plugin, int absorption, int threshold) - { - super(image, plugin, absorption); - this.threshold = threshold; - } - - @Override - public Color getTextColor() - { - int absorption = getCount(); - if (absorption >= threshold) - { - return aboveThresholdColor; - } - else - { - return belowThresholdColor; - } - } - - @Override - public String getTooltip() - { - int absorption = getCount(); - return "Absorption: " + absorption; - } -} +/* + * Copyright (c) 2018, Nickolaj + * 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.nightmarezone; + +import java.awt.Color; +import java.awt.image.BufferedImage; +import lombok.Setter; +import net.runelite.client.plugins.Plugin; +import net.runelite.client.ui.overlay.infobox.Counter; + +@Setter +public class AbsorptionCounter extends Counter +{ + private int threshold; + private Color aboveThresholdColor = Color.GREEN; + private Color belowThresholdColor = Color.RED; + + AbsorptionCounter(BufferedImage image, Plugin plugin, int absorption, int threshold) + { + super(image, plugin, absorption); + this.threshold = threshold; + } + + @Override + public Color getTextColor() + { + int absorption = getCount(); + if (absorption >= threshold) + { + return aboveThresholdColor; + } + else + { + return belowThresholdColor; + } + } + + @Override + public String getTooltip() + { + int absorption = getCount(); + return "Absorption: " + absorption; + } +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/nightmarezone/NightmareZoneOverlay.java b/runelite-client/src/main/java/net/runelite/client/plugins/nightmarezone/NightmareZoneOverlay.java index 71ae196d3e..88846f02d2 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/nightmarezone/NightmareZoneOverlay.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/nightmarezone/NightmareZoneOverlay.java @@ -1,160 +1,160 @@ -/* - * Copyright (c) 2018, Nickolaj - * 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.nightmarezone; - -import java.awt.Dimension; -import java.awt.Graphics2D; -import javax.inject.Inject; -import net.runelite.api.Client; -import net.runelite.api.ItemID; -import static net.runelite.api.MenuAction.RUNELITE_OVERLAY_CONFIG; -import net.runelite.api.Varbits; -import net.runelite.api.widgets.Widget; -import net.runelite.api.widgets.WidgetInfo; -import net.runelite.client.game.ItemManager; -import net.runelite.client.ui.overlay.Overlay; -import static net.runelite.client.ui.overlay.OverlayManager.OPTION_CONFIGURE; -import net.runelite.client.ui.overlay.OverlayMenuEntry; -import net.runelite.client.ui.overlay.OverlayPosition; -import net.runelite.client.ui.overlay.OverlayPriority; -import net.runelite.client.ui.overlay.components.LineComponent; -import net.runelite.client.ui.overlay.components.PanelComponent; -import net.runelite.client.ui.overlay.infobox.InfoBoxManager; -import net.runelite.client.util.StackFormatter; - -class NightmareZoneOverlay extends Overlay -{ - private final Client client; - private final NightmareZoneConfig config; - private final NightmareZonePlugin plugin; - private final InfoBoxManager infoBoxManager; - private final ItemManager itemManager; - - private AbsorptionCounter absorptionCounter; - private final PanelComponent panelComponent = new PanelComponent(); - - @Inject - NightmareZoneOverlay( - Client client, - NightmareZoneConfig config, - NightmareZonePlugin plugin, - InfoBoxManager infoBoxManager, - ItemManager itemManager) - { - super(plugin); - setPosition(OverlayPosition.TOP_LEFT); - setPriority(OverlayPriority.LOW); - this.client = client; - this.config = config; - this.plugin = plugin; - this.infoBoxManager = infoBoxManager; - this.itemManager = itemManager; - getMenuEntries().add(new OverlayMenuEntry(RUNELITE_OVERLAY_CONFIG, OPTION_CONFIGURE, "NMZ overlay")); - } - - @Override - public Dimension render(Graphics2D graphics) - { - if (!plugin.isInNightmareZone() || !config.moveOverlay()) - { - if (absorptionCounter != null) - { - removeAbsorptionCounter(); - // Restore original widget - Widget nmzWidget = client.getWidget(WidgetInfo.NIGHTMARE_ZONE); - if (nmzWidget != null) - { - nmzWidget.setHidden(false); - } - } - return null; - } - - Widget nmzWidget = client.getWidget(WidgetInfo.NIGHTMARE_ZONE); - - if (nmzWidget != null) - { - nmzWidget.setHidden(true); - } - - renderAbsorptionCounter(); - - panelComponent.getChildren().clear(); - panelComponent.getChildren().add(LineComponent.builder() - .left("Points: ") - .right(StackFormatter.formatNumber(client.getVar(Varbits.NMZ_POINTS))) - .build()); - - return panelComponent.render(graphics); - } - - private void renderAbsorptionCounter() - { - int absorptionPoints = client.getVar(Varbits.NMZ_ABSORPTION); - if (absorptionPoints == 0) - { - if (absorptionCounter != null) - { - removeAbsorptionCounter(); - absorptionCounter = null; - } - } - else if (config.moveOverlay()) - { - if (absorptionCounter == null) - { - addAbsorptionCounter(absorptionPoints); - } - else - { - absorptionCounter.setCount(absorptionPoints); - } - } - } - - private void addAbsorptionCounter(int startValue) - { - absorptionCounter = new AbsorptionCounter(itemManager.getImage(ItemID.ABSORPTION_4), plugin, startValue, config.absorptionThreshold()); - absorptionCounter.setAboveThresholdColor(config.absorptionColorAboveThreshold()); - absorptionCounter.setBelowThresholdColor(config.absorptionColorBelowThreshold()); - infoBoxManager.addInfoBox(absorptionCounter); - } - - public void removeAbsorptionCounter() - { - infoBoxManager.removeInfoBox(absorptionCounter); - absorptionCounter = null; - } - - public void updateConfig() - { - if (absorptionCounter != null) - { - absorptionCounter.setAboveThresholdColor(config.absorptionColorAboveThreshold()); - absorptionCounter.setBelowThresholdColor(config.absorptionColorBelowThreshold()); - absorptionCounter.setThreshold(config.absorptionThreshold()); - } - } -} +/* + * Copyright (c) 2018, Nickolaj + * 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.nightmarezone; + +import java.awt.Dimension; +import java.awt.Graphics2D; +import javax.inject.Inject; +import net.runelite.api.Client; +import net.runelite.api.ItemID; +import static net.runelite.api.MenuAction.RUNELITE_OVERLAY_CONFIG; +import net.runelite.api.Varbits; +import net.runelite.api.widgets.Widget; +import net.runelite.api.widgets.WidgetInfo; +import net.runelite.client.game.ItemManager; +import net.runelite.client.ui.overlay.Overlay; +import static net.runelite.client.ui.overlay.OverlayManager.OPTION_CONFIGURE; +import net.runelite.client.ui.overlay.OverlayMenuEntry; +import net.runelite.client.ui.overlay.OverlayPosition; +import net.runelite.client.ui.overlay.OverlayPriority; +import net.runelite.client.ui.overlay.components.LineComponent; +import net.runelite.client.ui.overlay.components.PanelComponent; +import net.runelite.client.ui.overlay.infobox.InfoBoxManager; +import net.runelite.client.util.StackFormatter; + +class NightmareZoneOverlay extends Overlay +{ + private final Client client; + private final NightmareZoneConfig config; + private final NightmareZonePlugin plugin; + private final InfoBoxManager infoBoxManager; + private final ItemManager itemManager; + + private AbsorptionCounter absorptionCounter; + private final PanelComponent panelComponent = new PanelComponent(); + + @Inject + NightmareZoneOverlay( + Client client, + NightmareZoneConfig config, + NightmareZonePlugin plugin, + InfoBoxManager infoBoxManager, + ItemManager itemManager) + { + super(plugin); + setPosition(OverlayPosition.TOP_LEFT); + setPriority(OverlayPriority.LOW); + this.client = client; + this.config = config; + this.plugin = plugin; + this.infoBoxManager = infoBoxManager; + this.itemManager = itemManager; + getMenuEntries().add(new OverlayMenuEntry(RUNELITE_OVERLAY_CONFIG, OPTION_CONFIGURE, "NMZ overlay")); + } + + @Override + public Dimension render(Graphics2D graphics) + { + if (!plugin.isInNightmareZone() || !config.moveOverlay()) + { + if (absorptionCounter != null) + { + removeAbsorptionCounter(); + // Restore original widget + Widget nmzWidget = client.getWidget(WidgetInfo.NIGHTMARE_ZONE); + if (nmzWidget != null) + { + nmzWidget.setHidden(false); + } + } + return null; + } + + Widget nmzWidget = client.getWidget(WidgetInfo.NIGHTMARE_ZONE); + + if (nmzWidget != null) + { + nmzWidget.setHidden(true); + } + + renderAbsorptionCounter(); + + panelComponent.getChildren().clear(); + panelComponent.getChildren().add(LineComponent.builder() + .left("Points: ") + .right(StackFormatter.formatNumber(client.getVar(Varbits.NMZ_POINTS))) + .build()); + + return panelComponent.render(graphics); + } + + private void renderAbsorptionCounter() + { + int absorptionPoints = client.getVar(Varbits.NMZ_ABSORPTION); + if (absorptionPoints == 0) + { + if (absorptionCounter != null) + { + removeAbsorptionCounter(); + absorptionCounter = null; + } + } + else if (config.moveOverlay()) + { + if (absorptionCounter == null) + { + addAbsorptionCounter(absorptionPoints); + } + else + { + absorptionCounter.setCount(absorptionPoints); + } + } + } + + private void addAbsorptionCounter(int startValue) + { + absorptionCounter = new AbsorptionCounter(itemManager.getImage(ItemID.ABSORPTION_4), plugin, startValue, config.absorptionThreshold()); + absorptionCounter.setAboveThresholdColor(config.absorptionColorAboveThreshold()); + absorptionCounter.setBelowThresholdColor(config.absorptionColorBelowThreshold()); + infoBoxManager.addInfoBox(absorptionCounter); + } + + public void removeAbsorptionCounter() + { + infoBoxManager.removeInfoBox(absorptionCounter); + absorptionCounter = null; + } + + public void updateConfig() + { + if (absorptionCounter != null) + { + absorptionCounter.setAboveThresholdColor(config.absorptionColorAboveThreshold()); + absorptionCounter.setBelowThresholdColor(config.absorptionColorBelowThreshold()); + absorptionCounter.setThreshold(config.absorptionThreshold()); + } + } +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/nightmarezone/NightmareZonePlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/nightmarezone/NightmareZonePlugin.java index d5b91a94cd..2cf0c9885f 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/nightmarezone/NightmareZonePlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/nightmarezone/NightmareZonePlugin.java @@ -1,200 +1,200 @@ -/* - * Copyright (c) 2018, Nickolaj - * 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.nightmarezone; - -import com.google.inject.Provides; -import java.util.Arrays; -import javax.inject.Inject; -import net.runelite.api.ChatMessageType; -import net.runelite.api.Client; -import net.runelite.api.Varbits; -import net.runelite.api.events.ChatMessage; -import net.runelite.api.events.ConfigChanged; -import net.runelite.api.events.GameTick; -import net.runelite.api.widgets.Widget; -import net.runelite.api.widgets.WidgetInfo; -import net.runelite.client.Notifier; -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.ui.overlay.OverlayManager; -import net.runelite.client.util.Text; - -@PluginDescriptor( - name = "Nightmare Zone", - description = "Show NMZ points/absorption and/or notify about expiring potions", - tags = {"combat", "nmz", "minigame", "notifications"} -) -public class NightmareZonePlugin extends Plugin -{ - private static final int[] NMZ_MAP_REGION = {9033}; - - @Inject - private Notifier notifier; - - @Inject - private Client client; - - @Inject - private OverlayManager overlayManager; - - @Inject - private NightmareZoneConfig config; - - @Inject - private NightmareZoneOverlay overlay; - - // This starts as true since you need to get - // above the threshold before sending notifications - private boolean absorptionNotificationSend = true; - - @Override - protected void startUp() throws Exception - { - overlayManager.add(overlay); - overlay.removeAbsorptionCounter(); - } - - @Override - protected void shutDown() throws Exception - { - overlayManager.remove(overlay); - overlay.removeAbsorptionCounter(); - - Widget nmzWidget = client.getWidget(WidgetInfo.NIGHTMARE_ZONE); - - if (nmzWidget != null) - { - nmzWidget.setHidden(false); - } - } - - @Subscribe - public void onConfigChanged(ConfigChanged event) - { - overlay.updateConfig(); - } - - @Provides - NightmareZoneConfig getConfig(ConfigManager configManager) - { - return configManager.getConfig(NightmareZoneConfig.class); - } - - @Subscribe - public void onGameTick(GameTick event) - { - if (!isInNightmareZone()) - { - if (!absorptionNotificationSend) - { - absorptionNotificationSend = true; - } - - return; - } - if (config.absorptionNotification()) - { - checkAbsorption(); - } - } - - @Subscribe - public void onChatMessage(ChatMessage event) - { - if (event.getType() != ChatMessageType.GAMEMESSAGE - || !isInNightmareZone()) - { - return; - } - - String msg = Text.removeTags(event.getMessage()); //remove color - if (msg.contains("The effects of overload have worn off, and you feel normal again.")) - { - if (config.overloadNotification()) - { - notifier.notify("Your overload has worn off"); - } - } - else if (msg.contains("A power-up has spawned:")) - { - if (msg.contains("Power surge")) - { - if (config.powerSurgeNotification()) - { - notifier.notify(msg); - } - } - else if (msg.contains("Recurrent damage")) - { - if (config.recurrentDamageNotification()) - { - notifier.notify(msg); - } - } - else if (msg.contains("Zapper")) - { - if (config.zapperNotification()) - { - notifier.notify(msg); - } - } - else if (msg.contains("Ultimate force")) - { - if (config.ultimateForceNotification()) - { - notifier.notify(msg); - } - } - } - } - - private void checkAbsorption() - { - int absorptionPoints = client.getVar(Varbits.NMZ_ABSORPTION); - - if (!absorptionNotificationSend) - { - if (absorptionPoints < config.absorptionThreshold()) - { - notifier.notify("Absorption points below: " + config.absorptionThreshold()); - absorptionNotificationSend = true; - } - } - else - { - if (absorptionPoints > config.absorptionThreshold()) - { - absorptionNotificationSend = false; - } - } - } - - public boolean isInNightmareZone() - { - return Arrays.equals(client.getMapRegions(), NMZ_MAP_REGION); - } -} +/* + * Copyright (c) 2018, Nickolaj + * 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.nightmarezone; + +import com.google.inject.Provides; +import java.util.Arrays; +import javax.inject.Inject; +import net.runelite.api.ChatMessageType; +import net.runelite.api.Client; +import net.runelite.api.Varbits; +import net.runelite.api.events.ChatMessage; +import net.runelite.api.events.ConfigChanged; +import net.runelite.api.events.GameTick; +import net.runelite.api.widgets.Widget; +import net.runelite.api.widgets.WidgetInfo; +import net.runelite.client.Notifier; +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.ui.overlay.OverlayManager; +import net.runelite.client.util.Text; + +@PluginDescriptor( + name = "Nightmare Zone", + description = "Show NMZ points/absorption and/or notify about expiring potions", + tags = {"combat", "nmz", "minigame", "notifications"} +) +public class NightmareZonePlugin extends Plugin +{ + private static final int[] NMZ_MAP_REGION = {9033}; + + @Inject + private Notifier notifier; + + @Inject + private Client client; + + @Inject + private OverlayManager overlayManager; + + @Inject + private NightmareZoneConfig config; + + @Inject + private NightmareZoneOverlay overlay; + + // This starts as true since you need to get + // above the threshold before sending notifications + private boolean absorptionNotificationSend = true; + + @Override + protected void startUp() throws Exception + { + overlayManager.add(overlay); + overlay.removeAbsorptionCounter(); + } + + @Override + protected void shutDown() throws Exception + { + overlayManager.remove(overlay); + overlay.removeAbsorptionCounter(); + + Widget nmzWidget = client.getWidget(WidgetInfo.NIGHTMARE_ZONE); + + if (nmzWidget != null) + { + nmzWidget.setHidden(false); + } + } + + @Subscribe + public void onConfigChanged(ConfigChanged event) + { + overlay.updateConfig(); + } + + @Provides + NightmareZoneConfig getConfig(ConfigManager configManager) + { + return configManager.getConfig(NightmareZoneConfig.class); + } + + @Subscribe + public void onGameTick(GameTick event) + { + if (!isInNightmareZone()) + { + if (!absorptionNotificationSend) + { + absorptionNotificationSend = true; + } + + return; + } + if (config.absorptionNotification()) + { + checkAbsorption(); + } + } + + @Subscribe + public void onChatMessage(ChatMessage event) + { + if (event.getType() != ChatMessageType.GAMEMESSAGE + || !isInNightmareZone()) + { + return; + } + + String msg = Text.removeTags(event.getMessage()); //remove color + if (msg.contains("The effects of overload have worn off, and you feel normal again.")) + { + if (config.overloadNotification()) + { + notifier.notify("Your overload has worn off"); + } + } + else if (msg.contains("A power-up has spawned:")) + { + if (msg.contains("Power surge")) + { + if (config.powerSurgeNotification()) + { + notifier.notify(msg); + } + } + else if (msg.contains("Recurrent damage")) + { + if (config.recurrentDamageNotification()) + { + notifier.notify(msg); + } + } + else if (msg.contains("Zapper")) + { + if (config.zapperNotification()) + { + notifier.notify(msg); + } + } + else if (msg.contains("Ultimate force")) + { + if (config.ultimateForceNotification()) + { + notifier.notify(msg); + } + } + } + } + + private void checkAbsorption() + { + int absorptionPoints = client.getVar(Varbits.NMZ_ABSORPTION); + + if (!absorptionNotificationSend) + { + if (absorptionPoints < config.absorptionThreshold()) + { + notifier.notify("Absorption points below: " + config.absorptionThreshold()); + absorptionNotificationSend = true; + } + } + else + { + if (absorptionPoints > config.absorptionThreshold()) + { + absorptionNotificationSend = false; + } + } + } + + public boolean isInNightmareZone() + { + return Arrays.equals(client.getMapRegions(), NMZ_MAP_REGION); + } +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/notes/NotesPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/notes/NotesPlugin.java index 0b23ac8eb2..67f397c646 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/notes/NotesPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/notes/NotesPlugin.java @@ -1,93 +1,93 @@ -/* - * Copyright (c) 2018 Charlie Waters - * 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.notes; - -import com.google.inject.Provides; -import java.awt.image.BufferedImage; -import javax.inject.Inject; -import net.runelite.client.events.SessionOpen; -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.ui.ClientToolbar; -import net.runelite.client.ui.NavigationButton; -import net.runelite.client.util.ImageUtil; - -@PluginDescriptor( - name = "Notes", - description = "Enable the Notes panel", - tags = {"panel"}, - loadWhenOutdated = true -) -public class NotesPlugin extends Plugin -{ - @Inject - private ClientToolbar clientToolbar; - - @Inject - private NotesConfig config; - - private NotesPanel panel; - private NavigationButton navButton; - - @Provides - NotesConfig getConfig(ConfigManager configManager) - { - return configManager.getConfig(NotesConfig.class); - } - - @Override - protected void startUp() throws Exception - { - panel = injector.getInstance(NotesPanel.class); - panel.init(config); - - final BufferedImage icon = ImageUtil.getResourceStreamFromClass(getClass(), "notes_icon.png"); - - navButton = NavigationButton.builder() - .tooltip("Notes") - .icon(icon) - .priority(7) - .panel(panel) - .build(); - - clientToolbar.addNavigation(navButton); - } - - @Override - protected void shutDown() - { - clientToolbar.removeNavigation(navButton); - } - - @Subscribe - public void onSessionOpen(SessionOpen event) - { - // update notes - String data = config.notesData(); - panel.setNotes(data); - } -} +/* + * Copyright (c) 2018 Charlie Waters + * 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.notes; + +import com.google.inject.Provides; +import java.awt.image.BufferedImage; +import javax.inject.Inject; +import net.runelite.client.config.ConfigManager; +import net.runelite.client.eventbus.Subscribe; +import net.runelite.client.events.SessionOpen; +import net.runelite.client.plugins.Plugin; +import net.runelite.client.plugins.PluginDescriptor; +import net.runelite.client.ui.ClientToolbar; +import net.runelite.client.ui.NavigationButton; +import net.runelite.client.util.ImageUtil; + +@PluginDescriptor( + name = "Notes", + description = "Enable the Notes panel", + tags = {"panel"}, + loadWhenOutdated = true +) +public class NotesPlugin extends Plugin +{ + @Inject + private ClientToolbar clientToolbar; + + @Inject + private NotesConfig config; + + private NotesPanel panel; + private NavigationButton navButton; + + @Provides + NotesConfig getConfig(ConfigManager configManager) + { + return configManager.getConfig(NotesConfig.class); + } + + @Override + protected void startUp() throws Exception + { + panel = injector.getInstance(NotesPanel.class); + panel.init(config); + + final BufferedImage icon = ImageUtil.getResourceStreamFromClass(getClass(), "notes_icon.png"); + + navButton = NavigationButton.builder() + .tooltip("Notes") + .icon(icon) + .priority(7) + .panel(panel) + .build(); + + clientToolbar.addNavigation(navButton); + } + + @Override + protected void shutDown() + { + clientToolbar.removeNavigation(navButton); + } + + @Subscribe + public void onSessionOpen(SessionOpen event) + { + // update notes + String data = config.notesData(); + panel.setNotes(data); + } +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/npchighlight/NpcIndicatorsPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/npchighlight/NpcIndicatorsPlugin.java index 983668eb00..1e114c453c 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/npchighlight/NpcIndicatorsPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/npchighlight/NpcIndicatorsPlugin.java @@ -67,7 +67,6 @@ import net.runelite.client.input.KeyManager; import net.runelite.client.plugins.Plugin; import net.runelite.client.plugins.PluginDescriptor; import net.runelite.client.ui.overlay.OverlayManager; -import net.runelite.client.util.ColorUtil; import net.runelite.client.util.Text; import net.runelite.client.util.WildcardMatcher; diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/npchighlight/NpcSceneOverlay.java b/runelite-client/src/main/java/net/runelite/client/plugins/npchighlight/NpcSceneOverlay.java index e84b6106e9..db84106343 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/npchighlight/NpcSceneOverlay.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/npchighlight/NpcSceneOverlay.java @@ -62,7 +62,7 @@ public class NpcSceneOverlay extends Overlay static { - ((DecimalFormat)TIME_LEFT_FORMATTER).applyPattern("#0.0"); + ((DecimalFormat) TIME_LEFT_FORMATTER).applyPattern("#0.0"); } private final Client client; diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/npcunaggroarea/NpcAggroAreaOverlay.java b/runelite-client/src/main/java/net/runelite/client/plugins/npcunaggroarea/NpcAggroAreaOverlay.java index 811952de57..f697d68473 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/npcunaggroarea/NpcAggroAreaOverlay.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/npcunaggroarea/NpcAggroAreaOverlay.java @@ -1,119 +1,119 @@ -/* - * Copyright (c) 2018, Woox - * 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.npcunaggroarea; - -import java.awt.BasicStroke; -import java.awt.Color; -import java.awt.Dimension; -import java.awt.Graphics2D; -import java.awt.Rectangle; -import java.awt.geom.GeneralPath; -import java.time.Instant; -import javax.inject.Inject; -import net.runelite.api.Client; -import net.runelite.api.Perspective; -import net.runelite.api.Point; -import net.runelite.api.coords.LocalPoint; -import net.runelite.api.geometry.Geometry; -import net.runelite.client.ui.overlay.Overlay; -import net.runelite.client.ui.overlay.OverlayLayer; -import net.runelite.client.ui.overlay.OverlayPosition; -import net.runelite.client.ui.overlay.OverlayPriority; - -class NpcAggroAreaOverlay extends Overlay -{ - private static final int MAX_LOCAL_DRAW_LENGTH = 20 * Perspective.LOCAL_TILE_SIZE; - - private final Client client; - private final NpcAggroAreaConfig config; - private final NpcAggroAreaPlugin plugin; - - @Inject - private NpcAggroAreaOverlay(Client client, NpcAggroAreaConfig config, NpcAggroAreaPlugin plugin) - { - this.client = client; - this.config = config; - this.plugin = plugin; - - setLayer(OverlayLayer.ABOVE_SCENE); - setPriority(OverlayPriority.LOW); - setPosition(OverlayPosition.DYNAMIC); - } - - @Override - public Dimension render(Graphics2D graphics) - { - if (!plugin.isActive() || plugin.getSafeCenters()[1] == null) - { - return null; - } - - GeneralPath lines = plugin.getLinesToDisplay()[client.getPlane()]; - if (lines == null) - { - return null; - } - - Color outlineColor = config.aggroAreaColor(); - AggressionTimer timer = plugin.getCurrentTimer(); - if (timer == null || Instant.now().compareTo(timer.getEndTime()) < 0) - { - outlineColor = new Color( - outlineColor.getRed(), - outlineColor.getGreen(), - outlineColor.getBlue(), - 100); - } - - renderPath(graphics, lines, outlineColor); - return null; - } - - private void renderPath(Graphics2D graphics, GeneralPath path, Color color) - { - LocalPoint playerLp = client.getLocalPlayer().getLocalLocation(); - Rectangle viewArea = new Rectangle( - playerLp.getX() - MAX_LOCAL_DRAW_LENGTH, - playerLp.getY() - MAX_LOCAL_DRAW_LENGTH, - MAX_LOCAL_DRAW_LENGTH * 2, - MAX_LOCAL_DRAW_LENGTH * 2); - - graphics.setColor(color); - graphics.setStroke(new BasicStroke(1)); - - path = Geometry.clipPath(path, viewArea); - path = Geometry.filterPath(path, (p1, p2) -> - Perspective.localToCanvas(client, new LocalPoint((int)p1[0], (int)p1[1]), client.getPlane()) != null && - Perspective.localToCanvas(client, new LocalPoint((int)p2[0], (int)p2[1]), client.getPlane()) != null); - path = Geometry.transformPath(path, coords -> - { - Point point = Perspective.localToCanvas(client, new LocalPoint((int)coords[0], (int)coords[1]), client.getPlane()); - coords[0] = point.getX(); - coords[1] = point.getY(); - }); - - graphics.draw(path); - } -} +/* + * Copyright (c) 2018, Woox + * 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.npcunaggroarea; + +import java.awt.BasicStroke; +import java.awt.Color; +import java.awt.Dimension; +import java.awt.Graphics2D; +import java.awt.Rectangle; +import java.awt.geom.GeneralPath; +import java.time.Instant; +import javax.inject.Inject; +import net.runelite.api.Client; +import net.runelite.api.Perspective; +import net.runelite.api.Point; +import net.runelite.api.coords.LocalPoint; +import net.runelite.api.geometry.Geometry; +import net.runelite.client.ui.overlay.Overlay; +import net.runelite.client.ui.overlay.OverlayLayer; +import net.runelite.client.ui.overlay.OverlayPosition; +import net.runelite.client.ui.overlay.OverlayPriority; + +class NpcAggroAreaOverlay extends Overlay +{ + private static final int MAX_LOCAL_DRAW_LENGTH = 20 * Perspective.LOCAL_TILE_SIZE; + + private final Client client; + private final NpcAggroAreaConfig config; + private final NpcAggroAreaPlugin plugin; + + @Inject + private NpcAggroAreaOverlay(Client client, NpcAggroAreaConfig config, NpcAggroAreaPlugin plugin) + { + this.client = client; + this.config = config; + this.plugin = plugin; + + setLayer(OverlayLayer.ABOVE_SCENE); + setPriority(OverlayPriority.LOW); + setPosition(OverlayPosition.DYNAMIC); + } + + @Override + public Dimension render(Graphics2D graphics) + { + if (!plugin.isActive() || plugin.getSafeCenters()[1] == null) + { + return null; + } + + GeneralPath lines = plugin.getLinesToDisplay()[client.getPlane()]; + if (lines == null) + { + return null; + } + + Color outlineColor = config.aggroAreaColor(); + AggressionTimer timer = plugin.getCurrentTimer(); + if (timer == null || Instant.now().compareTo(timer.getEndTime()) < 0) + { + outlineColor = new Color( + outlineColor.getRed(), + outlineColor.getGreen(), + outlineColor.getBlue(), + 100); + } + + renderPath(graphics, lines, outlineColor); + return null; + } + + private void renderPath(Graphics2D graphics, GeneralPath path, Color color) + { + LocalPoint playerLp = client.getLocalPlayer().getLocalLocation(); + Rectangle viewArea = new Rectangle( + playerLp.getX() - MAX_LOCAL_DRAW_LENGTH, + playerLp.getY() - MAX_LOCAL_DRAW_LENGTH, + MAX_LOCAL_DRAW_LENGTH * 2, + MAX_LOCAL_DRAW_LENGTH * 2); + + graphics.setColor(color); + graphics.setStroke(new BasicStroke(1)); + + path = Geometry.clipPath(path, viewArea); + path = Geometry.filterPath(path, (p1, p2) -> + Perspective.localToCanvas(client, new LocalPoint((int) p1[0], (int) p1[1]), client.getPlane()) != null && + Perspective.localToCanvas(client, new LocalPoint((int) p2[0], (int) p2[1]), client.getPlane()) != null); + path = Geometry.transformPath(path, coords -> + { + Point point = Perspective.localToCanvas(client, new LocalPoint((int) coords[0], (int) coords[1]), client.getPlane()); + coords[0] = point.getX(); + coords[1] = point.getY(); + }); + + graphics.draw(path); + } +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/npcunaggroarea/NpcAggroAreaPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/npcunaggroarea/NpcAggroAreaPlugin.java index 6d10bdba62..50aac7cf2c 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/npcunaggroarea/NpcAggroAreaPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/npcunaggroarea/NpcAggroAreaPlugin.java @@ -194,7 +194,7 @@ public class NpcAggroAreaPlugin extends Plugin private void transformWorldToLocal(float[] coords) { - final LocalPoint lp = LocalPoint.fromWorld(client, (int)coords[0], (int)coords[1]); + final LocalPoint lp = LocalPoint.fromWorld(client, (int) coords[0], (int) coords[1]); coords[0] = lp.getX() - Perspective.LOCAL_TILE_SIZE / 2f; coords[1] = lp.getY() - Perspective.LOCAL_TILE_SIZE / 2f; } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/objectindicators/ObjectIndicatorsPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/objectindicators/ObjectIndicatorsPlugin.java index 05fd84d0d8..3ab1377b8a 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/objectindicators/ObjectIndicatorsPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/objectindicators/ObjectIndicatorsPlugin.java @@ -1,391 +1,391 @@ -/* - * Copyright (c) 2018, Tomas Slusny - * Copyright (c) 2018, Adam - * 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.objectindicators; - -import com.google.common.base.Strings; -import com.google.gson.Gson; -import com.google.gson.reflect.TypeToken; -import com.google.inject.Provides; -import java.awt.event.KeyEvent; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; -import javax.inject.Inject; -import lombok.AccessLevel; -import lombok.Getter; -import lombok.extern.slf4j.Slf4j; -import net.runelite.api.Client; -import static net.runelite.api.Constants.REGION_SIZE; -import net.runelite.api.DecorativeObject; -import net.runelite.api.GameObject; -import net.runelite.api.GameState; -import net.runelite.api.MenuAction; -import net.runelite.api.MenuEntry; -import net.runelite.api.ObjectComposition; -import net.runelite.api.Scene; -import net.runelite.api.Tile; -import net.runelite.api.TileObject; -import net.runelite.api.coords.WorldPoint; -import net.runelite.api.events.FocusChanged; -import net.runelite.api.events.GameObjectDespawned; -import net.runelite.api.events.GameObjectSpawned; -import net.runelite.api.events.GameStateChanged; -import net.runelite.api.events.MenuEntryAdded; -import net.runelite.api.events.MenuOptionClicked; -import net.runelite.api.events.DecorativeObjectSpawned; -import net.runelite.api.events.DecorativeObjectDespawned; -import net.runelite.client.config.ConfigManager; -import net.runelite.client.eventbus.Subscribe; -import net.runelite.client.input.KeyListener; -import net.runelite.client.input.KeyManager; -import net.runelite.client.plugins.Plugin; -import net.runelite.client.plugins.PluginDescriptor; -import net.runelite.client.ui.overlay.OverlayManager; - -@Slf4j -@PluginDescriptor( - name = "Object Markers", - description = "Enable marking of objects using the Shift key", - tags = {"overlay", "objects", "mark", "marker"}, - enabledByDefault = false -) -public class ObjectIndicatorsPlugin extends Plugin implements KeyListener -{ - private static final String CONFIG_GROUP = "objectindicators"; - private static final String MARK = "Mark object"; - - private final Gson GSON = new Gson(); - @Getter(AccessLevel.PACKAGE) - private final List objects = new ArrayList<>(); - private final Map> points = new HashMap<>(); - private boolean hotKeyPressed; - - @Inject - private Client client; - - @Inject - private ConfigManager configManager; - - @Inject - private OverlayManager overlayManager; - - @Inject - private ObjectIndicatorsOverlay overlay; - - @Inject - private KeyManager keyManager; - - @Provides - ObjectIndicatorsConfig provideConfig(ConfigManager configManager) - { - return configManager.getConfig(ObjectIndicatorsConfig.class); - } - - @Override - protected void startUp() - { - overlayManager.add(overlay); - keyManager.registerKeyListener(this); - } - - @Override - protected void shutDown() - { - overlayManager.remove(overlay); - keyManager.unregisterKeyListener(this); - points.clear(); - objects.clear(); - hotKeyPressed = false; - } - - @Override - public void keyTyped(KeyEvent e) - { - - } - - @Override - public void keyPressed(KeyEvent e) - { - if (e.getKeyCode() == KeyEvent.VK_SHIFT) - { - hotKeyPressed = true; - } - } - - @Override - public void keyReleased(KeyEvent e) - { - if (e.getKeyCode() == KeyEvent.VK_SHIFT) - { - hotKeyPressed = false; - } - } - - @Subscribe - public void onFocusChanged(final FocusChanged event) - { - if (!event.isFocused()) - { - hotKeyPressed = false; - } - } - - @Subscribe - public void onGameObjectSpawned(GameObjectSpawned event) - { - final GameObject eventObject = event.getGameObject(); - checkObjectPoints(eventObject); - } - - @Subscribe - public void onDecorativeObjectSpawned(DecorativeObjectSpawned event) - { - final DecorativeObject eventObject = event.getDecorativeObject(); - checkObjectPoints(eventObject); - } - - @Subscribe - public void onGameObjectDespawned(GameObjectDespawned event) - { - objects.remove(event.getGameObject()); - } - - @Subscribe - public void onDecorativeObjectDespawned(DecorativeObjectDespawned event) - { - objects.remove(event.getDecorativeObject()); - } - - @Subscribe - public void onGameStateChanged(GameStateChanged gameStateChanged) - { - GameState gameState = gameStateChanged.getGameState(); - if (gameState == GameState.LOADING) - { - // Reload points with new map regions - - points.clear(); - for (int regionId : client.getMapRegions()) - { - // load points for region - final Set regionPoints = loadPoints(regionId); - if (regionPoints != null) - { - points.put(regionId, regionPoints); - } - } - } - - if (gameStateChanged.getGameState() != GameState.LOGGED_IN) - { - objects.clear(); - } - } - - @Subscribe - public void onMenuEntryAdded(MenuEntryAdded event) - { - if (!hotKeyPressed || event.getType() != MenuAction.EXAMINE_OBJECT.getId()) - { - return; - } - - MenuEntry[] menuEntries = client.getMenuEntries(); - menuEntries = Arrays.copyOf(menuEntries, menuEntries.length + 1); - MenuEntry menuEntry = menuEntries[menuEntries.length - 1] = new MenuEntry(); - menuEntry.setOption(MARK); - menuEntry.setTarget(event.getTarget()); - menuEntry.setParam0(event.getActionParam0()); - menuEntry.setParam1(event.getActionParam1()); - menuEntry.setIdentifier(event.getIdentifier()); - menuEntry.setType(MenuAction.RUNELITE.getId()); - client.setMenuEntries(menuEntries); - } - - @Subscribe - public void onMenuOptionClicked(MenuOptionClicked event) - { - if (event.getMenuAction() != MenuAction.RUNELITE || !event.getMenuOption().equals(MARK)) - { - return; - } - - Scene scene = client.getScene(); - Tile[][][] tiles = scene.getTiles(); - final int x = event.getActionParam(); - final int y = event.getWidgetId(); - final int z = client.getPlane(); - final Tile tile = tiles[z][x][y]; - - TileObject object = findTileObject(tile, event.getId()); - if (object == null) - { - return; - } - - ObjectComposition objectDefinition = client.getObjectDefinition(object.getId()); - String name = objectDefinition.getName(); - if (Strings.isNullOrEmpty(name)) - { - return; - } - - markObject(name, object); - } - - private void checkObjectPoints(TileObject object) - { - final WorldPoint worldPoint = WorldPoint.fromLocalInstance(client, object.getLocalLocation()); - final Set objectPoints = points.get(worldPoint.getRegionID()); - - if (objectPoints == null) - { - return; - } - - for (ObjectPoint objectPoint : objectPoints) - { - if ((worldPoint.getX() & (REGION_SIZE - 1)) == objectPoint.getRegionX() - && (worldPoint.getY() & (REGION_SIZE - 1)) == objectPoint.getRegionY()) - { - if (objectPoint.getName().equals(client.getObjectDefinition(object.getId()).getName())) - { - objects.add(object); - break; - } - } - } - } - - private TileObject findTileObject(Tile tile, int id) - { - if (tile == null) - { - return null; - } - - final GameObject[] tileGameObjects = tile.getGameObjects(); - final DecorativeObject tileDecorativeObject = tile.getDecorativeObject(); - - if (tileDecorativeObject != null && tileDecorativeObject.getId() == id) - { - return tileDecorativeObject; - } - - for (GameObject object : tileGameObjects) - { - if (object == null) - { - continue; - } - - if (object.getId() == id) - { - return object; - } - - // Check impostors - final ObjectComposition comp = client.getObjectDefinition(object.getId()); - - if (comp.getImpostorIds() != null) - { - for (int impostorId : comp.getImpostorIds()) - { - if (impostorId == id) - { - return object; - } - } - } - } - - return null; - } - - private void markObject(String name, final TileObject object) - { - if (object == null) - { - return; - } - - final WorldPoint worldPoint = WorldPoint.fromLocalInstance(client, object.getLocalLocation()); - final int regionId = worldPoint.getRegionID(); - final ObjectPoint point = new ObjectPoint( - name, - regionId, - worldPoint.getX() & (REGION_SIZE - 1), - worldPoint.getY() & (REGION_SIZE - 1), - client.getPlane()); - - Set objectPoints = points.computeIfAbsent(regionId, k -> new HashSet<>()); - - if (objectPoints.contains(point)) - { - objectPoints.remove(point); - objects.remove(object); - } - else - { - objectPoints.add(point); - objects.add(object); - } - - savePoints(regionId, objectPoints); - } - - private void savePoints(final int id, final Set points) - { - if (points.isEmpty()) - { - configManager.unsetConfiguration(CONFIG_GROUP, "region_" + id); - } - else - { - final String json = GSON.toJson(points); - configManager.setConfiguration(CONFIG_GROUP, "region_" + id, json); - } - } - - private Set loadPoints(final int id) - { - final String json = configManager.getConfiguration(CONFIG_GROUP, "region_" + id); - - if (Strings.isNullOrEmpty(json)) - { - return null; - } - - return GSON.fromJson(json, new TypeToken>() - { - }.getType()); - } +/* + * Copyright (c) 2018, Tomas Slusny + * Copyright (c) 2018, Adam + * 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.objectindicators; + +import com.google.common.base.Strings; +import com.google.gson.Gson; +import com.google.gson.reflect.TypeToken; +import com.google.inject.Provides; +import java.awt.event.KeyEvent; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import javax.inject.Inject; +import lombok.AccessLevel; +import lombok.Getter; +import lombok.extern.slf4j.Slf4j; +import net.runelite.api.Client; +import static net.runelite.api.Constants.REGION_SIZE; +import net.runelite.api.DecorativeObject; +import net.runelite.api.GameObject; +import net.runelite.api.GameState; +import net.runelite.api.MenuAction; +import net.runelite.api.MenuEntry; +import net.runelite.api.ObjectComposition; +import net.runelite.api.Scene; +import net.runelite.api.Tile; +import net.runelite.api.TileObject; +import net.runelite.api.coords.WorldPoint; +import net.runelite.api.events.DecorativeObjectDespawned; +import net.runelite.api.events.DecorativeObjectSpawned; +import net.runelite.api.events.FocusChanged; +import net.runelite.api.events.GameObjectDespawned; +import net.runelite.api.events.GameObjectSpawned; +import net.runelite.api.events.GameStateChanged; +import net.runelite.api.events.MenuEntryAdded; +import net.runelite.api.events.MenuOptionClicked; +import net.runelite.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.ui.overlay.OverlayManager; + +@Slf4j +@PluginDescriptor( + name = "Object Markers", + description = "Enable marking of objects using the Shift key", + tags = {"overlay", "objects", "mark", "marker"}, + enabledByDefault = false +) +public class ObjectIndicatorsPlugin extends Plugin implements KeyListener +{ + private static final String CONFIG_GROUP = "objectindicators"; + private static final String MARK = "Mark object"; + + private final Gson GSON = new Gson(); + @Getter(AccessLevel.PACKAGE) + private final List objects = new ArrayList<>(); + private final Map> points = new HashMap<>(); + private boolean hotKeyPressed; + + @Inject + private Client client; + + @Inject + private ConfigManager configManager; + + @Inject + private OverlayManager overlayManager; + + @Inject + private ObjectIndicatorsOverlay overlay; + + @Inject + private KeyManager keyManager; + + @Provides + ObjectIndicatorsConfig provideConfig(ConfigManager configManager) + { + return configManager.getConfig(ObjectIndicatorsConfig.class); + } + + @Override + protected void startUp() + { + overlayManager.add(overlay); + keyManager.registerKeyListener(this); + } + + @Override + protected void shutDown() + { + overlayManager.remove(overlay); + keyManager.unregisterKeyListener(this); + points.clear(); + objects.clear(); + hotKeyPressed = false; + } + + @Override + public void keyTyped(KeyEvent e) + { + + } + + @Override + public void keyPressed(KeyEvent e) + { + if (e.getKeyCode() == KeyEvent.VK_SHIFT) + { + hotKeyPressed = true; + } + } + + @Override + public void keyReleased(KeyEvent e) + { + if (e.getKeyCode() == KeyEvent.VK_SHIFT) + { + hotKeyPressed = false; + } + } + + @Subscribe + public void onFocusChanged(final FocusChanged event) + { + if (!event.isFocused()) + { + hotKeyPressed = false; + } + } + + @Subscribe + public void onGameObjectSpawned(GameObjectSpawned event) + { + final GameObject eventObject = event.getGameObject(); + checkObjectPoints(eventObject); + } + + @Subscribe + public void onDecorativeObjectSpawned(DecorativeObjectSpawned event) + { + final DecorativeObject eventObject = event.getDecorativeObject(); + checkObjectPoints(eventObject); + } + + @Subscribe + public void onGameObjectDespawned(GameObjectDespawned event) + { + objects.remove(event.getGameObject()); + } + + @Subscribe + public void onDecorativeObjectDespawned(DecorativeObjectDespawned event) + { + objects.remove(event.getDecorativeObject()); + } + + @Subscribe + public void onGameStateChanged(GameStateChanged gameStateChanged) + { + GameState gameState = gameStateChanged.getGameState(); + if (gameState == GameState.LOADING) + { + // Reload points with new map regions + + points.clear(); + for (int regionId : client.getMapRegions()) + { + // load points for region + final Set regionPoints = loadPoints(regionId); + if (regionPoints != null) + { + points.put(regionId, regionPoints); + } + } + } + + if (gameStateChanged.getGameState() != GameState.LOGGED_IN) + { + objects.clear(); + } + } + + @Subscribe + public void onMenuEntryAdded(MenuEntryAdded event) + { + if (!hotKeyPressed || event.getType() != MenuAction.EXAMINE_OBJECT.getId()) + { + return; + } + + MenuEntry[] menuEntries = client.getMenuEntries(); + menuEntries = Arrays.copyOf(menuEntries, menuEntries.length + 1); + MenuEntry menuEntry = menuEntries[menuEntries.length - 1] = new MenuEntry(); + menuEntry.setOption(MARK); + menuEntry.setTarget(event.getTarget()); + menuEntry.setParam0(event.getActionParam0()); + menuEntry.setParam1(event.getActionParam1()); + menuEntry.setIdentifier(event.getIdentifier()); + menuEntry.setType(MenuAction.RUNELITE.getId()); + client.setMenuEntries(menuEntries); + } + + @Subscribe + public void onMenuOptionClicked(MenuOptionClicked event) + { + if (event.getMenuAction() != MenuAction.RUNELITE || !event.getMenuOption().equals(MARK)) + { + return; + } + + Scene scene = client.getScene(); + Tile[][][] tiles = scene.getTiles(); + final int x = event.getActionParam(); + final int y = event.getWidgetId(); + final int z = client.getPlane(); + final Tile tile = tiles[z][x][y]; + + TileObject object = findTileObject(tile, event.getId()); + if (object == null) + { + return; + } + + ObjectComposition objectDefinition = client.getObjectDefinition(object.getId()); + String name = objectDefinition.getName(); + if (Strings.isNullOrEmpty(name)) + { + return; + } + + markObject(name, object); + } + + private void checkObjectPoints(TileObject object) + { + final WorldPoint worldPoint = WorldPoint.fromLocalInstance(client, object.getLocalLocation()); + final Set objectPoints = points.get(worldPoint.getRegionID()); + + if (objectPoints == null) + { + return; + } + + for (ObjectPoint objectPoint : objectPoints) + { + if ((worldPoint.getX() & (REGION_SIZE - 1)) == objectPoint.getRegionX() + && (worldPoint.getY() & (REGION_SIZE - 1)) == objectPoint.getRegionY()) + { + if (objectPoint.getName().equals(client.getObjectDefinition(object.getId()).getName())) + { + objects.add(object); + break; + } + } + } + } + + private TileObject findTileObject(Tile tile, int id) + { + if (tile == null) + { + return null; + } + + final GameObject[] tileGameObjects = tile.getGameObjects(); + final DecorativeObject tileDecorativeObject = tile.getDecorativeObject(); + + if (tileDecorativeObject != null && tileDecorativeObject.getId() == id) + { + return tileDecorativeObject; + } + + for (GameObject object : tileGameObjects) + { + if (object == null) + { + continue; + } + + if (object.getId() == id) + { + return object; + } + + // Check impostors + final ObjectComposition comp = client.getObjectDefinition(object.getId()); + + if (comp.getImpostorIds() != null) + { + for (int impostorId : comp.getImpostorIds()) + { + if (impostorId == id) + { + return object; + } + } + } + } + + return null; + } + + private void markObject(String name, final TileObject object) + { + if (object == null) + { + return; + } + + final WorldPoint worldPoint = WorldPoint.fromLocalInstance(client, object.getLocalLocation()); + final int regionId = worldPoint.getRegionID(); + final ObjectPoint point = new ObjectPoint( + name, + regionId, + worldPoint.getX() & (REGION_SIZE - 1), + worldPoint.getY() & (REGION_SIZE - 1), + client.getPlane()); + + Set objectPoints = points.computeIfAbsent(regionId, k -> new HashSet<>()); + + if (objectPoints.contains(point)) + { + objectPoints.remove(point); + objects.remove(object); + } + else + { + objectPoints.add(point); + objects.add(object); + } + + savePoints(regionId, objectPoints); + } + + private void savePoints(final int id, final Set points) + { + if (points.isEmpty()) + { + configManager.unsetConfiguration(CONFIG_GROUP, "region_" + id); + } + else + { + final String json = GSON.toJson(points); + configManager.setConfiguration(CONFIG_GROUP, "region_" + id, json); + } + } + + private Set loadPoints(final int id) + { + final String json = configManager.getConfiguration(CONFIG_GROUP, "region_" + id); + + if (Strings.isNullOrEmpty(json)) + { + return null; + } + + return GSON.fromJson(json, new TypeToken>() + { + }.getType()); + } } \ No newline at end of file diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/opponentinfo/PlayerComparisonOverlay.java b/runelite-client/src/main/java/net/runelite/client/plugins/opponentinfo/PlayerComparisonOverlay.java index 7517e4e3bf..9f3f8afb4c 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/opponentinfo/PlayerComparisonOverlay.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/opponentinfo/PlayerComparisonOverlay.java @@ -1,187 +1,187 @@ -/* - * Copyright (c) 2018, Jordan Atwood - * Copyright (c) 2018, Adam - * 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.opponentinfo; - -import java.awt.Color; -import java.awt.Dimension; -import java.awt.Graphics2D; -import javax.inject.Inject; -import net.runelite.api.Actor; -import net.runelite.api.Client; -import static net.runelite.api.MenuAction.RUNELITE_OVERLAY_CONFIG; -import net.runelite.api.Player; -import net.runelite.api.Skill; -import net.runelite.client.game.HiscoreManager; -import net.runelite.client.ui.overlay.Overlay; -import net.runelite.client.ui.overlay.OverlayLayer; -import static net.runelite.client.ui.overlay.OverlayManager.OPTION_CONFIGURE; -import net.runelite.client.ui.overlay.OverlayMenuEntry; -import net.runelite.client.ui.overlay.OverlayPosition; -import net.runelite.client.ui.overlay.components.LineComponent; -import net.runelite.client.ui.overlay.components.PanelComponent; -import net.runelite.client.ui.overlay.components.TitleComponent; -import net.runelite.client.util.Text; -import net.runelite.http.api.hiscore.HiscoreResult; -import net.runelite.http.api.hiscore.HiscoreSkill; - -class PlayerComparisonOverlay extends Overlay -{ - private static final Color HIGHER_STAT_TEXT_COLOR = Color.GREEN; - private static final Color LOWER_STAT_TEXT_COLOR = Color.RED; - private static final Color NEUTRAL_TEXT_COLOR = Color.WHITE; - private static final Color HIGHLIGHT_COLOR = new Color(255, 200, 0, 255); - - private static final Skill[] COMBAT_SKILLS = new Skill[]{ - Skill.ATTACK, - Skill.STRENGTH, - Skill.DEFENCE, - Skill.HITPOINTS, - Skill.RANGED, - Skill.MAGIC, - Skill.PRAYER - }; - - private static final HiscoreSkill[] HISCORE_COMBAT_SKILLS = new HiscoreSkill[]{ - HiscoreSkill.ATTACK, - HiscoreSkill.STRENGTH, - HiscoreSkill.DEFENCE, - HiscoreSkill.HITPOINTS, - HiscoreSkill.RANGED, - HiscoreSkill.MAGIC, - HiscoreSkill.PRAYER - }; - - private static final String LEFT_COLUMN_HEADER = "Skill"; - private static final String RIGHT_COLUMN_HEADER = "You/Them"; - - private final Client client; - private final OpponentInfoPlugin opponentInfoPlugin; - private final OpponentInfoConfig config; - private final HiscoreManager hiscoreManager; - private final PanelComponent panelComponent = new PanelComponent(); - - @Inject - private PlayerComparisonOverlay(Client client, OpponentInfoPlugin opponentInfoPlugin, OpponentInfoConfig config, HiscoreManager hiscoreManager) - { - super(opponentInfoPlugin); - this.client = client; - this.opponentInfoPlugin = opponentInfoPlugin; - this.config = config; - this.hiscoreManager = hiscoreManager; - - setPosition(OverlayPosition.BOTTOM_LEFT); - setLayer(OverlayLayer.ABOVE_WIDGETS); - getMenuEntries().add(new OverlayMenuEntry(RUNELITE_OVERLAY_CONFIG, OPTION_CONFIGURE, "Opponent info overlay")); - } - - @Override - public Dimension render(Graphics2D graphics) - { - if (!config.lookupOnInteraction()) - { - return null; - } - - final Actor opponent = opponentInfoPlugin.getLastOpponent(); - - if (opponent == null) - { - return null; - } - - // Don't try to look up NPC names - if (!(opponent instanceof Player)) - { - return null; - } - - final String opponentName = Text.removeTags(opponent.getName()); - final HiscoreResult hiscoreResult = hiscoreManager.lookupAsync(opponentName, opponentInfoPlugin.getHiscoreEndpoint()); - if (hiscoreResult == null) - { - return null; - } - - panelComponent.getChildren().clear(); - generateComparisonTable(panelComponent, hiscoreResult); - return panelComponent.render(graphics); - } - - private void generateComparisonTable(PanelComponent panelComponent, HiscoreResult opponentSkills) - { - final String opponentName = opponentSkills.getPlayer(); - - panelComponent.getChildren().add( - TitleComponent.builder() - .text(opponentName) - .color(HIGHLIGHT_COLOR) - .build()); - - panelComponent.getChildren().add( - LineComponent.builder() - .left(LEFT_COLUMN_HEADER) - .leftColor(HIGHLIGHT_COLOR) - .right(RIGHT_COLUMN_HEADER) - .rightColor(HIGHLIGHT_COLOR) - .build()); - - for (int i = 0; i < COMBAT_SKILLS.length; ++i) - { - final HiscoreSkill hiscoreSkill = HISCORE_COMBAT_SKILLS[i]; - final Skill skill = COMBAT_SKILLS[i]; - - final net.runelite.http.api.hiscore.Skill opponentSkill = opponentSkills.getSkill(hiscoreSkill); - - if (opponentSkill == null || opponentSkill.getLevel() == -1) - { - continue; - } - - final int playerSkillLevel = client.getRealSkillLevel(skill); - final int opponentSkillLevel = opponentSkill.getLevel(); - - panelComponent.getChildren().add( - LineComponent.builder() - .left(hiscoreSkill.getName()) - .right(Integer.toString(playerSkillLevel) + "/" + Integer.toString(opponentSkillLevel)) - .rightColor(comparisonStatColor(playerSkillLevel, opponentSkillLevel)) - .build()); - } - } - - private static Color comparisonStatColor(int a, int b) - { - if (a > b) - { - return HIGHER_STAT_TEXT_COLOR; - } - if (a < b) - { - return LOWER_STAT_TEXT_COLOR; - } - return NEUTRAL_TEXT_COLOR; - } -} +/* + * Copyright (c) 2018, Jordan Atwood + * Copyright (c) 2018, Adam + * 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.opponentinfo; + +import java.awt.Color; +import java.awt.Dimension; +import java.awt.Graphics2D; +import javax.inject.Inject; +import net.runelite.api.Actor; +import net.runelite.api.Client; +import static net.runelite.api.MenuAction.RUNELITE_OVERLAY_CONFIG; +import net.runelite.api.Player; +import net.runelite.api.Skill; +import net.runelite.client.game.HiscoreManager; +import net.runelite.client.ui.overlay.Overlay; +import net.runelite.client.ui.overlay.OverlayLayer; +import static net.runelite.client.ui.overlay.OverlayManager.OPTION_CONFIGURE; +import net.runelite.client.ui.overlay.OverlayMenuEntry; +import net.runelite.client.ui.overlay.OverlayPosition; +import net.runelite.client.ui.overlay.components.LineComponent; +import net.runelite.client.ui.overlay.components.PanelComponent; +import net.runelite.client.ui.overlay.components.TitleComponent; +import net.runelite.client.util.Text; +import net.runelite.http.api.hiscore.HiscoreResult; +import net.runelite.http.api.hiscore.HiscoreSkill; + +class PlayerComparisonOverlay extends Overlay +{ + private static final Color HIGHER_STAT_TEXT_COLOR = Color.GREEN; + private static final Color LOWER_STAT_TEXT_COLOR = Color.RED; + private static final Color NEUTRAL_TEXT_COLOR = Color.WHITE; + private static final Color HIGHLIGHT_COLOR = new Color(255, 200, 0, 255); + + private static final Skill[] COMBAT_SKILLS = new Skill[]{ + Skill.ATTACK, + Skill.STRENGTH, + Skill.DEFENCE, + Skill.HITPOINTS, + Skill.RANGED, + Skill.MAGIC, + Skill.PRAYER + }; + + private static final HiscoreSkill[] HISCORE_COMBAT_SKILLS = new HiscoreSkill[]{ + HiscoreSkill.ATTACK, + HiscoreSkill.STRENGTH, + HiscoreSkill.DEFENCE, + HiscoreSkill.HITPOINTS, + HiscoreSkill.RANGED, + HiscoreSkill.MAGIC, + HiscoreSkill.PRAYER + }; + + private static final String LEFT_COLUMN_HEADER = "Skill"; + private static final String RIGHT_COLUMN_HEADER = "You/Them"; + + private final Client client; + private final OpponentInfoPlugin opponentInfoPlugin; + private final OpponentInfoConfig config; + private final HiscoreManager hiscoreManager; + private final PanelComponent panelComponent = new PanelComponent(); + + @Inject + private PlayerComparisonOverlay(Client client, OpponentInfoPlugin opponentInfoPlugin, OpponentInfoConfig config, HiscoreManager hiscoreManager) + { + super(opponentInfoPlugin); + this.client = client; + this.opponentInfoPlugin = opponentInfoPlugin; + this.config = config; + this.hiscoreManager = hiscoreManager; + + setPosition(OverlayPosition.BOTTOM_LEFT); + setLayer(OverlayLayer.ABOVE_WIDGETS); + getMenuEntries().add(new OverlayMenuEntry(RUNELITE_OVERLAY_CONFIG, OPTION_CONFIGURE, "Opponent info overlay")); + } + + @Override + public Dimension render(Graphics2D graphics) + { + if (!config.lookupOnInteraction()) + { + return null; + } + + final Actor opponent = opponentInfoPlugin.getLastOpponent(); + + if (opponent == null) + { + return null; + } + + // Don't try to look up NPC names + if (!(opponent instanceof Player)) + { + return null; + } + + final String opponentName = Text.removeTags(opponent.getName()); + final HiscoreResult hiscoreResult = hiscoreManager.lookupAsync(opponentName, opponentInfoPlugin.getHiscoreEndpoint()); + if (hiscoreResult == null) + { + return null; + } + + panelComponent.getChildren().clear(); + generateComparisonTable(panelComponent, hiscoreResult); + return panelComponent.render(graphics); + } + + private void generateComparisonTable(PanelComponent panelComponent, HiscoreResult opponentSkills) + { + final String opponentName = opponentSkills.getPlayer(); + + panelComponent.getChildren().add( + TitleComponent.builder() + .text(opponentName) + .color(HIGHLIGHT_COLOR) + .build()); + + panelComponent.getChildren().add( + LineComponent.builder() + .left(LEFT_COLUMN_HEADER) + .leftColor(HIGHLIGHT_COLOR) + .right(RIGHT_COLUMN_HEADER) + .rightColor(HIGHLIGHT_COLOR) + .build()); + + for (int i = 0; i < COMBAT_SKILLS.length; ++i) + { + final HiscoreSkill hiscoreSkill = HISCORE_COMBAT_SKILLS[i]; + final Skill skill = COMBAT_SKILLS[i]; + + final net.runelite.http.api.hiscore.Skill opponentSkill = opponentSkills.getSkill(hiscoreSkill); + + if (opponentSkill == null || opponentSkill.getLevel() == -1) + { + continue; + } + + final int playerSkillLevel = client.getRealSkillLevel(skill); + final int opponentSkillLevel = opponentSkill.getLevel(); + + panelComponent.getChildren().add( + LineComponent.builder() + .left(hiscoreSkill.getName()) + .right(playerSkillLevel + "/" + opponentSkillLevel) + .rightColor(comparisonStatColor(playerSkillLevel, opponentSkillLevel)) + .build()); + } + } + + private static Color comparisonStatColor(int a, int b) + { + if (a > b) + { + return HIGHER_STAT_TEXT_COLOR; + } + if (a < b) + { + return LOWER_STAT_TEXT_COLOR; + } + return NEUTRAL_TEXT_COLOR; + } +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/party/PartyPluginService.java b/runelite-client/src/main/java/net/runelite/client/plugins/party/PartyPluginService.java index 8f944eb833..c31fd86444 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/party/PartyPluginService.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/party/PartyPluginService.java @@ -1,40 +1,41 @@ -/* - * Copyright (c) 2019, Adam - * 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.party; - -import java.util.UUID; -import javax.annotation.Nullable; -import net.runelite.client.plugins.party.data.PartyData; - -public interface PartyPluginService -{ - /** - * Get the party data for a party member - * @param memberId member id - * @return party data for member - */ - @Nullable - PartyData getPartyData(UUID memberId); -} +/* + * Copyright (c) 2019, Adam + * 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.party; + +import java.util.UUID; +import javax.annotation.Nullable; +import net.runelite.client.plugins.party.data.PartyData; + +public interface PartyPluginService +{ + /** + * Get the party data for a party member + * + * @param memberId member id + * @return party data for member + */ + @Nullable + PartyData getPartyData(UUID memberId); +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/pestcontrol/PortalWeaknessOverlay.java b/runelite-client/src/main/java/net/runelite/client/plugins/pestcontrol/PortalWeaknessOverlay.java index ff0deee9c2..ed83ff2b2e 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/pestcontrol/PortalWeaknessOverlay.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/pestcontrol/PortalWeaknessOverlay.java @@ -1,198 +1,194 @@ -/* - * Copyright (c) 2019, Yani - * 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.pestcontrol; - -import com.google.inject.Inject; -import java.awt.AlphaComposite; -import java.awt.Composite; -import java.awt.Dimension; -import java.awt.Graphics2D; -import java.awt.image.BufferedImage; -import lombok.extern.slf4j.Slf4j; -import net.runelite.api.Client; -import net.runelite.api.ItemID; -import net.runelite.api.Perspective; -import net.runelite.api.Point; -import net.runelite.api.Skill; -import net.runelite.api.coords.LocalPoint; -import net.runelite.api.coords.WorldPoint; -import net.runelite.client.game.ItemManager; -import net.runelite.client.game.SkillIconManager; -import net.runelite.client.ui.overlay.Overlay; -import net.runelite.client.ui.overlay.OverlayLayer; -import net.runelite.client.ui.overlay.OverlayPosition; -import net.runelite.client.ui.overlay.OverlayUtil; - -@Slf4j -public class PortalWeaknessOverlay extends Overlay -{ - private int zOffset = 100; - - private final PestControlConfig config; - private final PestControlPlugin plugin; - private final Client client; - - private BufferedImage magicImage; - private BufferedImage rangedImage; - private BufferedImage stabImage; - private BufferedImage slashImage; - private BufferedImage crushImage; - - @Inject - PortalWeaknessOverlay( - PestControlConfig config, - PestControlPlugin plugin, - Client client, - ItemManager itemManager, - SkillIconManager skillIconManager - ) - { - this.config = config; - this.plugin = plugin; - this.client = client; - - this.magicImage = skillIconManager.getSkillImage(Skill.MAGIC); - this.rangedImage = skillIconManager.getSkillImage(Skill.RANGED); - - this.stabImage = itemManager.getImage(ItemID.WHITE_DAGGER); - this.slashImage = itemManager.getImage(ItemID.WHITE_SCIMITAR); - this.crushImage = itemManager.getImage(ItemID.WHITE_WARHAMMER); - - setPosition(OverlayPosition.DYNAMIC); - setLayer(OverlayLayer.UNDER_WIDGETS); - } - - private Point getPortalPoint(Portal portal) - { - WorldPoint portalLocation = portal.getLocation(); - LocalPoint localLocation = LocalPoint.fromWorld(client, portalLocation); - - if (localLocation == null) - { - return null; - } - - // We can use any image here as it's only needed to calculate the position - Point imageLocation = Perspective.getCanvasImageLocation(client, localLocation, magicImage, zOffset); - - if (imageLocation != null) - { - return imageLocation; - } - - return null; - } - - private void renderPortalWeakness(Graphics2D graphics, Portal portal, BufferedImage image) - { - Point portalPoint = getPortalPoint(portal); - - if (portalPoint != null) - { - Composite originalComposite = graphics.getComposite(); - Composite translucentComposite = AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.5f); - graphics.setComposite(translucentComposite); - - OverlayUtil.renderImageLocation(graphics, portalPoint, image); - - graphics.setComposite(originalComposite); - } - } - - private void renderDoublePortalWeakness( - Graphics2D graphics, - Portal portal, - BufferedImage imageLeft, - BufferedImage imageRight - ) - { - Point portalPoint = getPortalPoint(portal); - - if (portalPoint != null) - { - Point portalLeft = new Point( - portalPoint.getX() - (imageLeft.getWidth() / 2) - 5, - portalPoint.getY() - ); - - Point portalRight = new Point( - portalPoint.getX() + (imageRight.getWidth() / 2) + 5, - portalPoint.getY() - ); - - Composite originalComposite = graphics.getComposite(); - Composite translucentComposite = AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.6f); - graphics.setComposite(translucentComposite); - - OverlayUtil.renderImageLocation(graphics, portalLeft, imageLeft); - OverlayUtil.renderImageLocation(graphics, portalPoint, imageRight); - - graphics.setComposite(originalComposite); - } - } - - @Override - public Dimension render(Graphics2D graphics) - { - Game game = plugin.getGame(); - - if (game == null) - { - return null; - } - - for (Portal portal : game.getPortals()) - { - if (!portal.isDead()) - { - switch (portal.getColor()) - { - case BLUE: - { - renderPortalWeakness(graphics, portal, magicImage); - break; - } - case YELLOW: - { - renderDoublePortalWeakness(graphics, portal, stabImage, slashImage); - break; - } - case RED: - { - renderPortalWeakness(graphics, portal, crushImage); - break; - } - case PURPLE: - { - renderPortalWeakness(graphics, portal, rangedImage); - break; - } - } - } - } - - return null; - } +/* + * Copyright (c) 2019, Yani + * 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.pestcontrol; + +import com.google.inject.Inject; +import java.awt.AlphaComposite; +import java.awt.Composite; +import java.awt.Dimension; +import java.awt.Graphics2D; +import java.awt.image.BufferedImage; +import lombok.extern.slf4j.Slf4j; +import net.runelite.api.Client; +import net.runelite.api.ItemID; +import net.runelite.api.Perspective; +import net.runelite.api.Point; +import net.runelite.api.Skill; +import net.runelite.api.coords.LocalPoint; +import net.runelite.api.coords.WorldPoint; +import net.runelite.client.game.ItemManager; +import net.runelite.client.game.SkillIconManager; +import net.runelite.client.ui.overlay.Overlay; +import net.runelite.client.ui.overlay.OverlayLayer; +import net.runelite.client.ui.overlay.OverlayPosition; +import net.runelite.client.ui.overlay.OverlayUtil; + +@Slf4j +public class PortalWeaknessOverlay extends Overlay +{ + private int zOffset = 100; + + private final PestControlConfig config; + private final PestControlPlugin plugin; + private final Client client; + + private BufferedImage magicImage; + private BufferedImage rangedImage; + private BufferedImage stabImage; + private BufferedImage slashImage; + private BufferedImage crushImage; + + @Inject + PortalWeaknessOverlay( + PestControlConfig config, + PestControlPlugin plugin, + Client client, + ItemManager itemManager, + SkillIconManager skillIconManager + ) + { + this.config = config; + this.plugin = plugin; + this.client = client; + + this.magicImage = skillIconManager.getSkillImage(Skill.MAGIC); + this.rangedImage = skillIconManager.getSkillImage(Skill.RANGED); + + this.stabImage = itemManager.getImage(ItemID.WHITE_DAGGER); + this.slashImage = itemManager.getImage(ItemID.WHITE_SCIMITAR); + this.crushImage = itemManager.getImage(ItemID.WHITE_WARHAMMER); + + setPosition(OverlayPosition.DYNAMIC); + setLayer(OverlayLayer.UNDER_WIDGETS); + } + + private Point getPortalPoint(Portal portal) + { + WorldPoint portalLocation = portal.getLocation(); + LocalPoint localLocation = LocalPoint.fromWorld(client, portalLocation); + + if (localLocation == null) + { + return null; + } + + // We can use any image here as it's only needed to calculate the position + Point imageLocation = Perspective.getCanvasImageLocation(client, localLocation, magicImage, zOffset); + + return imageLocation; + + } + + private void renderPortalWeakness(Graphics2D graphics, Portal portal, BufferedImage image) + { + Point portalPoint = getPortalPoint(portal); + + if (portalPoint != null) + { + Composite originalComposite = graphics.getComposite(); + Composite translucentComposite = AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.5f); + graphics.setComposite(translucentComposite); + + OverlayUtil.renderImageLocation(graphics, portalPoint, image); + + graphics.setComposite(originalComposite); + } + } + + private void renderDoublePortalWeakness( + Graphics2D graphics, + Portal portal, + BufferedImage imageLeft, + BufferedImage imageRight + ) + { + Point portalPoint = getPortalPoint(portal); + + if (portalPoint != null) + { + Point portalLeft = new Point( + portalPoint.getX() - (imageLeft.getWidth() / 2) - 5, + portalPoint.getY() + ); + + Point portalRight = new Point( + portalPoint.getX() + (imageRight.getWidth() / 2) + 5, + portalPoint.getY() + ); + + Composite originalComposite = graphics.getComposite(); + Composite translucentComposite = AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.6f); + graphics.setComposite(translucentComposite); + + OverlayUtil.renderImageLocation(graphics, portalLeft, imageLeft); + OverlayUtil.renderImageLocation(graphics, portalPoint, imageRight); + + graphics.setComposite(originalComposite); + } + } + + @Override + public Dimension render(Graphics2D graphics) + { + Game game = plugin.getGame(); + + if (game == null) + { + return null; + } + + for (Portal portal : game.getPortals()) + { + if (!portal.isDead()) + { + switch (portal.getColor()) + { + case BLUE: + { + renderPortalWeakness(graphics, portal, magicImage); + break; + } + case YELLOW: + { + renderDoublePortalWeakness(graphics, portal, stabImage, slashImage); + break; + } + case RED: + { + renderPortalWeakness(graphics, portal, crushImage); + break; + } + case PURPLE: + { + renderPortalWeakness(graphics, portal, rangedImage); + break; + } + } + } + } + + return null; + } } \ No newline at end of file diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/pestcontrol/WidgetOverlay.java b/runelite-client/src/main/java/net/runelite/client/plugins/pestcontrol/WidgetOverlay.java index 4633128d6d..9fb06588fd 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/pestcontrol/WidgetOverlay.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/pestcontrol/WidgetOverlay.java @@ -1,210 +1,210 @@ -/* - * Copyright (c) 2017, Kronos - * Copyright (c) 2017, Adam - * Copyright (c) 2019, Yani - * 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.pestcontrol; - -import java.awt.Color; -import java.awt.Dimension; -import java.awt.FontMetrics; -import java.awt.Graphics2D; -import java.awt.geom.Rectangle2D; -import javax.inject.Inject; -import lombok.extern.slf4j.Slf4j; -import net.runelite.api.Client; -import net.runelite.api.widgets.Widget; -import net.runelite.api.widgets.WidgetInfo; -import net.runelite.client.ui.overlay.Overlay; -import net.runelite.client.ui.overlay.OverlayLayer; -import net.runelite.client.ui.overlay.OverlayPosition; - -@Slf4j -public class WidgetOverlay extends Overlay -{ - private final Client client; - - private final PestControlPlugin plugin; - - @Inject - public WidgetOverlay(Client client, PestControlPlugin plugin) - { - this.plugin = plugin; - this.client = client; - - setPosition(OverlayPosition.DYNAMIC); - setLayer(OverlayLayer.ABOVE_SCENE); - } - - public Integer getPortalHitpoints(PortalColor color) - { - if (plugin.getGame() == null) - { - return null; - } - - WidgetInfo healthWidgetInfo = null; - - switch (color) - { - case RED: - { - healthWidgetInfo = WidgetPortal.RED.getHitpoints(); - break; - } - case BLUE: - { - healthWidgetInfo = WidgetPortal.BLUE.getHitpoints(); - break; - } - case PURPLE: - { - healthWidgetInfo = WidgetPortal.PURPLE.getHitpoints(); - break; - } - case YELLOW: - { - healthWidgetInfo = WidgetPortal.YELLOW.getHitpoints(); - break; - } - } - - if (healthWidgetInfo == null) - { - return null; - } - - Widget healthWidget = client.getWidget(healthWidgetInfo); - - if (healthWidget == null) - { - return null; - } - - return Integer.parseInt(healthWidget.getText().trim()); - } - - @Override - public Dimension render(Graphics2D graphics) - { - if (plugin.getGame() == null) - { - return null; - } - - for (Portal portal : plugin.getGame().getNextPortals()) - { - renderWidgetOverlay(graphics, portal, "NEXT", Color.ORANGE); - } - - for (Portal portal : plugin.getGame().getActivePortals()) - { - renderWidgetOverlay(graphics, portal, "ATT", Color.RED); - } - - renderProgressWidget(graphics); - - return null; - } - - private void renderWidgetOverlay(Graphics2D graphics, Portal portal, String text, Color color) - { - Widget shield = client.getWidget(portal.getWidget().getShield()); - Widget icon = client.getWidget(portal.getWidget().getIcon()); - Widget hp = client.getWidget(portal.getWidget().getHitpoints()); - - Widget bar = client.getWidget(WidgetInfo.PEST_CONTROL_ACTIVITY_BAR).getChild(0); - - Rectangle2D barBounds = bar.getBounds().getBounds2D(); - - // create one rectangle from two different widget bounds - Rectangle2D bounds = union(shield.getBounds().getBounds2D(), icon.getBounds().getBounds2D()); - bounds = union(bounds, hp.getBounds().getBounds2D()); - - graphics.setColor(color); - graphics.draw(new Rectangle2D.Double(bounds.getX(), bounds.getY() - 2, bounds.getWidth(), bounds.getHeight() - 3)); - - FontMetrics fm = graphics.getFontMetrics(); - Rectangle2D textBounds = fm.getStringBounds(text, graphics); - int x = (int) (bounds.getX() + (bounds.getWidth() / 2) - (textBounds.getWidth() / 2)); - int y = (int) (bounds.getY() + bounds.getHeight() + textBounds.getHeight() + barBounds.getHeight()); - - graphics.setColor(Color.BLACK); - graphics.drawString(text, x + 1, y + 5); - graphics.setColor(color); - graphics.drawString(text, x, y + 4); - } - - private void renderProgressWidget(Graphics2D graphics) - { - String text; - int percentage; - - Widget bar = client.getWidget(WidgetInfo.PEST_CONTROL_ACTIVITY_BAR).getChild(0); - Rectangle2D bounds = bar.getBounds().getBounds2D(); - - Widget prgs = client.getWidget(WidgetInfo.PEST_CONTROL_ACTIVITY_PROGRESS).getChild(0); - - // At 0% the inner widget changes and your progress will not increase anymore - if ((int) (prgs.getBounds().getX()) - bounds.getX() != 2) - { - percentage = 0; - text = "FAILED"; - } - else - { - percentage = (int) ((prgs.getBounds().getWidth() / bounds.getWidth()) * 100); - text = String.valueOf(percentage) + "%"; - } - - Color color = Color.GREEN; - if (percentage < 25) - { - color = Color.RED; - } - - FontMetrics fm = graphics.getFontMetrics(); - Rectangle2D textBounds = fm.getStringBounds(text, graphics); - int x = (int) (bounds.getX() - textBounds.getWidth() - 4); - int y = (int) (bounds.getY() + fm.getHeight() - 2); - - graphics.setColor(Color.BLACK); - graphics.drawString(text, x + 1, y + 1); - graphics.setColor(color); - graphics.drawString(text, x, y); - } - - private static Rectangle2D union(Rectangle2D src1, Rectangle2D src2) - { - double x1 = Math.min(src1.getMinX(), src2.getMinX()); - double y1 = Math.min(src1.getMinY(), src2.getMinY()); - double x2 = Math.max(src1.getMaxX(), src2.getMaxX()); - double y2 = Math.max(src1.getMaxY(), src2.getMaxY()); - - Rectangle2D result = new Rectangle2D.Double(); - result.setFrameFromDiagonal(x1, y1, x2, y2); - - return result; - } -} +/* + * Copyright (c) 2017, Kronos + * Copyright (c) 2017, Adam + * Copyright (c) 2019, Yani + * 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.pestcontrol; + +import java.awt.Color; +import java.awt.Dimension; +import java.awt.FontMetrics; +import java.awt.Graphics2D; +import java.awt.geom.Rectangle2D; +import javax.inject.Inject; +import lombok.extern.slf4j.Slf4j; +import net.runelite.api.Client; +import net.runelite.api.widgets.Widget; +import net.runelite.api.widgets.WidgetInfo; +import net.runelite.client.ui.overlay.Overlay; +import net.runelite.client.ui.overlay.OverlayLayer; +import net.runelite.client.ui.overlay.OverlayPosition; + +@Slf4j +public class WidgetOverlay extends Overlay +{ + private final Client client; + + private final PestControlPlugin plugin; + + @Inject + public WidgetOverlay(Client client, PestControlPlugin plugin) + { + this.plugin = plugin; + this.client = client; + + setPosition(OverlayPosition.DYNAMIC); + setLayer(OverlayLayer.ABOVE_SCENE); + } + + public Integer getPortalHitpoints(PortalColor color) + { + if (plugin.getGame() == null) + { + return null; + } + + WidgetInfo healthWidgetInfo = null; + + switch (color) + { + case RED: + { + healthWidgetInfo = WidgetPortal.RED.getHitpoints(); + break; + } + case BLUE: + { + healthWidgetInfo = WidgetPortal.BLUE.getHitpoints(); + break; + } + case PURPLE: + { + healthWidgetInfo = WidgetPortal.PURPLE.getHitpoints(); + break; + } + case YELLOW: + { + healthWidgetInfo = WidgetPortal.YELLOW.getHitpoints(); + break; + } + } + + if (healthWidgetInfo == null) + { + return null; + } + + Widget healthWidget = client.getWidget(healthWidgetInfo); + + if (healthWidget == null) + { + return null; + } + + return Integer.parseInt(healthWidget.getText().trim()); + } + + @Override + public Dimension render(Graphics2D graphics) + { + if (plugin.getGame() == null) + { + return null; + } + + for (Portal portal : plugin.getGame().getNextPortals()) + { + renderWidgetOverlay(graphics, portal, "NEXT", Color.ORANGE); + } + + for (Portal portal : plugin.getGame().getActivePortals()) + { + renderWidgetOverlay(graphics, portal, "ATT", Color.RED); + } + + renderProgressWidget(graphics); + + return null; + } + + private void renderWidgetOverlay(Graphics2D graphics, Portal portal, String text, Color color) + { + Widget shield = client.getWidget(portal.getWidget().getShield()); + Widget icon = client.getWidget(portal.getWidget().getIcon()); + Widget hp = client.getWidget(portal.getWidget().getHitpoints()); + + Widget bar = client.getWidget(WidgetInfo.PEST_CONTROL_ACTIVITY_BAR).getChild(0); + + Rectangle2D barBounds = bar.getBounds().getBounds2D(); + + // create one rectangle from two different widget bounds + Rectangle2D bounds = union(shield.getBounds().getBounds2D(), icon.getBounds().getBounds2D()); + bounds = union(bounds, hp.getBounds().getBounds2D()); + + graphics.setColor(color); + graphics.draw(new Rectangle2D.Double(bounds.getX(), bounds.getY() - 2, bounds.getWidth(), bounds.getHeight() - 3)); + + FontMetrics fm = graphics.getFontMetrics(); + Rectangle2D textBounds = fm.getStringBounds(text, graphics); + int x = (int) (bounds.getX() + (bounds.getWidth() / 2) - (textBounds.getWidth() / 2)); + int y = (int) (bounds.getY() + bounds.getHeight() + textBounds.getHeight() + barBounds.getHeight()); + + graphics.setColor(Color.BLACK); + graphics.drawString(text, x + 1, y + 5); + graphics.setColor(color); + graphics.drawString(text, x, y + 4); + } + + private void renderProgressWidget(Graphics2D graphics) + { + String text; + int percentage; + + Widget bar = client.getWidget(WidgetInfo.PEST_CONTROL_ACTIVITY_BAR).getChild(0); + Rectangle2D bounds = bar.getBounds().getBounds2D(); + + Widget prgs = client.getWidget(WidgetInfo.PEST_CONTROL_ACTIVITY_PROGRESS).getChild(0); + + // At 0% the inner widget changes and your progress will not increase anymore + if ((int) (prgs.getBounds().getX()) - bounds.getX() != 2) + { + percentage = 0; + text = "FAILED"; + } + else + { + percentage = (int) ((prgs.getBounds().getWidth() / bounds.getWidth()) * 100); + text = percentage + "%"; + } + + Color color = Color.GREEN; + if (percentage < 25) + { + color = Color.RED; + } + + FontMetrics fm = graphics.getFontMetrics(); + Rectangle2D textBounds = fm.getStringBounds(text, graphics); + int x = (int) (bounds.getX() - textBounds.getWidth() - 4); + int y = (int) (bounds.getY() + fm.getHeight() - 2); + + graphics.setColor(Color.BLACK); + graphics.drawString(text, x + 1, y + 1); + graphics.setColor(color); + graphics.drawString(text, x, y); + } + + private static Rectangle2D union(Rectangle2D src1, Rectangle2D src2) + { + double x1 = Math.min(src1.getMinX(), src2.getMinX()); + double y1 = Math.min(src1.getMinY(), src2.getMinY()); + double x2 = Math.max(src1.getMaxX(), src2.getMaxX()); + double y2 = Math.max(src1.getMaxY(), src2.getMaxY()); + + Rectangle2D result = new Rectangle2D.Double(); + result.setFrameFromDiagonal(x1, y1, x2, y2); + + return result; + } +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/playerindicators/PlayerIndicatorsConfig.java b/runelite-client/src/main/java/net/runelite/client/plugins/playerindicators/PlayerIndicatorsConfig.java index 79bd8a7eb7..ffeccd7def 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/playerindicators/PlayerIndicatorsConfig.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/playerindicators/PlayerIndicatorsConfig.java @@ -25,7 +25,6 @@ package net.runelite.client.plugins.playerindicators; import java.awt.Color; - import net.runelite.api.ClanMemberRank; import net.runelite.client.config.Config; import net.runelite.client.config.ConfigGroup; @@ -201,11 +200,11 @@ public interface PlayerIndicatorsConfig extends Config } @ConfigItem( - position = 15, - keyName = "highlightTargets", - name = "Highlight attackable players in wilderness on the minimap", - description = "Highlights players on the minimap that the current player can attack based on combat/wilderness levels", - group = "Target Indicator" + position = 15, + keyName = "highlightTargets", + name = "Highlight attackable players in wilderness on the minimap", + description = "Highlights players on the minimap that the current player can attack based on combat/wilderness levels", + group = "Target Indicator" ) default boolean highlightTargets() { @@ -213,11 +212,11 @@ public interface PlayerIndicatorsConfig extends Config } @ConfigItem( - position = 16, - keyName = "highlightOverheadTargets", - name = "Highlights attackable players over their head", - description = "Highlights players over their head that the current player can attack based on combat/wilderness levels", - group = "Target Indicator" + position = 16, + keyName = "highlightOverheadTargets", + name = "Highlights attackable players over their head", + description = "Highlights players over their head that the current player can attack based on combat/wilderness levels", + group = "Target Indicator" ) default boolean highlightOverheadTargets() { @@ -225,11 +224,11 @@ public interface PlayerIndicatorsConfig extends Config } @ConfigItem( - position = 17, - keyName = "targetColor", - name = "Target color", - description = "Color of attackable targets", - group = "Target Indicator" + position = 17, + keyName = "targetColor", + name = "Target color", + description = "Color of attackable targets", + group = "Target Indicator" ) default Color getTargetColor() { @@ -237,11 +236,11 @@ public interface PlayerIndicatorsConfig extends Config } @ConfigItem( - position = 18, - keyName = "showCombat", - name = "Show Combat Levels", - description = "Show the combat level of attackable players next to their name.", - group = "Target Indicator" + position = 18, + keyName = "showCombat", + name = "Show Combat Levels", + description = "Show the combat level of attackable players next to their name.", + group = "Target Indicator" ) default boolean showCombatLevel() { @@ -249,11 +248,11 @@ public interface PlayerIndicatorsConfig extends Config } @ConfigItem( - position = 19, - keyName = "playerSkull", - name = "Show Skull Information", - description = "Indicate of the player is skulled.", - group = "Target Indicator" + position = 19, + keyName = "playerSkull", + name = "Show Skull Information", + description = "Indicate of the player is skulled.", + group = "Target Indicator" ) default boolean playerSkull() { @@ -273,11 +272,11 @@ public interface PlayerIndicatorsConfig extends Config } @ConfigItem( - position = 19, - keyName = "skulledTargetsOnly", - name = "Tag Skulls Only", - description = "Only indicate skulled targets (which are also attackable)", - group = "Target Indicator" + position = 19, + keyName = "skulledTargetsOnly", + name = "Tag Skulls Only", + description = "Only indicate skulled targets (which are also attackable)", + group = "Target Indicator" ) default boolean skulledTargetsOnly() { @@ -285,11 +284,11 @@ public interface PlayerIndicatorsConfig extends Config } @ConfigItem( - position = 19, - keyName = "targetRisk", - name = "Indicate Target Risk", - description = "Indicates the risk (in K GP) of the target", - group = "Target Indicator" + position = 19, + keyName = "targetRisk", + name = "Indicate Target Risk", + description = "Indicates the risk (in K GP) of the target", + group = "Target Indicator" ) default boolean targetRisk() { @@ -308,11 +307,11 @@ public interface PlayerIndicatorsConfig extends Config }*/ @ConfigItem( - keyName = "useClanchatRanks", - name = "Use Ranks as Callers", - description = "Uses clanchat ranks as the list of callers", - group = "Callers", - position = 24 + keyName = "useClanchatRanks", + name = "Use Ranks as Callers", + description = "Uses clanchat ranks as the list of callers", + group = "Callers", + position = 24 ) default boolean useClanchatRanks() { @@ -320,11 +319,11 @@ public interface PlayerIndicatorsConfig extends Config } @ConfigItem( - keyName = "callerRank", - name = "Minimum rank for Clan Caller", - description = "Chooses the minimum rank to use as clanchat callers.", - group = "Callers", - position = 25 + keyName = "callerRank", + name = "Minimum rank for Clan Caller", + description = "Chooses the minimum rank to use as clanchat callers.", + group = "Callers", + position = 25 ) default ClanMemberRank callerRank() { @@ -332,54 +331,58 @@ public interface PlayerIndicatorsConfig extends Config } @ConfigItem( - keyName = "callers", - name = "List of callers to highlight", - description = "Highlights callers, only highlights one at a time. Separate each entry with a comma and enter" + - " in the order you want them highlighted.", - group = "Callers" + keyName = "callers", + name = "List of callers to highlight", + description = "Highlights callers, only highlights one at a time. Separate each entry with a comma and enter" + + " in the order you want them highlighted.", + group = "Callers" ) default String callers() { return " "; } + @ConfigItem( - keyName = "highlightCallers", - name = "Highlight Callers", - description = "Highlights Callers Onscreen", - group = "Callers" + keyName = "highlightCallers", + name = "Highlight Callers", + description = "Highlights Callers Onscreen", + group = "Callers" ) default boolean highlightCallers() { return true; } + @ConfigItem( - position = 26, - keyName = "callerColor", - name = "Caller Color", - description = "Color of Indicated Callers", - group = "Callers" + position = 26, + keyName = "callerColor", + name = "Caller Color", + description = "Color of Indicated Callers", + group = "Callers" ) default Color callerColor() { return Color.WHITE; } + @ConfigItem( - position = 27, - keyName = "highlightPile", - name = "Highlight Pile", - description = "Highlights Pile Onscreen", - group = "Callers" + position = 27, + keyName = "highlightPile", + name = "Highlight Pile", + description = "Highlights Pile Onscreen", + group = "Callers" ) default boolean highlightPile() { return false; } + @ConfigItem( - position = 29, - keyName = "drawPileHull", - name = "Draws the hull of the pile.", - description = "Draws the hull of the pile for best visibility.", - group = "Callers" + position = 29, + keyName = "drawPileHull", + name = "Draws the hull of the pile.", + description = "Draws the hull of the pile for best visibility.", + group = "Callers" ) default boolean drawPileHull() { @@ -387,29 +390,30 @@ public interface PlayerIndicatorsConfig extends Config } @Range( - min = 1, - max = 10 + min = 1, + max = 10 ) @ConfigItem( - position = 30, - keyName = "pileColor", - name = "Pile Color", - description = "Color of Indicated Pile", - group = "Callers" + position = 30, + keyName = "pileColor", + name = "Pile Color", + description = "Color of Indicated Pile", + group = "Callers" ) default Color pileColor() { return Color.WHITE; } + @ConfigItem( - position = 27, - keyName = "unchargedGlory", - name = "Uncharged Glory Indication", - description = "Indicates if players have an uncharged glory" + position = 27, + keyName = "unchargedGlory", + name = "Uncharged Glory Indication", + description = "Indicates if players have an uncharged glory" ) default boolean unchargedGlory() { return false; } - + } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/playerindicators/PlayerIndicatorsOverlay.java b/runelite-client/src/main/java/net/runelite/client/plugins/playerindicators/PlayerIndicatorsOverlay.java index 97ba662798..6f2aff1484 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/playerindicators/PlayerIndicatorsOverlay.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/playerindicators/PlayerIndicatorsOverlay.java @@ -70,7 +70,7 @@ public class PlayerIndicatorsOverlay extends Overlay @Inject private PlayerIndicatorsOverlay(PlayerIndicatorsConfig config, PlayerIndicatorsService playerIndicatorsService, - ClanManager clanManager) + ClanManager clanManager) { this.config = config; this.playerIndicatorsService = playerIndicatorsService; diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/playerindicators/PlayerIndicatorsPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/playerindicators/PlayerIndicatorsPlugin.java index 2c38b7fc3d..e1c62de125 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/playerindicators/PlayerIndicatorsPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/playerindicators/PlayerIndicatorsPlugin.java @@ -36,7 +36,19 @@ import net.runelite.api.ClanMember; import net.runelite.api.ClanMemberRank; import static net.runelite.api.ClanMemberRank.UNRANKED; import net.runelite.api.Client; -import static net.runelite.api.MenuAction.*; +import static net.runelite.api.MenuAction.FOLLOW; +import static net.runelite.api.MenuAction.ITEM_USE_ON_PLAYER; +import static net.runelite.api.MenuAction.PLAYER_EIGTH_OPTION; +import static net.runelite.api.MenuAction.PLAYER_FIFTH_OPTION; +import static net.runelite.api.MenuAction.PLAYER_FIRST_OPTION; +import static net.runelite.api.MenuAction.PLAYER_FOURTH_OPTION; +import static net.runelite.api.MenuAction.PLAYER_SECOND_OPTION; +import static net.runelite.api.MenuAction.PLAYER_SEVENTH_OPTION; +import static net.runelite.api.MenuAction.PLAYER_SIXTH_OPTION; +import static net.runelite.api.MenuAction.PLAYER_THIRD_OPTION; +import static net.runelite.api.MenuAction.RUNELITE; +import static net.runelite.api.MenuAction.SPELL_CAST_ON_PLAYER; +import static net.runelite.api.MenuAction.TRADE; import net.runelite.api.MenuEntry; import net.runelite.api.Player; import net.runelite.api.events.ClanMemberJoined; @@ -54,39 +66,39 @@ import net.runelite.client.util.ColorUtil; import net.runelite.client.util.PvPUtil; @PluginDescriptor( - name = "Player Indicators", - description = "Highlight players on-screen and/or on the minimap", - tags = {"highlight", "minimap", "overlay", "players", "pklite"} + name = "Player Indicators", + description = "Highlight players on-screen and/or on the minimap", + tags = {"highlight", "minimap", "overlay", "players", "pklite"} ) public class PlayerIndicatorsPlugin extends Plugin { @Inject private OverlayManager overlayManager; - + @Inject private PlayerIndicatorsConfig config; - + @Inject private PlayerIndicatorsOverlay playerIndicatorsOverlay; - + @Inject private PlayerIndicatorsTileOverlay playerIndicatorsTileOverlay; - + @Inject private PlayerIndicatorsMinimapOverlay playerIndicatorsMinimapOverlay; - + @Inject private Client client; - + @Inject private ClanManager clanManager; - + @Provides PlayerIndicatorsConfig provideConfig(ConfigManager configManager) { return configManager.getConfig(PlayerIndicatorsConfig.class); } - + @Override protected void startUp() throws Exception { @@ -95,7 +107,7 @@ public class PlayerIndicatorsPlugin extends Plugin overlayManager.add(playerIndicatorsMinimapOverlay); getCallerList(); } - + @Override protected void shutDown() throws Exception { @@ -103,10 +115,10 @@ public class PlayerIndicatorsPlugin extends Plugin overlayManager.remove(playerIndicatorsTileOverlay); overlayManager.remove(playerIndicatorsMinimapOverlay); } - - private ArrayList callers = new ArrayList<>(); + + private ArrayList callers = new ArrayList<>(); private List pileList; - + @Subscribe public void onConfigChanged(ConfigChanged e) { @@ -115,7 +127,7 @@ public class PlayerIndicatorsPlugin extends Plugin getCallerList(); } } - + @Subscribe public void onGameTick(GameTick gameTick) { @@ -123,7 +135,7 @@ public class PlayerIndicatorsPlugin extends Plugin { for (Player p : client.getPlayers()) { - for (String name:callers) + for (String name : callers) { Actor pile; String finalName = name.toLowerCase().replace("_", " "); @@ -144,19 +156,19 @@ public class PlayerIndicatorsPlugin extends Plugin } } } - + @Subscribe public void onClanMemberJoined(ClanMemberJoined event) { getCallerList(); } - + @Subscribe public void onClanMemberLeft(ClanMemberLeft event) { getCallerList(); } - + private void getCallerList() { callers.clear(); @@ -183,12 +195,12 @@ public class PlayerIndicatorsPlugin extends Plugin } pileList = Arrays.asList(new String[callers.size()]); } - + boolean isCaller(Player player) { if (callers != null) { - for (String name:callers) + for (String name : callers) { String finalName = name.toLowerCase().replace("_", " "); if (player.getName().toLowerCase().replace("_", " ").equals(finalName)) @@ -200,7 +212,7 @@ public class PlayerIndicatorsPlugin extends Plugin return false; } - + boolean isPile(Player player) { if (Objects.nonNull(pileList) && pileList.size() > 0) @@ -209,48 +221,48 @@ public class PlayerIndicatorsPlugin extends Plugin } return false; } - + @Subscribe public void onMenuEntryAdded(MenuEntryAdded menuEntryAdded) { int type = menuEntryAdded.getType(); - + if (type >= 2000) { type -= 2000; } - + int identifier = menuEntryAdded.getIdentifier(); if (type == FOLLOW.getId() || type == TRADE.getId() - || type == SPELL_CAST_ON_PLAYER.getId() || type == ITEM_USE_ON_PLAYER.getId() - || type == PLAYER_FIRST_OPTION.getId() - || type == PLAYER_SECOND_OPTION.getId() - || type == PLAYER_THIRD_OPTION.getId() - || type == PLAYER_FOURTH_OPTION.getId() - || type == PLAYER_FIFTH_OPTION.getId() - || type == PLAYER_SIXTH_OPTION.getId() - || type == PLAYER_SEVENTH_OPTION.getId() - || type == PLAYER_EIGTH_OPTION.getId() - || type == RUNELITE.getId()) + || type == SPELL_CAST_ON_PLAYER.getId() || type == ITEM_USE_ON_PLAYER.getId() + || type == PLAYER_FIRST_OPTION.getId() + || type == PLAYER_SECOND_OPTION.getId() + || type == PLAYER_THIRD_OPTION.getId() + || type == PLAYER_FOURTH_OPTION.getId() + || type == PLAYER_FIFTH_OPTION.getId() + || type == PLAYER_SIXTH_OPTION.getId() + || type == PLAYER_SEVENTH_OPTION.getId() + || type == PLAYER_EIGTH_OPTION.getId() + || type == RUNELITE.getId()) { final Player localPlayer = client.getLocalPlayer(); Player[] players = client.getCachedPlayers(); Player player = null; - + if (identifier >= 0 && identifier < players.length) { player = players[identifier]; } - + if (player == null) { return; } - + int image = -1; int image2 = -1; Color color = null; - + if (config.colorPlayerMenu() && client.isFriended(player.getName(), false)) { color = config.getFriendColor(); @@ -258,7 +270,7 @@ public class PlayerIndicatorsPlugin extends Plugin else if (config.colorPlayerMenu() && player.isClanMember()) { color = config.getClanMemberColor(); - + ClanMemberRank rank = clanManager.getRank(player.getName()); if (rank != UNRANKED) { @@ -266,21 +278,21 @@ public class PlayerIndicatorsPlugin extends Plugin } } else if (config.colorPlayerMenu() && player.getTeam() > 0 && localPlayer.getTeam() == player.getTeam()) - { - color = config.getTeamMemberColor(); - } - else if (!player.isClanMember() && !player.isFriend() && !PvPUtil.isAttackable(client, player)) - { - color = config.getNonClanMemberColor(); - } - else if (config.colorPlayerMenu() && !player.isClanMember() && client.isFriended(player.getName(), false) && PvPUtil.isAttackable(client, player)) - { - color = config.getTargetColor(); - } - else if (config.colorPlayerMenu() && PvPUtil.isAttackable(client, player) && !player.isClanMember() && !player.isFriend()) - { - color = config.getTargetColor(); - } + { + color = config.getTeamMemberColor(); + } + else if (!player.isClanMember() && !player.isFriend() && !PvPUtil.isAttackable(client, player)) + { + color = config.getNonClanMemberColor(); + } + else if (config.colorPlayerMenu() && !player.isClanMember() && client.isFriended(player.getName(), false) && PvPUtil.isAttackable(client, player)) + { + color = config.getTargetColor(); + } + else if (config.colorPlayerMenu() && PvPUtil.isAttackable(client, player) && !player.isClanMember() && !player.isFriend()) + { + color = config.getTargetColor(); + } /* if (config.rightClickOverhead() && !player.isClanMember() && player.getOverheadIcon() != null) { if (player.getOverheadIcon().equals(HeadIcon.MAGIC)) @@ -324,8 +336,8 @@ public class PlayerIndicatorsPlugin extends Plugin { MenuEntry[] menuEntries = client.getMenuEntries(); MenuEntry lastEntry = menuEntries[menuEntries.length - 1]; - - + + if (color != null && config.colorPlayerMenu()) { // strip out existing " + lastEntry.getTarget()); } - + client.setMenuEntries(menuEntries); } } } - + public enum minimapSkullLocations { BEFORE_NAME, diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/playerindicators/PlayerIndicatorsTileOverlay.java b/runelite-client/src/main/java/net/runelite/client/plugins/playerindicators/PlayerIndicatorsTileOverlay.java index 98602e7a4c..bf69efda5f 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/playerindicators/PlayerIndicatorsTileOverlay.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/playerindicators/PlayerIndicatorsTileOverlay.java @@ -25,7 +25,11 @@ package net.runelite.client.plugins.playerindicators; -import java.awt.*; +import java.awt.BasicStroke; +import java.awt.Color; +import java.awt.Dimension; +import java.awt.Graphics2D; +import java.awt.Polygon; import javax.inject.Inject; import net.runelite.client.ui.overlay.Overlay; import net.runelite.client.ui.overlay.OverlayLayer; @@ -41,7 +45,7 @@ public class PlayerIndicatorsTileOverlay extends Overlay @Inject private PlayerIndicatorsTileOverlay(PlayerIndicatorsConfig config, - PlayerIndicatorsService playerIndicatorsService, PlayerIndicatorsPlugin plugin) + PlayerIndicatorsService playerIndicatorsService, PlayerIndicatorsPlugin plugin) { this.config = config; this.playerIndicatorsService = playerIndicatorsService; diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/playerinfo/PlayerInfoConfig.java b/runelite-client/src/main/java/net/runelite/client/plugins/playerinfo/PlayerInfoConfig.java index af6767f1b0..19c46301bf 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/playerinfo/PlayerInfoConfig.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/playerinfo/PlayerInfoConfig.java @@ -1,123 +1,122 @@ -/* - * Copyright (c) 2018, https://runelitepl.us - * 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.playerinfo; - -import net.runelite.client.config.Config; -import net.runelite.client.config.ConfigGroup; -import net.runelite.client.config.ConfigItem; - -import java.awt.*; - -@ConfigGroup("playerinfo") -public interface PlayerInfoConfig extends Config -{ - @ConfigItem( - keyName = "enableHealth", - name = "Enable Health Display", - description = "Configures whether or not to display health information", - position = 1 - ) - default boolean enableHealth() - { - return true; - } - - @ConfigItem( - keyName = "enablePrayer", - name = "Enable Prayer Display", - description = "Configures whether or not to display prayer information", - position = 2 - ) - default boolean enablePrayer() - { - return true; - } - - @ConfigItem( - keyName = "enableEnergy", - name = "Enable Run Energy Display", - description = "Configures whether or not to display run energy information", - position = 3 - ) - default boolean enableEnergy() - { - return true; - } - - @ConfigItem( - keyName = "enableSpec", - name = "Enable Special Attack Display", - description = "Configures whether or not to display special attack information", - position = 4 - ) - default boolean enableSpec() - { - return true; - } - - @ConfigItem( - keyName = "enableWorld", - name = "Enable World Display", - description = "Configures whether or not to display world information", - position = 4 - ) - default boolean enableWorld() - { - return true; - } - - @ConfigItem( - keyName = "colorHigh", - name = "Color High", - description = "The color displayed for high values.", - position = 5 - ) - default Color colorHigh() - { - return Color.GREEN; - } - - @ConfigItem( - keyName = "colorMed", - name = "Color Medium", - description = "The color displayed for medium values.", - position = 6 - ) - default Color colorMed() - { - return Color.YELLOW; - } - - @ConfigItem( - keyName = "colorLow", - name = "Color Low", - description = "The color displayed for low values.", - position = 7 - ) - default Color colorLow() - { - return Color.RED; - } -} +/* + * Copyright (c) 2018, https://runelitepl.us + * 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.playerinfo; + +import java.awt.Color; +import net.runelite.client.config.Config; +import net.runelite.client.config.ConfigGroup; +import net.runelite.client.config.ConfigItem; + +@ConfigGroup("playerinfo") +public interface PlayerInfoConfig extends Config +{ + @ConfigItem( + keyName = "enableHealth", + name = "Enable Health Display", + description = "Configures whether or not to display health information", + position = 1 + ) + default boolean enableHealth() + { + return true; + } + + @ConfigItem( + keyName = "enablePrayer", + name = "Enable Prayer Display", + description = "Configures whether or not to display prayer information", + position = 2 + ) + default boolean enablePrayer() + { + return true; + } + + @ConfigItem( + keyName = "enableEnergy", + name = "Enable Run Energy Display", + description = "Configures whether or not to display run energy information", + position = 3 + ) + default boolean enableEnergy() + { + return true; + } + + @ConfigItem( + keyName = "enableSpec", + name = "Enable Special Attack Display", + description = "Configures whether or not to display special attack information", + position = 4 + ) + default boolean enableSpec() + { + return true; + } + + @ConfigItem( + keyName = "enableWorld", + name = "Enable World Display", + description = "Configures whether or not to display world information", + position = 4 + ) + default boolean enableWorld() + { + return true; + } + + @ConfigItem( + keyName = "colorHigh", + name = "Color High", + description = "The color displayed for high values.", + position = 5 + ) + default Color colorHigh() + { + return Color.GREEN; + } + + @ConfigItem( + keyName = "colorMed", + name = "Color Medium", + description = "The color displayed for medium values.", + position = 6 + ) + default Color colorMed() + { + return Color.YELLOW; + } + + @ConfigItem( + keyName = "colorLow", + name = "Color Low", + description = "The color displayed for low values.", + position = 7 + ) + default Color colorLow() + { + return Color.RED; + } +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/playerinfo/PlayerInfoCustomIndicator.java b/runelite-client/src/main/java/net/runelite/client/plugins/playerinfo/PlayerInfoCustomIndicator.java index cadf30033b..b76a0b9b52 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/playerinfo/PlayerInfoCustomIndicator.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/playerinfo/PlayerInfoCustomIndicator.java @@ -1,140 +1,140 @@ -/* - * Copyright (c) 2018, https://runelitepl.us - * 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.playerinfo; - -import lombok.AllArgsConstructor; -import lombok.Getter; -import net.runelite.api.Client; -import net.runelite.api.Skill; -import net.runelite.api.VarPlayer; -import net.runelite.client.ui.overlay.infobox.InfoBox; -import net.runelite.client.util.ColorUtil; - -import java.awt.*; - -public class PlayerInfoCustomIndicator extends InfoBox -{ - @AllArgsConstructor - @Getter - enum IndicatorType - { - HEALTH("Current Hitpoints"), - PRAYER("Current Prayer Points"), - ENERGY("Current Run Energy"), - SPECIAL("Current Special Attack"), - WORLD("Current World"); - - private final String description; - } - - private final PlayerInfoConfig config; - private final Client client; - private final IndicatorType type; - - PlayerInfoCustomIndicator(Image image, PlayerInfoPlugin plugin, PlayerInfoConfig config, Client client, IndicatorType type) - { - super(image, plugin); - this.config = config; - this.client = client; - this.type = type; - - setTooltip(type.getDescription()); - } - - @Override - public String getText() - { - switch (type) - { - case HEALTH: - return String.valueOf(client.getBoostedSkillLevel(Skill.HITPOINTS)); - case PRAYER: - return String.valueOf(client.getBoostedSkillLevel(Skill.PRAYER)); - case ENERGY: - return String.valueOf(client.getEnergy()); - case SPECIAL: - return String.valueOf(client.getVar(VarPlayer.SPECIAL_ATTACK_PERCENT) / 10); - case WORLD: - return String.valueOf(client.getWorld()); - } - - return null; - } - - @Override - public Color getTextColor() - { - float currLvl = 0; - switch (type) - { - case HEALTH: - currLvl = client.getBoostedSkillLevel(Skill.HITPOINTS) / (float) client.getRealSkillLevel(Skill.HITPOINTS); - break; - case PRAYER: - currLvl = client.getBoostedSkillLevel(Skill.PRAYER) / (float) client.getRealSkillLevel(Skill.PRAYER); - break; - case ENERGY: - currLvl = client.getEnergy() / 100.0F; - break; - case SPECIAL: - currLvl = client.getVar(VarPlayer.SPECIAL_ATTACK_PERCENT) / 1000.0F; - case WORLD: - currLvl = 1000; // hacky - } - - if (currLvl > 1.0) - { - return config.colorHigh(); - } - else if (currLvl > 0.5) - { - return ColorUtil.colorLerp(config.colorMed(), config.colorHigh(), (currLvl * 2) - 1.0F); - } - else - { - return ColorUtil.colorLerp(config.colorLow(), config.colorMed(), (currLvl * 2)); - } - } - - @Override - public boolean render() - { - switch (type) - { - case HEALTH: - return config.enableHealth(); - case PRAYER: - return config.enablePrayer(); - case ENERGY: - return config.enableEnergy(); - case SPECIAL: - return config.enableSpec(); - case WORLD: - return config.enableWorld(); - } - - return false; - } -} +/* + * Copyright (c) 2018, https://runelitepl.us + * 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.playerinfo; + +import java.awt.Color; +import java.awt.Image; +import lombok.AllArgsConstructor; +import lombok.Getter; +import net.runelite.api.Client; +import net.runelite.api.Skill; +import net.runelite.api.VarPlayer; +import net.runelite.client.ui.overlay.infobox.InfoBox; +import net.runelite.client.util.ColorUtil; + +public class PlayerInfoCustomIndicator extends InfoBox +{ + @AllArgsConstructor + @Getter + enum IndicatorType + { + HEALTH("Current Hitpoints"), + PRAYER("Current Prayer Points"), + ENERGY("Current Run Energy"), + SPECIAL("Current Special Attack"), + WORLD("Current World"); + + private final String description; + } + + private final PlayerInfoConfig config; + private final Client client; + private final IndicatorType type; + + PlayerInfoCustomIndicator(Image image, PlayerInfoPlugin plugin, PlayerInfoConfig config, Client client, IndicatorType type) + { + super(image, plugin); + this.config = config; + this.client = client; + this.type = type; + + setTooltip(type.getDescription()); + } + + @Override + public String getText() + { + switch (type) + { + case HEALTH: + return String.valueOf(client.getBoostedSkillLevel(Skill.HITPOINTS)); + case PRAYER: + return String.valueOf(client.getBoostedSkillLevel(Skill.PRAYER)); + case ENERGY: + return String.valueOf(client.getEnergy()); + case SPECIAL: + return String.valueOf(client.getVar(VarPlayer.SPECIAL_ATTACK_PERCENT) / 10); + case WORLD: + return String.valueOf(client.getWorld()); + } + + return null; + } + + @Override + public Color getTextColor() + { + float currLvl = 0; + switch (type) + { + case HEALTH: + currLvl = client.getBoostedSkillLevel(Skill.HITPOINTS) / (float) client.getRealSkillLevel(Skill.HITPOINTS); + break; + case PRAYER: + currLvl = client.getBoostedSkillLevel(Skill.PRAYER) / (float) client.getRealSkillLevel(Skill.PRAYER); + break; + case ENERGY: + currLvl = client.getEnergy() / 100.0F; + break; + case SPECIAL: + currLvl = client.getVar(VarPlayer.SPECIAL_ATTACK_PERCENT) / 1000.0F; + case WORLD: + currLvl = 1000; // hacky + } + + if (currLvl > 1.0) + { + return config.colorHigh(); + } + else if (currLvl > 0.5) + { + return ColorUtil.colorLerp(config.colorMed(), config.colorHigh(), (currLvl * 2) - 1.0F); + } + else + { + return ColorUtil.colorLerp(config.colorLow(), config.colorMed(), (currLvl * 2)); + } + } + + @Override + public boolean render() + { + switch (type) + { + case HEALTH: + return config.enableHealth(); + case PRAYER: + return config.enablePrayer(); + case ENERGY: + return config.enableEnergy(); + case SPECIAL: + return config.enableSpec(); + case WORLD: + return config.enableWorld(); + } + + return false; + } +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/playerinfo/PlayerInfoPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/playerinfo/PlayerInfoPlugin.java index 6ab9e47f82..4cef00950f 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/playerinfo/PlayerInfoPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/playerinfo/PlayerInfoPlugin.java @@ -1,110 +1,109 @@ -/* - * Copyright (c) 2018, https://runelitepl.us - * 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.playerinfo; - -import com.google.inject.Provides; -import net.runelite.api.*; -import net.runelite.client.callback.ClientThread; -import net.runelite.client.config.ConfigManager; -import net.runelite.client.game.SkillIconManager; -import net.runelite.client.game.SpriteManager; -import net.runelite.client.plugins.Plugin; -import net.runelite.client.plugins.PluginDescriptor; -import net.runelite.client.plugins.PluginType; -import net.runelite.client.ui.overlay.infobox.InfoBoxManager; - -import javax.inject.Inject; -import javax.inject.Singleton; - -import java.awt.image.BufferedImage; - -import static net.runelite.client.plugins.playerinfo.PlayerInfoCustomIndicator.*; - -@PluginDescriptor( - name = "Player Information", - description = "An alternative to the Minimap Orbs", - tags = {"combat", "overlay"}, - type = PluginType.UTILITY, - enabledByDefault = false -) -@Singleton -public class PlayerInfoPlugin extends Plugin -{ - @Inject - private Client client; - - @Inject - private ClientThread clientThread; - - @Inject - private InfoBoxManager infoBoxManager; - - @Inject - private PlayerInfoConfig config; - - @Inject - private SpriteManager spriteManager; - - @Inject - private SkillIconManager skillIconManager; - - @Provides - PlayerInfoConfig provideConfig(ConfigManager configManager) - { - return configManager.getConfig(PlayerInfoConfig.class); - } - - @Override - protected void startUp() throws Exception - { - clientThread.invoke(() -> - { - if (client.getGameState().ordinal() < GameState.LOGIN_SCREEN.ordinal()) - { - return false; - } - - BufferedImage healthImg = spriteManager.getSprite(SpriteID.MINIMAP_ORB_HITPOINTS_ICON, 0); - BufferedImage prayerImg = spriteManager.getSprite(SpriteID.MINIMAP_ORB_PRAYER_ICON, 0); - BufferedImage energyImg = spriteManager.getSprite(SpriteID.MINIMAP_ORB_RUN_ICON, 0); - BufferedImage combatImg = spriteManager.getSprite(SpriteID.MINIMAP_ORB_SPECIAL_ICON, 0); - BufferedImage worldImg = spriteManager.getSprite(SpriteID.MINIMAP_ORB_WORLD_MAP_PLANET, 0); - - infoBoxManager.addInfoBox(new PlayerInfoCustomIndicator(healthImg, this, config, client, IndicatorType.HEALTH)); - infoBoxManager.addInfoBox(new PlayerInfoCustomIndicator(prayerImg, this, config, client, IndicatorType.PRAYER)); - infoBoxManager.addInfoBox(new PlayerInfoCustomIndicator(energyImg, this, config, client, IndicatorType.ENERGY)); - infoBoxManager.addInfoBox(new PlayerInfoCustomIndicator(combatImg, this, config, client, IndicatorType.SPECIAL)); - infoBoxManager.addInfoBox(new PlayerInfoCustomIndicator(worldImg, this, config, client, IndicatorType.WORLD)); - - return true; - }); - } - - @Override - protected void shutDown() throws Exception - { - infoBoxManager.removeIf(i -> i instanceof PlayerInfoCustomIndicator); - } -} +/* + * Copyright (c) 2018, https://runelitepl.us + * 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.playerinfo; + +import com.google.inject.Provides; +import java.awt.image.BufferedImage; +import javax.inject.Inject; +import javax.inject.Singleton; +import net.runelite.api.Client; +import net.runelite.api.GameState; +import net.runelite.api.SpriteID; +import net.runelite.client.callback.ClientThread; +import net.runelite.client.config.ConfigManager; +import net.runelite.client.game.SkillIconManager; +import net.runelite.client.game.SpriteManager; +import net.runelite.client.plugins.Plugin; +import net.runelite.client.plugins.PluginDescriptor; +import net.runelite.client.plugins.PluginType; +import static net.runelite.client.plugins.playerinfo.PlayerInfoCustomIndicator.IndicatorType; +import net.runelite.client.ui.overlay.infobox.InfoBoxManager; + +@PluginDescriptor( + name = "Player Information", + description = "An alternative to the Minimap Orbs", + tags = {"combat", "overlay"}, + type = PluginType.UTILITY, + enabledByDefault = false +) +@Singleton +public class PlayerInfoPlugin extends Plugin +{ + @Inject + private Client client; + + @Inject + private ClientThread clientThread; + + @Inject + private InfoBoxManager infoBoxManager; + + @Inject + private PlayerInfoConfig config; + + @Inject + private SpriteManager spriteManager; + + @Inject + private SkillIconManager skillIconManager; + + @Provides + PlayerInfoConfig provideConfig(ConfigManager configManager) + { + return configManager.getConfig(PlayerInfoConfig.class); + } + + @Override + protected void startUp() throws Exception + { + clientThread.invoke(() -> + { + if (client.getGameState().ordinal() < GameState.LOGIN_SCREEN.ordinal()) + { + return false; + } + + BufferedImage healthImg = spriteManager.getSprite(SpriteID.MINIMAP_ORB_HITPOINTS_ICON, 0); + BufferedImage prayerImg = spriteManager.getSprite(SpriteID.MINIMAP_ORB_PRAYER_ICON, 0); + BufferedImage energyImg = spriteManager.getSprite(SpriteID.MINIMAP_ORB_RUN_ICON, 0); + BufferedImage combatImg = spriteManager.getSprite(SpriteID.MINIMAP_ORB_SPECIAL_ICON, 0); + BufferedImage worldImg = spriteManager.getSprite(SpriteID.MINIMAP_ORB_WORLD_MAP_PLANET, 0); + + infoBoxManager.addInfoBox(new PlayerInfoCustomIndicator(healthImg, this, config, client, IndicatorType.HEALTH)); + infoBoxManager.addInfoBox(new PlayerInfoCustomIndicator(prayerImg, this, config, client, IndicatorType.PRAYER)); + infoBoxManager.addInfoBox(new PlayerInfoCustomIndicator(energyImg, this, config, client, IndicatorType.ENERGY)); + infoBoxManager.addInfoBox(new PlayerInfoCustomIndicator(combatImg, this, config, client, IndicatorType.SPECIAL)); + infoBoxManager.addInfoBox(new PlayerInfoCustomIndicator(worldImg, this, config, client, IndicatorType.WORLD)); + + return true; + }); + } + + @Override + protected void shutDown() throws Exception + { + infoBoxManager.removeIf(i -> i instanceof PlayerInfoCustomIndicator); + } +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/poh/PohIcons.java b/runelite-client/src/main/java/net/runelite/client/plugins/poh/PohIcons.java index 656cf85716..db671698fa 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/poh/PohIcons.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/poh/PohIcons.java @@ -39,7 +39,164 @@ import static net.runelite.api.NullObjectID.NULL_13632; import static net.runelite.api.NullObjectID.NULL_13634; import static net.runelite.api.NullObjectID.NULL_29228; import static net.runelite.api.NullObjectID.NULL_29229; -import static net.runelite.api.ObjectID.*; +import static net.runelite.api.ObjectID.ALTAR_13179; +import static net.runelite.api.ObjectID.ALTAR_13180; +import static net.runelite.api.ObjectID.ALTAR_13181; +import static net.runelite.api.ObjectID.ALTAR_13182; +import static net.runelite.api.ObjectID.ALTAR_13183; +import static net.runelite.api.ObjectID.ALTAR_13184; +import static net.runelite.api.ObjectID.ALTAR_13185; +import static net.runelite.api.ObjectID.ALTAR_13186; +import static net.runelite.api.ObjectID.ALTAR_13187; +import static net.runelite.api.ObjectID.ALTAR_13188; +import static net.runelite.api.ObjectID.ALTAR_13189; +import static net.runelite.api.ObjectID.ALTAR_13190; +import static net.runelite.api.ObjectID.ALTAR_13191; +import static net.runelite.api.ObjectID.ALTAR_13192; +import static net.runelite.api.ObjectID.ALTAR_13193; +import static net.runelite.api.ObjectID.ALTAR_13194; +import static net.runelite.api.ObjectID.ALTAR_13196; +import static net.runelite.api.ObjectID.ALTAR_13197; +import static net.runelite.api.ObjectID.ALTAR_13198; +import static net.runelite.api.ObjectID.ALTAR_13199; +import static net.runelite.api.ObjectID.ALTAR_OF_THE_OCCULT; +import static net.runelite.api.ObjectID.AMULET_OF_GLORY; +import static net.runelite.api.ObjectID.ANCIENT_ALTAR; +import static net.runelite.api.ObjectID.ANNAKARL_PORTAL; +import static net.runelite.api.ObjectID.ANNAKARL_PORTAL_29349; +import static net.runelite.api.ObjectID.ANNAKARL_PORTAL_29357; +import static net.runelite.api.ObjectID.ARDOUGNE_PORTAL; +import static net.runelite.api.ObjectID.ARDOUGNE_PORTAL_13626; +import static net.runelite.api.ObjectID.ARDOUGNE_PORTAL_13633; +import static net.runelite.api.ObjectID.ARMOUR_REPAIR_STAND; +import static net.runelite.api.ObjectID.BASIC_JEWELLERY_BOX; +import static net.runelite.api.ObjectID.CARRALLANGAR_PORTAL; +import static net.runelite.api.ObjectID.CARRALLANGAR_PORTAL_33437; +import static net.runelite.api.ObjectID.CARRALLANGAR_PORTAL_33440; +import static net.runelite.api.ObjectID.CATHERBY_PORTAL; +import static net.runelite.api.ObjectID.CATHERBY_PORTAL_33435; +import static net.runelite.api.ObjectID.CATHERBY_PORTAL_33438; +import static net.runelite.api.ObjectID.DARK_ALTAR; +import static net.runelite.api.ObjectID.DIGSITE_PENDANT; +import static net.runelite.api.ObjectID.DIGSITE_PENDANT_33417; +import static net.runelite.api.ObjectID.DIGSITE_PENDANT_33418; +import static net.runelite.api.ObjectID.DIGSITE_PENDANT_33420; +import static net.runelite.api.ObjectID.FALADOR_PORTAL; +import static net.runelite.api.ObjectID.FALADOR_PORTAL_13624; +import static net.runelite.api.ObjectID.FALADOR_PORTAL_13631; +import static net.runelite.api.ObjectID.FANCY_JEWELLERY_BOX; +import static net.runelite.api.ObjectID.FANCY_REJUVENATION_POOL; +import static net.runelite.api.ObjectID.FISHING_GUILD_PORTAL; +import static net.runelite.api.ObjectID.FISHING_GUILD_PORTAL_29351; +import static net.runelite.api.ObjectID.FISHING_GUILD_PORTAL_29359; +import static net.runelite.api.ObjectID.GHORROCK_PORTAL; +import static net.runelite.api.ObjectID.GHORROCK_PORTAL_33436; +import static net.runelite.api.ObjectID.GHORROCK_PORTAL_33439; +import static net.runelite.api.ObjectID.KHARYRLL_PORTAL; +import static net.runelite.api.ObjectID.KHARYRLL_PORTAL_29346; +import static net.runelite.api.ObjectID.KHARYRLL_PORTAL_29354; +import static net.runelite.api.ObjectID.KOUREND_PORTAL; +import static net.runelite.api.ObjectID.KOUREND_PORTAL_29353; +import static net.runelite.api.ObjectID.KOUREND_PORTAL_29361; +import static net.runelite.api.ObjectID.LUMBRIDGE_PORTAL; +import static net.runelite.api.ObjectID.LUMBRIDGE_PORTAL_13623; +import static net.runelite.api.ObjectID.LUMBRIDGE_PORTAL_13630; +import static net.runelite.api.ObjectID.LUNAR_ALTAR; +import static net.runelite.api.ObjectID.LUNAR_ISLE_PORTAL; +import static net.runelite.api.ObjectID.LUNAR_ISLE_PORTAL_29347; +import static net.runelite.api.ObjectID.LUNAR_ISLE_PORTAL_29355; +import static net.runelite.api.ObjectID.MARIM_PORTAL; +import static net.runelite.api.ObjectID.MARIM_PORTAL_29352; +import static net.runelite.api.ObjectID.MARIM_PORTAL_29360; +import static net.runelite.api.ObjectID.OBELISK_31554; +import static net.runelite.api.ObjectID.ORNATE_JEWELLERY_BOX; +import static net.runelite.api.ObjectID.ORNATE_REJUVENATION_POOL; +import static net.runelite.api.ObjectID.POOL_OF_REJUVENATION; +import static net.runelite.api.ObjectID.POOL_OF_RESTORATION; +import static net.runelite.api.ObjectID.POOL_OF_REVITALISATION; +import static net.runelite.api.ObjectID.PORTAL_4525; +import static net.runelite.api.ObjectID.PORTAL_NEXUS; +import static net.runelite.api.ObjectID.PORTAL_NEXUS_33355; +import static net.runelite.api.ObjectID.PORTAL_NEXUS_33356; +import static net.runelite.api.ObjectID.PORTAL_NEXUS_33357; +import static net.runelite.api.ObjectID.PORTAL_NEXUS_33358; +import static net.runelite.api.ObjectID.PORTAL_NEXUS_33359; +import static net.runelite.api.ObjectID.PORTAL_NEXUS_33360; +import static net.runelite.api.ObjectID.PORTAL_NEXUS_33361; +import static net.runelite.api.ObjectID.PORTAL_NEXUS_33362; +import static net.runelite.api.ObjectID.PORTAL_NEXUS_33363; +import static net.runelite.api.ObjectID.PORTAL_NEXUS_33364; +import static net.runelite.api.ObjectID.PORTAL_NEXUS_33365; +import static net.runelite.api.ObjectID.PORTAL_NEXUS_33366; +import static net.runelite.api.ObjectID.PORTAL_NEXUS_33367; +import static net.runelite.api.ObjectID.PORTAL_NEXUS_33368; +import static net.runelite.api.ObjectID.PORTAL_NEXUS_33369; +import static net.runelite.api.ObjectID.PORTAL_NEXUS_33370; +import static net.runelite.api.ObjectID.PORTAL_NEXUS_33371; +import static net.runelite.api.ObjectID.PORTAL_NEXUS_33372; +import static net.runelite.api.ObjectID.PORTAL_NEXUS_33373; +import static net.runelite.api.ObjectID.PORTAL_NEXUS_33374; +import static net.runelite.api.ObjectID.PORTAL_NEXUS_33375; +import static net.runelite.api.ObjectID.PORTAL_NEXUS_33376; +import static net.runelite.api.ObjectID.PORTAL_NEXUS_33377; +import static net.runelite.api.ObjectID.PORTAL_NEXUS_33378; +import static net.runelite.api.ObjectID.PORTAL_NEXUS_33379; +import static net.runelite.api.ObjectID.PORTAL_NEXUS_33380; +import static net.runelite.api.ObjectID.PORTAL_NEXUS_33381; +import static net.runelite.api.ObjectID.PORTAL_NEXUS_33382; +import static net.runelite.api.ObjectID.PORTAL_NEXUS_33383; +import static net.runelite.api.ObjectID.PORTAL_NEXUS_33384; +import static net.runelite.api.ObjectID.PORTAL_NEXUS_33385; +import static net.runelite.api.ObjectID.PORTAL_NEXUS_33386; +import static net.runelite.api.ObjectID.PORTAL_NEXUS_33387; +import static net.runelite.api.ObjectID.PORTAL_NEXUS_33388; +import static net.runelite.api.ObjectID.PORTAL_NEXUS_33389; +import static net.runelite.api.ObjectID.PORTAL_NEXUS_33390; +import static net.runelite.api.ObjectID.PORTAL_NEXUS_33391; +import static net.runelite.api.ObjectID.PORTAL_NEXUS_33392; +import static net.runelite.api.ObjectID.PORTAL_NEXUS_33393; +import static net.runelite.api.ObjectID.PORTAL_NEXUS_33394; +import static net.runelite.api.ObjectID.PORTAL_NEXUS_33395; +import static net.runelite.api.ObjectID.PORTAL_NEXUS_33396; +import static net.runelite.api.ObjectID.PORTAL_NEXUS_33397; +import static net.runelite.api.ObjectID.PORTAL_NEXUS_33398; +import static net.runelite.api.ObjectID.PORTAL_NEXUS_33399; +import static net.runelite.api.ObjectID.PORTAL_NEXUS_33400; +import static net.runelite.api.ObjectID.PORTAL_NEXUS_33401; +import static net.runelite.api.ObjectID.PORTAL_NEXUS_33402; +import static net.runelite.api.ObjectID.PORTAL_NEXUS_33403; +import static net.runelite.api.ObjectID.PORTAL_NEXUS_33404; +import static net.runelite.api.ObjectID.PORTAL_NEXUS_33405; +import static net.runelite.api.ObjectID.PORTAL_NEXUS_33406; +import static net.runelite.api.ObjectID.PORTAL_NEXUS_33407; +import static net.runelite.api.ObjectID.PORTAL_NEXUS_33408; +import static net.runelite.api.ObjectID.PORTAL_NEXUS_33409; +import static net.runelite.api.ObjectID.PORTAL_NEXUS_33410; +import static net.runelite.api.ObjectID.PORTAL_NEXUS_33423; +import static net.runelite.api.ObjectID.PORTAL_NEXUS_33424; +import static net.runelite.api.ObjectID.PORTAL_NEXUS_33425; +import static net.runelite.api.ObjectID.PORTAL_NEXUS_33426; +import static net.runelite.api.ObjectID.PORTAL_NEXUS_33427; +import static net.runelite.api.ObjectID.PORTAL_NEXUS_33428; +import static net.runelite.api.ObjectID.PORTAL_NEXUS_33429; +import static net.runelite.api.ObjectID.PORTAL_NEXUS_33430; +import static net.runelite.api.ObjectID.PORTAL_NEXUS_33431; +import static net.runelite.api.ObjectID.SENNTISTEN_PORTAL; +import static net.runelite.api.ObjectID.SENNTISTEN_PORTAL_29348; +import static net.runelite.api.ObjectID.SENNTISTEN_PORTAL_29356; +import static net.runelite.api.ObjectID.SPIRIT_TREE_29227; +import static net.runelite.api.ObjectID.TROLL_STRONGHOLD_PORTAL; +import static net.runelite.api.ObjectID.TROLL_STRONGHOLD_PORTAL_33180; +import static net.runelite.api.ObjectID.TROLL_STRONGHOLD_PORTAL_33181; +import static net.runelite.api.ObjectID.WATERBIRTH_ISLAND_PORTAL; +import static net.runelite.api.ObjectID.WATERBIRTH_ISLAND_PORTAL_29350; +import static net.runelite.api.ObjectID.WATERBIRTH_ISLAND_PORTAL_29358; +import static net.runelite.api.ObjectID.XERICS_TALISMAN; +import static net.runelite.api.ObjectID.XERICS_TALISMAN_33412; +import static net.runelite.api.ObjectID.XERICS_TALISMAN_33413; +import static net.runelite.api.ObjectID.XERICS_TALISMAN_33414; +import static net.runelite.api.ObjectID.XERICS_TALISMAN_33415; +import static net.runelite.api.ObjectID.XERICS_TALISMAN_33419; import net.runelite.client.util.ImageUtil; public enum PohIcons @@ -85,7 +242,7 @@ public enum PohIcons PORTAL_NEXUS_33403, PORTAL_NEXUS_33404, PORTAL_NEXUS_33405, PORTAL_NEXUS_33406, PORTAL_NEXUS_33407, PORTAL_NEXUS_33408, PORTAL_NEXUS_33409, PORTAL_NEXUS_33410, PORTAL_NEXUS_33423, PORTAL_NEXUS_33424, PORTAL_NEXUS_33425, PORTAL_NEXUS_33426, PORTAL_NEXUS_33427, PORTAL_NEXUS_33428, PORTAL_NEXUS_33429, PORTAL_NEXUS_33430, PORTAL_NEXUS_33431 - ), + ), XERICSTALISMAN("xericstalisman", XERICS_TALISMAN, XERICS_TALISMAN_33412, XERICS_TALISMAN_33413, XERICS_TALISMAN_33414, XERICS_TALISMAN_33415, XERICS_TALISMAN_33419 ), diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/poh/PohOverlay.java b/runelite-client/src/main/java/net/runelite/client/plugins/poh/PohOverlay.java index 368e763f8f..f0c8a85289 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/poh/PohOverlay.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/poh/PohOverlay.java @@ -1,148 +1,148 @@ -/* - * Copyright (c) 2018, Seth - * 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.poh; - -import java.awt.Dimension; -import java.awt.Graphics2D; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import javax.inject.Inject; -import lombok.Getter; -import net.runelite.api.Client; -import net.runelite.api.Perspective; -import net.runelite.api.coords.LocalPoint; -import net.runelite.client.ui.overlay.Overlay; -import net.runelite.client.ui.overlay.OverlayLayer; -import net.runelite.client.ui.overlay.OverlayPosition; - -public class PohOverlay extends Overlay -{ - private static final PohIcons[] PORTALS = new PohIcons[] - { - PohIcons.LUMBRIDGE, PohIcons.FALADOR, PohIcons.VARROCK, PohIcons.CAMELOT, PohIcons.ARDOUGNE, - PohIcons.YANILLE, PohIcons.LUNARISLE, PohIcons.WATERBIRTH, PohIcons.FISHINGGUILD, - PohIcons.SENNTISTEN, PohIcons.KHARYLL, PohIcons.ANNAKARL, PohIcons.KOUREND, PohIcons.MARIM, PohIcons.TROLLSTRONGHOLD, PohIcons.CARRALLANGAR, PohIcons.CATHERBY, PohIcons.GHORROCK - - }; - - private static final int MAX_DISTANCE = 2350; - - @Getter - private final List iconList = new ArrayList<>(); - - private final Client client; - private final PohConfig config; - private final PohPlugin plugin; - - @Inject - public PohOverlay(Client client, PohConfig config, PohPlugin plugin) - { - setPosition(OverlayPosition.DYNAMIC); - setLayer(OverlayLayer.ABOVE_WIDGETS); - this.client = client; - this.config = config; - this.plugin = plugin; - } - - @Override - public Dimension render(Graphics2D graphics) - { - LocalPoint localLocation = client.getLocalPlayer().getLocalLocation(); - plugin.getPohObjects().forEach((object, tile) -> - { - LocalPoint location = object.getLocalLocation(); - if (tile.getPlane() == client.getPlane() && localLocation.distanceTo(location) <= MAX_DISTANCE) - { - PohIcons icon = PohIcons.getIcon(object.getId()); - - if (icon != null && iconList.contains(icon)) - { - net.runelite.api.Point minimapLoc = Perspective.getMiniMapImageLocation(client, object.getLocalLocation(), icon.getImage()); - - if (minimapLoc != null) - { - graphics.drawImage(icon.getImage(), minimapLoc.getX(), minimapLoc.getY(), null); - } - } - } - }); - - return null; - } - - public void updateConfig() - { - iconList.clear(); - if (config.showPortals()) - { - Collections.addAll(iconList, PORTALS); - } - if (config.showAltar()) - { - iconList.add(PohIcons.ALTAR); - } - if (config.showGlory()) - { - iconList.add(PohIcons.GLORY); - } - if (config.showRepairStand()) - { - iconList.add(PohIcons.REPAIR); - } - if (config.showPools()) - { - iconList.add(PohIcons.POOLS); - } - if (config.showExitPortal()) - { - iconList.add(PohIcons.EXITPORTAL); - } - if (config.showSpellbook()) - { - iconList.add(PohIcons.SPELLBOOKALTAR); - } - if (config.showJewelleryBox()) - { - iconList.add(PohIcons.JEWELLERYBOX); - } - if (config.showMagicTravel()) - { - iconList.add(PohIcons.MAGICTRAVEL); - } - if (config.showPortalNexus()) - { - iconList.add(PohIcons.PORTALNEXUS); - } - if (config.showDigsitePendant()) - { - iconList.add(PohIcons.DIGSITEPENDANT); - } - if (config.showXericsTalisman()) - { - iconList.add(PohIcons.XERICSTALISMAN); - } - } -} +/* + * Copyright (c) 2018, Seth + * 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.poh; + +import java.awt.Dimension; +import java.awt.Graphics2D; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import javax.inject.Inject; +import lombok.Getter; +import net.runelite.api.Client; +import net.runelite.api.Perspective; +import net.runelite.api.coords.LocalPoint; +import net.runelite.client.ui.overlay.Overlay; +import net.runelite.client.ui.overlay.OverlayLayer; +import net.runelite.client.ui.overlay.OverlayPosition; + +public class PohOverlay extends Overlay +{ + private static final PohIcons[] PORTALS = new PohIcons[] + { + PohIcons.LUMBRIDGE, PohIcons.FALADOR, PohIcons.VARROCK, PohIcons.CAMELOT, PohIcons.ARDOUGNE, + PohIcons.YANILLE, PohIcons.LUNARISLE, PohIcons.WATERBIRTH, PohIcons.FISHINGGUILD, + PohIcons.SENNTISTEN, PohIcons.KHARYLL, PohIcons.ANNAKARL, PohIcons.KOUREND, PohIcons.MARIM, PohIcons.TROLLSTRONGHOLD, PohIcons.CARRALLANGAR, PohIcons.CATHERBY, PohIcons.GHORROCK + + }; + + private static final int MAX_DISTANCE = 2350; + + @Getter + private final List iconList = new ArrayList<>(); + + private final Client client; + private final PohConfig config; + private final PohPlugin plugin; + + @Inject + public PohOverlay(Client client, PohConfig config, PohPlugin plugin) + { + setPosition(OverlayPosition.DYNAMIC); + setLayer(OverlayLayer.ABOVE_WIDGETS); + this.client = client; + this.config = config; + this.plugin = plugin; + } + + @Override + public Dimension render(Graphics2D graphics) + { + LocalPoint localLocation = client.getLocalPlayer().getLocalLocation(); + plugin.getPohObjects().forEach((object, tile) -> + { + LocalPoint location = object.getLocalLocation(); + if (tile.getPlane() == client.getPlane() && localLocation.distanceTo(location) <= MAX_DISTANCE) + { + PohIcons icon = PohIcons.getIcon(object.getId()); + + if (icon != null && iconList.contains(icon)) + { + net.runelite.api.Point minimapLoc = Perspective.getMiniMapImageLocation(client, object.getLocalLocation(), icon.getImage()); + + if (minimapLoc != null) + { + graphics.drawImage(icon.getImage(), minimapLoc.getX(), minimapLoc.getY(), null); + } + } + } + }); + + return null; + } + + public void updateConfig() + { + iconList.clear(); + if (config.showPortals()) + { + Collections.addAll(iconList, PORTALS); + } + if (config.showAltar()) + { + iconList.add(PohIcons.ALTAR); + } + if (config.showGlory()) + { + iconList.add(PohIcons.GLORY); + } + if (config.showRepairStand()) + { + iconList.add(PohIcons.REPAIR); + } + if (config.showPools()) + { + iconList.add(PohIcons.POOLS); + } + if (config.showExitPortal()) + { + iconList.add(PohIcons.EXITPORTAL); + } + if (config.showSpellbook()) + { + iconList.add(PohIcons.SPELLBOOKALTAR); + } + if (config.showJewelleryBox()) + { + iconList.add(PohIcons.JEWELLERYBOX); + } + if (config.showMagicTravel()) + { + iconList.add(PohIcons.MAGICTRAVEL); + } + if (config.showPortalNexus()) + { + iconList.add(PohIcons.PORTALNEXUS); + } + if (config.showDigsitePendant()) + { + iconList.add(PohIcons.DIGSITEPENDANT); + } + if (config.showXericsTalisman()) + { + iconList.add(PohIcons.XERICSTALISMAN); + } + } +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/poh/PohPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/poh/PohPlugin.java index 04df91d05c..be70c9689d 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/poh/PohPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/poh/PohPlugin.java @@ -80,7 +80,7 @@ public class PohPlugin extends Plugin private final Map pohObjects = new HashMap<>(); @Getter(AccessLevel.PACKAGE) - private final Map incenseBurners = new HashMap<>(); + private final Map incenseBurners = new HashMap<>(); @Inject private OverlayManager overlayManager; diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/poison/PoisonInfobox.java b/runelite-client/src/main/java/net/runelite/client/plugins/poison/PoisonInfobox.java index f8d7233ab1..2be70c1e13 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/poison/PoisonInfobox.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/poison/PoisonInfobox.java @@ -1,80 +1,80 @@ -/* - * Copyright (c) 2018 Hydrox6 - * 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.poison; - -import java.awt.Color; -import java.time.Duration; -import java.time.Instant; -import java.time.temporal.ChronoUnit; -import java.awt.image.BufferedImage; -import net.runelite.client.ui.overlay.infobox.Timer; - -class PoisonInfobox extends Timer -{ - private final PoisonPlugin plugin; - - PoisonInfobox(int duration, BufferedImage image, PoisonPlugin plugin) - { - super(duration, ChronoUnit.MILLIS, image, plugin); - this.plugin = plugin; - } - - @Override - public String getTooltip() - { - return plugin.createTooltip(); - } - - @Override - public Color getTextColor() - { - return Color.RED.brighter(); - } - - @Override - public String getText() - { - Duration timeLeft = Duration.between(Instant.now(), getEndTime()); - - if (!timeLeft.isNegative()) - { - return super.getText(); - } - return " "; - } - - @Override - public boolean render() - { - return true; - } - - @Override - public boolean cull() - { - return false; - } -} - +/* + * Copyright (c) 2018 Hydrox6 + * 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.poison; + +import java.awt.Color; +import java.awt.image.BufferedImage; +import java.time.Duration; +import java.time.Instant; +import java.time.temporal.ChronoUnit; +import net.runelite.client.ui.overlay.infobox.Timer; + +class PoisonInfobox extends Timer +{ + private final PoisonPlugin plugin; + + PoisonInfobox(int duration, BufferedImage image, PoisonPlugin plugin) + { + super(duration, ChronoUnit.MILLIS, image, plugin); + this.plugin = plugin; + } + + @Override + public String getTooltip() + { + return plugin.createTooltip(); + } + + @Override + public Color getTextColor() + { + return Color.RED.brighter(); + } + + @Override + public String getText() + { + Duration timeLeft = Duration.between(Instant.now(), getEndTime()); + + if (!timeLeft.isNegative()) + { + return super.getText(); + } + return " "; + } + + @Override + public boolean render() + { + return true; + } + + @Override + public boolean cull() + { + return false; + } +} + diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/poison/PoisonPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/poison/PoisonPlugin.java index 05fc574947..8ce309843c 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/poison/PoisonPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/poison/PoisonPlugin.java @@ -1,357 +1,357 @@ -/* - * Copyright (c) 2018 Hydrox6 - * Copyright (c) 2019, Lucas - * 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.poison; - -import com.google.inject.Provides; -import java.awt.Color; -import java.awt.FontMetrics; -import java.awt.Graphics; -import java.awt.image.BufferedImage; -import java.text.MessageFormat; -import java.time.Duration; -import java.time.Instant; -import java.time.temporal.ChronoUnit; -import javax.inject.Inject; -import lombok.Getter; -import net.runelite.api.Client; -import net.runelite.api.GameState; -import net.runelite.api.SpriteID; -import net.runelite.api.VarPlayer; -import net.runelite.api.events.ConfigChanged; -import net.runelite.api.events.VarbitChanged; -import net.runelite.client.callback.ClientThread; -import net.runelite.client.config.ConfigManager; -import net.runelite.client.eventbus.Subscribe; -import net.runelite.client.game.SpriteManager; -import net.runelite.client.plugins.Plugin; -import net.runelite.client.plugins.PluginDescriptor; -import net.runelite.client.ui.FontManager; -import net.runelite.client.ui.overlay.OverlayManager; -import net.runelite.client.ui.overlay.infobox.InfoBoxManager; -import net.runelite.client.util.ColorUtil; -import net.runelite.client.util.ImageUtil; - -@PluginDescriptor( - name = "Poison", - description = "Tracks current damage values for Poison and Venom", - tags = {"combat", "poison", "venom", "heart", "hp"} -) -public class PoisonPlugin extends Plugin -{ - private static final int POISON_TICK_MILLIS = 18000; - private static final int VENOM_THRESHOLD = 1000000; - private static final int VENOM_MAXIMUM_DAMAGE = 20; - - private static final BufferedImage HEART_DISEASE; - private static final BufferedImage HEART_POISON; - private static final BufferedImage HEART_VENOM; - - static - { - HEART_DISEASE = ImageUtil.resizeCanvas(ImageUtil.getResourceStreamFromClass(PoisonPlugin.class, "1067-DISEASE.png"), 26, 26); - HEART_POISON = ImageUtil.resizeCanvas(ImageUtil.getResourceStreamFromClass(PoisonPlugin.class, "1067-POISON.png"), 26, 26); - HEART_VENOM = ImageUtil.resizeCanvas(ImageUtil.getResourceStreamFromClass(PoisonPlugin.class, "1067-VENOM.png"), 26, 26); - } - - @Inject - private Client client; - - @Inject - private ClientThread clientThread; - - @Inject - private PoisonOverlay poisonOverlay; - - @Inject - private OverlayManager overlayManager; - - @Inject - private InfoBoxManager infoBoxManager; - - @Inject - private SpriteManager spriteManager; - - @Inject - private PoisonConfig config; - - @Getter - private int lastDamage; - private boolean envenomed; - private PoisonInfobox infobox; - private Instant nextPoisonTick; - private int lastValue = 0; - private int lastDiseaseValue = 0; - private BufferedImage heart; - private int nextTickCount; - - @Provides - PoisonConfig getConfig(ConfigManager configManager) - { - return configManager.getConfig(PoisonConfig.class); - } - - @Override - protected void startUp() throws Exception - { - overlayManager.add(poisonOverlay); - - if (client.getGameState() == GameState.LOGGED_IN) - { - clientThread.invoke(this::checkHealthIcon); - } - } - - @Override - protected void shutDown() throws Exception - { - overlayManager.remove(poisonOverlay); - - if (infobox != null) - { - infoBoxManager.removeInfoBox(infobox); - infobox = null; - } - - envenomed = false; - lastDamage = 0; - nextPoisonTick = null; - lastValue = 0; - lastDiseaseValue = 0; - - clientThread.invoke(this::resetHealthIcon); - } - - @Subscribe - public void onVarbitChanged(VarbitChanged event) - { - final int poisonValue = client.getVar(VarPlayer.POISON); - if (poisonValue != lastValue) - { - envenomed = poisonValue >= VENOM_THRESHOLD; - - if (nextTickCount - client.getTickCount() <= 30 || lastValue == 0) - { - nextPoisonTick = Instant.now().plus(Duration.of(POISON_TICK_MILLIS, ChronoUnit.MILLIS)); - nextTickCount = client.getTickCount() + 30; - } - - lastValue = poisonValue; - final int damage = nextDamage(poisonValue); - this.lastDamage = damage; - - if (config.showInfoboxes()) - { - if (infobox != null) - { - infoBoxManager.removeInfoBox(infobox); - infobox = null; - } - - if (damage > 0) - { - final BufferedImage image = getSplat(envenomed ? SpriteID.HITSPLAT_DARK_GREEN_VENOM : SpriteID.HITSPLAT_GREEN_POISON, damage); - - if (image != null) - { - int duration = 600 * (nextTickCount - client.getTickCount()); - infobox = new PoisonInfobox(duration, image, this); - infoBoxManager.addInfoBox(infobox); - } - } - } - checkHealthIcon(); - } - - final int diseaseValue = client.getVar(VarPlayer.DISEASE_VALUE); - if (diseaseValue != lastDiseaseValue) - { - lastDiseaseValue = diseaseValue; - checkHealthIcon(); - } - } - - @Subscribe - public void onConfigChanged(ConfigChanged event) - { - if (!event.getGroup().equals(PoisonConfig.GROUP)) - { - return; - } - - if (!config.showInfoboxes() && infobox != null) - { - infoBoxManager.removeInfoBox(infobox); - infobox = null; - } - - if (config.changeHealthIcon()) - { - clientThread.invoke(this::checkHealthIcon); - } - else - { - clientThread.invoke(this::resetHealthIcon); - } - } - - private static int nextDamage(int poisonValue) - { - int damage; - - if (poisonValue >= VENOM_THRESHOLD) - { - //Venom Damage starts at 6, and increments in twos; - //The VarPlayer increments in values of 1, however. - poisonValue -= VENOM_THRESHOLD - 3; - damage = poisonValue * 2; - //Venom Damage caps at 20, but the VarPlayer keeps increasing - if (damage > VENOM_MAXIMUM_DAMAGE) - { - damage = VENOM_MAXIMUM_DAMAGE; - } - } - else - { - damage = (int) Math.ceil(poisonValue / 5.0f); - } - - return damage; - } - - private BufferedImage getSplat(int id, int damage) - { - //Get a copy of the hitsplat to get a clean one each time - final BufferedImage rawSplat = spriteManager.getSprite(id, 0); - if (rawSplat == null) - { - return null; - } - - final BufferedImage splat = new BufferedImage( - rawSplat.getColorModel(), - rawSplat.copyData(null), - rawSplat.getColorModel().isAlphaPremultiplied(), - null); - - final Graphics g = splat.getGraphics(); - g.setFont(FontManager.getRunescapeSmallFont()); - - // Align the text in the centre of the hitsplat - final FontMetrics metrics = g.getFontMetrics(); - final String text = String.valueOf(damage); - final int x = (splat.getWidth() - metrics.stringWidth(text)) / 2; - final int y = (splat.getHeight() - metrics.getHeight()) / 2 + metrics.getAscent(); - - g.setColor(Color.BLACK); - g.drawString(String.valueOf(damage), x + 1, y + 1); - g.setColor(Color.WHITE); - g.drawString(String.valueOf(damage), x, y); - return splat; - } - - private static String getFormattedTime(Duration timeLeft) - { - if (timeLeft.isNegative()) - { - return "Now!"; - } - - int seconds = (int) (timeLeft.toMillis() / 1000L); - int minutes = seconds / 60; - int secs = seconds % 60; - - return String.format("%d:%02d", minutes, secs); - } - - String createTooltip() - { - Duration timeLeft; - if (nextPoisonTick.isBefore(Instant.now()) && !envenomed) - { - timeLeft = Duration.of(POISON_TICK_MILLIS * (lastValue - 1), ChronoUnit.MILLIS); - } - else - { - timeLeft = Duration.between(Instant.now(), nextPoisonTick).plusMillis(POISON_TICK_MILLIS * (lastValue - 1)); - } - - String line1 = MessageFormat.format("Next {0} damage: {1}
Time until damage: {2}", - envenomed ? "venom" : "poison", ColorUtil.wrapWithColorTag(String.valueOf(lastDamage), Color.RED), - getFormattedTime(Duration.between(Instant.now(), nextPoisonTick))); - String line2 = envenomed ? "" : MessageFormat.format("
Time until cure: {0}", getFormattedTime(timeLeft)); - - return line1 + line2; - } - - private void checkHealthIcon() - { - if (!config.changeHealthIcon()) - { - return; - } - - final BufferedImage newHeart; - final int poison = client.getVar(VarPlayer.IS_POISONED); - - if (poison >= VENOM_THRESHOLD) - { - newHeart = HEART_VENOM; - } - else if (poison > 0) - { - newHeart = HEART_POISON; - } - else if (client.getVar(VarPlayer.DISEASE_VALUE) > 0) - { - newHeart = HEART_DISEASE; - } - else - { - resetHealthIcon(); - return; - } - - // Only update sprites when the heart icon actually changes - if (newHeart != heart) - { - heart = newHeart; - client.getWidgetSpriteCache().reset(); - client.getSpriteOverrides().put(SpriteID.MINIMAP_ORB_HITPOINTS_ICON, ImageUtil.getImageSpritePixels(heart, client)); - } - } - - private void resetHealthIcon() - { - if (heart == null) - { - return; - } - - client.getWidgetSpriteCache().reset(); - client.getSpriteOverrides().remove(SpriteID.MINIMAP_ORB_HITPOINTS_ICON); - heart = null; - } +/* + * Copyright (c) 2018 Hydrox6 + * Copyright (c) 2019, Lucas + * 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.poison; + +import com.google.inject.Provides; +import java.awt.Color; +import java.awt.FontMetrics; +import java.awt.Graphics; +import java.awt.image.BufferedImage; +import java.text.MessageFormat; +import java.time.Duration; +import java.time.Instant; +import java.time.temporal.ChronoUnit; +import javax.inject.Inject; +import lombok.Getter; +import net.runelite.api.Client; +import net.runelite.api.GameState; +import net.runelite.api.SpriteID; +import net.runelite.api.VarPlayer; +import net.runelite.api.events.ConfigChanged; +import net.runelite.api.events.VarbitChanged; +import net.runelite.client.callback.ClientThread; +import net.runelite.client.config.ConfigManager; +import net.runelite.client.eventbus.Subscribe; +import net.runelite.client.game.SpriteManager; +import net.runelite.client.plugins.Plugin; +import net.runelite.client.plugins.PluginDescriptor; +import net.runelite.client.ui.FontManager; +import net.runelite.client.ui.overlay.OverlayManager; +import net.runelite.client.ui.overlay.infobox.InfoBoxManager; +import net.runelite.client.util.ColorUtil; +import net.runelite.client.util.ImageUtil; + +@PluginDescriptor( + name = "Poison", + description = "Tracks current damage values for Poison and Venom", + tags = {"combat", "poison", "venom", "heart", "hp"} +) +public class PoisonPlugin extends Plugin +{ + private static final int POISON_TICK_MILLIS = 18000; + private static final int VENOM_THRESHOLD = 1000000; + private static final int VENOM_MAXIMUM_DAMAGE = 20; + + private static final BufferedImage HEART_DISEASE; + private static final BufferedImage HEART_POISON; + private static final BufferedImage HEART_VENOM; + + static + { + HEART_DISEASE = ImageUtil.resizeCanvas(ImageUtil.getResourceStreamFromClass(PoisonPlugin.class, "1067-DISEASE.png"), 26, 26); + HEART_POISON = ImageUtil.resizeCanvas(ImageUtil.getResourceStreamFromClass(PoisonPlugin.class, "1067-POISON.png"), 26, 26); + HEART_VENOM = ImageUtil.resizeCanvas(ImageUtil.getResourceStreamFromClass(PoisonPlugin.class, "1067-VENOM.png"), 26, 26); + } + + @Inject + private Client client; + + @Inject + private ClientThread clientThread; + + @Inject + private PoisonOverlay poisonOverlay; + + @Inject + private OverlayManager overlayManager; + + @Inject + private InfoBoxManager infoBoxManager; + + @Inject + private SpriteManager spriteManager; + + @Inject + private PoisonConfig config; + + @Getter + private int lastDamage; + private boolean envenomed; + private PoisonInfobox infobox; + private Instant nextPoisonTick; + private int lastValue = 0; + private int lastDiseaseValue = 0; + private BufferedImage heart; + private int nextTickCount; + + @Provides + PoisonConfig getConfig(ConfigManager configManager) + { + return configManager.getConfig(PoisonConfig.class); + } + + @Override + protected void startUp() throws Exception + { + overlayManager.add(poisonOverlay); + + if (client.getGameState() == GameState.LOGGED_IN) + { + clientThread.invoke(this::checkHealthIcon); + } + } + + @Override + protected void shutDown() throws Exception + { + overlayManager.remove(poisonOverlay); + + if (infobox != null) + { + infoBoxManager.removeInfoBox(infobox); + infobox = null; + } + + envenomed = false; + lastDamage = 0; + nextPoisonTick = null; + lastValue = 0; + lastDiseaseValue = 0; + + clientThread.invoke(this::resetHealthIcon); + } + + @Subscribe + public void onVarbitChanged(VarbitChanged event) + { + final int poisonValue = client.getVar(VarPlayer.POISON); + if (poisonValue != lastValue) + { + envenomed = poisonValue >= VENOM_THRESHOLD; + + if (nextTickCount - client.getTickCount() <= 30 || lastValue == 0) + { + nextPoisonTick = Instant.now().plus(Duration.of(POISON_TICK_MILLIS, ChronoUnit.MILLIS)); + nextTickCount = client.getTickCount() + 30; + } + + lastValue = poisonValue; + final int damage = nextDamage(poisonValue); + this.lastDamage = damage; + + if (config.showInfoboxes()) + { + if (infobox != null) + { + infoBoxManager.removeInfoBox(infobox); + infobox = null; + } + + if (damage > 0) + { + final BufferedImage image = getSplat(envenomed ? SpriteID.HITSPLAT_DARK_GREEN_VENOM : SpriteID.HITSPLAT_GREEN_POISON, damage); + + if (image != null) + { + int duration = 600 * (nextTickCount - client.getTickCount()); + infobox = new PoisonInfobox(duration, image, this); + infoBoxManager.addInfoBox(infobox); + } + } + } + checkHealthIcon(); + } + + final int diseaseValue = client.getVar(VarPlayer.DISEASE_VALUE); + if (diseaseValue != lastDiseaseValue) + { + lastDiseaseValue = diseaseValue; + checkHealthIcon(); + } + } + + @Subscribe + public void onConfigChanged(ConfigChanged event) + { + if (!event.getGroup().equals(PoisonConfig.GROUP)) + { + return; + } + + if (!config.showInfoboxes() && infobox != null) + { + infoBoxManager.removeInfoBox(infobox); + infobox = null; + } + + if (config.changeHealthIcon()) + { + clientThread.invoke(this::checkHealthIcon); + } + else + { + clientThread.invoke(this::resetHealthIcon); + } + } + + private static int nextDamage(int poisonValue) + { + int damage; + + if (poisonValue >= VENOM_THRESHOLD) + { + //Venom Damage starts at 6, and increments in twos; + //The VarPlayer increments in values of 1, however. + poisonValue -= VENOM_THRESHOLD - 3; + damage = poisonValue * 2; + //Venom Damage caps at 20, but the VarPlayer keeps increasing + if (damage > VENOM_MAXIMUM_DAMAGE) + { + damage = VENOM_MAXIMUM_DAMAGE; + } + } + else + { + damage = (int) Math.ceil(poisonValue / 5.0f); + } + + return damage; + } + + private BufferedImage getSplat(int id, int damage) + { + //Get a copy of the hitsplat to get a clean one each time + final BufferedImage rawSplat = spriteManager.getSprite(id, 0); + if (rawSplat == null) + { + return null; + } + + final BufferedImage splat = new BufferedImage( + rawSplat.getColorModel(), + rawSplat.copyData(null), + rawSplat.getColorModel().isAlphaPremultiplied(), + null); + + final Graphics g = splat.getGraphics(); + g.setFont(FontManager.getRunescapeSmallFont()); + + // Align the text in the centre of the hitsplat + final FontMetrics metrics = g.getFontMetrics(); + final String text = String.valueOf(damage); + final int x = (splat.getWidth() - metrics.stringWidth(text)) / 2; + final int y = (splat.getHeight() - metrics.getHeight()) / 2 + metrics.getAscent(); + + g.setColor(Color.BLACK); + g.drawString(String.valueOf(damage), x + 1, y + 1); + g.setColor(Color.WHITE); + g.drawString(String.valueOf(damage), x, y); + return splat; + } + + private static String getFormattedTime(Duration timeLeft) + { + if (timeLeft.isNegative()) + { + return "Now!"; + } + + int seconds = (int) (timeLeft.toMillis() / 1000L); + int minutes = seconds / 60; + int secs = seconds % 60; + + return String.format("%d:%02d", minutes, secs); + } + + String createTooltip() + { + Duration timeLeft; + if (nextPoisonTick.isBefore(Instant.now()) && !envenomed) + { + timeLeft = Duration.of(POISON_TICK_MILLIS * (lastValue - 1), ChronoUnit.MILLIS); + } + else + { + timeLeft = Duration.between(Instant.now(), nextPoisonTick).plusMillis(POISON_TICK_MILLIS * (lastValue - 1)); + } + + String line1 = MessageFormat.format("Next {0} damage: {1}
Time until damage: {2}", + envenomed ? "venom" : "poison", ColorUtil.wrapWithColorTag(String.valueOf(lastDamage), Color.RED), + getFormattedTime(Duration.between(Instant.now(), nextPoisonTick))); + String line2 = envenomed ? "" : MessageFormat.format("
Time until cure: {0}", getFormattedTime(timeLeft)); + + return line1 + line2; + } + + private void checkHealthIcon() + { + if (!config.changeHealthIcon()) + { + return; + } + + final BufferedImage newHeart; + final int poison = client.getVar(VarPlayer.IS_POISONED); + + if (poison >= VENOM_THRESHOLD) + { + newHeart = HEART_VENOM; + } + else if (poison > 0) + { + newHeart = HEART_POISON; + } + else if (client.getVar(VarPlayer.DISEASE_VALUE) > 0) + { + newHeart = HEART_DISEASE; + } + else + { + resetHealthIcon(); + return; + } + + // Only update sprites when the heart icon actually changes + if (newHeart != heart) + { + heart = newHeart; + client.getWidgetSpriteCache().reset(); + client.getSpriteOverrides().put(SpriteID.MINIMAP_ORB_HITPOINTS_ICON, ImageUtil.getImageSpritePixels(heart, client)); + } + } + + private void resetHealthIcon() + { + if (heart == null) + { + return; + } + + client.getWidgetSpriteCache().reset(); + client.getSpriteOverrides().remove(SpriteID.MINIMAP_ORB_HITPOINTS_ICON); + heart = null; + } } \ No newline at end of file diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/prayagainstplayer/PrayAgainstPlayerPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/prayagainstplayer/PrayAgainstPlayerPlugin.java index 32c539a637..bc0598a4c9 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/prayagainstplayer/PrayAgainstPlayerPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/prayagainstplayer/PrayAgainstPlayerPlugin.java @@ -29,16 +29,13 @@ import java.awt.Color; import java.awt.Dimension; import java.awt.image.BufferedImage; import java.awt.image.ColorModel; -import java.awt.image.DataBufferByte; import java.awt.image.IndexColorModel; import java.awt.image.WritableRaster; import java.util.ArrayList; -import java.util.Arrays; import javax.inject.Inject; import net.runelite.api.AnimationID; import net.runelite.api.Client; import net.runelite.api.GameState; -import net.runelite.api.IndexedSprite; import net.runelite.api.Player; import net.runelite.api.SpriteID; import net.runelite.api.events.AnimationChanged; diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/prayagainstplayer/WeaponType.java b/runelite-client/src/main/java/net/runelite/client/plugins/prayagainstplayer/WeaponType.java index 1dc00c8311..358ba36726 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/prayagainstplayer/WeaponType.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/prayagainstplayer/WeaponType.java @@ -29,7 +29,8 @@ import net.runelite.api.ItemComposition; import net.runelite.api.Player; import net.runelite.api.kit.KitType; -enum WeaponType { +enum WeaponType +{ WEAPON_MELEE, WEAPON_RANGED, @@ -38,32 +39,46 @@ enum WeaponType { /** * im fully aware this could of been done better!!! + * * @param client * @param attacker * @return */ - public static WeaponType checkWeaponOnPlayer (Client client, Player attacker) { + public static WeaponType checkWeaponOnPlayer(Client client, Player attacker) + { int itemId = attacker.getPlayerComposition().getEquipmentId(KitType.WEAPON); ItemComposition itemComposition = client.getItemDefinition(itemId); String weaponNameGivenLowerCase = itemComposition.getName().toLowerCase(); - if (itemId == -1) return WEAPON_MELEE; - if (weaponNameGivenLowerCase == null || weaponNameGivenLowerCase.toLowerCase().contains("null")) return WEAPON_MELEE; + if (itemId == -1) + { + return WEAPON_MELEE; + } + if (weaponNameGivenLowerCase == null || weaponNameGivenLowerCase.toLowerCase().contains("null")) + { + return WEAPON_MELEE; + } - for (String meleeWeaponName : meleeWeaponNames) { - if (weaponNameGivenLowerCase.contains(meleeWeaponName) && !weaponNameGivenLowerCase.contains("thrownaxe")) { + for (String meleeWeaponName : meleeWeaponNames) + { + if (weaponNameGivenLowerCase.contains(meleeWeaponName) && !weaponNameGivenLowerCase.contains("thrownaxe")) + { return WEAPON_MELEE; } } - for (String rangedWeaponName : rangedWeaponNames) { - if (weaponNameGivenLowerCase.contains(rangedWeaponName)) { + for (String rangedWeaponName : rangedWeaponNames) + { + if (weaponNameGivenLowerCase.contains(rangedWeaponName)) + { return WEAPON_RANGED; } } - for (String magicWeaponName : magicWeaponNames) { - if (weaponNameGivenLowerCase.contains(magicWeaponName)) { + for (String magicWeaponName : magicWeaponNames) + { + if (weaponNameGivenLowerCase.contains(magicWeaponName)) + { return WEAPON_MAGIC; } } @@ -73,35 +88,35 @@ enum WeaponType { } private static String[] meleeWeaponNames = { - "sword", - "scimitar", - "dagger", - "spear", - "mace", - "axe", - "whip", - "tentacle", - "-ket-", - "-xil-", - "warhammer", - "halberd", - "claws", - "hasta", - "scythe", - "maul", - "anchor", - "sabre", - "excalibur", - "machete", - "dragon hunter lance", - "event rpg", - "silverlight", - "darklight", - "arclight", - "flail", - "granite hammer", - "rapier", - "bulwark" + "sword", + "scimitar", + "dagger", + "spear", + "mace", + "axe", + "whip", + "tentacle", + "-ket-", + "-xil-", + "warhammer", + "halberd", + "claws", + "hasta", + "scythe", + "maul", + "anchor", + "sabre", + "excalibur", + "machete", + "dragon hunter lance", + "event rpg", + "silverlight", + "darklight", + "arclight", + "flail", + "granite hammer", + "rapier", + "bulwark" }; private static String[] rangedWeaponNames = { diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/prayer/PrayerDoseOverlay.java b/runelite-client/src/main/java/net/runelite/client/plugins/prayer/PrayerDoseOverlay.java index ab1d91fb16..c9b590a4d2 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/prayer/PrayerDoseOverlay.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/prayer/PrayerDoseOverlay.java @@ -199,6 +199,6 @@ class PrayerDoseOverlay extends Overlay final int seconds = (int) Math.floor(secondsLeft - (minutes * 60.0)); // Return the text - return Integer.toString(minutes) + ":" + StringUtils.leftPad(Integer.toString(seconds), 2, "0"); + return minutes + ":" + StringUtils.leftPad(Integer.toString(seconds), 2, "0"); } } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/profiles/ProfilesPanel.java b/runelite-client/src/main/java/net/runelite/client/plugins/profiles/ProfilesPanel.java index 46864425c3..5ec398a7bf 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/profiles/ProfilesPanel.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/profiles/ProfilesPanel.java @@ -439,7 +439,7 @@ class ProfilesPanel extends PluginPanel private void addAccounts(String data) { - // log.info("Data: " + data); + // log.info("Data: " + data); data = data.trim(); if (!data.contains(":")) { diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/puzzlesolver/PuzzleSolverOverlay.java b/runelite-client/src/main/java/net/runelite/client/plugins/puzzlesolver/PuzzleSolverOverlay.java index 67c821d841..9788e1e445 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/puzzlesolver/PuzzleSolverOverlay.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/puzzlesolver/PuzzleSolverOverlay.java @@ -1,478 +1,478 @@ -/* - * Copyright (c) 2018, Lotto - * Copyright (c) 2018, Henke - * 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.puzzlesolver; - -import java.awt.Color; -import java.awt.Dimension; -import java.awt.FontMetrics; -import java.awt.Graphics2D; -import java.awt.Point; -import java.awt.Rectangle; -import java.awt.image.BufferedImage; -import java.util.Arrays; -import java.util.concurrent.Future; -import java.util.concurrent.ScheduledExecutorService; -import javax.inject.Inject; -import net.runelite.api.Client; -import net.runelite.api.GameState; -import net.runelite.api.InventoryID; -import net.runelite.api.Item; -import net.runelite.api.ItemContainer; -import static net.runelite.api.SpriteID.MINIMAP_DESTINATION_FLAG; -import static net.runelite.client.plugins.puzzlesolver.solver.PuzzleSolver.BLANK_TILE_VALUE; -import static net.runelite.client.plugins.puzzlesolver.solver.PuzzleSolver.DIMENSION; -import net.runelite.api.widgets.Widget; -import net.runelite.api.widgets.WidgetInfo; -import net.runelite.client.game.SpriteManager; -import net.runelite.client.plugins.puzzlesolver.solver.PuzzleSolver; -import net.runelite.client.plugins.puzzlesolver.solver.PuzzleState; -import net.runelite.client.plugins.puzzlesolver.solver.heuristics.ManhattanDistance; -import net.runelite.client.plugins.puzzlesolver.solver.pathfinding.IDAStar; -import net.runelite.client.plugins.puzzlesolver.solver.pathfinding.IDAStarMM; -import net.runelite.client.ui.overlay.Overlay; -import net.runelite.client.ui.overlay.OverlayLayer; -import net.runelite.client.ui.overlay.OverlayPosition; -import net.runelite.client.ui.overlay.OverlayPriority; -import net.runelite.client.ui.overlay.OverlayUtil; -import net.runelite.client.ui.overlay.components.BackgroundComponent; -import net.runelite.client.ui.overlay.components.TextComponent; -import net.runelite.client.util.ImageUtil; - -public class PuzzleSolverOverlay extends Overlay -{ - private static final int INFO_BOX_WIDTH = 100; - private static final int INFO_BOX_OFFSET_Y = 50; - private static final int INFO_BOX_TOP_BORDER = 2; - private static final int INFO_BOX_BOTTOM_BORDER = 2; - - private static final int PUZZLE_TILE_SIZE = 39; - private static final int DOT_MARKER_SIZE = 16; - - private final Client client; - private final PuzzleSolverConfig config; - private final ScheduledExecutorService executorService; - private final SpriteManager spriteManager; - - private PuzzleSolver solver; - private Future solverFuture; - private int[] cachedItems; - - private BufferedImage upArrow; - private BufferedImage leftArrow; - private BufferedImage rightArrow; - - @Inject - public PuzzleSolverOverlay(Client client, PuzzleSolverConfig config, ScheduledExecutorService executorService, SpriteManager spriteManager) - { - setPosition(OverlayPosition.DYNAMIC); - setPriority(OverlayPriority.HIGH); - setLayer(OverlayLayer.ABOVE_WIDGETS); - this.client = client; - this.config = config; - this.executorService = executorService; - this.spriteManager = spriteManager; - } - - @Override - public Dimension render(Graphics2D graphics) - { - if ((!config.displaySolution() && !config.displayRemainingMoves()) - || client.getGameState() != GameState.LOGGED_IN) - { - return null; - } - - boolean useNormalSolver = true; - ItemContainer container = client.getItemContainer(InventoryID.PUZZLE_BOX); - - if (container == null) - { - useNormalSolver = false; - container = client.getItemContainer(InventoryID.MONKEY_MADNESS_PUZZLE_BOX); - - if (container == null) - { - return null; - } - } - - Widget puzzleBox = client.getWidget(WidgetInfo.PUZZLE_BOX); - - if (puzzleBox == null) - { - return null; - } - - net.runelite.api.Point puzzleBoxLocation = puzzleBox.getCanvasLocation(); - - String infoString = "Solving.."; - - int[] itemIds = getItemIds(container, useNormalSolver); - boolean shouldCache = false; - - if (solver != null) - { - if (solver.hasFailed()) - { - infoString = "The puzzle could not be solved"; - } - else - { - if (solver.hasSolution()) - { - boolean foundPosition = false; - - // Find the current state by looking at the current step and then the next 5 steps - for (int i = 0; i < 6; i++) - { - int j = solver.getPosition() + i; - - if (j == solver.getStepCount()) - { - break; - } - - PuzzleState currentState = solver.getStep(j); - - // If this is false, player has moved the empty tile - if (currentState != null && currentState.hasPieces(itemIds)) - { - foundPosition = true; - solver.setPosition(j); - if (i > 0) - { - shouldCache = true; - } - break; - } - } - - // If looking at the next steps didn't find the current state, - // see if we can find the current state in the 5 previous steps - if (!foundPosition) - { - for (int i = 1; i < 6; i++) - { - int j = solver.getPosition() - i; - - if (j < 0) - { - break; - } - - PuzzleState currentState = solver.getStep(j); - - if (currentState != null && currentState.hasPieces(itemIds)) - { - foundPosition = true; - shouldCache = true; - solver.setPosition(j); - break; - } - } - } - - if (foundPosition) - { - int stepsLeft = solver.getStepCount() - solver.getPosition() - 1; - - if (stepsLeft == 0) - { - infoString = "Solved!"; - } - else if (config.displayRemainingMoves()) - { - infoString = "Moves left: " + stepsLeft; - } - else - { - infoString = null; - } - - if (config.displaySolution()) - { - if (config.drawDots()) - { - graphics.setColor(Color.YELLOW); - - // Display the next 4 steps - for (int i = 1; i < 5; i++) - { - int j = solver.getPosition() + i; - - if (j >= solver.getStepCount()) - { - break; - } - - PuzzleState futureMove = solver.getStep(j); - - if (futureMove == null) - { - break; - } - - int blankX = futureMove.getEmptyPiece() % DIMENSION; - int blankY = futureMove.getEmptyPiece() / DIMENSION; - - int markerSize = DOT_MARKER_SIZE - i * 3; - - int x = puzzleBoxLocation.getX() + blankX * PUZZLE_TILE_SIZE - + PUZZLE_TILE_SIZE / 2 - markerSize / 2; - - int y = puzzleBoxLocation.getY() + blankY * PUZZLE_TILE_SIZE - + PUZZLE_TILE_SIZE / 2 - markerSize / 2; - - graphics.fillOval(x, y, markerSize, markerSize); - } - } - else - { - // Find the current blank tile position - PuzzleState currentMove = solver.getStep(solver.getPosition()); - - int lastBlankX = currentMove.getEmptyPiece() % DIMENSION; - int lastBlankY = currentMove.getEmptyPiece() / DIMENSION; - - // Display the next 3 steps - for (int i = 1; i < 4; i++) - { - int j = solver.getPosition() + i; - - if (j >= solver.getStepCount()) - { - break; - } - - PuzzleState futureMove = solver.getStep(j); - - if (futureMove == null) - { - break; - } - - int blankX = futureMove.getEmptyPiece() % DIMENSION; - int blankY = futureMove.getEmptyPiece() / DIMENSION; - - int xDelta = blankX - lastBlankX; - int yDelta = blankY - lastBlankY; - - BufferedImage arrow; - if (xDelta > 0) - { - arrow = getRightArrow(); - } - else if (xDelta < 0) - { - arrow = getLeftArrow(); - } - else if (yDelta > 0) - { - arrow = getDownArrow(); - } - else - { - arrow = getUpArrow(); - } - - int x = puzzleBoxLocation.getX() + blankX * PUZZLE_TILE_SIZE - + PUZZLE_TILE_SIZE / 2 - arrow.getWidth() / 2; - - int y = puzzleBoxLocation.getY() + blankY * PUZZLE_TILE_SIZE - + PUZZLE_TILE_SIZE / 2 - arrow.getHeight() / 2; - - OverlayUtil.renderImageLocation(graphics, new net.runelite.api.Point(x, y), arrow); - - lastBlankX = blankX; - lastBlankY = blankY; - } - } - } - } - } - } - } - - // Draw info box - if (infoString != null) - { - int x = puzzleBoxLocation.getX() + puzzleBox.getWidth() / 2 - INFO_BOX_WIDTH / 2; - int y = puzzleBoxLocation.getY() - INFO_BOX_OFFSET_Y; - - FontMetrics fm = graphics.getFontMetrics(); - int height = INFO_BOX_TOP_BORDER + fm.getHeight() + INFO_BOX_BOTTOM_BORDER; - - BackgroundComponent backgroundComponent = new BackgroundComponent(); - backgroundComponent.setRectangle(new Rectangle(x, y, INFO_BOX_WIDTH, height)); - backgroundComponent.render(graphics); - - int textOffsetX = (INFO_BOX_WIDTH - fm.stringWidth(infoString)) / 2; - int textOffsetY = fm.getHeight(); - - TextComponent textComponent = new TextComponent(); - textComponent.setPosition(new Point(x + textOffsetX, y + textOffsetY)); - textComponent.setText(infoString); - textComponent.render(graphics); - } - - // Solve the puzzle if we don't have an up to date solution - if (solver == null || cachedItems == null - || (!shouldCache && solver.hasExceededWaitDuration() && !Arrays.equals(cachedItems, itemIds))) - { - solve(itemIds, useNormalSolver); - shouldCache = true; - } - - if (shouldCache) - { - cacheItems(itemIds); - } - - return null; - } - - private int[] getItemIds(ItemContainer container, boolean useNormalSolver) - { - int[] itemIds = new int[DIMENSION * DIMENSION]; - - Item[] items = container.getItems(); - - for (int i = 0; i < items.length; i++) - { - itemIds[i] = items[i].getId(); - } - - // If blank is in the last position, items doesn't contain it, so let's add it manually - if (itemIds.length > items.length) - { - itemIds[items.length] = BLANK_TILE_VALUE; - } - - return convertToSolverFormat(itemIds, useNormalSolver); - } - - private int[] convertToSolverFormat(int[] items, boolean useNormalSolver) - { - int lowestId = Integer.MAX_VALUE; - - int[] convertedItems = new int[items.length]; - - for (int id : items) - { - if (id == BLANK_TILE_VALUE) - { - continue; - } - - if (lowestId > id) - { - lowestId = id; - } - } - - for (int i = 0; i < items.length; i++) - { - if (items[i] != BLANK_TILE_VALUE) - { - int value = items[i] - lowestId; - - // The MM puzzle has gaps - if (!useNormalSolver) - { - value /= 2; - } - - convertedItems[i] = value; - } - else - { - convertedItems[i] = BLANK_TILE_VALUE; - } - } - - return convertedItems; - } - - private void cacheItems(int[] items) - { - cachedItems = new int[items.length]; - System.arraycopy(items, 0, cachedItems, 0, cachedItems.length); - } - - private void solve(int[] items, boolean useNormalSolver) - { - if (solverFuture != null) - { - solverFuture.cancel(true); - } - - PuzzleState puzzleState = new PuzzleState(items); - - if (useNormalSolver) - { - solver = new PuzzleSolver(new IDAStar(new ManhattanDistance()), puzzleState); - } - else - { - solver = new PuzzleSolver(new IDAStarMM(new ManhattanDistance()), puzzleState); - } - - solverFuture = executorService.submit(solver); - } - - private BufferedImage getDownArrow() - { - return spriteManager.getSprite(MINIMAP_DESTINATION_FLAG, 1); - } - - private BufferedImage getUpArrow() - { - if (upArrow == null) - { - upArrow = ImageUtil.rotateImage(getDownArrow(), Math.PI); - } - return upArrow; - } - - private BufferedImage getLeftArrow() - { - if (leftArrow == null) - { - leftArrow = ImageUtil.rotateImage(getDownArrow(), Math.PI / 2); - } - return leftArrow; - } - - private BufferedImage getRightArrow() - { - if (rightArrow == null) - { - rightArrow = ImageUtil.rotateImage(getDownArrow(), 3 * Math.PI / 2); - } - return rightArrow; - } -} +/* + * Copyright (c) 2018, Lotto + * Copyright (c) 2018, Henke + * 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.puzzlesolver; + +import java.awt.Color; +import java.awt.Dimension; +import java.awt.FontMetrics; +import java.awt.Graphics2D; +import java.awt.Point; +import java.awt.Rectangle; +import java.awt.image.BufferedImage; +import java.util.Arrays; +import java.util.concurrent.Future; +import java.util.concurrent.ScheduledExecutorService; +import javax.inject.Inject; +import net.runelite.api.Client; +import net.runelite.api.GameState; +import net.runelite.api.InventoryID; +import net.runelite.api.Item; +import net.runelite.api.ItemContainer; +import static net.runelite.api.SpriteID.MINIMAP_DESTINATION_FLAG; +import net.runelite.api.widgets.Widget; +import net.runelite.api.widgets.WidgetInfo; +import net.runelite.client.game.SpriteManager; +import net.runelite.client.plugins.puzzlesolver.solver.PuzzleSolver; +import static net.runelite.client.plugins.puzzlesolver.solver.PuzzleSolver.BLANK_TILE_VALUE; +import static net.runelite.client.plugins.puzzlesolver.solver.PuzzleSolver.DIMENSION; +import net.runelite.client.plugins.puzzlesolver.solver.PuzzleState; +import net.runelite.client.plugins.puzzlesolver.solver.heuristics.ManhattanDistance; +import net.runelite.client.plugins.puzzlesolver.solver.pathfinding.IDAStar; +import net.runelite.client.plugins.puzzlesolver.solver.pathfinding.IDAStarMM; +import net.runelite.client.ui.overlay.Overlay; +import net.runelite.client.ui.overlay.OverlayLayer; +import net.runelite.client.ui.overlay.OverlayPosition; +import net.runelite.client.ui.overlay.OverlayPriority; +import net.runelite.client.ui.overlay.OverlayUtil; +import net.runelite.client.ui.overlay.components.BackgroundComponent; +import net.runelite.client.ui.overlay.components.TextComponent; +import net.runelite.client.util.ImageUtil; + +public class PuzzleSolverOverlay extends Overlay +{ + private static final int INFO_BOX_WIDTH = 100; + private static final int INFO_BOX_OFFSET_Y = 50; + private static final int INFO_BOX_TOP_BORDER = 2; + private static final int INFO_BOX_BOTTOM_BORDER = 2; + + private static final int PUZZLE_TILE_SIZE = 39; + private static final int DOT_MARKER_SIZE = 16; + + private final Client client; + private final PuzzleSolverConfig config; + private final ScheduledExecutorService executorService; + private final SpriteManager spriteManager; + + private PuzzleSolver solver; + private Future solverFuture; + private int[] cachedItems; + + private BufferedImage upArrow; + private BufferedImage leftArrow; + private BufferedImage rightArrow; + + @Inject + public PuzzleSolverOverlay(Client client, PuzzleSolverConfig config, ScheduledExecutorService executorService, SpriteManager spriteManager) + { + setPosition(OverlayPosition.DYNAMIC); + setPriority(OverlayPriority.HIGH); + setLayer(OverlayLayer.ABOVE_WIDGETS); + this.client = client; + this.config = config; + this.executorService = executorService; + this.spriteManager = spriteManager; + } + + @Override + public Dimension render(Graphics2D graphics) + { + if ((!config.displaySolution() && !config.displayRemainingMoves()) + || client.getGameState() != GameState.LOGGED_IN) + { + return null; + } + + boolean useNormalSolver = true; + ItemContainer container = client.getItemContainer(InventoryID.PUZZLE_BOX); + + if (container == null) + { + useNormalSolver = false; + container = client.getItemContainer(InventoryID.MONKEY_MADNESS_PUZZLE_BOX); + + if (container == null) + { + return null; + } + } + + Widget puzzleBox = client.getWidget(WidgetInfo.PUZZLE_BOX); + + if (puzzleBox == null) + { + return null; + } + + net.runelite.api.Point puzzleBoxLocation = puzzleBox.getCanvasLocation(); + + String infoString = "Solving.."; + + int[] itemIds = getItemIds(container, useNormalSolver); + boolean shouldCache = false; + + if (solver != null) + { + if (solver.hasFailed()) + { + infoString = "The puzzle could not be solved"; + } + else + { + if (solver.hasSolution()) + { + boolean foundPosition = false; + + // Find the current state by looking at the current step and then the next 5 steps + for (int i = 0; i < 6; i++) + { + int j = solver.getPosition() + i; + + if (j == solver.getStepCount()) + { + break; + } + + PuzzleState currentState = solver.getStep(j); + + // If this is false, player has moved the empty tile + if (currentState != null && currentState.hasPieces(itemIds)) + { + foundPosition = true; + solver.setPosition(j); + if (i > 0) + { + shouldCache = true; + } + break; + } + } + + // If looking at the next steps didn't find the current state, + // see if we can find the current state in the 5 previous steps + if (!foundPosition) + { + for (int i = 1; i < 6; i++) + { + int j = solver.getPosition() - i; + + if (j < 0) + { + break; + } + + PuzzleState currentState = solver.getStep(j); + + if (currentState != null && currentState.hasPieces(itemIds)) + { + foundPosition = true; + shouldCache = true; + solver.setPosition(j); + break; + } + } + } + + if (foundPosition) + { + int stepsLeft = solver.getStepCount() - solver.getPosition() - 1; + + if (stepsLeft == 0) + { + infoString = "Solved!"; + } + else if (config.displayRemainingMoves()) + { + infoString = "Moves left: " + stepsLeft; + } + else + { + infoString = null; + } + + if (config.displaySolution()) + { + if (config.drawDots()) + { + graphics.setColor(Color.YELLOW); + + // Display the next 4 steps + for (int i = 1; i < 5; i++) + { + int j = solver.getPosition() + i; + + if (j >= solver.getStepCount()) + { + break; + } + + PuzzleState futureMove = solver.getStep(j); + + if (futureMove == null) + { + break; + } + + int blankX = futureMove.getEmptyPiece() % DIMENSION; + int blankY = futureMove.getEmptyPiece() / DIMENSION; + + int markerSize = DOT_MARKER_SIZE - i * 3; + + int x = puzzleBoxLocation.getX() + blankX * PUZZLE_TILE_SIZE + + PUZZLE_TILE_SIZE / 2 - markerSize / 2; + + int y = puzzleBoxLocation.getY() + blankY * PUZZLE_TILE_SIZE + + PUZZLE_TILE_SIZE / 2 - markerSize / 2; + + graphics.fillOval(x, y, markerSize, markerSize); + } + } + else + { + // Find the current blank tile position + PuzzleState currentMove = solver.getStep(solver.getPosition()); + + int lastBlankX = currentMove.getEmptyPiece() % DIMENSION; + int lastBlankY = currentMove.getEmptyPiece() / DIMENSION; + + // Display the next 3 steps + for (int i = 1; i < 4; i++) + { + int j = solver.getPosition() + i; + + if (j >= solver.getStepCount()) + { + break; + } + + PuzzleState futureMove = solver.getStep(j); + + if (futureMove == null) + { + break; + } + + int blankX = futureMove.getEmptyPiece() % DIMENSION; + int blankY = futureMove.getEmptyPiece() / DIMENSION; + + int xDelta = blankX - lastBlankX; + int yDelta = blankY - lastBlankY; + + BufferedImage arrow; + if (xDelta > 0) + { + arrow = getRightArrow(); + } + else if (xDelta < 0) + { + arrow = getLeftArrow(); + } + else if (yDelta > 0) + { + arrow = getDownArrow(); + } + else + { + arrow = getUpArrow(); + } + + int x = puzzleBoxLocation.getX() + blankX * PUZZLE_TILE_SIZE + + PUZZLE_TILE_SIZE / 2 - arrow.getWidth() / 2; + + int y = puzzleBoxLocation.getY() + blankY * PUZZLE_TILE_SIZE + + PUZZLE_TILE_SIZE / 2 - arrow.getHeight() / 2; + + OverlayUtil.renderImageLocation(graphics, new net.runelite.api.Point(x, y), arrow); + + lastBlankX = blankX; + lastBlankY = blankY; + } + } + } + } + } + } + } + + // Draw info box + if (infoString != null) + { + int x = puzzleBoxLocation.getX() + puzzleBox.getWidth() / 2 - INFO_BOX_WIDTH / 2; + int y = puzzleBoxLocation.getY() - INFO_BOX_OFFSET_Y; + + FontMetrics fm = graphics.getFontMetrics(); + int height = INFO_BOX_TOP_BORDER + fm.getHeight() + INFO_BOX_BOTTOM_BORDER; + + BackgroundComponent backgroundComponent = new BackgroundComponent(); + backgroundComponent.setRectangle(new Rectangle(x, y, INFO_BOX_WIDTH, height)); + backgroundComponent.render(graphics); + + int textOffsetX = (INFO_BOX_WIDTH - fm.stringWidth(infoString)) / 2; + int textOffsetY = fm.getHeight(); + + TextComponent textComponent = new TextComponent(); + textComponent.setPosition(new Point(x + textOffsetX, y + textOffsetY)); + textComponent.setText(infoString); + textComponent.render(graphics); + } + + // Solve the puzzle if we don't have an up to date solution + if (solver == null || cachedItems == null + || (!shouldCache && solver.hasExceededWaitDuration() && !Arrays.equals(cachedItems, itemIds))) + { + solve(itemIds, useNormalSolver); + shouldCache = true; + } + + if (shouldCache) + { + cacheItems(itemIds); + } + + return null; + } + + private int[] getItemIds(ItemContainer container, boolean useNormalSolver) + { + int[] itemIds = new int[DIMENSION * DIMENSION]; + + Item[] items = container.getItems(); + + for (int i = 0; i < items.length; i++) + { + itemIds[i] = items[i].getId(); + } + + // If blank is in the last position, items doesn't contain it, so let's add it manually + if (itemIds.length > items.length) + { + itemIds[items.length] = BLANK_TILE_VALUE; + } + + return convertToSolverFormat(itemIds, useNormalSolver); + } + + private int[] convertToSolverFormat(int[] items, boolean useNormalSolver) + { + int lowestId = Integer.MAX_VALUE; + + int[] convertedItems = new int[items.length]; + + for (int id : items) + { + if (id == BLANK_TILE_VALUE) + { + continue; + } + + if (lowestId > id) + { + lowestId = id; + } + } + + for (int i = 0; i < items.length; i++) + { + if (items[i] != BLANK_TILE_VALUE) + { + int value = items[i] - lowestId; + + // The MM puzzle has gaps + if (!useNormalSolver) + { + value /= 2; + } + + convertedItems[i] = value; + } + else + { + convertedItems[i] = BLANK_TILE_VALUE; + } + } + + return convertedItems; + } + + private void cacheItems(int[] items) + { + cachedItems = new int[items.length]; + System.arraycopy(items, 0, cachedItems, 0, cachedItems.length); + } + + private void solve(int[] items, boolean useNormalSolver) + { + if (solverFuture != null) + { + solverFuture.cancel(true); + } + + PuzzleState puzzleState = new PuzzleState(items); + + if (useNormalSolver) + { + solver = new PuzzleSolver(new IDAStar(new ManhattanDistance()), puzzleState); + } + else + { + solver = new PuzzleSolver(new IDAStarMM(new ManhattanDistance()), puzzleState); + } + + solverFuture = executorService.submit(solver); + } + + private BufferedImage getDownArrow() + { + return spriteManager.getSprite(MINIMAP_DESTINATION_FLAG, 1); + } + + private BufferedImage getUpArrow() + { + if (upArrow == null) + { + upArrow = ImageUtil.rotateImage(getDownArrow(), Math.PI); + } + return upArrow; + } + + private BufferedImage getLeftArrow() + { + if (leftArrow == null) + { + leftArrow = ImageUtil.rotateImage(getDownArrow(), Math.PI / 2); + } + return leftArrow; + } + + private BufferedImage getRightArrow() + { + if (rightArrow == null) + { + rightArrow = ImageUtil.rotateImage(getDownArrow(), 3 * Math.PI / 2); + } + return rightArrow; + } +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/puzzlesolver/lightbox/Combination.java b/runelite-client/src/main/java/net/runelite/client/plugins/puzzlesolver/lightbox/Combination.java index 5ed1afd0ea..50749d2755 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/puzzlesolver/lightbox/Combination.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/puzzlesolver/lightbox/Combination.java @@ -1,30 +1,30 @@ -/* - * Copyright (c) 2018, Adam - * 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.puzzlesolver.lightbox; - -public enum Combination -{ - A, B, C, D, E, F, G, H; -} +/* + * Copyright (c) 2018, Adam + * 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.puzzlesolver.lightbox; + +public enum Combination +{ + A, B, C, D, E, F, G, H +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/puzzlesolver/solver/PuzzleState.java b/runelite-client/src/main/java/net/runelite/client/plugins/puzzlesolver/solver/PuzzleState.java index a34675feb8..2d0c9b0257 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/puzzlesolver/solver/PuzzleState.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/puzzlesolver/solver/PuzzleState.java @@ -1,225 +1,221 @@ -/* - * Copyright (c) 2018, Lotto - * 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.puzzlesolver.solver; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; -import net.runelite.client.plugins.puzzlesolver.solver.heuristics.Heuristic; -import static net.runelite.client.plugins.puzzlesolver.solver.PuzzleSolver.DIMENSION; -import static net.runelite.client.plugins.puzzlesolver.solver.PuzzleSolver.BLANK_TILE_VALUE; - -public class PuzzleState -{ - private PuzzleState parent; - - private int[] pieces; - private int emptyPiece = -1; - - private int h = -1; - - public PuzzleState(int[] pieces) - { - if (pieces == null) - { - throw new IllegalStateException("Pieces cannot be null"); - } - - if (DIMENSION * DIMENSION != pieces.length) - { - throw new IllegalStateException("Piece array does not have the right dimensions"); - } - - this.pieces = pieces; - findEmptyPiece(); - } - - private PuzzleState(PuzzleState state) - { - this.pieces = Arrays.copyOf(state.pieces, state.pieces.length); - this.emptyPiece = state.emptyPiece; - } - - private void findEmptyPiece() - { - for (int i = 0; i < pieces.length; i++) - { - if (pieces[i] == BLANK_TILE_VALUE) - { - this.emptyPiece = i; - return; - } - } - throw new IllegalStateException("Incorrect empty piece passed in!"); - } - - public List computeMoves() - { - List moves = new ArrayList<>(); - - int emptyPieceX = emptyPiece % DIMENSION; - int emptyPieceY = emptyPiece / DIMENSION; - - // Move left if there is space to the left - if (emptyPieceX > 0) - { - if (parent == null || parent.emptyPiece != emptyPiece - 1) - { - PuzzleState state = new PuzzleState(this); - state.parent = this; - - state.pieces[emptyPiece - 1] = BLANK_TILE_VALUE; - state.pieces[emptyPiece] = pieces[emptyPiece - 1]; - state.emptyPiece--; - - moves.add(state); - } - } - - // Move right if there is space to the right - if (emptyPieceX < DIMENSION - 1) - { - if (parent == null || parent.emptyPiece != emptyPiece + 1) - { - PuzzleState state = new PuzzleState(this); - state.parent = this; - - state.pieces[emptyPiece + 1] = BLANK_TILE_VALUE; - state.pieces[emptyPiece] = pieces[emptyPiece + 1]; - state.emptyPiece++; - - moves.add(state); - } - } - - // Move up if there is space upwards - if (emptyPieceY > 0) - { - if (parent == null || parent.emptyPiece != emptyPiece - DIMENSION) - { - PuzzleState state = new PuzzleState(this); - state.parent = this; - - state.pieces[emptyPiece - DIMENSION] = BLANK_TILE_VALUE; - state.pieces[emptyPiece] = pieces[emptyPiece - DIMENSION]; - state.emptyPiece -= DIMENSION; - - moves.add(state); - } - } - - // Move down if there is space downwards - if (emptyPieceY < DIMENSION - 1) - { - if (parent == null || parent.emptyPiece != emptyPiece + DIMENSION) - { - PuzzleState state = new PuzzleState(this); - state.parent = this; - - state.pieces[emptyPiece + DIMENSION] = BLANK_TILE_VALUE; - state.pieces[emptyPiece] = pieces[emptyPiece + DIMENSION]; - state.emptyPiece += DIMENSION; - - moves.add(state); - } - } - - return moves; - } - - public PuzzleState getParent() - { - return parent; - } - - public boolean hasPieces(int[] pieces) - { - return Arrays.equals(pieces, this.pieces); - } - - public int getPiece(int x, int y) - { - return pieces[y * DIMENSION + x]; - } - - public int getEmptyPiece() - { - return emptyPiece; - } - - public int getHeuristicValue(Heuristic heuristic) - { - if (h == -1) - { - // cache the value - h = heuristic.computeValue(this); - } - - return h; - } - - public PuzzleState swap(int x1, int y1, int x2, int y2) - { - int val1 = getPiece(x1, y1); - int val2 = getPiece(x2, y2); - - if (!isValidSwap(x1, y1, x2, y2)) - { - throw new IllegalStateException(String.format("Invalid swap: (%1$d, %2$d), (%3$d, %4$d)", x1, y1, x2, y2)); - } - - PuzzleState newState = new PuzzleState(this); - - newState.pieces[y1 * DIMENSION + x1] = val2; - newState.pieces[y2 * DIMENSION + x2] = val1; - newState.findEmptyPiece(); - - return newState; - } - - private boolean isValidSwap(int x1, int y1, int x2, int y2) - { - int absX = Math.abs(x1 - x2); - int absY = Math.abs(y1 - y2); - - if (getPiece(x1, y1) != BLANK_TILE_VALUE && getPiece(x2, y2) != BLANK_TILE_VALUE) - { - return false; - } - - if (x1 == x2 && absY == 1) - { - return true; - } - - if (y1 == y2 && absX == 1) - { - return true; - } - - return false; - } -} +/* + * Copyright (c) 2018, Lotto + * 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.puzzlesolver.solver; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import static net.runelite.client.plugins.puzzlesolver.solver.PuzzleSolver.BLANK_TILE_VALUE; +import static net.runelite.client.plugins.puzzlesolver.solver.PuzzleSolver.DIMENSION; +import net.runelite.client.plugins.puzzlesolver.solver.heuristics.Heuristic; + +public class PuzzleState +{ + private PuzzleState parent; + + private int[] pieces; + private int emptyPiece = -1; + + private int h = -1; + + public PuzzleState(int[] pieces) + { + if (pieces == null) + { + throw new IllegalStateException("Pieces cannot be null"); + } + + if (DIMENSION * DIMENSION != pieces.length) + { + throw new IllegalStateException("Piece array does not have the right dimensions"); + } + + this.pieces = pieces; + findEmptyPiece(); + } + + private PuzzleState(PuzzleState state) + { + this.pieces = Arrays.copyOf(state.pieces, state.pieces.length); + this.emptyPiece = state.emptyPiece; + } + + private void findEmptyPiece() + { + for (int i = 0; i < pieces.length; i++) + { + if (pieces[i] == BLANK_TILE_VALUE) + { + this.emptyPiece = i; + return; + } + } + throw new IllegalStateException("Incorrect empty piece passed in!"); + } + + public List computeMoves() + { + List moves = new ArrayList<>(); + + int emptyPieceX = emptyPiece % DIMENSION; + int emptyPieceY = emptyPiece / DIMENSION; + + // Move left if there is space to the left + if (emptyPieceX > 0) + { + if (parent == null || parent.emptyPiece != emptyPiece - 1) + { + PuzzleState state = new PuzzleState(this); + state.parent = this; + + state.pieces[emptyPiece - 1] = BLANK_TILE_VALUE; + state.pieces[emptyPiece] = pieces[emptyPiece - 1]; + state.emptyPiece--; + + moves.add(state); + } + } + + // Move right if there is space to the right + if (emptyPieceX < DIMENSION - 1) + { + if (parent == null || parent.emptyPiece != emptyPiece + 1) + { + PuzzleState state = new PuzzleState(this); + state.parent = this; + + state.pieces[emptyPiece + 1] = BLANK_TILE_VALUE; + state.pieces[emptyPiece] = pieces[emptyPiece + 1]; + state.emptyPiece++; + + moves.add(state); + } + } + + // Move up if there is space upwards + if (emptyPieceY > 0) + { + if (parent == null || parent.emptyPiece != emptyPiece - DIMENSION) + { + PuzzleState state = new PuzzleState(this); + state.parent = this; + + state.pieces[emptyPiece - DIMENSION] = BLANK_TILE_VALUE; + state.pieces[emptyPiece] = pieces[emptyPiece - DIMENSION]; + state.emptyPiece -= DIMENSION; + + moves.add(state); + } + } + + // Move down if there is space downwards + if (emptyPieceY < DIMENSION - 1) + { + if (parent == null || parent.emptyPiece != emptyPiece + DIMENSION) + { + PuzzleState state = new PuzzleState(this); + state.parent = this; + + state.pieces[emptyPiece + DIMENSION] = BLANK_TILE_VALUE; + state.pieces[emptyPiece] = pieces[emptyPiece + DIMENSION]; + state.emptyPiece += DIMENSION; + + moves.add(state); + } + } + + return moves; + } + + public PuzzleState getParent() + { + return parent; + } + + public boolean hasPieces(int[] pieces) + { + return Arrays.equals(pieces, this.pieces); + } + + public int getPiece(int x, int y) + { + return pieces[y * DIMENSION + x]; + } + + public int getEmptyPiece() + { + return emptyPiece; + } + + public int getHeuristicValue(Heuristic heuristic) + { + if (h == -1) + { + // cache the value + h = heuristic.computeValue(this); + } + + return h; + } + + public PuzzleState swap(int x1, int y1, int x2, int y2) + { + int val1 = getPiece(x1, y1); + int val2 = getPiece(x2, y2); + + if (!isValidSwap(x1, y1, x2, y2)) + { + throw new IllegalStateException(String.format("Invalid swap: (%1$d, %2$d), (%3$d, %4$d)", x1, y1, x2, y2)); + } + + PuzzleState newState = new PuzzleState(this); + + newState.pieces[y1 * DIMENSION + x1] = val2; + newState.pieces[y2 * DIMENSION + x2] = val1; + newState.findEmptyPiece(); + + return newState; + } + + private boolean isValidSwap(int x1, int y1, int x2, int y2) + { + int absX = Math.abs(x1 - x2); + int absY = Math.abs(y1 - y2); + + if (getPiece(x1, y1) != BLANK_TILE_VALUE && getPiece(x2, y2) != BLANK_TILE_VALUE) + { + return false; + } + + if (x1 == x2 && absY == 1) + { + return true; + } + + return y1 == y2 && absX == 1; + + } +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/puzzlesolver/solver/PuzzleSwapPattern.java b/runelite-client/src/main/java/net/runelite/client/plugins/puzzlesolver/solver/PuzzleSwapPattern.java index fe7949efd5..80e5622082 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/puzzlesolver/solver/PuzzleSwapPattern.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/puzzlesolver/solver/PuzzleSwapPattern.java @@ -1,66 +1,66 @@ -/* - * Copyright (c) 2018, Steffen Hauge - * 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.puzzlesolver.solver; - -import lombok.Getter; -import lombok.RequiredArgsConstructor; - -@RequiredArgsConstructor -@Getter -public enum PuzzleSwapPattern -{ - ROTATE_LEFT_UP(new int[]{1, -1, 0, -1, -1, -1, -1, 0}, 1, 1), //Reference point - ROTATE_LEFT_DOWN(1, -1), - ROTATE_RIGHT_UP(-1, 1), - ROTATE_RIGHT_DOWN(-1, -1), - ROTATE_UP_LEFT(new int[]{-1, 1, -1, 0, -1, -1, 0, -1}, 1 , 1), //Reference point - ROTATE_UP_RIGHT(-1, 1), - ROTATE_DOWN_LEFT(1, -1), - ROTATE_DOWN_RIGHT(-1, -1), - LAST_PIECE_ROW(new int[]{-1, -1, 0, -1, -1, 0, -1, 1}, 1, 1), - LAST_PIECE_COLUMN(new int[]{-1, -1, -1, 0, 0, -1, 1, -1}, 1, 1), - SHUFFLE_UP_RIGHT(new int[]{1, -1, 0, -1}, 1, 1), - SHUFFLE_UP_LEFT(new int[]{-1, -1, 0, -1}, 1, 1), - SHUFFLE_UP_BELOW(new int[]{-1, 1, -1, 0}, 1, 1), - SHUFFLE_UP_ABOVE(new int[]{-1, -1, -1, 0}, 1, 1); - - /** - * Points used for swaps relative to locVal - */ - private final int[] points; - /** - * Modifier for X coordinate - */ - private final int modX; - /** - * Modifier for Y coordinate - */ - private final int modY; - - PuzzleSwapPattern(int modX, int modY) - { - this(null, modX, modY); - } -} +/* + * Copyright (c) 2018, Steffen Hauge + * 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.puzzlesolver.solver; + +import lombok.Getter; +import lombok.RequiredArgsConstructor; + +@RequiredArgsConstructor +@Getter +public enum PuzzleSwapPattern +{ + ROTATE_LEFT_UP(new int[]{1, -1, 0, -1, -1, -1, -1, 0}, 1, 1), //Reference point + ROTATE_LEFT_DOWN(1, -1), + ROTATE_RIGHT_UP(-1, 1), + ROTATE_RIGHT_DOWN(-1, -1), + ROTATE_UP_LEFT(new int[]{-1, 1, -1, 0, -1, -1, 0, -1}, 1, 1), //Reference point + ROTATE_UP_RIGHT(-1, 1), + ROTATE_DOWN_LEFT(1, -1), + ROTATE_DOWN_RIGHT(-1, -1), + LAST_PIECE_ROW(new int[]{-1, -1, 0, -1, -1, 0, -1, 1}, 1, 1), + LAST_PIECE_COLUMN(new int[]{-1, -1, -1, 0, 0, -1, 1, -1}, 1, 1), + SHUFFLE_UP_RIGHT(new int[]{1, -1, 0, -1}, 1, 1), + SHUFFLE_UP_LEFT(new int[]{-1, -1, 0, -1}, 1, 1), + SHUFFLE_UP_BELOW(new int[]{-1, 1, -1, 0}, 1, 1), + SHUFFLE_UP_ABOVE(new int[]{-1, -1, -1, 0}, 1, 1); + + /** + * Points used for swaps relative to locVal + */ + private final int[] points; + /** + * Modifier for X coordinate + */ + private final int modX; + /** + * Modifier for Y coordinate + */ + private final int modY; + + PuzzleSwapPattern(int modX, int modY) + { + this(null, modX, modY); + } +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/puzzlesolver/solver/heuristics/ManhattanDistance.java b/runelite-client/src/main/java/net/runelite/client/plugins/puzzlesolver/solver/heuristics/ManhattanDistance.java index 9c89f9e71d..df9b66d9ad 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/puzzlesolver/solver/heuristics/ManhattanDistance.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/puzzlesolver/solver/heuristics/ManhattanDistance.java @@ -1,122 +1,146 @@ -/* - * Copyright (c) 2018, Lotto - * Copyright (c) 2018, Henke - * 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.puzzlesolver.solver.heuristics; - -import net.runelite.client.plugins.puzzlesolver.solver.PuzzleState; -import static net.runelite.client.plugins.puzzlesolver.solver.PuzzleSolver.DIMENSION; -import static net.runelite.client.plugins.puzzlesolver.solver.PuzzleSolver.BLANK_TILE_VALUE; - -/** - * An implementation of the manhattan distance heuristic function. - * - * https://heuristicswiki.wikispaces.com/Manhattan+Distance - */ -public class ManhattanDistance implements Heuristic -{ - @Override - public int computeValue(PuzzleState state) - { - int value = 0; - - PuzzleState parent = state.getParent(); - - if (parent == null) - { - for (int x = 0; x < DIMENSION; x++) - { - for (int y = 0; y < DIMENSION; y++) - { - int piece = state.getPiece(x, y); - - if (piece == BLANK_TILE_VALUE) - { - continue; - } - - int goalX = piece % DIMENSION; - int goalY = piece / DIMENSION; - - value += Math.abs(x - goalX) + Math.abs(y - goalY); - } - } - } - else - { - /* - If the Manhattan distance for the parent has already been - calculated, we can take advantage of that and just - add/subtract from their heuristic value. - - Doing this decreases the execution time of the heuristic by about 25%. - */ - value = parent.getHeuristicValue(this); - - int x = parent.getEmptyPiece() % DIMENSION; - int y = parent.getEmptyPiece() / DIMENSION; - - int x2 = state.getEmptyPiece() % DIMENSION; - int y2 = state.getEmptyPiece() / DIMENSION; - - int piece = state.getPiece(x, y); - - if (x2 > x) - { - int targetX = piece % DIMENSION; - - // right - if (targetX > x) value++; - else value--; - } - else if (x2 < x) - { - int targetX = piece % DIMENSION; - - // left - if (targetX < x) value++; - else value--; - } - else if (y2 > y) - { - int targetY = piece / DIMENSION; - - // down - if (targetY > y) value++; - else value--; - } - else - { - int targetY = piece / DIMENSION; - - // up - if (targetY < y) value++; - else value--; - } - } - - return value; - } -} +/* + * Copyright (c) 2018, Lotto + * Copyright (c) 2018, Henke + * 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.puzzlesolver.solver.heuristics; + +import static net.runelite.client.plugins.puzzlesolver.solver.PuzzleSolver.BLANK_TILE_VALUE; +import static net.runelite.client.plugins.puzzlesolver.solver.PuzzleSolver.DIMENSION; +import net.runelite.client.plugins.puzzlesolver.solver.PuzzleState; + +/** + * An implementation of the manhattan distance heuristic function. + *

+ * https://heuristicswiki.wikispaces.com/Manhattan+Distance + */ +public class ManhattanDistance implements Heuristic +{ + @Override + public int computeValue(PuzzleState state) + { + int value = 0; + + PuzzleState parent = state.getParent(); + + if (parent == null) + { + for (int x = 0; x < DIMENSION; x++) + { + for (int y = 0; y < DIMENSION; y++) + { + int piece = state.getPiece(x, y); + + if (piece == BLANK_TILE_VALUE) + { + continue; + } + + int goalX = piece % DIMENSION; + int goalY = piece / DIMENSION; + + value += Math.abs(x - goalX) + Math.abs(y - goalY); + } + } + } + else + { + /* + If the Manhattan distance for the parent has already been + calculated, we can take advantage of that and just + add/subtract from their heuristic value. + + Doing this decreases the execution time of the heuristic by about 25%. + */ + value = parent.getHeuristicValue(this); + + int x = parent.getEmptyPiece() % DIMENSION; + int y = parent.getEmptyPiece() / DIMENSION; + + int x2 = state.getEmptyPiece() % DIMENSION; + int y2 = state.getEmptyPiece() / DIMENSION; + + int piece = state.getPiece(x, y); + + if (x2 > x) + { + int targetX = piece % DIMENSION; + + // right + if (targetX > x) + { + value++; + } + else + { + value--; + } + } + else if (x2 < x) + { + int targetX = piece % DIMENSION; + + // left + if (targetX < x) + { + value++; + } + else + { + value--; + } + } + else if (y2 > y) + { + int targetY = piece / DIMENSION; + + // down + if (targetY > y) + { + value++; + } + else + { + value--; + } + } + else + { + int targetY = piece / DIMENSION; + + // up + if (targetY < y) + { + value++; + } + else + { + value--; + } + } + } + + return value; + } +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/puzzlesolver/solver/pathfinding/IDAStar.java b/runelite-client/src/main/java/net/runelite/client/plugins/puzzlesolver/solver/pathfinding/IDAStar.java index b43418a291..fc26d1889e 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/puzzlesolver/solver/pathfinding/IDAStar.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/puzzlesolver/solver/pathfinding/IDAStar.java @@ -1,106 +1,106 @@ -/* - * Copyright (c) 2018, Lotto - * 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.puzzlesolver.solver.pathfinding; - -import java.util.ArrayList; -import java.util.List; -import net.runelite.client.plugins.puzzlesolver.solver.PuzzleState; -import net.runelite.client.plugins.puzzlesolver.solver.heuristics.Heuristic; - -/** - * An implementation of the IDA* algorithm. - * - * https://en.wikipedia.org/wiki/Iterative_deepening_A* - */ -public class IDAStar extends Pathfinder -{ - public IDAStar(Heuristic heuristic) - { - super(heuristic); - } - - @Override - public List computePath(PuzzleState root) - { - PuzzleState goalNode = path(root); - - List path = new ArrayList<>(); - - PuzzleState parent = goalNode; - while (parent != null) - { - path.add(0, parent); - parent = parent.getParent(); - } - - return path; - } - - private PuzzleState path(PuzzleState root) - { - int bound = root.getHeuristicValue(getHeuristic()); - - while (true) - { - PuzzleState t = search(root, 0, bound); - - if (t != null) - { - return t; - } - - bound += 1; - } - } - - private PuzzleState search(PuzzleState node, int g, int bound) - { - int h = node.getHeuristicValue(getHeuristic()); - int f = g + h; - - if (f > bound) - { - return null; - } - - if (h == 0) - { - return node; - } - - for (PuzzleState successor : node.computeMoves()) - { - PuzzleState t = search(successor, g + 1, bound); - - if (t != null) - { - return t; - } - } - - return null; - } -} +/* + * Copyright (c) 2018, Lotto + * 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.puzzlesolver.solver.pathfinding; + +import java.util.ArrayList; +import java.util.List; +import net.runelite.client.plugins.puzzlesolver.solver.PuzzleState; +import net.runelite.client.plugins.puzzlesolver.solver.heuristics.Heuristic; + +/** + * An implementation of the IDA* algorithm. + *

+ * https://en.wikipedia.org/wiki/Iterative_deepening_A* + */ +public class IDAStar extends Pathfinder +{ + public IDAStar(Heuristic heuristic) + { + super(heuristic); + } + + @Override + public List computePath(PuzzleState root) + { + PuzzleState goalNode = path(root); + + List path = new ArrayList<>(); + + PuzzleState parent = goalNode; + while (parent != null) + { + path.add(0, parent); + parent = parent.getParent(); + } + + return path; + } + + private PuzzleState path(PuzzleState root) + { + int bound = root.getHeuristicValue(getHeuristic()); + + while (true) + { + PuzzleState t = search(root, 0, bound); + + if (t != null) + { + return t; + } + + bound += 1; + } + } + + private PuzzleState search(PuzzleState node, int g, int bound) + { + int h = node.getHeuristicValue(getHeuristic()); + int f = g + h; + + if (f > bound) + { + return null; + } + + if (h == 0) + { + return node; + } + + for (PuzzleState successor : node.computeMoves()) + { + PuzzleState t = search(successor, g + 1, bound); + + if (t != null) + { + return t; + } + } + + return null; + } +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/puzzlesolver/solver/pathfinding/IDAStarMM.java b/runelite-client/src/main/java/net/runelite/client/plugins/puzzlesolver/solver/pathfinding/IDAStarMM.java index f96b6971bd..97749e048a 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/puzzlesolver/solver/pathfinding/IDAStarMM.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/puzzlesolver/solver/pathfinding/IDAStarMM.java @@ -1,716 +1,729 @@ -/* - * Copyright (c) 2018, Steffen Hauge - * 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.puzzlesolver.solver.pathfinding; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; -import net.runelite.api.Point; -import static net.runelite.client.plugins.puzzlesolver.solver.PuzzleSolver.BLANK_TILE_VALUE; -import static net.runelite.client.plugins.puzzlesolver.solver.PuzzleSolver.DIMENSION; -import net.runelite.client.plugins.puzzlesolver.solver.PuzzleState; -import net.runelite.client.plugins.puzzlesolver.solver.PuzzleSwapPattern; -import static net.runelite.client.plugins.puzzlesolver.solver.PuzzleSwapPattern.*; -import net.runelite.client.plugins.puzzlesolver.solver.heuristics.Heuristic; - -public class IDAStarMM extends IDAStar -{ - private PuzzleState currentState; - private List stateList = new ArrayList<>(); - private List> validRowNumbers = new ArrayList<>(); - private List> validColumnNumbers = new ArrayList<>(); - - public IDAStarMM(Heuristic heuristic) - { - super(heuristic); - - //Add valid numbers for rows and columns - validRowNumbers.add(Arrays.asList(0, 1, 2, 3, 4)); - validRowNumbers.add(Arrays.asList(6, 7, 8, 9)); - validColumnNumbers.add(Arrays.asList(5, 10, 15, 20)); - } - - @Override - public List computePath(PuzzleState root) - { - currentState = root; - stateList.add(root); - - List path = new ArrayList<>(); - - //Reduce to 4x5 - solveRow(0); - - //Reduce to 4x4 - solveColumn(); - - //Reduce to 3x4 - solveRow(1); - - //Remove last state - stateList.remove(stateList.size() - 1); - - //Pathfinder for 4x4 - path.addAll(super.computePath(currentState)); - - path.addAll(0, stateList); - - return path; - } - - private void solveRow(int row) - { - for (int i = row; i < DIMENSION; i++) - { - int valTarget = row * DIMENSION + i; - - int valCurrent = currentState.getPiece(i, row); - - if (valCurrent != valTarget) - { - moveTowardsVal(valTarget, i, row, true); - } - } - } - - private void solveColumn() - { - int column = 0; - - for (int i = column + 1; i < DIMENSION; i++) - { - int valTarget = column + i * DIMENSION; - - int valCurrent = currentState.getPiece(column, i); - - if (valCurrent != valTarget) - { - moveTowardsVal(valTarget, column, i, false); - } - } - } - - private void moveTowardsVal(int valTarget, int x, int y, boolean rowMode) - { - //Not in place - boolean reached = false; - - while (currentState.getPiece(x, y) != valTarget) - { - //Find piece location - Point locVal = findPiece(valTarget); - Point locBlank = findPiece(BLANK_TILE_VALUE); - - if (reached) - { - //Swap towards locTarget - if (rowMode) - { - alignTargetX(valTarget, x, y); - swapUpRow(valTarget, x, y); - } - else - { - alignTargetY(valTarget, x, y); - swapLeftColumn(valTarget, x, y); - } - } - else - { - int distX = locVal.getX() - locBlank.getX(); - int distY = locVal.getY() - locBlank.getY(); - int distAbsX = Math.abs(distX); - int distAbsY = Math.abs(distY); - - if (distX == 0) - { - //Same column - if (distAbsY == 1) - { - //Next to - reached = true; - } - else - { - //More than 2 away, move towards on Y-axis - if (distY >= 2) - { - Point locSwap = new Point(locBlank.getX(), locBlank.getY() + 1); - swap(locBlank, locSwap); - } - else if (distY <= -2) - { - Point locSwap = new Point(locBlank.getX(), locBlank.getY() - 1); - swap(locBlank, locSwap); - } - } - } - else if (distY == 0) - { - //Same row - if (distAbsX == 1) - { - //Next to - reached = true; - } - else - { - //More than 2 away, move towards on X-axis - if (distX >= 2) - { - Point locSwap = new Point(locBlank.getX() + 1, locBlank.getY()); - swap(locBlank, locSwap); - } - else if (distX <= -2) - { - Point locSwap = new Point(locBlank.getX() - 1, locBlank.getY()); - swap(locBlank, locSwap); - } - } - } - else - { - //Different row and column - if (rowMode) - { - //Check if already correct above - if (locBlank.getY() - 1 == y - && validRowNumbers.get(y).contains(currentState.getPiece(locBlank.getX(), locBlank.getY() - 1)) - && currentState.getPiece(locBlank.getX(), locBlank.getY() - 1) < valTarget - && distY <= -1) - { - //Move forward - Point locSwap = new Point(locBlank.getX() + 1, locBlank.getY()); - swap(locBlank, locSwap); - continue; - } - - //Move downwards or upwards - if (distY >= 1) - { - Point locSwap = new Point(locBlank.getX(), locBlank.getY() + 1); - swap(locBlank, locSwap); - } - else if (distY <= -1) - { - Point locSwap = new Point(locBlank.getX(), locBlank.getY() - 1); - swap(locBlank, locSwap); - } - } - else - { - //Check if already correct to the left - if (locBlank.getX() - 1 == x - && validColumnNumbers.get(x).contains(currentState.getPiece(locBlank.getX() - 1, locBlank.getY())) - && currentState.getPiece(locBlank.getX() - 1, locBlank.getY()) < valTarget - && distX <= -1) - { - //Move down - Point locSwap = new Point(locBlank.getX(), locBlank.getY() + 1); - swap(locBlank, locSwap); - continue; - } - - //Move right or left - if (distX >= 1) - { - Point locSwap = new Point(locBlank.getX() + 1, locBlank.getY()); - swap(locBlank, locSwap); - } - else if (distX <= -1) - { - Point locSwap = new Point(locBlank.getX() - 1, locBlank.getY()); - swap(locBlank, locSwap); - } - } - } - } - } - } - - private void alignTargetX(int valTarget, int x, int y) - { - Point locVal = findPiece(valTarget); - - //Check if same column - if (locVal.getX() == x) - { - return; - } - - //1 = right, -1 = left - int direction = Integer.signum(x - locVal.getX()); - - while (locVal.getX() != x) - { - locVal = findPiece(valTarget); - Point locBlank = findPiece(BLANK_TILE_VALUE); - - //Check if aligned - if (x - locVal.getX() == 0) - { - break; - } - - if (locVal.getX() == locBlank.getX()) - { - int diff = locBlank.getY() - locVal.getY(); - if (diff == 1) - { - //Below - Point loc1 = new Point(locBlank.getX() + direction, locBlank.getY()); - Point loc2 = new Point(loc1.getX(), loc1.getY() - 1); - - swap(locBlank, loc1); - swap(loc1, loc2); - swap(loc2, locVal); - } - else if (diff == -1) - { - //Above - swap(locBlank, locVal); - } - } - else if (locVal.getY() == locBlank.getY()) - { - int diff = locBlank.getX() - locVal.getX(); - if (diff == 1) - { - //Right - if (direction == 1) - { - swap(locVal, locBlank); - } - else if (direction == -1) - { - //Check space - if (locVal.getY() == DIMENSION - 1) - { - //No space below, use upper rotate - performSwapPattern(locBlank, locVal, ROTATE_LEFT_UP); - } - else - { - //Space below, use lower rotate - performSwapPattern(locBlank, locVal, ROTATE_LEFT_DOWN); - } - } - } - else if (diff == -1) - { - //Left - if (direction == -1) - { - swap(locVal, locBlank); - } - else if (direction == 1) - { - //Check space - if (locVal.getY() == DIMENSION - 1) - { - //No space below, use upper rotate - performSwapPattern(locBlank, locVal, ROTATE_RIGHT_UP); - } - else - { - //Space below, use lower rotate - performSwapPattern(locBlank, locVal, ROTATE_RIGHT_DOWN); - } - } - } - } - } - } - - //Swaps up until inserted into the correct place - private void swapUpRow(int valTarget, int x, int y) - { - Point locVal = findPiece(valTarget); - Point locBlank = findPiece(BLANK_TILE_VALUE); - - //Check if already placed correct - if (locVal.getX() == x && locVal.getY() == y) - { - return; - } - - //Check if simple swap is enough - if (locBlank.getX() == x && locBlank.getY() == y && locVal.getY() - 1 == y) - { - swap(locBlank, locVal); - return; - } - - //Move up - while (true) - { - locVal = findPiece(valTarget); - locBlank = findPiece(BLANK_TILE_VALUE); - - //Check if already placed correct - if (locVal.getX() == x && locVal.getY() == y) - { - return; - } - - if (locVal.getX() == locBlank.getX()) - { - int diff = locBlank.getY() - locVal.getY(); - if (diff == 1) - { - //Below - - //Last piece - if (x == DIMENSION - 1) - { - performSwapPattern(locBlank, locVal, LAST_PIECE_ROW); - return; - } - - performSwapPattern(locBlank, locVal, ROTATE_UP_RIGHT); - } - else if (diff == -1) - { - //Above - swap(locBlank, locVal); - } - } - else if (locVal.getY() == locBlank.getY()) - { - int diff = locBlank.getX() - locVal.getX(); - if (diff == 1) - { - //Right - performSwapPattern(locBlank, locVal, SHUFFLE_UP_RIGHT); - } - else if (diff == -1) - { - //Left - - //Don't remove correct pieces from row - if (locVal.getY() - 1 == y) - { - //Swap blank to below and continue - Point loc1 = new Point(locBlank.getX(), locBlank.getY() + 1); - Point loc2 = new Point(loc1.getX() + 1, loc1.getY()); - - swap(locBlank, loc1); - swap(loc1, loc2); - - continue; - } - - performSwapPattern(locBlank, locVal, SHUFFLE_UP_LEFT); - } - } - } - } - - private void alignTargetY(int valTarget, int x, int y) - { - Point locVal = findPiece(valTarget); - - //Check if same row - if (locVal.getY() == y) - { - return; - } - - //1 = down, -1 = up - int direction = Integer.signum(y - locVal.getY()); - - while (locVal.getY() != y) - { - locVal = findPiece(valTarget); - Point locBlank = findPiece(BLANK_TILE_VALUE); - - //Check if aligned - if (y - locVal.getY() == 0) - { - break; - } - - if (locVal.getY() == locBlank.getY()) - { - int diff = locBlank.getX() - locVal.getX(); - if (diff == 1) - { - //Right - Point loc1 = new Point(locBlank.getX(), locBlank.getY() + direction); - Point loc2 = new Point(loc1.getX() - 1, loc1.getY()); - - swap(locBlank, loc1); - swap(loc1, loc2); - swap(loc2, locVal); - } - else if (diff == -1) - { - //Left - swap(locBlank, locVal); - } - } - else if (locVal.getX() == locBlank.getX()) - { - int diff = locBlank.getY() - locVal.getY(); - if (diff == 1) - { - //Below - if (direction == 1) - { - swap(locVal, locBlank); - } - else if (direction == -1) - { - //Check space - if (locVal.getX() == DIMENSION - 1) - { - //No space to the right, use left rotate - performSwapPattern(locBlank, locVal, ROTATE_UP_LEFT); - } - else - { - //Space to the right, use right rotate - performSwapPattern(locBlank, locVal, ROTATE_UP_RIGHT); - } - } - } - else if (diff == -1) - { - //Above - if (direction == -1) - { - swap(locVal, locBlank); - } - else if (direction == 1) - { - //Check space - if (locVal.getX() == DIMENSION - 1) - { - //No space to the right, use left rotate - performSwapPattern(locBlank, locVal, ROTATE_DOWN_LEFT); - } - else - { - //Space to the right, use right rotate - performSwapPattern(locBlank, locVal, ROTATE_DOWN_RIGHT); - } - } - } - } - } - } - - //Swaps left until inserted into the correct place - private void swapLeftColumn(int valTarget, int x, int y) - { - Point locVal = findPiece(valTarget); - Point locBlank = findPiece(BLANK_TILE_VALUE); - - //Check if already placed correct - if (locVal.getX() == x && locVal.getY() == y) - { - return; - } - - //Check if simple swap is enough - if (locBlank.getX() == x && locBlank.getY() == y && locVal.getX() - 1 == x) - { - swap(locBlank, locVal); - return; - } - - //Move left - while (true) - { - locVal = findPiece(valTarget); - locBlank = findPiece(BLANK_TILE_VALUE); - - //Check if already placed correct - if (locVal.getX() == x && locVal.getY() == y) - { - return; - } - - if (locVal.getX() == locBlank.getX()) - { - int diff = locBlank.getY() - locVal.getY(); - if (diff == 1) - { - //Below - performSwapPattern(locBlank, locVal, SHUFFLE_UP_BELOW); - } - else if (diff == -1) - { - //Above - - //Don't remove correct pices from row - if (locVal.getX() - 1 == x) - { - //Swap blank to right and continue - Point loc1 = new Point(locBlank.getX() + 1, locBlank.getY()); - Point loc2 = new Point(loc1.getX(), loc1.getY() + 1); - - swap(locBlank, loc1); - swap(loc1, loc2); - - continue; - } - - performSwapPattern(locBlank, locVal, SHUFFLE_UP_ABOVE); - } - } - else if (locVal.getY() == locBlank.getY()) - { - int diff = locBlank.getX() - locVal.getX(); - if (diff == 1) - { - //Right - - //Last piece - if (y == DIMENSION - 1) - { - performSwapPattern(locBlank, locVal, LAST_PIECE_COLUMN); - return; - } - - performSwapPattern(locBlank, locVal, ROTATE_LEFT_DOWN); - } - else if (diff == -1) - { - //Left - swap(locBlank, locVal); - } - } - } - } - - private void swap(Point p1, Point p2) - { - PuzzleState newState = currentState.swap(p1.getX(), p1.getY(), p2.getX(), p2.getY()); - - currentState = newState; - stateList.add(newState); - } - - private Point findPiece(int val) - { - for (int x = 0; x < DIMENSION; x++) - { - for (int y = 0; y < DIMENSION; y++) - { - if (currentState.getPiece(x, y) == val) - { - return new Point(x, y); - } - } - } - // This should never happen - throw new IllegalStateException("Piece wasn't found!"); - } - - /** - * Assumes locBlank is first point for swap and locVal is last point for swap - * - * swap(locBlank, loc1); - * swap(loc1, loc2); - * swap(loc2, locVal); - */ - private void performSwapPattern(Point locBlank, Point locVal, PuzzleSwapPattern pattern) - { - int[] offsets; - switch (pattern) - { - case ROTATE_LEFT_UP: - case ROTATE_RIGHT_UP: - case ROTATE_RIGHT_DOWN: - case ROTATE_LEFT_DOWN: - offsets = ROTATE_LEFT_UP.getPoints(); - break; - case ROTATE_UP_LEFT: - case ROTATE_UP_RIGHT: - case ROTATE_DOWN_LEFT: - case ROTATE_DOWN_RIGHT: - offsets = ROTATE_UP_LEFT.getPoints(); - break; - default: - offsets = pattern.getPoints(); - } - - if (offsets == null || offsets.length % 2 == 1) - { - // This should never happen - throw new IllegalStateException("Unexpected points given in pattern!"); - } - - int modX = pattern.getModX(); - int modY = pattern.getModY(); - - ArrayList points = new ArrayList<>(); - - for (int i = 0; i < offsets.length; i += 2) - { - int x = locVal.getX() + modX * offsets[i]; - int y = locVal.getY() + modY * offsets[i + 1]; - - points.add(new Point(x, y)); - } - - // Add locVal as last point - points.add(locVal); - - if (pattern != LAST_PIECE_ROW && pattern != LAST_PIECE_COLUMN) - { - Point start = locBlank; - for (Point p : points) - { - swap(start, p); - start = p; - } - } - else - { - Point loc1 = points.get(0); - Point loc2 = points.get(1); - Point loc3 = points.get(2); - Point loc4 = points.get(3); - - swap(locBlank, locVal); - swap(locVal, loc3); - swap(loc3, loc1); - swap(loc1, loc2); - swap(loc2, locVal); - swap(locVal, loc3); - swap(loc3, loc1); - swap(loc1, loc2); - swap(loc2, locVal); - swap(locVal, locBlank); - swap(locBlank, loc4); - swap(loc4, loc3); - swap(loc3, loc1); - swap(loc1, loc2); - swap(loc2, locVal); - } - } -} +/* + * Copyright (c) 2018, Steffen Hauge + * 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.puzzlesolver.solver.pathfinding; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import net.runelite.api.Point; +import static net.runelite.client.plugins.puzzlesolver.solver.PuzzleSolver.BLANK_TILE_VALUE; +import static net.runelite.client.plugins.puzzlesolver.solver.PuzzleSolver.DIMENSION; +import net.runelite.client.plugins.puzzlesolver.solver.PuzzleState; +import net.runelite.client.plugins.puzzlesolver.solver.PuzzleSwapPattern; +import static net.runelite.client.plugins.puzzlesolver.solver.PuzzleSwapPattern.LAST_PIECE_COLUMN; +import static net.runelite.client.plugins.puzzlesolver.solver.PuzzleSwapPattern.LAST_PIECE_ROW; +import static net.runelite.client.plugins.puzzlesolver.solver.PuzzleSwapPattern.ROTATE_DOWN_LEFT; +import static net.runelite.client.plugins.puzzlesolver.solver.PuzzleSwapPattern.ROTATE_DOWN_RIGHT; +import static net.runelite.client.plugins.puzzlesolver.solver.PuzzleSwapPattern.ROTATE_LEFT_DOWN; +import static net.runelite.client.plugins.puzzlesolver.solver.PuzzleSwapPattern.ROTATE_LEFT_UP; +import static net.runelite.client.plugins.puzzlesolver.solver.PuzzleSwapPattern.ROTATE_RIGHT_DOWN; +import static net.runelite.client.plugins.puzzlesolver.solver.PuzzleSwapPattern.ROTATE_RIGHT_UP; +import static net.runelite.client.plugins.puzzlesolver.solver.PuzzleSwapPattern.ROTATE_UP_LEFT; +import static net.runelite.client.plugins.puzzlesolver.solver.PuzzleSwapPattern.ROTATE_UP_RIGHT; +import static net.runelite.client.plugins.puzzlesolver.solver.PuzzleSwapPattern.SHUFFLE_UP_ABOVE; +import static net.runelite.client.plugins.puzzlesolver.solver.PuzzleSwapPattern.SHUFFLE_UP_BELOW; +import static net.runelite.client.plugins.puzzlesolver.solver.PuzzleSwapPattern.SHUFFLE_UP_LEFT; +import static net.runelite.client.plugins.puzzlesolver.solver.PuzzleSwapPattern.SHUFFLE_UP_RIGHT; +import net.runelite.client.plugins.puzzlesolver.solver.heuristics.Heuristic; + +public class IDAStarMM extends IDAStar +{ + private PuzzleState currentState; + private List stateList = new ArrayList<>(); + private List> validRowNumbers = new ArrayList<>(); + private List> validColumnNumbers = new ArrayList<>(); + + public IDAStarMM(Heuristic heuristic) + { + super(heuristic); + + //Add valid numbers for rows and columns + validRowNumbers.add(Arrays.asList(0, 1, 2, 3, 4)); + validRowNumbers.add(Arrays.asList(6, 7, 8, 9)); + validColumnNumbers.add(Arrays.asList(5, 10, 15, 20)); + } + + @Override + public List computePath(PuzzleState root) + { + currentState = root; + stateList.add(root); + + List path = new ArrayList<>(); + + //Reduce to 4x5 + solveRow(0); + + //Reduce to 4x4 + solveColumn(); + + //Reduce to 3x4 + solveRow(1); + + //Remove last state + stateList.remove(stateList.size() - 1); + + //Pathfinder for 4x4 + path.addAll(super.computePath(currentState)); + + path.addAll(0, stateList); + + return path; + } + + private void solveRow(int row) + { + for (int i = row; i < DIMENSION; i++) + { + int valTarget = row * DIMENSION + i; + + int valCurrent = currentState.getPiece(i, row); + + if (valCurrent != valTarget) + { + moveTowardsVal(valTarget, i, row, true); + } + } + } + + private void solveColumn() + { + int column = 0; + + for (int i = column + 1; i < DIMENSION; i++) + { + int valTarget = column + i * DIMENSION; + + int valCurrent = currentState.getPiece(column, i); + + if (valCurrent != valTarget) + { + moveTowardsVal(valTarget, column, i, false); + } + } + } + + private void moveTowardsVal(int valTarget, int x, int y, boolean rowMode) + { + //Not in place + boolean reached = false; + + while (currentState.getPiece(x, y) != valTarget) + { + //Find piece location + Point locVal = findPiece(valTarget); + Point locBlank = findPiece(BLANK_TILE_VALUE); + + if (reached) + { + //Swap towards locTarget + if (rowMode) + { + alignTargetX(valTarget, x, y); + swapUpRow(valTarget, x, y); + } + else + { + alignTargetY(valTarget, x, y); + swapLeftColumn(valTarget, x, y); + } + } + else + { + int distX = locVal.getX() - locBlank.getX(); + int distY = locVal.getY() - locBlank.getY(); + int distAbsX = Math.abs(distX); + int distAbsY = Math.abs(distY); + + if (distX == 0) + { + //Same column + if (distAbsY == 1) + { + //Next to + reached = true; + } + else + { + //More than 2 away, move towards on Y-axis + if (distY >= 2) + { + Point locSwap = new Point(locBlank.getX(), locBlank.getY() + 1); + swap(locBlank, locSwap); + } + else if (distY <= -2) + { + Point locSwap = new Point(locBlank.getX(), locBlank.getY() - 1); + swap(locBlank, locSwap); + } + } + } + else if (distY == 0) + { + //Same row + if (distAbsX == 1) + { + //Next to + reached = true; + } + else + { + //More than 2 away, move towards on X-axis + if (distX >= 2) + { + Point locSwap = new Point(locBlank.getX() + 1, locBlank.getY()); + swap(locBlank, locSwap); + } + else if (distX <= -2) + { + Point locSwap = new Point(locBlank.getX() - 1, locBlank.getY()); + swap(locBlank, locSwap); + } + } + } + else + { + //Different row and column + if (rowMode) + { + //Check if already correct above + if (locBlank.getY() - 1 == y + && validRowNumbers.get(y).contains(currentState.getPiece(locBlank.getX(), locBlank.getY() - 1)) + && currentState.getPiece(locBlank.getX(), locBlank.getY() - 1) < valTarget + && distY <= -1) + { + //Move forward + Point locSwap = new Point(locBlank.getX() + 1, locBlank.getY()); + swap(locBlank, locSwap); + continue; + } + + //Move downwards or upwards + if (distY >= 1) + { + Point locSwap = new Point(locBlank.getX(), locBlank.getY() + 1); + swap(locBlank, locSwap); + } + else if (distY <= -1) + { + Point locSwap = new Point(locBlank.getX(), locBlank.getY() - 1); + swap(locBlank, locSwap); + } + } + else + { + //Check if already correct to the left + if (locBlank.getX() - 1 == x + && validColumnNumbers.get(x).contains(currentState.getPiece(locBlank.getX() - 1, locBlank.getY())) + && currentState.getPiece(locBlank.getX() - 1, locBlank.getY()) < valTarget + && distX <= -1) + { + //Move down + Point locSwap = new Point(locBlank.getX(), locBlank.getY() + 1); + swap(locBlank, locSwap); + continue; + } + + //Move right or left + if (distX >= 1) + { + Point locSwap = new Point(locBlank.getX() + 1, locBlank.getY()); + swap(locBlank, locSwap); + } + else if (distX <= -1) + { + Point locSwap = new Point(locBlank.getX() - 1, locBlank.getY()); + swap(locBlank, locSwap); + } + } + } + } + } + } + + private void alignTargetX(int valTarget, int x, int y) + { + Point locVal = findPiece(valTarget); + + //Check if same column + if (locVal.getX() == x) + { + return; + } + + //1 = right, -1 = left + int direction = Integer.signum(x - locVal.getX()); + + while (locVal.getX() != x) + { + locVal = findPiece(valTarget); + Point locBlank = findPiece(BLANK_TILE_VALUE); + + //Check if aligned + if (x - locVal.getX() == 0) + { + break; + } + + if (locVal.getX() == locBlank.getX()) + { + int diff = locBlank.getY() - locVal.getY(); + if (diff == 1) + { + //Below + Point loc1 = new Point(locBlank.getX() + direction, locBlank.getY()); + Point loc2 = new Point(loc1.getX(), loc1.getY() - 1); + + swap(locBlank, loc1); + swap(loc1, loc2); + swap(loc2, locVal); + } + else if (diff == -1) + { + //Above + swap(locBlank, locVal); + } + } + else if (locVal.getY() == locBlank.getY()) + { + int diff = locBlank.getX() - locVal.getX(); + if (diff == 1) + { + //Right + if (direction == 1) + { + swap(locVal, locBlank); + } + else if (direction == -1) + { + //Check space + if (locVal.getY() == DIMENSION - 1) + { + //No space below, use upper rotate + performSwapPattern(locBlank, locVal, ROTATE_LEFT_UP); + } + else + { + //Space below, use lower rotate + performSwapPattern(locBlank, locVal, ROTATE_LEFT_DOWN); + } + } + } + else if (diff == -1) + { + //Left + if (direction == -1) + { + swap(locVal, locBlank); + } + else if (direction == 1) + { + //Check space + if (locVal.getY() == DIMENSION - 1) + { + //No space below, use upper rotate + performSwapPattern(locBlank, locVal, ROTATE_RIGHT_UP); + } + else + { + //Space below, use lower rotate + performSwapPattern(locBlank, locVal, ROTATE_RIGHT_DOWN); + } + } + } + } + } + } + + //Swaps up until inserted into the correct place + private void swapUpRow(int valTarget, int x, int y) + { + Point locVal = findPiece(valTarget); + Point locBlank = findPiece(BLANK_TILE_VALUE); + + //Check if already placed correct + if (locVal.getX() == x && locVal.getY() == y) + { + return; + } + + //Check if simple swap is enough + if (locBlank.getX() == x && locBlank.getY() == y && locVal.getY() - 1 == y) + { + swap(locBlank, locVal); + return; + } + + //Move up + while (true) + { + locVal = findPiece(valTarget); + locBlank = findPiece(BLANK_TILE_VALUE); + + //Check if already placed correct + if (locVal.getX() == x && locVal.getY() == y) + { + return; + } + + if (locVal.getX() == locBlank.getX()) + { + int diff = locBlank.getY() - locVal.getY(); + if (diff == 1) + { + //Below + + //Last piece + if (x == DIMENSION - 1) + { + performSwapPattern(locBlank, locVal, LAST_PIECE_ROW); + return; + } + + performSwapPattern(locBlank, locVal, ROTATE_UP_RIGHT); + } + else if (diff == -1) + { + //Above + swap(locBlank, locVal); + } + } + else if (locVal.getY() == locBlank.getY()) + { + int diff = locBlank.getX() - locVal.getX(); + if (diff == 1) + { + //Right + performSwapPattern(locBlank, locVal, SHUFFLE_UP_RIGHT); + } + else if (diff == -1) + { + //Left + + //Don't remove correct pieces from row + if (locVal.getY() - 1 == y) + { + //Swap blank to below and continue + Point loc1 = new Point(locBlank.getX(), locBlank.getY() + 1); + Point loc2 = new Point(loc1.getX() + 1, loc1.getY()); + + swap(locBlank, loc1); + swap(loc1, loc2); + + continue; + } + + performSwapPattern(locBlank, locVal, SHUFFLE_UP_LEFT); + } + } + } + } + + private void alignTargetY(int valTarget, int x, int y) + { + Point locVal = findPiece(valTarget); + + //Check if same row + if (locVal.getY() == y) + { + return; + } + + //1 = down, -1 = up + int direction = Integer.signum(y - locVal.getY()); + + while (locVal.getY() != y) + { + locVal = findPiece(valTarget); + Point locBlank = findPiece(BLANK_TILE_VALUE); + + //Check if aligned + if (y - locVal.getY() == 0) + { + break; + } + + if (locVal.getY() == locBlank.getY()) + { + int diff = locBlank.getX() - locVal.getX(); + if (diff == 1) + { + //Right + Point loc1 = new Point(locBlank.getX(), locBlank.getY() + direction); + Point loc2 = new Point(loc1.getX() - 1, loc1.getY()); + + swap(locBlank, loc1); + swap(loc1, loc2); + swap(loc2, locVal); + } + else if (diff == -1) + { + //Left + swap(locBlank, locVal); + } + } + else if (locVal.getX() == locBlank.getX()) + { + int diff = locBlank.getY() - locVal.getY(); + if (diff == 1) + { + //Below + if (direction == 1) + { + swap(locVal, locBlank); + } + else if (direction == -1) + { + //Check space + if (locVal.getX() == DIMENSION - 1) + { + //No space to the right, use left rotate + performSwapPattern(locBlank, locVal, ROTATE_UP_LEFT); + } + else + { + //Space to the right, use right rotate + performSwapPattern(locBlank, locVal, ROTATE_UP_RIGHT); + } + } + } + else if (diff == -1) + { + //Above + if (direction == -1) + { + swap(locVal, locBlank); + } + else if (direction == 1) + { + //Check space + if (locVal.getX() == DIMENSION - 1) + { + //No space to the right, use left rotate + performSwapPattern(locBlank, locVal, ROTATE_DOWN_LEFT); + } + else + { + //Space to the right, use right rotate + performSwapPattern(locBlank, locVal, ROTATE_DOWN_RIGHT); + } + } + } + } + } + } + + //Swaps left until inserted into the correct place + private void swapLeftColumn(int valTarget, int x, int y) + { + Point locVal = findPiece(valTarget); + Point locBlank = findPiece(BLANK_TILE_VALUE); + + //Check if already placed correct + if (locVal.getX() == x && locVal.getY() == y) + { + return; + } + + //Check if simple swap is enough + if (locBlank.getX() == x && locBlank.getY() == y && locVal.getX() - 1 == x) + { + swap(locBlank, locVal); + return; + } + + //Move left + while (true) + { + locVal = findPiece(valTarget); + locBlank = findPiece(BLANK_TILE_VALUE); + + //Check if already placed correct + if (locVal.getX() == x && locVal.getY() == y) + { + return; + } + + if (locVal.getX() == locBlank.getX()) + { + int diff = locBlank.getY() - locVal.getY(); + if (diff == 1) + { + //Below + performSwapPattern(locBlank, locVal, SHUFFLE_UP_BELOW); + } + else if (diff == -1) + { + //Above + + //Don't remove correct pices from row + if (locVal.getX() - 1 == x) + { + //Swap blank to right and continue + Point loc1 = new Point(locBlank.getX() + 1, locBlank.getY()); + Point loc2 = new Point(loc1.getX(), loc1.getY() + 1); + + swap(locBlank, loc1); + swap(loc1, loc2); + + continue; + } + + performSwapPattern(locBlank, locVal, SHUFFLE_UP_ABOVE); + } + } + else if (locVal.getY() == locBlank.getY()) + { + int diff = locBlank.getX() - locVal.getX(); + if (diff == 1) + { + //Right + + //Last piece + if (y == DIMENSION - 1) + { + performSwapPattern(locBlank, locVal, LAST_PIECE_COLUMN); + return; + } + + performSwapPattern(locBlank, locVal, ROTATE_LEFT_DOWN); + } + else if (diff == -1) + { + //Left + swap(locBlank, locVal); + } + } + } + } + + private void swap(Point p1, Point p2) + { + PuzzleState newState = currentState.swap(p1.getX(), p1.getY(), p2.getX(), p2.getY()); + + currentState = newState; + stateList.add(newState); + } + + private Point findPiece(int val) + { + for (int x = 0; x < DIMENSION; x++) + { + for (int y = 0; y < DIMENSION; y++) + { + if (currentState.getPiece(x, y) == val) + { + return new Point(x, y); + } + } + } + // This should never happen + throw new IllegalStateException("Piece wasn't found!"); + } + + /** + * Assumes locBlank is first point for swap and locVal is last point for swap + *

+ * swap(locBlank, loc1); + * swap(loc1, loc2); + * swap(loc2, locVal); + */ + private void performSwapPattern(Point locBlank, Point locVal, PuzzleSwapPattern pattern) + { + int[] offsets; + switch (pattern) + { + case ROTATE_LEFT_UP: + case ROTATE_RIGHT_UP: + case ROTATE_RIGHT_DOWN: + case ROTATE_LEFT_DOWN: + offsets = ROTATE_LEFT_UP.getPoints(); + break; + case ROTATE_UP_LEFT: + case ROTATE_UP_RIGHT: + case ROTATE_DOWN_LEFT: + case ROTATE_DOWN_RIGHT: + offsets = ROTATE_UP_LEFT.getPoints(); + break; + default: + offsets = pattern.getPoints(); + } + + if (offsets == null || offsets.length % 2 == 1) + { + // This should never happen + throw new IllegalStateException("Unexpected points given in pattern!"); + } + + int modX = pattern.getModX(); + int modY = pattern.getModY(); + + ArrayList points = new ArrayList<>(); + + for (int i = 0; i < offsets.length; i += 2) + { + int x = locVal.getX() + modX * offsets[i]; + int y = locVal.getY() + modY * offsets[i + 1]; + + points.add(new Point(x, y)); + } + + // Add locVal as last point + points.add(locVal); + + if (pattern != LAST_PIECE_ROW && pattern != LAST_PIECE_COLUMN) + { + Point start = locBlank; + for (Point p : points) + { + swap(start, p); + start = p; + } + } + else + { + Point loc1 = points.get(0); + Point loc2 = points.get(1); + Point loc3 = points.get(2); + Point loc4 = points.get(3); + + swap(locBlank, locVal); + swap(locVal, loc3); + swap(loc3, loc1); + swap(loc1, loc2); + swap(loc2, locVal); + swap(locVal, loc3); + swap(loc3, loc1); + swap(loc1, loc2); + swap(loc2, locVal); + swap(locVal, locBlank); + swap(locBlank, loc4); + swap(loc4, loc3); + swap(loc3, loc1); + swap(loc1, loc2); + swap(loc2, locVal); + } + } +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/pvptools/PvpToolsPanel.java b/runelite-client/src/main/java/net/runelite/client/plugins/pvptools/PvpToolsPanel.java index 6e709ede39..3156f8061c 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/pvptools/PvpToolsPanel.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/pvptools/PvpToolsPanel.java @@ -14,7 +14,6 @@ import java.awt.BorderLayout; import java.awt.Color; import java.awt.Font; import java.awt.GridLayout; -import javax.inject.Inject; import javax.swing.Box; import javax.swing.JButton; import javax.swing.JLabel; diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/pyramidplunder/PyramidPlunderOverlay.java b/runelite-client/src/main/java/net/runelite/client/plugins/pyramidplunder/PyramidPlunderOverlay.java index fd61a03229..7607a8022f 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/pyramidplunder/PyramidPlunderOverlay.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/pyramidplunder/PyramidPlunderOverlay.java @@ -1,131 +1,132 @@ -/* - * Copyright (c) 2018, Steffen Hauge - * 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.pyramidplunder; - -import java.awt.Color; -import java.awt.Dimension; -import java.awt.Graphics2D; -import java.awt.geom.Area; -import javax.inject.Inject; -import net.runelite.api.Client; -import net.runelite.api.ObjectComposition; -import static net.runelite.api.ObjectID.SPEARTRAP_21280; -import static net.runelite.api.ObjectID.TOMB_DOOR_20948; -import static net.runelite.api.ObjectID.TOMB_DOOR_20949; -import net.runelite.api.Point; -import net.runelite.api.coords.LocalPoint; -import net.runelite.client.ui.overlay.Overlay; -import net.runelite.client.ui.overlay.OverlayLayer; -import net.runelite.client.ui.overlay.OverlayPosition; - -public class PyramidPlunderOverlay extends Overlay -{ - private static final int MAX_DISTANCE = 2400; - private static final Color COLOR_DOOR = Color.GREEN; - private static final Color COLOR_SPEAR_TRAP = Color.ORANGE; - - private final Client client; - private final PyramidPlunderPlugin plugin; - private final PyramidPlunderConfig config; - - @Inject - private PyramidPlunderOverlay(Client client, PyramidPlunderPlugin plugin, PyramidPlunderConfig config) - { - this.client = client; - this.plugin = plugin; - this.config = config; - setPosition(OverlayPosition.DYNAMIC); - setLayer(OverlayLayer.ABOVE_SCENE); - } - @Override - public Dimension render(Graphics2D graphics) - { - if (!plugin.isInGame()) - { - return null; - } - - LocalPoint playerLocation = client.getLocalPlayer().getLocalLocation(); - Point mousePosition = client.getMouseCanvasPosition(); - - plugin.getObstacles().forEach((object, tile) -> - { - if (Obstacles.WALL_OBSTACLE_IDS.contains(object.getId()) && !config.highlightDoors() || - Obstacles.TRAP_OBSTACLE_IDS.contains(object.getId()) && !config.highlightSpearTrap()) - { - return; - } - - if (tile.getPlane() == client.getPlane() && - object.getLocalLocation().distanceTo(playerLocation) < MAX_DISTANCE) - { - int objectID = object.getId(); - if (Obstacles.WALL_OBSTACLE_IDS.contains(object.getId())) - { - //Impostor - ObjectComposition comp = client.getObjectDefinition(objectID); - ObjectComposition impostor = comp.getImpostor(); - - if (impostor == null) - { - return; - } - objectID = impostor.getId(); - } - - Area objectClickbox = object.getClickbox(); - if (objectClickbox != null) - { - Color configColor = Color.GREEN; - switch (objectID) - { - case SPEARTRAP_21280: - configColor = COLOR_SPEAR_TRAP; - break; - case TOMB_DOOR_20948: - case TOMB_DOOR_20949: - configColor = COLOR_DOOR; - break; - } - - if (objectClickbox.contains(mousePosition.getX(), mousePosition.getY())) - { - graphics.setColor(configColor.darker()); - } - else - { - graphics.setColor(configColor); - } - - graphics.draw(objectClickbox); - graphics.setColor(new Color(configColor.getRed(), configColor.getGreen(), configColor.getBlue(), 50)); - graphics.fill(objectClickbox); - } - } - }); - - return null; - } -} +/* + * Copyright (c) 2018, Steffen Hauge + * 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.pyramidplunder; + +import java.awt.Color; +import java.awt.Dimension; +import java.awt.Graphics2D; +import java.awt.geom.Area; +import javax.inject.Inject; +import net.runelite.api.Client; +import net.runelite.api.ObjectComposition; +import static net.runelite.api.ObjectID.SPEARTRAP_21280; +import static net.runelite.api.ObjectID.TOMB_DOOR_20948; +import static net.runelite.api.ObjectID.TOMB_DOOR_20949; +import net.runelite.api.Point; +import net.runelite.api.coords.LocalPoint; +import net.runelite.client.ui.overlay.Overlay; +import net.runelite.client.ui.overlay.OverlayLayer; +import net.runelite.client.ui.overlay.OverlayPosition; + +public class PyramidPlunderOverlay extends Overlay +{ + private static final int MAX_DISTANCE = 2400; + private static final Color COLOR_DOOR = Color.GREEN; + private static final Color COLOR_SPEAR_TRAP = Color.ORANGE; + + private final Client client; + private final PyramidPlunderPlugin plugin; + private final PyramidPlunderConfig config; + + @Inject + private PyramidPlunderOverlay(Client client, PyramidPlunderPlugin plugin, PyramidPlunderConfig config) + { + this.client = client; + this.plugin = plugin; + this.config = config; + setPosition(OverlayPosition.DYNAMIC); + setLayer(OverlayLayer.ABOVE_SCENE); + } + + @Override + public Dimension render(Graphics2D graphics) + { + if (!plugin.isInGame()) + { + return null; + } + + LocalPoint playerLocation = client.getLocalPlayer().getLocalLocation(); + Point mousePosition = client.getMouseCanvasPosition(); + + plugin.getObstacles().forEach((object, tile) -> + { + if (Obstacles.WALL_OBSTACLE_IDS.contains(object.getId()) && !config.highlightDoors() || + Obstacles.TRAP_OBSTACLE_IDS.contains(object.getId()) && !config.highlightSpearTrap()) + { + return; + } + + if (tile.getPlane() == client.getPlane() && + object.getLocalLocation().distanceTo(playerLocation) < MAX_DISTANCE) + { + int objectID = object.getId(); + if (Obstacles.WALL_OBSTACLE_IDS.contains(object.getId())) + { + //Impostor + ObjectComposition comp = client.getObjectDefinition(objectID); + ObjectComposition impostor = comp.getImpostor(); + + if (impostor == null) + { + return; + } + objectID = impostor.getId(); + } + + Area objectClickbox = object.getClickbox(); + if (objectClickbox != null) + { + Color configColor = Color.GREEN; + switch (objectID) + { + case SPEARTRAP_21280: + configColor = COLOR_SPEAR_TRAP; + break; + case TOMB_DOOR_20948: + case TOMB_DOOR_20949: + configColor = COLOR_DOOR; + break; + } + + if (objectClickbox.contains(mousePosition.getX(), mousePosition.getY())) + { + graphics.setColor(configColor.darker()); + } + else + { + graphics.setColor(configColor); + } + + graphics.draw(objectClickbox); + graphics.setColor(new Color(configColor.getRed(), configColor.getGreen(), configColor.getBlue(), 50)); + graphics.fill(objectClickbox); + } + } + }); + + return null; + } +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/pyramidplunder/PyramidPlunderPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/pyramidplunder/PyramidPlunderPlugin.java index 1ada10d2bc..31beb64cd8 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/pyramidplunder/PyramidPlunderPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/pyramidplunder/PyramidPlunderPlugin.java @@ -1,273 +1,269 @@ -/* - * Copyright (c) 2018, Steffen Hauge - * 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.pyramidplunder; - -import com.google.common.eventbus.Subscribe; -import com.google.inject.Provides; -import java.time.temporal.ChronoUnit; -import java.util.HashMap; -import java.util.Map; -import javax.inject.Inject; -import lombok.Getter; -import net.runelite.api.Client; -import static net.runelite.api.ItemID.PHARAOHS_SCEPTRE; -import net.runelite.api.Player; -import net.runelite.api.Tile; -import net.runelite.api.TileObject; -import net.runelite.api.Varbits; -import net.runelite.api.coords.WorldPoint; -import net.runelite.api.events.ConfigChanged; -import net.runelite.api.events.GameObjectChanged; -import net.runelite.api.events.GameObjectDespawned; -import net.runelite.api.events.GameObjectSpawned; -import net.runelite.api.events.GameStateChanged; -import net.runelite.api.events.VarbitChanged; -import net.runelite.api.events.WallObjectChanged; -import net.runelite.api.events.WallObjectDespawned; -import net.runelite.api.events.WallObjectSpawned; -import net.runelite.client.config.ConfigManager; -import net.runelite.client.game.ItemManager; -import net.runelite.client.plugins.Plugin; -import net.runelite.client.plugins.PluginDescriptor; -import net.runelite.client.plugins.PluginType; -import net.runelite.client.ui.overlay.OverlayManager; -import net.runelite.client.ui.overlay.infobox.InfoBoxManager; - -@PluginDescriptor( - name = "PyramidPlunder", - description = "Highlights doors and spear traps in pyramid plunder and adds a numerical timer", - tags = {"pyramidplunder", "pyramid", "plunder", "overlay", "skilling", "thieving"}, - type = PluginType.UTILITY, - enabledByDefault = false -) - -public class PyramidPlunderPlugin extends Plugin -{ - private static final int PYRAMIND_PLUNDER_REGION_ID = 7749; - private static final int PYRAMIND_PLUNDER_TIMER_MAX = 500; - private static final double GAMETICK_SECOND = 0.6; - - @Getter - private final Map obstacles = new HashMap<>(); - - @Inject - private Client client; - - @Inject - private PyramidPlunderConfig config; - - @Inject - private InfoBoxManager infoBoxManager; - - @Inject - private ItemManager itemManager; - - @Inject - private OverlayManager overlayManager; - - @Inject - private PyramidPlunderOverlay pyramidPlunderOverlay; - - @Getter - private boolean isInGame; - - private int pyramidTimer = 0; - - @Provides - PyramidPlunderConfig getConfig(ConfigManager configManager) - { - return configManager.getConfig(PyramidPlunderConfig.class); - } - - @Override - protected void startUp() throws Exception - { - overlayManager.add(pyramidPlunderOverlay); - } - - @Override - protected void shutDown() throws Exception - { - overlayManager.remove(pyramidPlunderOverlay); - obstacles.clear(); - reset(); - } - - @Subscribe - public void onConfigChanged(ConfigChanged event) - { - if (!config.showTimer()) - { - removeTimer(); - } - - if (config.showTimer() && isInGame) - { - int remainingTime = PYRAMIND_PLUNDER_TIMER_MAX - pyramidTimer; - - if (remainingTime >= 2) - { - double timeInSeconds = remainingTime * GAMETICK_SECOND; - showTimer((int)timeInSeconds, ChronoUnit.SECONDS); - } - } - } - - private void removeTimer() - { - infoBoxManager.removeIf(infoBox -> infoBox instanceof PyramidPlunderTimer); - } - - private void showTimer() - { - showTimer(5, ChronoUnit.MINUTES); - } - - private void showTimer(int period, ChronoUnit chronoUnit) - { - removeTimer(); - infoBoxManager.addInfoBox(new PyramidPlunderTimer(this, itemManager.getImage(PHARAOHS_SCEPTRE), period, chronoUnit)); - } - - @Subscribe - public void onGameStateChange(GameStateChanged event) - { - switch (event.getGameState()) - { - case HOPPING: - case LOGIN_SCREEN: - reset(); - break; - case LOADING: - obstacles.clear(); - case LOGGED_IN: - if (!isInRegion()) - { - reset(); - } - break; - } - } - - private boolean isInRegion() - { - Player local = client.getLocalPlayer(); - if (local == null) - { - return false; - } - - WorldPoint location = local.getWorldLocation(); - if (location.getRegionID() != PYRAMIND_PLUNDER_REGION_ID) - { - return false; - } - - return true; - } - - @Subscribe - public void onVarbitChanged(VarbitChanged event) - { - int lastValue = pyramidTimer; - pyramidTimer = client.getVar(Varbits.PYRAMID_PLUNDER_TIMER); - - if (lastValue == pyramidTimer) - { - return; - } - - if (pyramidTimer == 0) - { - reset(); - } - if (pyramidTimer == 1) - { - isInGame = true; - if (config.showTimer()) - { - showTimer(); - } - } - } - - private void reset() - { - isInGame = false; - removeTimer(); - } - - @Subscribe - public void onGameObjectSpawned(GameObjectSpawned event) - { - onTileObject(event.getTile(), null, event.getGameObject()); - } - - @Subscribe - public void onGameObjectChanged(GameObjectChanged event) - { - onTileObject(event.getTile(), event.getPrevious(), event.getGameObject()); - } - - @Subscribe - public void onGameObjectDeSpawned(GameObjectDespawned event) - { - onTileObject(event.getTile(), event.getGameObject(), null); - } - - @Subscribe - public void onWallObjectSpawned(WallObjectSpawned event) - { - onTileObject(event.getTile(), null, event.getWallObject()); - } - - @Subscribe - public void onWallObjectChanged(WallObjectChanged event) - { - onTileObject(event.getTile(), event.getPrevious(), event.getWallObject()); - } - - @Subscribe - public void onWallObjectDeSpawned(WallObjectDespawned event) - { - onTileObject(event.getTile(), event.getWallObject(), null); - } - - private void onTileObject(Tile tile, TileObject oldObject, TileObject newObject) - { - obstacles.remove(oldObject); - - if (newObject == null) - { - return; - } - - if (Obstacles.WALL_OBSTACLE_IDS.contains(newObject.getId()) || - Obstacles.TRAP_OBSTACLE_IDS.contains(newObject.getId())) - { - obstacles.put(newObject, tile); - } - } -} +/* + * Copyright (c) 2018, Steffen Hauge + * 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.pyramidplunder; + +import com.google.common.eventbus.Subscribe; +import com.google.inject.Provides; +import java.time.temporal.ChronoUnit; +import java.util.HashMap; +import java.util.Map; +import javax.inject.Inject; +import lombok.Getter; +import net.runelite.api.Client; +import static net.runelite.api.ItemID.PHARAOHS_SCEPTRE; +import net.runelite.api.Player; +import net.runelite.api.Tile; +import net.runelite.api.TileObject; +import net.runelite.api.Varbits; +import net.runelite.api.coords.WorldPoint; +import net.runelite.api.events.ConfigChanged; +import net.runelite.api.events.GameObjectChanged; +import net.runelite.api.events.GameObjectDespawned; +import net.runelite.api.events.GameObjectSpawned; +import net.runelite.api.events.GameStateChanged; +import net.runelite.api.events.VarbitChanged; +import net.runelite.api.events.WallObjectChanged; +import net.runelite.api.events.WallObjectDespawned; +import net.runelite.api.events.WallObjectSpawned; +import net.runelite.client.config.ConfigManager; +import net.runelite.client.game.ItemManager; +import net.runelite.client.plugins.Plugin; +import net.runelite.client.plugins.PluginDescriptor; +import net.runelite.client.plugins.PluginType; +import net.runelite.client.ui.overlay.OverlayManager; +import net.runelite.client.ui.overlay.infobox.InfoBoxManager; + +@PluginDescriptor( + name = "PyramidPlunder", + description = "Highlights doors and spear traps in pyramid plunder and adds a numerical timer", + tags = {"pyramidplunder", "pyramid", "plunder", "overlay", "skilling", "thieving"}, + type = PluginType.UTILITY, + enabledByDefault = false +) + +public class PyramidPlunderPlugin extends Plugin +{ + private static final int PYRAMIND_PLUNDER_REGION_ID = 7749; + private static final int PYRAMIND_PLUNDER_TIMER_MAX = 500; + private static final double GAMETICK_SECOND = 0.6; + + @Getter + private final Map obstacles = new HashMap<>(); + + @Inject + private Client client; + + @Inject + private PyramidPlunderConfig config; + + @Inject + private InfoBoxManager infoBoxManager; + + @Inject + private ItemManager itemManager; + + @Inject + private OverlayManager overlayManager; + + @Inject + private PyramidPlunderOverlay pyramidPlunderOverlay; + + @Getter + private boolean isInGame; + + private int pyramidTimer = 0; + + @Provides + PyramidPlunderConfig getConfig(ConfigManager configManager) + { + return configManager.getConfig(PyramidPlunderConfig.class); + } + + @Override + protected void startUp() throws Exception + { + overlayManager.add(pyramidPlunderOverlay); + } + + @Override + protected void shutDown() throws Exception + { + overlayManager.remove(pyramidPlunderOverlay); + obstacles.clear(); + reset(); + } + + @Subscribe + public void onConfigChanged(ConfigChanged event) + { + if (!config.showTimer()) + { + removeTimer(); + } + + if (config.showTimer() && isInGame) + { + int remainingTime = PYRAMIND_PLUNDER_TIMER_MAX - pyramidTimer; + + if (remainingTime >= 2) + { + double timeInSeconds = remainingTime * GAMETICK_SECOND; + showTimer((int) timeInSeconds, ChronoUnit.SECONDS); + } + } + } + + private void removeTimer() + { + infoBoxManager.removeIf(infoBox -> infoBox instanceof PyramidPlunderTimer); + } + + private void showTimer() + { + showTimer(5, ChronoUnit.MINUTES); + } + + private void showTimer(int period, ChronoUnit chronoUnit) + { + removeTimer(); + infoBoxManager.addInfoBox(new PyramidPlunderTimer(this, itemManager.getImage(PHARAOHS_SCEPTRE), period, chronoUnit)); + } + + @Subscribe + public void onGameStateChange(GameStateChanged event) + { + switch (event.getGameState()) + { + case HOPPING: + case LOGIN_SCREEN: + reset(); + break; + case LOADING: + obstacles.clear(); + case LOGGED_IN: + if (!isInRegion()) + { + reset(); + } + break; + } + } + + private boolean isInRegion() + { + Player local = client.getLocalPlayer(); + if (local == null) + { + return false; + } + + WorldPoint location = local.getWorldLocation(); + return location.getRegionID() == PYRAMIND_PLUNDER_REGION_ID; + + } + + @Subscribe + public void onVarbitChanged(VarbitChanged event) + { + int lastValue = pyramidTimer; + pyramidTimer = client.getVar(Varbits.PYRAMID_PLUNDER_TIMER); + + if (lastValue == pyramidTimer) + { + return; + } + + if (pyramidTimer == 0) + { + reset(); + } + if (pyramidTimer == 1) + { + isInGame = true; + if (config.showTimer()) + { + showTimer(); + } + } + } + + private void reset() + { + isInGame = false; + removeTimer(); + } + + @Subscribe + public void onGameObjectSpawned(GameObjectSpawned event) + { + onTileObject(event.getTile(), null, event.getGameObject()); + } + + @Subscribe + public void onGameObjectChanged(GameObjectChanged event) + { + onTileObject(event.getTile(), event.getPrevious(), event.getGameObject()); + } + + @Subscribe + public void onGameObjectDeSpawned(GameObjectDespawned event) + { + onTileObject(event.getTile(), event.getGameObject(), null); + } + + @Subscribe + public void onWallObjectSpawned(WallObjectSpawned event) + { + onTileObject(event.getTile(), null, event.getWallObject()); + } + + @Subscribe + public void onWallObjectChanged(WallObjectChanged event) + { + onTileObject(event.getTile(), event.getPrevious(), event.getWallObject()); + } + + @Subscribe + public void onWallObjectDeSpawned(WallObjectDespawned event) + { + onTileObject(event.getTile(), event.getWallObject(), null); + } + + private void onTileObject(Tile tile, TileObject oldObject, TileObject newObject) + { + obstacles.remove(oldObject); + + if (newObject == null) + { + return; + } + + if (Obstacles.WALL_OBSTACLE_IDS.contains(newObject.getId()) || + Obstacles.TRAP_OBSTACLE_IDS.contains(newObject.getId())) + { + obstacles.put(newObject, tile); + } + } +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/questhelper/quests/cooksassistant/CooksAssistant.java b/runelite-client/src/main/java/net/runelite/client/plugins/questhelper/quests/cooksassistant/CooksAssistant.java index da55e5662e..4905524600 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/questhelper/quests/cooksassistant/CooksAssistant.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/questhelper/quests/cooksassistant/CooksAssistant.java @@ -1,58 +1,58 @@ -/* - * Copyright (c) 2019, Trevor - * 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.questhelper.quests.cooksassistant; - -import java.util.HashMap; -import java.util.Map; -import net.runelite.api.ItemID; -import net.runelite.api.NpcID; -import net.runelite.api.Quest; -import net.runelite.api.coords.WorldPoint; -import net.runelite.client.plugins.questhelper.ItemRequirement; -import net.runelite.client.plugins.questhelper.QuestHelper; -import net.runelite.client.plugins.questhelper.steps.NpcTalkStep; -import net.runelite.client.plugins.questhelper.steps.QuestStep; -import net.runelite.client.plugins.questhelper.QuestDescriptor; - -@QuestDescriptor( - quest = Quest.COOKS_ASSISTANT -) -public class CooksAssistant extends QuestHelper -{ - @Override - protected Map loadSteps() - { - Map steps = new HashMap<>(); - - steps.put(0, new NpcTalkStep(this, NpcID.COOK_4626, new WorldPoint(3206, 3214, 0), - "Give the Cook in Lumbridge Castle's kitchen the required items to finish the quest.", - new ItemRequirement(ItemID.BUCKET_OF_MILK), new ItemRequirement(ItemID.POT_OF_FLOUR), - new ItemRequirement(ItemID.EGG))); - - steps.put(1, steps.get(0)); - - return steps; - } +/* + * Copyright (c) 2019, Trevor + * 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.questhelper.quests.cooksassistant; + +import java.util.HashMap; +import java.util.Map; +import net.runelite.api.ItemID; +import net.runelite.api.NpcID; +import net.runelite.api.Quest; +import net.runelite.api.coords.WorldPoint; +import net.runelite.client.plugins.questhelper.ItemRequirement; +import net.runelite.client.plugins.questhelper.QuestDescriptor; +import net.runelite.client.plugins.questhelper.QuestHelper; +import net.runelite.client.plugins.questhelper.steps.NpcTalkStep; +import net.runelite.client.plugins.questhelper.steps.QuestStep; + +@QuestDescriptor( + quest = Quest.COOKS_ASSISTANT +) +public class CooksAssistant extends QuestHelper +{ + @Override + protected Map loadSteps() + { + Map steps = new HashMap<>(); + + steps.put(0, new NpcTalkStep(this, NpcID.COOK_4626, new WorldPoint(3206, 3214, 0), + "Give the Cook in Lumbridge Castle's kitchen the required items to finish the quest.", + new ItemRequirement(ItemID.BUCKET_OF_MILK), new ItemRequirement(ItemID.POT_OF_FLOUR), + new ItemRequirement(ItemID.EGG))); + + steps.put(1, steps.get(0)); + + return steps; + } } \ No newline at end of file diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/questhelper/quests/impcatcher/ImpCatcher.java b/runelite-client/src/main/java/net/runelite/client/plugins/questhelper/quests/impcatcher/ImpCatcher.java index 666fe7ea5f..8083582671 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/questhelper/quests/impcatcher/ImpCatcher.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/questhelper/quests/impcatcher/ImpCatcher.java @@ -1,58 +1,58 @@ -/* - * Copyright (c) 2019, Trevor - * 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.questhelper.quests.impcatcher; - -import java.util.HashMap; -import java.util.Map; -import net.runelite.api.ItemID; -import net.runelite.api.NpcID; -import net.runelite.api.Quest; -import net.runelite.api.coords.WorldPoint; -import net.runelite.client.plugins.questhelper.ItemRequirement; -import net.runelite.client.plugins.questhelper.QuestHelper; -import net.runelite.client.plugins.questhelper.steps.NpcTalkStep; -import net.runelite.client.plugins.questhelper.steps.QuestStep; -import net.runelite.client.plugins.questhelper.QuestDescriptor; - -@QuestDescriptor( - quest = Quest.IMP_CATCHER -) -public class ImpCatcher extends QuestHelper -{ - @Override - protected Map loadSteps() - { - Map steps = new HashMap<>(); - - steps.put(0, new NpcTalkStep(this, NpcID.WIZARD_MIZGOG, new WorldPoint(3103, 3163, 2), - "Talk to Wizard Mizgog on the top floor of the Wizards' Tower with the required items to finish the quest.", - new ItemRequirement(ItemID.BLACK_BEAD), new ItemRequirement(ItemID.WHITE_BEAD), - new ItemRequirement(ItemID.RED_BEAD), new ItemRequirement(ItemID.YELLOW_BEAD))); - - steps.put(1, steps.get(0)); - - return steps; - } -} +/* + * Copyright (c) 2019, Trevor + * 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.questhelper.quests.impcatcher; + +import java.util.HashMap; +import java.util.Map; +import net.runelite.api.ItemID; +import net.runelite.api.NpcID; +import net.runelite.api.Quest; +import net.runelite.api.coords.WorldPoint; +import net.runelite.client.plugins.questhelper.ItemRequirement; +import net.runelite.client.plugins.questhelper.QuestDescriptor; +import net.runelite.client.plugins.questhelper.QuestHelper; +import net.runelite.client.plugins.questhelper.steps.NpcTalkStep; +import net.runelite.client.plugins.questhelper.steps.QuestStep; + +@QuestDescriptor( + quest = Quest.IMP_CATCHER +) +public class ImpCatcher extends QuestHelper +{ + @Override + protected Map loadSteps() + { + Map steps = new HashMap<>(); + + steps.put(0, new NpcTalkStep(this, NpcID.WIZARD_MIZGOG, new WorldPoint(3103, 3163, 2), + "Talk to Wizard Mizgog on the top floor of the Wizards' Tower with the required items to finish the quest.", + new ItemRequirement(ItemID.BLACK_BEAD), new ItemRequirement(ItemID.WHITE_BEAD), + new ItemRequirement(ItemID.RED_BEAD), new ItemRequirement(ItemID.YELLOW_BEAD))); + + steps.put(1, steps.get(0)); + + return steps; + } +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/questhelper/quests/xmarksthespot/XMarksTheSpot.java b/runelite-client/src/main/java/net/runelite/client/plugins/questhelper/quests/xmarksthespot/XMarksTheSpot.java index e18fab85e0..f6b98a2e0d 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/questhelper/quests/xmarksthespot/XMarksTheSpot.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/questhelper/quests/xmarksthespot/XMarksTheSpot.java @@ -1,80 +1,80 @@ -/* - * Copyright (c) 2019, Trevor - * 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.questhelper.quests.xmarksthespot; - -import java.util.HashMap; -import java.util.Map; -import net.runelite.api.ItemID; -import net.runelite.api.NpcID; -import net.runelite.api.Quest; -import net.runelite.api.coords.WorldPoint; -import net.runelite.client.plugins.questhelper.ItemRequirement; -import net.runelite.client.plugins.questhelper.QuestHelper; -import net.runelite.client.plugins.questhelper.steps.DigStep; -import net.runelite.client.plugins.questhelper.steps.NpcTalkStep; -import net.runelite.client.plugins.questhelper.steps.QuestStep; -import net.runelite.client.plugins.questhelper.QuestDescriptor; - -@QuestDescriptor( - quest = Quest.X_MARKS_THE_SPOT -) -public class XMarksTheSpot extends QuestHelper -{ - @Override - protected Map loadSteps() - { - Map steps = new HashMap<>(); - - steps.put(0, new NpcTalkStep(this, NpcID.VEOS_8484, new WorldPoint(3228, 3242, 0), - "Talk to Veos in The Sheared Ram pub in Lumbridge to start the quest.")); - - steps.put(1, steps.get(0)); - - steps.put(2, new DigStep(this, new WorldPoint(3230, 3209, 0), - "Dig north of Bob's Brilliant Axes, on the west side of the plant against the wall of his house.", - new ItemRequirement(ItemID.TREASURE_SCROLL))); - - steps.put(3, new DigStep(this, new WorldPoint(3203, 3212, 0), - "Dig behind Lumbridge Castle, just outside the kitchen door.", - new ItemRequirement(ItemID.TREASURE_SCROLL_23068))); - - steps.put(4, new DigStep(this, new WorldPoint(3109, 3264, 0), - "Dig north-west of the Draynor Village jail, just by the wheat farm.", - new ItemRequirement(ItemID.MYSTERIOUS_ORB_23069))); - - steps.put(5, new DigStep(this, new WorldPoint(3078, 3259, 0), - "Dig in the pig pen just west where Martin the Master Gardener is.", - new ItemRequirement(ItemID.TREASURE_SCROLL_23070))); - - steps.put(6, new NpcTalkStep(this, NpcID.VEOS_8484, new WorldPoint(3054, 3245, 0), - "Talk to Veos directly south of the Rusty Anchor Inn in Port Sarim to finish the quest.", - new ItemRequirement(ItemID.ANCIENT_CASKET))); - - steps.put(7, new NpcTalkStep(this, NpcID.VEOS_8484, new WorldPoint(3054, 3245, 0), - "Talk to Veos directly south of the Rusty Anchor Inn in Port Sarim to finish the quest.")); - - return steps; - } -} +/* + * Copyright (c) 2019, Trevor + * 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.questhelper.quests.xmarksthespot; + +import java.util.HashMap; +import java.util.Map; +import net.runelite.api.ItemID; +import net.runelite.api.NpcID; +import net.runelite.api.Quest; +import net.runelite.api.coords.WorldPoint; +import net.runelite.client.plugins.questhelper.ItemRequirement; +import net.runelite.client.plugins.questhelper.QuestDescriptor; +import net.runelite.client.plugins.questhelper.QuestHelper; +import net.runelite.client.plugins.questhelper.steps.DigStep; +import net.runelite.client.plugins.questhelper.steps.NpcTalkStep; +import net.runelite.client.plugins.questhelper.steps.QuestStep; + +@QuestDescriptor( + quest = Quest.X_MARKS_THE_SPOT +) +public class XMarksTheSpot extends QuestHelper +{ + @Override + protected Map loadSteps() + { + Map steps = new HashMap<>(); + + steps.put(0, new NpcTalkStep(this, NpcID.VEOS_8484, new WorldPoint(3228, 3242, 0), + "Talk to Veos in The Sheared Ram pub in Lumbridge to start the quest.")); + + steps.put(1, steps.get(0)); + + steps.put(2, new DigStep(this, new WorldPoint(3230, 3209, 0), + "Dig north of Bob's Brilliant Axes, on the west side of the plant against the wall of his house.", + new ItemRequirement(ItemID.TREASURE_SCROLL))); + + steps.put(3, new DigStep(this, new WorldPoint(3203, 3212, 0), + "Dig behind Lumbridge Castle, just outside the kitchen door.", + new ItemRequirement(ItemID.TREASURE_SCROLL_23068))); + + steps.put(4, new DigStep(this, new WorldPoint(3109, 3264, 0), + "Dig north-west of the Draynor Village jail, just by the wheat farm.", + new ItemRequirement(ItemID.MYSTERIOUS_ORB_23069))); + + steps.put(5, new DigStep(this, new WorldPoint(3078, 3259, 0), + "Dig in the pig pen just west where Martin the Master Gardener is.", + new ItemRequirement(ItemID.TREASURE_SCROLL_23070))); + + steps.put(6, new NpcTalkStep(this, NpcID.VEOS_8484, new WorldPoint(3054, 3245, 0), + "Talk to Veos directly south of the Rusty Anchor Inn in Port Sarim to finish the quest.", + new ItemRequirement(ItemID.ANCIENT_CASKET))); + + steps.put(7, new NpcTalkStep(this, NpcID.VEOS_8484, new WorldPoint(3054, 3245, 0), + "Talk to Veos directly south of the Rusty Anchor Inn in Port Sarim to finish the quest.")); + + return steps; + } +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/questhelper/steps/NpcTalkStep.java b/runelite-client/src/main/java/net/runelite/client/plugins/questhelper/steps/NpcTalkStep.java index a42b4c7bf9..c5e87854c2 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/questhelper/steps/NpcTalkStep.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/questhelper/steps/NpcTalkStep.java @@ -1,161 +1,158 @@ -/* - * Copyright (c) 2019, Trevor - * 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.questhelper.steps; - -import java.awt.Color; -import java.awt.Graphics2D; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; -import javax.inject.Inject; -import net.runelite.api.Client; -import net.runelite.api.NPC; -import net.runelite.api.coords.WorldPoint; -import net.runelite.api.events.NpcDespawned; -import net.runelite.api.events.NpcSpawned; -import net.runelite.client.eventbus.Subscribe; -import net.runelite.client.game.ItemManager; -import net.runelite.client.plugins.questhelper.ItemRequirement; -import net.runelite.client.plugins.questhelper.QuestHelper; -import net.runelite.client.plugins.questhelper.QuestHelperPlugin; -import net.runelite.client.plugins.questhelper.QuestHelperWorldMapPoint; -import static net.runelite.client.plugins.questhelper.QuestHelperWorldOverlay.IMAGE_Z_OFFSET; -import net.runelite.client.ui.overlay.OverlayUtil; -import net.runelite.client.ui.overlay.components.LineComponent; -import net.runelite.client.ui.overlay.components.PanelComponent; -import net.runelite.client.ui.overlay.worldmap.WorldMapPointManager; - -public class NpcTalkStep extends QuestStep -{ - @Inject - protected Client client; - - @Inject - protected ItemManager itemManager; - - @Inject - protected WorldMapPointManager worldMapPointManager; - - private int npcID; - private WorldPoint worldPoint; - private List npcsToHighlight = new ArrayList<>(); - List itemRequirements; - - public NpcTalkStep(QuestHelper questHelper, int npcID, WorldPoint worldPoint, String text, ItemRequirement... itemRequirements) - { - super(questHelper, text); - this.npcID = npcID; - this.worldPoint = worldPoint; - this.itemRequirements = Arrays.asList(itemRequirements); - } - - @Override - public void startUp() throws Exception - { - for (NPC npc : client.getNpcs()) - { - if (npcID == npc.getId()) - { - npcsToHighlight.add(npc); - } - } - worldMapPointManager.add(new QuestHelperWorldMapPoint(worldPoint, getQuestImage())); - } - - @Override - public void shutDown() throws Exception - { - npcsToHighlight.clear(); - worldMapPointManager.removeIf(QuestHelperWorldMapPoint.class::isInstance); - } - - @Subscribe - public void onNpcSpawned(NpcSpawned event) - { - if (event.getNpc().getId() == npcID) - { - npcsToHighlight.add(event.getNpc()); - } - } - - @Subscribe - public void onNpcDespawned(NpcDespawned event) - { - if (npcsToHighlight.contains(event.getNpc())) - { - npcsToHighlight.remove(event.getNpc()); - } - } - - @Override - public void makeOverlayHint(PanelComponent panelComponent, QuestHelperPlugin plugin) - { - super.makeOverlayHint(panelComponent, plugin); - - if (itemRequirements.isEmpty()) - { - return; - } - - panelComponent.getChildren().add(LineComponent.builder().left("Required Items:").build()); - for (ItemRequirement itemRequirement : itemRequirements) - { - String text = itemRequirement.getQuantity() + " x " + itemManager.getItemComposition(itemRequirement.getId()).getName(); - Color color; - if (itemRequirement.check(client)) - { - color = Color.GREEN; - } - else - { - color = Color.RED; - } - panelComponent.getChildren().add(LineComponent.builder() - .left(text) - .leftColor(color) - .build()); - } - } - - @Override - public void makeWorldOverlayHint(Graphics2D graphics, QuestHelperPlugin plugin) - { - if (!worldPoint.isInScene(client)) - { - return; - } - - if (npcsToHighlight.isEmpty()) - { - return; - } - - for (NPC npc : npcsToHighlight) - { - OverlayUtil.renderActorOverlayImage(graphics, npc, getQuestImage(), Color.CYAN, IMAGE_Z_OFFSET); - } - - } -} +/* + * Copyright (c) 2019, Trevor + * 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.questhelper.steps; + +import java.awt.Color; +import java.awt.Graphics2D; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import javax.inject.Inject; +import net.runelite.api.Client; +import net.runelite.api.NPC; +import net.runelite.api.coords.WorldPoint; +import net.runelite.api.events.NpcDespawned; +import net.runelite.api.events.NpcSpawned; +import net.runelite.client.eventbus.Subscribe; +import net.runelite.client.game.ItemManager; +import net.runelite.client.plugins.questhelper.ItemRequirement; +import net.runelite.client.plugins.questhelper.QuestHelper; +import net.runelite.client.plugins.questhelper.QuestHelperPlugin; +import net.runelite.client.plugins.questhelper.QuestHelperWorldMapPoint; +import static net.runelite.client.plugins.questhelper.QuestHelperWorldOverlay.IMAGE_Z_OFFSET; +import net.runelite.client.ui.overlay.OverlayUtil; +import net.runelite.client.ui.overlay.components.LineComponent; +import net.runelite.client.ui.overlay.components.PanelComponent; +import net.runelite.client.ui.overlay.worldmap.WorldMapPointManager; + +public class NpcTalkStep extends QuestStep +{ + @Inject + protected Client client; + + @Inject + protected ItemManager itemManager; + + @Inject + protected WorldMapPointManager worldMapPointManager; + + private int npcID; + private WorldPoint worldPoint; + private List npcsToHighlight = new ArrayList<>(); + List itemRequirements; + + public NpcTalkStep(QuestHelper questHelper, int npcID, WorldPoint worldPoint, String text, ItemRequirement... itemRequirements) + { + super(questHelper, text); + this.npcID = npcID; + this.worldPoint = worldPoint; + this.itemRequirements = Arrays.asList(itemRequirements); + } + + @Override + public void startUp() throws Exception + { + for (NPC npc : client.getNpcs()) + { + if (npcID == npc.getId()) + { + npcsToHighlight.add(npc); + } + } + worldMapPointManager.add(new QuestHelperWorldMapPoint(worldPoint, getQuestImage())); + } + + @Override + public void shutDown() throws Exception + { + npcsToHighlight.clear(); + worldMapPointManager.removeIf(QuestHelperWorldMapPoint.class::isInstance); + } + + @Subscribe + public void onNpcSpawned(NpcSpawned event) + { + if (event.getNpc().getId() == npcID) + { + npcsToHighlight.add(event.getNpc()); + } + } + + @Subscribe + public void onNpcDespawned(NpcDespawned event) + { + npcsToHighlight.remove(event.getNpc()); + } + + @Override + public void makeOverlayHint(PanelComponent panelComponent, QuestHelperPlugin plugin) + { + super.makeOverlayHint(panelComponent, plugin); + + if (itemRequirements.isEmpty()) + { + return; + } + + panelComponent.getChildren().add(LineComponent.builder().left("Required Items:").build()); + for (ItemRequirement itemRequirement : itemRequirements) + { + String text = itemRequirement.getQuantity() + " x " + itemManager.getItemComposition(itemRequirement.getId()).getName(); + Color color; + if (itemRequirement.check(client)) + { + color = Color.GREEN; + } + else + { + color = Color.RED; + } + panelComponent.getChildren().add(LineComponent.builder() + .left(text) + .leftColor(color) + .build()); + } + } + + @Override + public void makeWorldOverlayHint(Graphics2D graphics, QuestHelperPlugin plugin) + { + if (!worldPoint.isInScene(client)) + { + return; + } + + if (npcsToHighlight.isEmpty()) + { + return; + } + + for (NPC npc : npcsToHighlight) + { + OverlayUtil.renderActorOverlayImage(graphics, npc, getQuestImage(), Color.CYAN, IMAGE_Z_OFFSET); + } + + } +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/questlist/QuestListPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/questlist/QuestListPlugin.java index 2ebf2a4318..20871956d9 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/questlist/QuestListPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/questlist/QuestListPlugin.java @@ -1,398 +1,398 @@ -/* - * Copyright (c) 2019 Spudjb - * 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.questlist; - -import com.google.common.collect.ImmutableList; -import lombok.AllArgsConstructor; -import lombok.Data; -import lombok.Getter; -import net.runelite.api.Client; -import net.runelite.api.GameState; -import net.runelite.api.ScriptID; -import net.runelite.api.SoundEffectID; -import net.runelite.api.SpriteID; -import net.runelite.api.VarClientInt; -import net.runelite.api.Varbits; -import net.runelite.api.events.GameStateChanged; -import net.runelite.api.events.ScriptCallbackEvent; -import net.runelite.api.events.VarClientIntChanged; -import net.runelite.api.events.VarbitChanged; -import net.runelite.api.widgets.JavaScriptCallback; -import net.runelite.api.widgets.Widget; -import net.runelite.api.widgets.WidgetInfo; -import net.runelite.api.widgets.WidgetPositionMode; -import net.runelite.api.widgets.WidgetType; -import net.runelite.client.callback.ClientThread; -import net.runelite.client.eventbus.Subscribe; -import net.runelite.client.game.chatbox.ChatboxPanelManager; -import net.runelite.client.game.chatbox.ChatboxTextInput; -import net.runelite.client.plugins.Plugin; -import net.runelite.client.plugins.PluginDescriptor; -import net.runelite.client.util.Text; -import javax.inject.Inject; -import java.util.Arrays; -import java.util.Collection; -import java.util.Comparator; -import java.util.EnumMap; -import java.util.List; -import java.util.stream.Collectors; - -@PluginDescriptor( - name = "Quest List", - description = "Adds searching and filtering to the quest list" -) -public class QuestListPlugin extends Plugin -{ - private static final int ENTRY_PADDING = 8; - private static final List QUEST_HEADERS = ImmutableList.of("Free Quests", "Members' Quests", "Miniquests"); - - private static final String MENU_OPEN = "Open"; - private static final String MENU_CLOSE = "Close"; - - private static final String MENU_TOGGLE = "Toggle"; - - private static final String MENU_SEARCH = "Search"; - private static final String MENU_SHOW = "Show"; - - @Inject - private Client client; - - @Inject - private ChatboxPanelManager chatboxPanelManager; - - @Inject - private ClientThread clientThread; - - private ChatboxTextInput searchInput; - private Widget questSearchButton; - private Widget questHideButton; - - private EnumMap> questSet; - - private QuestState currentFilterState; - - @Subscribe - public void onGameStateChanged(GameStateChanged e) - { - if (e.getGameState() == GameState.LOGGING_IN) - { - currentFilterState = QuestState.ALL; - } - } - - @Subscribe - public void onScriptCallbackEvent(ScriptCallbackEvent event) - { - if (!event.getEventName().equals("questProgressUpdated")) - { - return; - } - - Widget header = client.getWidget(WidgetInfo.QUESTLIST_BOX); - if (header != null) - { - questSearchButton = header.createChild(-1, WidgetType.GRAPHIC); - questSearchButton.setSpriteId(SpriteID.GE_SEARCH); - questSearchButton.setOriginalWidth(18); - questSearchButton.setOriginalHeight(17); - questSearchButton.setXPositionMode(WidgetPositionMode.ABSOLUTE_RIGHT); - questSearchButton.setOriginalX(5); - questSearchButton.setOriginalY(0); - questSearchButton.setHasListener(true); - questSearchButton.setAction(1, MENU_OPEN); - questSearchButton.setOnOpListener((JavaScriptCallback) e -> openSearch()); - questSearchButton.setName(MENU_SEARCH); - questSearchButton.revalidate(); - - questHideButton = header.createChild(-1, WidgetType.GRAPHIC); - redrawHideButton(); - - questHideButton.setOriginalWidth(13); - questHideButton.setOriginalHeight(13); - questHideButton.setXPositionMode(WidgetPositionMode.ABSOLUTE_RIGHT); - questHideButton.setOriginalX(24); - questHideButton.setOriginalY(2); - questHideButton.setHasListener(true); - questHideButton.setOnOpListener((JavaScriptCallback) e -> toggleHidden()); - questHideButton.setAction(1, MENU_TOGGLE); - questHideButton.revalidate(); - - questSet = new EnumMap<>(QuestContainer.class); - - updateFilter(); - } - } - - @Subscribe - public void onVarbitChanged(VarbitChanged varbitChanged) - { - if (isChatboxOpen() && !isOnQuestTab()) - { - chatboxPanelManager.close(); - } - } - - @Subscribe - public void onVarClientIntChanged(VarClientIntChanged varClientIntChanged) - { - if (varClientIntChanged.getIndex() == VarClientInt.INVENTORY_TAB.getIndex()) - { - if (isChatboxOpen() && !isOnQuestTab()) - { - chatboxPanelManager.close(); - } - } - } - - private void toggleHidden() - { - QuestState[] questStates = QuestState.values(); - int nextState = (currentFilterState.ordinal() + 1) % questStates.length; - currentFilterState = questStates[nextState]; - - redrawHideButton(); - - updateFilter(); - client.playSoundEffect(SoundEffectID.UI_BOOP); - } - - private void redrawHideButton() - { - questHideButton.setSpriteId(currentFilterState.getSpriteId()); - questHideButton.setName(MENU_SHOW + " " + currentFilterState.getName()); - } - - private boolean isOnQuestTab() - { - return client.getVar(Varbits.QUEST_TAB) == 0 && client.getVar(VarClientInt.INVENTORY_TAB) == 2; - } - - private boolean isChatboxOpen() - { - return searchInput != null && chatboxPanelManager.getCurrentInput() == searchInput; - } - - private void closeSearch() - { - updateFilter(""); - chatboxPanelManager.close(); - client.playSoundEffect(SoundEffectID.UI_BOOP); - } - - private void openSearch() - { - updateFilter(""); - client.playSoundEffect(SoundEffectID.UI_BOOP); - questSearchButton.setAction(1, MENU_CLOSE); - questSearchButton.setOnOpListener((JavaScriptCallback) e -> closeSearch()); - searchInput = chatboxPanelManager.openTextInput("Search quest list") - .onChanged(s -> clientThread.invokeLater(() -> updateFilter(s))) - .onClose(() -> - { - clientThread.invokeLater(() -> updateFilter("")); - questSearchButton.setOnOpListener((JavaScriptCallback) e -> openSearch()); - questSearchButton.setAction(1, MENU_OPEN); - }) - .build(); - } - - private void updateFilter() - { - String filter = ""; - if (isChatboxOpen()) - { - filter = searchInput.getValue(); - } - - updateFilter(filter); - } - - private void updateFilter(String filter) - { - filter = filter.toLowerCase(); - final Widget container = client.getWidget(WidgetInfo.QUESTLIST_CONTAINER); - - final Widget freeList = client.getWidget(QuestContainer.FREE_QUESTS.widgetInfo); - final Widget memberList = client.getWidget(QuestContainer.MEMBER_QUESTS.widgetInfo); - final Widget miniList = client.getWidget(QuestContainer.MINI_QUESTS.widgetInfo); - - if (container == null || freeList == null || memberList == null || miniList == null) - { - return; - } - - updateList(QuestContainer.FREE_QUESTS, filter); - updateList(QuestContainer.MEMBER_QUESTS, filter); - updateList(QuestContainer.MINI_QUESTS, filter); - - memberList.setOriginalY(freeList.getOriginalY() + freeList.getOriginalHeight() + ENTRY_PADDING); - miniList.setOriginalY(memberList.getOriginalY() + memberList.getOriginalHeight() + ENTRY_PADDING); - - // originalHeight is changed within updateList so revalidate all lists - freeList.revalidate(); - memberList.revalidate(); - miniList.revalidate(); - - int y = miniList.getRelativeY() + miniList.getHeight() + 10; - - int newHeight; - if (container.getScrollHeight() > 0) - { - newHeight = (container.getScrollY() * y) / container.getScrollHeight(); - } - else - { - newHeight = 0; - } - - container.setScrollHeight(y); - container.revalidateScroll(); - - clientThread.invokeLater(() -> - client.runScript( - ScriptID.UPDATE_SCROLLBAR, - WidgetInfo.QUESTLIST_SCROLLBAR.getId(), - WidgetInfo.QUESTLIST_CONTAINER.getId(), - newHeight - )); - } - - private void updateList(QuestContainer questContainer, String filter) - { - Widget list = client.getWidget(questContainer.widgetInfo); - if (list == null) - { - return; - } - - Collection quests = questSet.get(questContainer); - - if (quests != null) - { - // Check to make sure the list hasn't been rebuild since we were last her - // Do this by making sure the list's dynamic children are the same as when we last saw them - if (quests.stream().noneMatch(w -> - { - Widget codeWidget = w.getQuest(); - if (codeWidget == null) - { - return false; - } - return list.getChild(codeWidget.getIndex()) == codeWidget; - })) - { - quests = null; - } - } - - if (quests == null) - { - // Find all of the widgets that we care about, sorting by their Y value - quests = Arrays.stream(list.getDynamicChildren()) - .sorted(Comparator.comparing(Widget::getRelativeY)) - .filter(w -> !QUEST_HEADERS.contains(w.getText())) - .map(w -> new QuestWidget(w, Text.removeTags(w.getText()).toLowerCase())) - .collect(Collectors.toList()); - questSet.put(questContainer, quests); - } - - // offset because of header - int y = 20; - for (QuestWidget questInfo : quests) - { - Widget quest = questInfo.getQuest(); - QuestState questState = QuestState.getByColor(quest.getTextColor()); - - boolean hidden; - if (!filter.isEmpty()) - { - // If searching, show result regardless of filtered state - hidden = !questInfo.getTitle().contains(filter); - } - else - { - // Otherwise hide if it doesn't match the filter state - hidden = currentFilterState != QuestState.ALL && questState != currentFilterState; - } - - quest.setHidden(hidden); - quest.setOriginalY(y); - quest.revalidate(); - - if (!hidden) - { - y += quest.getHeight(); - } - } - - list.setOriginalHeight(y); - } - - @AllArgsConstructor - @Getter - private enum QuestContainer - { - FREE_QUESTS(WidgetInfo.QUESTLIST_FREE_CONTAINER), - MEMBER_QUESTS(WidgetInfo.QUESTLIST_MEMBERS_CONTAINER), - MINI_QUESTS(WidgetInfo.QUESTLIST_MINIQUEST_CONTAINER); - - private final WidgetInfo widgetInfo; - } - - @AllArgsConstructor - @Getter - private enum QuestState - { - NOT_STARTED(0xff0000, "Not started", SpriteID.MINIMAP_ORB_HITPOINTS), - IN_PROGRESS(0xffff00, "In progress", SpriteID.MINIMAP_ORB_HITPOINTS_DISEASE), - COMPLETE(0xdc10d, "Completed", SpriteID.MINIMAP_ORB_HITPOINTS_POISON), - ALL(0, "All", SpriteID.MINIMAP_ORB_PRAYER); - - private final int color; - private final String name; - private final int spriteId; - - static QuestState getByColor(int color) - { - for (QuestState value : values()) - { - if (value.getColor() == color) - { - return value; - } - } - - return null; - } - } - - @Data - @AllArgsConstructor - private static class QuestWidget - { - private Widget quest; - private String title; - } -} +/* + * Copyright (c) 2019 Spudjb + * 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.questlist; + +import com.google.common.collect.ImmutableList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Comparator; +import java.util.EnumMap; +import java.util.List; +import java.util.stream.Collectors; +import javax.inject.Inject; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.Getter; +import net.runelite.api.Client; +import net.runelite.api.GameState; +import net.runelite.api.ScriptID; +import net.runelite.api.SoundEffectID; +import net.runelite.api.SpriteID; +import net.runelite.api.VarClientInt; +import net.runelite.api.Varbits; +import net.runelite.api.events.GameStateChanged; +import net.runelite.api.events.ScriptCallbackEvent; +import net.runelite.api.events.VarClientIntChanged; +import net.runelite.api.events.VarbitChanged; +import net.runelite.api.widgets.JavaScriptCallback; +import net.runelite.api.widgets.Widget; +import net.runelite.api.widgets.WidgetInfo; +import net.runelite.api.widgets.WidgetPositionMode; +import net.runelite.api.widgets.WidgetType; +import net.runelite.client.callback.ClientThread; +import net.runelite.client.eventbus.Subscribe; +import net.runelite.client.game.chatbox.ChatboxPanelManager; +import net.runelite.client.game.chatbox.ChatboxTextInput; +import net.runelite.client.plugins.Plugin; +import net.runelite.client.plugins.PluginDescriptor; +import net.runelite.client.util.Text; + +@PluginDescriptor( + name = "Quest List", + description = "Adds searching and filtering to the quest list" +) +public class QuestListPlugin extends Plugin +{ + private static final int ENTRY_PADDING = 8; + private static final List QUEST_HEADERS = ImmutableList.of("Free Quests", "Members' Quests", "Miniquests"); + + private static final String MENU_OPEN = "Open"; + private static final String MENU_CLOSE = "Close"; + + private static final String MENU_TOGGLE = "Toggle"; + + private static final String MENU_SEARCH = "Search"; + private static final String MENU_SHOW = "Show"; + + @Inject + private Client client; + + @Inject + private ChatboxPanelManager chatboxPanelManager; + + @Inject + private ClientThread clientThread; + + private ChatboxTextInput searchInput; + private Widget questSearchButton; + private Widget questHideButton; + + private EnumMap> questSet; + + private QuestState currentFilterState; + + @Subscribe + public void onGameStateChanged(GameStateChanged e) + { + if (e.getGameState() == GameState.LOGGING_IN) + { + currentFilterState = QuestState.ALL; + } + } + + @Subscribe + public void onScriptCallbackEvent(ScriptCallbackEvent event) + { + if (!event.getEventName().equals("questProgressUpdated")) + { + return; + } + + Widget header = client.getWidget(WidgetInfo.QUESTLIST_BOX); + if (header != null) + { + questSearchButton = header.createChild(-1, WidgetType.GRAPHIC); + questSearchButton.setSpriteId(SpriteID.GE_SEARCH); + questSearchButton.setOriginalWidth(18); + questSearchButton.setOriginalHeight(17); + questSearchButton.setXPositionMode(WidgetPositionMode.ABSOLUTE_RIGHT); + questSearchButton.setOriginalX(5); + questSearchButton.setOriginalY(0); + questSearchButton.setHasListener(true); + questSearchButton.setAction(1, MENU_OPEN); + questSearchButton.setOnOpListener((JavaScriptCallback) e -> openSearch()); + questSearchButton.setName(MENU_SEARCH); + questSearchButton.revalidate(); + + questHideButton = header.createChild(-1, WidgetType.GRAPHIC); + redrawHideButton(); + + questHideButton.setOriginalWidth(13); + questHideButton.setOriginalHeight(13); + questHideButton.setXPositionMode(WidgetPositionMode.ABSOLUTE_RIGHT); + questHideButton.setOriginalX(24); + questHideButton.setOriginalY(2); + questHideButton.setHasListener(true); + questHideButton.setOnOpListener((JavaScriptCallback) e -> toggleHidden()); + questHideButton.setAction(1, MENU_TOGGLE); + questHideButton.revalidate(); + + questSet = new EnumMap<>(QuestContainer.class); + + updateFilter(); + } + } + + @Subscribe + public void onVarbitChanged(VarbitChanged varbitChanged) + { + if (isChatboxOpen() && !isOnQuestTab()) + { + chatboxPanelManager.close(); + } + } + + @Subscribe + public void onVarClientIntChanged(VarClientIntChanged varClientIntChanged) + { + if (varClientIntChanged.getIndex() == VarClientInt.INVENTORY_TAB.getIndex()) + { + if (isChatboxOpen() && !isOnQuestTab()) + { + chatboxPanelManager.close(); + } + } + } + + private void toggleHidden() + { + QuestState[] questStates = QuestState.values(); + int nextState = (currentFilterState.ordinal() + 1) % questStates.length; + currentFilterState = questStates[nextState]; + + redrawHideButton(); + + updateFilter(); + client.playSoundEffect(SoundEffectID.UI_BOOP); + } + + private void redrawHideButton() + { + questHideButton.setSpriteId(currentFilterState.getSpriteId()); + questHideButton.setName(MENU_SHOW + " " + currentFilterState.getName()); + } + + private boolean isOnQuestTab() + { + return client.getVar(Varbits.QUEST_TAB) == 0 && client.getVar(VarClientInt.INVENTORY_TAB) == 2; + } + + private boolean isChatboxOpen() + { + return searchInput != null && chatboxPanelManager.getCurrentInput() == searchInput; + } + + private void closeSearch() + { + updateFilter(""); + chatboxPanelManager.close(); + client.playSoundEffect(SoundEffectID.UI_BOOP); + } + + private void openSearch() + { + updateFilter(""); + client.playSoundEffect(SoundEffectID.UI_BOOP); + questSearchButton.setAction(1, MENU_CLOSE); + questSearchButton.setOnOpListener((JavaScriptCallback) e -> closeSearch()); + searchInput = chatboxPanelManager.openTextInput("Search quest list") + .onChanged(s -> clientThread.invokeLater(() -> updateFilter(s))) + .onClose(() -> + { + clientThread.invokeLater(() -> updateFilter("")); + questSearchButton.setOnOpListener((JavaScriptCallback) e -> openSearch()); + questSearchButton.setAction(1, MENU_OPEN); + }) + .build(); + } + + private void updateFilter() + { + String filter = ""; + if (isChatboxOpen()) + { + filter = searchInput.getValue(); + } + + updateFilter(filter); + } + + private void updateFilter(String filter) + { + filter = filter.toLowerCase(); + final Widget container = client.getWidget(WidgetInfo.QUESTLIST_CONTAINER); + + final Widget freeList = client.getWidget(QuestContainer.FREE_QUESTS.widgetInfo); + final Widget memberList = client.getWidget(QuestContainer.MEMBER_QUESTS.widgetInfo); + final Widget miniList = client.getWidget(QuestContainer.MINI_QUESTS.widgetInfo); + + if (container == null || freeList == null || memberList == null || miniList == null) + { + return; + } + + updateList(QuestContainer.FREE_QUESTS, filter); + updateList(QuestContainer.MEMBER_QUESTS, filter); + updateList(QuestContainer.MINI_QUESTS, filter); + + memberList.setOriginalY(freeList.getOriginalY() + freeList.getOriginalHeight() + ENTRY_PADDING); + miniList.setOriginalY(memberList.getOriginalY() + memberList.getOriginalHeight() + ENTRY_PADDING); + + // originalHeight is changed within updateList so revalidate all lists + freeList.revalidate(); + memberList.revalidate(); + miniList.revalidate(); + + int y = miniList.getRelativeY() + miniList.getHeight() + 10; + + int newHeight; + if (container.getScrollHeight() > 0) + { + newHeight = (container.getScrollY() * y) / container.getScrollHeight(); + } + else + { + newHeight = 0; + } + + container.setScrollHeight(y); + container.revalidateScroll(); + + clientThread.invokeLater(() -> + client.runScript( + ScriptID.UPDATE_SCROLLBAR, + WidgetInfo.QUESTLIST_SCROLLBAR.getId(), + WidgetInfo.QUESTLIST_CONTAINER.getId(), + newHeight + )); + } + + private void updateList(QuestContainer questContainer, String filter) + { + Widget list = client.getWidget(questContainer.widgetInfo); + if (list == null) + { + return; + } + + Collection quests = questSet.get(questContainer); + + if (quests != null) + { + // Check to make sure the list hasn't been rebuild since we were last her + // Do this by making sure the list's dynamic children are the same as when we last saw them + if (quests.stream().noneMatch(w -> + { + Widget codeWidget = w.getQuest(); + if (codeWidget == null) + { + return false; + } + return list.getChild(codeWidget.getIndex()) == codeWidget; + })) + { + quests = null; + } + } + + if (quests == null) + { + // Find all of the widgets that we care about, sorting by their Y value + quests = Arrays.stream(list.getDynamicChildren()) + .sorted(Comparator.comparing(Widget::getRelativeY)) + .filter(w -> !QUEST_HEADERS.contains(w.getText())) + .map(w -> new QuestWidget(w, Text.removeTags(w.getText()).toLowerCase())) + .collect(Collectors.toList()); + questSet.put(questContainer, quests); + } + + // offset because of header + int y = 20; + for (QuestWidget questInfo : quests) + { + Widget quest = questInfo.getQuest(); + QuestState questState = QuestState.getByColor(quest.getTextColor()); + + boolean hidden; + if (!filter.isEmpty()) + { + // If searching, show result regardless of filtered state + hidden = !questInfo.getTitle().contains(filter); + } + else + { + // Otherwise hide if it doesn't match the filter state + hidden = currentFilterState != QuestState.ALL && questState != currentFilterState; + } + + quest.setHidden(hidden); + quest.setOriginalY(y); + quest.revalidate(); + + if (!hidden) + { + y += quest.getHeight(); + } + } + + list.setOriginalHeight(y); + } + + @AllArgsConstructor + @Getter + private enum QuestContainer + { + FREE_QUESTS(WidgetInfo.QUESTLIST_FREE_CONTAINER), + MEMBER_QUESTS(WidgetInfo.QUESTLIST_MEMBERS_CONTAINER), + MINI_QUESTS(WidgetInfo.QUESTLIST_MINIQUEST_CONTAINER); + + private final WidgetInfo widgetInfo; + } + + @AllArgsConstructor + @Getter + private enum QuestState + { + NOT_STARTED(0xff0000, "Not started", SpriteID.MINIMAP_ORB_HITPOINTS), + IN_PROGRESS(0xffff00, "In progress", SpriteID.MINIMAP_ORB_HITPOINTS_DISEASE), + COMPLETE(0xdc10d, "Completed", SpriteID.MINIMAP_ORB_HITPOINTS_POISON), + ALL(0, "All", SpriteID.MINIMAP_ORB_PRAYER); + + private final int color; + private final String name; + private final int spriteId; + + static QuestState getByColor(int color) + { + for (QuestState value : values()) + { + if (value.getColor() == color) + { + return value; + } + } + + return null; + } + } + + @Data + @AllArgsConstructor + private static class QuestWidget + { + private Widget quest; + private String title; + } +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/raids/RaidsConfig.java b/runelite-client/src/main/java/net/runelite/client/plugins/raids/RaidsConfig.java index 4adc61df11..14f5add239 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/raids/RaidsConfig.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/raids/RaidsConfig.java @@ -25,12 +25,9 @@ package net.runelite.client.plugins.raids; import java.awt.Color; -import java.awt.event.InputEvent; -import java.awt.event.KeyEvent; import net.runelite.client.config.Config; import net.runelite.client.config.ConfigGroup; import net.runelite.client.config.ConfigItem; -import net.runelite.client.config.Keybind; @ConfigGroup("raids") public interface RaidsConfig extends Config @@ -189,6 +186,7 @@ public interface RaidsConfig extends Config { return true; } + @ConfigItem( position = 16, keyName = "showRecommendedItems", @@ -300,10 +298,10 @@ public interface RaidsConfig extends Config } @ConfigItem( - position = 26, - keyName = "displayFloorBreak", - name = "Layout floor break", - description = "Displays floor break in layout" + position = 26, + keyName = "displayFloorBreak", + name = "Layout floor break", + description = "Displays floor break in layout" ) default boolean displayFloorBreak() { diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/raids/RaidsOverlay.java b/runelite-client/src/main/java/net/runelite/client/plugins/raids/RaidsOverlay.java index 98fc24efa9..de7fd5779a 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/raids/RaidsOverlay.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/raids/RaidsOverlay.java @@ -24,31 +24,35 @@ */ package net.runelite.client.plugins.raids; +import java.awt.Color; +import java.awt.Dimension; +import java.awt.Graphics2D; import java.awt.Point; import java.awt.image.BufferedImage; import java.util.ArrayList; import java.util.HashSet; import java.util.List; import java.util.Set; +import javax.inject.Inject; import lombok.Getter; import lombok.Setter; -import java.awt.Color; -import java.awt.Dimension; -import java.awt.Graphics2D; -import javax.inject.Inject; import net.runelite.api.Client; +import static net.runelite.api.MenuAction.RUNELITE_OVERLAY_CONFIG; import net.runelite.api.SpriteID; import net.runelite.api.widgets.WidgetInfo; import net.runelite.client.game.ItemManager; import net.runelite.client.game.SpriteManager; -import static net.runelite.api.MenuAction.RUNELITE_OVERLAY_CONFIG; import net.runelite.client.plugins.raids.solver.Room; import net.runelite.client.ui.overlay.Overlay; import static net.runelite.client.ui.overlay.OverlayManager.OPTION_CONFIGURE; import net.runelite.client.ui.overlay.OverlayMenuEntry; import net.runelite.client.ui.overlay.OverlayPosition; import net.runelite.client.ui.overlay.OverlayPriority; -import net.runelite.client.ui.overlay.components.*; +import net.runelite.client.ui.overlay.components.ComponentOrientation; +import net.runelite.client.ui.overlay.components.ImageComponent; +import net.runelite.client.ui.overlay.components.LineComponent; +import net.runelite.client.ui.overlay.components.PanelComponent; +import net.runelite.client.ui.overlay.components.TitleComponent; import net.runelite.client.util.ImageUtil; import net.runelite.client.util.Text; @@ -191,7 +195,9 @@ public class RaidsOverlay extends Overlay roomCount++; } if (tightrope) + { puzzles = crabs ? "cr" : iceDemon ? "ri" : thieving ? "tr" : "?r"; + } else if (config.hideRopeless()) { panelComponent.getChildren().add(TitleComponent.builder() @@ -211,7 +217,9 @@ public class RaidsOverlay extends Overlay for (Integer s : scavRooms) { if (s > i) + { break; + } prev = s; } scavsBeforeIceRooms.add(prev); @@ -280,7 +288,9 @@ public class RaidsOverlay extends Overlay if (config.showRecommendedItems()) { if (plugin.getRecommendedItemsList().get(bossNameLC) != null) + { imageIds.addAll(plugin.getRecommendedItemsList().get(bossNameLC)); + } } panelComponent.getChildren().add(LineComponent.builder() @@ -295,7 +305,9 @@ public class RaidsOverlay extends Overlay String puzzleName = room.getPuzzle().getName(); String puzzleNameLC = puzzleName.toLowerCase(); if (plugin.getRecommendedItemsList().get(puzzleNameLC) != null) + { imageIds.addAll(plugin.getRecommendedItemsList().get(puzzleNameLC)); + } if (plugin.getRoomWhitelist().contains(puzzleNameLC)) { color = Color.GREEN; @@ -370,7 +382,7 @@ public class RaidsOverlay extends Overlay panelImages.setPreferredLocation(new Point(0, imagesVerticalOffset)); panelImages.setBackgroundColor(null); - if (2 * (imagesMaxHeight / ICON_SIZE) >= idArray.length ) + if (2 * (imagesMaxHeight / ICON_SIZE) >= idArray.length) { panelImages.setWrapping(2); } @@ -399,15 +411,25 @@ public class RaidsOverlay extends Overlay { BufferedImage bim; if (id != SpriteID.SPELL_ICE_BARRAGE) + { bim = itemManager.getImage(id); + } else + { bim = spriteManager.getSprite(id, 0); + } if (bim == null) + { return null; + } if (!small) + { return ImageUtil.resizeCanvas(bim, ICON_SIZE, ICON_SIZE); + } if (id != SpriteID.SPELL_ICE_BARRAGE) + { return ImageUtil.resizeImage(bim, SMALL_ICON_SIZE, SMALL_ICON_SIZE); + } return ImageUtil.resizeCanvas(bim, SMALL_ICON_SIZE, SMALL_ICON_SIZE); } } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/raids/RaidsPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/raids/RaidsPlugin.java index 5729d20cd6..66becd116f 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/raids/RaidsPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/raids/RaidsPlugin.java @@ -1,872 +1,879 @@ -/* - * Copyright (c) 2018, Kamiel - * 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.raids; - -import com.google.inject.Binder; -import com.google.inject.Provides; -import java.awt.Color; -import java.awt.Graphics2D; -import java.awt.Rectangle; -import java.awt.image.BufferedImage; -import java.text.DecimalFormat; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.concurrent.ScheduledExecutorService; -import java.util.regex.Matcher; -import java.util.regex.Pattern; -import javax.inject.Inject; -import lombok.Getter; -import lombok.extern.slf4j.Slf4j; -import net.runelite.api.ChatMessageType; -import net.runelite.api.Client; -import net.runelite.api.GameState; -import net.runelite.api.InstanceTemplates; -import net.runelite.api.ItemID; -import net.runelite.api.NullObjectID; -import static net.runelite.api.Perspective.SCENE_SIZE; -import net.runelite.api.Point; -import net.runelite.api.SpriteID; -import static net.runelite.api.SpriteID.TAB_QUESTS_BROWN_RAIDING_PARTY; -import net.runelite.api.Tile; -import net.runelite.api.VarPlayer; -import net.runelite.api.Varbits; -import net.runelite.api.events.ChatMessage; -import net.runelite.api.events.ClientTick; -import net.runelite.api.events.ConfigChanged; -import net.runelite.api.events.VarbitChanged; -import net.runelite.api.events.WidgetHiddenChanged; -import net.runelite.api.widgets.Widget; -import net.runelite.api.widgets.WidgetInfo; -import net.runelite.api.widgets.WidgetInfo; -import net.runelite.client.callback.ClientThread; -import net.runelite.client.chat.ChatColorType; -import net.runelite.client.chat.ChatMessageBuilder; -import net.runelite.client.chat.ChatMessageManager; -import net.runelite.client.chat.QueuedMessage; -import net.runelite.client.config.ConfigManager; -import net.runelite.client.game.ItemManager; -import net.runelite.client.eventbus.Subscribe; -import net.runelite.client.game.SpriteManager; -import net.runelite.client.input.KeyManager; -import net.runelite.client.plugins.Plugin; -import net.runelite.client.plugins.PluginDescriptor; -import net.runelite.client.plugins.PluginType; -import net.runelite.client.plugins.raids.solver.Layout; -import net.runelite.client.plugins.raids.solver.LayoutSolver; -import net.runelite.client.plugins.raids.solver.RotationSolver; -import net.runelite.client.ui.ClientToolbar; -import net.runelite.client.ui.DrawManager; -import net.runelite.client.ui.FontManager; -import net.runelite.client.ui.NavigationButton; -import net.runelite.client.ui.overlay.OverlayManager; -import net.runelite.client.ui.overlay.WidgetOverlay; -import net.runelite.client.ui.overlay.infobox.InfoBoxManager; -import net.runelite.client.ui.overlay.tooltip.Tooltip; -import net.runelite.client.ui.overlay.tooltip.TooltipManager; -import net.runelite.client.util.ImageUtil; -import net.runelite.client.util.Text; -import net.runelite.client.util.HotkeyListener; -import org.apache.commons.lang3.StringUtils; - -@PluginDescriptor( - name = "Chambers Of Xeric", - description = "Show helpful information for the Chambers of Xeric raid", - tags = {"combat", "raid", "overlay", "pve", "pvm", "bosses", "cox", "olm"}, - type = PluginType.PVM -) -@Slf4j -public class RaidsPlugin extends Plugin -{ - private static final int LOBBY_PLANE = 3; - private static final DecimalFormat DECIMAL_FORMAT = new DecimalFormat("###.##"); - static final DecimalFormat POINTS_FORMAT = new DecimalFormat("#,###"); - private static final String SPLIT_REGEX = "\\s*,\\s*"; - private static final Pattern ROTATION_REGEX = Pattern.compile("\\[(.*?)]"); - private static final int LINE_COMPONENT_HEIGHT = 16; - - @Inject - private ItemManager itemManager; - private static final Pattern LEVEL_COMPLETE_REGEX = Pattern.compile("(.+) level complete! Duration: ([0-9:]+)"); - private static final Pattern RAID_COMPLETE_REGEX = Pattern.compile("Congratulations - your raid is complete! Duration: ([0-9:]+)"); - - @Inject - private ChatMessageManager chatMessageManager; - - @Inject - private InfoBoxManager infoBoxManager; - - @Inject - private Client client; - - @Inject - private DrawManager drawManager; - - @Inject - private ScheduledExecutorService executor; - - @Inject - private RaidsConfig config; - - @Inject - private OverlayManager overlayManager; - - @Inject - private RaidsOverlay overlay; - - @Inject - private RaidsPointsOverlay pointsOverlay; - - @Inject - private LayoutSolver layoutSolver; - - @Inject - private SpriteManager spriteManager; - - @Inject - private ClientThread clientThread; - - @Inject - private KeyManager keyManager; - - @Inject - private TooltipManager tooltipManager; - - @Getter - private final ArrayList roomWhitelist = new ArrayList<>(); - - @Getter - private final ArrayList roomBlacklist = new ArrayList<>(); - - @Getter - private final ArrayList rotationWhitelist = new ArrayList<>(); - - @Getter - private final ArrayList layoutWhitelist = new ArrayList<>(); - - @Getter - private final Map> recommendedItemsList = new HashMap<>(); - - @Getter - private Raid raid; - - @Getter - private boolean inRaidChambers; - - @Inject - private ClientToolbar clientToolbar; - private RaidsPanel panel; - private int upperTime = -1; - private int middleTime = -1; - private int lowerTime = -1; - private int raidTime = -1; - private WidgetOverlay widgetOverlay; - private String tooltip; - public boolean canShow; - private NavigationButton navButton; - - @Provides - RaidsConfig provideConfig(ConfigManager configManager) - { - return configManager.getConfig(RaidsConfig.class); - } - - @Override - public void configure(Binder binder) - { - binder.bind(RaidsOverlay.class); - } - - @Override - protected void startUp() throws Exception - { - overlayManager.add(overlay); - overlayManager.add(pointsOverlay); - updateLists(); - clientThread.invokeLater(() -> checkRaidPresence(true)); - widgetOverlay = overlayManager.getWidgetOverlay(WidgetInfo.RAIDS_POINTS_INFOBOX); - panel = injector.getInstance(RaidsPanel.class); - panel.init(config); - final BufferedImage icon = ImageUtil.getResourceStreamFromClass(this.getClass(), "instancereloadhelper.png"); - navButton = NavigationButton.builder() - .tooltip("Raids Reload") - .icon(icon) - .priority(8) - .panel(panel) - .build(); - clientToolbar.addNavigation(navButton); - } - - @Override - protected void shutDown() throws Exception - { - overlayManager.remove(overlay); - overlayManager.remove(pointsOverlay); - clientToolbar.removeNavigation(navButton); - inRaidChambers = false; - widgetOverlay = null; - raid = null; - - final Widget widget = client.getWidget(WidgetInfo.RAIDS_POINTS_INFOBOX); - if (widget != null) - { - widget.setHidden(false); - } - reset(); - } - - @Subscribe - public void onConfigChanged(ConfigChanged event) - { - if (!event.getGroup().equals("raids")) - { - return; - } - - updateLists(); - clientThread.invokeLater(() -> checkRaidPresence(true)); - } - - @Subscribe - public void onWidgetHiddenChanged(WidgetHiddenChanged event) - { - if (!inRaidChambers || event.isHidden()) - { - return; - } - - Widget widget = event.getWidget(); - - if (widget == client.getWidget(WidgetInfo.RAIDS_POINTS_INFOBOX)) - { - widget.setHidden(true); - } - } - - @Subscribe - public void onVarbitChanged(VarbitChanged event) - { - checkRaidPresence(false); - } - - @Subscribe - public void onChatMessage(ChatMessage event) - { - if (inRaidChambers && event.getType() == ChatMessageType.FRIENDSCHATNOTIFICATION) - { - String message = Text.removeTags(event.getMessage()); - Matcher matcher; - - matcher = LEVEL_COMPLETE_REGEX.matcher(message); - if (matcher.find()) - { - String floor = matcher.group(1); - int time = timeToSeconds(matcher.group(2)); - if (floor.equals("Upper")) - { - upperTime = time; - } - else if (floor.equals("Middle")) - { - middleTime = time; - } - else if (floor.equals("Lower")) - { - lowerTime = time; - } - updateTooltip(); - } - - matcher = RAID_COMPLETE_REGEX.matcher(message); - if (matcher.find()) - { - raidTime = timeToSeconds(matcher.group(1)); - int timesec = timeToSeconds(matcher.group(1)); - updateTooltip(); - - if (config.pointsMessage()) - { - int totalPoints = client.getVar(Varbits.TOTAL_POINTS); - int personalPoints = client.getVar(Varbits.PERSONAL_POINTS); - int partySize = client.getVar(Varbits.RAID_PARTY_SIZE); - - double percentage = personalPoints / (totalPoints / 100.0); - - String chatMessage = new ChatMessageBuilder() - .append(ChatColorType.NORMAL) - .append("Total points: ") - .append(ChatColorType.HIGHLIGHT) - .append(POINTS_FORMAT.format(totalPoints)) - .append(ChatColorType.NORMAL) - .append(", Personal points: ") - .append(ChatColorType.HIGHLIGHT) - .append(POINTS_FORMAT.format(personalPoints)) - .append(ChatColorType.NORMAL) - .append(" (") - .append(ChatColorType.HIGHLIGHT) - .append(DECIMAL_FORMAT.format(percentage)) - .append(ChatColorType.NORMAL) - .append("%)") - .build(); - - chatMessageManager.queue(QueuedMessage.builder() - .type(ChatMessageType.FRIENDSCHATNOTIFICATION) - .runeLiteFormattedMessage(chatMessage) - .build()); - if (config.ptsHr()) - { - String ptssolo; - { - ptssolo = POINTS_FORMAT.format(((float) personalPoints / (float) timesec) * 3600); - } - - String ptsteam; - { - ptsteam = POINTS_FORMAT.format(((float) totalPoints / (float) timesec) * 3600); - } - - String ptssplit; - { - ptssplit = POINTS_FORMAT.format(((float) (totalPoints / (float) timesec) * 3600) / (partySize)); - } - - - String chatMessage2 = new ChatMessageBuilder() - .append(ChatColorType.NORMAL) - .append("Solo Pts/Hr: ") - .append(ChatColorType.HIGHLIGHT) - .append(ptssolo) - .append(ChatColorType.NORMAL) - .append("Team Pts/Hr: ") - .append(ChatColorType.HIGHLIGHT) - .append(ptsteam) - .build(); - - chatMessageManager.queue(QueuedMessage.builder() - .type(ChatMessageType.FRIENDSCHATNOTIFICATION) - .runeLiteFormattedMessage(chatMessage2) - .build()); - - String chatMessage3 = new ChatMessageBuilder() - .append(ChatColorType.NORMAL) - .append("Split Pts/Hr: ") - .append(ChatColorType.HIGHLIGHT) - .append(ptssplit) - .build(); - - chatMessageManager.queue(QueuedMessage.builder() - .type(ChatMessageType.FRIENDSCHATNOTIFICATION) - .runeLiteFormattedMessage(chatMessage3) - .build()); - } - } - } - } - } - - @Subscribe - public void onClientTick(ClientTick event) - { - if (!config.raidsTimer() - || !client.getGameState().equals(GameState.LOGGED_IN) - || tooltip == null) - { - return; - } - - final Point mousePosition = client.getMouseCanvasPosition(); - if (widgetOverlay.getBounds().contains(mousePosition.getX(), mousePosition.getY())) - { - tooltipManager.add(new Tooltip(tooltip)); - } - } - - public void checkRaidPresence(boolean force) - { - if (client.getGameState() != GameState.LOGGED_IN) - { - return; - } - - boolean setting = client.getVar(Varbits.IN_RAID) == 1; - - if (force || inRaidChambers != setting) - { - inRaidChambers = setting; - - if (inRaidChambers) - { - raid = buildRaid(); - - if (raid == null) - { - log.debug("Failed to build raid"); - return; - } - - Layout layout = layoutSolver.findLayout(raid.toCode()); - - if (layout == null) - { - log.debug("Could not find layout match"); - return; - } - - raid.updateLayout(layout); - RotationSolver.solve(raid.getCombatRooms()); - overlay.setScoutOverlayShown(true); - sendRaidLayoutMessage(); - } - else - { - if (!config.scoutOverlayAtBank()) - { - overlay.setScoutOverlayShown(false); - } - - reset(); - } - } - - // If we left party raid was started or we left raid - if (client.getVar(VarPlayer.IN_RAID_PARTY) == -1 && (!inRaidChambers || !config.scoutOverlayInRaid())) - { - overlay.setScoutOverlayShown(false); - } - } - - private void sendRaidLayoutMessage() - { - if (!config.layoutMessage()) - { - return; - } - - final String layout = getRaid().getLayout().toCodeString(); - final String rooms = getRaid().toRoomString(); - final String raidData = "[" + layout + "]: " + rooms; - - chatMessageManager.queue(QueuedMessage.builder() - .type(ChatMessageType.FRIENDSCHATNOTIFICATION) - .runeLiteFormattedMessage(new ChatMessageBuilder() - .append(ChatColorType.HIGHLIGHT) - .append("Layout: ") - .append(ChatColorType.NORMAL) - .append(raidData) - .build()) - .build()); - } - - - private void updateLists() - { - updateList(roomWhitelist, config.whitelistedRooms()); - updateList(roomBlacklist, config.blacklistedRooms()); - updateList(rotationWhitelist, config.whitelistedRotations()); - updateList(layoutWhitelist, config.whitelistedLayouts()); - updateMap(recommendedItemsList, config.recommendedItems()); - } - - private void updateMap(Map> map, String input) - { - map.clear(); - - Matcher m = ROTATION_REGEX.matcher(input); - while (m.find()) - { - String everything = m.group(1).toLowerCase(); - int split = everything.indexOf(','); - if (split < 0) - continue; - String key = everything.substring(0, split); - if (key.length() < 1) - continue; - String[] itemNames = everything.substring(split).split(SPLIT_REGEX); - - map.computeIfAbsent(key, k -> new ArrayList<>()); - - for (String itemName : itemNames) - { - if (itemName.equals("")) - continue; - if (itemName.equals("ice barrage")) - map.get(key).add(SpriteID.SPELL_ICE_BARRAGE); - else if (itemName.startsWith("salve")) - map.get(key).add(ItemID.SALVE_AMULETEI); - else if (itemManager.search(itemName).size() > 0) - map.get(key).add(itemManager.search(itemName).get(0).getId()); - else - log.info("RaidsPlugin: Could not find an item ID for item: " + itemName); - } - } - } - - private void updateList(ArrayList list, String input) - { - list.clear(); - - if (list == rotationWhitelist) - { - Matcher m = ROTATION_REGEX.matcher(input); - while (m.find()) - { - String rotation = m.group(1).toLowerCase(); - - if (!list.contains(rotation)) - { - list.add(rotation); - } - } - } - else - { - list.addAll(Arrays.asList(input.toLowerCase().split(SPLIT_REGEX))); - } - } - - int getRotationMatches() - { - String rotation = raid.getRotationString().toLowerCase(); - String[] bosses = rotation.split(SPLIT_REGEX); - - if (rotationWhitelist.contains(rotation)) - { - return bosses.length; - } - - for (String whitelisted : rotationWhitelist) - { - int matches = 0; - String[] whitelistedBosses = whitelisted.split(SPLIT_REGEX); - - for (int i = 0; i < whitelistedBosses.length; i++) - { - if (i < bosses.length && whitelistedBosses[i].equals(bosses[i])) - { - matches++; - } - else - { - matches = 0; - break; - } - } - - if (matches >= 2) - { - return matches; - } - } - - return 0; - } - - private Point findLobbyBase() - { - Tile[][] tiles = client.getScene().getTiles()[LOBBY_PLANE]; - - for (int x = 0; x < SCENE_SIZE; x++) - { - for (int y = 0; y < SCENE_SIZE; y++) - { - if (tiles[x][y] == null || tiles[x][y].getWallObject() == null) - { - continue; - } - - if (tiles[x][y].getWallObject().getId() == NullObjectID.NULL_12231) - { - return tiles[x][y].getSceneLocation(); - } - } - } - - return null; - } - - private Raid buildRaid() - { - Point gridBase = findLobbyBase(); - - if (gridBase == null) - { - return null; - } - - Raid raid = new Raid(); - Tile[][] tiles; - int position, x, y, offsetX; - int startX = -2; - - for (int plane = 3; plane > 1; plane--) - { - tiles = client.getScene().getTiles()[plane]; - - if (tiles[gridBase.getX() + RaidRoom.ROOM_MAX_SIZE][gridBase.getY()] == null) - { - position = 1; - } - else - { - position = 0; - } - - for (int i = 1; i > -2; i--) - { - y = gridBase.getY() + (i * RaidRoom.ROOM_MAX_SIZE); - - for (int j = startX; j < 4; j++) - { - x = gridBase.getX() + (j * RaidRoom.ROOM_MAX_SIZE); - offsetX = 0; - - if (x > SCENE_SIZE && position > 1 && position < 4) - { - position++; - } - - if (x < 0) - { - offsetX = Math.abs(x) + 1; //add 1 because the tile at x=0 will always be null - } - - if (x < SCENE_SIZE && y >= 0 && y < SCENE_SIZE) - { - if (tiles[x + offsetX][y] == null) - { - if (position == 4) - { - position++; - break; - } - - continue; - } - - if (position == 0 && startX != j) - { - startX = j; - } - - Tile base = tiles[offsetX > 0 ? 1 : x][y]; - RaidRoom room = determineRoom(base); - raid.setRoom(room, position + Math.abs((plane - 3) * 8)); - position++; - } - } - } - } - - return raid; - } - - private RaidRoom determineRoom(Tile base) - { - RaidRoom room = new RaidRoom(base, RaidRoom.Type.EMPTY); - int chunkData = client.getInstanceTemplateChunks()[base.getPlane()][(base.getSceneLocation().getX()) / 8][base.getSceneLocation().getY() / 8]; - InstanceTemplates template = InstanceTemplates.findMatch(chunkData); - - if (template == null) - { - return room; - } - - switch (template) - { - case RAIDS_LOBBY: - case RAIDS_START: - room.setType(RaidRoom.Type.START); - break; - - case RAIDS_END: - room.setType(RaidRoom.Type.END); - break; - - case RAIDS_SCAVENGERS: - case RAIDS_SCAVENGERS2: - room.setType(RaidRoom.Type.SCAVENGERS); - break; - - case RAIDS_SHAMANS: - room.setType(RaidRoom.Type.COMBAT); - room.setBoss(RaidRoom.Boss.SHAMANS); - break; - - case RAIDS_VASA: - room.setType(RaidRoom.Type.COMBAT); - room.setBoss(RaidRoom.Boss.VASA); - break; - - case RAIDS_VANGUARDS: - room.setType(RaidRoom.Type.COMBAT); - room.setBoss(RaidRoom.Boss.VANGUARDS); - break; - - case RAIDS_ICE_DEMON: - room.setType(RaidRoom.Type.PUZZLE); - room.setPuzzle(RaidRoom.Puzzle.ICE_DEMON); - break; - - case RAIDS_THIEVING: - room.setType(RaidRoom.Type.PUZZLE); - room.setPuzzle(RaidRoom.Puzzle.THIEVING); - break; - - case RAIDS_FARMING: - case RAIDS_FARMING2: - room.setType(RaidRoom.Type.FARMING); - break; - - case RAIDS_MUTTADILES: - room.setType(RaidRoom.Type.COMBAT); - room.setBoss(RaidRoom.Boss.MUTTADILES); - break; - - case RAIDS_MYSTICS: - room.setType(RaidRoom.Type.COMBAT); - room.setBoss(RaidRoom.Boss.MYSTICS); - break; - - case RAIDS_TEKTON: - room.setType(RaidRoom.Type.COMBAT); - room.setBoss(RaidRoom.Boss.TEKTON); - break; - - case RAIDS_TIGHTROPE: - room.setType(RaidRoom.Type.PUZZLE); - room.setPuzzle(RaidRoom.Puzzle.TIGHTROPE); - break; - - case RAIDS_GUARDIANS: - room.setType(RaidRoom.Type.COMBAT); - room.setBoss(RaidRoom.Boss.GUARDIANS); - break; - - case RAIDS_CRABS: - room.setType(RaidRoom.Type.PUZZLE); - room.setPuzzle(RaidRoom.Puzzle.CRABS); - break; - - case RAIDS_VESPULA: - room.setType(RaidRoom.Type.COMBAT); - room.setBoss(RaidRoom.Boss.VESPULA); - break; - } - - return room; - } - - public void reset() - { - raid = null; - upperTime = -1; - middleTime = -1; - lowerTime = -1; - raidTime = -1; - tooltip = null; - } - - private int timeToSeconds(String s) - { - int seconds = -1; - String[] split = s.split(":"); - if (split.length == 2) - { - seconds = Integer.parseInt(split[0]) * 60 + Integer.parseInt(split[1]); - } - if (split.length == 3) - { - seconds = Integer.parseInt(split[0]) * 3600 + Integer.parseInt(split[1]) * 60 + Integer.parseInt(split[2]); - } - return seconds; - } - - private String secondsToTime(int seconds) - { - StringBuilder builder = new StringBuilder(); - if (seconds >= 3600) - { - builder.append((int)Math.floor(seconds / 3600) + ";"); - } - seconds %= 3600; - if (builder.toString().equals("")) - { - builder.append((int)Math.floor(seconds / 60)); - } - else - { - builder.append(StringUtils.leftPad(String.valueOf((int)Math.floor(seconds / 60)), 2, '0')); - } - builder.append(":"); - seconds %= 60; - builder.append(StringUtils.leftPad(String.valueOf(seconds), 2, '0')); - return builder.toString(); - } - - private void updateTooltip() - { - StringBuilder builder = new StringBuilder(); - if (upperTime == -1) - { - tooltip = null; - return; - } - builder.append("Upper level: " + secondsToTime(upperTime)); - if (middleTime == -1) - { - if (lowerTime == -1) - { - tooltip = builder.toString(); - return; - } - else - { - builder.append("
Lower level: " + secondsToTime(lowerTime - upperTime)); - } - } - else - { - builder.append("
Middle level: " + secondsToTime(middleTime - upperTime)); - if (lowerTime == -1) - { - tooltip = builder.toString(); - return; - } - else - { - builder.append("
Lower level: " + secondsToTime(lowerTime - middleTime)); - } - } - if (raidTime == -1) - { - tooltip = builder.toString(); - return; - } - builder.append("
Olm: " + secondsToTime(raidTime - lowerTime)); - tooltip = builder.toString(); - } -} +/* + * Copyright (c) 2018, Kamiel + * 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.raids; + +import com.google.inject.Binder; +import com.google.inject.Provides; +import java.awt.image.BufferedImage; +import java.text.DecimalFormat; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.concurrent.ScheduledExecutorService; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import javax.inject.Inject; +import lombok.Getter; +import lombok.extern.slf4j.Slf4j; +import net.runelite.api.ChatMessageType; +import net.runelite.api.Client; +import net.runelite.api.GameState; +import net.runelite.api.InstanceTemplates; +import net.runelite.api.ItemID; +import net.runelite.api.NullObjectID; +import static net.runelite.api.Perspective.SCENE_SIZE; +import net.runelite.api.Point; +import net.runelite.api.SpriteID; +import net.runelite.api.Tile; +import net.runelite.api.VarPlayer; +import net.runelite.api.Varbits; +import net.runelite.api.events.ChatMessage; +import net.runelite.api.events.ClientTick; +import net.runelite.api.events.ConfigChanged; +import net.runelite.api.events.VarbitChanged; +import net.runelite.api.events.WidgetHiddenChanged; +import net.runelite.api.widgets.Widget; +import net.runelite.api.widgets.WidgetInfo; +import net.runelite.client.callback.ClientThread; +import net.runelite.client.chat.ChatColorType; +import net.runelite.client.chat.ChatMessageBuilder; +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.game.ItemManager; +import net.runelite.client.game.SpriteManager; +import net.runelite.client.input.KeyManager; +import net.runelite.client.plugins.Plugin; +import net.runelite.client.plugins.PluginDescriptor; +import net.runelite.client.plugins.PluginType; +import net.runelite.client.plugins.raids.solver.Layout; +import net.runelite.client.plugins.raids.solver.LayoutSolver; +import net.runelite.client.plugins.raids.solver.RotationSolver; +import net.runelite.client.ui.ClientToolbar; +import net.runelite.client.ui.DrawManager; +import net.runelite.client.ui.NavigationButton; +import net.runelite.client.ui.overlay.OverlayManager; +import net.runelite.client.ui.overlay.WidgetOverlay; +import net.runelite.client.ui.overlay.infobox.InfoBoxManager; +import net.runelite.client.ui.overlay.tooltip.Tooltip; +import net.runelite.client.ui.overlay.tooltip.TooltipManager; +import net.runelite.client.util.ImageUtil; +import net.runelite.client.util.Text; +import org.apache.commons.lang3.StringUtils; + +@PluginDescriptor( + name = "Chambers Of Xeric", + description = "Show helpful information for the Chambers of Xeric raid", + tags = {"combat", "raid", "overlay", "pve", "pvm", "bosses", "cox", "olm"}, + type = PluginType.PVM +) +@Slf4j +public class RaidsPlugin extends Plugin +{ + private static final int LOBBY_PLANE = 3; + private static final DecimalFormat DECIMAL_FORMAT = new DecimalFormat("###.##"); + static final DecimalFormat POINTS_FORMAT = new DecimalFormat("#,###"); + private static final String SPLIT_REGEX = "\\s*,\\s*"; + private static final Pattern ROTATION_REGEX = Pattern.compile("\\[(.*?)]"); + private static final int LINE_COMPONENT_HEIGHT = 16; + + @Inject + private ItemManager itemManager; + private static final Pattern LEVEL_COMPLETE_REGEX = Pattern.compile("(.+) level complete! Duration: ([0-9:]+)"); + private static final Pattern RAID_COMPLETE_REGEX = Pattern.compile("Congratulations - your raid is complete! Duration: ([0-9:]+)"); + + @Inject + private ChatMessageManager chatMessageManager; + + @Inject + private InfoBoxManager infoBoxManager; + + @Inject + private Client client; + + @Inject + private DrawManager drawManager; + + @Inject + private ScheduledExecutorService executor; + + @Inject + private RaidsConfig config; + + @Inject + private OverlayManager overlayManager; + + @Inject + private RaidsOverlay overlay; + + @Inject + private RaidsPointsOverlay pointsOverlay; + + @Inject + private LayoutSolver layoutSolver; + + @Inject + private SpriteManager spriteManager; + + @Inject + private ClientThread clientThread; + + @Inject + private KeyManager keyManager; + + @Inject + private TooltipManager tooltipManager; + + @Getter + private final ArrayList roomWhitelist = new ArrayList<>(); + + @Getter + private final ArrayList roomBlacklist = new ArrayList<>(); + + @Getter + private final ArrayList rotationWhitelist = new ArrayList<>(); + + @Getter + private final ArrayList layoutWhitelist = new ArrayList<>(); + + @Getter + private final Map> recommendedItemsList = new HashMap<>(); + + @Getter + private Raid raid; + + @Getter + private boolean inRaidChambers; + + @Inject + private ClientToolbar clientToolbar; + private RaidsPanel panel; + private int upperTime = -1; + private int middleTime = -1; + private int lowerTime = -1; + private int raidTime = -1; + private WidgetOverlay widgetOverlay; + private String tooltip; + public boolean canShow; + private NavigationButton navButton; + + @Provides + RaidsConfig provideConfig(ConfigManager configManager) + { + return configManager.getConfig(RaidsConfig.class); + } + + @Override + public void configure(Binder binder) + { + binder.bind(RaidsOverlay.class); + } + + @Override + protected void startUp() throws Exception + { + overlayManager.add(overlay); + overlayManager.add(pointsOverlay); + updateLists(); + clientThread.invokeLater(() -> checkRaidPresence(true)); + widgetOverlay = overlayManager.getWidgetOverlay(WidgetInfo.RAIDS_POINTS_INFOBOX); + panel = injector.getInstance(RaidsPanel.class); + panel.init(config); + final BufferedImage icon = ImageUtil.getResourceStreamFromClass(this.getClass(), "instancereloadhelper.png"); + navButton = NavigationButton.builder() + .tooltip("Raids Reload") + .icon(icon) + .priority(8) + .panel(panel) + .build(); + clientToolbar.addNavigation(navButton); + } + + @Override + protected void shutDown() throws Exception + { + overlayManager.remove(overlay); + overlayManager.remove(pointsOverlay); + clientToolbar.removeNavigation(navButton); + inRaidChambers = false; + widgetOverlay = null; + raid = null; + + final Widget widget = client.getWidget(WidgetInfo.RAIDS_POINTS_INFOBOX); + if (widget != null) + { + widget.setHidden(false); + } + reset(); + } + + @Subscribe + public void onConfigChanged(ConfigChanged event) + { + if (!event.getGroup().equals("raids")) + { + return; + } + + updateLists(); + clientThread.invokeLater(() -> checkRaidPresence(true)); + } + + @Subscribe + public void onWidgetHiddenChanged(WidgetHiddenChanged event) + { + if (!inRaidChambers || event.isHidden()) + { + return; + } + + Widget widget = event.getWidget(); + + if (widget == client.getWidget(WidgetInfo.RAIDS_POINTS_INFOBOX)) + { + widget.setHidden(true); + } + } + + @Subscribe + public void onVarbitChanged(VarbitChanged event) + { + checkRaidPresence(false); + } + + @Subscribe + public void onChatMessage(ChatMessage event) + { + if (inRaidChambers && event.getType() == ChatMessageType.FRIENDSCHATNOTIFICATION) + { + String message = Text.removeTags(event.getMessage()); + Matcher matcher; + + matcher = LEVEL_COMPLETE_REGEX.matcher(message); + if (matcher.find()) + { + String floor = matcher.group(1); + int time = timeToSeconds(matcher.group(2)); + if (floor.equals("Upper")) + { + upperTime = time; + } + else if (floor.equals("Middle")) + { + middleTime = time; + } + else if (floor.equals("Lower")) + { + lowerTime = time; + } + updateTooltip(); + } + + matcher = RAID_COMPLETE_REGEX.matcher(message); + if (matcher.find()) + { + raidTime = timeToSeconds(matcher.group(1)); + int timesec = timeToSeconds(matcher.group(1)); + updateTooltip(); + + if (config.pointsMessage()) + { + int totalPoints = client.getVar(Varbits.TOTAL_POINTS); + int personalPoints = client.getVar(Varbits.PERSONAL_POINTS); + int partySize = client.getVar(Varbits.RAID_PARTY_SIZE); + + double percentage = personalPoints / (totalPoints / 100.0); + + String chatMessage = new ChatMessageBuilder() + .append(ChatColorType.NORMAL) + .append("Total points: ") + .append(ChatColorType.HIGHLIGHT) + .append(POINTS_FORMAT.format(totalPoints)) + .append(ChatColorType.NORMAL) + .append(", Personal points: ") + .append(ChatColorType.HIGHLIGHT) + .append(POINTS_FORMAT.format(personalPoints)) + .append(ChatColorType.NORMAL) + .append(" (") + .append(ChatColorType.HIGHLIGHT) + .append(DECIMAL_FORMAT.format(percentage)) + .append(ChatColorType.NORMAL) + .append("%)") + .build(); + + chatMessageManager.queue(QueuedMessage.builder() + .type(ChatMessageType.FRIENDSCHATNOTIFICATION) + .runeLiteFormattedMessage(chatMessage) + .build()); + if (config.ptsHr()) + { + String ptssolo; + { + ptssolo = POINTS_FORMAT.format(((float) personalPoints / (float) timesec) * 3600); + } + + String ptsteam; + { + ptsteam = POINTS_FORMAT.format(((float) totalPoints / (float) timesec) * 3600); + } + + String ptssplit; + { + ptssplit = POINTS_FORMAT.format(((totalPoints / (float) timesec) * 3600) / (partySize)); + } + + + String chatMessage2 = new ChatMessageBuilder() + .append(ChatColorType.NORMAL) + .append("Solo Pts/Hr: ") + .append(ChatColorType.HIGHLIGHT) + .append(ptssolo) + .append(ChatColorType.NORMAL) + .append("Team Pts/Hr: ") + .append(ChatColorType.HIGHLIGHT) + .append(ptsteam) + .build(); + + chatMessageManager.queue(QueuedMessage.builder() + .type(ChatMessageType.FRIENDSCHATNOTIFICATION) + .runeLiteFormattedMessage(chatMessage2) + .build()); + + String chatMessage3 = new ChatMessageBuilder() + .append(ChatColorType.NORMAL) + .append("Split Pts/Hr: ") + .append(ChatColorType.HIGHLIGHT) + .append(ptssplit) + .build(); + + chatMessageManager.queue(QueuedMessage.builder() + .type(ChatMessageType.FRIENDSCHATNOTIFICATION) + .runeLiteFormattedMessage(chatMessage3) + .build()); + } + } + } + } + } + + @Subscribe + public void onClientTick(ClientTick event) + { + if (!config.raidsTimer() + || !client.getGameState().equals(GameState.LOGGED_IN) + || tooltip == null) + { + return; + } + + final Point mousePosition = client.getMouseCanvasPosition(); + if (widgetOverlay.getBounds().contains(mousePosition.getX(), mousePosition.getY())) + { + tooltipManager.add(new Tooltip(tooltip)); + } + } + + public void checkRaidPresence(boolean force) + { + if (client.getGameState() != GameState.LOGGED_IN) + { + return; + } + + boolean setting = client.getVar(Varbits.IN_RAID) == 1; + + if (force || inRaidChambers != setting) + { + inRaidChambers = setting; + + if (inRaidChambers) + { + raid = buildRaid(); + + if (raid == null) + { + log.debug("Failed to build raid"); + return; + } + + Layout layout = layoutSolver.findLayout(raid.toCode()); + + if (layout == null) + { + log.debug("Could not find layout match"); + return; + } + + raid.updateLayout(layout); + RotationSolver.solve(raid.getCombatRooms()); + overlay.setScoutOverlayShown(true); + sendRaidLayoutMessage(); + } + else + { + if (!config.scoutOverlayAtBank()) + { + overlay.setScoutOverlayShown(false); + } + + reset(); + } + } + + // If we left party raid was started or we left raid + if (client.getVar(VarPlayer.IN_RAID_PARTY) == -1 && (!inRaidChambers || !config.scoutOverlayInRaid())) + { + overlay.setScoutOverlayShown(false); + } + } + + private void sendRaidLayoutMessage() + { + if (!config.layoutMessage()) + { + return; + } + + final String layout = getRaid().getLayout().toCodeString(); + final String rooms = getRaid().toRoomString(); + final String raidData = "[" + layout + "]: " + rooms; + + chatMessageManager.queue(QueuedMessage.builder() + .type(ChatMessageType.FRIENDSCHATNOTIFICATION) + .runeLiteFormattedMessage(new ChatMessageBuilder() + .append(ChatColorType.HIGHLIGHT) + .append("Layout: ") + .append(ChatColorType.NORMAL) + .append(raidData) + .build()) + .build()); + } + + + private void updateLists() + { + updateList(roomWhitelist, config.whitelistedRooms()); + updateList(roomBlacklist, config.blacklistedRooms()); + updateList(rotationWhitelist, config.whitelistedRotations()); + updateList(layoutWhitelist, config.whitelistedLayouts()); + updateMap(recommendedItemsList, config.recommendedItems()); + } + + private void updateMap(Map> map, String input) + { + map.clear(); + + Matcher m = ROTATION_REGEX.matcher(input); + while (m.find()) + { + String everything = m.group(1).toLowerCase(); + int split = everything.indexOf(','); + if (split < 0) + { + continue; + } + String key = everything.substring(0, split); + if (key.length() < 1) + { + continue; + } + String[] itemNames = everything.substring(split).split(SPLIT_REGEX); + + map.computeIfAbsent(key, k -> new ArrayList<>()); + + for (String itemName : itemNames) + { + if (itemName.equals("")) + { + continue; + } + if (itemName.equals("ice barrage")) + { + map.get(key).add(SpriteID.SPELL_ICE_BARRAGE); + } + else if (itemName.startsWith("salve")) + { + map.get(key).add(ItemID.SALVE_AMULETEI); + } + else if (itemManager.search(itemName).size() > 0) + { + map.get(key).add(itemManager.search(itemName).get(0).getId()); + } + else + { + log.info("RaidsPlugin: Could not find an item ID for item: " + itemName); + } + } + } + } + + private void updateList(ArrayList list, String input) + { + list.clear(); + + if (list == rotationWhitelist) + { + Matcher m = ROTATION_REGEX.matcher(input); + while (m.find()) + { + String rotation = m.group(1).toLowerCase(); + + if (!list.contains(rotation)) + { + list.add(rotation); + } + } + } + else + { + list.addAll(Arrays.asList(input.toLowerCase().split(SPLIT_REGEX))); + } + } + + int getRotationMatches() + { + String rotation = raid.getRotationString().toLowerCase(); + String[] bosses = rotation.split(SPLIT_REGEX); + + if (rotationWhitelist.contains(rotation)) + { + return bosses.length; + } + + for (String whitelisted : rotationWhitelist) + { + int matches = 0; + String[] whitelistedBosses = whitelisted.split(SPLIT_REGEX); + + for (int i = 0; i < whitelistedBosses.length; i++) + { + if (i < bosses.length && whitelistedBosses[i].equals(bosses[i])) + { + matches++; + } + else + { + matches = 0; + break; + } + } + + if (matches >= 2) + { + return matches; + } + } + + return 0; + } + + private Point findLobbyBase() + { + Tile[][] tiles = client.getScene().getTiles()[LOBBY_PLANE]; + + for (int x = 0; x < SCENE_SIZE; x++) + { + for (int y = 0; y < SCENE_SIZE; y++) + { + if (tiles[x][y] == null || tiles[x][y].getWallObject() == null) + { + continue; + } + + if (tiles[x][y].getWallObject().getId() == NullObjectID.NULL_12231) + { + return tiles[x][y].getSceneLocation(); + } + } + } + + return null; + } + + private Raid buildRaid() + { + Point gridBase = findLobbyBase(); + + if (gridBase == null) + { + return null; + } + + Raid raid = new Raid(); + Tile[][] tiles; + int position, x, y, offsetX; + int startX = -2; + + for (int plane = 3; plane > 1; plane--) + { + tiles = client.getScene().getTiles()[plane]; + + if (tiles[gridBase.getX() + RaidRoom.ROOM_MAX_SIZE][gridBase.getY()] == null) + { + position = 1; + } + else + { + position = 0; + } + + for (int i = 1; i > -2; i--) + { + y = gridBase.getY() + (i * RaidRoom.ROOM_MAX_SIZE); + + for (int j = startX; j < 4; j++) + { + x = gridBase.getX() + (j * RaidRoom.ROOM_MAX_SIZE); + offsetX = 0; + + if (x > SCENE_SIZE && position > 1 && position < 4) + { + position++; + } + + if (x < 0) + { + offsetX = Math.abs(x) + 1; //add 1 because the tile at x=0 will always be null + } + + if (x < SCENE_SIZE && y >= 0 && y < SCENE_SIZE) + { + if (tiles[x + offsetX][y] == null) + { + if (position == 4) + { + position++; + break; + } + + continue; + } + + if (position == 0 && startX != j) + { + startX = j; + } + + Tile base = tiles[offsetX > 0 ? 1 : x][y]; + RaidRoom room = determineRoom(base); + raid.setRoom(room, position + Math.abs((plane - 3) * 8)); + position++; + } + } + } + } + + return raid; + } + + private RaidRoom determineRoom(Tile base) + { + RaidRoom room = new RaidRoom(base, RaidRoom.Type.EMPTY); + int chunkData = client.getInstanceTemplateChunks()[base.getPlane()][(base.getSceneLocation().getX()) / 8][base.getSceneLocation().getY() / 8]; + InstanceTemplates template = InstanceTemplates.findMatch(chunkData); + + if (template == null) + { + return room; + } + + switch (template) + { + case RAIDS_LOBBY: + case RAIDS_START: + room.setType(RaidRoom.Type.START); + break; + + case RAIDS_END: + room.setType(RaidRoom.Type.END); + break; + + case RAIDS_SCAVENGERS: + case RAIDS_SCAVENGERS2: + room.setType(RaidRoom.Type.SCAVENGERS); + break; + + case RAIDS_SHAMANS: + room.setType(RaidRoom.Type.COMBAT); + room.setBoss(RaidRoom.Boss.SHAMANS); + break; + + case RAIDS_VASA: + room.setType(RaidRoom.Type.COMBAT); + room.setBoss(RaidRoom.Boss.VASA); + break; + + case RAIDS_VANGUARDS: + room.setType(RaidRoom.Type.COMBAT); + room.setBoss(RaidRoom.Boss.VANGUARDS); + break; + + case RAIDS_ICE_DEMON: + room.setType(RaidRoom.Type.PUZZLE); + room.setPuzzle(RaidRoom.Puzzle.ICE_DEMON); + break; + + case RAIDS_THIEVING: + room.setType(RaidRoom.Type.PUZZLE); + room.setPuzzle(RaidRoom.Puzzle.THIEVING); + break; + + case RAIDS_FARMING: + case RAIDS_FARMING2: + room.setType(RaidRoom.Type.FARMING); + break; + + case RAIDS_MUTTADILES: + room.setType(RaidRoom.Type.COMBAT); + room.setBoss(RaidRoom.Boss.MUTTADILES); + break; + + case RAIDS_MYSTICS: + room.setType(RaidRoom.Type.COMBAT); + room.setBoss(RaidRoom.Boss.MYSTICS); + break; + + case RAIDS_TEKTON: + room.setType(RaidRoom.Type.COMBAT); + room.setBoss(RaidRoom.Boss.TEKTON); + break; + + case RAIDS_TIGHTROPE: + room.setType(RaidRoom.Type.PUZZLE); + room.setPuzzle(RaidRoom.Puzzle.TIGHTROPE); + break; + + case RAIDS_GUARDIANS: + room.setType(RaidRoom.Type.COMBAT); + room.setBoss(RaidRoom.Boss.GUARDIANS); + break; + + case RAIDS_CRABS: + room.setType(RaidRoom.Type.PUZZLE); + room.setPuzzle(RaidRoom.Puzzle.CRABS); + break; + + case RAIDS_VESPULA: + room.setType(RaidRoom.Type.COMBAT); + room.setBoss(RaidRoom.Boss.VESPULA); + break; + } + + return room; + } + + public void reset() + { + raid = null; + upperTime = -1; + middleTime = -1; + lowerTime = -1; + raidTime = -1; + tooltip = null; + } + + private int timeToSeconds(String s) + { + int seconds = -1; + String[] split = s.split(":"); + if (split.length == 2) + { + seconds = Integer.parseInt(split[0]) * 60 + Integer.parseInt(split[1]); + } + if (split.length == 3) + { + seconds = Integer.parseInt(split[0]) * 3600 + Integer.parseInt(split[1]) * 60 + Integer.parseInt(split[2]); + } + return seconds; + } + + private String secondsToTime(int seconds) + { + StringBuilder builder = new StringBuilder(); + if (seconds >= 3600) + { + builder.append((int) Math.floor(seconds / 3600) + ";"); + } + seconds %= 3600; + if (builder.toString().equals("")) + { + builder.append((int) Math.floor(seconds / 60)); + } + else + { + builder.append(StringUtils.leftPad(String.valueOf((int) Math.floor(seconds / 60)), 2, '0')); + } + builder.append(":"); + seconds %= 60; + builder.append(StringUtils.leftPad(String.valueOf(seconds), 2, '0')); + return builder.toString(); + } + + private void updateTooltip() + { + StringBuilder builder = new StringBuilder(); + if (upperTime == -1) + { + tooltip = null; + return; + } + builder.append("Upper level: " + secondsToTime(upperTime)); + if (middleTime == -1) + { + if (lowerTime == -1) + { + tooltip = builder.toString(); + return; + } + else + { + builder.append("
Lower level: " + secondsToTime(lowerTime - upperTime)); + } + } + else + { + builder.append("
Middle level: " + secondsToTime(middleTime - upperTime)); + if (lowerTime == -1) + { + tooltip = builder.toString(); + return; + } + else + { + builder.append("
Lower level: " + secondsToTime(lowerTime - middleTime)); + } + } + if (raidTime == -1) + { + tooltip = builder.toString(); + return; + } + builder.append("
Olm: " + secondsToTime(raidTime - lowerTime)); + tooltip = builder.toString(); + } +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/raids/RaidsPointsOverlay.java b/runelite-client/src/main/java/net/runelite/client/plugins/raids/RaidsPointsOverlay.java index 5e4c98f4c8..ba6de9983f 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/raids/RaidsPointsOverlay.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/raids/RaidsPointsOverlay.java @@ -1,121 +1,122 @@ -/* - * Copyright (c) 2018, Kamiel - * 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.raids; - -import java.awt.Dimension; -import java.awt.Graphics2D; -import java.text.NumberFormat; -import java.util.Locale; -import javax.inject.Inject; -import net.runelite.api.Client; -import static net.runelite.api.MenuAction.RUNELITE_OVERLAY_CONFIG; -import net.runelite.api.Varbits; -import static net.runelite.client.plugins.raids.RaidsPlugin.POINTS_FORMAT; -import net.runelite.client.ui.overlay.Overlay; -import static net.runelite.client.ui.overlay.OverlayManager.OPTION_CONFIGURE; -import net.runelite.client.ui.overlay.OverlayMenuEntry; -import net.runelite.client.ui.overlay.OverlayPosition; -import net.runelite.client.ui.overlay.OverlayPriority; -import net.runelite.client.ui.overlay.components.LineComponent; -import net.runelite.client.ui.overlay.components.PanelComponent; - -public class RaidsPointsOverlay extends Overlay -{ - @Inject - private Client client; - - @Inject - private RaidsPlugin plugin; - - private final PanelComponent panel = new PanelComponent(); - - private static final NumberFormat UNIQUE_FORMAT = NumberFormat.getPercentInstance(Locale.ENGLISH); - static - { - UNIQUE_FORMAT.setMaximumFractionDigits(2); - UNIQUE_FORMAT.setMinimumFractionDigits(2); - } - - @Inject - private RaidsPointsOverlay(RaidsPlugin plugin) - { - super(plugin); - setPosition(OverlayPosition.TOP_RIGHT); - setPriority(OverlayPriority.HIGH); - getMenuEntries().add(new OverlayMenuEntry(RUNELITE_OVERLAY_CONFIG, OPTION_CONFIGURE, "Raids overlay")); - } - - @Override - public Dimension render(Graphics2D graphics) - { - if (!plugin.isInRaidChambers()) - { - return null; - } - - int totalPoints = client.getVar(Varbits.TOTAL_POINTS); - int personalPoints = client.getVar(Varbits.PERSONAL_POINTS); - int partySize = client.getVar(Varbits.RAID_PARTY_SIZE); - double uniqueChance = totalPoints / 867500f; - - panel.getChildren().clear(); - panel.getChildren().add(LineComponent.builder() - .left("Total:") - .right(POINTS_FORMAT.format(totalPoints)) - .build()); - - panel.getChildren().add(LineComponent.builder() - .left(client.getLocalPlayer().getName() + ":") - .right(POINTS_FORMAT.format(personalPoints)) - .build()); - - - if (partySize > 1) - { - panel.getChildren().add(LineComponent.builder() - .left("Party size:") - .right(String.valueOf(partySize)) - .build()); - } - - panel.getChildren().add(LineComponent.builder() - .left("Unique:") - .right(UNIQUE_FORMAT.format(uniqueChance)) - .build()); - //TODO this is annoyingly bugged, personalpoints returns null for some reason -/* - if (partySize > 1) - { - double personalChance = uniqueChance * (double)(personalPoints / totalPoints); - - panel.getChildren().add(LineComponent.builder() - .left("Personal:") - .right(UNIQUE_FORMAT.format(personalChance)) - .build()); - }*/ - - return panel.render(graphics); - } +/* + * Copyright (c) 2018, Kamiel + * 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.raids; + +import java.awt.Dimension; +import java.awt.Graphics2D; +import java.text.NumberFormat; +import java.util.Locale; +import javax.inject.Inject; +import net.runelite.api.Client; +import static net.runelite.api.MenuAction.RUNELITE_OVERLAY_CONFIG; +import net.runelite.api.Varbits; +import static net.runelite.client.plugins.raids.RaidsPlugin.POINTS_FORMAT; +import net.runelite.client.ui.overlay.Overlay; +import static net.runelite.client.ui.overlay.OverlayManager.OPTION_CONFIGURE; +import net.runelite.client.ui.overlay.OverlayMenuEntry; +import net.runelite.client.ui.overlay.OverlayPosition; +import net.runelite.client.ui.overlay.OverlayPriority; +import net.runelite.client.ui.overlay.components.LineComponent; +import net.runelite.client.ui.overlay.components.PanelComponent; + +public class RaidsPointsOverlay extends Overlay +{ + @Inject + private Client client; + + @Inject + private RaidsPlugin plugin; + + private final PanelComponent panel = new PanelComponent(); + + private static final NumberFormat UNIQUE_FORMAT = NumberFormat.getPercentInstance(Locale.ENGLISH); + + static + { + UNIQUE_FORMAT.setMaximumFractionDigits(2); + UNIQUE_FORMAT.setMinimumFractionDigits(2); + } + + @Inject + private RaidsPointsOverlay(RaidsPlugin plugin) + { + super(plugin); + setPosition(OverlayPosition.TOP_RIGHT); + setPriority(OverlayPriority.HIGH); + getMenuEntries().add(new OverlayMenuEntry(RUNELITE_OVERLAY_CONFIG, OPTION_CONFIGURE, "Raids overlay")); + } + + @Override + public Dimension render(Graphics2D graphics) + { + if (!plugin.isInRaidChambers()) + { + return null; + } + + int totalPoints = client.getVar(Varbits.TOTAL_POINTS); + int personalPoints = client.getVar(Varbits.PERSONAL_POINTS); + int partySize = client.getVar(Varbits.RAID_PARTY_SIZE); + double uniqueChance = totalPoints / 867500f; + + panel.getChildren().clear(); + panel.getChildren().add(LineComponent.builder() + .left("Total:") + .right(POINTS_FORMAT.format(totalPoints)) + .build()); + + panel.getChildren().add(LineComponent.builder() + .left(client.getLocalPlayer().getName() + ":") + .right(POINTS_FORMAT.format(personalPoints)) + .build()); + + + if (partySize > 1) + { + panel.getChildren().add(LineComponent.builder() + .left("Party size:") + .right(String.valueOf(partySize)) + .build()); + } + + panel.getChildren().add(LineComponent.builder() + .left("Unique:") + .right(UNIQUE_FORMAT.format(uniqueChance)) + .build()); + //TODO this is annoyingly bugged, personalpoints returns null for some reason +/* + if (partySize > 1) + { + double personalChance = uniqueChance * (double)(personalPoints / totalPoints); + + panel.getChildren().add(LineComponent.builder() + .left("Personal:") + .right(UNIQUE_FORMAT.format(personalChance)) + .build()); + }*/ + + return panel.render(graphics); + } } \ No newline at end of file diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/raids/shortcuts/ShortcutConfig.java b/runelite-client/src/main/java/net/runelite/client/plugins/raids/shortcuts/ShortcutConfig.java index 857afd3a4d..78dc54f534 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/raids/shortcuts/ShortcutConfig.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/raids/shortcuts/ShortcutConfig.java @@ -4,7 +4,8 @@ import net.runelite.client.config.ConfigGroup; import net.runelite.client.config.ConfigItem; @ConfigGroup("shortcut") -public interface ShortcutConfig { +public interface ShortcutConfig +{ @ConfigItem( keyName = "highlightShortcuts", name = "Highlight shortcuts", diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/raids/shortcuts/ShortcutOverlay.java b/runelite-client/src/main/java/net/runelite/client/plugins/raids/shortcuts/ShortcutOverlay.java index c23c99521f..6ae37169e8 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/raids/shortcuts/ShortcutOverlay.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/raids/shortcuts/ShortcutOverlay.java @@ -4,9 +4,7 @@ import java.awt.Dimension; import java.awt.Graphics2D; import java.awt.Polygon; import java.awt.image.BufferedImage; - import javax.inject.Inject; - import net.runelite.api.Client; import net.runelite.api.GameObject; import net.runelite.api.Perspective; @@ -27,7 +25,7 @@ public class ShortcutOverlay extends Overlay private final BufferedImage treeIcon; private final BufferedImage strengthIcon; private final BufferedImage miningIcon; - + @Inject ShortcutOverlay(Client client, ShortcutConfig config, ShortcutPlugin plugin, SkillIconManager iconManager) { @@ -37,72 +35,72 @@ public class ShortcutOverlay extends Overlay setPosition(OverlayPosition.DYNAMIC); setPriority(OverlayPriority.LOW); setLayer(OverlayLayer.ABOVE_SCENE); - + treeIcon = iconManager.getSkillImage(Skill.WOODCUTTING); strengthIcon = iconManager.getSkillImage(Skill.STRENGTH); miningIcon = iconManager.getSkillImage(Skill.MINING); } - + @Override - public Dimension render(Graphics2D graphics) + public Dimension render(Graphics2D graphics) { - for (TileObject shortcut : plugin.getShortcut()) + for (TileObject shortcut : plugin.getShortcut()) { - if (shortcut.getPlane() == client.getPlane()) + if (shortcut.getPlane() == client.getPlane()) { Polygon poly; - if ((shortcut instanceof GameObject)) + if ((shortcut instanceof GameObject)) { poly = ((GameObject) shortcut).getConvexHull(); } - else + else { poly = shortcut.getCanvasTilePoly(); } - if (poly != null) + if (poly != null) { String name; - switch (shortcut.getId()) + switch (shortcut.getId()) { - case 29736: - name = "Tree"; - break; - case 29738: - name = "Rocks"; - break; - case 297480: - name = "Boulder"; - break; - case 29737: - case 29739: - default: - name = "null"; + case 29736: + name = "Tree"; + break; + case 29738: + name = "Rocks"; + break; + case 297480: + name = "Boulder"; + break; + case 29737: + case 29739: + default: + name = "null"; } if (config.highlightShortcuts()) { - if (name.equals("Tree")) + if (name.equals("Tree")) { Point canvasLoc = Perspective.getCanvasImageLocation(client, shortcut.getLocalLocation(), - treeIcon, 150); - if (canvasLoc != null) + treeIcon, 150); + if (canvasLoc != null) { graphics.drawImage(treeIcon, canvasLoc.getX(), canvasLoc.getY(), null); } } - if (name.equals("Rocks")) + if (name.equals("Rocks")) { Point canvasLoc = Perspective.getCanvasImageLocation(client, shortcut.getLocalLocation(), - miningIcon, 150); - if (canvasLoc != null) + miningIcon, 150); + if (canvasLoc != null) { graphics.drawImage(miningIcon, canvasLoc.getX(), canvasLoc.getY(), null); } } - if (name.equals("Boulder")) + if (name.equals("Boulder")) { Point canvasLoc = Perspective.getCanvasImageLocation(client, shortcut.getLocalLocation(), - strengthIcon, 150); - if (canvasLoc != null) + strengthIcon, 150); + if (canvasLoc != null) { graphics.drawImage(strengthIcon, canvasLoc.getX(), canvasLoc.getY(), null); } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/raids/shortcuts/ShortcutPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/raids/shortcuts/ShortcutPlugin.java index 30fb3b2e42..ec60f730f0 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/raids/shortcuts/ShortcutPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/raids/shortcuts/ShortcutPlugin.java @@ -1,13 +1,10 @@ package net.runelite.client.plugins.raids.shortcuts; +import com.google.inject.Provides; import java.util.ArrayList; import java.util.Iterator; import java.util.List; - import javax.inject.Inject; - -import com.google.inject.Provides; - import lombok.extern.slf4j.Slf4j; import net.runelite.api.Client; import net.runelite.api.TileObject; @@ -31,58 +28,58 @@ public class ShortcutPlugin extends Plugin { @Inject private Client client; - + @Inject private OverlayManager overlayManager; - + @Inject private ShortcutOverlay overlay; - + private final List shortcut = new ArrayList<>(); - + List getShortcut() { return shortcut; } - + @Provides ShortcutConfig provideConfig(ConfigManager configManager) { - return (ShortcutConfig)configManager.getConfig(ShortcutConfig.class); + return configManager.getConfig(ShortcutConfig.class); } - + @Override protected void startUp() { overlayManager.add(overlay); } - + @Override protected void shutDown() { overlayManager.remove(overlay); } - + @Subscribe - public void onGameObjectSpawned(GameObjectSpawned event) + public void onGameObjectSpawned(GameObjectSpawned event) { WorldPoint worldPoint = WorldPoint.fromLocalInstance(client, event.getGameObject().getLocalLocation()); if (worldPoint == null) { return; } - if ((event.getGameObject().getId() == 29740) || (event.getGameObject().getId() == 29736) || (event.getGameObject().getId() == 29738)) + if ((event.getGameObject().getId() == 29740) || (event.getGameObject().getId() == 29736) || (event.getGameObject().getId() == 29738)) { shortcut.add(event.getGameObject()); } - } - + } + @Subscribe public void onGameObjectDespawned(GameObjectDespawned event) { shortcut.remove(event.getGameObject()); } - + @Subscribe public void onGameTick(GameTick tick) { @@ -93,8 +90,8 @@ public class ShortcutPlugin extends Plugin Iterator it = shortcut.iterator(); while (it.hasNext()) { - TileObject object = (TileObject)it.next(); - if (object.getCanvasLocation() == null) + TileObject object = it.next(); + if (object.getCanvasLocation() == null) { it.remove(); } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/raids/solver/LayoutSolver.java b/runelite-client/src/main/java/net/runelite/client/plugins/raids/solver/LayoutSolver.java index 10cba7bf20..c06a7ffc0b 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/raids/solver/LayoutSolver.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/raids/solver/LayoutSolver.java @@ -1,222 +1,222 @@ -/* - * Copyright (c) 2018, Kamiel - * 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.raids.solver; - -import com.google.inject.Singleton; -import java.util.ArrayList; -import java.util.List; -import java.util.regex.Matcher; -import java.util.regex.Pattern; -import lombok.Getter; -import lombok.extern.slf4j.Slf4j; - -/* - * Implementation of https://github.com/WooxSolo/raids-layout - * Copyright (c) 2017 WooxSolo - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - */ -@Slf4j -@Singleton -public class LayoutSolver -{ - @Getter - private static final List layouts = new ArrayList<>(); - private static final Pattern regex = Pattern.compile("^([A-Z]*)\\.([A-Z]*) - #([A-Z]*)#([A-Z]*)$"); - private static final String[] codes = - { - "FSCCP.PCSCF - #WNWSWN#ESEENW", - "FSCCS.PCPSF - #WSEEEN#WSWNWS", - "FSCPC.CSCPF - #WNWWSE#EENWWW", - "SCCFC.PSCSF - #EEENWW#WSEEEN", - "SCCFP.CCSPF - #NESEEN#WSWNWS", - "SCFCP.CCSPF - #ESEENW#ESWWNW", - "SCFCP.CSCFS - #ENEESW#ENWWSW", - "SCFCPC.CSPCSF - #ESWWNWS#NESENES", - "SCFPC.CSPCF - #WSWWNE#WSEENE", - "SCFPC.PCCSF - #WSEENE#WWWSEE", - "SCFPC.SCPCF - #NESENE#WSWWNE", - "SCPFC.CCPSF - #NWWWSE#WNEESE", - "SCPFC.CSPCF - #NEEESW#WWNEEE", - "SCPFC.CSPSF - #WWSEEE#NWSWWN", - "SCSPF.CCSPF - #ESWWNW#ESENES", - "SFCCP.CSCPF - #WNEESE#NWSWWN", - "SFCCS.PCPSF - #ENWWSW#ENESEN", - "SPCFC.CSPCF - #WWNEEE#WSWNWS", - "SPCFC.SCCPF - #ESENES#WWWNEE", - "SPSFP.CCCSF - #NWSWWN#ESEENW", - "SCFCP.CSCPF - #ENESEN#WWWSEE", - "SCPFC.PCSCF - #WNEEES#NWSWNW", - "SFCCPC.PCSCPF - #WSEENES#WWWNEEE", - "FSPCC.PSCCF - #WWWSEE#ENWWSW", - "FSCCP.PCSCF - #ENWWWS#NEESEN", - "SCPFC.CCSSF - #NEESEN#WSWWNE", - }; - - public LayoutSolver() - { - build(); - } - - public Layout findLayout(String code) - { - Layout solution = null; - int matches = 0; - boolean match; - - for (Layout layout : layouts) - { - match = true; - - for (int i = 0; i < code.length(); i++) - { - Room room = layout.getRoomAt(i); - char c = code.charAt(i); - - if (room != null && c != ' ' && c != room.getSymbol()) - { - match = false; - break; - } - } - - if (match) - { - solution = layout; - matches++; - log.debug("Found matching layout: " + layout.toCode()); - } - } - - if (matches == 1) - { - return solution; - } - - return null; - } - - private int calcStart(String directions) - { - int startPos = 0; - int position = 0; - - for (int i = 0; i < directions.length(); i++) - { - char c = directions.charAt(i); - int delta = dirToPosDelta(c); - position += delta; - - if (position < 0 || position >= 8 || (position == 3 && delta == -1) || (position == 4 && delta == 1)) - { - position -= delta; - startPos -= delta; - } - } - - return startPos; - } - - private int dirToPosDelta(char direction) - { - switch (String.valueOf(direction)) - { - case "N": - return -4; - - case "E": - return 1; - - case "S": - return 4; - - case "W": - return -1; - - default: - return 0; - } - } - - private void build() - { - for (String code : codes) - { - Matcher match = regex.matcher(code); - - if (!match.find()) - { - continue; - } - - String symbols, directions; - int position = calcStart(match.group(3)); - Layout layout = new Layout(); - Room lastRoom = null; - Room room; - - for (int floor = 0; floor < 2; floor++) - { - symbols = match.group(1 + floor); - directions = match.group(3 + floor); - - for (int i = 0; i < directions.length(); i++) - { - char symbol = (i == 0 ? '#' : symbols.charAt(i - 1)); - - room = new Room(position, symbol); - - if (lastRoom != null) - { - lastRoom.setNext(room); - room.setPrevious(lastRoom); - } - - layout.add(room); - lastRoom = room; - - int delta = dirToPosDelta(directions.charAt(i)); - position += delta; - } - - room = new Room(position, '¤'); - room.setPrevious(lastRoom); - lastRoom.setNext(room); - layout.add(room); - position += 8; - } - - layouts.add(layout); - } - } -} +/* + * Copyright (c) 2018, Kamiel + * 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.raids.solver; + +import com.google.inject.Singleton; +import java.util.ArrayList; +import java.util.List; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import lombok.Getter; +import lombok.extern.slf4j.Slf4j; + +/* + * Implementation of https://github.com/WooxSolo/raids-layout + * Copyright (c) 2017 WooxSolo + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + */ +@Slf4j +@Singleton +public class LayoutSolver +{ + @Getter + private static final List layouts = new ArrayList<>(); + private static final Pattern regex = Pattern.compile("^([A-Z]*)\\.([A-Z]*) - #([A-Z]*)#([A-Z]*)$"); + private static final String[] codes = + { + "FSCCP.PCSCF - #WNWSWN#ESEENW", + "FSCCS.PCPSF - #WSEEEN#WSWNWS", + "FSCPC.CSCPF - #WNWWSE#EENWWW", + "SCCFC.PSCSF - #EEENWW#WSEEEN", + "SCCFP.CCSPF - #NESEEN#WSWNWS", + "SCFCP.CCSPF - #ESEENW#ESWWNW", + "SCFCP.CSCFS - #ENEESW#ENWWSW", + "SCFCPC.CSPCSF - #ESWWNWS#NESENES", + "SCFPC.CSPCF - #WSWWNE#WSEENE", + "SCFPC.PCCSF - #WSEENE#WWWSEE", + "SCFPC.SCPCF - #NESENE#WSWWNE", + "SCPFC.CCPSF - #NWWWSE#WNEESE", + "SCPFC.CSPCF - #NEEESW#WWNEEE", + "SCPFC.CSPSF - #WWSEEE#NWSWWN", + "SCSPF.CCSPF - #ESWWNW#ESENES", + "SFCCP.CSCPF - #WNEESE#NWSWWN", + "SFCCS.PCPSF - #ENWWSW#ENESEN", + "SPCFC.CSPCF - #WWNEEE#WSWNWS", + "SPCFC.SCCPF - #ESENES#WWWNEE", + "SPSFP.CCCSF - #NWSWWN#ESEENW", + "SCFCP.CSCPF - #ENESEN#WWWSEE", + "SCPFC.PCSCF - #WNEEES#NWSWNW", + "SFCCPC.PCSCPF - #WSEENES#WWWNEEE", + "FSPCC.PSCCF - #WWWSEE#ENWWSW", + "FSCCP.PCSCF - #ENWWWS#NEESEN", + "SCPFC.CCSSF - #NEESEN#WSWWNE", + }; + + public LayoutSolver() + { + build(); + } + + public Layout findLayout(String code) + { + Layout solution = null; + int matches = 0; + boolean match; + + for (Layout layout : layouts) + { + match = true; + + for (int i = 0; i < code.length(); i++) + { + Room room = layout.getRoomAt(i); + char c = code.charAt(i); + + if (room != null && c != ' ' && c != room.getSymbol()) + { + match = false; + break; + } + } + + if (match) + { + solution = layout; + matches++; + log.debug("Found matching layout: " + layout.toCode()); + } + } + + if (matches == 1) + { + return solution; + } + + return null; + } + + private int calcStart(String directions) + { + int startPos = 0; + int position = 0; + + for (int i = 0; i < directions.length(); i++) + { + char c = directions.charAt(i); + int delta = dirToPosDelta(c); + position += delta; + + if (position < 0 || position >= 8 || (position == 3 && delta == -1) || (position == 4 && delta == 1)) + { + position -= delta; + startPos -= delta; + } + } + + return startPos; + } + + private int dirToPosDelta(char direction) + { + switch (String.valueOf(direction)) + { + case "N": + return -4; + + case "E": + return 1; + + case "S": + return 4; + + case "W": + return -1; + + default: + return 0; + } + } + + private void build() + { + for (String code : codes) + { + Matcher match = regex.matcher(code); + + if (!match.find()) + { + continue; + } + + String symbols, directions; + int position = calcStart(match.group(3)); + Layout layout = new Layout(); + Room lastRoom = null; + Room room; + + for (int floor = 0; floor < 2; floor++) + { + symbols = match.group(1 + floor); + directions = match.group(3 + floor); + + for (int i = 0; i < directions.length(); i++) + { + char symbol = (i == 0 ? '#' : symbols.charAt(i - 1)); + + room = new Room(position, symbol); + + if (lastRoom != null) + { + lastRoom.setNext(room); + room.setPrevious(lastRoom); + } + + layout.add(room); + lastRoom = room; + + int delta = dirToPosDelta(directions.charAt(i)); + position += delta; + } + + room = new Room(position, '¤'); + room.setPrevious(lastRoom); + lastRoom.setNext(room); + layout.add(room); + position += 8; + } + + layouts.add(layout); + } + } +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/raids/solver/RotationSolver.java b/runelite-client/src/main/java/net/runelite/client/plugins/raids/solver/RotationSolver.java index 1acf3ed2df..52f363a28f 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/raids/solver/RotationSolver.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/raids/solver/RotationSolver.java @@ -1,150 +1,150 @@ -/* - * Copyright (c) 2018, Kamiel - * 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.raids.solver; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; -import net.runelite.client.plugins.raids.RaidRoom; -import net.runelite.client.plugins.raids.RaidRoom.Boss; - -public class RotationSolver -{ - private static class Rotation extends ArrayList - { - Rotation(Collection bosses) - { - super(bosses); - } - - @Override - public E get(int index) - { - if (index < 0) - { - index = index + size(); - } - - return super.get(index % size()); - } - } - - private static final Rotation[] ROTATIONS = - { - new Rotation<>(Arrays.asList(Boss.TEKTON, Boss.VASA, Boss.GUARDIANS, Boss.MYSTICS, Boss.SHAMANS, Boss.MUTTADILES, Boss.VANGUARDS, Boss.VESPULA)), - new Rotation<>(Arrays.asList(Boss.TEKTON, Boss.MUTTADILES, Boss.GUARDIANS, Boss.VESPULA, Boss.SHAMANS, Boss.VASA, Boss.VANGUARDS, Boss.MYSTICS)), - new Rotation<>(Arrays.asList(Boss.VESPULA, Boss.VANGUARDS, Boss.MUTTADILES, Boss.SHAMANS, Boss.MYSTICS, Boss.GUARDIANS, Boss.VASA, Boss.TEKTON)), - new Rotation<>(Arrays.asList(Boss.MYSTICS, Boss.VANGUARDS, Boss.VASA, Boss.SHAMANS, Boss.VESPULA, Boss.GUARDIANS, Boss.MUTTADILES, Boss.TEKTON)) - }; - - public static boolean solve(RaidRoom[] rooms) - { - if (rooms == null) - { - return false; - } - - Rotation match = null; - Integer start = null; - Integer index = null; - int known = 0; - - for (int i = 0; i < rooms.length; i++) - { - if (rooms[i] == null || rooms[i].getBoss() == null || rooms[i].getBoss() == Boss.UNKNOWN) - { - continue; - } - - if (start == null) - { - start = i; - } - - known++; - } - - if (known < 2) - { - return false; - } - - if (known == rooms.length) - { - return true; - } - - for (Rotation rotation : ROTATIONS) - { - COMPARE: - for (int i = 0; i < rotation.size(); i++) - { - if (rooms[start].getBoss() == rotation.get(i)) - { - for (int j = start + 1; j < rooms.length; j++) - { - if (rooms[j].getBoss() == null || rooms[j].getBoss() == Boss.UNKNOWN) - { - continue; - } - - if (rooms[j].getBoss() != rotation.get(i + j - start)) - { - break COMPARE; - } - } - - if (match != null && match != rotation) - { - return false; - } - - index = i - start; - match = rotation; - } - } - } - - if (match == null) - { - return false; - } - - for (int i = 0; i < rooms.length; i++) - { - if (rooms[i] == null) - { - continue; - } - - if (rooms[i].getBoss() == null || rooms[i].getBoss() == Boss.UNKNOWN) - { - rooms[i].setBoss(match.get(index + i)); - } - } - - return true; - } -} +/* + * Copyright (c) 2018, Kamiel + * 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.raids.solver; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import net.runelite.client.plugins.raids.RaidRoom; +import net.runelite.client.plugins.raids.RaidRoom.Boss; + +public class RotationSolver +{ + private static class Rotation extends ArrayList + { + Rotation(Collection bosses) + { + super(bosses); + } + + @Override + public E get(int index) + { + if (index < 0) + { + index = index + size(); + } + + return super.get(index % size()); + } + } + + private static final Rotation[] ROTATIONS = + { + new Rotation<>(Arrays.asList(Boss.TEKTON, Boss.VASA, Boss.GUARDIANS, Boss.MYSTICS, Boss.SHAMANS, Boss.MUTTADILES, Boss.VANGUARDS, Boss.VESPULA)), + new Rotation<>(Arrays.asList(Boss.TEKTON, Boss.MUTTADILES, Boss.GUARDIANS, Boss.VESPULA, Boss.SHAMANS, Boss.VASA, Boss.VANGUARDS, Boss.MYSTICS)), + new Rotation<>(Arrays.asList(Boss.VESPULA, Boss.VANGUARDS, Boss.MUTTADILES, Boss.SHAMANS, Boss.MYSTICS, Boss.GUARDIANS, Boss.VASA, Boss.TEKTON)), + new Rotation<>(Arrays.asList(Boss.MYSTICS, Boss.VANGUARDS, Boss.VASA, Boss.SHAMANS, Boss.VESPULA, Boss.GUARDIANS, Boss.MUTTADILES, Boss.TEKTON)) + }; + + public static boolean solve(RaidRoom[] rooms) + { + if (rooms == null) + { + return false; + } + + Rotation match = null; + Integer start = null; + Integer index = null; + int known = 0; + + for (int i = 0; i < rooms.length; i++) + { + if (rooms[i] == null || rooms[i].getBoss() == null || rooms[i].getBoss() == Boss.UNKNOWN) + { + continue; + } + + if (start == null) + { + start = i; + } + + known++; + } + + if (known < 2) + { + return false; + } + + if (known == rooms.length) + { + return true; + } + + for (Rotation rotation : ROTATIONS) + { + COMPARE: + for (int i = 0; i < rotation.size(); i++) + { + if (rooms[start].getBoss() == rotation.get(i)) + { + for (int j = start + 1; j < rooms.length; j++) + { + if (rooms[j].getBoss() == null || rooms[j].getBoss() == Boss.UNKNOWN) + { + continue; + } + + if (rooms[j].getBoss() != rotation.get(i + j - start)) + { + break COMPARE; + } + } + + if (match != null && match != rotation) + { + return false; + } + + index = i - start; + match = rotation; + } + } + } + + if (match == null) + { + return false; + } + + for (int i = 0; i < rooms.length; i++) + { + if (rooms[i] == null) + { + continue; + } + + if (rooms[i].getBoss() == null || rooms[i].getBoss() == Boss.UNKNOWN) + { + rooms[i].setBoss(match.get(index + i)); + } + } + + return true; + } +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/raidsthieving/BatSolver/BatSolver.java b/runelite-client/src/main/java/net/runelite/client/plugins/raidsthieving/BatSolver/BatSolver.java index ebbad81a54..ae285cf44b 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/raidsthieving/BatSolver/BatSolver.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/raidsthieving/BatSolver/BatSolver.java @@ -1,193 +1,193 @@ -/* - * Copyright (c) 2018, Tim Lehner - * 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.raidsthieving.BatSolver; - -import java.util.Map; -import java.util.HashSet; -import java.util.HashMap; -import java.util.TreeSet; -import java.util.List; -import java.util.ArrayList; -import static net.runelite.client.plugins.raidsthieving.BatSolver.SolutionSet.SOLUTION_SETS; - -public class BatSolver -{ - private Map numberOfSolutionsWithPoison; - private final SolutionSet solution; - - private final HashSet grubsChests; - - public BatSolver(ThievingRoomType roomType) - { - solution = new SolutionSet(roomType); - grubsChests = new HashSet<>(); - } - - public void addEmptyChest(int chestId) - { - // When a new empty chest is found, add it to the current solution set - solution.addEmptyChest(chestId); - calculateChanceOfPoison(); - } - - public void addGrubsChest(int chestId) - { - // When a chest with grubs is found, keep track of it to invalidate solutions - grubsChests.add(chestId); - calculateChanceOfPoison(); - } - - public TreeSet matchSolutions() - { - TreeSet possibleEmptyChests = new TreeSet<>(); - for (SolutionSet knownSolution : SolutionSet.SOLUTION_SETS) - { - if (knownSolution.getType() == solution.getType() && matchSolution(knownSolution)) - { - possibleEmptyChests.addAll(knownSolution.getEmptyChests()); - } - } - - return possibleEmptyChests; - } - - private boolean matchSolution(SolutionSet testSolution) - { - for (Integer grubsChest : grubsChests) - { - if (testSolution.containsChest(grubsChest)) - { - // If one of the chests is known to have grubs, it cannot be a solution - return false; - } - } - - boolean matchesAll = true; - boolean everMatched = false; - for (int i : solution.getEmptyChests()) - { - if (!testSolution.containsChest(i)) - { - matchesAll = false; - } - else - { - everMatched = true; - } - } - return matchesAll && everMatched; - } - - public ThievingRoomType getType() - { - return solution.getType(); - } - - - public void calculateChanceOfPoison() - { - if (getType() == null) - { - numberOfSolutionsWithPoison = null; - return; - } - - numberOfSolutionsWithPoison = new HashMap<>(); - for (SolutionSet sol : getPosssibleSolutions()) - { - if (getType() == sol.getType() && (solution.getEmptyChests().size() == 0 || matchSolution(sol))) - { - for (Integer i : sol.getEmptyChests()) - { - if (numberOfSolutionsWithPoison.containsKey(i)) - { - numberOfSolutionsWithPoison.put(i, numberOfSolutionsWithPoison.get(i) + 1); - } - else - { - numberOfSolutionsWithPoison.put(i, 1); - } - } - } - } - } - - private List getPosssibleSolutions() - { - List possibleSolutions = new ArrayList<>(); - for (SolutionSet soln : SOLUTION_SETS) - { - // Check if we've found grubs in one of the chests, invalidating it as an solution - boolean foundMatch = false; - for (int i : grubsChests) - { - if (soln.containsChest(i)) - { - foundMatch = true; - } - } - if (!foundMatch) - { - possibleSolutions.add(soln); - } - } - return possibleSolutions; - } - - public double relativeLikelihoodPoison(int chestId) - { - // Returns a double between 0 and 1 of how likely the chest has poison based on the number of possible solutions - // Uses a Sigmoid like function to give good contrast in drawn opacity, - // perhaps could be changed to something more accurate quantitavely. - if (numberOfSolutionsWithPoison == null) - { - calculateChanceOfPoison(); - } - if (numberOfSolutionsWithPoison == null) - { - return 1.0; - } - int mostFrequentPoison = 0; - for (Map.Entry entry : numberOfSolutionsWithPoison.entrySet()) - { - if (entry.getValue() > mostFrequentPoison) - { - mostFrequentPoison = entry.getValue(); - } - } - int timesFound = 0; - if (numberOfSolutionsWithPoison.containsKey(chestId)) - { - timesFound = numberOfSolutionsWithPoison.get(chestId); - } - double chestChance = (double) (timesFound) / (double) (mostFrequentPoison); - return 1. / (1 + Math.exp(5 - 10 * chestChance)); - } - - public int getNumberOfEmptyChests() - { - return solution.getEmptyChests().size(); - } -} +/* + * Copyright (c) 2018, Tim Lehner + * 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.raidsthieving.BatSolver; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.TreeSet; +import static net.runelite.client.plugins.raidsthieving.BatSolver.SolutionSet.SOLUTION_SETS; + +public class BatSolver +{ + private Map numberOfSolutionsWithPoison; + private final SolutionSet solution; + + private final HashSet grubsChests; + + public BatSolver(ThievingRoomType roomType) + { + solution = new SolutionSet(roomType); + grubsChests = new HashSet<>(); + } + + public void addEmptyChest(int chestId) + { + // When a new empty chest is found, add it to the current solution set + solution.addEmptyChest(chestId); + calculateChanceOfPoison(); + } + + public void addGrubsChest(int chestId) + { + // When a chest with grubs is found, keep track of it to invalidate solutions + grubsChests.add(chestId); + calculateChanceOfPoison(); + } + + public TreeSet matchSolutions() + { + TreeSet possibleEmptyChests = new TreeSet<>(); + for (SolutionSet knownSolution : SolutionSet.SOLUTION_SETS) + { + if (knownSolution.getType() == solution.getType() && matchSolution(knownSolution)) + { + possibleEmptyChests.addAll(knownSolution.getEmptyChests()); + } + } + + return possibleEmptyChests; + } + + private boolean matchSolution(SolutionSet testSolution) + { + for (Integer grubsChest : grubsChests) + { + if (testSolution.containsChest(grubsChest)) + { + // If one of the chests is known to have grubs, it cannot be a solution + return false; + } + } + + boolean matchesAll = true; + boolean everMatched = false; + for (int i : solution.getEmptyChests()) + { + if (!testSolution.containsChest(i)) + { + matchesAll = false; + } + else + { + everMatched = true; + } + } + return matchesAll && everMatched; + } + + public ThievingRoomType getType() + { + return solution.getType(); + } + + + public void calculateChanceOfPoison() + { + if (getType() == null) + { + numberOfSolutionsWithPoison = null; + return; + } + + numberOfSolutionsWithPoison = new HashMap<>(); + for (SolutionSet sol : getPosssibleSolutions()) + { + if (getType() == sol.getType() && (solution.getEmptyChests().size() == 0 || matchSolution(sol))) + { + for (Integer i : sol.getEmptyChests()) + { + if (numberOfSolutionsWithPoison.containsKey(i)) + { + numberOfSolutionsWithPoison.put(i, numberOfSolutionsWithPoison.get(i) + 1); + } + else + { + numberOfSolutionsWithPoison.put(i, 1); + } + } + } + } + } + + private List getPosssibleSolutions() + { + List possibleSolutions = new ArrayList<>(); + for (SolutionSet soln : SOLUTION_SETS) + { + // Check if we've found grubs in one of the chests, invalidating it as an solution + boolean foundMatch = false; + for (int i : grubsChests) + { + if (soln.containsChest(i)) + { + foundMatch = true; + } + } + if (!foundMatch) + { + possibleSolutions.add(soln); + } + } + return possibleSolutions; + } + + public double relativeLikelihoodPoison(int chestId) + { + // Returns a double between 0 and 1 of how likely the chest has poison based on the number of possible solutions + // Uses a Sigmoid like function to give good contrast in drawn opacity, + // perhaps could be changed to something more accurate quantitavely. + if (numberOfSolutionsWithPoison == null) + { + calculateChanceOfPoison(); + } + if (numberOfSolutionsWithPoison == null) + { + return 1.0; + } + int mostFrequentPoison = 0; + for (Map.Entry entry : numberOfSolutionsWithPoison.entrySet()) + { + if (entry.getValue() > mostFrequentPoison) + { + mostFrequentPoison = entry.getValue(); + } + } + int timesFound = 0; + if (numberOfSolutionsWithPoison.containsKey(chestId)) + { + timesFound = numberOfSolutionsWithPoison.get(chestId); + } + double chestChance = (double) (timesFound) / (double) (mostFrequentPoison); + return 1. / (1 + Math.exp(5 - 10 * chestChance)); + } + + public int getNumberOfEmptyChests() + { + return solution.getEmptyChests().size(); + } +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/raidsthieving/BatSolver/ChestIdentifier.java b/runelite-client/src/main/java/net/runelite/client/plugins/raidsthieving/BatSolver/ChestIdentifier.java index 7346e4ecf6..5fab1e39d5 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/raidsthieving/BatSolver/ChestIdentifier.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/raidsthieving/BatSolver/ChestIdentifier.java @@ -1,261 +1,261 @@ -/* - * Copyright (c) 2018, Tim Lehner - * 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.raidsthieving.BatSolver; - -import net.runelite.client.plugins.raidsthieving.InstancePoint; -import net.runelite.client.plugins.raidsthieving.ThievingChest; -import java.util.HashMap; -import java.util.Map; - -public class ChestIdentifier -{ - public ChestIdentifier(ThievingRoomType roomType) - { - chestIds = new HashMap<>(); - switch (roomType) - { - case LEFT_TURN: - chestIds.put(new InstancePoint(3283, 5379), 1); - chestIds.put(new InstancePoint(3285, 5380), 2); - chestIds.put(new InstancePoint(3279, 5381), 3); - chestIds.put(new InstancePoint(3287, 5382), 4); - chestIds.put(new InstancePoint(3281, 5382), 5); - chestIds.put(new InstancePoint(3284, 5383), 6); - chestIds.put(new InstancePoint(3283, 5384), 7); - chestIds.put(new InstancePoint(3286, 5384), 8); - chestIds.put(new InstancePoint(3288, 5384), 9); - chestIds.put(new InstancePoint(3277, 5385), 10); - chestIds.put(new InstancePoint(3280, 5385), 11); - chestIds.put(new InstancePoint(3285, 5386), 12); - chestIds.put(new InstancePoint(3290, 5386), 13); - chestIds.put(new InstancePoint(3275, 5387), 14); - chestIds.put(new InstancePoint(3287, 5387), 15); - chestIds.put(new InstancePoint(3288, 5387), 16); - chestIds.put(new InstancePoint(3281, 5388), 17); - chestIds.put(new InstancePoint(3291, 5388), 18); - chestIds.put(new InstancePoint(3280, 5389), 19); - chestIds.put(new InstancePoint(3285, 5389), 20); - chestIds.put(new InstancePoint(3289, 5389), 21); - chestIds.put(new InstancePoint(3283, 5390), 22); - chestIds.put(new InstancePoint(3285, 5390), 23); - chestIds.put(new InstancePoint(3288, 5390), 24); - chestIds.put(new InstancePoint(3290, 5390), 25); - chestIds.put(new InstancePoint(3282, 5391), 26); - chestIds.put(new InstancePoint(3289, 5391), 27); - chestIds.put(new InstancePoint(3292, 5391), 28); - chestIds.put(new InstancePoint(3279, 5392), 29); - chestIds.put(new InstancePoint(3276, 5393), 30); - chestIds.put(new InstancePoint(3279, 5393), 31); - chestIds.put(new InstancePoint(3284, 5393), 32); - chestIds.put(new InstancePoint(3285, 5393), 33); - chestIds.put(new InstancePoint(3291, 5393), 34); - chestIds.put(new InstancePoint(3275, 5394), 35); - chestIds.put(new InstancePoint(3277, 5394), 36); - chestIds.put(new InstancePoint(3288, 5394), 37); - chestIds.put(new InstancePoint(3276, 5395), 38); - chestIds.put(new InstancePoint(3281, 5395), 39); - chestIds.put(new InstancePoint(3285, 5395), 40); - chestIds.put(new InstancePoint(3287, 5395), 41); - chestIds.put(new InstancePoint(3289, 5395), 42); - chestIds.put(new InstancePoint(3274, 5396), 43); - chestIds.put(new InstancePoint(3283, 5396), 44); - chestIds.put(new InstancePoint(3285, 5396), 45); - chestIds.put(new InstancePoint(3288, 5396), 46); - chestIds.put(new InstancePoint(3272, 5397), 47); - chestIds.put(new InstancePoint(3280, 5397), 48); - chestIds.put(new InstancePoint(3277, 5398), 49); - chestIds.put(new InstancePoint(3281, 5398), 50); - chestIds.put(new InstancePoint(3284, 5398), 51); - chestIds.put(new InstancePoint(3276, 5399), 52); - chestIds.put(new InstancePoint(3278, 5399), 53); - chestIds.put(new InstancePoint(3283, 5399), 54); - chestIds.put(new InstancePoint(3285, 5399), 55); - chestIds.put(new InstancePoint(3277, 5400), 56); - chestIds.put(new InstancePoint(3284, 5400), 57); - chestIds.put(new InstancePoint(3288, 5400), 58); - chestIds.put(new InstancePoint(3281, 5401), 59); - chestIds.put(new InstancePoint(3286, 5401), 60); - chestIds.put(new InstancePoint(3279, 5402), 61); - chestIds.put(new InstancePoint(3285, 5402), 62); - chestIds.put(new InstancePoint(3280, 5403), 63); - chestIds.put(new InstancePoint(3283, 5403), 64); - break; - case RIGHT_TURN: - chestIds.put(new InstancePoint(3338, 5405), 1); - chestIds.put(new InstancePoint(3334, 5405), 2); - chestIds.put(new InstancePoint(3342, 5404), 3); - chestIds.put(new InstancePoint(3340, 5404), 4); - chestIds.put(new InstancePoint(3345, 5403), 5); - chestIds.put(new InstancePoint(3334, 5403), 6); - chestIds.put(new InstancePoint(3330, 5403), 7); - chestIds.put(new InstancePoint(3343, 5402), 8); - chestIds.put(new InstancePoint(3342, 5402), 9); - chestIds.put(new InstancePoint(3339, 5402), 10); - chestIds.put(new InstancePoint(3338, 5402), 11); - chestIds.put(new InstancePoint(3336, 5402), 12); - chestIds.put(new InstancePoint(3347, 5401), 13); - chestIds.put(new InstancePoint(3330, 5401), 14); - chestIds.put(new InstancePoint(3345, 5400), 15); - chestIds.put(new InstancePoint(3341, 5400), 16); - chestIds.put(new InstancePoint(3337, 5400), 17); - chestIds.put(new InstancePoint(3334, 5400), 18); - chestIds.put(new InstancePoint(3345, 5399), 19); - chestIds.put(new InstancePoint(3343, 5399), 20); - chestIds.put(new InstancePoint(3340, 5399), 21); - chestIds.put(new InstancePoint(3335, 5399), 22); - chestIds.put(new InstancePoint(3331, 5399), 23); - chestIds.put(new InstancePoint(3338, 5398), 24); - chestIds.put(new InstancePoint(3337, 5398), 25); - chestIds.put(new InstancePoint(3345, 5397), 26); - chestIds.put(new InstancePoint(3341, 5397), 27); - chestIds.put(new InstancePoint(3334, 5397), 28); - chestIds.put(new InstancePoint(3331, 5397), 29); - chestIds.put(new InstancePoint(3346, 5396), 30); - chestIds.put(new InstancePoint(3343, 5396), 31); - chestIds.put(new InstancePoint(3339, 5396), 32); - chestIds.put(new InstancePoint(3335, 5396), 33); - chestIds.put(new InstancePoint(3333, 5396), 34); - chestIds.put(new InstancePoint(3340, 5395), 35); - chestIds.put(new InstancePoint(3337, 5395), 36); - chestIds.put(new InstancePoint(3334, 5395), 37); - chestIds.put(new InstancePoint(3345, 5394), 38); - chestIds.put(new InstancePoint(3342, 5394), 39); - chestIds.put(new InstancePoint(3332, 5394), 40); - chestIds.put(new InstancePoint(3343, 5393), 41); - chestIds.put(new InstancePoint(3341, 5393), 42); - chestIds.put(new InstancePoint(3338, 5393), 43); - chestIds.put(new InstancePoint(3335, 5393), 44); - chestIds.put(new InstancePoint(3334, 5393), 45); - chestIds.put(new InstancePoint(3346, 5392), 46); - chestIds.put(new InstancePoint(3342, 5392), 47); - chestIds.put(new InstancePoint(3332, 5392), 48); - chestIds.put(new InstancePoint(3350, 5391), 49); - chestIds.put(new InstancePoint(3346, 5391), 50); - chestIds.put(new InstancePoint(3340, 5391), 51); - chestIds.put(new InstancePoint(3339, 5391), 52); - chestIds.put(new InstancePoint(3336, 5391), 53); - chestIds.put(new InstancePoint(3333, 5391), 54); - chestIds.put(new InstancePoint(3349, 5390), 55); - chestIds.put(new InstancePoint(3343, 5390), 56); - chestIds.put(new InstancePoint(3337, 5390), 57); - chestIds.put(new InstancePoint(3335, 5390), 58); - chestIds.put(new InstancePoint(3344, 5389), 59); - chestIds.put(new InstancePoint(3340, 5389), 60); - chestIds.put(new InstancePoint(3336, 5389), 61); - chestIds.put(new InstancePoint(3333, 5389), 62); - chestIds.put(new InstancePoint(3346, 5388), 63); - chestIds.put(new InstancePoint(3340, 5387), 64); - chestIds.put(new InstancePoint(3337, 5386), 65); - chestIds.put(new InstancePoint(3333, 5386), 66); - chestIds.put(new InstancePoint(3338, 5385), 67); - chestIds.put(new InstancePoint(3336, 5385), 68); - chestIds.put(new InstancePoint(3337, 5384), 69); - chestIds.put(new InstancePoint(3340, 5382), 70); - chestIds.put(new InstancePoint(3334, 5383), 71); - chestIds.put(new InstancePoint(3340, 5379), 72); - chestIds.put(new InstancePoint(3338, 5380), 73); - chestIds.put(new InstancePoint(3336, 5381), 74); - break; - case STRAIGHT: - chestIds.put(new InstancePoint(3308, 5378), 1); - chestIds.put(new InstancePoint(3305, 5379), 2); - chestIds.put(new InstancePoint(3307, 5379), 3); - chestIds.put(new InstancePoint(3304, 5381), 4); - chestIds.put(new InstancePoint(3310, 5381), 5); - chestIds.put(new InstancePoint(3302, 5382), 6); - chestIds.put(new InstancePoint(3307, 5382), 7); - chestIds.put(new InstancePoint(3312, 5382), 8); - chestIds.put(new InstancePoint(3317, 5382), 9); - chestIds.put(new InstancePoint(3319, 5382), 10); - chestIds.put(new InstancePoint(3304, 5383), 11); - chestIds.put(new InstancePoint(3305, 5383), 12); - chestIds.put(new InstancePoint(3307, 5383), 13); - chestIds.put(new InstancePoint(3310, 5383), 14); - chestIds.put(new InstancePoint(3315, 5383), 15); - chestIds.put(new InstancePoint(3320, 5383), 16); - chestIds.put(new InstancePoint(3300, 5384), 17); - chestIds.put(new InstancePoint(3309, 5384), 18); - chestIds.put(new InstancePoint(3311, 5384), 19); - chestIds.put(new InstancePoint(3313, 5384), 20); - chestIds.put(new InstancePoint(3317, 5384), 21); - chestIds.put(new InstancePoint(3318, 5384), 22); - chestIds.put(new InstancePoint(3302, 5385), 23); - chestIds.put(new InstancePoint(3306, 5385), 24); - chestIds.put(new InstancePoint(3310, 5385), 25); - chestIds.put(new InstancePoint(3313, 5385), 26); - chestIds.put(new InstancePoint(3320, 5385), 27); - chestIds.put(new InstancePoint(3302, 5386), 28); - chestIds.put(new InstancePoint(3305, 5386), 29); - chestIds.put(new InstancePoint(3316, 5386), 30); - chestIds.put(new InstancePoint(3321, 5386), 31); - chestIds.put(new InstancePoint(3300, 5387), 32); - chestIds.put(new InstancePoint(3308, 5387), 33); - chestIds.put(new InstancePoint(3314, 5387), 34); - chestIds.put(new InstancePoint(3317, 5387), 35); - chestIds.put(new InstancePoint(3301, 5388), 36); - chestIds.put(new InstancePoint(3306, 5388), 37); - chestIds.put(new InstancePoint(3312, 5388), 38); - chestIds.put(new InstancePoint(3322, 5388), 39); - chestIds.put(new InstancePoint(3309, 5389), 40); - chestIds.put(new InstancePoint(3311, 5389), 41); - chestIds.put(new InstancePoint(3313, 5389), 42); - chestIds.put(new InstancePoint(3316, 5389), 43); - chestIds.put(new InstancePoint(3320, 5389), 44); - chestIds.put(new InstancePoint(3300, 5390), 45); - chestIds.put(new InstancePoint(3303, 5390), 46); - chestIds.put(new InstancePoint(3304, 5390), 47); - chestIds.put(new InstancePoint(3312, 5390), 48); - chestIds.put(new InstancePoint(3320, 5390), 49); - chestIds.put(new InstancePoint(3307, 5391), 50); - chestIds.put(new InstancePoint(3310, 5391), 51); - chestIds.put(new InstancePoint(3317, 5391), 52); - chestIds.put(new InstancePoint(3318, 5391), 53); - chestIds.put(new InstancePoint(3323, 5391), 54); - chestIds.put(new InstancePoint(3301, 5392), 55); - chestIds.put(new InstancePoint(3303, 5392), 56); - chestIds.put(new InstancePoint(3309, 5392), 57); - chestIds.put(new InstancePoint(3314, 5392), 58); - chestIds.put(new InstancePoint(3322, 5392), 59); - chestIds.put(new InstancePoint(3305, 5393), 60); - chestIds.put(new InstancePoint(3307, 5393), 61); - chestIds.put(new InstancePoint(3316, 5393), 62); - chestIds.put(new InstancePoint(3309, 5394), 63); - chestIds.put(new InstancePoint(3312, 5394), 64); - chestIds.put(new InstancePoint(3322, 5394), 65); - chestIds.put(new InstancePoint(3310, 5379), 66); - break; - } - - } - - public int indentifyChest(ThievingChest chest) - { - int id = chestIds.get(chest.getInstancePoint()); - chest.setChestId(id); - return id; - } - - private Map chestIds; -} +/* + * Copyright (c) 2018, Tim Lehner + * 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.raidsthieving.BatSolver; + +import java.util.HashMap; +import java.util.Map; +import net.runelite.client.plugins.raidsthieving.InstancePoint; +import net.runelite.client.plugins.raidsthieving.ThievingChest; + +public class ChestIdentifier +{ + public ChestIdentifier(ThievingRoomType roomType) + { + chestIds = new HashMap<>(); + switch (roomType) + { + case LEFT_TURN: + chestIds.put(new InstancePoint(3283, 5379), 1); + chestIds.put(new InstancePoint(3285, 5380), 2); + chestIds.put(new InstancePoint(3279, 5381), 3); + chestIds.put(new InstancePoint(3287, 5382), 4); + chestIds.put(new InstancePoint(3281, 5382), 5); + chestIds.put(new InstancePoint(3284, 5383), 6); + chestIds.put(new InstancePoint(3283, 5384), 7); + chestIds.put(new InstancePoint(3286, 5384), 8); + chestIds.put(new InstancePoint(3288, 5384), 9); + chestIds.put(new InstancePoint(3277, 5385), 10); + chestIds.put(new InstancePoint(3280, 5385), 11); + chestIds.put(new InstancePoint(3285, 5386), 12); + chestIds.put(new InstancePoint(3290, 5386), 13); + chestIds.put(new InstancePoint(3275, 5387), 14); + chestIds.put(new InstancePoint(3287, 5387), 15); + chestIds.put(new InstancePoint(3288, 5387), 16); + chestIds.put(new InstancePoint(3281, 5388), 17); + chestIds.put(new InstancePoint(3291, 5388), 18); + chestIds.put(new InstancePoint(3280, 5389), 19); + chestIds.put(new InstancePoint(3285, 5389), 20); + chestIds.put(new InstancePoint(3289, 5389), 21); + chestIds.put(new InstancePoint(3283, 5390), 22); + chestIds.put(new InstancePoint(3285, 5390), 23); + chestIds.put(new InstancePoint(3288, 5390), 24); + chestIds.put(new InstancePoint(3290, 5390), 25); + chestIds.put(new InstancePoint(3282, 5391), 26); + chestIds.put(new InstancePoint(3289, 5391), 27); + chestIds.put(new InstancePoint(3292, 5391), 28); + chestIds.put(new InstancePoint(3279, 5392), 29); + chestIds.put(new InstancePoint(3276, 5393), 30); + chestIds.put(new InstancePoint(3279, 5393), 31); + chestIds.put(new InstancePoint(3284, 5393), 32); + chestIds.put(new InstancePoint(3285, 5393), 33); + chestIds.put(new InstancePoint(3291, 5393), 34); + chestIds.put(new InstancePoint(3275, 5394), 35); + chestIds.put(new InstancePoint(3277, 5394), 36); + chestIds.put(new InstancePoint(3288, 5394), 37); + chestIds.put(new InstancePoint(3276, 5395), 38); + chestIds.put(new InstancePoint(3281, 5395), 39); + chestIds.put(new InstancePoint(3285, 5395), 40); + chestIds.put(new InstancePoint(3287, 5395), 41); + chestIds.put(new InstancePoint(3289, 5395), 42); + chestIds.put(new InstancePoint(3274, 5396), 43); + chestIds.put(new InstancePoint(3283, 5396), 44); + chestIds.put(new InstancePoint(3285, 5396), 45); + chestIds.put(new InstancePoint(3288, 5396), 46); + chestIds.put(new InstancePoint(3272, 5397), 47); + chestIds.put(new InstancePoint(3280, 5397), 48); + chestIds.put(new InstancePoint(3277, 5398), 49); + chestIds.put(new InstancePoint(3281, 5398), 50); + chestIds.put(new InstancePoint(3284, 5398), 51); + chestIds.put(new InstancePoint(3276, 5399), 52); + chestIds.put(new InstancePoint(3278, 5399), 53); + chestIds.put(new InstancePoint(3283, 5399), 54); + chestIds.put(new InstancePoint(3285, 5399), 55); + chestIds.put(new InstancePoint(3277, 5400), 56); + chestIds.put(new InstancePoint(3284, 5400), 57); + chestIds.put(new InstancePoint(3288, 5400), 58); + chestIds.put(new InstancePoint(3281, 5401), 59); + chestIds.put(new InstancePoint(3286, 5401), 60); + chestIds.put(new InstancePoint(3279, 5402), 61); + chestIds.put(new InstancePoint(3285, 5402), 62); + chestIds.put(new InstancePoint(3280, 5403), 63); + chestIds.put(new InstancePoint(3283, 5403), 64); + break; + case RIGHT_TURN: + chestIds.put(new InstancePoint(3338, 5405), 1); + chestIds.put(new InstancePoint(3334, 5405), 2); + chestIds.put(new InstancePoint(3342, 5404), 3); + chestIds.put(new InstancePoint(3340, 5404), 4); + chestIds.put(new InstancePoint(3345, 5403), 5); + chestIds.put(new InstancePoint(3334, 5403), 6); + chestIds.put(new InstancePoint(3330, 5403), 7); + chestIds.put(new InstancePoint(3343, 5402), 8); + chestIds.put(new InstancePoint(3342, 5402), 9); + chestIds.put(new InstancePoint(3339, 5402), 10); + chestIds.put(new InstancePoint(3338, 5402), 11); + chestIds.put(new InstancePoint(3336, 5402), 12); + chestIds.put(new InstancePoint(3347, 5401), 13); + chestIds.put(new InstancePoint(3330, 5401), 14); + chestIds.put(new InstancePoint(3345, 5400), 15); + chestIds.put(new InstancePoint(3341, 5400), 16); + chestIds.put(new InstancePoint(3337, 5400), 17); + chestIds.put(new InstancePoint(3334, 5400), 18); + chestIds.put(new InstancePoint(3345, 5399), 19); + chestIds.put(new InstancePoint(3343, 5399), 20); + chestIds.put(new InstancePoint(3340, 5399), 21); + chestIds.put(new InstancePoint(3335, 5399), 22); + chestIds.put(new InstancePoint(3331, 5399), 23); + chestIds.put(new InstancePoint(3338, 5398), 24); + chestIds.put(new InstancePoint(3337, 5398), 25); + chestIds.put(new InstancePoint(3345, 5397), 26); + chestIds.put(new InstancePoint(3341, 5397), 27); + chestIds.put(new InstancePoint(3334, 5397), 28); + chestIds.put(new InstancePoint(3331, 5397), 29); + chestIds.put(new InstancePoint(3346, 5396), 30); + chestIds.put(new InstancePoint(3343, 5396), 31); + chestIds.put(new InstancePoint(3339, 5396), 32); + chestIds.put(new InstancePoint(3335, 5396), 33); + chestIds.put(new InstancePoint(3333, 5396), 34); + chestIds.put(new InstancePoint(3340, 5395), 35); + chestIds.put(new InstancePoint(3337, 5395), 36); + chestIds.put(new InstancePoint(3334, 5395), 37); + chestIds.put(new InstancePoint(3345, 5394), 38); + chestIds.put(new InstancePoint(3342, 5394), 39); + chestIds.put(new InstancePoint(3332, 5394), 40); + chestIds.put(new InstancePoint(3343, 5393), 41); + chestIds.put(new InstancePoint(3341, 5393), 42); + chestIds.put(new InstancePoint(3338, 5393), 43); + chestIds.put(new InstancePoint(3335, 5393), 44); + chestIds.put(new InstancePoint(3334, 5393), 45); + chestIds.put(new InstancePoint(3346, 5392), 46); + chestIds.put(new InstancePoint(3342, 5392), 47); + chestIds.put(new InstancePoint(3332, 5392), 48); + chestIds.put(new InstancePoint(3350, 5391), 49); + chestIds.put(new InstancePoint(3346, 5391), 50); + chestIds.put(new InstancePoint(3340, 5391), 51); + chestIds.put(new InstancePoint(3339, 5391), 52); + chestIds.put(new InstancePoint(3336, 5391), 53); + chestIds.put(new InstancePoint(3333, 5391), 54); + chestIds.put(new InstancePoint(3349, 5390), 55); + chestIds.put(new InstancePoint(3343, 5390), 56); + chestIds.put(new InstancePoint(3337, 5390), 57); + chestIds.put(new InstancePoint(3335, 5390), 58); + chestIds.put(new InstancePoint(3344, 5389), 59); + chestIds.put(new InstancePoint(3340, 5389), 60); + chestIds.put(new InstancePoint(3336, 5389), 61); + chestIds.put(new InstancePoint(3333, 5389), 62); + chestIds.put(new InstancePoint(3346, 5388), 63); + chestIds.put(new InstancePoint(3340, 5387), 64); + chestIds.put(new InstancePoint(3337, 5386), 65); + chestIds.put(new InstancePoint(3333, 5386), 66); + chestIds.put(new InstancePoint(3338, 5385), 67); + chestIds.put(new InstancePoint(3336, 5385), 68); + chestIds.put(new InstancePoint(3337, 5384), 69); + chestIds.put(new InstancePoint(3340, 5382), 70); + chestIds.put(new InstancePoint(3334, 5383), 71); + chestIds.put(new InstancePoint(3340, 5379), 72); + chestIds.put(new InstancePoint(3338, 5380), 73); + chestIds.put(new InstancePoint(3336, 5381), 74); + break; + case STRAIGHT: + chestIds.put(new InstancePoint(3308, 5378), 1); + chestIds.put(new InstancePoint(3305, 5379), 2); + chestIds.put(new InstancePoint(3307, 5379), 3); + chestIds.put(new InstancePoint(3304, 5381), 4); + chestIds.put(new InstancePoint(3310, 5381), 5); + chestIds.put(new InstancePoint(3302, 5382), 6); + chestIds.put(new InstancePoint(3307, 5382), 7); + chestIds.put(new InstancePoint(3312, 5382), 8); + chestIds.put(new InstancePoint(3317, 5382), 9); + chestIds.put(new InstancePoint(3319, 5382), 10); + chestIds.put(new InstancePoint(3304, 5383), 11); + chestIds.put(new InstancePoint(3305, 5383), 12); + chestIds.put(new InstancePoint(3307, 5383), 13); + chestIds.put(new InstancePoint(3310, 5383), 14); + chestIds.put(new InstancePoint(3315, 5383), 15); + chestIds.put(new InstancePoint(3320, 5383), 16); + chestIds.put(new InstancePoint(3300, 5384), 17); + chestIds.put(new InstancePoint(3309, 5384), 18); + chestIds.put(new InstancePoint(3311, 5384), 19); + chestIds.put(new InstancePoint(3313, 5384), 20); + chestIds.put(new InstancePoint(3317, 5384), 21); + chestIds.put(new InstancePoint(3318, 5384), 22); + chestIds.put(new InstancePoint(3302, 5385), 23); + chestIds.put(new InstancePoint(3306, 5385), 24); + chestIds.put(new InstancePoint(3310, 5385), 25); + chestIds.put(new InstancePoint(3313, 5385), 26); + chestIds.put(new InstancePoint(3320, 5385), 27); + chestIds.put(new InstancePoint(3302, 5386), 28); + chestIds.put(new InstancePoint(3305, 5386), 29); + chestIds.put(new InstancePoint(3316, 5386), 30); + chestIds.put(new InstancePoint(3321, 5386), 31); + chestIds.put(new InstancePoint(3300, 5387), 32); + chestIds.put(new InstancePoint(3308, 5387), 33); + chestIds.put(new InstancePoint(3314, 5387), 34); + chestIds.put(new InstancePoint(3317, 5387), 35); + chestIds.put(new InstancePoint(3301, 5388), 36); + chestIds.put(new InstancePoint(3306, 5388), 37); + chestIds.put(new InstancePoint(3312, 5388), 38); + chestIds.put(new InstancePoint(3322, 5388), 39); + chestIds.put(new InstancePoint(3309, 5389), 40); + chestIds.put(new InstancePoint(3311, 5389), 41); + chestIds.put(new InstancePoint(3313, 5389), 42); + chestIds.put(new InstancePoint(3316, 5389), 43); + chestIds.put(new InstancePoint(3320, 5389), 44); + chestIds.put(new InstancePoint(3300, 5390), 45); + chestIds.put(new InstancePoint(3303, 5390), 46); + chestIds.put(new InstancePoint(3304, 5390), 47); + chestIds.put(new InstancePoint(3312, 5390), 48); + chestIds.put(new InstancePoint(3320, 5390), 49); + chestIds.put(new InstancePoint(3307, 5391), 50); + chestIds.put(new InstancePoint(3310, 5391), 51); + chestIds.put(new InstancePoint(3317, 5391), 52); + chestIds.put(new InstancePoint(3318, 5391), 53); + chestIds.put(new InstancePoint(3323, 5391), 54); + chestIds.put(new InstancePoint(3301, 5392), 55); + chestIds.put(new InstancePoint(3303, 5392), 56); + chestIds.put(new InstancePoint(3309, 5392), 57); + chestIds.put(new InstancePoint(3314, 5392), 58); + chestIds.put(new InstancePoint(3322, 5392), 59); + chestIds.put(new InstancePoint(3305, 5393), 60); + chestIds.put(new InstancePoint(3307, 5393), 61); + chestIds.put(new InstancePoint(3316, 5393), 62); + chestIds.put(new InstancePoint(3309, 5394), 63); + chestIds.put(new InstancePoint(3312, 5394), 64); + chestIds.put(new InstancePoint(3322, 5394), 65); + chestIds.put(new InstancePoint(3310, 5379), 66); + break; + } + + } + + public int indentifyChest(ThievingChest chest) + { + int id = chestIds.get(chest.getInstancePoint()); + chest.setChestId(id); + return id; + } + + private Map chestIds; +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/raidsthieving/BatSolver/SolutionSet.java b/runelite-client/src/main/java/net/runelite/client/plugins/raidsthieving/BatSolver/SolutionSet.java index dc1c3c3dc2..56c4520160 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/raidsthieving/BatSolver/SolutionSet.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/raidsthieving/BatSolver/SolutionSet.java @@ -1,165 +1,165 @@ -/* - * Copyright (c) 2018, Tim Lehner - * 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.raidsthieving.BatSolver; - -import lombok.Getter; -import java.util.HashSet; -import java.util.Arrays; -import java.util.Set; - -// Each Thieving room has 4 empty chests -// User-reported data shows these 4 come in groups, -// -// e.g. if there is an empty chest in L room chest 1, the other empty chests could be 16, 17, 38, 54, 55 -// See https://dikkenoob.github.io/ for more information - -public class SolutionSet -{ - public static final SolutionSet[] SOLUTION_SETS = - { - new SolutionSet(ThievingRoomType.LEFT_TURN, 1, 16, 17, 55), - new SolutionSet(ThievingRoomType.LEFT_TURN, 1, 17, 38, 54), - new SolutionSet(ThievingRoomType.LEFT_TURN, 2, 7, 21, 37), - new SolutionSet(ThievingRoomType.LEFT_TURN, 3, 5, 19, 30), - new SolutionSet(ThievingRoomType.LEFT_TURN, 3, 11, 15, 40), - new SolutionSet(ThievingRoomType.LEFT_TURN, 4, 22, 27, 46), - new SolutionSet(ThievingRoomType.LEFT_TURN, 5, 9, 19, 45), - new SolutionSet(ThievingRoomType.LEFT_TURN, 6, 24, 26, 41), - new SolutionSet(ThievingRoomType.LEFT_TURN, 6, 26, 32, 52), - new SolutionSet(ThievingRoomType.LEFT_TURN, 7, 13, 44, 59), - new SolutionSet(ThievingRoomType.LEFT_TURN, 8, 14, 41, 43), - new SolutionSet(ThievingRoomType.LEFT_TURN, 8, 10, 28, 33), - new SolutionSet(ThievingRoomType.LEFT_TURN, 8, 31, 47, 50), - new SolutionSet(ThievingRoomType.LEFT_TURN, 10, 35, 54, 63), - new SolutionSet(ThievingRoomType.LEFT_TURN, 10, 30, 32, 59), - new SolutionSet(ThievingRoomType.LEFT_TURN, 12, 40, 53, 56), - new SolutionSet(ThievingRoomType.LEFT_TURN, 12, 13, 42, 54), - new SolutionSet(ThievingRoomType.LEFT_TURN, 13, 22, 27, 46), - new SolutionSet(ThievingRoomType.LEFT_TURN, 14, 18, 23, 51), - new SolutionSet(ThievingRoomType.LEFT_TURN, 15, 43, 44, 58), - new SolutionSet(ThievingRoomType.LEFT_TURN, 15, 16, 42, 45), - new SolutionSet(ThievingRoomType.LEFT_TURN, 20, 29, 45, 51), - new SolutionSet(ThievingRoomType.LEFT_TURN, 20, 25, 32, 34), - new SolutionSet(ThievingRoomType.LEFT_TURN, 20, 28, 51, 62), - new SolutionSet(ThievingRoomType.LEFT_TURN, 21, 39, 41, 58), - new SolutionSet(ThievingRoomType.LEFT_TURN, 22, 25, 54, 64), - new SolutionSet(ThievingRoomType.LEFT_TURN, 23, 31, 47, 55), - new SolutionSet(ThievingRoomType.LEFT_TURN, 23, 33, 37, 60), - new SolutionSet(ThievingRoomType.LEFT_TURN, 24, 34, 55), - new SolutionSet(ThievingRoomType.LEFT_TURN, 26, 50, 63, 27), - new SolutionSet(ThievingRoomType.LEFT_TURN, 29, 39, 41, 61), - new SolutionSet(ThievingRoomType.LEFT_TURN, 33, 46, 52, 57), - new SolutionSet(ThievingRoomType.LEFT_TURN, 34, 45, 49, 60), - new SolutionSet(ThievingRoomType.LEFT_TURN, 36, 40, 42, 62), - new SolutionSet(ThievingRoomType.LEFT_TURN, 37, 38, 51, 64), - new SolutionSet(ThievingRoomType.LEFT_TURN, 48, 53, 55, 56), - new SolutionSet(ThievingRoomType.RIGHT_TURN, 1, 6, 28, 41), - new SolutionSet(ThievingRoomType.RIGHT_TURN, 1, 42, 55, 60), - new SolutionSet(ThievingRoomType.RIGHT_TURN, 2, 10, 31, 44), - new SolutionSet(ThievingRoomType.RIGHT_TURN, 2, 33, 51, 68), - new SolutionSet(ThievingRoomType.RIGHT_TURN, 3, 31, 43, 46), - new SolutionSet(ThievingRoomType.RIGHT_TURN, 3, 5, 21, 48), - new SolutionSet(ThievingRoomType.RIGHT_TURN, 4, 20, 24, 33), - new SolutionSet(ThievingRoomType.RIGHT_TURN, 4, 38, 47), - new SolutionSet(ThievingRoomType.RIGHT_TURN, 5, 21, 48), - new SolutionSet(ThievingRoomType.RIGHT_TURN, 5, 17, 35, 63), - new SolutionSet(ThievingRoomType.RIGHT_TURN, 7, 17, 45, 47), - new SolutionSet(ThievingRoomType.RIGHT_TURN, 7, 37, 41, 52), - new SolutionSet(ThievingRoomType.RIGHT_TURN, 8, 13, 40, 42), - new SolutionSet(ThievingRoomType.RIGHT_TURN, 8, 20, 24, 30), - new SolutionSet(ThievingRoomType.RIGHT_TURN, 9, 15, 23, 35), - new SolutionSet(ThievingRoomType.RIGHT_TURN, 11, 13, 21, 50), - new SolutionSet(ThievingRoomType.RIGHT_TURN, 11, 18, 37, 39), - new SolutionSet(ThievingRoomType.RIGHT_TURN, 12, 14, 27, 34), - new SolutionSet(ThievingRoomType.RIGHT_TURN, 14, 45, 67, 71), - new SolutionSet(ThievingRoomType.RIGHT_TURN, 16, 22, 29, 32), - new SolutionSet(ThievingRoomType.RIGHT_TURN, 18, 28, 31, 64), - new SolutionSet(ThievingRoomType.RIGHT_TURN, 19, 21, 63, 69), - new SolutionSet(ThievingRoomType.RIGHT_TURN, 20, 51, 68, 72), - new SolutionSet(ThievingRoomType.RIGHT_TURN, 22, 29, 56, 61), - new SolutionSet(ThievingRoomType.RIGHT_TURN, 23, 53, 66, 74), - new SolutionSet(ThievingRoomType.RIGHT_TURN, 26, 35, 53, 59), - new SolutionSet(ThievingRoomType.RIGHT_TURN, 27, 30, 55, 57), - new SolutionSet(ThievingRoomType.RIGHT_TURN, 31, 58, 60, 73), - new SolutionSet(ThievingRoomType.RIGHT_TURN, 34, 57, 58, 70), - new SolutionSet(ThievingRoomType.RIGHT_TURN, 38, 56, 61, 70), - new SolutionSet(ThievingRoomType.RIGHT_TURN, 40, 54, 65, 72), - new SolutionSet(ThievingRoomType.RIGHT_TURN, 42, 46, 65), - new SolutionSet(ThievingRoomType.RIGHT_TURN, 47, 49, 66, 67), - new SolutionSet(ThievingRoomType.RIGHT_TURN, 48, 62, 69), - new SolutionSet(ThievingRoomType.RIGHT_TURN, 9, 19, 32, 41), - new SolutionSet(ThievingRoomType.RIGHT_TURN, 16, 26, 36, 39), - new SolutionSet(ThievingRoomType.STRAIGHT, 1, 39, 43, 51), - new SolutionSet(ThievingRoomType.STRAIGHT, 2, 15, 20, 53), - new SolutionSet(ThievingRoomType.STRAIGHT, 3, 10, 42, 44), - new SolutionSet(ThievingRoomType.STRAIGHT, 4, 14, 38, 52), - new SolutionSet(ThievingRoomType.STRAIGHT, 5, 6, 35, 41), - new SolutionSet(ThievingRoomType.STRAIGHT, 7, 16, 34, 49), - new SolutionSet(ThievingRoomType.STRAIGHT, 9, 12, 26, 27), - new SolutionSet(ThievingRoomType.STRAIGHT, 13, 25, 30, 31), - new SolutionSet(ThievingRoomType.STRAIGHT, 15, 20, 53), - new SolutionSet(ThievingRoomType.STRAIGHT, 17, 24, 34, 58), - new SolutionSet(ThievingRoomType.STRAIGHT, 18, 23, 35, 57), - new SolutionSet(ThievingRoomType.STRAIGHT, 19, 26, 47, 65), - new SolutionSet(ThievingRoomType.STRAIGHT, 21, 33, 36, 61), - new SolutionSet(ThievingRoomType.STRAIGHT, 21, 54, 66), - new SolutionSet(ThievingRoomType.STRAIGHT, 22, 25, 46, 55), - new SolutionSet(ThievingRoomType.STRAIGHT, 24, 34, 58), - new SolutionSet(ThievingRoomType.STRAIGHT, 28, 40, 52, 62), - new SolutionSet(ThievingRoomType.STRAIGHT, 29, 41, 42, 63), - new SolutionSet(ThievingRoomType.STRAIGHT, 30, 32, 37, 64), - new SolutionSet(ThievingRoomType.STRAIGHT, 39, 43, 51), - new SolutionSet(ThievingRoomType.STRAIGHT, 43, 45, 50, 60), - new SolutionSet(ThievingRoomType.STRAIGHT, 51, 53, 56, 59) - }; - - SolutionSet(ThievingRoomType type) - { - this.type = type; - emptyChests = new HashSet<>(); - } - - private SolutionSet(ThievingRoomType type, Integer... emptyChests) - { - this.type = type; - this.emptyChests = new HashSet<>(Arrays.asList(emptyChests)); - } - - public void addEmptyChest(int chestId) - { - emptyChests.add(chestId); - } - - public boolean containsChest(int chestId) - { - return emptyChests.contains(chestId); - } - - @Getter - private ThievingRoomType type; - - @Getter - private Set emptyChests; -} +/* + * Copyright (c) 2018, Tim Lehner + * 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.raidsthieving.BatSolver; + +import java.util.Arrays; +import java.util.HashSet; +import java.util.Set; +import lombok.Getter; + +// Each Thieving room has 4 empty chests +// User-reported data shows these 4 come in groups, +// +// e.g. if there is an empty chest in L room chest 1, the other empty chests could be 16, 17, 38, 54, 55 +// See https://dikkenoob.github.io/ for more information + +public class SolutionSet +{ + public static final SolutionSet[] SOLUTION_SETS = + { + new SolutionSet(ThievingRoomType.LEFT_TURN, 1, 16, 17, 55), + new SolutionSet(ThievingRoomType.LEFT_TURN, 1, 17, 38, 54), + new SolutionSet(ThievingRoomType.LEFT_TURN, 2, 7, 21, 37), + new SolutionSet(ThievingRoomType.LEFT_TURN, 3, 5, 19, 30), + new SolutionSet(ThievingRoomType.LEFT_TURN, 3, 11, 15, 40), + new SolutionSet(ThievingRoomType.LEFT_TURN, 4, 22, 27, 46), + new SolutionSet(ThievingRoomType.LEFT_TURN, 5, 9, 19, 45), + new SolutionSet(ThievingRoomType.LEFT_TURN, 6, 24, 26, 41), + new SolutionSet(ThievingRoomType.LEFT_TURN, 6, 26, 32, 52), + new SolutionSet(ThievingRoomType.LEFT_TURN, 7, 13, 44, 59), + new SolutionSet(ThievingRoomType.LEFT_TURN, 8, 14, 41, 43), + new SolutionSet(ThievingRoomType.LEFT_TURN, 8, 10, 28, 33), + new SolutionSet(ThievingRoomType.LEFT_TURN, 8, 31, 47, 50), + new SolutionSet(ThievingRoomType.LEFT_TURN, 10, 35, 54, 63), + new SolutionSet(ThievingRoomType.LEFT_TURN, 10, 30, 32, 59), + new SolutionSet(ThievingRoomType.LEFT_TURN, 12, 40, 53, 56), + new SolutionSet(ThievingRoomType.LEFT_TURN, 12, 13, 42, 54), + new SolutionSet(ThievingRoomType.LEFT_TURN, 13, 22, 27, 46), + new SolutionSet(ThievingRoomType.LEFT_TURN, 14, 18, 23, 51), + new SolutionSet(ThievingRoomType.LEFT_TURN, 15, 43, 44, 58), + new SolutionSet(ThievingRoomType.LEFT_TURN, 15, 16, 42, 45), + new SolutionSet(ThievingRoomType.LEFT_TURN, 20, 29, 45, 51), + new SolutionSet(ThievingRoomType.LEFT_TURN, 20, 25, 32, 34), + new SolutionSet(ThievingRoomType.LEFT_TURN, 20, 28, 51, 62), + new SolutionSet(ThievingRoomType.LEFT_TURN, 21, 39, 41, 58), + new SolutionSet(ThievingRoomType.LEFT_TURN, 22, 25, 54, 64), + new SolutionSet(ThievingRoomType.LEFT_TURN, 23, 31, 47, 55), + new SolutionSet(ThievingRoomType.LEFT_TURN, 23, 33, 37, 60), + new SolutionSet(ThievingRoomType.LEFT_TURN, 24, 34, 55), + new SolutionSet(ThievingRoomType.LEFT_TURN, 26, 50, 63, 27), + new SolutionSet(ThievingRoomType.LEFT_TURN, 29, 39, 41, 61), + new SolutionSet(ThievingRoomType.LEFT_TURN, 33, 46, 52, 57), + new SolutionSet(ThievingRoomType.LEFT_TURN, 34, 45, 49, 60), + new SolutionSet(ThievingRoomType.LEFT_TURN, 36, 40, 42, 62), + new SolutionSet(ThievingRoomType.LEFT_TURN, 37, 38, 51, 64), + new SolutionSet(ThievingRoomType.LEFT_TURN, 48, 53, 55, 56), + new SolutionSet(ThievingRoomType.RIGHT_TURN, 1, 6, 28, 41), + new SolutionSet(ThievingRoomType.RIGHT_TURN, 1, 42, 55, 60), + new SolutionSet(ThievingRoomType.RIGHT_TURN, 2, 10, 31, 44), + new SolutionSet(ThievingRoomType.RIGHT_TURN, 2, 33, 51, 68), + new SolutionSet(ThievingRoomType.RIGHT_TURN, 3, 31, 43, 46), + new SolutionSet(ThievingRoomType.RIGHT_TURN, 3, 5, 21, 48), + new SolutionSet(ThievingRoomType.RIGHT_TURN, 4, 20, 24, 33), + new SolutionSet(ThievingRoomType.RIGHT_TURN, 4, 38, 47), + new SolutionSet(ThievingRoomType.RIGHT_TURN, 5, 21, 48), + new SolutionSet(ThievingRoomType.RIGHT_TURN, 5, 17, 35, 63), + new SolutionSet(ThievingRoomType.RIGHT_TURN, 7, 17, 45, 47), + new SolutionSet(ThievingRoomType.RIGHT_TURN, 7, 37, 41, 52), + new SolutionSet(ThievingRoomType.RIGHT_TURN, 8, 13, 40, 42), + new SolutionSet(ThievingRoomType.RIGHT_TURN, 8, 20, 24, 30), + new SolutionSet(ThievingRoomType.RIGHT_TURN, 9, 15, 23, 35), + new SolutionSet(ThievingRoomType.RIGHT_TURN, 11, 13, 21, 50), + new SolutionSet(ThievingRoomType.RIGHT_TURN, 11, 18, 37, 39), + new SolutionSet(ThievingRoomType.RIGHT_TURN, 12, 14, 27, 34), + new SolutionSet(ThievingRoomType.RIGHT_TURN, 14, 45, 67, 71), + new SolutionSet(ThievingRoomType.RIGHT_TURN, 16, 22, 29, 32), + new SolutionSet(ThievingRoomType.RIGHT_TURN, 18, 28, 31, 64), + new SolutionSet(ThievingRoomType.RIGHT_TURN, 19, 21, 63, 69), + new SolutionSet(ThievingRoomType.RIGHT_TURN, 20, 51, 68, 72), + new SolutionSet(ThievingRoomType.RIGHT_TURN, 22, 29, 56, 61), + new SolutionSet(ThievingRoomType.RIGHT_TURN, 23, 53, 66, 74), + new SolutionSet(ThievingRoomType.RIGHT_TURN, 26, 35, 53, 59), + new SolutionSet(ThievingRoomType.RIGHT_TURN, 27, 30, 55, 57), + new SolutionSet(ThievingRoomType.RIGHT_TURN, 31, 58, 60, 73), + new SolutionSet(ThievingRoomType.RIGHT_TURN, 34, 57, 58, 70), + new SolutionSet(ThievingRoomType.RIGHT_TURN, 38, 56, 61, 70), + new SolutionSet(ThievingRoomType.RIGHT_TURN, 40, 54, 65, 72), + new SolutionSet(ThievingRoomType.RIGHT_TURN, 42, 46, 65), + new SolutionSet(ThievingRoomType.RIGHT_TURN, 47, 49, 66, 67), + new SolutionSet(ThievingRoomType.RIGHT_TURN, 48, 62, 69), + new SolutionSet(ThievingRoomType.RIGHT_TURN, 9, 19, 32, 41), + new SolutionSet(ThievingRoomType.RIGHT_TURN, 16, 26, 36, 39), + new SolutionSet(ThievingRoomType.STRAIGHT, 1, 39, 43, 51), + new SolutionSet(ThievingRoomType.STRAIGHT, 2, 15, 20, 53), + new SolutionSet(ThievingRoomType.STRAIGHT, 3, 10, 42, 44), + new SolutionSet(ThievingRoomType.STRAIGHT, 4, 14, 38, 52), + new SolutionSet(ThievingRoomType.STRAIGHT, 5, 6, 35, 41), + new SolutionSet(ThievingRoomType.STRAIGHT, 7, 16, 34, 49), + new SolutionSet(ThievingRoomType.STRAIGHT, 9, 12, 26, 27), + new SolutionSet(ThievingRoomType.STRAIGHT, 13, 25, 30, 31), + new SolutionSet(ThievingRoomType.STRAIGHT, 15, 20, 53), + new SolutionSet(ThievingRoomType.STRAIGHT, 17, 24, 34, 58), + new SolutionSet(ThievingRoomType.STRAIGHT, 18, 23, 35, 57), + new SolutionSet(ThievingRoomType.STRAIGHT, 19, 26, 47, 65), + new SolutionSet(ThievingRoomType.STRAIGHT, 21, 33, 36, 61), + new SolutionSet(ThievingRoomType.STRAIGHT, 21, 54, 66), + new SolutionSet(ThievingRoomType.STRAIGHT, 22, 25, 46, 55), + new SolutionSet(ThievingRoomType.STRAIGHT, 24, 34, 58), + new SolutionSet(ThievingRoomType.STRAIGHT, 28, 40, 52, 62), + new SolutionSet(ThievingRoomType.STRAIGHT, 29, 41, 42, 63), + new SolutionSet(ThievingRoomType.STRAIGHT, 30, 32, 37, 64), + new SolutionSet(ThievingRoomType.STRAIGHT, 39, 43, 51), + new SolutionSet(ThievingRoomType.STRAIGHT, 43, 45, 50, 60), + new SolutionSet(ThievingRoomType.STRAIGHT, 51, 53, 56, 59) + }; + + SolutionSet(ThievingRoomType type) + { + this.type = type; + emptyChests = new HashSet<>(); + } + + private SolutionSet(ThievingRoomType type, Integer... emptyChests) + { + this.type = type; + this.emptyChests = new HashSet<>(Arrays.asList(emptyChests)); + } + + public void addEmptyChest(int chestId) + { + emptyChests.add(chestId); + } + + public boolean containsChest(int chestId) + { + return emptyChests.contains(chestId); + } + + @Getter + private ThievingRoomType type; + + @Getter + private Set emptyChests; +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/raidsthieving/ChestOverlay.java b/runelite-client/src/main/java/net/runelite/client/plugins/raidsthieving/ChestOverlay.java index 5e09486f89..6e478bae1d 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/raidsthieving/ChestOverlay.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/raidsthieving/ChestOverlay.java @@ -1,172 +1,172 @@ -/* - * Copyright (c) 2018, Tim Lehner - * 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.raidsthieving; - -import net.runelite.api.Client; -import net.runelite.api.Perspective; -import net.runelite.api.Point; -import net.runelite.api.coords.LocalPoint; -import net.runelite.api.coords.WorldPoint; -import net.runelite.client.plugins.raidsthieving.BatSolver.BatSolver; -import net.runelite.client.ui.overlay.Overlay; -import net.runelite.client.ui.overlay.OverlayLayer; -import net.runelite.client.ui.overlay.OverlayPosition; -import net.runelite.client.ui.overlay.components.ProgressPieComponent; -import javax.inject.Inject; -import java.awt.Color; -import java.awt.Dimension; -import java.awt.Graphics2D; -import java.util.Map; -import java.util.TreeSet; - -/** - * Represents the overlay that shows timers on traps that are placed by the - * player. - */ -public class ChestOverlay extends Overlay -{ - - private final Client client; - private final RaidsThievingPlugin plugin; - private final RaidsThievingConfig config; - - @Inject - ChestOverlay(Client client, RaidsThievingPlugin plugin, RaidsThievingConfig config) - { - setPosition(OverlayPosition.DYNAMIC); - setLayer(OverlayLayer.ABOVE_SCENE); - this.plugin = plugin; - this.config = config; - this.client = client; - } - - @Override - public Dimension render(Graphics2D graphics) - { - drawChests(graphics); - return null; - } - - /** - * Updates the timer colors. - */ - public void updateConfig() - { - } - - /** - * Iterates over all the traps that were placed by the local player, and - * draws a circle or a timer on the trap, depending on the trap state. - * - * @param graphics - */ - private void drawChests(Graphics2D graphics) - { - - for (Map.Entry entry : plugin.getChests().entrySet()) - { - ThievingChest chest = entry.getValue(); - WorldPoint pos = entry.getKey(); - - - if (chest != null) - { - if (!plugin.isBatsFound() && !chest.isEverOpened()) - { - if (shouldDrawChest(pos)) - { - Color drawColor = new Color(config.getPotentialBatColor().getRed(), - config.getPotentialBatColor().getGreen(), - config.getPotentialBatColor().getBlue(), - getChestOpacity(pos)); - drawCircleOnTrap(graphics, chest, drawColor); - } - } - if (chest.isPoison()) - { - drawCircleOnTrap(graphics, chest, config.getPoisonTrapColor()); - } - } - } - } - - private boolean shouldDrawChest(WorldPoint chestPos) - { - if (plugin.numberOfEmptyChestsFound() == 0) - { - return true; - } - int chestId = plugin.getChestId(chestPos); - BatSolver solver = plugin.getSolver(); - if (solver != null && chestId != -1) - { - TreeSet matches = solver.matchSolutions(); - return matches.contains(chestId) || matches.size() == 0; - } - return true; - } - - /** - * Draws a timer on a given trap. - * - * @param graphics - * @param chest The chest on which the circle needs to be drawn - * @param fill The fill color of the timer - */ - private void drawCircleOnTrap(Graphics2D graphics, ThievingChest chest, Color fill) - { - if (chest.getLocalPoint().getPlane() != client.getPlane()) - { - return; - } - LocalPoint localLoc = LocalPoint.fromWorld(client, chest.getLocalPoint()); - if (localLoc == null) - { - return; - } - Point loc = Perspective.localToCanvas(client, localLoc, chest.getLocalPoint().getPlane()); - - ProgressPieComponent pie = new ProgressPieComponent(); - pie.setFill(fill); - pie.setBorderColor(Color.BLACK); - pie.setPosition(loc); - pie.setProgress(1); - if (graphics != null && loc != null) - { - pie.render(graphics); - } - } - - private int getChestOpacity(WorldPoint chestPos) - { - int chestId = plugin.getChestId(chestPos); - BatSolver solver = plugin.getSolver(); - if (solver != null && chestId != -1) - { - return (int) (255 * solver.relativeLikelihoodPoison(chestId)); - } - return 255; - } -} +/* + * Copyright (c) 2018, Tim Lehner + * 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.raidsthieving; + +import java.awt.Color; +import java.awt.Dimension; +import java.awt.Graphics2D; +import java.util.Map; +import java.util.TreeSet; +import javax.inject.Inject; +import net.runelite.api.Client; +import net.runelite.api.Perspective; +import net.runelite.api.Point; +import net.runelite.api.coords.LocalPoint; +import net.runelite.api.coords.WorldPoint; +import net.runelite.client.plugins.raidsthieving.BatSolver.BatSolver; +import net.runelite.client.ui.overlay.Overlay; +import net.runelite.client.ui.overlay.OverlayLayer; +import net.runelite.client.ui.overlay.OverlayPosition; +import net.runelite.client.ui.overlay.components.ProgressPieComponent; + +/** + * Represents the overlay that shows timers on traps that are placed by the + * player. + */ +public class ChestOverlay extends Overlay +{ + + private final Client client; + private final RaidsThievingPlugin plugin; + private final RaidsThievingConfig config; + + @Inject + ChestOverlay(Client client, RaidsThievingPlugin plugin, RaidsThievingConfig config) + { + setPosition(OverlayPosition.DYNAMIC); + setLayer(OverlayLayer.ABOVE_SCENE); + this.plugin = plugin; + this.config = config; + this.client = client; + } + + @Override + public Dimension render(Graphics2D graphics) + { + drawChests(graphics); + return null; + } + + /** + * Updates the timer colors. + */ + public void updateConfig() + { + } + + /** + * Iterates over all the traps that were placed by the local player, and + * draws a circle or a timer on the trap, depending on the trap state. + * + * @param graphics + */ + private void drawChests(Graphics2D graphics) + { + + for (Map.Entry entry : plugin.getChests().entrySet()) + { + ThievingChest chest = entry.getValue(); + WorldPoint pos = entry.getKey(); + + + if (chest != null) + { + if (!plugin.isBatsFound() && !chest.isEverOpened()) + { + if (shouldDrawChest(pos)) + { + Color drawColor = new Color(config.getPotentialBatColor().getRed(), + config.getPotentialBatColor().getGreen(), + config.getPotentialBatColor().getBlue(), + getChestOpacity(pos)); + drawCircleOnTrap(graphics, chest, drawColor); + } + } + if (chest.isPoison()) + { + drawCircleOnTrap(graphics, chest, config.getPoisonTrapColor()); + } + } + } + } + + private boolean shouldDrawChest(WorldPoint chestPos) + { + if (plugin.numberOfEmptyChestsFound() == 0) + { + return true; + } + int chestId = plugin.getChestId(chestPos); + BatSolver solver = plugin.getSolver(); + if (solver != null && chestId != -1) + { + TreeSet matches = solver.matchSolutions(); + return matches.contains(chestId) || matches.size() == 0; + } + return true; + } + + /** + * Draws a timer on a given trap. + * + * @param graphics + * @param chest The chest on which the circle needs to be drawn + * @param fill The fill color of the timer + */ + private void drawCircleOnTrap(Graphics2D graphics, ThievingChest chest, Color fill) + { + if (chest.getLocalPoint().getPlane() != client.getPlane()) + { + return; + } + LocalPoint localLoc = LocalPoint.fromWorld(client, chest.getLocalPoint()); + if (localLoc == null) + { + return; + } + Point loc = Perspective.localToCanvas(client, localLoc, chest.getLocalPoint().getPlane()); + + ProgressPieComponent pie = new ProgressPieComponent(); + pie.setFill(fill); + pie.setBorderColor(Color.BLACK); + pie.setPosition(loc); + pie.setProgress(1); + if (graphics != null && loc != null) + { + pie.render(graphics); + } + } + + private int getChestOpacity(WorldPoint chestPos) + { + int chestId = plugin.getChestId(chestPos); + BatSolver solver = plugin.getSolver(); + if (solver != null && chestId != -1) + { + return (int) (255 * solver.relativeLikelihoodPoison(chestId)); + } + return 255; + } +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/raidsthieving/InstancePoint.java b/runelite-client/src/main/java/net/runelite/client/plugins/raidsthieving/InstancePoint.java index 0df80aeb65..ea463317e4 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/raidsthieving/InstancePoint.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/raidsthieving/InstancePoint.java @@ -1,98 +1,103 @@ -package net.runelite.client.plugins.raidsthieving; - -import lombok.Getter; -import net.runelite.api.Client; -import net.runelite.api.Point; -import net.runelite.api.coords.WorldPoint; - -import java.util.Objects; - -/** - * Represents a point in the instance chunk, invariant of rotation. - */ -@Getter -public class InstancePoint -{ - private static final int CHUNK_SIZE = 8; - private static final double CHUNK_OFFSET = 3.5; - - public InstancePoint(int x, int y, int rot) - { - this.x = x; - this.y = y; - this.rot = rot; - } - - public InstancePoint(int x, int y) - { - this.x = x; - this.y = y; - this.rot = 0; - } - - public static InstancePoint buildFromPoint(WorldPoint worldPoint, Client client) - { - Point point = new Point(worldPoint.getX(), worldPoint.getY()); - Point base = new Point(client.getBaseX(), client.getBaseY()); - int plane = worldPoint.getPlane(); - - int deltaX = point.getX() - base.getX(); - int deltaY = point.getY() - base.getY(); - int chunkIndexX = deltaX / CHUNK_SIZE; - int chunkIndexY = deltaY / CHUNK_SIZE; - - int chunkData = client.getInstanceTemplateChunks()[plane][chunkIndexX][chunkIndexY]; - int rotation = chunkData >> 1 & 0x3; - int y = (chunkData >> 3 & 0x7FF) * 8; - int x = (chunkData >> 14 & 0x3FF) * 8; - - return buildFromTile(base, point, rotation, new Point(x, y)); - } - - public static InstancePoint buildFromTile(Point base, Point tile, int rot, Point chunkOrigin) - { - int deltaX = tile.getX() - base.getX(); - int deltaY = tile.getY() - base.getY(); - - double chunkOffsetX = (deltaX % CHUNK_SIZE) - CHUNK_OFFSET; - double chunkOffsetY = (deltaY % CHUNK_SIZE) - CHUNK_OFFSET; - - for (int i = 0; i < rot; i++) - { - double temp = chunkOffsetX; - chunkOffsetX = -chunkOffsetY; - chunkOffsetY = temp; - } - - chunkOffsetX += CHUNK_OFFSET; - chunkOffsetY += CHUNK_OFFSET; - - int invariantChunkOffsetX = (int) chunkOffsetX; - int invariantChunkOffsetY = (int) chunkOffsetY; - - return new InstancePoint( - chunkOrigin.getX() + invariantChunkOffsetX, - chunkOrigin.getY() + invariantChunkOffsetY, - rot); - } - - @Override - public boolean equals(Object o) - { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - InstancePoint that = (InstancePoint) o; - return x == that.x && - y == that.y; - } - - @Override - public int hashCode() - { - return Objects.hash(x, y); - } - - private int x; - private int y; - private int rot; -} +package net.runelite.client.plugins.raidsthieving; + +import java.util.Objects; +import lombok.Getter; +import net.runelite.api.Client; +import net.runelite.api.Point; +import net.runelite.api.coords.WorldPoint; + +/** + * Represents a point in the instance chunk, invariant of rotation. + */ +@Getter +public class InstancePoint +{ + private static final int CHUNK_SIZE = 8; + private static final double CHUNK_OFFSET = 3.5; + + public InstancePoint(int x, int y, int rot) + { + this.x = x; + this.y = y; + this.rot = rot; + } + + public InstancePoint(int x, int y) + { + this.x = x; + this.y = y; + this.rot = 0; + } + + public static InstancePoint buildFromPoint(WorldPoint worldPoint, Client client) + { + Point point = new Point(worldPoint.getX(), worldPoint.getY()); + Point base = new Point(client.getBaseX(), client.getBaseY()); + int plane = worldPoint.getPlane(); + + int deltaX = point.getX() - base.getX(); + int deltaY = point.getY() - base.getY(); + int chunkIndexX = deltaX / CHUNK_SIZE; + int chunkIndexY = deltaY / CHUNK_SIZE; + + int chunkData = client.getInstanceTemplateChunks()[plane][chunkIndexX][chunkIndexY]; + int rotation = chunkData >> 1 & 0x3; + int y = (chunkData >> 3 & 0x7FF) * 8; + int x = (chunkData >> 14 & 0x3FF) * 8; + + return buildFromTile(base, point, rotation, new Point(x, y)); + } + + public static InstancePoint buildFromTile(Point base, Point tile, int rot, Point chunkOrigin) + { + int deltaX = tile.getX() - base.getX(); + int deltaY = tile.getY() - base.getY(); + + double chunkOffsetX = (deltaX % CHUNK_SIZE) - CHUNK_OFFSET; + double chunkOffsetY = (deltaY % CHUNK_SIZE) - CHUNK_OFFSET; + + for (int i = 0; i < rot; i++) + { + double temp = chunkOffsetX; + chunkOffsetX = -chunkOffsetY; + chunkOffsetY = temp; + } + + chunkOffsetX += CHUNK_OFFSET; + chunkOffsetY += CHUNK_OFFSET; + + int invariantChunkOffsetX = (int) chunkOffsetX; + int invariantChunkOffsetY = (int) chunkOffsetY; + + return new InstancePoint( + chunkOrigin.getX() + invariantChunkOffsetX, + chunkOrigin.getY() + invariantChunkOffsetY, + rot); + } + + @Override + public boolean equals(Object o) + { + if (this == o) + { + return true; + } + if (o == null || getClass() != o.getClass()) + { + return false; + } + InstancePoint that = (InstancePoint) o; + return x == that.x && + y == that.y; + } + + @Override + public int hashCode() + { + return Objects.hash(x, y); + } + + private int x; + private int y; + private int rot; +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/raidsthieving/RaidsThievingConfig.java b/runelite-client/src/main/java/net/runelite/client/plugins/raidsthieving/RaidsThievingConfig.java index bb055edf4e..90d8415302 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/raidsthieving/RaidsThievingConfig.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/raidsthieving/RaidsThievingConfig.java @@ -1,67 +1,67 @@ -/* - * Copyright (c) 2017, Tim Lehner - * 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.raidsthieving; - -import net.runelite.client.config.Config; -import net.runelite.client.config.ConfigGroup; -import net.runelite.client.config.ConfigItem; -import java.awt.Color; - -@ConfigGroup("raidsthievingplugin") -public interface RaidsThievingConfig extends Config -{ - @ConfigItem( - position = 1, - keyName = "hexColorPotentialBat", - name = "Potential Bat", - description = "Color of marker for chests which could have bat" - ) - default Color getPotentialBatColor() - { - return Color.YELLOW; - } - - @ConfigItem( - position = 2, - keyName = "hexColorPoison", - name = "Poison trap", - description = "Color of chest with poison" - ) - default Color getPoisonTrapColor() - { - return Color.GREEN; - } - - @ConfigItem( - position = 5, - keyName = "batNotify", - name = "Notify when found", - description = "Send notification if you see bats being found." - ) - default boolean batFoundNotify() - { - return false; - } -} +/* + * Copyright (c) 2017, Tim Lehner + * 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.raidsthieving; + +import java.awt.Color; +import net.runelite.client.config.Config; +import net.runelite.client.config.ConfigGroup; +import net.runelite.client.config.ConfigItem; + +@ConfigGroup("raidsthievingplugin") +public interface RaidsThievingConfig extends Config +{ + @ConfigItem( + position = 1, + keyName = "hexColorPotentialBat", + name = "Potential Bat", + description = "Color of marker for chests which could have bat" + ) + default Color getPotentialBatColor() + { + return Color.YELLOW; + } + + @ConfigItem( + position = 2, + keyName = "hexColorPoison", + name = "Poison trap", + description = "Color of chest with poison" + ) + default Color getPoisonTrapColor() + { + return Color.GREEN; + } + + @ConfigItem( + position = 5, + keyName = "batNotify", + name = "Notify when found", + description = "Send notification if you see bats being found." + ) + default boolean batFoundNotify() + { + return false; + } +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/raidsthieving/RaidsThievingPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/raidsthieving/RaidsThievingPlugin.java index 8f0baf9639..3c1b19a4e5 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/raidsthieving/RaidsThievingPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/raidsthieving/RaidsThievingPlugin.java @@ -1,272 +1,272 @@ -/* - * Copyright (c) 2017, Tim Lehner - * 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.raidsthieving; - -import com.google.inject.Provides; -import lombok.Getter; -import lombok.extern.slf4j.Slf4j; -import net.runelite.api.Client; -import net.runelite.api.GameObject; -import net.runelite.api.GraphicsObject; -import net.runelite.api.Varbits; -import net.runelite.api.coords.WorldPoint; -import net.runelite.api.events.ConfigChanged; -import net.runelite.api.events.GameObjectSpawned; -import net.runelite.api.events.GraphicsObjectCreated; -import net.runelite.api.events.VarbitChanged; -import net.runelite.client.Notifier; -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.plugins.PluginType; -import net.runelite.client.plugins.raidsthieving.BatSolver.BatSolver; -import net.runelite.client.plugins.raidsthieving.BatSolver.ChestIdentifier; -import net.runelite.client.plugins.raidsthieving.BatSolver.ThievingRoomType; -import net.runelite.client.ui.overlay.OverlayManager; -import javax.inject.Inject; -import java.text.MessageFormat; -import java.time.Instant; -import java.util.HashMap; -import java.util.Map; - -@Slf4j -@PluginDescriptor( - name = "Raids Bat Finder", - description = "Tracks which chests need to be searched for bats and which poison", - tags = {"overlay", "skilling", "raid"}, - type = PluginType.PVM -) -public class RaidsThievingPlugin extends Plugin -{ - @Inject - private Client client; - - @Inject - private OverlayManager overlayManager; - - @Inject - private ChestOverlay overlay; - - @Inject - private Notifier notifier; - - @Inject - private RaidsThievingConfig config; - - @Getter - private final Map chests = new HashMap<>(); - - @Getter - private Instant lastActionTime = Instant.ofEpochMilli(0); - - private boolean inRaidChambers; - - @Getter - private boolean batsFound; - - @Getter - private BatSolver solver; - - @Getter - private ChestIdentifier mapper; - - - @Provides - RaidsThievingConfig provideConfig(ConfigManager configManager) - { - return configManager.getConfig(RaidsThievingConfig.class); - } - - @Override - protected void startUp() - { - overlayManager.add(overlay); - overlay.updateConfig(); - reset(); - } - - @Override - protected void shutDown() throws Exception - { - overlayManager.remove(overlay); - lastActionTime = Instant.ofEpochMilli(0); - chests.clear(); - } - - - @Subscribe - public void onGameObjectSpawned(GameObjectSpawned event) - { - GameObject obj = event.getGameObject(); - WorldPoint loc = obj.getWorldLocation(); - InstancePoint absLoc = InstancePoint.buildFromPoint(loc, client); - - if (obj.getId() == RaidsThievingConstants.EMPTY_TROUGH) - { - ThievingRoomType type = ThievingRoomType.IdentifyByInstancePoint(absLoc); - - if (type != null) - { - solver = new BatSolver(type); - mapper = new ChestIdentifier(type); - for (ThievingChest chest : chests.values()) - { - mapper.indentifyChest(chest); - } - } - else - { - log.error(MessageFormat.format("Unable to identify room type with: {0} {1} {2} {3} {4}.", - loc.getX(), loc.getY(), absLoc.getX(), absLoc.getY(), absLoc.getRot())); - log.error("Please report this @https://github.com/runelite/runelite/pull/4914!"); - } - } - if (obj.getId() == RaidsThievingConstants.CLOSED_CHEST_ID) - { - if (!chests.containsKey(loc)) - { - ThievingChest chest = new ThievingChest(obj, absLoc); - - if (mapper != null) - { - mapper.indentifyChest(chest); - } - - chests.put(loc, chest); - } - else - { - checkForBats(); - } - } - - if (obj.getId() == RaidsThievingConstants.OPEN_FULL_CHEST_1 || - obj.getId() == RaidsThievingConstants.OPEN_FULL_CHEST_2) - { - ThievingChest chest = chests.get(obj.getWorldLocation()); - // We found a chest that has grubs - log.info(MessageFormat.format("Found grubs at {0}, {1} chestId: {2}", loc.getX(), loc.getY(), chest.getChestId())); - if (solver != null && chest.getChestId() != -1) - { - chest.setEverOpened(true); - solver.addGrubsChest(chest.getChestId()); - } - checkForBats(); - } - - if (obj.getId() == RaidsThievingConstants.OPEN_EMPTY_CHEST) - { - ThievingChest chest = chests.get(obj.getWorldLocation()); - // We found a chest that could have poison - if (solver != null && chest.getChestId() != -1) - { - chest.setEmpty(true); - chest.setEverOpened(true); - solver.addEmptyChest(chest.getChestId()); - } - } - } - - - @Subscribe - public void onGraphicsObjectCreated(GraphicsObjectCreated event) - { - GraphicsObject obj = event.getGraphicsObject(); - if (obj.getId() == 184) - { - log.debug("Found poison splat"); - WorldPoint loc = WorldPoint.fromLocal(client, obj.getLocation()); - chests.get(loc).setPoison(true); - } - } - - @Subscribe - public void onVarbitChanged(VarbitChanged event) - { - boolean setting = client.getVar(Varbits.IN_RAID) == 1; - - if (inRaidChambers != setting) - { - inRaidChambers = setting; - reset(); - } - - } - - @Subscribe - public void onConfigChanged(ConfigChanged event) - { - if (event.getGroup().equals("raidsthievingplugin")) - { - overlay.updateConfig(); - } - } - - private void reset() - { - chests.clear(); - batsFound = false; - solver = null; - mapper = null; - } - - public int numberOfEmptyChestsFound() - { - int total = 0; - for (ThievingChest chest : chests.values()) - { - if (chest.isEmpty()) - { - total++; - } - } - return total; - } - - - private boolean checkForBats() - { - for (ThievingChest chest : chests.values()) - { - if (chest.isEmpty() && !chest.isPoison()) - { - batsFound = true; - if (config.batFoundNotify()) - { - notifier.notify("Bats have been found!"); - } - return true; - } - } - return false; - } - - public int getChestId(WorldPoint worldPoint) - { - return chests.get(worldPoint).getChestId(); - } -} - +/* + * Copyright (c) 2017, Tim Lehner + * 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.raidsthieving; + +import com.google.inject.Provides; +import java.text.MessageFormat; +import java.time.Instant; +import java.util.HashMap; +import java.util.Map; +import javax.inject.Inject; +import lombok.Getter; +import lombok.extern.slf4j.Slf4j; +import net.runelite.api.Client; +import net.runelite.api.GameObject; +import net.runelite.api.GraphicsObject; +import net.runelite.api.Varbits; +import net.runelite.api.coords.WorldPoint; +import net.runelite.api.events.ConfigChanged; +import net.runelite.api.events.GameObjectSpawned; +import net.runelite.api.events.GraphicsObjectCreated; +import net.runelite.api.events.VarbitChanged; +import net.runelite.client.Notifier; +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.plugins.PluginType; +import net.runelite.client.plugins.raidsthieving.BatSolver.BatSolver; +import net.runelite.client.plugins.raidsthieving.BatSolver.ChestIdentifier; +import net.runelite.client.plugins.raidsthieving.BatSolver.ThievingRoomType; +import net.runelite.client.ui.overlay.OverlayManager; + +@Slf4j +@PluginDescriptor( + name = "Raids Bat Finder", + description = "Tracks which chests need to be searched for bats and which poison", + tags = {"overlay", "skilling", "raid"}, + type = PluginType.PVM +) +public class RaidsThievingPlugin extends Plugin +{ + @Inject + private Client client; + + @Inject + private OverlayManager overlayManager; + + @Inject + private ChestOverlay overlay; + + @Inject + private Notifier notifier; + + @Inject + private RaidsThievingConfig config; + + @Getter + private final Map chests = new HashMap<>(); + + @Getter + private Instant lastActionTime = Instant.ofEpochMilli(0); + + private boolean inRaidChambers; + + @Getter + private boolean batsFound; + + @Getter + private BatSolver solver; + + @Getter + private ChestIdentifier mapper; + + + @Provides + RaidsThievingConfig provideConfig(ConfigManager configManager) + { + return configManager.getConfig(RaidsThievingConfig.class); + } + + @Override + protected void startUp() + { + overlayManager.add(overlay); + overlay.updateConfig(); + reset(); + } + + @Override + protected void shutDown() throws Exception + { + overlayManager.remove(overlay); + lastActionTime = Instant.ofEpochMilli(0); + chests.clear(); + } + + + @Subscribe + public void onGameObjectSpawned(GameObjectSpawned event) + { + GameObject obj = event.getGameObject(); + WorldPoint loc = obj.getWorldLocation(); + InstancePoint absLoc = InstancePoint.buildFromPoint(loc, client); + + if (obj.getId() == RaidsThievingConstants.EMPTY_TROUGH) + { + ThievingRoomType type = ThievingRoomType.IdentifyByInstancePoint(absLoc); + + if (type != null) + { + solver = new BatSolver(type); + mapper = new ChestIdentifier(type); + for (ThievingChest chest : chests.values()) + { + mapper.indentifyChest(chest); + } + } + else + { + log.error(MessageFormat.format("Unable to identify room type with: {0} {1} {2} {3} {4}.", + loc.getX(), loc.getY(), absLoc.getX(), absLoc.getY(), absLoc.getRot())); + log.error("Please report this @https://github.com/runelite/runelite/pull/4914!"); + } + } + if (obj.getId() == RaidsThievingConstants.CLOSED_CHEST_ID) + { + if (!chests.containsKey(loc)) + { + ThievingChest chest = new ThievingChest(obj, absLoc); + + if (mapper != null) + { + mapper.indentifyChest(chest); + } + + chests.put(loc, chest); + } + else + { + checkForBats(); + } + } + + if (obj.getId() == RaidsThievingConstants.OPEN_FULL_CHEST_1 || + obj.getId() == RaidsThievingConstants.OPEN_FULL_CHEST_2) + { + ThievingChest chest = chests.get(obj.getWorldLocation()); + // We found a chest that has grubs + log.info(MessageFormat.format("Found grubs at {0}, {1} chestId: {2}", loc.getX(), loc.getY(), chest.getChestId())); + if (solver != null && chest.getChestId() != -1) + { + chest.setEverOpened(true); + solver.addGrubsChest(chest.getChestId()); + } + checkForBats(); + } + + if (obj.getId() == RaidsThievingConstants.OPEN_EMPTY_CHEST) + { + ThievingChest chest = chests.get(obj.getWorldLocation()); + // We found a chest that could have poison + if (solver != null && chest.getChestId() != -1) + { + chest.setEmpty(true); + chest.setEverOpened(true); + solver.addEmptyChest(chest.getChestId()); + } + } + } + + + @Subscribe + public void onGraphicsObjectCreated(GraphicsObjectCreated event) + { + GraphicsObject obj = event.getGraphicsObject(); + if (obj.getId() == 184) + { + log.debug("Found poison splat"); + WorldPoint loc = WorldPoint.fromLocal(client, obj.getLocation()); + chests.get(loc).setPoison(true); + } + } + + @Subscribe + public void onVarbitChanged(VarbitChanged event) + { + boolean setting = client.getVar(Varbits.IN_RAID) == 1; + + if (inRaidChambers != setting) + { + inRaidChambers = setting; + reset(); + } + + } + + @Subscribe + public void onConfigChanged(ConfigChanged event) + { + if (event.getGroup().equals("raidsthievingplugin")) + { + overlay.updateConfig(); + } + } + + private void reset() + { + chests.clear(); + batsFound = false; + solver = null; + mapper = null; + } + + public int numberOfEmptyChestsFound() + { + int total = 0; + for (ThievingChest chest : chests.values()) + { + if (chest.isEmpty()) + { + total++; + } + } + return total; + } + + + private boolean checkForBats() + { + for (ThievingChest chest : chests.values()) + { + if (chest.isEmpty() && !chest.isPoison()) + { + batsFound = true; + if (config.batFoundNotify()) + { + notifier.notify("Bats have been found!"); + } + return true; + } + } + return false; + } + + public int getChestId(WorldPoint worldPoint) + { + return chests.get(worldPoint).getChestId(); + } +} + diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/rememberclan/RememberClanConfig.java b/runelite-client/src/main/java/net/runelite/client/plugins/rememberclan/RememberClanConfig.java index 20775b1d35..d27f688d2e 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/rememberclan/RememberClanConfig.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/rememberclan/RememberClanConfig.java @@ -1,48 +1,48 @@ -/* - * Copyright (c) 2018, Infinitay - * Copyright (c) 2018, Shaun Dreclin - * - * 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.rememberclan; - -import net.runelite.client.config.Config; -import net.runelite.client.config.ConfigGroup; -import net.runelite.client.config.ConfigItem; - -@ConfigGroup("rememberclan") -public interface RememberClanConfig extends Config -{ - @ConfigItem( - position = 1, - keyName = "clanname", - name = "Clan Name", - description = "Clanname to always remember" - ) - default String clanname() - { - return ""; - } - - -} +/* + * Copyright (c) 2018, Infinitay + * Copyright (c) 2018, Shaun Dreclin + * + * 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.rememberclan; + +import net.runelite.client.config.Config; +import net.runelite.client.config.ConfigGroup; +import net.runelite.client.config.ConfigItem; + +@ConfigGroup("rememberclan") +public interface RememberClanConfig extends Config +{ + @ConfigItem( + position = 1, + keyName = "clanname", + name = "Clan Name", + description = "Clanname to always remember" + ) + default String clanname() + { + return ""; + } + + +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/rememberclan/RememberClanPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/rememberclan/RememberClanPlugin.java index bdac2a3289..e28d856023 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/rememberclan/RememberClanPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/rememberclan/RememberClanPlugin.java @@ -1,80 +1,75 @@ -/* - * Copyright (c) 2018, Infinitay - * Copyright (c) 2018, Shaun Dreclin - * 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.rememberclan; - -import com.google.inject.Provides; -import javax.inject.Inject; - -import net.runelite.api.*; -import net.runelite.api.events.GameStateChanged; -import net.runelite.api.events.GameTick; -import net.runelite.api.vars.AccountType; -import net.runelite.client.chat.ChatColorType; -import net.runelite.client.chat.ChatMessageBuilder; -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.plugins.Plugin; -import net.runelite.client.plugins.PluginDescriptor; -import net.runelite.client.plugins.PluginType; - -@PluginDescriptor( - name = "Remember Clan", - description = "Remember a specific clan!", - type = PluginType.UTILITY, - enabledByDefault = false -) -public class RememberClanPlugin extends Plugin -{ - - @Inject - private Client client; - - @Inject - private RememberClanConfig config; - - @Inject - private ChatMessageManager chatMessageManager; - - private boolean loggingIn; - - @Provides - RememberClanConfig provideConfig(ConfigManager configManager) - { - return configManager.getConfig(RememberClanConfig.class); - } - - @Subscribe - public void onGameTick(GameTick event) - { - client.setVar(VarClientStr.RECENT_CLAN_CHAT,config.clanname()); - - } - - -} +/* + * Copyright (c) 2018, Infinitay + * Copyright (c) 2018, Shaun Dreclin + * 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.rememberclan; + +import com.google.inject.Provides; +import javax.inject.Inject; +import net.runelite.api.Client; +import net.runelite.api.VarClientStr; +import net.runelite.api.events.GameTick; +import net.runelite.client.chat.ChatMessageManager; +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.plugins.PluginType; + +@PluginDescriptor( + name = "Remember Clan", + description = "Remember a specific clan!", + type = PluginType.UTILITY, + enabledByDefault = false +) +public class RememberClanPlugin extends Plugin +{ + + @Inject + private Client client; + + @Inject + private RememberClanConfig config; + + @Inject + private ChatMessageManager chatMessageManager; + + private boolean loggingIn; + + @Provides + RememberClanConfig provideConfig(ConfigManager configManager) + { + return configManager.getConfig(RememberClanConfig.class); + } + + @Subscribe + public void onGameTick(GameTick event) + { + client.setVar(VarClientStr.RECENT_CLAN_CHAT, config.clanname()); + + } + + +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/reorderprayers/ReorderPrayersPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/reorderprayers/ReorderPrayersPlugin.java index 0c85f32c8e..64d1051add 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/reorderprayers/ReorderPrayersPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/reorderprayers/ReorderPrayersPlugin.java @@ -1,453 +1,453 @@ -/* - * Copyright (c) 2018, Adam - * 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.reorderprayers; - -import com.google.common.collect.ImmutableList; -import com.google.inject.Provides; -import java.util.Arrays; -import java.util.List; -import java.util.Objects; -import java.util.stream.Collectors; -import javax.inject.Inject; -import net.runelite.api.Client; -import net.runelite.api.GameState; -import net.runelite.api.HashTable; -import net.runelite.api.Prayer; -import net.runelite.api.WidgetNode; -import net.runelite.api.events.ConfigChanged; -import net.runelite.api.events.DraggingWidgetChanged; -import net.runelite.api.events.GameStateChanged; -import net.runelite.api.events.WidgetLoaded; -import net.runelite.api.events.WidgetMenuOptionClicked; -import net.runelite.api.widgets.Widget; -import static net.runelite.api.widgets.WidgetConfig.DRAG; -import static net.runelite.api.widgets.WidgetConfig.DRAG_ON; -import net.runelite.api.widgets.WidgetID; -import net.runelite.api.widgets.WidgetInfo; -import net.runelite.client.config.ConfigManager; -import net.runelite.client.eventbus.Subscribe; -import net.runelite.client.menus.MenuManager; -import net.runelite.client.menus.WidgetMenuOption; -import net.runelite.client.plugins.Plugin; -import net.runelite.client.plugins.PluginDescriptor; - -@PluginDescriptor( - name = "Reorder Prayers", - description = "Reorder the prayers displayed on the Prayer panel" -) -public class ReorderPrayersPlugin extends Plugin -{ - - static final String CONFIG_GROUP_KEY = "reorderprayers"; - - static final String CONFIG_UNLOCK_REORDERING_KEY = "unlockPrayerReordering"; - - static final String CONFIG_PRAYER_ORDER_KEY = "prayerOrder"; - - private static final int PRAYER_WIDTH = 34; - - private static final int PRAYER_HEIGHT = 34; - - private static final int PRAYER_X_OFFSET = 37; - - private static final int PRAYER_Y_OFFSET = 37; - - private static final int QUICK_PRAYER_SPRITE_X_OFFSET = 2; - - private static final int QUICK_PRAYER_SPRITE_Y_OFFSET = 2; - - private static final int PRAYER_COLUMN_COUNT = 5; - - private static final int PRAYER_COUNT = Prayer.values().length; - - private static final List PRAYER_WIDGET_INFO_LIST = ImmutableList.of( - WidgetInfo.PRAYER_THICK_SKIN, - WidgetInfo.PRAYER_BURST_OF_STRENGTH, - WidgetInfo.PRAYER_CLARITY_OF_THOUGHT, - WidgetInfo.PRAYER_SHARP_EYE, - WidgetInfo.PRAYER_MYSTIC_WILL, - WidgetInfo.PRAYER_ROCK_SKIN, - WidgetInfo.PRAYER_SUPERHUMAN_STRENGTH, - WidgetInfo.PRAYER_IMPROVED_REFLEXES, - WidgetInfo.PRAYER_RAPID_RESTORE, - WidgetInfo.PRAYER_RAPID_HEAL, - WidgetInfo.PRAYER_PROTECT_ITEM, - WidgetInfo.PRAYER_HAWK_EYE, - WidgetInfo.PRAYER_MYSTIC_LORE, - WidgetInfo.PRAYER_STEEL_SKIN, - WidgetInfo.PRAYER_ULTIMATE_STRENGTH, - WidgetInfo.PRAYER_INCREDIBLE_REFLEXES, - WidgetInfo.PRAYER_PROTECT_FROM_MAGIC, - WidgetInfo.PRAYER_PROTECT_FROM_MISSILES, - WidgetInfo.PRAYER_PROTECT_FROM_MELEE, - WidgetInfo.PRAYER_EAGLE_EYE, - WidgetInfo.PRAYER_MYSTIC_MIGHT, - WidgetInfo.PRAYER_RETRIBUTION, - WidgetInfo.PRAYER_REDEMPTION, - WidgetInfo.PRAYER_SMITE, - WidgetInfo.PRAYER_PRESERVE, - WidgetInfo.PRAYER_CHIVALRY, - WidgetInfo.PRAYER_PIETY, - WidgetInfo.PRAYER_RIGOUR, - WidgetInfo.PRAYER_AUGURY - ); - - private static final List QUICK_PRAYER_CHILD_IDS = ImmutableList.of( - WidgetID.QuickPrayer.THICK_SKIN_CHILD_ID, - WidgetID.QuickPrayer.BURST_OF_STRENGTH_CHILD_ID, - WidgetID.QuickPrayer.CLARITY_OF_THOUGHT_CHILD_ID, - WidgetID.QuickPrayer.SHARP_EYE_CHILD_ID, - WidgetID.QuickPrayer.MYSTIC_WILL_CHILD_ID, - WidgetID.QuickPrayer.ROCK_SKIN_CHILD_ID, - WidgetID.QuickPrayer.SUPERHUMAN_STRENGTH_CHILD_ID, - WidgetID.QuickPrayer.IMPROVED_REFLEXES_CHILD_ID, - WidgetID.QuickPrayer.RAPID_RESTORE_CHILD_ID, - WidgetID.QuickPrayer.RAPID_HEAL_CHILD_ID, - WidgetID.QuickPrayer.PROTECT_ITEM_CHILD_ID, - WidgetID.QuickPrayer.HAWK_EYE_CHILD_ID, - WidgetID.QuickPrayer.MYSTIC_LORE_CHILD_ID, - WidgetID.QuickPrayer.STEEL_SKIN_CHILD_ID, - WidgetID.QuickPrayer.ULTIMATE_STRENGTH_CHILD_ID, - WidgetID.QuickPrayer.INCREDIBLE_REFLEXES_CHILD_ID, - WidgetID.QuickPrayer.PROTECT_FROM_MAGIC_CHILD_ID, - WidgetID.QuickPrayer.PROTECT_FROM_MISSILES_CHILD_ID, - WidgetID.QuickPrayer.PROTECT_FROM_MELEE_CHILD_ID, - WidgetID.QuickPrayer.EAGLE_EYE_CHILD_ID, - WidgetID.QuickPrayer.MYSTIC_MIGHT_CHILD_ID, - WidgetID.QuickPrayer.RETRIBUTION_CHILD_ID, - WidgetID.QuickPrayer.REDEMPTION_CHILD_ID, - WidgetID.QuickPrayer.SMITE_CHILD_ID, - WidgetID.QuickPrayer.PRESERVE_CHILD_ID, - WidgetID.QuickPrayer.CHIVALRY_CHILD_ID, - WidgetID.QuickPrayer.PIETY_CHILD_ID, - WidgetID.QuickPrayer.RIGOUR_CHILD_ID, - WidgetID.QuickPrayer.AUGURY_CHILD_ID - ); - - private static final String LOCK = "Lock"; - - private static final String UNLOCK = "Unlock"; - - private static final String MENU_TARGET = "Reordering"; - - private static final WidgetMenuOption FIXED_PRAYER_TAB_LOCK = new WidgetMenuOption(LOCK, - MENU_TARGET, WidgetInfo.FIXED_VIEWPORT_PRAYER_TAB); - - private static final WidgetMenuOption FIXED_PRAYER_TAB_UNLOCK = new WidgetMenuOption(UNLOCK, - MENU_TARGET, WidgetInfo.FIXED_VIEWPORT_PRAYER_TAB); - - private static final WidgetMenuOption RESIZABLE_PRAYER_TAB_LOCK = new WidgetMenuOption(LOCK, - MENU_TARGET, WidgetInfo.RESIZABLE_VIEWPORT_PRAYER_TAB); - - private static final WidgetMenuOption RESIZABLE_PRAYER_TAB_UNLOCK = new WidgetMenuOption(UNLOCK, - MENU_TARGET, WidgetInfo.RESIZABLE_VIEWPORT_PRAYER_TAB); - - private static final WidgetMenuOption RESIZABLE_BOTTOM_LINE_PRAYER_TAB_LOCK = new WidgetMenuOption(LOCK, - MENU_TARGET, WidgetInfo.RESIZABLE_VIEWPORT_BOTTOM_LINE_PRAYER_TAB); - - private static final WidgetMenuOption RESIZABLE_BOTTOM_LINE_PRAYER_TAB_UNLOCK = new WidgetMenuOption(UNLOCK, - MENU_TARGET, WidgetInfo.RESIZABLE_VIEWPORT_BOTTOM_LINE_PRAYER_TAB); - - @Inject - private Client client; - - @Inject - private ReorderPrayersConfig config; - - @Inject - private MenuManager menuManager; - - private Prayer[] prayerOrder; - - static String prayerOrderToString(Prayer[] prayerOrder) - { - return Arrays.stream(prayerOrder) - .map(Prayer::name) - .collect(Collectors.joining(",")); - } - - private static Prayer[] stringToPrayerOrder(String string) - { - return Arrays.stream(string.split(",")) - .map(Prayer::valueOf) - .toArray(Prayer[]::new); - } - - private static int getPrayerIndex(Widget widget) - { - int x = widget.getOriginalX() / PRAYER_X_OFFSET; - int y = widget.getOriginalY() / PRAYER_Y_OFFSET; - return x + y * PRAYER_COLUMN_COUNT; - } - - private static void setWidgetPosition(Widget widget, int x, int y) - { - widget.setRelativeX(x); - widget.setRelativeY(y); - widget.setOriginalX(x); - widget.setOriginalY(y); - } - - @Provides - ReorderPrayersConfig provideConfig(ConfigManager configManager) - { - return configManager.getConfig(ReorderPrayersConfig.class); - } - - @Override - protected void startUp() throws Exception - { - refreshPrayerTabOption(); - prayerOrder = stringToPrayerOrder(config.prayerOrder()); - reorderPrayers(); - } - - @Override - protected void shutDown() throws Exception - { - clearPrayerTabMenus(); - prayerOrder = Prayer.values(); - reorderPrayers(false); - } - - @Subscribe - public void onGameStateChanged(GameStateChanged event) - { - if (event.getGameState() == GameState.LOGGED_IN) - { - reorderPrayers(); - } - } - - @Subscribe - public void onConfigChanged(ConfigChanged event) - { - if (event.getGroup().equals(CONFIG_GROUP_KEY)) - { - if (event.getKey().equals(CONFIG_PRAYER_ORDER_KEY)) - { - prayerOrder = stringToPrayerOrder(config.prayerOrder()); - } - else if (event.getKey().equals(CONFIG_UNLOCK_REORDERING_KEY)) - { - refreshPrayerTabOption(); - } - reorderPrayers(); - } - } - - @Subscribe - public void onWidgetLoaded(WidgetLoaded event) - { - if (event.getGroupId() == WidgetID.PRAYER_GROUP_ID || event.getGroupId() == WidgetID.QUICK_PRAYERS_GROUP_ID) - { - reorderPrayers(); - } - } - - @Subscribe - public void onDraggingWidgetChanged(DraggingWidgetChanged event) - { - // is dragging widget and mouse button released - if (event.isDraggingWidget() && client.getMouseCurrentButton() == 0) - { - Widget draggedWidget = client.getDraggedWidget(); - Widget draggedOnWidget = client.getDraggedOnWidget(); - if (draggedWidget != null && draggedOnWidget != null) - { - int draggedGroupId = WidgetInfo.TO_GROUP(draggedWidget.getId()); - int draggedOnGroupId = WidgetInfo.TO_GROUP(draggedOnWidget.getId()); - if (draggedGroupId != WidgetID.PRAYER_GROUP_ID || draggedOnGroupId != WidgetID.PRAYER_GROUP_ID - || draggedOnWidget.getWidth() != PRAYER_WIDTH || draggedOnWidget.getHeight() != PRAYER_HEIGHT) - { - return; - } - // reset dragged on widget to prevent sending a drag widget packet to the server - client.setDraggedOnWidget(null); - - int fromPrayerIndex = getPrayerIndex(draggedWidget); - int toPrayerIndex = getPrayerIndex(draggedOnWidget); - - Prayer tmp = prayerOrder[toPrayerIndex]; - prayerOrder[toPrayerIndex] = prayerOrder[fromPrayerIndex]; - prayerOrder[fromPrayerIndex] = tmp; - - save(); - } - } - } - - @Subscribe - public void onWidgetMenuOptionClicked(WidgetMenuOptionClicked event) - { - if (event.getWidget() == WidgetInfo.FIXED_VIEWPORT_PRAYER_TAB - || event.getWidget() == WidgetInfo.RESIZABLE_VIEWPORT_PRAYER_TAB - || event.getWidget() == WidgetInfo.RESIZABLE_VIEWPORT_BOTTOM_LINE_PRAYER_TAB) - { - config.unlockPrayerReordering(event.getMenuOption().equals(UNLOCK)); - } - } - - private void clearPrayerTabMenus() - { - menuManager.removeManagedCustomMenu(FIXED_PRAYER_TAB_LOCK); - menuManager.removeManagedCustomMenu(RESIZABLE_PRAYER_TAB_LOCK); - menuManager.removeManagedCustomMenu(RESIZABLE_BOTTOM_LINE_PRAYER_TAB_LOCK); - menuManager.removeManagedCustomMenu(FIXED_PRAYER_TAB_UNLOCK); - menuManager.removeManagedCustomMenu(RESIZABLE_PRAYER_TAB_UNLOCK); - menuManager.removeManagedCustomMenu(RESIZABLE_BOTTOM_LINE_PRAYER_TAB_UNLOCK); - } - - private void refreshPrayerTabOption() - { - clearPrayerTabMenus(); - if (config.unlockPrayerReordering()) - { - menuManager.addManagedCustomMenu(FIXED_PRAYER_TAB_LOCK); - menuManager.addManagedCustomMenu(RESIZABLE_PRAYER_TAB_LOCK); - menuManager.addManagedCustomMenu(RESIZABLE_BOTTOM_LINE_PRAYER_TAB_LOCK); - } - else - { - menuManager.addManagedCustomMenu(FIXED_PRAYER_TAB_UNLOCK); - menuManager.addManagedCustomMenu(RESIZABLE_PRAYER_TAB_UNLOCK); - menuManager.addManagedCustomMenu(RESIZABLE_BOTTOM_LINE_PRAYER_TAB_UNLOCK); - } - } - - private PrayerTabState getPrayerTabState() - { - HashTable componentTable = client.getComponentTable(); - for (WidgetNode widgetNode : componentTable.getNodes()) - { - if (widgetNode.getId() == WidgetID.PRAYER_GROUP_ID) - { - return PrayerTabState.PRAYERS; - } - else if (widgetNode.getId() == WidgetID.QUICK_PRAYERS_GROUP_ID) - { - return PrayerTabState.QUICK_PRAYERS; - } - } - return PrayerTabState.NONE; - } - - private void save() - { - config.prayerOrder(prayerOrderToString(prayerOrder)); - } - - private void reorderPrayers() - { - reorderPrayers(config.unlockPrayerReordering()); - } - - private void reorderPrayers(boolean unlocked) - { - if (client.getGameState() != GameState.LOGGED_IN) - { - return; - } - - PrayerTabState prayerTabState = getPrayerTabState(); - - if (prayerTabState == PrayerTabState.PRAYERS) - { - List prayerWidgets = PRAYER_WIDGET_INFO_LIST.stream() - .map(client::getWidget) - .filter(Objects::nonNull) - .collect(Collectors.toList()); - - if (prayerWidgets.size() != PRAYER_WIDGET_INFO_LIST.size()) - { - return; - } - - for (int index = 0; index < prayerOrder.length; index++) - { - Prayer prayer = prayerOrder[index]; - Widget prayerWidget = prayerWidgets.get(prayer.ordinal()); - - int widgetConfig = prayerWidget.getClickMask(); - if (unlocked) - { - // allow dragging of this widget - widgetConfig |= DRAG; - // allow this widget to be dragged on - widgetConfig |= DRAG_ON; - } - else - { - // remove drag flag - widgetConfig &= ~DRAG; - // remove drag on flag - widgetConfig &= ~DRAG_ON; - } - prayerWidget.setClickMask(widgetConfig); - - int x = index % PRAYER_COLUMN_COUNT; - int y = index / PRAYER_COLUMN_COUNT; - int widgetX = x * PRAYER_X_OFFSET; - int widgetY = y * PRAYER_Y_OFFSET; - setWidgetPosition(prayerWidget, widgetX, widgetY); - } - } - else if (prayerTabState == PrayerTabState.QUICK_PRAYERS) - { - Widget prayersContainer = client.getWidget(WidgetInfo.QUICK_PRAYER_PRAYERS); - if (prayersContainer == null) - { - return; - } - Widget[] prayerWidgets = prayersContainer.getDynamicChildren(); - if (prayerWidgets == null || prayerWidgets.length != PRAYER_COUNT * 3) - { - return; - } - - for (int index = 0; index < prayerOrder.length; index++) - { - Prayer prayer = prayerOrder[index]; - - int x = index % PRAYER_COLUMN_COUNT; - int y = index / PRAYER_COLUMN_COUNT; - - Widget prayerWidget = prayerWidgets[QUICK_PRAYER_CHILD_IDS.get(prayer.ordinal())]; - setWidgetPosition(prayerWidget, x * PRAYER_X_OFFSET, y * PRAYER_Y_OFFSET); - - int childId = PRAYER_COUNT + 2 * prayer.ordinal(); - - Widget prayerSpriteWidget = prayerWidgets[childId]; - setWidgetPosition(prayerSpriteWidget, - QUICK_PRAYER_SPRITE_X_OFFSET + x * PRAYER_X_OFFSET, - QUICK_PRAYER_SPRITE_Y_OFFSET + y * PRAYER_Y_OFFSET); - - Widget prayerToggleWidget = prayerWidgets[childId + 1]; - setWidgetPosition(prayerToggleWidget, x * PRAYER_X_OFFSET, y * PRAYER_Y_OFFSET); - } - } - } - -} +/* + * Copyright (c) 2018, Adam + * 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.reorderprayers; + +import com.google.common.collect.ImmutableList; +import com.google.inject.Provides; +import java.util.Arrays; +import java.util.List; +import java.util.Objects; +import java.util.stream.Collectors; +import javax.inject.Inject; +import net.runelite.api.Client; +import net.runelite.api.GameState; +import net.runelite.api.HashTable; +import net.runelite.api.Prayer; +import net.runelite.api.WidgetNode; +import net.runelite.api.events.ConfigChanged; +import net.runelite.api.events.DraggingWidgetChanged; +import net.runelite.api.events.GameStateChanged; +import net.runelite.api.events.WidgetLoaded; +import net.runelite.api.events.WidgetMenuOptionClicked; +import net.runelite.api.widgets.Widget; +import static net.runelite.api.widgets.WidgetConfig.DRAG; +import static net.runelite.api.widgets.WidgetConfig.DRAG_ON; +import net.runelite.api.widgets.WidgetID; +import net.runelite.api.widgets.WidgetInfo; +import net.runelite.client.config.ConfigManager; +import net.runelite.client.eventbus.Subscribe; +import net.runelite.client.menus.MenuManager; +import net.runelite.client.menus.WidgetMenuOption; +import net.runelite.client.plugins.Plugin; +import net.runelite.client.plugins.PluginDescriptor; + +@PluginDescriptor( + name = "Reorder Prayers", + description = "Reorder the prayers displayed on the Prayer panel" +) +public class ReorderPrayersPlugin extends Plugin +{ + + static final String CONFIG_GROUP_KEY = "reorderprayers"; + + static final String CONFIG_UNLOCK_REORDERING_KEY = "unlockPrayerReordering"; + + static final String CONFIG_PRAYER_ORDER_KEY = "prayerOrder"; + + private static final int PRAYER_WIDTH = 34; + + private static final int PRAYER_HEIGHT = 34; + + private static final int PRAYER_X_OFFSET = 37; + + private static final int PRAYER_Y_OFFSET = 37; + + private static final int QUICK_PRAYER_SPRITE_X_OFFSET = 2; + + private static final int QUICK_PRAYER_SPRITE_Y_OFFSET = 2; + + private static final int PRAYER_COLUMN_COUNT = 5; + + private static final int PRAYER_COUNT = Prayer.values().length; + + private static final List PRAYER_WIDGET_INFO_LIST = ImmutableList.of( + WidgetInfo.PRAYER_THICK_SKIN, + WidgetInfo.PRAYER_BURST_OF_STRENGTH, + WidgetInfo.PRAYER_CLARITY_OF_THOUGHT, + WidgetInfo.PRAYER_SHARP_EYE, + WidgetInfo.PRAYER_MYSTIC_WILL, + WidgetInfo.PRAYER_ROCK_SKIN, + WidgetInfo.PRAYER_SUPERHUMAN_STRENGTH, + WidgetInfo.PRAYER_IMPROVED_REFLEXES, + WidgetInfo.PRAYER_RAPID_RESTORE, + WidgetInfo.PRAYER_RAPID_HEAL, + WidgetInfo.PRAYER_PROTECT_ITEM, + WidgetInfo.PRAYER_HAWK_EYE, + WidgetInfo.PRAYER_MYSTIC_LORE, + WidgetInfo.PRAYER_STEEL_SKIN, + WidgetInfo.PRAYER_ULTIMATE_STRENGTH, + WidgetInfo.PRAYER_INCREDIBLE_REFLEXES, + WidgetInfo.PRAYER_PROTECT_FROM_MAGIC, + WidgetInfo.PRAYER_PROTECT_FROM_MISSILES, + WidgetInfo.PRAYER_PROTECT_FROM_MELEE, + WidgetInfo.PRAYER_EAGLE_EYE, + WidgetInfo.PRAYER_MYSTIC_MIGHT, + WidgetInfo.PRAYER_RETRIBUTION, + WidgetInfo.PRAYER_REDEMPTION, + WidgetInfo.PRAYER_SMITE, + WidgetInfo.PRAYER_PRESERVE, + WidgetInfo.PRAYER_CHIVALRY, + WidgetInfo.PRAYER_PIETY, + WidgetInfo.PRAYER_RIGOUR, + WidgetInfo.PRAYER_AUGURY + ); + + private static final List QUICK_PRAYER_CHILD_IDS = ImmutableList.of( + WidgetID.QuickPrayer.THICK_SKIN_CHILD_ID, + WidgetID.QuickPrayer.BURST_OF_STRENGTH_CHILD_ID, + WidgetID.QuickPrayer.CLARITY_OF_THOUGHT_CHILD_ID, + WidgetID.QuickPrayer.SHARP_EYE_CHILD_ID, + WidgetID.QuickPrayer.MYSTIC_WILL_CHILD_ID, + WidgetID.QuickPrayer.ROCK_SKIN_CHILD_ID, + WidgetID.QuickPrayer.SUPERHUMAN_STRENGTH_CHILD_ID, + WidgetID.QuickPrayer.IMPROVED_REFLEXES_CHILD_ID, + WidgetID.QuickPrayer.RAPID_RESTORE_CHILD_ID, + WidgetID.QuickPrayer.RAPID_HEAL_CHILD_ID, + WidgetID.QuickPrayer.PROTECT_ITEM_CHILD_ID, + WidgetID.QuickPrayer.HAWK_EYE_CHILD_ID, + WidgetID.QuickPrayer.MYSTIC_LORE_CHILD_ID, + WidgetID.QuickPrayer.STEEL_SKIN_CHILD_ID, + WidgetID.QuickPrayer.ULTIMATE_STRENGTH_CHILD_ID, + WidgetID.QuickPrayer.INCREDIBLE_REFLEXES_CHILD_ID, + WidgetID.QuickPrayer.PROTECT_FROM_MAGIC_CHILD_ID, + WidgetID.QuickPrayer.PROTECT_FROM_MISSILES_CHILD_ID, + WidgetID.QuickPrayer.PROTECT_FROM_MELEE_CHILD_ID, + WidgetID.QuickPrayer.EAGLE_EYE_CHILD_ID, + WidgetID.QuickPrayer.MYSTIC_MIGHT_CHILD_ID, + WidgetID.QuickPrayer.RETRIBUTION_CHILD_ID, + WidgetID.QuickPrayer.REDEMPTION_CHILD_ID, + WidgetID.QuickPrayer.SMITE_CHILD_ID, + WidgetID.QuickPrayer.PRESERVE_CHILD_ID, + WidgetID.QuickPrayer.CHIVALRY_CHILD_ID, + WidgetID.QuickPrayer.PIETY_CHILD_ID, + WidgetID.QuickPrayer.RIGOUR_CHILD_ID, + WidgetID.QuickPrayer.AUGURY_CHILD_ID + ); + + private static final String LOCK = "Lock"; + + private static final String UNLOCK = "Unlock"; + + private static final String MENU_TARGET = "Reordering"; + + private static final WidgetMenuOption FIXED_PRAYER_TAB_LOCK = new WidgetMenuOption(LOCK, + MENU_TARGET, WidgetInfo.FIXED_VIEWPORT_PRAYER_TAB); + + private static final WidgetMenuOption FIXED_PRAYER_TAB_UNLOCK = new WidgetMenuOption(UNLOCK, + MENU_TARGET, WidgetInfo.FIXED_VIEWPORT_PRAYER_TAB); + + private static final WidgetMenuOption RESIZABLE_PRAYER_TAB_LOCK = new WidgetMenuOption(LOCK, + MENU_TARGET, WidgetInfo.RESIZABLE_VIEWPORT_PRAYER_TAB); + + private static final WidgetMenuOption RESIZABLE_PRAYER_TAB_UNLOCK = new WidgetMenuOption(UNLOCK, + MENU_TARGET, WidgetInfo.RESIZABLE_VIEWPORT_PRAYER_TAB); + + private static final WidgetMenuOption RESIZABLE_BOTTOM_LINE_PRAYER_TAB_LOCK = new WidgetMenuOption(LOCK, + MENU_TARGET, WidgetInfo.RESIZABLE_VIEWPORT_BOTTOM_LINE_PRAYER_TAB); + + private static final WidgetMenuOption RESIZABLE_BOTTOM_LINE_PRAYER_TAB_UNLOCK = new WidgetMenuOption(UNLOCK, + MENU_TARGET, WidgetInfo.RESIZABLE_VIEWPORT_BOTTOM_LINE_PRAYER_TAB); + + @Inject + private Client client; + + @Inject + private ReorderPrayersConfig config; + + @Inject + private MenuManager menuManager; + + private Prayer[] prayerOrder; + + static String prayerOrderToString(Prayer[] prayerOrder) + { + return Arrays.stream(prayerOrder) + .map(Prayer::name) + .collect(Collectors.joining(",")); + } + + private static Prayer[] stringToPrayerOrder(String string) + { + return Arrays.stream(string.split(",")) + .map(Prayer::valueOf) + .toArray(Prayer[]::new); + } + + private static int getPrayerIndex(Widget widget) + { + int x = widget.getOriginalX() / PRAYER_X_OFFSET; + int y = widget.getOriginalY() / PRAYER_Y_OFFSET; + return x + y * PRAYER_COLUMN_COUNT; + } + + private static void setWidgetPosition(Widget widget, int x, int y) + { + widget.setRelativeX(x); + widget.setRelativeY(y); + widget.setOriginalX(x); + widget.setOriginalY(y); + } + + @Provides + ReorderPrayersConfig provideConfig(ConfigManager configManager) + { + return configManager.getConfig(ReorderPrayersConfig.class); + } + + @Override + protected void startUp() throws Exception + { + refreshPrayerTabOption(); + prayerOrder = stringToPrayerOrder(config.prayerOrder()); + reorderPrayers(); + } + + @Override + protected void shutDown() throws Exception + { + clearPrayerTabMenus(); + prayerOrder = Prayer.values(); + reorderPrayers(false); + } + + @Subscribe + public void onGameStateChanged(GameStateChanged event) + { + if (event.getGameState() == GameState.LOGGED_IN) + { + reorderPrayers(); + } + } + + @Subscribe + public void onConfigChanged(ConfigChanged event) + { + if (event.getGroup().equals(CONFIG_GROUP_KEY)) + { + if (event.getKey().equals(CONFIG_PRAYER_ORDER_KEY)) + { + prayerOrder = stringToPrayerOrder(config.prayerOrder()); + } + else if (event.getKey().equals(CONFIG_UNLOCK_REORDERING_KEY)) + { + refreshPrayerTabOption(); + } + reorderPrayers(); + } + } + + @Subscribe + public void onWidgetLoaded(WidgetLoaded event) + { + if (event.getGroupId() == WidgetID.PRAYER_GROUP_ID || event.getGroupId() == WidgetID.QUICK_PRAYERS_GROUP_ID) + { + reorderPrayers(); + } + } + + @Subscribe + public void onDraggingWidgetChanged(DraggingWidgetChanged event) + { + // is dragging widget and mouse button released + if (event.isDraggingWidget() && client.getMouseCurrentButton() == 0) + { + Widget draggedWidget = client.getDraggedWidget(); + Widget draggedOnWidget = client.getDraggedOnWidget(); + if (draggedWidget != null && draggedOnWidget != null) + { + int draggedGroupId = WidgetInfo.TO_GROUP(draggedWidget.getId()); + int draggedOnGroupId = WidgetInfo.TO_GROUP(draggedOnWidget.getId()); + if (draggedGroupId != WidgetID.PRAYER_GROUP_ID || draggedOnGroupId != WidgetID.PRAYER_GROUP_ID + || draggedOnWidget.getWidth() != PRAYER_WIDTH || draggedOnWidget.getHeight() != PRAYER_HEIGHT) + { + return; + } + // reset dragged on widget to prevent sending a drag widget packet to the server + client.setDraggedOnWidget(null); + + int fromPrayerIndex = getPrayerIndex(draggedWidget); + int toPrayerIndex = getPrayerIndex(draggedOnWidget); + + Prayer tmp = prayerOrder[toPrayerIndex]; + prayerOrder[toPrayerIndex] = prayerOrder[fromPrayerIndex]; + prayerOrder[fromPrayerIndex] = tmp; + + save(); + } + } + } + + @Subscribe + public void onWidgetMenuOptionClicked(WidgetMenuOptionClicked event) + { + if (event.getWidget() == WidgetInfo.FIXED_VIEWPORT_PRAYER_TAB + || event.getWidget() == WidgetInfo.RESIZABLE_VIEWPORT_PRAYER_TAB + || event.getWidget() == WidgetInfo.RESIZABLE_VIEWPORT_BOTTOM_LINE_PRAYER_TAB) + { + config.unlockPrayerReordering(event.getMenuOption().equals(UNLOCK)); + } + } + + private void clearPrayerTabMenus() + { + menuManager.removeManagedCustomMenu(FIXED_PRAYER_TAB_LOCK); + menuManager.removeManagedCustomMenu(RESIZABLE_PRAYER_TAB_LOCK); + menuManager.removeManagedCustomMenu(RESIZABLE_BOTTOM_LINE_PRAYER_TAB_LOCK); + menuManager.removeManagedCustomMenu(FIXED_PRAYER_TAB_UNLOCK); + menuManager.removeManagedCustomMenu(RESIZABLE_PRAYER_TAB_UNLOCK); + menuManager.removeManagedCustomMenu(RESIZABLE_BOTTOM_LINE_PRAYER_TAB_UNLOCK); + } + + private void refreshPrayerTabOption() + { + clearPrayerTabMenus(); + if (config.unlockPrayerReordering()) + { + menuManager.addManagedCustomMenu(FIXED_PRAYER_TAB_LOCK); + menuManager.addManagedCustomMenu(RESIZABLE_PRAYER_TAB_LOCK); + menuManager.addManagedCustomMenu(RESIZABLE_BOTTOM_LINE_PRAYER_TAB_LOCK); + } + else + { + menuManager.addManagedCustomMenu(FIXED_PRAYER_TAB_UNLOCK); + menuManager.addManagedCustomMenu(RESIZABLE_PRAYER_TAB_UNLOCK); + menuManager.addManagedCustomMenu(RESIZABLE_BOTTOM_LINE_PRAYER_TAB_UNLOCK); + } + } + + private PrayerTabState getPrayerTabState() + { + HashTable componentTable = client.getComponentTable(); + for (WidgetNode widgetNode : componentTable.getNodes()) + { + if (widgetNode.getId() == WidgetID.PRAYER_GROUP_ID) + { + return PrayerTabState.PRAYERS; + } + else if (widgetNode.getId() == WidgetID.QUICK_PRAYERS_GROUP_ID) + { + return PrayerTabState.QUICK_PRAYERS; + } + } + return PrayerTabState.NONE; + } + + private void save() + { + config.prayerOrder(prayerOrderToString(prayerOrder)); + } + + private void reorderPrayers() + { + reorderPrayers(config.unlockPrayerReordering()); + } + + private void reorderPrayers(boolean unlocked) + { + if (client.getGameState() != GameState.LOGGED_IN) + { + return; + } + + PrayerTabState prayerTabState = getPrayerTabState(); + + if (prayerTabState == PrayerTabState.PRAYERS) + { + List prayerWidgets = PRAYER_WIDGET_INFO_LIST.stream() + .map(client::getWidget) + .filter(Objects::nonNull) + .collect(Collectors.toList()); + + if (prayerWidgets.size() != PRAYER_WIDGET_INFO_LIST.size()) + { + return; + } + + for (int index = 0; index < prayerOrder.length; index++) + { + Prayer prayer = prayerOrder[index]; + Widget prayerWidget = prayerWidgets.get(prayer.ordinal()); + + int widgetConfig = prayerWidget.getClickMask(); + if (unlocked) + { + // allow dragging of this widget + widgetConfig |= DRAG; + // allow this widget to be dragged on + widgetConfig |= DRAG_ON; + } + else + { + // remove drag flag + widgetConfig &= ~DRAG; + // remove drag on flag + widgetConfig &= ~DRAG_ON; + } + prayerWidget.setClickMask(widgetConfig); + + int x = index % PRAYER_COLUMN_COUNT; + int y = index / PRAYER_COLUMN_COUNT; + int widgetX = x * PRAYER_X_OFFSET; + int widgetY = y * PRAYER_Y_OFFSET; + setWidgetPosition(prayerWidget, widgetX, widgetY); + } + } + else if (prayerTabState == PrayerTabState.QUICK_PRAYERS) + { + Widget prayersContainer = client.getWidget(WidgetInfo.QUICK_PRAYER_PRAYERS); + if (prayersContainer == null) + { + return; + } + Widget[] prayerWidgets = prayersContainer.getDynamicChildren(); + if (prayerWidgets == null || prayerWidgets.length != PRAYER_COUNT * 3) + { + return; + } + + for (int index = 0; index < prayerOrder.length; index++) + { + Prayer prayer = prayerOrder[index]; + + int x = index % PRAYER_COLUMN_COUNT; + int y = index / PRAYER_COLUMN_COUNT; + + Widget prayerWidget = prayerWidgets[QUICK_PRAYER_CHILD_IDS.get(prayer.ordinal())]; + setWidgetPosition(prayerWidget, x * PRAYER_X_OFFSET, y * PRAYER_Y_OFFSET); + + int childId = PRAYER_COUNT + 2 * prayer.ordinal(); + + Widget prayerSpriteWidget = prayerWidgets[childId]; + setWidgetPosition(prayerSpriteWidget, + QUICK_PRAYER_SPRITE_X_OFFSET + x * PRAYER_X_OFFSET, + QUICK_PRAYER_SPRITE_Y_OFFSET + y * PRAYER_Y_OFFSET); + + Widget prayerToggleWidget = prayerWidgets[childId + 1]; + setWidgetPosition(prayerToggleWidget, x * PRAYER_X_OFFSET, y * PRAYER_Y_OFFSET); + } + } + } + +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/roguesden/Obstacles.java b/runelite-client/src/main/java/net/runelite/client/plugins/roguesden/Obstacles.java index 13c6052336..d4c2b356c3 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/roguesden/Obstacles.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/roguesden/Obstacles.java @@ -1,53 +1,64 @@ -/* - * Copyright (c) 2018, Shaun Dreclin - * 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.roguesden; - -import com.google.common.collect.Sets; -import java.util.Set; -import static net.runelite.api.ObjectID.*; -import static net.runelite.api.NullObjectID.*; - -class Obstacles -{ - public static final Set OBSTACLE_IDS_HULL = Sets.newHashSet( - SPINNING_BLADES_7224, - CONTORTION_BARS, - PENDULUM, - WALL_7249, /*Wall crushers*/ - WALL_7248, /*Wall blade*/ - LEDGE_7240, /*Ledge climb*/ - NULL_7235 /*Wall safe*/ - ); - - public static final Set OBSTACLE_IDS_TILE = Sets.newHashSet( - FLOOR, /*Floor spikes*/ - WALL_7228, /*Wall spikes*/ - WALL_7229, /*Wall spears*/ - FLOOR_7245, /*Pressure pad a*/ - FLOOR_7230, /*Pressure pad b*/ - BLADE_7252, /*Floor blade*/ - 7239 /*Bridge [Ground object]*/ - ); -} +/* + * Copyright (c) 2018, Shaun Dreclin + * 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.roguesden; + +import com.google.common.collect.Sets; +import java.util.Set; +import static net.runelite.api.NullObjectID.NULL_7235; +import static net.runelite.api.ObjectID.BLADE_7252; +import static net.runelite.api.ObjectID.CONTORTION_BARS; +import static net.runelite.api.ObjectID.FLOOR; +import static net.runelite.api.ObjectID.FLOOR_7230; +import static net.runelite.api.ObjectID.FLOOR_7245; +import static net.runelite.api.ObjectID.LEDGE_7240; +import static net.runelite.api.ObjectID.PENDULUM; +import static net.runelite.api.ObjectID.SPINNING_BLADES_7224; +import static net.runelite.api.ObjectID.WALL_7228; +import static net.runelite.api.ObjectID.WALL_7229; +import static net.runelite.api.ObjectID.WALL_7248; +import static net.runelite.api.ObjectID.WALL_7249; + +class Obstacles +{ + public static final Set OBSTACLE_IDS_HULL = Sets.newHashSet( + SPINNING_BLADES_7224, + CONTORTION_BARS, + PENDULUM, + WALL_7249, /*Wall crushers*/ + WALL_7248, /*Wall blade*/ + LEDGE_7240, /*Ledge climb*/ + NULL_7235 /*Wall safe*/ + ); + + public static final Set OBSTACLE_IDS_TILE = Sets.newHashSet( + FLOOR, /*Floor spikes*/ + WALL_7228, /*Wall spikes*/ + WALL_7229, /*Wall spears*/ + FLOOR_7245, /*Pressure pad a*/ + FLOOR_7230, /*Pressure pad b*/ + BLADE_7252, /*Floor blade*/ + 7239 /*Bridge [Ground object]*/ + ); +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/runecraft/AbyssOverlay.java b/runelite-client/src/main/java/net/runelite/client/plugins/runecraft/AbyssOverlay.java index 23f8e390b8..9e8a28ff6b 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/runecraft/AbyssOverlay.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/runecraft/AbyssOverlay.java @@ -1,241 +1,241 @@ -/* - * Copyright (c) 2016-2018, Seth - * 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.runecraft; - -import java.awt.Color; -import java.awt.Polygon; -import java.awt.geom.Area; -import static net.runelite.client.plugins.runecraft.AbyssRifts.AIR_RIFT; -import static net.runelite.client.plugins.runecraft.AbyssRifts.BLOOD_RIFT; -import static net.runelite.client.plugins.runecraft.AbyssRifts.BODY_RIFT; -import static net.runelite.client.plugins.runecraft.AbyssRifts.CHAOS_RIFT; -import static net.runelite.client.plugins.runecraft.AbyssRifts.COSMIC_RIFT; -import static net.runelite.client.plugins.runecraft.AbyssRifts.DEATH_RIFT; -import static net.runelite.client.plugins.runecraft.AbyssRifts.EARTH_RIFT; -import static net.runelite.client.plugins.runecraft.AbyssRifts.FIRE_RIFT; -import static net.runelite.client.plugins.runecraft.AbyssRifts.LAW_RIFT; -import static net.runelite.client.plugins.runecraft.AbyssRifts.MIND_RIFT; -import static net.runelite.client.plugins.runecraft.AbyssRifts.NATURE_RIFT; -import static net.runelite.client.plugins.runecraft.AbyssRifts.SOUL_RIFT; -import static net.runelite.client.plugins.runecraft.AbyssRifts.WATER_RIFT; -import com.google.inject.Inject; -import java.awt.Dimension; -import java.awt.Graphics2D; -import java.awt.image.BufferedImage; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Map; -import java.util.Set; -import net.runelite.api.Client; -import net.runelite.api.DecorativeObject; -import net.runelite.api.NPC; -import net.runelite.api.Perspective; -import net.runelite.api.Point; -import net.runelite.client.game.ItemManager; -import net.runelite.client.ui.overlay.Overlay; -import net.runelite.client.ui.overlay.OverlayLayer; -import net.runelite.client.ui.overlay.OverlayPosition; -import net.runelite.client.ui.overlay.OverlayUtil; - -class AbyssOverlay extends Overlay -{ - private static final Dimension IMAGE_SIZE = new Dimension(15, 14); - - private final Set rifts = new HashSet<>(); - private final Map abyssIcons = new HashMap<>(); - - private final Client client; - private final RunecraftPlugin plugin; - private final RunecraftConfig config; - - @Inject - private ItemManager itemManager; - - @Inject - AbyssOverlay(Client client, RunecraftPlugin plugin, RunecraftConfig config) - { - setPosition(OverlayPosition.DYNAMIC); - setLayer(OverlayLayer.ABOVE_WIDGETS); - this.client = client; - this.plugin = plugin; - this.config = config; - } - - @Override - public Dimension render(Graphics2D graphics) - { - if (config.showRifts()) - { - for (DecorativeObject object : plugin.getAbyssObjects()) - { - renderRifts(graphics, object); - } - } - - if (config.hightlightDarkMage()) - { - highlightDarkMage(graphics); - } - - return null; - } - - private void highlightDarkMage(Graphics2D graphics) - { - if (!plugin.isDegradedPouchInInventory()) - { - return; - } - - NPC darkMage = plugin.getDarkMage(); - if (darkMage == null) - { - return; - } - - Polygon tilePoly = darkMage.getCanvasTilePoly(); - if (tilePoly == null) - { - return; - } - - OverlayUtil.renderPolygon(graphics, tilePoly, Color.green); - } - - private void renderRifts(Graphics2D graphics, DecorativeObject object) - { - AbyssRifts rift = AbyssRifts.getRift(object.getId()); - if (rift == null || !rifts.contains(rift)) - { - return; - } - - if (config.showClickBox()) - { - //Draw clickbox - Point mousePosition = client.getMouseCanvasPosition(); - Area objectClickbox = object.getClickbox(); - if (objectClickbox != null) - { - if (objectClickbox.contains(mousePosition.getX(), mousePosition.getY())) - { - graphics.setColor(Color.MAGENTA.darker()); - } - else - { - graphics.setColor(Color.MAGENTA); - } - graphics.draw(objectClickbox); - graphics.setColor(new Color(255, 0, 255, 20)); - graphics.fill(objectClickbox); - } - } - - //Draw minimap - BufferedImage image = getImage(rift); - Point miniMapImage = Perspective.getMiniMapImageLocation(client, object.getLocalLocation(), image); - - if (miniMapImage != null) - { - graphics.drawImage(image, miniMapImage.getX(), miniMapImage.getY(), null); - } - } - - public BufferedImage getImage(AbyssRifts rift) - { - BufferedImage image = abyssIcons.get(rift); - if (image != null) - { - return image; - } - - // Since item image is too big, we must resize it first. - image = itemManager.getImage(rift.getItemId()); - BufferedImage resizedImage = new BufferedImage(IMAGE_SIZE.width, IMAGE_SIZE.height, BufferedImage.TYPE_INT_ARGB); - Graphics2D g = resizedImage.createGraphics(); - g.drawImage(image, 0, 0, IMAGE_SIZE.width, IMAGE_SIZE.height, null); - g.dispose(); - - abyssIcons.put(rift, resizedImage); - return resizedImage; - } - - public void updateConfig() - { - rifts.clear(); - if (config.showAir()) - { - rifts.add(AIR_RIFT); - } - if (config.showBlood()) - { - rifts.add(BLOOD_RIFT); - } - if (config.showBody()) - { - rifts.add(BODY_RIFT); - } - if (config.showChaos()) - { - rifts.add(CHAOS_RIFT); - } - if (config.showCosmic()) - { - rifts.add(COSMIC_RIFT); - } - if (config.showDeath()) - { - rifts.add(DEATH_RIFT); - } - if (config.showEarth()) - { - rifts.add(EARTH_RIFT); - } - if (config.showFire()) - { - rifts.add(FIRE_RIFT); - } - if (config.showLaw()) - { - rifts.add(LAW_RIFT); - } - if (config.showMind()) - { - rifts.add(MIND_RIFT); - } - if (config.showNature()) - { - rifts.add(NATURE_RIFT); - } - if (config.showSoul()) - { - rifts.add(SOUL_RIFT); - } - if (config.showWater()) - { - rifts.add(WATER_RIFT); - } - } -} +/* + * Copyright (c) 2016-2018, Seth + * 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.runecraft; + +import com.google.inject.Inject; +import java.awt.Color; +import java.awt.Dimension; +import java.awt.Graphics2D; +import java.awt.Polygon; +import java.awt.geom.Area; +import java.awt.image.BufferedImage; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; +import net.runelite.api.Client; +import net.runelite.api.DecorativeObject; +import net.runelite.api.NPC; +import net.runelite.api.Perspective; +import net.runelite.api.Point; +import net.runelite.client.game.ItemManager; +import static net.runelite.client.plugins.runecraft.AbyssRifts.AIR_RIFT; +import static net.runelite.client.plugins.runecraft.AbyssRifts.BLOOD_RIFT; +import static net.runelite.client.plugins.runecraft.AbyssRifts.BODY_RIFT; +import static net.runelite.client.plugins.runecraft.AbyssRifts.CHAOS_RIFT; +import static net.runelite.client.plugins.runecraft.AbyssRifts.COSMIC_RIFT; +import static net.runelite.client.plugins.runecraft.AbyssRifts.DEATH_RIFT; +import static net.runelite.client.plugins.runecraft.AbyssRifts.EARTH_RIFT; +import static net.runelite.client.plugins.runecraft.AbyssRifts.FIRE_RIFT; +import static net.runelite.client.plugins.runecraft.AbyssRifts.LAW_RIFT; +import static net.runelite.client.plugins.runecraft.AbyssRifts.MIND_RIFT; +import static net.runelite.client.plugins.runecraft.AbyssRifts.NATURE_RIFT; +import static net.runelite.client.plugins.runecraft.AbyssRifts.SOUL_RIFT; +import static net.runelite.client.plugins.runecraft.AbyssRifts.WATER_RIFT; +import net.runelite.client.ui.overlay.Overlay; +import net.runelite.client.ui.overlay.OverlayLayer; +import net.runelite.client.ui.overlay.OverlayPosition; +import net.runelite.client.ui.overlay.OverlayUtil; + +class AbyssOverlay extends Overlay +{ + private static final Dimension IMAGE_SIZE = new Dimension(15, 14); + + private final Set rifts = new HashSet<>(); + private final Map abyssIcons = new HashMap<>(); + + private final Client client; + private final RunecraftPlugin plugin; + private final RunecraftConfig config; + + @Inject + private ItemManager itemManager; + + @Inject + AbyssOverlay(Client client, RunecraftPlugin plugin, RunecraftConfig config) + { + setPosition(OverlayPosition.DYNAMIC); + setLayer(OverlayLayer.ABOVE_WIDGETS); + this.client = client; + this.plugin = plugin; + this.config = config; + } + + @Override + public Dimension render(Graphics2D graphics) + { + if (config.showRifts()) + { + for (DecorativeObject object : plugin.getAbyssObjects()) + { + renderRifts(graphics, object); + } + } + + if (config.hightlightDarkMage()) + { + highlightDarkMage(graphics); + } + + return null; + } + + private void highlightDarkMage(Graphics2D graphics) + { + if (!plugin.isDegradedPouchInInventory()) + { + return; + } + + NPC darkMage = plugin.getDarkMage(); + if (darkMage == null) + { + return; + } + + Polygon tilePoly = darkMage.getCanvasTilePoly(); + if (tilePoly == null) + { + return; + } + + OverlayUtil.renderPolygon(graphics, tilePoly, Color.green); + } + + private void renderRifts(Graphics2D graphics, DecorativeObject object) + { + AbyssRifts rift = AbyssRifts.getRift(object.getId()); + if (rift == null || !rifts.contains(rift)) + { + return; + } + + if (config.showClickBox()) + { + //Draw clickbox + Point mousePosition = client.getMouseCanvasPosition(); + Area objectClickbox = object.getClickbox(); + if (objectClickbox != null) + { + if (objectClickbox.contains(mousePosition.getX(), mousePosition.getY())) + { + graphics.setColor(Color.MAGENTA.darker()); + } + else + { + graphics.setColor(Color.MAGENTA); + } + graphics.draw(objectClickbox); + graphics.setColor(new Color(255, 0, 255, 20)); + graphics.fill(objectClickbox); + } + } + + //Draw minimap + BufferedImage image = getImage(rift); + Point miniMapImage = Perspective.getMiniMapImageLocation(client, object.getLocalLocation(), image); + + if (miniMapImage != null) + { + graphics.drawImage(image, miniMapImage.getX(), miniMapImage.getY(), null); + } + } + + public BufferedImage getImage(AbyssRifts rift) + { + BufferedImage image = abyssIcons.get(rift); + if (image != null) + { + return image; + } + + // Since item image is too big, we must resize it first. + image = itemManager.getImage(rift.getItemId()); + BufferedImage resizedImage = new BufferedImage(IMAGE_SIZE.width, IMAGE_SIZE.height, BufferedImage.TYPE_INT_ARGB); + Graphics2D g = resizedImage.createGraphics(); + g.drawImage(image, 0, 0, IMAGE_SIZE.width, IMAGE_SIZE.height, null); + g.dispose(); + + abyssIcons.put(rift, resizedImage); + return resizedImage; + } + + public void updateConfig() + { + rifts.clear(); + if (config.showAir()) + { + rifts.add(AIR_RIFT); + } + if (config.showBlood()) + { + rifts.add(BLOOD_RIFT); + } + if (config.showBody()) + { + rifts.add(BODY_RIFT); + } + if (config.showChaos()) + { + rifts.add(CHAOS_RIFT); + } + if (config.showCosmic()) + { + rifts.add(COSMIC_RIFT); + } + if (config.showDeath()) + { + rifts.add(DEATH_RIFT); + } + if (config.showEarth()) + { + rifts.add(EARTH_RIFT); + } + if (config.showFire()) + { + rifts.add(FIRE_RIFT); + } + if (config.showLaw()) + { + rifts.add(LAW_RIFT); + } + if (config.showMind()) + { + rifts.add(MIND_RIFT); + } + if (config.showNature()) + { + rifts.add(NATURE_RIFT); + } + if (config.showSoul()) + { + rifts.add(SOUL_RIFT); + } + if (config.showWater()) + { + rifts.add(WATER_RIFT); + } + } +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/runecraft/RunecraftConfig.java b/runelite-client/src/main/java/net/runelite/client/plugins/runecraft/RunecraftConfig.java index 38d6edc501..743d8b13d2 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/runecraft/RunecraftConfig.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/runecraft/RunecraftConfig.java @@ -218,6 +218,7 @@ public interface RunecraftConfig extends Config { return true; } + @ConfigItem( keyName = "opLavas", name = "Op lavas", diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/runecraft/RunecraftPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/runecraft/RunecraftPlugin.java index 475a6bf998..55563b2fb9 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/runecraft/RunecraftPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/runecraft/RunecraftPlugin.java @@ -174,7 +174,7 @@ public class RunecraftPlugin extends Plugin swap(client, "fill", option, target); swap(client, "cancel", option, "", target); } - else if (option.equals("fill") && id != 9) + else if (option.equals("fill") && id != 9) { swap(client, "empty", option, target); } @@ -232,6 +232,7 @@ public class RunecraftPlugin extends Plugin { return searchIndex(entries, option, target, false); } + private int searchIndex(MenuEntry[] entries, String option, String target, boolean contains) { for (int i = entries.length - 1; i >= 0; i--) @@ -290,9 +291,9 @@ public class RunecraftPlugin extends Plugin if (event.getItemContainer() == client.getItemContainer(InventoryID.INVENTORY)) { - final Item[] items = event.getItemContainer().getItems(); - degradedPouchInInventory = Stream.of(items).anyMatch(i -> DEGRADED_POUCHES.contains(i.getId())); - } + final Item[] items = event.getItemContainer().getItems(); + degradedPouchInInventory = Stream.of(items).anyMatch(i -> DEGRADED_POUCHES.contains(i.getId())); + } else if (event.getItemContainer() == client.getItemContainer(InventoryID.EQUIPMENT)) { final Item[] items = event.getItemContainer().getItems(); @@ -319,6 +320,7 @@ public class RunecraftPlugin extends Plugin darkMage = null; } } + private boolean wearingBindingNeck() { final ItemContainer worn = client.getItemContainer(InventoryID.EQUIPMENT); diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/runedoku/RunedokuConfig.java b/runelite-client/src/main/java/net/runelite/client/plugins/runedoku/RunedokuConfig.java index 5d6cab6084..ddfc69a4dd 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/runedoku/RunedokuConfig.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/runedoku/RunedokuConfig.java @@ -1,84 +1,111 @@ package net.runelite.client.plugins.runedoku; +import java.awt.Color; import net.runelite.client.config.Config; import net.runelite.client.config.ConfigGroup; import net.runelite.client.config.ConfigItem; -import java.awt.*; - @ConfigGroup("runedoku") -public interface RunedokuConfig extends Config { +public interface RunedokuConfig extends Config +{ @ConfigItem( - position = 0, - keyName = "mindRuneColor", - name = "Mind Rune Color", - description = "Color used to highlight Mind runes." + position = 0, + keyName = "mindRuneColor", + name = "Mind Rune Color", + description = "Color used to highlight Mind runes." ) - default Color mindRuneColor() { return Color.PINK; } + default Color mindRuneColor() + { + return Color.PINK; + } @ConfigItem( - position = 1, - keyName = "fireRuneColor", - name = "Fire Rune Color", - description = "Color used to highlight Fire runes." + position = 1, + keyName = "fireRuneColor", + name = "Fire Rune Color", + description = "Color used to highlight Fire runes." ) - default Color fireRuneColor() { return Color.RED; } + default Color fireRuneColor() + { + return Color.RED; + } @ConfigItem( - position = 2, - keyName = "bodyRuneColor", - name = "Body Rune Color", - description = "Color used to highlight Body runes." + position = 2, + keyName = "bodyRuneColor", + name = "Body Rune Color", + description = "Color used to highlight Body runes." ) - default Color bodyRuneColor() { return Color.MAGENTA; } + default Color bodyRuneColor() + { + return Color.MAGENTA; + } @ConfigItem( - position = 3, - keyName = "airRuneColor", - name = "Air Rune Color", - description = "Color used to highlight Air runes." + position = 3, + keyName = "airRuneColor", + name = "Air Rune Color", + description = "Color used to highlight Air runes." ) - default Color airRuneColor() { return Color.WHITE; } + default Color airRuneColor() + { + return Color.WHITE; + } @ConfigItem( - position = 4, - keyName = "deathRuneColor", - name = "Death Rune Color", - description = "Color used to highlight Death runes." + position = 4, + keyName = "deathRuneColor", + name = "Death Rune Color", + description = "Color used to highlight Death runes." ) - default Color deathRuneColor() { return Color.BLACK; } + default Color deathRuneColor() + { + return Color.BLACK; + } @ConfigItem( - position = 5, - keyName = "waterRuneColor", - name = "Water Rune Color", - description = "Color used to highlight Water runes." + position = 5, + keyName = "waterRuneColor", + name = "Water Rune Color", + description = "Color used to highlight Water runes." ) - default Color waterRuneColor() { return Color.BLUE; } + default Color waterRuneColor() + { + return Color.BLUE; + } @ConfigItem( - position = 6, - keyName = "chaosRuneColor", - name = "Chaos Rune Color", - description = "Color used to highlight Chaos runes." + position = 6, + keyName = "chaosRuneColor", + name = "Chaos Rune Color", + description = "Color used to highlight Chaos runes." ) - default Color chaosRuneColor() { return Color.YELLOW; } + default Color chaosRuneColor() + { + return Color.YELLOW; + } @ConfigItem( - position = 7, - keyName = "earthRuneColor", - name = "Earth Rune Color", - description = "Color used to highlight Earth runes." + position = 7, + keyName = "earthRuneColor", + name = "Earth Rune Color", + description = "Color used to highlight Earth runes." ) - default Color earthRuneColor() { return Color.GREEN; } + default Color earthRuneColor() + { + return Color.GREEN; + } @ConfigItem( - position = 8, - keyName = "lawRuneColor", - name = "Law Rune Color", - description = "Color used to highlight Law runes." + position = 8, + keyName = "lawRuneColor", + name = "Law Rune Color", + description = "Color used to highlight Law runes." ) - default Color lawRuneColor() { return Color.CYAN; } + default Color lawRuneColor() + { + return Color.CYAN; + } } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/runedoku/RunedokuOverlay.java b/runelite-client/src/main/java/net/runelite/client/plugins/runedoku/RunedokuOverlay.java index 2f92172386..5cdb2908ce 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/runedoku/RunedokuOverlay.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/runedoku/RunedokuOverlay.java @@ -24,22 +24,25 @@ package net.runelite.client.plugins.runedoku; +import java.awt.Color; +import static java.awt.Color.RED; +import java.awt.Dimension; +import java.awt.Graphics2D; +import java.util.ArrayList; +import javax.inject.Inject; import net.runelite.api.Client; import net.runelite.api.widgets.Widget; -import net.runelite.client.ui.overlay.*; -import net.runelite.client.ui.overlay.components.PanelComponent; -import net.runelite.client.ui.overlay.tooltip.TooltipManager; - -import javax.inject.Inject; -import java.awt.*; -import java.util.ArrayList; - -import static java.awt.Color.RED; +import net.runelite.client.ui.overlay.Overlay; +import net.runelite.client.ui.overlay.OverlayLayer; +import net.runelite.client.ui.overlay.OverlayPosition; +import net.runelite.client.ui.overlay.OverlayPriority; +import net.runelite.client.ui.overlay.OverlayUtil; /** * @author gazivodag */ -class RunedokuOverlay extends Overlay { +class RunedokuOverlay extends Overlay +{ private final RunedokuPlugin plugin; private final Client client; @@ -47,7 +50,8 @@ class RunedokuOverlay extends Overlay { @Inject - private RunedokuOverlay(final RunedokuPlugin plugin, final Client client, final RunedokuUtil util) { + private RunedokuOverlay(final RunedokuPlugin plugin, final Client client, final RunedokuUtil util) + { super(plugin); this.plugin = plugin; this.client = client; @@ -59,12 +63,15 @@ class RunedokuOverlay extends Overlay { } @Override - public Dimension render(Graphics2D graphics) { + public Dimension render(Graphics2D graphics) + { - final Widget sudokuScreen = client.getWidget(288,131); + final Widget sudokuScreen = client.getWidget(288, 131); - if (sudokuScreen != null) { - if (!sudokuScreen.isHidden()) { + if (sudokuScreen != null) + { + if (!sudokuScreen.isHidden()) + { Sudoku sudoku = new Sudoku(util.createTable(client)); boolean solved = sudoku.solve(); @@ -79,20 +86,29 @@ class RunedokuOverlay extends Overlay { /** * highlights the runes on the left handside so you know which runes to place on the board + * * @param graphics * @param solved */ - private void renderReferenceRunes(Graphics2D graphics, boolean solved) { + private void renderReferenceRunes(Graphics2D graphics, boolean solved) + { //reference runes on the left handside - for (int i = 121 ; i < 130 ; i++) { + for (int i = 121; i < 130; i++) + { Widget widget = client.getWidget(288, i); - if (solved) { - if (!util.makeSimple(util.createTable(client)).contains(0)) { + if (solved) + { + if (!util.makeSimple(util.createTable(client)).contains(0)) + { OverlayUtil.renderPolygon(graphics, util.RectangleToPolygon(widget.getBounds()), Color.GREEN); - } else { + } + else + { OverlayUtil.renderPolygon(graphics, util.RectangleToPolygon(widget.getBounds()), util.referenceColors(i)); } - } else { + } + else + { OverlayUtil.renderPolygon(graphics, util.RectangleToPolygon(widget.getBounds()), RED); } @@ -101,24 +117,33 @@ class RunedokuOverlay extends Overlay { /** * goes through each 9x9 cell and tells you which piece to place in there + * * @param graphics * @param sudoku * @param solved */ - private void renderSolvedPuzzle(Graphics2D graphics, Sudoku sudoku, boolean solved) { + private void renderSolvedPuzzle(Graphics2D graphics, Sudoku sudoku, boolean solved) + { ArrayList simpleArr = util.makeSimple(sudoku.getBoard()); //highlight each cell to tell you which piece to place int iteration = 0; - for (int i = 10 ; i < 91 ; i++) { + for (int i = 10; i < 91; i++) + { Widget squareToHighlight = client.getWidget(288, i); - if (solved) { - if (!util.makeSimple(util.createTable(client)).contains(0)) { + if (solved) + { + if (!util.makeSimple(util.createTable(client)).contains(0)) + { OverlayUtil.renderPolygon(graphics, util.RectangleToPolygon(squareToHighlight.getBounds()), Color.GREEN); - } else { + } + else + { OverlayUtil.renderPolygon(graphics, util.RectangleToPolygon(squareToHighlight.getBounds()), util.sudokuPieceToColor(simpleArr.get(iteration))); } iteration++; - } else { + } + else + { OverlayUtil.renderPolygon(graphics, util.RectangleToPolygon(squareToHighlight.getBounds()), RED); } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/runedoku/RunedokuPiece.java b/runelite-client/src/main/java/net/runelite/client/plugins/runedoku/RunedokuPiece.java index c6a79628d6..7a6f50ab08 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/runedoku/RunedokuPiece.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/runedoku/RunedokuPiece.java @@ -24,7 +24,8 @@ package net.runelite.client.plugins.runedoku; -public enum RunedokuPiece { +public enum RunedokuPiece +{ NPC_PLACED_MIND_RUNE(6436, 1), //1 NPC_PLACED_FIRE_RUNE(6428, 2), //2 @@ -50,22 +51,28 @@ public enum RunedokuPiece { private final int pieceID; private final int pieceForSudoku; - RunedokuPiece (int pieceID, int pieceForSudoku) { + RunedokuPiece(int pieceID, int pieceForSudoku) + { this.pieceID = pieceID; this.pieceForSudoku = pieceForSudoku; } - int getId () { + int getId() + { return pieceID; } - int getPieceForSudoku() { + int getPieceForSudoku() + { return pieceForSudoku; } - static RunedokuPiece getById(int pieceID) { - for (RunedokuPiece e : RunedokuPiece.values()) { - if (e.getId() == pieceID) { + static RunedokuPiece getById(int pieceID) + { + for (RunedokuPiece e : RunedokuPiece.values()) + { + if (e.getId() == pieceID) + { return e; } } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/runedoku/RunedokuPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/runedoku/RunedokuPlugin.java index 81f80367d9..d984405992 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/runedoku/RunedokuPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/runedoku/RunedokuPlugin.java @@ -25,6 +25,8 @@ package net.runelite.client.plugins.runedoku; import com.google.inject.Provides; +import javax.inject.Inject; +import javax.inject.Singleton; import lombok.extern.slf4j.Slf4j; import net.runelite.api.Client; import net.runelite.client.config.ConfigManager; @@ -33,18 +35,16 @@ import net.runelite.client.plugins.PluginDescriptor; import net.runelite.client.plugins.PluginType; import net.runelite.client.ui.overlay.OverlayManager; -import javax.inject.Inject; -import javax.inject.Singleton; - @PluginDescriptor( - name = "Runedoku Solver", - description = "Show solutions for current Runedoku puzzle.", - tags = {"overlay", "runedoku", "sudoku", "puzzle", "solving"}, - type = PluginType.UTILITY + name = "Runedoku Solver", + description = "Show solutions for current Runedoku puzzle.", + tags = {"overlay", "runedoku", "sudoku", "puzzle", "solving"}, + type = PluginType.UTILITY ) @Slf4j @Singleton -public class RunedokuPlugin extends Plugin { +public class RunedokuPlugin extends Plugin +{ @Inject private Client client; @@ -62,17 +62,20 @@ public class RunedokuPlugin extends Plugin { private RunedokuConfig config; @Provides - RunedokuConfig provideConfig(ConfigManager configManager) { + RunedokuConfig provideConfig(ConfigManager configManager) + { return configManager.getConfig(RunedokuConfig.class); } @Override - protected void startUp() throws Exception { + protected void startUp() throws Exception + { overlayManager.add(runedokuOverlay); } @Override - protected void shutDown() throws Exception { + protected void shutDown() throws Exception + { overlayManager.remove(runedokuOverlay); } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/runedoku/RunedokuUtil.java b/runelite-client/src/main/java/net/runelite/client/plugins/runedoku/RunedokuUtil.java index 3c15d85c07..2f6baf1c6b 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/runedoku/RunedokuUtil.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/runedoku/RunedokuUtil.java @@ -1,24 +1,29 @@ package net.runelite.client.plugins.runedoku; +import java.awt.Color; +import java.awt.Polygon; +import java.awt.Rectangle; +import java.util.ArrayList; +import javax.inject.Inject; import net.runelite.api.Client; import net.runelite.api.widgets.Widget; import net.runelite.api.widgets.WidgetItem; -import javax.inject.Inject; -import java.awt.*; -import java.util.ArrayList; - -public class RunedokuUtil { +public class RunedokuUtil +{ private final RunedokuConfig config; @Inject - RunedokuUtil(final RunedokuConfig config) { + RunedokuUtil(final RunedokuConfig config) + { this.config = config; } - protected Color sudokuPieceToColor(int i) { - switch (i) { + protected Color sudokuPieceToColor(int i) + { + switch (i) + { case 1: return config.mindRuneColor(); case 2: @@ -42,8 +47,10 @@ public class RunedokuUtil { } } - protected Color referenceColors(int i) { - switch (i) { + protected Color referenceColors(int i) + { + switch (i) + { case 121: //earth return config.earthRuneColor(); case 122: //water @@ -69,13 +76,17 @@ public class RunedokuUtil { /** * Make the 2d array into an arraylist + * * @param board * @return */ - protected ArrayList makeSimple(int[][] board) { + protected ArrayList makeSimple(int[][] board) + { ArrayList list = new ArrayList<>(); - for (int i = 0 ; i < 9 ; i++) { - for (int ii = 0 ; ii < 9 ; ii++) { + for (int i = 0; i < 9; i++) + { + for (int ii = 0; ii < 9; ii++) + { list.add(board[i][ii]); } } @@ -84,10 +95,12 @@ public class RunedokuUtil { /** * utility method + * * @param rect * @return */ - protected Polygon RectangleToPolygon(Rectangle rect) { + protected Polygon RectangleToPolygon(Rectangle rect) + { int[] xpoints = {rect.x, rect.x + rect.width, rect.x + rect.width, rect.x}; int[] ypoints = {rect.y, rect.y, rect.y + rect.height, rect.y + rect.height}; return new Polygon(xpoints, ypoints, 4); @@ -95,27 +108,40 @@ public class RunedokuUtil { /** * Pulls data from what's on the Runedoku interface and creates a 2dimensional array for it - * @author gazivodag + * * @param client * @return sudoku table that the client currently sees in a 2d array + * @author gazivodag */ - protected int[][] createTable(Client client) { + protected int[][] createTable(Client client) + { int[][] myArr = new int[9][9]; - Widget sudokuScreen = client.getWidget(288,131); - for (int i = 0 ; i < 9 ; i++) { - for (int ii = 0 ; ii < 9 ; ii++) { + Widget sudokuScreen = client.getWidget(288, 131); + for (int i = 0; i < 9; i++) + { + for (int ii = 0; ii < 9; ii++) + { WidgetItem item; int myIndex; - if (i > 0) { + if (i > 0) + { myIndex = ((i * 10) + ii) - i; - } else { + } + else + { myIndex = ii; } - if (myIndex == 81) break; + if (myIndex == 81) + { + break; + } item = sudokuScreen.getWidgetItem(myIndex); - if (item != null) { + if (item != null) + { myArr[i][ii] = RunedokuPiece.getById(item.getId()).getPieceForSudoku(); - } else { + } + else + { myArr[i][ii] = 0; } } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/runedoku/Sudoku.java b/runelite-client/src/main/java/net/runelite/client/plugins/runedoku/Sudoku.java index 666e026bd7..d04aa2464e 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/runedoku/Sudoku.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/runedoku/Sudoku.java @@ -2,65 +2,97 @@ package net.runelite.client.plugins.runedoku; /** * Credits to whoever wrote this sudoku class. + * * @author ? */ -public class Sudoku { +public class Sudoku +{ private int[][] board; public static final int EMPTY = 0; public static final int SIZE = 9; - Sudoku(int[][] board) { + Sudoku(int[][] board) + { this.board = new int[SIZE][SIZE]; - for (int i = 0; i < SIZE; i++) { - for (int j = 0; j < SIZE; j++) { + for (int i = 0; i < SIZE; i++) + { + for (int j = 0; j < SIZE; j++) + { this.board[i][j] = board[i][j]; } } } - private boolean isInRow(int row, int number) { + private boolean isInRow(int row, int number) + { for (int i = 0; i < SIZE; i++) + { if (board[row][i] == number) + { return true; + } + } return false; } - private boolean isInCol(int col, int number) { + private boolean isInCol(int col, int number) + { for (int i = 0; i < SIZE; i++) + { if (board[i][col] == number) + { return true; + } + } return false; } - private boolean isInBox(int row, int col, int number) { + private boolean isInBox(int row, int col, int number) + { int r = row - row % 3; int c = col - col % 3; for (int i = r; i < r + 3; i++) + { for (int j = c; j < c + 3; j++) + { if (board[i][j] == number) + { return true; + } + } + } return false; } - private boolean isOk(int row, int col, int number) { - return !isInRow(row, number) && !isInCol(col, number) && !isInBox(row, col, number); + private boolean isOk(int row, int col, int number) + { + return !isInRow(row, number) && !isInCol(col, number) && !isInBox(row, col, number); } - public boolean solve() { - for (int row = 0; row < SIZE; row++) { - for (int col = 0; col < SIZE; col++) { - if (board[row][col] == EMPTY) { - for (int number = 1; number <= SIZE; number++) { - if (isOk(row, col, number)) { + public boolean solve() + { + for (int row = 0; row < SIZE; row++) + { + for (int col = 0; col < SIZE; col++) + { + if (board[row][col] == EMPTY) + { + for (int number = 1; number <= SIZE; number++) + { + if (isOk(row, col, number)) + { board[row][col] = number; - if (solve()) { + if (solve()) + { return true; - } else { + } + else + { board[row][col] = EMPTY; } } @@ -73,9 +105,12 @@ public class Sudoku { return true; } - public void display() { - for (int i = 0; i < SIZE; i++) { - for (int j = 0; j < SIZE; j++) { + public void display() + { + for (int i = 0; i < SIZE; i++) + { + for (int j = 0; j < SIZE; j++) + { System.out.print(" " + board[i][j]); } @@ -85,7 +120,8 @@ public class Sudoku { System.out.println(); } - public int[][] getBoard() { + public int[][] getBoard() + { return board; } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/runenergy/RunEnergyPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/runenergy/RunEnergyPlugin.java index fff84a100d..52170baa4e 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/runenergy/RunEnergyPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/runenergy/RunEnergyPlugin.java @@ -33,7 +33,99 @@ import net.runelite.api.EquipmentInventorySlot; import net.runelite.api.InventoryID; import net.runelite.api.Item; import net.runelite.api.ItemContainer; -import static net.runelite.api.ItemID.*; +import static net.runelite.api.ItemID.AGILITY_CAPE; +import static net.runelite.api.ItemID.AGILITY_CAPET; +import static net.runelite.api.ItemID.GRACEFUL_BOOTS_11861; +import static net.runelite.api.ItemID.GRACEFUL_BOOTS_13589; +import static net.runelite.api.ItemID.GRACEFUL_BOOTS_13590; +import static net.runelite.api.ItemID.GRACEFUL_BOOTS_13601; +import static net.runelite.api.ItemID.GRACEFUL_BOOTS_13602; +import static net.runelite.api.ItemID.GRACEFUL_BOOTS_13613; +import static net.runelite.api.ItemID.GRACEFUL_BOOTS_13614; +import static net.runelite.api.ItemID.GRACEFUL_BOOTS_13625; +import static net.runelite.api.ItemID.GRACEFUL_BOOTS_13626; +import static net.runelite.api.ItemID.GRACEFUL_BOOTS_13637; +import static net.runelite.api.ItemID.GRACEFUL_BOOTS_13638; +import static net.runelite.api.ItemID.GRACEFUL_BOOTS_13677; +import static net.runelite.api.ItemID.GRACEFUL_BOOTS_13678; +import static net.runelite.api.ItemID.GRACEFUL_BOOTS_21076; +import static net.runelite.api.ItemID.GRACEFUL_BOOTS_21078; +import static net.runelite.api.ItemID.GRACEFUL_CAPE_11853; +import static net.runelite.api.ItemID.GRACEFUL_CAPE_13581; +import static net.runelite.api.ItemID.GRACEFUL_CAPE_13582; +import static net.runelite.api.ItemID.GRACEFUL_CAPE_13593; +import static net.runelite.api.ItemID.GRACEFUL_CAPE_13594; +import static net.runelite.api.ItemID.GRACEFUL_CAPE_13605; +import static net.runelite.api.ItemID.GRACEFUL_CAPE_13606; +import static net.runelite.api.ItemID.GRACEFUL_CAPE_13617; +import static net.runelite.api.ItemID.GRACEFUL_CAPE_13618; +import static net.runelite.api.ItemID.GRACEFUL_CAPE_13629; +import static net.runelite.api.ItemID.GRACEFUL_CAPE_13630; +import static net.runelite.api.ItemID.GRACEFUL_CAPE_13669; +import static net.runelite.api.ItemID.GRACEFUL_CAPE_13670; +import static net.runelite.api.ItemID.GRACEFUL_CAPE_21064; +import static net.runelite.api.ItemID.GRACEFUL_CAPE_21066; +import static net.runelite.api.ItemID.GRACEFUL_GLOVES_11859; +import static net.runelite.api.ItemID.GRACEFUL_GLOVES_13587; +import static net.runelite.api.ItemID.GRACEFUL_GLOVES_13588; +import static net.runelite.api.ItemID.GRACEFUL_GLOVES_13599; +import static net.runelite.api.ItemID.GRACEFUL_GLOVES_13600; +import static net.runelite.api.ItemID.GRACEFUL_GLOVES_13611; +import static net.runelite.api.ItemID.GRACEFUL_GLOVES_13612; +import static net.runelite.api.ItemID.GRACEFUL_GLOVES_13623; +import static net.runelite.api.ItemID.GRACEFUL_GLOVES_13624; +import static net.runelite.api.ItemID.GRACEFUL_GLOVES_13635; +import static net.runelite.api.ItemID.GRACEFUL_GLOVES_13636; +import static net.runelite.api.ItemID.GRACEFUL_GLOVES_13675; +import static net.runelite.api.ItemID.GRACEFUL_GLOVES_13676; +import static net.runelite.api.ItemID.GRACEFUL_GLOVES_21073; +import static net.runelite.api.ItemID.GRACEFUL_GLOVES_21075; +import static net.runelite.api.ItemID.GRACEFUL_HOOD_11851; +import static net.runelite.api.ItemID.GRACEFUL_HOOD_13579; +import static net.runelite.api.ItemID.GRACEFUL_HOOD_13580; +import static net.runelite.api.ItemID.GRACEFUL_HOOD_13591; +import static net.runelite.api.ItemID.GRACEFUL_HOOD_13592; +import static net.runelite.api.ItemID.GRACEFUL_HOOD_13603; +import static net.runelite.api.ItemID.GRACEFUL_HOOD_13604; +import static net.runelite.api.ItemID.GRACEFUL_HOOD_13615; +import static net.runelite.api.ItemID.GRACEFUL_HOOD_13616; +import static net.runelite.api.ItemID.GRACEFUL_HOOD_13627; +import static net.runelite.api.ItemID.GRACEFUL_HOOD_13628; +import static net.runelite.api.ItemID.GRACEFUL_HOOD_13667; +import static net.runelite.api.ItemID.GRACEFUL_HOOD_13668; +import static net.runelite.api.ItemID.GRACEFUL_HOOD_21061; +import static net.runelite.api.ItemID.GRACEFUL_HOOD_21063; +import static net.runelite.api.ItemID.GRACEFUL_LEGS_11857; +import static net.runelite.api.ItemID.GRACEFUL_LEGS_13585; +import static net.runelite.api.ItemID.GRACEFUL_LEGS_13586; +import static net.runelite.api.ItemID.GRACEFUL_LEGS_13597; +import static net.runelite.api.ItemID.GRACEFUL_LEGS_13598; +import static net.runelite.api.ItemID.GRACEFUL_LEGS_13609; +import static net.runelite.api.ItemID.GRACEFUL_LEGS_13610; +import static net.runelite.api.ItemID.GRACEFUL_LEGS_13621; +import static net.runelite.api.ItemID.GRACEFUL_LEGS_13622; +import static net.runelite.api.ItemID.GRACEFUL_LEGS_13633; +import static net.runelite.api.ItemID.GRACEFUL_LEGS_13634; +import static net.runelite.api.ItemID.GRACEFUL_LEGS_13673; +import static net.runelite.api.ItemID.GRACEFUL_LEGS_13674; +import static net.runelite.api.ItemID.GRACEFUL_LEGS_21070; +import static net.runelite.api.ItemID.GRACEFUL_LEGS_21072; +import static net.runelite.api.ItemID.GRACEFUL_TOP_11855; +import static net.runelite.api.ItemID.GRACEFUL_TOP_13583; +import static net.runelite.api.ItemID.GRACEFUL_TOP_13584; +import static net.runelite.api.ItemID.GRACEFUL_TOP_13595; +import static net.runelite.api.ItemID.GRACEFUL_TOP_13596; +import static net.runelite.api.ItemID.GRACEFUL_TOP_13607; +import static net.runelite.api.ItemID.GRACEFUL_TOP_13608; +import static net.runelite.api.ItemID.GRACEFUL_TOP_13619; +import static net.runelite.api.ItemID.GRACEFUL_TOP_13620; +import static net.runelite.api.ItemID.GRACEFUL_TOP_13631; +import static net.runelite.api.ItemID.GRACEFUL_TOP_13632; +import static net.runelite.api.ItemID.GRACEFUL_TOP_13671; +import static net.runelite.api.ItemID.GRACEFUL_TOP_13672; +import static net.runelite.api.ItemID.GRACEFUL_TOP_21067; +import static net.runelite.api.ItemID.GRACEFUL_TOP_21069; +import static net.runelite.api.ItemID.MAX_CAPE; import net.runelite.api.Skill; import net.runelite.api.Varbits; import net.runelite.api.coords.WorldPoint; @@ -135,8 +227,8 @@ public class RunEnergyPlugin extends Plugin { localPlayerRunningToDestination = prevLocalPlayerLocation != null && - client.getLocalDestinationLocation() != null && - prevLocalPlayerLocation.distanceTo(client.getLocalPlayer().getWorldLocation()) > 1; + client.getLocalDestinationLocation() != null && + prevLocalPlayerLocation.distanceTo(client.getLocalPlayer().getWorldLocation()) > 1; prevLocalPlayerLocation = client.getLocalPlayer().getWorldLocation(); @@ -188,14 +280,14 @@ public class RunEnergyPlugin extends Plugin // Return the text if (inSeconds) { - return Integer.toString((int) Math.floor(secondsLeft)) + "s"; + return (int) Math.floor(secondsLeft) + "s"; } else { final int minutes = (int) Math.floor(secondsLeft / 60.0); final int seconds = (int) Math.floor(secondsLeft - (minutes * 60.0)); - return Integer.toString(minutes) + ":" + StringUtils.leftPad(Integer.toString(seconds), 2, "0"); + return minutes + ":" + StringUtils.leftPad(Integer.toString(seconds), 2, "0"); } } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/runepouch/RunepouchOverlay.java b/runelite-client/src/main/java/net/runelite/client/plugins/runepouch/RunepouchOverlay.java index a7e2fd86d7..014fe007f7 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/runepouch/RunepouchOverlay.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/runepouch/RunepouchOverlay.java @@ -1,179 +1,179 @@ -/* - * Copyright (c) 2017, Tyler - * 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.runepouch; - -import java.awt.Color; -import java.awt.Dimension; -import java.awt.Graphics2D; -import java.awt.image.BufferedImage; -import javax.inject.Inject; -import net.runelite.api.Client; -import net.runelite.api.ItemID; -import net.runelite.api.Point; -import net.runelite.api.Varbits; -import net.runelite.api.widgets.WidgetItem; -import net.runelite.client.game.ItemManager; -import static net.runelite.client.plugins.runepouch.config.RunePouchOverlayMode.BOTH; -import static net.runelite.client.plugins.runepouch.config.RunePouchOverlayMode.MOUSE_HOVER; -import net.runelite.client.ui.FontManager; -import net.runelite.client.ui.overlay.OverlayUtil; -import net.runelite.client.ui.overlay.WidgetItemOverlay; -import net.runelite.client.ui.overlay.tooltip.Tooltip; -import net.runelite.client.ui.overlay.tooltip.TooltipManager; -import net.runelite.client.util.ColorUtil; - -public class RunepouchOverlay extends WidgetItemOverlay -{ - private static final Varbits[] AMOUNT_VARBITS = - { - Varbits.RUNE_POUCH_AMOUNT1, Varbits.RUNE_POUCH_AMOUNT2, Varbits.RUNE_POUCH_AMOUNT3 - }; - private static final Varbits[] RUNE_VARBITS = - { - Varbits.RUNE_POUCH_RUNE1, Varbits.RUNE_POUCH_RUNE2, Varbits.RUNE_POUCH_RUNE3 - }; - private static final Dimension IMAGE_SIZE = new Dimension(11, 11); - - private final Client client; - private final RunepouchConfig config; - private final TooltipManager tooltipManager; - - @Inject - private ItemManager itemManager; - - @Inject - RunepouchOverlay(Client client, RunepouchConfig config, TooltipManager tooltipManager) - { - this.tooltipManager = tooltipManager; - this.client = client; - this.config = config; - showOnInventory(); - showOnBank(); - } - - @Override - public void renderItemOverlay(Graphics2D graphics, int itemId, WidgetItem itemWidget) - { - if (itemId != ItemID.RUNE_POUCH) - { - return; - } - - assert AMOUNT_VARBITS.length == RUNE_VARBITS.length; - - graphics.setFont(FontManager.getRunescapeSmallFont()); - - Point location = itemWidget.getCanvasLocation(); - StringBuilder tooltipBuilder = new StringBuilder(); - - for (int i = 0; i < AMOUNT_VARBITS.length; i++) - { - Varbits amountVarbit = AMOUNT_VARBITS[i]; - - int amount = client.getVar(amountVarbit); - if (amount <= 0) - { - continue; - } - - Varbits runeVarbit = RUNE_VARBITS[i]; - int runeId = client.getVar(runeVarbit); - Runes rune = Runes.getRune(runeId); - if (rune == null) - { - continue; - } - - tooltipBuilder - .append(amount) - .append(" ") - .append(ColorUtil.wrapWithColorTag(rune.getName(), Color.YELLOW)) - .append("
"); - - if (config.runePouchOverlayMode() == MOUSE_HOVER) - { - continue; - } - - graphics.setColor(Color.black); - graphics.drawString("" + formatNumber(amount), location.getX() + (config.showIcons() ? 13 : 6), - location.getY() + 14 + (graphics.getFontMetrics().getHeight() - 1) * i); - - graphics.setColor(config.fontColor()); - graphics.drawString("" + formatNumber(amount), location.getX() + (config.showIcons() ? 12 : 5), - location.getY() + 13 + (graphics.getFontMetrics().getHeight() - 1) * i); - - if (!config.showIcons()) - { - continue; - } - - BufferedImage image = getRuneImage(rune); - if (image != null) - { - OverlayUtil.renderImageLocation(graphics, - new Point(location.getX(), location.getY() + graphics.getFontMetrics().getHeight() * i), - image); - } - } - - String tooltip = tooltipBuilder.toString(); - - if (!tooltip.isEmpty() - && itemWidget.getCanvasBounds().contains(client.getMouseCanvasPosition().getX(), client.getMouseCanvasPosition().getY()) - && (config.runePouchOverlayMode() == MOUSE_HOVER || config.runePouchOverlayMode() == BOTH)) - { - tooltipManager.add(new Tooltip(tooltip)); - } - } - - private BufferedImage getRuneImage(Runes rune) - { - BufferedImage runeImg = rune.getImage(); - if (runeImg != null) - { - return runeImg; - } - - runeImg = itemManager.getImage(rune.getItemId()); - if (runeImg == null) - { - return null; - } - - BufferedImage resizedImg = new BufferedImage(IMAGE_SIZE.width, IMAGE_SIZE.height, BufferedImage.TYPE_INT_ARGB); - Graphics2D g = resizedImg.createGraphics(); - g.drawImage(runeImg, 0, 0, IMAGE_SIZE.width, IMAGE_SIZE.height, null); - g.dispose(); - - rune.setImage(resizedImg); - return resizedImg; - } - - private static String formatNumber(int amount) - { - return amount < 1000 ? String.valueOf(amount) : amount / 1000 + "K"; - } -} +/* + * Copyright (c) 2017, Tyler + * 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.runepouch; + +import java.awt.Color; +import java.awt.Dimension; +import java.awt.Graphics2D; +import java.awt.image.BufferedImage; +import javax.inject.Inject; +import net.runelite.api.Client; +import net.runelite.api.ItemID; +import net.runelite.api.Point; +import net.runelite.api.Varbits; +import net.runelite.api.widgets.WidgetItem; +import net.runelite.client.game.ItemManager; +import static net.runelite.client.plugins.runepouch.config.RunePouchOverlayMode.BOTH; +import static net.runelite.client.plugins.runepouch.config.RunePouchOverlayMode.MOUSE_HOVER; +import net.runelite.client.ui.FontManager; +import net.runelite.client.ui.overlay.OverlayUtil; +import net.runelite.client.ui.overlay.WidgetItemOverlay; +import net.runelite.client.ui.overlay.tooltip.Tooltip; +import net.runelite.client.ui.overlay.tooltip.TooltipManager; +import net.runelite.client.util.ColorUtil; + +public class RunepouchOverlay extends WidgetItemOverlay +{ + private static final Varbits[] AMOUNT_VARBITS = + { + Varbits.RUNE_POUCH_AMOUNT1, Varbits.RUNE_POUCH_AMOUNT2, Varbits.RUNE_POUCH_AMOUNT3 + }; + private static final Varbits[] RUNE_VARBITS = + { + Varbits.RUNE_POUCH_RUNE1, Varbits.RUNE_POUCH_RUNE2, Varbits.RUNE_POUCH_RUNE3 + }; + private static final Dimension IMAGE_SIZE = new Dimension(11, 11); + + private final Client client; + private final RunepouchConfig config; + private final TooltipManager tooltipManager; + + @Inject + private ItemManager itemManager; + + @Inject + RunepouchOverlay(Client client, RunepouchConfig config, TooltipManager tooltipManager) + { + this.tooltipManager = tooltipManager; + this.client = client; + this.config = config; + showOnInventory(); + showOnBank(); + } + + @Override + public void renderItemOverlay(Graphics2D graphics, int itemId, WidgetItem itemWidget) + { + if (itemId != ItemID.RUNE_POUCH) + { + return; + } + + assert AMOUNT_VARBITS.length == RUNE_VARBITS.length; + + graphics.setFont(FontManager.getRunescapeSmallFont()); + + Point location = itemWidget.getCanvasLocation(); + StringBuilder tooltipBuilder = new StringBuilder(); + + for (int i = 0; i < AMOUNT_VARBITS.length; i++) + { + Varbits amountVarbit = AMOUNT_VARBITS[i]; + + int amount = client.getVar(amountVarbit); + if (amount <= 0) + { + continue; + } + + Varbits runeVarbit = RUNE_VARBITS[i]; + int runeId = client.getVar(runeVarbit); + Runes rune = Runes.getRune(runeId); + if (rune == null) + { + continue; + } + + tooltipBuilder + .append(amount) + .append(" ") + .append(ColorUtil.wrapWithColorTag(rune.getName(), Color.YELLOW)) + .append("
"); + + if (config.runePouchOverlayMode() == MOUSE_HOVER) + { + continue; + } + + graphics.setColor(Color.black); + graphics.drawString("" + formatNumber(amount), location.getX() + (config.showIcons() ? 13 : 6), + location.getY() + 14 + (graphics.getFontMetrics().getHeight() - 1) * i); + + graphics.setColor(config.fontColor()); + graphics.drawString("" + formatNumber(amount), location.getX() + (config.showIcons() ? 12 : 5), + location.getY() + 13 + (graphics.getFontMetrics().getHeight() - 1) * i); + + if (!config.showIcons()) + { + continue; + } + + BufferedImage image = getRuneImage(rune); + if (image != null) + { + OverlayUtil.renderImageLocation(graphics, + new Point(location.getX(), location.getY() + graphics.getFontMetrics().getHeight() * i), + image); + } + } + + String tooltip = tooltipBuilder.toString(); + + if (!tooltip.isEmpty() + && itemWidget.getCanvasBounds().contains(client.getMouseCanvasPosition().getX(), client.getMouseCanvasPosition().getY()) + && (config.runePouchOverlayMode() == MOUSE_HOVER || config.runePouchOverlayMode() == BOTH)) + { + tooltipManager.add(new Tooltip(tooltip)); + } + } + + private BufferedImage getRuneImage(Runes rune) + { + BufferedImage runeImg = rune.getImage(); + if (runeImg != null) + { + return runeImg; + } + + runeImg = itemManager.getImage(rune.getItemId()); + if (runeImg == null) + { + return null; + } + + BufferedImage resizedImg = new BufferedImage(IMAGE_SIZE.width, IMAGE_SIZE.height, BufferedImage.TYPE_INT_ARGB); + Graphics2D g = resizedImg.createGraphics(); + g.drawImage(runeImg, 0, 0, IMAGE_SIZE.width, IMAGE_SIZE.height, null); + g.dispose(); + + rune.setImage(resizedImg); + return resizedImg; + } + + private static String formatNumber(int amount) + { + return amount < 1000 ? String.valueOf(amount) : amount / 1000 + "K"; + } +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/runepouch/Runes.java b/runelite-client/src/main/java/net/runelite/client/plugins/runepouch/Runes.java index b5aebe9bf6..3031aa7b97 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/runepouch/Runes.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/runepouch/Runes.java @@ -111,7 +111,7 @@ public enum Runes public String getName() { String name = this.name(); - name = name.substring(0, 1) + name.substring(1, name.length()).toLowerCase(); + name = name.substring(0, 1) + name.substring(1).toLowerCase(); return name; } } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/screenshot/ScreenshotPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/screenshot/ScreenshotPlugin.java index c586b9cd91..dcd010d81e 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/screenshot/ScreenshotPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/screenshot/ScreenshotPlugin.java @@ -1,754 +1,754 @@ -/* - * Copyright (c) 2018, Lotto - * 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.screenshot; - -import com.google.common.annotations.VisibleForTesting; -import com.google.common.collect.ImmutableList; -import com.google.common.collect.ImmutableMap; -import com.google.inject.Provides; -import java.awt.Desktop; -import java.awt.Graphics; -import java.awt.Image; -import java.awt.Toolkit; -import java.awt.TrayIcon; -import java.awt.datatransfer.Clipboard; -import java.awt.datatransfer.StringSelection; -import java.awt.image.BufferedImage; -import java.io.File; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.lang.reflect.InvocationTargetException; -import java.text.DateFormat; -import java.text.SimpleDateFormat; -import java.time.LocalDate; -import java.util.Date; -import java.util.EnumSet; -import java.util.concurrent.ScheduledExecutorService; -import java.util.function.Consumer; -import java.util.regex.Matcher; -import java.util.regex.Pattern; -import javax.imageio.ImageIO; -import javax.inject.Inject; -import javax.swing.SwingUtilities; -import lombok.AccessLevel; -import lombok.Getter; -import lombok.extern.slf4j.Slf4j; -import net.runelite.api.ChatMessageType; -import net.runelite.api.Client; -import net.runelite.api.GameState; -import net.runelite.api.Player; -import net.runelite.api.Point; -import net.runelite.api.SpriteID; -import net.runelite.api.WorldType; -import net.runelite.api.events.ChatMessage; -import net.runelite.api.events.GameStateChanged; -import net.runelite.api.events.GameTick; -import net.runelite.api.events.LocalPlayerDeath; -import net.runelite.api.events.WidgetLoaded; -import net.runelite.api.widgets.Widget; -import static net.runelite.api.widgets.WidgetID.BARROWS_REWARD_GROUP_ID; -import static net.runelite.api.widgets.WidgetID.CHAMBERS_OF_XERIC_REWARD_GROUP_ID; -import static net.runelite.api.widgets.WidgetID.CLUE_SCROLL_REWARD_GROUP_ID; -import static net.runelite.api.widgets.WidgetID.DIALOG_SPRITE_GROUP_ID; -import static net.runelite.api.widgets.WidgetID.KINGDOM_GROUP_ID; -import static net.runelite.api.widgets.WidgetID.LEVEL_UP_GROUP_ID; -import static net.runelite.api.widgets.WidgetID.QUEST_COMPLETED_GROUP_ID; -import static net.runelite.api.widgets.WidgetID.THEATRE_OF_BLOOD_REWARD_GROUP_ID; -import net.runelite.api.widgets.WidgetInfo; -import net.runelite.client.Notifier; -import static net.runelite.client.RuneLite.SCREENSHOT_DIR; -import net.runelite.client.config.ConfigManager; -import net.runelite.client.eventbus.Subscribe; -import net.runelite.client.events.PlayerLootReceived; -import net.runelite.client.game.SpriteManager; -import net.runelite.client.input.KeyManager; -import net.runelite.client.plugins.Plugin; -import net.runelite.client.plugins.PluginDescriptor; -import net.runelite.client.plugins.screenshot.imgur.ImageUploadRequest; -import net.runelite.client.plugins.screenshot.imgur.ImageUploadResponse; -import net.runelite.client.ui.ClientToolbar; -import net.runelite.client.ui.ClientUI; -import net.runelite.client.ui.DrawManager; -import net.runelite.client.ui.NavigationButton; -import net.runelite.client.ui.overlay.OverlayManager; -import net.runelite.client.util.HotkeyListener; -import net.runelite.client.util.ImageUtil; -import net.runelite.client.util.Text; -import net.runelite.http.api.RuneLiteAPI; -import okhttp3.Call; -import okhttp3.Callback; -import okhttp3.HttpUrl; -import okhttp3.MediaType; -import okhttp3.Request; -import okhttp3.RequestBody; -import okhttp3.Response; - -@PluginDescriptor( - name = "Screenshot", - description = "Enable the manual and automatic taking of screenshots", - tags = {"external", "images", "imgur", "integration", "notifications"} -) -@Slf4j -public class ScreenshotPlugin extends Plugin -{ - private static final String IMGUR_CLIENT_ID = "30d71e5f6860809"; - private static final HttpUrl IMGUR_IMAGE_UPLOAD_URL = HttpUrl.parse("https://api.imgur.com/3/image"); - private static final MediaType JSON = MediaType.parse("application/json"); - - private static final DateFormat TIME_FORMAT = new SimpleDateFormat("yyyy-MM-dd_HH-mm-ss"); - - private static final Pattern NUMBER_PATTERN = Pattern.compile("([0-9]+)"); - private static final Pattern LEVEL_UP_PATTERN = Pattern.compile(".*Your ([a-zA-Z]+) (?:level is|are)? now (\\d+)\\."); - private static final Pattern BOSSKILL_MESSAGE_PATTERN = Pattern.compile("Your (.+) kill count is: (\\d+)."); - private static final Pattern VALUABLE_DROP_PATTERN = Pattern.compile(".*Valuable drop: ([^<>]+)(?:)?"); - private static final Pattern UNTRADEABLE_DROP_PATTERN = Pattern.compile(".*Untradeable drop: ([^<>]+)(?:)?"); - private static final Pattern DUEL_END_PATTERN = Pattern.compile("You have now (won|lost) ([0-9]+) duels?\\."); - private static final ImmutableList PET_MESSAGES = ImmutableList.of("You have a funny feeling like you're being followed", - "You feel something weird sneaking into your backpack", - "You have a funny feeling like you would have been followed"); - - static String format(Date date) - { - synchronized (TIME_FORMAT) - { - return TIME_FORMAT.format(date); - } - } - - private String clueType; - private Integer clueNumber; - - private Integer barrowsNumber; - - private Integer chambersOfXericNumber; - - private Integer chambersOfXericChallengeNumber; - - private Integer theatreOfBloodNumber; - - private boolean shouldTakeScreenshot; - - @Inject - private ScreenshotConfig config; - - @Inject - private OverlayManager overlayManager; - - @Inject - private ScreenshotOverlay screenshotOverlay; - - @Inject - private Notifier notifier; - - @Inject - private Client client; - - @Inject - private ClientUI clientUi; - - @Inject - private ClientToolbar clientToolbar; - - @Inject - private DrawManager drawManager; - - @Inject - private ScheduledExecutorService executor; - - @Inject - private KeyManager keyManager; - - @Inject - private SpriteManager spriteManager; - - @Getter(AccessLevel.PACKAGE) - private BufferedImage reportButton; - - private NavigationButton titleBarButton; - - private final HotkeyListener hotkeyListener = new HotkeyListener(() -> config.hotkey()) - { - @Override - public void hotkeyPressed() - { - takeScreenshot(format(new Date())); - } - }; - - @Provides - ScreenshotConfig getConfig(ConfigManager configManager) - { - return configManager.getConfig(ScreenshotConfig.class); - } - - @Override - protected void startUp() throws Exception - { - overlayManager.add(screenshotOverlay); - SCREENSHOT_DIR.mkdirs(); - keyManager.registerKeyListener(hotkeyListener); - - final BufferedImage iconImage = ImageUtil.getResourceStreamFromClass(getClass(), "screenshot.png"); - - titleBarButton = NavigationButton.builder() - .tab(false) - .tooltip("Take screenshot") - .icon(iconImage) - .onClick(() -> takeScreenshot(format(new Date()))) - .popup(ImmutableMap - .builder() - .put("Open screenshot folder...", () -> - { - try - { - Desktop.getDesktop().open(SCREENSHOT_DIR); - } - catch (IOException ex) - { - log.warn("Error opening screenshot dir", ex); - } - }) - .build()) - .build(); - - clientToolbar.addNavigation(titleBarButton); - } - - @Override - protected void shutDown() throws Exception - { - overlayManager.remove(screenshotOverlay); - clientToolbar.removeNavigation(titleBarButton); - keyManager.unregisterKeyListener(hotkeyListener); - } - - @Subscribe - public void onGameStateChanged(GameStateChanged event) - { - if (event.getGameState() == GameState.LOGGED_IN - && reportButton == null) - { - reportButton = spriteManager.getSprite(SpriteID.CHATBOX_REPORT_BUTTON, 0); - } - } - - @Subscribe - public void onGameTick(GameTick event) - { - if (!shouldTakeScreenshot) - { - return; - } - - shouldTakeScreenshot = false; - - String fileName = null; - if (client.getWidget(WidgetInfo.LEVEL_UP_LEVEL) != null) - { - fileName = parseLevelUpWidget(WidgetInfo.LEVEL_UP_LEVEL); - } - else if (client.getWidget(WidgetInfo.DIALOG_SPRITE_TEXT) != null) - { - fileName = parseLevelUpWidget(WidgetInfo.DIALOG_SPRITE_TEXT); - } - else if (client.getWidget(WidgetInfo.QUEST_COMPLETED_NAME_TEXT) != null) - { - // "You have completed The Corsair Curse!" - String text = client.getWidget(WidgetInfo.QUEST_COMPLETED_NAME_TEXT).getText(); - fileName = "Quest(" + text.substring(19, text.length() - 1) + ")"; - } - - if (fileName != null) - { - takeScreenshot(fileName); - } - } - - @Subscribe - public void onLocalPlayerDeath(LocalPlayerDeath death) - { - if (config.screenshotPlayerDeath()) - { - takeScreenshot("Death " + format(new Date())); - } - } - - @Subscribe - public void onPlayerLootReceived(final PlayerLootReceived playerLootReceived) - { - if (config.screenshotKills()) - { - final Player player = playerLootReceived.getPlayer(); - final String name = player.getName(); - String fileName = "Kill " + name + " " + format(new Date()); - takeScreenshot(fileName); - } - } - - @Subscribe - public void onChatMessage(ChatMessage event) - { - if (event.getType() != ChatMessageType.GAMEMESSAGE && event.getType() != ChatMessageType.SPAM && event.getType() != ChatMessageType.TRADE) - { - return; - } - - String chatMessage = event.getMessage(); - - if (chatMessage.contains("You have completed") && chatMessage.contains("Treasure")) - { - Matcher m = NUMBER_PATTERN.matcher(Text.removeTags(chatMessage)); - if (m.find()) - { - clueNumber = Integer.valueOf(m.group()); - clueType = chatMessage.substring(chatMessage.lastIndexOf(m.group()) + m.group().length() + 1, chatMessage.indexOf("Treasure") - 1); - return; - } - } - - if (chatMessage.startsWith("Your Barrows chest count is")) - { - Matcher m = NUMBER_PATTERN.matcher(Text.removeTags(chatMessage)); - if (m.find()) - { - barrowsNumber = Integer.valueOf(m.group()); - return; - } - } - - if (chatMessage.startsWith("Your completed Chambers of Xeric count is:")) - { - Matcher m = NUMBER_PATTERN.matcher(Text.removeTags(chatMessage)); - if (m.find()) - { - chambersOfXericNumber = Integer.valueOf(m.group()); - return; - } - } - - if (chatMessage.startsWith("Your completed Chambers of Xeric Challenge Mode count is:")) - { - Matcher m = NUMBER_PATTERN.matcher(Text.removeTags(chatMessage)); - if (m.find()) - { - chambersOfXericChallengeNumber = Integer.valueOf(m.group()); - return; - } - } - - if (chatMessage.startsWith("Your completed Theatre of Blood count is:")) - { - Matcher m = NUMBER_PATTERN.matcher(Text.removeTags(chatMessage)); - if (m.find()) - { - theatreOfBloodNumber = Integer.valueOf(m.group()); - return; - } - } - - if (config.screenshotPet() && PET_MESSAGES.stream().anyMatch(chatMessage::contains)) - { - String fileName = "Pet " + format(new Date()); - takeScreenshot(fileName); - } - - if (config.screenshotBossKills() ) - { - Matcher m = BOSSKILL_MESSAGE_PATTERN.matcher(chatMessage); - if (m.matches()) - { - String bossName = m.group(1); - String bossKillcount = m.group(2); - String fileName = bossName + "(" + bossKillcount + ")"; - takeScreenshot(fileName); - } - } - - if (config.screenshotValuableDrop()) - { - Matcher m = VALUABLE_DROP_PATTERN.matcher(chatMessage); - if (m.matches()) - { - String valuableDropName = m.group(1); - String fileName = "Valuable drop " + valuableDropName + " " + format(new Date()); - takeScreenshot(fileName); - } - } - - if (config.screenshotUntradeableDrop()) - { - Matcher m = UNTRADEABLE_DROP_PATTERN.matcher(chatMessage); - if (m.matches()) - { - String untradeableDropName = m.group(1); - String fileName = "Untradeable drop " + untradeableDropName + " " + format(new Date()); - takeScreenshot(fileName); - } - } - - if (config.screenshotDuels()) - { - Matcher m = DUEL_END_PATTERN.matcher(chatMessage); - if (m.find()) - { - String result = m.group(1); - String count = m.group(2); - String fileName = "Duel " + result + " (" + count + ")"; - takeScreenshot(fileName); - } - } - } - - @Subscribe - public void onWidgetLoaded(WidgetLoaded event) - { - String fileName; - int groupId = event.getGroupId(); - - switch (groupId) - { - case QUEST_COMPLETED_GROUP_ID: - case CLUE_SCROLL_REWARD_GROUP_ID: - case CHAMBERS_OF_XERIC_REWARD_GROUP_ID: - case THEATRE_OF_BLOOD_REWARD_GROUP_ID: - case BARROWS_REWARD_GROUP_ID: - if (!config.screenshotRewards()) - { - return; - } - break; - case LEVEL_UP_GROUP_ID: - case DIALOG_SPRITE_GROUP_ID: - if (!config.screenshotLevels()) - { - return; - } - break; - case KINGDOM_GROUP_ID: - if (!config.screenshotKingdom()) - { - return; - } - break; - } - - switch (groupId) - { - case KINGDOM_GROUP_ID: - { - fileName = "Kingdom " + LocalDate.now(); - takeScreenshot(fileName); - break; - } - case CHAMBERS_OF_XERIC_REWARD_GROUP_ID: - { - if (chambersOfXericNumber != null) - { - fileName = "Chambers of Xeric(" + chambersOfXericNumber + ")"; - chambersOfXericNumber = null; - break; - } - else if (chambersOfXericChallengeNumber != null) - { - fileName = "Chambers of Xeric Challenge Mode(" + chambersOfXericChallengeNumber + ")"; - chambersOfXericChallengeNumber = null; - break; - } - else - { - return; - } - } - case THEATRE_OF_BLOOD_REWARD_GROUP_ID: - { - if (theatreOfBloodNumber == null) - { - return; - } - - fileName = "Theatre of Blood(" + theatreOfBloodNumber + ")"; - theatreOfBloodNumber = null; - break; - } - case BARROWS_REWARD_GROUP_ID: - { - if (barrowsNumber == null) - { - return; - } - - fileName = "Barrows(" + barrowsNumber + ")"; - barrowsNumber = null; - break; - } - case LEVEL_UP_GROUP_ID: - case DIALOG_SPRITE_GROUP_ID: - case QUEST_COMPLETED_GROUP_ID: - { - // level up widget gets loaded prior to the text being set, so wait until the next tick - shouldTakeScreenshot = true; - return; - } - case CLUE_SCROLL_REWARD_GROUP_ID: - { - if (clueType == null || clueNumber == null) - { - return; - } - - fileName = Character.toUpperCase(clueType.charAt(0)) + clueType.substring(1) + "(" + clueNumber + ")"; - clueType = null; - clueNumber = null; - break; - } - default: - return; - } - - takeScreenshot(fileName); - } - - /** - * Receives a WidgetInfo pointing to the middle widget of the level-up dialog, - * and parses it into a shortened string for filename usage. - * - * @param levelUpLevel WidgetInfo pointing to the required text widget, - * with the format "Your Skill (level is/are) now 99." - * @return Shortened string in the format "Skill(99)" - */ - String parseLevelUpWidget(WidgetInfo levelUpLevel) - { - Widget levelChild = client.getWidget(levelUpLevel); - if (levelChild == null) - { - return null; - } - - Matcher m = LEVEL_UP_PATTERN.matcher(levelChild.getText()); - if (!m.matches()) - { - return null; - } - - String skillName = m.group(1); - String skillLevel = m.group(2); - return skillName + "(" + skillLevel + ")"; - } - - /** - * Saves a screenshot of the client window to the screenshot folder as a PNG, - * and optionally uploads it to an image-hosting service. - * - * @param fileName Filename to use, without file extension. - */ - private void takeScreenshot(String fileName) - { - if (client.getGameState() == GameState.LOGIN_SCREEN) - { - // Prevent the screenshot from being captured - log.info("Login screenshot prevented"); - return; - } - - Consumer imageCallback = (img) -> - { - // This callback is on the game thread, move to executor thread - executor.submit(() -> takeScreenshot(fileName, img)); - }; - - if (config.displayDate()) - { - screenshotOverlay.queueForTimestamp(imageCallback); - } - else - { - drawManager.requestNextFrameListener(imageCallback); - } - } - - private void takeScreenshot(String fileName, Image image) - { - BufferedImage screenshot = config.includeFrame() - ? new BufferedImage(clientUi.getWidth(), clientUi.getHeight(), BufferedImage.TYPE_INT_ARGB) - : new BufferedImage(image.getWidth(null), image.getHeight(null), BufferedImage.TYPE_INT_ARGB); - - Graphics graphics = screenshot.getGraphics(); - - int gameOffsetX = 0; - int gameOffsetY = 0; - - if (config.includeFrame()) - { - // Draw the client frame onto the screenshot - try - { - SwingUtilities.invokeAndWait(() -> clientUi.paint(graphics)); - } - catch (InterruptedException | InvocationTargetException e) - { - log.warn("unable to paint client UI on screenshot", e); - } - - // Evaluate the position of the game inside the frame - final Point canvasOffset = clientUi.getCanvasOffset(); - gameOffsetX = canvasOffset.getX(); - gameOffsetY = canvasOffset.getY(); - } - - // Draw the game onto the screenshot - graphics.drawImage(image, gameOffsetX, gameOffsetY, null); - - File playerFolder; - if (client.getLocalPlayer() != null && client.getLocalPlayer().getName() != null) - { - final EnumSet worldTypes = client.getWorldType(); - final boolean dmm = worldTypes.contains(WorldType.DEADMAN); - final boolean sdmm = worldTypes.contains(WorldType.SEASONAL_DEADMAN); - final boolean dmmt = worldTypes.contains(WorldType.DEADMAN_TOURNAMENT); - final boolean isDmmWorld = dmm || sdmm || dmmt; - - String playerDir = client.getLocalPlayer().getName(); - if (isDmmWorld) - { - playerDir += "-Deadman"; - } - playerFolder = new File(SCREENSHOT_DIR, playerDir); - } - else - { - playerFolder = SCREENSHOT_DIR; - } - - playerFolder.mkdirs(); - - try - { - File screenshotFile = new File(playerFolder, fileName + ".png"); - - ImageIO.write(screenshot, "PNG", screenshotFile); - - if (config.uploadScreenshot()) - { - uploadScreenshot(screenshotFile); - } - else if (config.notifyWhenTaken()) - { - notifier.notify("A screenshot was saved to " + screenshotFile, TrayIcon.MessageType.INFO); - } - } - catch (IOException ex) - { - log.warn("error writing screenshot", ex); - } - } - - /** - * Uploads a screenshot to the Imgur image-hosting service, - * and copies the image link to the clipboard. - * - * @param screenshotFile Image file to upload. - * @throws IOException Thrown if the file cannot be read. - */ - private void uploadScreenshot(File screenshotFile) throws IOException - { - String json = RuneLiteAPI.GSON.toJson(new ImageUploadRequest(screenshotFile)); - - Request request = new Request.Builder() - .url(IMGUR_IMAGE_UPLOAD_URL) - .addHeader("Authorization", "Client-ID " + IMGUR_CLIENT_ID) - .post(RequestBody.create(JSON, json)) - .build(); - - RuneLiteAPI.CLIENT.newCall(request).enqueue(new Callback() - { - @Override - public void onFailure(Call call, IOException ex) - { - log.warn("error uploading screenshot", ex); - } - - @Override - public void onResponse(Call call, Response response) throws IOException - { - try (InputStream in = response.body().byteStream()) - { - ImageUploadResponse imageUploadResponse = RuneLiteAPI.GSON - .fromJson(new InputStreamReader(in), ImageUploadResponse.class); - - if (imageUploadResponse.isSuccess()) - { - String link = imageUploadResponse.getData().getLink(); - - StringSelection selection = new StringSelection(link); - Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard(); - clipboard.setContents(selection, selection); - - if (config.notifyWhenTaken()) - { - notifier.notify("A screenshot was uploaded and inserted into your clipboard!", TrayIcon.MessageType.INFO); - } - } - } - } - }); - } - - @VisibleForTesting - int getClueNumber() - { - return clueNumber; - } - - @VisibleForTesting - String getClueType() - { - return clueType; - } - - @VisibleForTesting - int getBarrowsNumber() - { - return barrowsNumber; - } - - @VisibleForTesting - int getChambersOfXericNumber() - { - return chambersOfXericNumber; - } - - @VisibleForTesting - int getChambersOfXericChallengeNumber() - { - return chambersOfXericChallengeNumber; - } - - @VisibleForTesting - int gettheatreOfBloodNumber() - { - return theatreOfBloodNumber; - } -} +/* + * Copyright (c) 2018, Lotto + * 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.screenshot; + +import com.google.common.annotations.VisibleForTesting; +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableMap; +import com.google.inject.Provides; +import java.awt.Desktop; +import java.awt.Graphics; +import java.awt.Image; +import java.awt.Toolkit; +import java.awt.TrayIcon; +import java.awt.datatransfer.Clipboard; +import java.awt.datatransfer.StringSelection; +import java.awt.image.BufferedImage; +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.lang.reflect.InvocationTargetException; +import java.text.DateFormat; +import java.text.SimpleDateFormat; +import java.time.LocalDate; +import java.util.Date; +import java.util.EnumSet; +import java.util.concurrent.ScheduledExecutorService; +import java.util.function.Consumer; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import javax.imageio.ImageIO; +import javax.inject.Inject; +import javax.swing.SwingUtilities; +import lombok.AccessLevel; +import lombok.Getter; +import lombok.extern.slf4j.Slf4j; +import net.runelite.api.ChatMessageType; +import net.runelite.api.Client; +import net.runelite.api.GameState; +import net.runelite.api.Player; +import net.runelite.api.Point; +import net.runelite.api.SpriteID; +import net.runelite.api.WorldType; +import net.runelite.api.events.ChatMessage; +import net.runelite.api.events.GameStateChanged; +import net.runelite.api.events.GameTick; +import net.runelite.api.events.LocalPlayerDeath; +import net.runelite.api.events.WidgetLoaded; +import net.runelite.api.widgets.Widget; +import static net.runelite.api.widgets.WidgetID.BARROWS_REWARD_GROUP_ID; +import static net.runelite.api.widgets.WidgetID.CHAMBERS_OF_XERIC_REWARD_GROUP_ID; +import static net.runelite.api.widgets.WidgetID.CLUE_SCROLL_REWARD_GROUP_ID; +import static net.runelite.api.widgets.WidgetID.DIALOG_SPRITE_GROUP_ID; +import static net.runelite.api.widgets.WidgetID.KINGDOM_GROUP_ID; +import static net.runelite.api.widgets.WidgetID.LEVEL_UP_GROUP_ID; +import static net.runelite.api.widgets.WidgetID.QUEST_COMPLETED_GROUP_ID; +import static net.runelite.api.widgets.WidgetID.THEATRE_OF_BLOOD_REWARD_GROUP_ID; +import net.runelite.api.widgets.WidgetInfo; +import net.runelite.client.Notifier; +import static net.runelite.client.RuneLite.SCREENSHOT_DIR; +import net.runelite.client.config.ConfigManager; +import net.runelite.client.eventbus.Subscribe; +import net.runelite.client.events.PlayerLootReceived; +import net.runelite.client.game.SpriteManager; +import net.runelite.client.input.KeyManager; +import net.runelite.client.plugins.Plugin; +import net.runelite.client.plugins.PluginDescriptor; +import net.runelite.client.plugins.screenshot.imgur.ImageUploadRequest; +import net.runelite.client.plugins.screenshot.imgur.ImageUploadResponse; +import net.runelite.client.ui.ClientToolbar; +import net.runelite.client.ui.ClientUI; +import net.runelite.client.ui.DrawManager; +import net.runelite.client.ui.NavigationButton; +import net.runelite.client.ui.overlay.OverlayManager; +import net.runelite.client.util.HotkeyListener; +import net.runelite.client.util.ImageUtil; +import net.runelite.client.util.Text; +import net.runelite.http.api.RuneLiteAPI; +import okhttp3.Call; +import okhttp3.Callback; +import okhttp3.HttpUrl; +import okhttp3.MediaType; +import okhttp3.Request; +import okhttp3.RequestBody; +import okhttp3.Response; + +@PluginDescriptor( + name = "Screenshot", + description = "Enable the manual and automatic taking of screenshots", + tags = {"external", "images", "imgur", "integration", "notifications"} +) +@Slf4j +public class ScreenshotPlugin extends Plugin +{ + private static final String IMGUR_CLIENT_ID = "30d71e5f6860809"; + private static final HttpUrl IMGUR_IMAGE_UPLOAD_URL = HttpUrl.parse("https://api.imgur.com/3/image"); + private static final MediaType JSON = MediaType.parse("application/json"); + + private static final DateFormat TIME_FORMAT = new SimpleDateFormat("yyyy-MM-dd_HH-mm-ss"); + + private static final Pattern NUMBER_PATTERN = Pattern.compile("([0-9]+)"); + private static final Pattern LEVEL_UP_PATTERN = Pattern.compile(".*Your ([a-zA-Z]+) (?:level is|are)? now (\\d+)\\."); + private static final Pattern BOSSKILL_MESSAGE_PATTERN = Pattern.compile("Your (.+) kill count is: (\\d+)."); + private static final Pattern VALUABLE_DROP_PATTERN = Pattern.compile(".*Valuable drop: ([^<>]+)(?:)?"); + private static final Pattern UNTRADEABLE_DROP_PATTERN = Pattern.compile(".*Untradeable drop: ([^<>]+)(?:)?"); + private static final Pattern DUEL_END_PATTERN = Pattern.compile("You have now (won|lost) ([0-9]+) duels?\\."); + private static final ImmutableList PET_MESSAGES = ImmutableList.of("You have a funny feeling like you're being followed", + "You feel something weird sneaking into your backpack", + "You have a funny feeling like you would have been followed"); + + static String format(Date date) + { + synchronized (TIME_FORMAT) + { + return TIME_FORMAT.format(date); + } + } + + private String clueType; + private Integer clueNumber; + + private Integer barrowsNumber; + + private Integer chambersOfXericNumber; + + private Integer chambersOfXericChallengeNumber; + + private Integer theatreOfBloodNumber; + + private boolean shouldTakeScreenshot; + + @Inject + private ScreenshotConfig config; + + @Inject + private OverlayManager overlayManager; + + @Inject + private ScreenshotOverlay screenshotOverlay; + + @Inject + private Notifier notifier; + + @Inject + private Client client; + + @Inject + private ClientUI clientUi; + + @Inject + private ClientToolbar clientToolbar; + + @Inject + private DrawManager drawManager; + + @Inject + private ScheduledExecutorService executor; + + @Inject + private KeyManager keyManager; + + @Inject + private SpriteManager spriteManager; + + @Getter(AccessLevel.PACKAGE) + private BufferedImage reportButton; + + private NavigationButton titleBarButton; + + private final HotkeyListener hotkeyListener = new HotkeyListener(() -> config.hotkey()) + { + @Override + public void hotkeyPressed() + { + takeScreenshot(format(new Date())); + } + }; + + @Provides + ScreenshotConfig getConfig(ConfigManager configManager) + { + return configManager.getConfig(ScreenshotConfig.class); + } + + @Override + protected void startUp() throws Exception + { + overlayManager.add(screenshotOverlay); + SCREENSHOT_DIR.mkdirs(); + keyManager.registerKeyListener(hotkeyListener); + + final BufferedImage iconImage = ImageUtil.getResourceStreamFromClass(getClass(), "screenshot.png"); + + titleBarButton = NavigationButton.builder() + .tab(false) + .tooltip("Take screenshot") + .icon(iconImage) + .onClick(() -> takeScreenshot(format(new Date()))) + .popup(ImmutableMap + .builder() + .put("Open screenshot folder...", () -> + { + try + { + Desktop.getDesktop().open(SCREENSHOT_DIR); + } + catch (IOException ex) + { + log.warn("Error opening screenshot dir", ex); + } + }) + .build()) + .build(); + + clientToolbar.addNavigation(titleBarButton); + } + + @Override + protected void shutDown() throws Exception + { + overlayManager.remove(screenshotOverlay); + clientToolbar.removeNavigation(titleBarButton); + keyManager.unregisterKeyListener(hotkeyListener); + } + + @Subscribe + public void onGameStateChanged(GameStateChanged event) + { + if (event.getGameState() == GameState.LOGGED_IN + && reportButton == null) + { + reportButton = spriteManager.getSprite(SpriteID.CHATBOX_REPORT_BUTTON, 0); + } + } + + @Subscribe + public void onGameTick(GameTick event) + { + if (!shouldTakeScreenshot) + { + return; + } + + shouldTakeScreenshot = false; + + String fileName = null; + if (client.getWidget(WidgetInfo.LEVEL_UP_LEVEL) != null) + { + fileName = parseLevelUpWidget(WidgetInfo.LEVEL_UP_LEVEL); + } + else if (client.getWidget(WidgetInfo.DIALOG_SPRITE_TEXT) != null) + { + fileName = parseLevelUpWidget(WidgetInfo.DIALOG_SPRITE_TEXT); + } + else if (client.getWidget(WidgetInfo.QUEST_COMPLETED_NAME_TEXT) != null) + { + // "You have completed The Corsair Curse!" + String text = client.getWidget(WidgetInfo.QUEST_COMPLETED_NAME_TEXT).getText(); + fileName = "Quest(" + text.substring(19, text.length() - 1) + ")"; + } + + if (fileName != null) + { + takeScreenshot(fileName); + } + } + + @Subscribe + public void onLocalPlayerDeath(LocalPlayerDeath death) + { + if (config.screenshotPlayerDeath()) + { + takeScreenshot("Death " + format(new Date())); + } + } + + @Subscribe + public void onPlayerLootReceived(final PlayerLootReceived playerLootReceived) + { + if (config.screenshotKills()) + { + final Player player = playerLootReceived.getPlayer(); + final String name = player.getName(); + String fileName = "Kill " + name + " " + format(new Date()); + takeScreenshot(fileName); + } + } + + @Subscribe + public void onChatMessage(ChatMessage event) + { + if (event.getType() != ChatMessageType.GAMEMESSAGE && event.getType() != ChatMessageType.SPAM && event.getType() != ChatMessageType.TRADE) + { + return; + } + + String chatMessage = event.getMessage(); + + if (chatMessage.contains("You have completed") && chatMessage.contains("Treasure")) + { + Matcher m = NUMBER_PATTERN.matcher(Text.removeTags(chatMessage)); + if (m.find()) + { + clueNumber = Integer.valueOf(m.group()); + clueType = chatMessage.substring(chatMessage.lastIndexOf(m.group()) + m.group().length() + 1, chatMessage.indexOf("Treasure") - 1); + return; + } + } + + if (chatMessage.startsWith("Your Barrows chest count is")) + { + Matcher m = NUMBER_PATTERN.matcher(Text.removeTags(chatMessage)); + if (m.find()) + { + barrowsNumber = Integer.valueOf(m.group()); + return; + } + } + + if (chatMessage.startsWith("Your completed Chambers of Xeric count is:")) + { + Matcher m = NUMBER_PATTERN.matcher(Text.removeTags(chatMessage)); + if (m.find()) + { + chambersOfXericNumber = Integer.valueOf(m.group()); + return; + } + } + + if (chatMessage.startsWith("Your completed Chambers of Xeric Challenge Mode count is:")) + { + Matcher m = NUMBER_PATTERN.matcher(Text.removeTags(chatMessage)); + if (m.find()) + { + chambersOfXericChallengeNumber = Integer.valueOf(m.group()); + return; + } + } + + if (chatMessage.startsWith("Your completed Theatre of Blood count is:")) + { + Matcher m = NUMBER_PATTERN.matcher(Text.removeTags(chatMessage)); + if (m.find()) + { + theatreOfBloodNumber = Integer.valueOf(m.group()); + return; + } + } + + if (config.screenshotPet() && PET_MESSAGES.stream().anyMatch(chatMessage::contains)) + { + String fileName = "Pet " + format(new Date()); + takeScreenshot(fileName); + } + + if (config.screenshotBossKills()) + { + Matcher m = BOSSKILL_MESSAGE_PATTERN.matcher(chatMessage); + if (m.matches()) + { + String bossName = m.group(1); + String bossKillcount = m.group(2); + String fileName = bossName + "(" + bossKillcount + ")"; + takeScreenshot(fileName); + } + } + + if (config.screenshotValuableDrop()) + { + Matcher m = VALUABLE_DROP_PATTERN.matcher(chatMessage); + if (m.matches()) + { + String valuableDropName = m.group(1); + String fileName = "Valuable drop " + valuableDropName + " " + format(new Date()); + takeScreenshot(fileName); + } + } + + if (config.screenshotUntradeableDrop()) + { + Matcher m = UNTRADEABLE_DROP_PATTERN.matcher(chatMessage); + if (m.matches()) + { + String untradeableDropName = m.group(1); + String fileName = "Untradeable drop " + untradeableDropName + " " + format(new Date()); + takeScreenshot(fileName); + } + } + + if (config.screenshotDuels()) + { + Matcher m = DUEL_END_PATTERN.matcher(chatMessage); + if (m.find()) + { + String result = m.group(1); + String count = m.group(2); + String fileName = "Duel " + result + " (" + count + ")"; + takeScreenshot(fileName); + } + } + } + + @Subscribe + public void onWidgetLoaded(WidgetLoaded event) + { + String fileName; + int groupId = event.getGroupId(); + + switch (groupId) + { + case QUEST_COMPLETED_GROUP_ID: + case CLUE_SCROLL_REWARD_GROUP_ID: + case CHAMBERS_OF_XERIC_REWARD_GROUP_ID: + case THEATRE_OF_BLOOD_REWARD_GROUP_ID: + case BARROWS_REWARD_GROUP_ID: + if (!config.screenshotRewards()) + { + return; + } + break; + case LEVEL_UP_GROUP_ID: + case DIALOG_SPRITE_GROUP_ID: + if (!config.screenshotLevels()) + { + return; + } + break; + case KINGDOM_GROUP_ID: + if (!config.screenshotKingdom()) + { + return; + } + break; + } + + switch (groupId) + { + case KINGDOM_GROUP_ID: + { + fileName = "Kingdom " + LocalDate.now(); + takeScreenshot(fileName); + break; + } + case CHAMBERS_OF_XERIC_REWARD_GROUP_ID: + { + if (chambersOfXericNumber != null) + { + fileName = "Chambers of Xeric(" + chambersOfXericNumber + ")"; + chambersOfXericNumber = null; + break; + } + else if (chambersOfXericChallengeNumber != null) + { + fileName = "Chambers of Xeric Challenge Mode(" + chambersOfXericChallengeNumber + ")"; + chambersOfXericChallengeNumber = null; + break; + } + else + { + return; + } + } + case THEATRE_OF_BLOOD_REWARD_GROUP_ID: + { + if (theatreOfBloodNumber == null) + { + return; + } + + fileName = "Theatre of Blood(" + theatreOfBloodNumber + ")"; + theatreOfBloodNumber = null; + break; + } + case BARROWS_REWARD_GROUP_ID: + { + if (barrowsNumber == null) + { + return; + } + + fileName = "Barrows(" + barrowsNumber + ")"; + barrowsNumber = null; + break; + } + case LEVEL_UP_GROUP_ID: + case DIALOG_SPRITE_GROUP_ID: + case QUEST_COMPLETED_GROUP_ID: + { + // level up widget gets loaded prior to the text being set, so wait until the next tick + shouldTakeScreenshot = true; + return; + } + case CLUE_SCROLL_REWARD_GROUP_ID: + { + if (clueType == null || clueNumber == null) + { + return; + } + + fileName = Character.toUpperCase(clueType.charAt(0)) + clueType.substring(1) + "(" + clueNumber + ")"; + clueType = null; + clueNumber = null; + break; + } + default: + return; + } + + takeScreenshot(fileName); + } + + /** + * Receives a WidgetInfo pointing to the middle widget of the level-up dialog, + * and parses it into a shortened string for filename usage. + * + * @param levelUpLevel WidgetInfo pointing to the required text widget, + * with the format "Your Skill (level is/are) now 99." + * @return Shortened string in the format "Skill(99)" + */ + String parseLevelUpWidget(WidgetInfo levelUpLevel) + { + Widget levelChild = client.getWidget(levelUpLevel); + if (levelChild == null) + { + return null; + } + + Matcher m = LEVEL_UP_PATTERN.matcher(levelChild.getText()); + if (!m.matches()) + { + return null; + } + + String skillName = m.group(1); + String skillLevel = m.group(2); + return skillName + "(" + skillLevel + ")"; + } + + /** + * Saves a screenshot of the client window to the screenshot folder as a PNG, + * and optionally uploads it to an image-hosting service. + * + * @param fileName Filename to use, without file extension. + */ + private void takeScreenshot(String fileName) + { + if (client.getGameState() == GameState.LOGIN_SCREEN) + { + // Prevent the screenshot from being captured + log.info("Login screenshot prevented"); + return; + } + + Consumer imageCallback = (img) -> + { + // This callback is on the game thread, move to executor thread + executor.submit(() -> takeScreenshot(fileName, img)); + }; + + if (config.displayDate()) + { + screenshotOverlay.queueForTimestamp(imageCallback); + } + else + { + drawManager.requestNextFrameListener(imageCallback); + } + } + + private void takeScreenshot(String fileName, Image image) + { + BufferedImage screenshot = config.includeFrame() + ? new BufferedImage(clientUi.getWidth(), clientUi.getHeight(), BufferedImage.TYPE_INT_ARGB) + : new BufferedImage(image.getWidth(null), image.getHeight(null), BufferedImage.TYPE_INT_ARGB); + + Graphics graphics = screenshot.getGraphics(); + + int gameOffsetX = 0; + int gameOffsetY = 0; + + if (config.includeFrame()) + { + // Draw the client frame onto the screenshot + try + { + SwingUtilities.invokeAndWait(() -> clientUi.paint(graphics)); + } + catch (InterruptedException | InvocationTargetException e) + { + log.warn("unable to paint client UI on screenshot", e); + } + + // Evaluate the position of the game inside the frame + final Point canvasOffset = clientUi.getCanvasOffset(); + gameOffsetX = canvasOffset.getX(); + gameOffsetY = canvasOffset.getY(); + } + + // Draw the game onto the screenshot + graphics.drawImage(image, gameOffsetX, gameOffsetY, null); + + File playerFolder; + if (client.getLocalPlayer() != null && client.getLocalPlayer().getName() != null) + { + final EnumSet worldTypes = client.getWorldType(); + final boolean dmm = worldTypes.contains(WorldType.DEADMAN); + final boolean sdmm = worldTypes.contains(WorldType.SEASONAL_DEADMAN); + final boolean dmmt = worldTypes.contains(WorldType.DEADMAN_TOURNAMENT); + final boolean isDmmWorld = dmm || sdmm || dmmt; + + String playerDir = client.getLocalPlayer().getName(); + if (isDmmWorld) + { + playerDir += "-Deadman"; + } + playerFolder = new File(SCREENSHOT_DIR, playerDir); + } + else + { + playerFolder = SCREENSHOT_DIR; + } + + playerFolder.mkdirs(); + + try + { + File screenshotFile = new File(playerFolder, fileName + ".png"); + + ImageIO.write(screenshot, "PNG", screenshotFile); + + if (config.uploadScreenshot()) + { + uploadScreenshot(screenshotFile); + } + else if (config.notifyWhenTaken()) + { + notifier.notify("A screenshot was saved to " + screenshotFile, TrayIcon.MessageType.INFO); + } + } + catch (IOException ex) + { + log.warn("error writing screenshot", ex); + } + } + + /** + * Uploads a screenshot to the Imgur image-hosting service, + * and copies the image link to the clipboard. + * + * @param screenshotFile Image file to upload. + * @throws IOException Thrown if the file cannot be read. + */ + private void uploadScreenshot(File screenshotFile) throws IOException + { + String json = RuneLiteAPI.GSON.toJson(new ImageUploadRequest(screenshotFile)); + + Request request = new Request.Builder() + .url(IMGUR_IMAGE_UPLOAD_URL) + .addHeader("Authorization", "Client-ID " + IMGUR_CLIENT_ID) + .post(RequestBody.create(JSON, json)) + .build(); + + RuneLiteAPI.CLIENT.newCall(request).enqueue(new Callback() + { + @Override + public void onFailure(Call call, IOException ex) + { + log.warn("error uploading screenshot", ex); + } + + @Override + public void onResponse(Call call, Response response) throws IOException + { + try (InputStream in = response.body().byteStream()) + { + ImageUploadResponse imageUploadResponse = RuneLiteAPI.GSON + .fromJson(new InputStreamReader(in), ImageUploadResponse.class); + + if (imageUploadResponse.isSuccess()) + { + String link = imageUploadResponse.getData().getLink(); + + StringSelection selection = new StringSelection(link); + Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard(); + clipboard.setContents(selection, selection); + + if (config.notifyWhenTaken()) + { + notifier.notify("A screenshot was uploaded and inserted into your clipboard!", TrayIcon.MessageType.INFO); + } + } + } + } + }); + } + + @VisibleForTesting + int getClueNumber() + { + return clueNumber; + } + + @VisibleForTesting + String getClueType() + { + return clueType; + } + + @VisibleForTesting + int getBarrowsNumber() + { + return barrowsNumber; + } + + @VisibleForTesting + int getChambersOfXericNumber() + { + return chambersOfXericNumber; + } + + @VisibleForTesting + int getChambersOfXericChallengeNumber() + { + return chambersOfXericChallengeNumber; + } + + @VisibleForTesting + int gettheatreOfBloodNumber() + { + return theatreOfBloodNumber; + } +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/shiftwalker/ShiftWalkerConfig.java b/runelite-client/src/main/java/net/runelite/client/plugins/shiftwalker/ShiftWalkerConfig.java index dfd21986ba..049dd866b7 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/shiftwalker/ShiftWalkerConfig.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/shiftwalker/ShiftWalkerConfig.java @@ -1,66 +1,66 @@ -/* - * Copyright (c) 2018, Plinko60 - * 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.shiftwalker; - -import net.runelite.client.config.Config; -import net.runelite.client.config.ConfigGroup; -import net.runelite.client.config.ConfigItem; - -@ConfigGroup("shiftwalkhere") -public interface ShiftWalkerConfig extends Config -{ - - @ConfigItem( - keyName = "shiftWalkEverything", - name = "Walk Under Everything", - description = "Enable this option when you do not want to interact with anything while Shift is pressed. " + - "If Walk Here is an option it will be the action taken." - ) - default boolean shiftWalkEverything() - { - return true; - } - - @ConfigItem( - keyName = "shiftWalkBoxTraps", - name = "Walk Under Box Traps", - description = "Press \"Shift\" to be able to walk under instead of picking up a Box Trap." - ) - default boolean shiftWalkBoxTraps() - { - return true; - } - - @ConfigItem( - keyName = "shiftWalkAttackOption", - name = "Walk Under Attack Options", - description = "Press \"Shift\" to be able to walk instead of attacking. Make sure Left Click Attack is on." - ) - default boolean shiftWalkAttackOption() - { - return true; - } - -} +/* + * Copyright (c) 2018, Plinko60 + * 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.shiftwalker; + +import net.runelite.client.config.Config; +import net.runelite.client.config.ConfigGroup; +import net.runelite.client.config.ConfigItem; + +@ConfigGroup("shiftwalkhere") +public interface ShiftWalkerConfig extends Config +{ + + @ConfigItem( + keyName = "shiftWalkEverything", + name = "Walk Under Everything", + description = "Enable this option when you do not want to interact with anything while Shift is pressed. " + + "If Walk Here is an option it will be the action taken." + ) + default boolean shiftWalkEverything() + { + return true; + } + + @ConfigItem( + keyName = "shiftWalkBoxTraps", + name = "Walk Under Box Traps", + description = "Press \"Shift\" to be able to walk under instead of picking up a Box Trap." + ) + default boolean shiftWalkBoxTraps() + { + return true; + } + + @ConfigItem( + keyName = "shiftWalkAttackOption", + name = "Walk Under Attack Options", + description = "Press \"Shift\" to be able to walk instead of attacking. Make sure Left Click Attack is on." + ) + default boolean shiftWalkAttackOption() + { + return true; + } + +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/shiftwalker/ShiftWalkerInputListener.java b/runelite-client/src/main/java/net/runelite/client/plugins/shiftwalker/ShiftWalkerInputListener.java index 677f30357d..9c1cb5b521 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/shiftwalker/ShiftWalkerInputListener.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/shiftwalker/ShiftWalkerInputListener.java @@ -1,61 +1,60 @@ -/* - * Copyright (c) 2018, Plinko60 - * 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.shiftwalker; - -import net.runelite.client.input.KeyListener; - -import javax.inject.Inject; -import java.awt.event.KeyEvent; - -public class ShiftWalkerInputListener implements KeyListener -{ - - @Inject - private ShiftWalkerPlugin plugin; - - @Override - public void keyTyped(KeyEvent event) - { - - } - - @Override - public void keyPressed(KeyEvent event) - { - if (event.getKeyCode() == KeyEvent.VK_SHIFT) - { - plugin.setHotKeyPressed(true); - } - } - - @Override - public void keyReleased(KeyEvent event) - { - if (event.getKeyCode() == KeyEvent.VK_SHIFT) - { - plugin.setHotKeyPressed(false); - } - } -} +/* + * Copyright (c) 2018, Plinko60 + * 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.shiftwalker; + +import java.awt.event.KeyEvent; +import javax.inject.Inject; +import net.runelite.client.input.KeyListener; + +public class ShiftWalkerInputListener implements KeyListener +{ + + @Inject + private ShiftWalkerPlugin plugin; + + @Override + public void keyTyped(KeyEvent event) + { + + } + + @Override + public void keyPressed(KeyEvent event) + { + if (event.getKeyCode() == KeyEvent.VK_SHIFT) + { + plugin.setHotKeyPressed(true); + } + } + + @Override + public void keyReleased(KeyEvent event) + { + if (event.getKeyCode() == KeyEvent.VK_SHIFT) + { + plugin.setHotKeyPressed(false); + } + } +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/shiftwalker/ShiftWalkerPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/shiftwalker/ShiftWalkerPlugin.java index fde27f5faf..ca460e98a2 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/shiftwalker/ShiftWalkerPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/shiftwalker/ShiftWalkerPlugin.java @@ -25,9 +25,13 @@ package net.runelite.client.plugins.shiftwalker; import com.google.inject.Provides; +import javax.inject.Inject; import lombok.Setter; -import net.runelite.api.*; -import net.runelite.api.events.*; +import net.runelite.api.Client; +import net.runelite.api.GameState; +import net.runelite.api.MenuEntry; +import net.runelite.api.events.FocusChanged; +import net.runelite.api.events.MenuEntryAdded; import net.runelite.client.config.ConfigManager; import net.runelite.client.eventbus.Subscribe; import net.runelite.client.input.KeyManager; @@ -36,8 +40,6 @@ import net.runelite.client.plugins.PluginDescriptor; import net.runelite.client.plugins.PluginType; import net.runelite.client.util.Text; -import javax.inject.Inject; - /** * Shift Walker Plugin. Credit to MenuEntrySwapperPlugin for code some code structure used here. */ @@ -46,7 +48,7 @@ import javax.inject.Inject; description = "Use Shift to toggle the Walk Here menu option. While pressed you will Walk rather than interact with objects.", tags = {"npcs", "items", "objects"}, enabledByDefault = false, - type = PluginType.UTILITY + type = PluginType.UTILITY ) public class ShiftWalkerPlugin extends Plugin { @@ -101,6 +103,7 @@ public class ShiftWalkerPlugin extends Plugin /** * Event when a new menu entry was added. + * * @param event {@link MenuEntryAdded}. */ @Subscribe @@ -127,7 +130,7 @@ public class ShiftWalkerPlugin extends Plugin stripEntries(); } else if (config.shiftWalkBoxTraps() && ShiftWalkerGroups.BOX_TRAP_TARGETS.contains(target) - && ShiftWalkerGroups.BOX_TRAP_KEYWORDS.contains(pOptionToReplace)) + && ShiftWalkerGroups.BOX_TRAP_KEYWORDS.contains(pOptionToReplace)) { //swap(pOptionToReplace); //Swap only on box traps stripEntries(); @@ -143,16 +146,19 @@ public class ShiftWalkerPlugin extends Plugin * Strip everything except "Walk here" * Other way was unconventional because if there was multiple targets in the menu entry it wouldn't swap correctly */ - private void stripEntries() { + private void stripEntries() + { MenuEntry walkkHereEntry = null; - for (MenuEntry entry : client.getMenuEntries()) { + for (MenuEntry entry : client.getMenuEntries()) + { if ("Walk here".equals(entry.getOption())) { walkkHereEntry = entry; } } - if (walkkHereEntry != null) { + if (walkkHereEntry != null) + { MenuEntry[] newEntries = new MenuEntry[1]; newEntries[0] = walkkHereEntry; client.setMenuEntries(newEntries); @@ -161,6 +167,7 @@ public class ShiftWalkerPlugin extends Plugin /** * Swaps menu entries if the entries could be found. This places Walk Here where the top level menu option was. + * * @param pOptionToReplace The String containing the Menu Option that needs to be replaced. IE: "Attack", "Chop Down". */ private void swap(String pOptionToReplace) // Swap isn't currently used, and I don't know what's going on here so leaving for now @@ -183,7 +190,8 @@ public class ShiftWalkerPlugin extends Plugin /** * Finds the index of the menu that contains the verbiage we are looking for. - * @param pMenuEntries The list of {@link MenuEntry}s. + * + * @param pMenuEntries The list of {@link MenuEntry}s. * @param pMenuEntryToSearchFor The Option in the menu to search for. * @return The index location or null if it was not found. */ diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/skillcalculator/BankedCalculator.java b/runelite-client/src/main/java/net/runelite/client/plugins/skillcalculator/BankedCalculator.java index a0f0da78a5..790890bf39 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/skillcalculator/BankedCalculator.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/skillcalculator/BankedCalculator.java @@ -1,666 +1,675 @@ -/* - * Copyright (c) 2018, 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.skillcalculator; - -import java.awt.BorderLayout; -import java.awt.Color; -import java.awt.Dimension; -import java.text.DecimalFormat; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Map; -import java.util.Set; -import javax.swing.BorderFactory; -import javax.swing.Box; -import javax.swing.BoxLayout; -import javax.swing.JCheckBox; -import javax.swing.JLabel; -import javax.swing.JPanel; -import javax.swing.SwingUtilities; -import lombok.extern.slf4j.Slf4j; -import net.runelite.api.Client; -import net.runelite.api.Experience; -import net.runelite.api.Skill; -import net.runelite.client.game.ItemManager; -import net.runelite.client.plugins.skillcalculator.banked.CriticalItem; -import net.runelite.client.plugins.skillcalculator.banked.beans.Activity; -import net.runelite.client.plugins.skillcalculator.banked.beans.SecondaryItem; -import net.runelite.client.plugins.skillcalculator.banked.ui.CriticalItemPanel; -import net.runelite.client.plugins.skillcalculator.beans.SkillDataBonus; -import net.runelite.client.ui.ColorScheme; -import net.runelite.client.ui.DynamicGridLayout; -import net.runelite.client.ui.FontManager; - -@Slf4j -public class BankedCalculator extends JPanel -{ - private static final DecimalFormat XP_FORMAT_COMMA = new DecimalFormat("#,###.#"); - - private final SkillCalculatorPanel parent; - private final Client client; - private final UICalculatorInputArea uiInput; - private final SkillCalculatorConfig config; - private final ItemManager itemManager; - - private final CacheSkillData skillData = new CacheSkillData(); - private final List bonusCheckBoxes = new ArrayList<>(); - - // UI Input data - private float xpFactor = 1.0f; - private CalculatorType currentCalc; - private Skill currentSkill; - - private double totalBankedXp = 0.0f; - private JLabel totalLabel = new JLabel(); - private JPanel detailConfigContainer; - private JPanel detailContainer; - - // Banked Experience magic - private Map bankMap = new HashMap<>(); - private Map categoryMap = new HashMap<>(); // Check if CriticalItem Category is enabled - private Map panelMap = new HashMap<>(); - private Map criticalMap = new HashMap<>(); // Quantity of CriticalItem inside bankMap - private Map activityMap = new HashMap<>(); // Selected Activity used for calculating xp - private Map linkedMap = new HashMap<>(); // ItemID of item that links to the CriticalItem - - BankedCalculator( - SkillCalculatorPanel parent, - Client client, - UICalculatorInputArea uiInput, - SkillCalculatorConfig config, - ItemManager itemManager) - { - this.parent = parent; - this.client = client; - this.uiInput = uiInput; - this.config = config; - this.itemManager = itemManager; - - setLayout(new DynamicGridLayout(0, 1, 0, 5)); - - detailContainer = new JPanel(); - detailContainer.setLayout(new BoxLayout(detailContainer, BoxLayout.Y_AXIS)); - - detailConfigContainer = new JPanel(); - detailConfigContainer.setLayout(new BoxLayout(detailConfigContainer, BoxLayout.Y_AXIS)); - } - - private void reset() - { - criticalMap.clear(); - linkedMap.clear(); - xpFactor = 1f; - } - - /** - * Update target Xp and Level inputs to match current Xp + total banked XP - */ - private void syncInputFields() - { - // Update Target XP & Level to include total banked xp - int newTotal = (int) (uiInput.getCurrentXPInput() + totalBankedXp); - uiInput.setTargetXPInput(newTotal); - uiInput.setTargetLevelInput(Experience.getLevelForXp(newTotal)); - } - - /* - * Banked Experience Logic - */ - - /** - * Shows the Banked Xp tab for the CalculatorType - * @param calculatorType Selected Calculator Type - */ - void openBanked(CalculatorType calculatorType) - { - // clean slate for creating the required panel - removeAll(); - reset(); - if (calculatorType.getSkill() != currentSkill) - { - // Only clear Category and Activity map on skill change. - activityMap.clear(); - categoryMap.clear(); - } - currentCalc = calculatorType; - currentSkill = calculatorType.getSkill(); - bankMap = parent.getBankMap(); - - uiInput.setCurrentLevelInput(client.getRealSkillLevel(currentSkill)); - uiInput.setCurrentXPInput(client.getSkillExperience(currentSkill)); - - // Only adds Banked Experience portion if enabled for this SkillCalc and have seen their bank - if (!calculatorType.isBankedXpFlag()) - { - add(new JLabel("

Banked Experience is not enabled for this skill.
", JLabel.CENTER)); - } - else if (bankMap.size() <= 0) - { - add(new JLabel( "Please visit a bank!", JLabel.CENTER)); - } - else - { - // Prevent editing of the target level/exp since we automagically adjust them - uiInput.getUiFieldTargetLevel().setEditable(false); - uiInput.getUiFieldTargetXP().setEditable(false); - - // Now we can actually show the Banked Experience Panel - // Adds Config Options for this panel - renderBankedXpOptions(); - - renderBonusXpOptions(); - - // sprite 202 - calculatedBankedMaps(); - - // Calculate total banked experience and create detail container - refreshDetailContainer(); - - // Add back all necessary content - add(detailConfigContainer); - add(totalLabel); - add(detailContainer); - } - - revalidate(); - repaint(); - - // Update the input fields. - syncInputFields(); - } - - /** - * Add the config options for toggling each Item Category - */ - private void renderBankedXpOptions() - { - Set categories = CriticalItem.getSkillCategories(currentSkill); - if (categories == null) - { - return; - } - - add(new JLabel("Configs:")); - - for (String category : categories) - { - JPanel uiOption = new JPanel(new BorderLayout()); - JLabel uiLabel = new JLabel(category); - JCheckBox uiCheckbox = new JCheckBox(); - - uiLabel.setForeground(Color.WHITE); - uiLabel.setFont(FontManager.getRunescapeSmallFont()); - - uiOption.setBorder(BorderFactory.createEmptyBorder(3, 7, 3, 0)); - uiOption.setBackground(ColorScheme.DARKER_GRAY_COLOR); - - // Everything is enabled by default - uiCheckbox.setSelected(true); - categoryMap.put(category, true); - - // Adjust Total Banked XP check-state of the box. - uiCheckbox.addActionListener(e -> toggleCategory(category, uiCheckbox.isSelected())); - uiCheckbox.setBackground(ColorScheme.MEDIUM_GRAY_COLOR); - - uiOption.add(uiLabel, BorderLayout.WEST); - uiOption.add(uiCheckbox, BorderLayout.EAST); - - add(uiOption); - add(Box.createRigidArea(new Dimension(0, 5))); - } - } - - /** - * Used to toggle Categories of Items inside the Banked Xp tab - * @param category Category Name - * @param enabled is enabled - */ - private void toggleCategory(String category, boolean enabled) - { - categoryMap.put(category, enabled); - refreshDetailContainer(); - } - - - /** - * Creates the Maps used for easy access when calculating Banked Xp - */ - private void calculatedBankedMaps() - { - // Grab all CriticalItems for this skill - ArrayList items = CriticalItem.getBySkillName(currentSkill); - - // Loop over all Critical Items for this skill and determine how many are in the bank - for (CriticalItem item : items) - { - Integer qty = bankMap.get(item.getItemID()); - if (qty != null && qty > 0) - { - if (criticalMap.containsKey(item)) - { - criticalMap.put(item, criticalMap.get(item) + qty); - } - else - { - criticalMap.put(item, qty); - } - - // Ensure the item this is linked to maps back to us. - if (item.getLinkedItemId() != -1) - { - CriticalItem i = CriticalItem.getByItemId(item.getLinkedItemId()); - if (i != null) - { - linkedMap.put(i, item.getItemID()); - } - } - } - } - } - - /** - * Populates the detailContainer with the necessary CriticalItemPanels - */ - private void refreshDetailContainer() - { - detailContainer.removeAll(); - panelMap.clear(); - - Map map = getBankedXpBreakdown(); - for (Map.Entry entry : map.entrySet()) - { - CriticalItem item = entry.getKey(); - createItemPanel(item); - } - - detailContainer.revalidate(); - detailContainer.repaint(); - - calculateBankedXpTotal(); - } - - /** - * Creates an Individual Item Panel if it should be displayed - * @param item CriticalItem this information is tied too - */ - private void createItemPanel(CriticalItem item) - { - // Category Included? - if (categoryMap.get(item.getCategory())) - { - // Get possible activities limited to current level - List activities = Activity.getByCriticalItem(item, uiInput.getCurrentLevelInput()); - - // Check if this should count as another item. - if (item.getLinkedItemId() != -1) - { - // Ensure the linked item panel is created even if there are none in bank. - CriticalItem linked = CriticalItem.getByItemId(item.getLinkedItemId()); - if (!criticalMap.containsKey(linked)) - { - createItemPanel(linked); - } - - // One activity and rewards no xp ignore. - if (activities.size() == 1) - { - if (activities.get(0).getXp() <= 0) - { - return; - } - } - } - - // If it doesn't have any activities ignore it in the breakdown. - if (activities.size() <= 0) - { - return; - } - // Either this item has multiple activities or the single activity rewards xp, create the item panel. - - // Determine xp rate for this item - Activity a = getSelectedActivity(item); - double activityXp = a == null ? 0 : a.getXp(); - double xp = activityXp * (item.isIgnoreBonus() ? 1.0f : xpFactor); - int amount = 0; - - // If it has linked items figure out the working total. - Map links = getLinkedTotalMap(item); - for (Integer num : links.values()) - { - amount += num; - } - - // Actually create the panel displaying banked experience for this item - CriticalItemPanel panel = new CriticalItemPanel(this, itemManager, item, xp, amount, links); - - // Limit to Banked Secondaries - if (config.limitedBankedSecondaries() && a != null) - { - panel.updateAmount(limitToActivitySecondaries(a, amount), true); - panel.recalculate(); - } - panelMap.put(item, panel); - detailContainer.add(panel); - } - - } - - /** - * Return the Activity the player selected for this Item. Defaults to First activity - * @param i CriticalItem to check for - * @return selected Activity - */ - public Activity getSelectedActivity(CriticalItem i) - { - // Pull from memory if available - Activity a = activityMap.get(i); - if (a != null) - { - return a; - } - - // If not in memory select the first Activity and add to memory - List activities = Activity.getByCriticalItem(i); - if (activities.size() == 0) - { - // If you can't find an activity it means this item must link to one and give 0 xp - return null; - } - - Activity selected = activities.get(0); - activityMap.put(i, selected); - return selected; - } - - /** - * Creates a Map of Item ID and QTY for this Skill by Category. Keeps order for better UI display - * @return Map of Item ID and QTY for this Skill by Category - */ - private Map getBankedXpBreakdown() - { - Map map = new LinkedHashMap<>(); - - for (String category : CriticalItem.getSkillCategories(currentSkill)) - { - ArrayList items = CriticalItem.getItemsForSkillCategories(currentSkill, category); - for (CriticalItem item : items) - { - Integer amount = bankMap.get(item.getItemID()); - if (amount != null && amount > 0) - { - map.put(item, amount); - } - } - } - - return map; - } - - /** - * Used to select an Activity for an item - * @param i CriticalItem - * @param a Activity selected - */ - public void activitySelected(CriticalItem i, Activity a) - { - // This is triggered on every click so don't update if activity didn't actually change - Activity cur = activityMap.get(i); - if (cur == a) - { - return; - } - - // Update selected activity in map - activityMap.put(i, a); - - // If had a previous selection and this item links to another check for item prevention change. - // If there are changes adjust the Linked panel quantity as well - if (cur != null && i.getLinkedItemId() != -1) - { - if (cur.isPreventLinked() != a.isPreventLinked()) - { - CriticalItem linked = CriticalItem.getByItemId(i.getLinkedItemId()); - CriticalItemPanel l = panelMap.get(linked); - if (l != null) - { - l.updateLinkedMap(getLinkedTotalMap(linked)); - int amount = config.limitedBankedSecondaries() ? limitToActivitySecondaries(a, l.getAmount()) : l.getAmount(); - l.updateAmount(amount, false); - l.recalculate(); - } - } - } - - // Total banked experience - CriticalItemPanel p = panelMap.get(i); - if (p != null) - { - p.updateLinkedMap(getLinkedTotalMap(i)); - int amount = config.limitedBankedSecondaries() ? limitToActivitySecondaries(a, p.getAmount()) : p.getAmount(); - p.updateAmount(amount, true); - p.updateXp(a.getXp() * (i.isIgnoreBonus() ? 1.0f : xpFactor)); - } - - // Update total banked xp value based on updated panels - calculateBankedXpTotal(); - } - - private Map getLinkedTotalMap(CriticalItem i) - { - return getLinkedTotalMap(i, true); - } - - /** - * Creates a Map of CriticalItem and Qty for all items that link to the passed CriticalItem - * @param i CriticalItem to base Map off of - * @param first Since this is called recursively we want to ensure the original CriticalItem is always added - * @return Map of Linked CriticalItems and their Qty - */ - private Map getLinkedTotalMap(CriticalItem i, boolean first) - { - Map map = new LinkedHashMap<>(); - if (!categoryMap.get(i.getCategory())) - { - return map; - } - - // This item has an activity selected and its preventing linked functionality? - Activity selected = activityMap.get(i); - if (selected != null && selected.isPreventLinked()) - { - // If initial request is for this item - if (!first) - { - return map; - } - } - - // Add self to map - int amount = criticalMap.getOrDefault(i, 0); - if (amount > 0) - { - map.put(i, amount); - } - - // This item doesn't link to anything, all done. - if (linkedMap.get(i) == null) - { - return map; - } - - CriticalItem item = CriticalItem.getByItemId(linkedMap.get(i)); - if (item == null) - { - log.warn("Error finding Critical Item for Item ID: {}", linkedMap.get(i)); - return map; - } - - map.putAll(getLinkedTotalMap(item, false)); - - return map; - } - - /** - * SkillCalculatorPlugin sends the Bank Map when the bank contents change - * @param map Map of Item IDs and Quantity - */ - void updateBankMap(Map map) - { - boolean oldMapFlag = (bankMap.size() <= 0); - bankMap = map; - // Refresh entire panel if old map was empty - if (oldMapFlag) - { - CalculatorType calc = CalculatorType.getBySkill(currentSkill); - SwingUtilities.invokeLater(() -> openBanked(calc)); - return; - } - - // recalculate all data related to banked experience except for activity selections - criticalMap.clear(); - linkedMap.clear(); - calculatedBankedMaps(); - - // Update the Total XP banked and the details panel - SwingUtilities.invokeLater(this::refreshDetailContainer); - } - - /** - * Loops over all ItemPanels too sum their total xp and updates the label with the new value - */ - private void calculateBankedXpTotal() - { - double total = 0.0; - for (CriticalItemPanel p : panelMap.values()) - { - total += p.getTotal(); - } - - totalBankedXp = total; - - syncBankedXp(); - } - - /** - * Used to update the UI to reflect the new Banked XP amount - */ - private void syncBankedXp() - { - totalLabel.setText("Total Banked xp: " + XP_FORMAT_COMMA.format(totalBankedXp)); - - syncInputFields(); - - revalidate(); - repaint(); - } - - /** - * Check Bank for Activity Secondaries and Limits to possible Activity amounts - * @param a Selected Activity - * @param possible Amount of Critical Item available - * @return possible Limited to Banked Secondaries - */ - private int limitToActivitySecondaries(Activity a, int possible) - { - for (SecondaryItem i : a.getSecondaries()) - { - int banked = bankMap.getOrDefault(i.getId(), 0); - int newPossible = banked / i.getQty(); - possible = newPossible < possible ? newPossible : possible; - } - - return possible; - } - - /** - * Renders the Xp Modifier options - */ - - private void renderBonusXpOptions() - { - SkillDataBonus[] bonuses = skillData.getSkillData(currentCalc.getDataFile()).getBonuses(); - if (bonuses != null) - { - add(new JLabel("Bonus Experience:")); - for (SkillDataBonus bonus : bonuses) - { - JPanel checkboxPanel = buildCheckboxPanel(bonus); - - add(checkboxPanel); - add(Box.createRigidArea(new Dimension(0, 5))); - } - } - } - - private JPanel buildCheckboxPanel(SkillDataBonus bonus) - { - JPanel uiOption = new JPanel(new BorderLayout()); - JLabel uiLabel = new JLabel(bonus.getName()); - JCheckBox uiCheckbox = new JCheckBox(); - - uiLabel.setForeground(Color.WHITE); - uiLabel.setFont(FontManager.getRunescapeSmallFont()); - - uiOption.setBorder(BorderFactory.createEmptyBorder(3, 7, 3, 0)); - uiOption.setBackground(ColorScheme.DARKER_GRAY_COLOR); - - // Adjust XP bonus depending on check-state of the boxes. - uiCheckbox.addActionListener(event -> adjustCheckboxes(uiCheckbox, bonus)); - - uiCheckbox.setBackground(ColorScheme.MEDIUM_GRAY_COLOR); - - uiOption.add(uiLabel, BorderLayout.WEST); - uiOption.add(uiCheckbox, BorderLayout.EAST); - bonusCheckBoxes.add(uiCheckbox); - - return uiOption; - } - - private void adjustCheckboxes(JCheckBox target, SkillDataBonus bonus) - { - adjustXPBonus(0); - bonusCheckBoxes.forEach(otherSelectedCheckbox -> - { - if (otherSelectedCheckbox != target) - { - otherSelectedCheckbox.setSelected(false); - } - }); - - if (target.isSelected()) - { - adjustXPBonus(bonus.getValue()); - } - } - - private void adjustXPBonus(float value) - { - xpFactor = 1f + value; - refreshDetailContainer(); - } +/* + * Copyright (c) 2018, 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.skillcalculator; + +import java.awt.BorderLayout; +import java.awt.Color; +import java.awt.Dimension; +import java.text.DecimalFormat; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; +import javax.swing.BorderFactory; +import javax.swing.Box; +import javax.swing.BoxLayout; +import javax.swing.JCheckBox; +import javax.swing.JLabel; +import javax.swing.JPanel; +import javax.swing.SwingUtilities; +import lombok.extern.slf4j.Slf4j; +import net.runelite.api.Client; +import net.runelite.api.Experience; +import net.runelite.api.Skill; +import net.runelite.client.game.ItemManager; +import net.runelite.client.plugins.skillcalculator.banked.CriticalItem; +import net.runelite.client.plugins.skillcalculator.banked.beans.Activity; +import net.runelite.client.plugins.skillcalculator.banked.beans.SecondaryItem; +import net.runelite.client.plugins.skillcalculator.banked.ui.CriticalItemPanel; +import net.runelite.client.plugins.skillcalculator.beans.SkillDataBonus; +import net.runelite.client.ui.ColorScheme; +import net.runelite.client.ui.DynamicGridLayout; +import net.runelite.client.ui.FontManager; + +@Slf4j +public class BankedCalculator extends JPanel +{ + private static final DecimalFormat XP_FORMAT_COMMA = new DecimalFormat("#,###.#"); + + private final SkillCalculatorPanel parent; + private final Client client; + private final UICalculatorInputArea uiInput; + private final SkillCalculatorConfig config; + private final ItemManager itemManager; + + private final CacheSkillData skillData = new CacheSkillData(); + private final List bonusCheckBoxes = new ArrayList<>(); + + // UI Input data + private float xpFactor = 1.0f; + private CalculatorType currentCalc; + private Skill currentSkill; + + private double totalBankedXp = 0.0f; + private JLabel totalLabel = new JLabel(); + private JPanel detailConfigContainer; + private JPanel detailContainer; + + // Banked Experience magic + private Map bankMap = new HashMap<>(); + private Map categoryMap = new HashMap<>(); // Check if CriticalItem Category is enabled + private Map panelMap = new HashMap<>(); + private Map criticalMap = new HashMap<>(); // Quantity of CriticalItem inside bankMap + private Map activityMap = new HashMap<>(); // Selected Activity used for calculating xp + private Map linkedMap = new HashMap<>(); // ItemID of item that links to the CriticalItem + + BankedCalculator( + SkillCalculatorPanel parent, + Client client, + UICalculatorInputArea uiInput, + SkillCalculatorConfig config, + ItemManager itemManager) + { + this.parent = parent; + this.client = client; + this.uiInput = uiInput; + this.config = config; + this.itemManager = itemManager; + + setLayout(new DynamicGridLayout(0, 1, 0, 5)); + + detailContainer = new JPanel(); + detailContainer.setLayout(new BoxLayout(detailContainer, BoxLayout.Y_AXIS)); + + detailConfigContainer = new JPanel(); + detailConfigContainer.setLayout(new BoxLayout(detailConfigContainer, BoxLayout.Y_AXIS)); + } + + private void reset() + { + criticalMap.clear(); + linkedMap.clear(); + xpFactor = 1f; + } + + /** + * Update target Xp and Level inputs to match current Xp + total banked XP + */ + private void syncInputFields() + { + // Update Target XP & Level to include total banked xp + int newTotal = (int) (uiInput.getCurrentXPInput() + totalBankedXp); + uiInput.setTargetXPInput(newTotal); + uiInput.setTargetLevelInput(Experience.getLevelForXp(newTotal)); + } + + /* + * Banked Experience Logic + */ + + /** + * Shows the Banked Xp tab for the CalculatorType + * + * @param calculatorType Selected Calculator Type + */ + void openBanked(CalculatorType calculatorType) + { + // clean slate for creating the required panel + removeAll(); + reset(); + if (calculatorType.getSkill() != currentSkill) + { + // Only clear Category and Activity map on skill change. + activityMap.clear(); + categoryMap.clear(); + } + currentCalc = calculatorType; + currentSkill = calculatorType.getSkill(); + bankMap = parent.getBankMap(); + + uiInput.setCurrentLevelInput(client.getRealSkillLevel(currentSkill)); + uiInput.setCurrentXPInput(client.getSkillExperience(currentSkill)); + + // Only adds Banked Experience portion if enabled for this SkillCalc and have seen their bank + if (!calculatorType.isBankedXpFlag()) + { + add(new JLabel("
Banked Experience is not enabled for this skill.
", JLabel.CENTER)); + } + else if (bankMap.size() <= 0) + { + add(new JLabel("Please visit a bank!", JLabel.CENTER)); + } + else + { + // Prevent editing of the target level/exp since we automagically adjust them + uiInput.getUiFieldTargetLevel().setEditable(false); + uiInput.getUiFieldTargetXP().setEditable(false); + + // Now we can actually show the Banked Experience Panel + // Adds Config Options for this panel + renderBankedXpOptions(); + + renderBonusXpOptions(); + + // sprite 202 + calculatedBankedMaps(); + + // Calculate total banked experience and create detail container + refreshDetailContainer(); + + // Add back all necessary content + add(detailConfigContainer); + add(totalLabel); + add(detailContainer); + } + + revalidate(); + repaint(); + + // Update the input fields. + syncInputFields(); + } + + /** + * Add the config options for toggling each Item Category + */ + private void renderBankedXpOptions() + { + Set categories = CriticalItem.getSkillCategories(currentSkill); + if (categories == null) + { + return; + } + + add(new JLabel("Configs:")); + + for (String category : categories) + { + JPanel uiOption = new JPanel(new BorderLayout()); + JLabel uiLabel = new JLabel(category); + JCheckBox uiCheckbox = new JCheckBox(); + + uiLabel.setForeground(Color.WHITE); + uiLabel.setFont(FontManager.getRunescapeSmallFont()); + + uiOption.setBorder(BorderFactory.createEmptyBorder(3, 7, 3, 0)); + uiOption.setBackground(ColorScheme.DARKER_GRAY_COLOR); + + // Everything is enabled by default + uiCheckbox.setSelected(true); + categoryMap.put(category, true); + + // Adjust Total Banked XP check-state of the box. + uiCheckbox.addActionListener(e -> toggleCategory(category, uiCheckbox.isSelected())); + uiCheckbox.setBackground(ColorScheme.MEDIUM_GRAY_COLOR); + + uiOption.add(uiLabel, BorderLayout.WEST); + uiOption.add(uiCheckbox, BorderLayout.EAST); + + add(uiOption); + add(Box.createRigidArea(new Dimension(0, 5))); + } + } + + /** + * Used to toggle Categories of Items inside the Banked Xp tab + * + * @param category Category Name + * @param enabled is enabled + */ + private void toggleCategory(String category, boolean enabled) + { + categoryMap.put(category, enabled); + refreshDetailContainer(); + } + + + /** + * Creates the Maps used for easy access when calculating Banked Xp + */ + private void calculatedBankedMaps() + { + // Grab all CriticalItems for this skill + ArrayList items = CriticalItem.getBySkillName(currentSkill); + + // Loop over all Critical Items for this skill and determine how many are in the bank + for (CriticalItem item : items) + { + Integer qty = bankMap.get(item.getItemID()); + if (qty != null && qty > 0) + { + if (criticalMap.containsKey(item)) + { + criticalMap.put(item, criticalMap.get(item) + qty); + } + else + { + criticalMap.put(item, qty); + } + + // Ensure the item this is linked to maps back to us. + if (item.getLinkedItemId() != -1) + { + CriticalItem i = CriticalItem.getByItemId(item.getLinkedItemId()); + if (i != null) + { + linkedMap.put(i, item.getItemID()); + } + } + } + } + } + + /** + * Populates the detailContainer with the necessary CriticalItemPanels + */ + private void refreshDetailContainer() + { + detailContainer.removeAll(); + panelMap.clear(); + + Map map = getBankedXpBreakdown(); + for (Map.Entry entry : map.entrySet()) + { + CriticalItem item = entry.getKey(); + createItemPanel(item); + } + + detailContainer.revalidate(); + detailContainer.repaint(); + + calculateBankedXpTotal(); + } + + /** + * Creates an Individual Item Panel if it should be displayed + * + * @param item CriticalItem this information is tied too + */ + private void createItemPanel(CriticalItem item) + { + // Category Included? + if (categoryMap.get(item.getCategory())) + { + // Get possible activities limited to current level + List activities = Activity.getByCriticalItem(item, uiInput.getCurrentLevelInput()); + + // Check if this should count as another item. + if (item.getLinkedItemId() != -1) + { + // Ensure the linked item panel is created even if there are none in bank. + CriticalItem linked = CriticalItem.getByItemId(item.getLinkedItemId()); + if (!criticalMap.containsKey(linked)) + { + createItemPanel(linked); + } + + // One activity and rewards no xp ignore. + if (activities.size() == 1) + { + if (activities.get(0).getXp() <= 0) + { + return; + } + } + } + + // If it doesn't have any activities ignore it in the breakdown. + if (activities.size() <= 0) + { + return; + } + // Either this item has multiple activities or the single activity rewards xp, create the item panel. + + // Determine xp rate for this item + Activity a = getSelectedActivity(item); + double activityXp = a == null ? 0 : a.getXp(); + double xp = activityXp * (item.isIgnoreBonus() ? 1.0f : xpFactor); + int amount = 0; + + // If it has linked items figure out the working total. + Map links = getLinkedTotalMap(item); + for (Integer num : links.values()) + { + amount += num; + } + + // Actually create the panel displaying banked experience for this item + CriticalItemPanel panel = new CriticalItemPanel(this, itemManager, item, xp, amount, links); + + // Limit to Banked Secondaries + if (config.limitedBankedSecondaries() && a != null) + { + panel.updateAmount(limitToActivitySecondaries(a, amount), true); + panel.recalculate(); + } + panelMap.put(item, panel); + detailContainer.add(panel); + } + + } + + /** + * Return the Activity the player selected for this Item. Defaults to First activity + * + * @param i CriticalItem to check for + * @return selected Activity + */ + public Activity getSelectedActivity(CriticalItem i) + { + // Pull from memory if available + Activity a = activityMap.get(i); + if (a != null) + { + return a; + } + + // If not in memory select the first Activity and add to memory + List activities = Activity.getByCriticalItem(i); + if (activities.size() == 0) + { + // If you can't find an activity it means this item must link to one and give 0 xp + return null; + } + + Activity selected = activities.get(0); + activityMap.put(i, selected); + return selected; + } + + /** + * Creates a Map of Item ID and QTY for this Skill by Category. Keeps order for better UI display + * + * @return Map of Item ID and QTY for this Skill by Category + */ + private Map getBankedXpBreakdown() + { + Map map = new LinkedHashMap<>(); + + for (String category : CriticalItem.getSkillCategories(currentSkill)) + { + ArrayList items = CriticalItem.getItemsForSkillCategories(currentSkill, category); + for (CriticalItem item : items) + { + Integer amount = bankMap.get(item.getItemID()); + if (amount != null && amount > 0) + { + map.put(item, amount); + } + } + } + + return map; + } + + /** + * Used to select an Activity for an item + * + * @param i CriticalItem + * @param a Activity selected + */ + public void activitySelected(CriticalItem i, Activity a) + { + // This is triggered on every click so don't update if activity didn't actually change + Activity cur = activityMap.get(i); + if (cur == a) + { + return; + } + + // Update selected activity in map + activityMap.put(i, a); + + // If had a previous selection and this item links to another check for item prevention change. + // If there are changes adjust the Linked panel quantity as well + if (cur != null && i.getLinkedItemId() != -1) + { + if (cur.isPreventLinked() != a.isPreventLinked()) + { + CriticalItem linked = CriticalItem.getByItemId(i.getLinkedItemId()); + CriticalItemPanel l = panelMap.get(linked); + if (l != null) + { + l.updateLinkedMap(getLinkedTotalMap(linked)); + int amount = config.limitedBankedSecondaries() ? limitToActivitySecondaries(a, l.getAmount()) : l.getAmount(); + l.updateAmount(amount, false); + l.recalculate(); + } + } + } + + // Total banked experience + CriticalItemPanel p = panelMap.get(i); + if (p != null) + { + p.updateLinkedMap(getLinkedTotalMap(i)); + int amount = config.limitedBankedSecondaries() ? limitToActivitySecondaries(a, p.getAmount()) : p.getAmount(); + p.updateAmount(amount, true); + p.updateXp(a.getXp() * (i.isIgnoreBonus() ? 1.0f : xpFactor)); + } + + // Update total banked xp value based on updated panels + calculateBankedXpTotal(); + } + + private Map getLinkedTotalMap(CriticalItem i) + { + return getLinkedTotalMap(i, true); + } + + /** + * Creates a Map of CriticalItem and Qty for all items that link to the passed CriticalItem + * + * @param i CriticalItem to base Map off of + * @param first Since this is called recursively we want to ensure the original CriticalItem is always added + * @return Map of Linked CriticalItems and their Qty + */ + private Map getLinkedTotalMap(CriticalItem i, boolean first) + { + Map map = new LinkedHashMap<>(); + if (!categoryMap.get(i.getCategory())) + { + return map; + } + + // This item has an activity selected and its preventing linked functionality? + Activity selected = activityMap.get(i); + if (selected != null && selected.isPreventLinked()) + { + // If initial request is for this item + if (!first) + { + return map; + } + } + + // Add self to map + int amount = criticalMap.getOrDefault(i, 0); + if (amount > 0) + { + map.put(i, amount); + } + + // This item doesn't link to anything, all done. + if (linkedMap.get(i) == null) + { + return map; + } + + CriticalItem item = CriticalItem.getByItemId(linkedMap.get(i)); + if (item == null) + { + log.warn("Error finding Critical Item for Item ID: {}", linkedMap.get(i)); + return map; + } + + map.putAll(getLinkedTotalMap(item, false)); + + return map; + } + + /** + * SkillCalculatorPlugin sends the Bank Map when the bank contents change + * + * @param map Map of Item IDs and Quantity + */ + void updateBankMap(Map map) + { + boolean oldMapFlag = (bankMap.size() <= 0); + bankMap = map; + // Refresh entire panel if old map was empty + if (oldMapFlag) + { + CalculatorType calc = CalculatorType.getBySkill(currentSkill); + SwingUtilities.invokeLater(() -> openBanked(calc)); + return; + } + + // recalculate all data related to banked experience except for activity selections + criticalMap.clear(); + linkedMap.clear(); + calculatedBankedMaps(); + + // Update the Total XP banked and the details panel + SwingUtilities.invokeLater(this::refreshDetailContainer); + } + + /** + * Loops over all ItemPanels too sum their total xp and updates the label with the new value + */ + private void calculateBankedXpTotal() + { + double total = 0.0; + for (CriticalItemPanel p : panelMap.values()) + { + total += p.getTotal(); + } + + totalBankedXp = total; + + syncBankedXp(); + } + + /** + * Used to update the UI to reflect the new Banked XP amount + */ + private void syncBankedXp() + { + totalLabel.setText("Total Banked xp: " + XP_FORMAT_COMMA.format(totalBankedXp)); + + syncInputFields(); + + revalidate(); + repaint(); + } + + /** + * Check Bank for Activity Secondaries and Limits to possible Activity amounts + * + * @param a Selected Activity + * @param possible Amount of Critical Item available + * @return possible Limited to Banked Secondaries + */ + private int limitToActivitySecondaries(Activity a, int possible) + { + for (SecondaryItem i : a.getSecondaries()) + { + int banked = bankMap.getOrDefault(i.getId(), 0); + int newPossible = banked / i.getQty(); + possible = newPossible < possible ? newPossible : possible; + } + + return possible; + } + + /** + * Renders the Xp Modifier options + */ + + private void renderBonusXpOptions() + { + SkillDataBonus[] bonuses = skillData.getSkillData(currentCalc.getDataFile()).getBonuses(); + if (bonuses != null) + { + add(new JLabel("Bonus Experience:")); + for (SkillDataBonus bonus : bonuses) + { + JPanel checkboxPanel = buildCheckboxPanel(bonus); + + add(checkboxPanel); + add(Box.createRigidArea(new Dimension(0, 5))); + } + } + } + + private JPanel buildCheckboxPanel(SkillDataBonus bonus) + { + JPanel uiOption = new JPanel(new BorderLayout()); + JLabel uiLabel = new JLabel(bonus.getName()); + JCheckBox uiCheckbox = new JCheckBox(); + + uiLabel.setForeground(Color.WHITE); + uiLabel.setFont(FontManager.getRunescapeSmallFont()); + + uiOption.setBorder(BorderFactory.createEmptyBorder(3, 7, 3, 0)); + uiOption.setBackground(ColorScheme.DARKER_GRAY_COLOR); + + // Adjust XP bonus depending on check-state of the boxes. + uiCheckbox.addActionListener(event -> adjustCheckboxes(uiCheckbox, bonus)); + + uiCheckbox.setBackground(ColorScheme.MEDIUM_GRAY_COLOR); + + uiOption.add(uiLabel, BorderLayout.WEST); + uiOption.add(uiCheckbox, BorderLayout.EAST); + bonusCheckBoxes.add(uiCheckbox); + + return uiOption; + } + + private void adjustCheckboxes(JCheckBox target, SkillDataBonus bonus) + { + adjustXPBonus(0); + bonusCheckBoxes.forEach(otherSelectedCheckbox -> + { + if (otherSelectedCheckbox != target) + { + otherSelectedCheckbox.setSelected(false); + } + }); + + if (target.isSelected()) + { + adjustXPBonus(bonus.getValue()); + } + } + + private void adjustXPBonus(float value) + { + xpFactor = 1f + value; + refreshDetailContainer(); + } } \ No newline at end of file diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/skillcalculator/SkillCalculator.java b/runelite-client/src/main/java/net/runelite/client/plugins/skillcalculator/SkillCalculator.java index 35fc1b2029..ea7af8bbca 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/skillcalculator/SkillCalculator.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/skillcalculator/SkillCalculator.java @@ -1,487 +1,488 @@ -/* - * Copyright (c) 2018, Kruithne - * Copyright (c) 2018, Psikoi - * 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.skillcalculator; - -import java.awt.BorderLayout; -import java.awt.Color; -import java.awt.Dimension; -import java.awt.event.MouseAdapter; -import java.awt.event.MouseEvent; -import java.text.DecimalFormat; -import java.text.NumberFormat; -import java.util.ArrayList; -import java.util.List; -import java.util.Optional; -import javax.swing.BorderFactory; -import javax.swing.Box; -import javax.swing.JCheckBox; -import javax.swing.JLabel; -import javax.swing.JPanel; -import lombok.AccessLevel; -import lombok.Getter; -import net.runelite.api.Client; -import net.runelite.api.Experience; -import net.runelite.api.Skill; -import net.runelite.client.game.ItemManager; -import net.runelite.client.game.SpriteManager; -import net.runelite.client.plugins.skillcalculator.beans.SkillData; -import net.runelite.client.plugins.skillcalculator.beans.SkillDataBonus; -import net.runelite.client.plugins.skillcalculator.beans.SkillDataEntry; -import net.runelite.client.ui.ColorScheme; -import net.runelite.client.ui.DynamicGridLayout; -import net.runelite.client.ui.FontManager; -import net.runelite.client.ui.PluginPanel; -import net.runelite.client.ui.components.IconTextField; -import org.apache.commons.lang3.tuple.ImmutablePair; -import org.apache.commons.lang3.tuple.Pair; - -class SkillCalculator extends JPanel -{ - private static final int MAX_XP = 200_000_000; - private static final DecimalFormat XP_FORMAT = new DecimalFormat("#.#"); - - private final UICalculatorInputArea uiInput; - private final Client client; - private final SpriteManager spriteManager; - private final ItemManager itemManager; - private final List uiActionSlots = new ArrayList<>(); - private final CacheSkillData cacheSkillData = new CacheSkillData(); - @Getter(AccessLevel.PACKAGE) - private final UICombinedActionSlot combinedActionSlot; - @Getter(AccessLevel.PACKAGE) - private final ArrayList combinedActionSlots = new ArrayList<>(); - private final List bonusCheckBoxes = new ArrayList<>(); - private final IconTextField searchBar = new IconTextField(); - - private SkillData skillData; - private int currentLevel = 1; - private int currentXP = Experience.getXpForLevel(currentLevel); - private int targetLevel = currentLevel + 1; - private int targetXP = Experience.getXpForLevel(targetLevel); - private float xpFactor = 1.0f; - private float lastBonus = 0.0f; - private CalculatorType calculatorType; - - SkillCalculator(Client client, UICalculatorInputArea uiInput, SpriteManager spriteManager, ItemManager itemManager) - { - this.client = client; - this.uiInput = uiInput; - this.spriteManager = spriteManager; - this.itemManager = itemManager; - - combinedActionSlot = new UICombinedActionSlot(spriteManager); - - searchBar.setIcon(IconTextField.Icon.SEARCH); - searchBar.setPreferredSize(new Dimension(PluginPanel.PANEL_WIDTH - 20, 30)); - searchBar.setBackground(ColorScheme.DARKER_GRAY_COLOR); - searchBar.setHoverBackgroundColor(ColorScheme.DARK_GRAY_HOVER_COLOR); - searchBar.addKeyListener(e -> onSearch()); - - setLayout(new DynamicGridLayout(0, 1, 0, 5)); - - // Register listeners on the input fields and then move on to the next related text field - uiInput.getUiFieldCurrentLevel().addActionListener(e -> - { - onFieldCurrentLevelUpdated(); - uiInput.getUiFieldTargetLevel().requestFocusInWindow(); - }); - - uiInput.getUiFieldCurrentXP().addActionListener(e -> - { - onFieldCurrentXPUpdated(); - uiInput.getUiFieldTargetXP().requestFocusInWindow(); - }); - - uiInput.getUiFieldTargetLevel().addActionListener(e -> onFieldTargetLevelUpdated()); - uiInput.getUiFieldTargetXP().addActionListener(e -> onFieldTargetXPUpdated()); - } - - void openCalculator(CalculatorType calculatorType) - { - this.calculatorType = calculatorType; - - // Load the skill data. - skillData = cacheSkillData.getSkillData(calculatorType.getDataFile()); - - // Reset the XP factor, removing bonuses. - xpFactor = 1.0f; - - // Update internal skill/XP values. - updateInternalValues(); - - // BankedCalculator prevents these from being editable so just ensure they are editable. - uiInput.getUiFieldTargetLevel().setEditable(true); - uiInput.getUiFieldTargetXP().setEditable(true); - - // Remove all components (action slots) from this panel. - removeAll(); - - // Clear the search bar - searchBar.setText(null); - - // Clear the search bar - searchBar.setText(null); - - // Add in checkboxes for available skill bonuses. - renderBonusOptions(); - - // Add the combined action slot. - add(combinedActionSlot); - - // Add the search bar - add(searchBar); - - // Create action slots for the skill actions. - renderActionSlots(); - - // Update the input fields. - updateInputFields(); - } - - private void updateInternalValues() - { - updateCurrentValues(); - updateTargetValues(); - } - - private void updateCurrentValues() - { - currentXP = client.getSkillExperience(calculatorType.getSkill()); - currentLevel = Experience.getLevelForXp(currentXP); - } - private void updateTargetValues() - { - targetLevel = enforceSkillBounds(currentLevel + 1); - targetXP = Experience.getXpForLevel(targetLevel); - } - - private void updateCombinedAction() - { - int size = combinedActionSlots.size(); - if (size > 1) - { - combinedActionSlot.setTitle(size + " actions selected"); - } - else if (size == 1) - { - combinedActionSlot.setTitle("1 action selected"); - } - else - { - combinedActionSlot.setTitle("No action selected"); - combinedActionSlot.setText("Shift-click to select multiple"); - return; - } - - int actionCount = 0; - int neededXP = targetXP - currentXP; - double xp = 0; - - for (UIActionSlot slot : combinedActionSlots) - { - xp += slot.getValue(); - } - - if (neededXP > 0) - { - assert xp != 0; - actionCount = (int) Math.ceil(neededXP / xp); - } - - combinedActionSlot.setText(formatXPActionString(xp, actionCount, "exp - ")); - } - - private void clearCombinedSlots() - { - for (UIActionSlot slot : combinedActionSlots) - { - slot.setSelected(false); - } - - combinedActionSlots.clear(); - } - - private void renderBonusOptions() - { - if (skillData.getBonuses() != null) - { - List uiCheckBoxList = new ArrayList<>(); - lastBonus = 0.0f; - - for (SkillDataBonus bonus : skillData.getBonuses()) - { - Pair> combinedCheckboxPanel = buildCheckboxPanel(bonus, uiCheckBoxList); - JPanel checkboxPanel = combinedCheckboxPanel.getKey(); - uiCheckBoxList = combinedCheckboxPanel.getValue(); - - add(checkboxPanel); - } - - add(Box.createRigidArea(new Dimension(0, 5))); - } - } - - private Pair> buildCheckboxPanel(SkillDataBonus bonus, List uiCheckBoxList) - { - JPanel uiOption = new JPanel(new BorderLayout()); - JLabel uiLabel = new JLabel(bonus.getName()); - JCheckBox uiCheckbox = new JCheckBox(); - - uiLabel.setForeground(Color.WHITE); - uiLabel.setFont(FontManager.getRunescapeSmallFont()); - - uiOption.setBorder(BorderFactory.createEmptyBorder(3, 7, 3, 0)); - uiOption.setBackground(ColorScheme.DARKER_GRAY_COLOR); - - JCheckBox uiCheckBox = new JCheckBox(); - uiCheckBox.setBackground(ColorScheme.MEDIUM_GRAY_COLOR); - uiCheckBox.addActionListener(e -> - { - if (uiCheckBox.isSelected()) - { - adjustXPBonus(uiCheckBox.isSelected(), bonus.getValue()); - lastBonus = bonus.getValue(); - - for (JCheckBox checkBox : uiCheckBoxList) - { - if (checkBox != uiCheckBox) - { - checkBox.setSelected(false); - } - } - } - else if (xpFactor > 1.0) - { - xpFactor = 1.0f; - lastBonus = 0.0f; - calculate(); - } - - updateCombinedAction(); - }); - - uiCheckBoxList.add(uiCheckBox); - - uiOption.add(uiCheckBox, BorderLayout.EAST); - - uiOption.add(uiLabel, BorderLayout.WEST); - bonusCheckBoxes.add(uiCheckbox); - - return new ImmutablePair<>(uiOption, uiCheckBoxList); - } - - private void renderActionSlots() - { - // Wipe the list of references to the slot components. - uiActionSlots.clear(); - - // Create new components for the action slots. - for (SkillDataEntry action : skillData.getActions()) - { - JLabel uiIcon = new JLabel(); - - if (action.getIcon() != null) - { - itemManager.getImage(action.getIcon()).addTo(uiIcon); - } - else if (action.getSprite() != null) - { - spriteManager.addSpriteTo(uiIcon, action.getSprite(), 0); - } - - UIActionSlot slot = new UIActionSlot(action, uiIcon); - uiActionSlots.add(slot); // Keep our own reference. - add(slot); // Add component to the panel. - - slot.addMouseListener(new MouseAdapter() - { - @Override - public void mousePressed(MouseEvent e) - { - if (!e.isShiftDown()) - { - clearCombinedSlots(); - } - - if (slot.isSelected()) - { - combinedActionSlots.remove(slot); - } - else - { - combinedActionSlots.add(slot); - } - - slot.setSelected(!slot.isSelected()); - updateCombinedAction(); - } - }); - } - - // Refresh the rendering of this panel. - revalidate(); - repaint(); - } - - private void calculate() - { - for (UIActionSlot slot : uiActionSlots) - { - int actionCount = 0; - int neededXP = targetXP - currentXP; - SkillDataEntry action = slot.getAction(); - double xp = (action.isIgnoreBonus()) ? action.getXp() : action.getXp() * xpFactor; - - if (neededXP > 0) - { - actionCount = (int) Math.ceil(neededXP / xp); - } - - slot.setText("Lvl. " + action.getLevel() + " (" + formatXPActionString(xp, actionCount, "exp) - ")); - slot.setAvailable(currentLevel >= action.getLevel()); - slot.setOverlapping(action.getLevel() < targetLevel); - slot.setValue(xp); - } - - updateCombinedAction(); - } - - private String formatXPActionString(double xp, int actionCount, String expExpression) - { - return XP_FORMAT.format(xp) + expExpression + NumberFormat.getIntegerInstance().format(actionCount) + (actionCount > 1 ? " actions" : " action"); - } - - private void updateInputFields() - { - if (targetXP < currentXP) - { - targetLevel = enforceSkillBounds(currentLevel + 1); - targetXP = Experience.getXpForLevel(targetLevel); - } - - uiInput.setCurrentLevelInput(currentLevel); - uiInput.setCurrentXPInput(currentXP); - uiInput.setTargetLevelInput(targetLevel); - uiInput.setTargetXPInput(targetXP); - calculate(); - } - - private void adjustXPBonus(boolean addBonus, float value) - { - clearLastBonus(); - xpFactor += addBonus ? value : -value; - calculate(); - } - - private void clearLastBonus() - { - xpFactor -= lastBonus; - calculate(); - } - - private void onFieldCurrentLevelUpdated() - { - currentLevel = enforceSkillBounds(uiInput.getCurrentLevelInput()); - currentXP = Experience.getXpForLevel(currentLevel); - updateInputFields(); - } - - private void onFieldCurrentXPUpdated() - { - currentXP = enforceXPBounds(uiInput.getCurrentXPInput()); - currentLevel = Experience.getLevelForXp(currentXP); - updateInputFields(); - } - - private void onFieldTargetLevelUpdated() - { - targetLevel = enforceSkillBounds(uiInput.getTargetLevelInput()); - targetXP = Experience.getXpForLevel(targetLevel); - updateInputFields(); - } - - private void onFieldTargetXPUpdated() - { - targetXP = enforceXPBounds(uiInput.getTargetXPInput()); - targetLevel = Experience.getLevelForXp(targetXP); - updateInputFields(); - } - - private static int enforceSkillBounds(int input) - { - return Math.min(Experience.MAX_VIRT_LEVEL, Math.max(1, input)); - } - - private static int enforceXPBounds(int input) - { - return Math.min(MAX_XP, Math.max(0, input)); - } - - private void onSearch() - { - //only show slots that match our search text - uiActionSlots.forEach(slot -> - { - if (slotContainsText(slot, searchBar.getText())) - { - super.add(slot); - } - else - { - super.remove(slot); - } - - revalidate(); - }); - } - - private boolean slotContainsText(UIActionSlot slot, String text) - { - return slot.getAction().getName().toLowerCase().contains(text.toLowerCase()); - } - - /** - * Updates the current skill calculator (if present) - *

- * This method is invoked by the {@link SkillCalculatorPlugin} event subscriber - * when an {@link ExperienceChanged} object is posted to the event bus - */ - void updateSkillCalculator(Skill skill) - { - // If the user has selected a calculator, update its fields - Optional.ofNullable(calculatorType).ifPresent(calc -> - { - if (skill.equals(calculatorType.getSkill())) - { - // Update our model "current" values - updateCurrentValues(); - - // Update the UI to reflect our new model - updateInputFields(); - } - }); - } +/* + * Copyright (c) 2018, Kruithne + * Copyright (c) 2018, Psikoi + * 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.skillcalculator; + +import java.awt.BorderLayout; +import java.awt.Color; +import java.awt.Dimension; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import java.text.DecimalFormat; +import java.text.NumberFormat; +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; +import javax.swing.BorderFactory; +import javax.swing.Box; +import javax.swing.JCheckBox; +import javax.swing.JLabel; +import javax.swing.JPanel; +import lombok.AccessLevel; +import lombok.Getter; +import net.runelite.api.Client; +import net.runelite.api.Experience; +import net.runelite.api.Skill; +import net.runelite.client.game.ItemManager; +import net.runelite.client.game.SpriteManager; +import net.runelite.client.plugins.skillcalculator.beans.SkillData; +import net.runelite.client.plugins.skillcalculator.beans.SkillDataBonus; +import net.runelite.client.plugins.skillcalculator.beans.SkillDataEntry; +import net.runelite.client.ui.ColorScheme; +import net.runelite.client.ui.DynamicGridLayout; +import net.runelite.client.ui.FontManager; +import net.runelite.client.ui.PluginPanel; +import net.runelite.client.ui.components.IconTextField; +import org.apache.commons.lang3.tuple.ImmutablePair; +import org.apache.commons.lang3.tuple.Pair; + +class SkillCalculator extends JPanel +{ + private static final int MAX_XP = 200_000_000; + private static final DecimalFormat XP_FORMAT = new DecimalFormat("#.#"); + + private final UICalculatorInputArea uiInput; + private final Client client; + private final SpriteManager spriteManager; + private final ItemManager itemManager; + private final List uiActionSlots = new ArrayList<>(); + private final CacheSkillData cacheSkillData = new CacheSkillData(); + @Getter(AccessLevel.PACKAGE) + private final UICombinedActionSlot combinedActionSlot; + @Getter(AccessLevel.PACKAGE) + private final ArrayList combinedActionSlots = new ArrayList<>(); + private final List bonusCheckBoxes = new ArrayList<>(); + private final IconTextField searchBar = new IconTextField(); + + private SkillData skillData; + private int currentLevel = 1; + private int currentXP = Experience.getXpForLevel(currentLevel); + private int targetLevel = currentLevel + 1; + private int targetXP = Experience.getXpForLevel(targetLevel); + private float xpFactor = 1.0f; + private float lastBonus = 0.0f; + private CalculatorType calculatorType; + + SkillCalculator(Client client, UICalculatorInputArea uiInput, SpriteManager spriteManager, ItemManager itemManager) + { + this.client = client; + this.uiInput = uiInput; + this.spriteManager = spriteManager; + this.itemManager = itemManager; + + combinedActionSlot = new UICombinedActionSlot(spriteManager); + + searchBar.setIcon(IconTextField.Icon.SEARCH); + searchBar.setPreferredSize(new Dimension(PluginPanel.PANEL_WIDTH - 20, 30)); + searchBar.setBackground(ColorScheme.DARKER_GRAY_COLOR); + searchBar.setHoverBackgroundColor(ColorScheme.DARK_GRAY_HOVER_COLOR); + searchBar.addKeyListener(e -> onSearch()); + + setLayout(new DynamicGridLayout(0, 1, 0, 5)); + + // Register listeners on the input fields and then move on to the next related text field + uiInput.getUiFieldCurrentLevel().addActionListener(e -> + { + onFieldCurrentLevelUpdated(); + uiInput.getUiFieldTargetLevel().requestFocusInWindow(); + }); + + uiInput.getUiFieldCurrentXP().addActionListener(e -> + { + onFieldCurrentXPUpdated(); + uiInput.getUiFieldTargetXP().requestFocusInWindow(); + }); + + uiInput.getUiFieldTargetLevel().addActionListener(e -> onFieldTargetLevelUpdated()); + uiInput.getUiFieldTargetXP().addActionListener(e -> onFieldTargetXPUpdated()); + } + + void openCalculator(CalculatorType calculatorType) + { + this.calculatorType = calculatorType; + + // Load the skill data. + skillData = cacheSkillData.getSkillData(calculatorType.getDataFile()); + + // Reset the XP factor, removing bonuses. + xpFactor = 1.0f; + + // Update internal skill/XP values. + updateInternalValues(); + + // BankedCalculator prevents these from being editable so just ensure they are editable. + uiInput.getUiFieldTargetLevel().setEditable(true); + uiInput.getUiFieldTargetXP().setEditable(true); + + // Remove all components (action slots) from this panel. + removeAll(); + + // Clear the search bar + searchBar.setText(null); + + // Clear the search bar + searchBar.setText(null); + + // Add in checkboxes for available skill bonuses. + renderBonusOptions(); + + // Add the combined action slot. + add(combinedActionSlot); + + // Add the search bar + add(searchBar); + + // Create action slots for the skill actions. + renderActionSlots(); + + // Update the input fields. + updateInputFields(); + } + + private void updateInternalValues() + { + updateCurrentValues(); + updateTargetValues(); + } + + private void updateCurrentValues() + { + currentXP = client.getSkillExperience(calculatorType.getSkill()); + currentLevel = Experience.getLevelForXp(currentXP); + } + + private void updateTargetValues() + { + targetLevel = enforceSkillBounds(currentLevel + 1); + targetXP = Experience.getXpForLevel(targetLevel); + } + + private void updateCombinedAction() + { + int size = combinedActionSlots.size(); + if (size > 1) + { + combinedActionSlot.setTitle(size + " actions selected"); + } + else if (size == 1) + { + combinedActionSlot.setTitle("1 action selected"); + } + else + { + combinedActionSlot.setTitle("No action selected"); + combinedActionSlot.setText("Shift-click to select multiple"); + return; + } + + int actionCount = 0; + int neededXP = targetXP - currentXP; + double xp = 0; + + for (UIActionSlot slot : combinedActionSlots) + { + xp += slot.getValue(); + } + + if (neededXP > 0) + { + assert xp != 0; + actionCount = (int) Math.ceil(neededXP / xp); + } + + combinedActionSlot.setText(formatXPActionString(xp, actionCount, "exp - ")); + } + + private void clearCombinedSlots() + { + for (UIActionSlot slot : combinedActionSlots) + { + slot.setSelected(false); + } + + combinedActionSlots.clear(); + } + + private void renderBonusOptions() + { + if (skillData.getBonuses() != null) + { + List uiCheckBoxList = new ArrayList<>(); + lastBonus = 0.0f; + + for (SkillDataBonus bonus : skillData.getBonuses()) + { + Pair> combinedCheckboxPanel = buildCheckboxPanel(bonus, uiCheckBoxList); + JPanel checkboxPanel = combinedCheckboxPanel.getKey(); + uiCheckBoxList = combinedCheckboxPanel.getValue(); + + add(checkboxPanel); + } + + add(Box.createRigidArea(new Dimension(0, 5))); + } + } + + private Pair> buildCheckboxPanel(SkillDataBonus bonus, List uiCheckBoxList) + { + JPanel uiOption = new JPanel(new BorderLayout()); + JLabel uiLabel = new JLabel(bonus.getName()); + JCheckBox uiCheckbox = new JCheckBox(); + + uiLabel.setForeground(Color.WHITE); + uiLabel.setFont(FontManager.getRunescapeSmallFont()); + + uiOption.setBorder(BorderFactory.createEmptyBorder(3, 7, 3, 0)); + uiOption.setBackground(ColorScheme.DARKER_GRAY_COLOR); + + JCheckBox uiCheckBox = new JCheckBox(); + uiCheckBox.setBackground(ColorScheme.MEDIUM_GRAY_COLOR); + uiCheckBox.addActionListener(e -> + { + if (uiCheckBox.isSelected()) + { + adjustXPBonus(uiCheckBox.isSelected(), bonus.getValue()); + lastBonus = bonus.getValue(); + + for (JCheckBox checkBox : uiCheckBoxList) + { + if (checkBox != uiCheckBox) + { + checkBox.setSelected(false); + } + } + } + else if (xpFactor > 1.0) + { + xpFactor = 1.0f; + lastBonus = 0.0f; + calculate(); + } + + updateCombinedAction(); + }); + + uiCheckBoxList.add(uiCheckBox); + + uiOption.add(uiCheckBox, BorderLayout.EAST); + + uiOption.add(uiLabel, BorderLayout.WEST); + bonusCheckBoxes.add(uiCheckbox); + + return new ImmutablePair<>(uiOption, uiCheckBoxList); + } + + private void renderActionSlots() + { + // Wipe the list of references to the slot components. + uiActionSlots.clear(); + + // Create new components for the action slots. + for (SkillDataEntry action : skillData.getActions()) + { + JLabel uiIcon = new JLabel(); + + if (action.getIcon() != null) + { + itemManager.getImage(action.getIcon()).addTo(uiIcon); + } + else if (action.getSprite() != null) + { + spriteManager.addSpriteTo(uiIcon, action.getSprite(), 0); + } + + UIActionSlot slot = new UIActionSlot(action, uiIcon); + uiActionSlots.add(slot); // Keep our own reference. + add(slot); // Add component to the panel. + + slot.addMouseListener(new MouseAdapter() + { + @Override + public void mousePressed(MouseEvent e) + { + if (!e.isShiftDown()) + { + clearCombinedSlots(); + } + + if (slot.isSelected()) + { + combinedActionSlots.remove(slot); + } + else + { + combinedActionSlots.add(slot); + } + + slot.setSelected(!slot.isSelected()); + updateCombinedAction(); + } + }); + } + + // Refresh the rendering of this panel. + revalidate(); + repaint(); + } + + private void calculate() + { + for (UIActionSlot slot : uiActionSlots) + { + int actionCount = 0; + int neededXP = targetXP - currentXP; + SkillDataEntry action = slot.getAction(); + double xp = (action.isIgnoreBonus()) ? action.getXp() : action.getXp() * xpFactor; + + if (neededXP > 0) + { + actionCount = (int) Math.ceil(neededXP / xp); + } + + slot.setText("Lvl. " + action.getLevel() + " (" + formatXPActionString(xp, actionCount, "exp) - ")); + slot.setAvailable(currentLevel >= action.getLevel()); + slot.setOverlapping(action.getLevel() < targetLevel); + slot.setValue(xp); + } + + updateCombinedAction(); + } + + private String formatXPActionString(double xp, int actionCount, String expExpression) + { + return XP_FORMAT.format(xp) + expExpression + NumberFormat.getIntegerInstance().format(actionCount) + (actionCount > 1 ? " actions" : " action"); + } + + private void updateInputFields() + { + if (targetXP < currentXP) + { + targetLevel = enforceSkillBounds(currentLevel + 1); + targetXP = Experience.getXpForLevel(targetLevel); + } + + uiInput.setCurrentLevelInput(currentLevel); + uiInput.setCurrentXPInput(currentXP); + uiInput.setTargetLevelInput(targetLevel); + uiInput.setTargetXPInput(targetXP); + calculate(); + } + + private void adjustXPBonus(boolean addBonus, float value) + { + clearLastBonus(); + xpFactor += addBonus ? value : -value; + calculate(); + } + + private void clearLastBonus() + { + xpFactor -= lastBonus; + calculate(); + } + + private void onFieldCurrentLevelUpdated() + { + currentLevel = enforceSkillBounds(uiInput.getCurrentLevelInput()); + currentXP = Experience.getXpForLevel(currentLevel); + updateInputFields(); + } + + private void onFieldCurrentXPUpdated() + { + currentXP = enforceXPBounds(uiInput.getCurrentXPInput()); + currentLevel = Experience.getLevelForXp(currentXP); + updateInputFields(); + } + + private void onFieldTargetLevelUpdated() + { + targetLevel = enforceSkillBounds(uiInput.getTargetLevelInput()); + targetXP = Experience.getXpForLevel(targetLevel); + updateInputFields(); + } + + private void onFieldTargetXPUpdated() + { + targetXP = enforceXPBounds(uiInput.getTargetXPInput()); + targetLevel = Experience.getLevelForXp(targetXP); + updateInputFields(); + } + + private static int enforceSkillBounds(int input) + { + return Math.min(Experience.MAX_VIRT_LEVEL, Math.max(1, input)); + } + + private static int enforceXPBounds(int input) + { + return Math.min(MAX_XP, Math.max(0, input)); + } + + private void onSearch() + { + //only show slots that match our search text + uiActionSlots.forEach(slot -> + { + if (slotContainsText(slot, searchBar.getText())) + { + super.add(slot); + } + else + { + super.remove(slot); + } + + revalidate(); + }); + } + + private boolean slotContainsText(UIActionSlot slot, String text) + { + return slot.getAction().getName().toLowerCase().contains(text.toLowerCase()); + } + + /** + * Updates the current skill calculator (if present) + *

+ * This method is invoked by the {@link SkillCalculatorPlugin} event subscriber + * when an {@link ExperienceChanged} object is posted to the event bus + */ + void updateSkillCalculator(Skill skill) + { + // If the user has selected a calculator, update its fields + Optional.ofNullable(calculatorType).ifPresent(calc -> + { + if (skill.equals(calculatorType.getSkill())) + { + // Update our model "current" values + updateCurrentValues(); + + // Update the UI to reflect our new model + updateInputFields(); + } + }); + } } \ No newline at end of file diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/skillcalculator/SkillCalculatorConfig.java b/runelite-client/src/main/java/net/runelite/client/plugins/skillcalculator/SkillCalculatorConfig.java index ce8a4c2ddd..0a1d8e5ce9 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/skillcalculator/SkillCalculatorConfig.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/skillcalculator/SkillCalculatorConfig.java @@ -1,55 +1,55 @@ -/* - * Copyright (c) 2018, 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.skillcalculator; - -import net.runelite.client.config.Config; -import net.runelite.client.config.ConfigGroup; -import net.runelite.client.config.ConfigItem; - -@ConfigGroup("skillCalculator") -public interface SkillCalculatorConfig extends Config -{ - @ConfigItem( - keyName = "showBankedXp", - name = "Show Banked xp Tab", - description = "Shows the Banked xp tab inside the Calculator Panel", - position = 0 - ) - default boolean showBankedXp() - { - return true; - } - - @ConfigItem( - keyName = "limitedBankedSecondaries", - name = "Limit Banked xp to Secondaries", - description = "Limits the Banked xp shown based on secondaries banked as well", - position = 1 - ) - default boolean limitedBankedSecondaries() - { - return false; - } +/* + * Copyright (c) 2018, 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.skillcalculator; + +import net.runelite.client.config.Config; +import net.runelite.client.config.ConfigGroup; +import net.runelite.client.config.ConfigItem; + +@ConfigGroup("skillCalculator") +public interface SkillCalculatorConfig extends Config +{ + @ConfigItem( + keyName = "showBankedXp", + name = "Show Banked xp Tab", + description = "Shows the Banked xp tab inside the Calculator Panel", + position = 0 + ) + default boolean showBankedXp() + { + return true; + } + + @ConfigItem( + keyName = "limitedBankedSecondaries", + name = "Limit Banked xp to Secondaries", + description = "Limits the Banked xp shown based on secondaries banked as well", + position = 1 + ) + default boolean limitedBankedSecondaries() + { + return false; + } } \ No newline at end of file diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/skillcalculator/SkillCalculatorPanel.java b/runelite-client/src/main/java/net/runelite/client/plugins/skillcalculator/SkillCalculatorPanel.java index 30ab0b8486..939bd70b74 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/skillcalculator/SkillCalculatorPanel.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/skillcalculator/SkillCalculatorPanel.java @@ -1,243 +1,243 @@ -/* - * Copyright (c) 2018, Kruithne - * Copyright (c) 2018, Psikoi - * Copyright (c) 2018, 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.skillcalculator; - -import java.awt.GridBagConstraints; -import java.awt.GridBagLayout; -import java.awt.GridLayout; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.Map; -import java.util.Objects; -import javax.swing.ImageIcon; -import javax.swing.JScrollPane; -import javax.swing.SwingUtilities; -import javax.swing.border.EmptyBorder; -import lombok.Getter; -import lombok.extern.slf4j.Slf4j; -import net.runelite.api.Client; -import net.runelite.api.Skill; -import net.runelite.client.game.ItemManager; -import net.runelite.client.game.SkillIconManager; -import net.runelite.client.game.SpriteManager; -import net.runelite.client.ui.ColorScheme; -import net.runelite.client.ui.PluginPanel; -import net.runelite.client.ui.components.materialtabs.MaterialTab; -import net.runelite.client.ui.components.materialtabs.MaterialTabGroup; - -@Slf4j -class SkillCalculatorPanel extends PluginPanel -{ - private final SkillCalculator uiCalculator; - private final SkillIconManager iconManager; - private final SkillCalculatorConfig config; - private final BankedCalculator bankedCalculator; - - private CalculatorType currentCalc; - private final MaterialTabGroup skillGroup; - private final MaterialTabGroup tabGroup; - private String currentTab; - private ArrayList tabs = new ArrayList<>(); - @Getter - private Map bankMap = new HashMap<>(); - private GridBagConstraints c; - - SkillCalculatorPanel(SkillIconManager iconManager, Client client, SkillCalculatorConfig config, SpriteManager spriteManager, ItemManager itemManager) - { - super(); - getScrollPane().setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS); - - this.iconManager = iconManager; - this.config = config; - - setBorder(new EmptyBorder(10, 10, 10, 10)); - setLayout(new GridBagLayout()); - - c = new GridBagConstraints(); - c.fill = GridBagConstraints.HORIZONTAL; - c.weightx = 1; - c.gridx = 0; - c.gridy = 0; - - skillGroup = new MaterialTabGroup(); - skillGroup.setLayout(new GridLayout(0, 6, 7, 7)); - - addCalculatorButtons(); - - final UICalculatorInputArea uiInput = new UICalculatorInputArea(); - uiInput.setBorder(new EmptyBorder(15, 0, 15, 0)); - uiInput.setBackground(ColorScheme.DARK_GRAY_COLOR); - uiCalculator = new SkillCalculator(client, uiInput, spriteManager, itemManager); - - bankedCalculator = new BankedCalculator(this, client, uiInput, config, itemManager); - - tabGroup = new MaterialTabGroup(); - tabGroup.setBorder(new EmptyBorder(0, 0, 10, 0)); - - addTabButtons(); - - add(skillGroup, c); - c.gridy++; - - add(uiInput, c); - c.gridy++; - - add(tabGroup, c); - c.gridy++; - - add(uiCalculator, c); - } - - private void addCalculatorButtons() - { - for (CalculatorType calculatorType : CalculatorType.values()) - { - ImageIcon icon = new ImageIcon(iconManager.getSkillImage(calculatorType.getSkill(), true)); - MaterialTab tab = new MaterialTab(icon, skillGroup, null); - tab.setOnSelectEvent(() -> - { - if (currentCalc == calculatorType) - { - return true; - } - currentCalc = calculatorType; - selectedTab(currentTab, true); - return true; - }); - - skillGroup.addTab(tab); - } - } - - private void addTabButtons() - { - tabGroup.removeAll(); - tabs.clear(); - - tabs.add("Calculator"); - if (config.showBankedXp()) - { - tabs.add("Banked Xp"); - } - // Only show if both options are visible - tabGroup.setVisible(tabs.size() > 1); - - tabGroup.setLayout(new GridLayout(0, tabs.size(), 7, 7)); - - for (String s : tabs) - { - MaterialTab matTab = new MaterialTab(s, tabGroup, null); - - matTab.setHorizontalAlignment(SwingUtilities.CENTER); - - // Ensure Background is applied - matTab.setOpaque(true); - matTab.setBackground(ColorScheme.DARKER_GRAY_COLOR); - - // When Clicked - matTab.setOnSelectEvent(() -> - { - selectedTab(s, false); - return true; - }); - - tabGroup.addTab(matTab); - } - - MaterialTab selected = tabGroup.getTab(0); - if (tabs.contains(currentTab)) - { - selected = tabGroup.getTab(tabs.indexOf(currentTab)); - } - - tabGroup.select(selected); - currentTab = selected.getText(); - } - - private void selectedTab(String s, boolean force) - { - // Do not refresh the panel if they clicked the same tab, unless they selected a new skill - if (Objects.equals(currentTab, s) && !force) - { - return; - } - - currentTab = s; - - // Only open a panel if a skill is selected - if (currentCalc == null) - { - return; - } - - switch (s) - { - case "Calculator": - remove(bankedCalculator); - add(uiCalculator, c); - uiCalculator.openCalculator(currentCalc); - break; - case "Banked Xp": - remove(uiCalculator); - add(bankedCalculator, c); - bankedCalculator.openBanked(currentCalc); - break; - } - - this.revalidate(); - this.repaint(); - } - - // Refresh entire panel - void refreshPanel() - { - // Recreate Tabs (in case of Config change) and selects the first tab - addTabButtons(); - - // Ensure reload - selectedTab(currentTab, true); - - this.revalidate(); - this.repaint(); - } - - // Wrapper function for updating SkillCalculator's bankMap - void updateBankMap(Map bank) - { - bankMap = bank; - if (currentCalc != null & currentTab.equals("Banked Xp")) - { - bankedCalculator.updateBankMap(bankMap); - } - } - - void updateSkillCalculator(Skill skill) - { - uiCalculator.updateSkillCalculator(skill); - } +/* + * Copyright (c) 2018, Kruithne + * Copyright (c) 2018, Psikoi + * Copyright (c) 2018, 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.skillcalculator; + +import java.awt.GridBagConstraints; +import java.awt.GridBagLayout; +import java.awt.GridLayout; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; +import javax.swing.ImageIcon; +import javax.swing.JScrollPane; +import javax.swing.SwingUtilities; +import javax.swing.border.EmptyBorder; +import lombok.Getter; +import lombok.extern.slf4j.Slf4j; +import net.runelite.api.Client; +import net.runelite.api.Skill; +import net.runelite.client.game.ItemManager; +import net.runelite.client.game.SkillIconManager; +import net.runelite.client.game.SpriteManager; +import net.runelite.client.ui.ColorScheme; +import net.runelite.client.ui.PluginPanel; +import net.runelite.client.ui.components.materialtabs.MaterialTab; +import net.runelite.client.ui.components.materialtabs.MaterialTabGroup; + +@Slf4j +class SkillCalculatorPanel extends PluginPanel +{ + private final SkillCalculator uiCalculator; + private final SkillIconManager iconManager; + private final SkillCalculatorConfig config; + private final BankedCalculator bankedCalculator; + + private CalculatorType currentCalc; + private final MaterialTabGroup skillGroup; + private final MaterialTabGroup tabGroup; + private String currentTab; + private ArrayList tabs = new ArrayList<>(); + @Getter + private Map bankMap = new HashMap<>(); + private GridBagConstraints c; + + SkillCalculatorPanel(SkillIconManager iconManager, Client client, SkillCalculatorConfig config, SpriteManager spriteManager, ItemManager itemManager) + { + super(); + getScrollPane().setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS); + + this.iconManager = iconManager; + this.config = config; + + setBorder(new EmptyBorder(10, 10, 10, 10)); + setLayout(new GridBagLayout()); + + c = new GridBagConstraints(); + c.fill = GridBagConstraints.HORIZONTAL; + c.weightx = 1; + c.gridx = 0; + c.gridy = 0; + + skillGroup = new MaterialTabGroup(); + skillGroup.setLayout(new GridLayout(0, 6, 7, 7)); + + addCalculatorButtons(); + + final UICalculatorInputArea uiInput = new UICalculatorInputArea(); + uiInput.setBorder(new EmptyBorder(15, 0, 15, 0)); + uiInput.setBackground(ColorScheme.DARK_GRAY_COLOR); + uiCalculator = new SkillCalculator(client, uiInput, spriteManager, itemManager); + + bankedCalculator = new BankedCalculator(this, client, uiInput, config, itemManager); + + tabGroup = new MaterialTabGroup(); + tabGroup.setBorder(new EmptyBorder(0, 0, 10, 0)); + + addTabButtons(); + + add(skillGroup, c); + c.gridy++; + + add(uiInput, c); + c.gridy++; + + add(tabGroup, c); + c.gridy++; + + add(uiCalculator, c); + } + + private void addCalculatorButtons() + { + for (CalculatorType calculatorType : CalculatorType.values()) + { + ImageIcon icon = new ImageIcon(iconManager.getSkillImage(calculatorType.getSkill(), true)); + MaterialTab tab = new MaterialTab(icon, skillGroup, null); + tab.setOnSelectEvent(() -> + { + if (currentCalc == calculatorType) + { + return true; + } + currentCalc = calculatorType; + selectedTab(currentTab, true); + return true; + }); + + skillGroup.addTab(tab); + } + } + + private void addTabButtons() + { + tabGroup.removeAll(); + tabs.clear(); + + tabs.add("Calculator"); + if (config.showBankedXp()) + { + tabs.add("Banked Xp"); + } + // Only show if both options are visible + tabGroup.setVisible(tabs.size() > 1); + + tabGroup.setLayout(new GridLayout(0, tabs.size(), 7, 7)); + + for (String s : tabs) + { + MaterialTab matTab = new MaterialTab(s, tabGroup, null); + + matTab.setHorizontalAlignment(SwingUtilities.CENTER); + + // Ensure Background is applied + matTab.setOpaque(true); + matTab.setBackground(ColorScheme.DARKER_GRAY_COLOR); + + // When Clicked + matTab.setOnSelectEvent(() -> + { + selectedTab(s, false); + return true; + }); + + tabGroup.addTab(matTab); + } + + MaterialTab selected = tabGroup.getTab(0); + if (tabs.contains(currentTab)) + { + selected = tabGroup.getTab(tabs.indexOf(currentTab)); + } + + tabGroup.select(selected); + currentTab = selected.getText(); + } + + private void selectedTab(String s, boolean force) + { + // Do not refresh the panel if they clicked the same tab, unless they selected a new skill + if (Objects.equals(currentTab, s) && !force) + { + return; + } + + currentTab = s; + + // Only open a panel if a skill is selected + if (currentCalc == null) + { + return; + } + + switch (s) + { + case "Calculator": + remove(bankedCalculator); + add(uiCalculator, c); + uiCalculator.openCalculator(currentCalc); + break; + case "Banked Xp": + remove(uiCalculator); + add(bankedCalculator, c); + bankedCalculator.openBanked(currentCalc); + break; + } + + this.revalidate(); + this.repaint(); + } + + // Refresh entire panel + void refreshPanel() + { + // Recreate Tabs (in case of Config change) and selects the first tab + addTabButtons(); + + // Ensure reload + selectedTab(currentTab, true); + + this.revalidate(); + this.repaint(); + } + + // Wrapper function for updating SkillCalculator's bankMap + void updateBankMap(Map bank) + { + bankMap = bank; + if (currentCalc != null & currentTab.equals("Banked Xp")) + { + bankedCalculator.updateBankMap(bankMap); + } + } + + void updateSkillCalculator(Skill skill) + { + uiCalculator.updateSkillCalculator(skill); + } } \ No newline at end of file diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/skillcalculator/banked/CriticalItem.java b/runelite-client/src/main/java/net/runelite/client/plugins/skillcalculator/banked/CriticalItem.java index 9cc6633746..8e5e0334c3 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/skillcalculator/banked/CriticalItem.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/skillcalculator/banked/CriticalItem.java @@ -1,408 +1,417 @@ -/* - * Copyright (c) 2018, 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.skillcalculator.banked; - -import lombok.Getter; -import net.runelite.api.ItemComposition; -import net.runelite.api.ItemID; -import net.runelite.api.Skill; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Map; -import java.util.Set; -import net.runelite.client.game.ItemManager; - -public enum CriticalItem -{ - /** - * Construction Items - */ - // Planks - PLANK(ItemID.PLANK, "Planks", Skill.CONSTRUCTION), - OAK_PLANK(ItemID.OAK_PLANK, "Planks", Skill.CONSTRUCTION), - TEAK_PLANK(ItemID.TEAK_PLANK, "Planks", Skill.CONSTRUCTION), - MAHOGANY_PLANK(ItemID.MAHOGANY_PLANK, "Planks", Skill.CONSTRUCTION), - // Logs - LOGS(ItemID.LOGS, "Logs", Skill.CONSTRUCTION, ItemID.PLANK), - OAK_LOGS(ItemID.OAK_LOGS, "Logs", Skill.CONSTRUCTION, ItemID.OAK_PLANK), - TEAK_LOGS(ItemID.TEAK_LOGS, "Logs", Skill.CONSTRUCTION, ItemID.TEAK_PLANK), - MAHOGANY_LOGS(ItemID.MAHOGANY_LOGS, "Logs", Skill.CONSTRUCTION, ItemID.MAHOGANY_PLANK), - - /** - * Herblore Items - */ - // Grimy Herbs - GRIMY_GUAM_LEAF(ItemID.GRIMY_GUAM_LEAF, "Grimy Herbs", Skill.HERBLORE, ItemID.GUAM_LEAF), - GRIMY_MARRENTILL(ItemID.GRIMY_MARRENTILL, "Grimy Herbs", Skill.HERBLORE, ItemID.MARRENTILL), - GRIMY_TARROMIN(ItemID.GRIMY_TARROMIN, "Grimy Herbs", Skill.HERBLORE, ItemID.TARROMIN), - GRIMY_HARRALANDER(ItemID.GRIMY_HARRALANDER, "Grimy Herbs", Skill.HERBLORE, ItemID.HARRALANDER), - GRIMY_RANARR_WEED(ItemID.GRIMY_RANARR_WEED, "Grimy Herbs", Skill.HERBLORE, ItemID.RANARR_WEED), - GRIMY_TOADFLAX(ItemID.GRIMY_TOADFLAX, "Grimy Herbs", Skill.HERBLORE, ItemID.TOADFLAX), - GRIMY_IRIT_LEAF(ItemID.GRIMY_IRIT_LEAF, "Grimy Herbs", Skill.HERBLORE, ItemID.IRIT_LEAF), - GRIMY_AVANTOE(ItemID.GRIMY_AVANTOE, "Grimy Herbs", Skill.HERBLORE, ItemID.AVANTOE), - GRIMY_KWUARM(ItemID.GRIMY_KWUARM, "Grimy Herbs", Skill.HERBLORE, ItemID.KWUARM), - GRIMY_SNAPDRAGON(ItemID.GRIMY_SNAPDRAGON, "Grimy Herbs", Skill.HERBLORE, ItemID.SNAPDRAGON), - GRIMY_CADANTINE(ItemID.GRIMY_CADANTINE, "Grimy Herbs", Skill.HERBLORE, ItemID.CADANTINE), - GRIMY_LANTADYME(ItemID.GRIMY_LANTADYME, "Grimy Herbs", Skill.HERBLORE, ItemID.LANTADYME), - GRIMY_DWARF_WEED(ItemID.GRIMY_DWARF_WEED, "Grimy Herbs", Skill.HERBLORE, ItemID.DWARF_WEED), - GRIMY_TORSTOL(ItemID.GRIMY_TORSTOL, "Grimy Herbs", Skill.HERBLORE, ItemID.TORSTOL), - // Clean Herbs - GUAM_LEAF(ItemID.GUAM_LEAF, "Cleaned Herbs", Skill.HERBLORE, ItemID.GUAM_POTION_UNF), - MARRENTILL(ItemID.MARRENTILL, "Cleaned Herbs", Skill.HERBLORE, ItemID.MARRENTILL_POTION_UNF), - TARROMIN(ItemID.TARROMIN, "Cleaned Herbs", Skill.HERBLORE, ItemID.TARROMIN_POTION_UNF), - HARRALANDER(ItemID.HARRALANDER, "Cleaned Herbs", Skill.HERBLORE, ItemID.HARRALANDER_POTION_UNF), - RANARR_WEED(ItemID.RANARR_WEED, "Cleaned Herbs", Skill.HERBLORE, ItemID.RANARR_POTION_UNF), - TOADFLAX(ItemID.TOADFLAX, "Cleaned Herbs", Skill.HERBLORE, ItemID.TOADFLAX_POTION_UNF), - IRIT_LEAF(ItemID.IRIT_LEAF, "Cleaned Herbs", Skill.HERBLORE, ItemID.IRIT_POTION_UNF), - AVANTOE(ItemID.AVANTOE, "Cleaned Herbs", Skill.HERBLORE, ItemID.AVANTOE_POTION_UNF), - KWUARM(ItemID.KWUARM, "Cleaned Herbs", Skill.HERBLORE, ItemID.KWUARM_POTION_UNF), - SNAPDRAGON(ItemID.SNAPDRAGON, "Cleaned Herbs", Skill.HERBLORE, ItemID.SNAPDRAGON_POTION_UNF), - CADANTINE(ItemID.CADANTINE, "Cleaned Herbs", Skill.HERBLORE, ItemID.CADANTINE_POTION_UNF), - LANTADYME(ItemID.LANTADYME, "Cleaned Herbs", Skill.HERBLORE, ItemID.LANTADYME_POTION_UNF), - DWARF_WEED(ItemID.DWARF_WEED, "Cleaned Herbs", Skill.HERBLORE, ItemID.DWARF_WEED_POTION_UNF), - TORSTOL(ItemID.TORSTOL, "Cleaned Herbs", Skill.HERBLORE, ItemID.TORSTOL_POTION_UNF), - // Unfinished Potions - GUAM_LEAF_POTION_UNF(ItemID.GUAM_POTION_UNF, "Unfinished Potions", Skill.HERBLORE), - MARRENTILL_POTION_UNF(ItemID.MARRENTILL_POTION_UNF, "Unfinished Potions", Skill.HERBLORE), - TARROMIN_POTION_UNF(ItemID.TARROMIN_POTION_UNF, "Unfinished Potions", Skill.HERBLORE), - HARRALANDER_POTION_UNF(ItemID.HARRALANDER_POTION_UNF, "Unfinished Potions", Skill.HERBLORE), - RANARR_POTION_UNF(ItemID.RANARR_POTION_UNF, "Unfinished Potions", Skill.HERBLORE), - TOADFLAX_POTION_UNF(ItemID.TOADFLAX_POTION_UNF, "Unfinished Potions", Skill.HERBLORE), - IRIT_POTION_UNF(ItemID.IRIT_POTION_UNF, "Unfinished Potions", Skill.HERBLORE), - AVANTOE_POTION_UNF(ItemID.AVANTOE_POTION_UNF, "Unfinished Potions", Skill.HERBLORE), - KWUARM_POTION_UNF(ItemID.KWUARM_POTION_UNF, "Unfinished Potions", Skill.HERBLORE), - SNAPDRAGON_POTION_UNF(ItemID.SNAPDRAGON_POTION_UNF, "Unfinished Potions", Skill.HERBLORE), - CADANTINE_POTION_UNF(ItemID.CADANTINE_POTION_UNF, "Unfinished Potions", Skill.HERBLORE), - LANTADYME_POTION_UNF(ItemID.LANTADYME_POTION_UNF, "Unfinished Potions", Skill.HERBLORE), - DWARF_WEED_POTION_UNF(ItemID.DWARF_WEED_POTION_UNF, "Unfinished Potions", Skill.HERBLORE), - TORSTOL_POTION_UNF(ItemID.TORSTOL_POTION_UNF, "Unfinished Potions", Skill.HERBLORE), - - /** - * Prayer Items - */ - // Bones - BONES(ItemID.BONES, "Bones", Skill.PRAYER), - WOLF_BONES(ItemID.WOLF_BONES, "Bones", Skill.PRAYER), - BURNT_BONES(ItemID.BURNT_BONES, "Bones", Skill.PRAYER), - MONKEY_BONES(ItemID.MONKEY_BONES, "Bones", Skill.PRAYER), - BAT_BONES(ItemID.BAT_BONES, "Bones", Skill.PRAYER), - JOGRE_BONES(ItemID.JOGRE_BONES, "Bones", Skill.PRAYER), - BIG_BONES(ItemID.BIG_BONES, "Bones", Skill.PRAYER), - ZOGRE_BONES(ItemID.ZOGRE_BONES, "Bones", Skill.PRAYER), - SHAIKAHAN_BONES(ItemID.SHAIKAHAN_BONES, "Bones", Skill.PRAYER), - BABYDRAGON_BONES(ItemID.BABYDRAGON_BONES, "Bones", Skill.PRAYER), - WYVERN_BONES(ItemID.WYVERN_BONES, "Bones", Skill.PRAYER), - DRAGON_BONES(ItemID.DRAGON_BONES, "Bones", Skill.PRAYER), - FAYRG_BONES(ItemID.FAYRG_BONES, "Bones", Skill.PRAYER), - LAVA_DRAGON_BONES(ItemID.LAVA_DRAGON_BONES, "Bones", Skill.PRAYER), - RAURG_BONES(ItemID.RAURG_BONES, "Bones", Skill.PRAYER), - DAGANNOTH_BONES(ItemID.DAGANNOTH_BONES, "Bones", Skill.PRAYER), - OURG_BONES(ItemID.OURG_BONES, "Bones", Skill.PRAYER), - SUPERIOR_DRAGON_BONES(ItemID.SUPERIOR_DRAGON_BONES, "Bones", Skill.PRAYER), - // Shade Remains (Pyre Logs) - LOAR_REMAINS(ItemID.LOAR_REMAINS, "Shades", Skill.PRAYER, true), - PHRIN_REMAINS(ItemID.PHRIN_REMAINS, "Shades", Skill.PRAYER, true), - RIYL_REMAINS(ItemID.RIYL_REMAINS, "Shades", Skill.PRAYER, true), - ASYN_REMAINS(ItemID.ASYN_REMAINS, "Shades", Skill.PRAYER, true), - FIYR_REMAINS(ItemID.FIYR_REMAINS, "Shades", Skill.PRAYER, true), - // Ensouled Heads - ENSOULED_GOBLIN_HEAD(ItemID.ENSOULED_GOBLIN_HEAD_13448, "Ensouled Heads", Skill.PRAYER, true), - ENSOULED_MONKEY_HEAD(ItemID.ENSOULED_MONKEY_HEAD_13451, "Ensouled Heads", Skill.PRAYER, true), - ENSOULED_IMP_HEAD(ItemID.ENSOULED_IMP_HEAD_13454, "Ensouled Heads", Skill.PRAYER, true), - ENSOULED_MINOTAUR_HEAD(ItemID.ENSOULED_MINOTAUR_HEAD_13457, "Ensouled Heads", Skill.PRAYER, true), - ENSOULED_SCORPION_HEAD(ItemID.ENSOULED_SCORPION_HEAD_13460, "Ensouled Heads", Skill.PRAYER, true), - ENSOULED_BEAR_HEAD(ItemID.ENSOULED_BEAR_HEAD_13463, "Ensouled Heads", Skill.PRAYER, true), - ENSOULED_UNICORN_HEAD(ItemID.ENSOULED_UNICORN_HEAD_13466, "Ensouled Heads", Skill.PRAYER, true), - ENSOULED_DOG_HEAD(ItemID.ENSOULED_DOG_HEAD_13469, "Ensouled Heads", Skill.PRAYER, true), - ENSOULED_CHAOS_DRUID_HEAD(ItemID.ENSOULED_CHAOS_DRUID_HEAD_13472, "Ensouled Heads", Skill.PRAYER, true), - ENSOULED_GIANT_HEAD(ItemID.ENSOULED_GIANT_HEAD_13475, "Ensouled Heads", Skill.PRAYER, true), - ENSOULED_OGRE_HEAD(ItemID.ENSOULED_OGRE_HEAD_13478, "Ensouled Heads", Skill.PRAYER, true), - ENSOULED_ELF_HEAD(ItemID.ENSOULED_ELF_HEAD_13481, "Ensouled Heads", Skill.PRAYER, true), - ENSOULED_TROLL_HEAD(ItemID.ENSOULED_TROLL_HEAD_13484, "Ensouled Heads", Skill.PRAYER, true), - ENSOULED_HORROR_HEAD(ItemID.ENSOULED_HORROR_HEAD_13487, "Ensouled Heads", Skill.PRAYER, true), - ENSOULED_KALPHITE_HEAD(ItemID.ENSOULED_KALPHITE_HEAD_13490, "Ensouled Heads", Skill.PRAYER, true), - ENSOULED_DAGANNOTH_HEAD(ItemID.ENSOULED_DAGANNOTH_HEAD_13493, "Ensouled Heads", Skill.PRAYER, true), - ENSOULED_BLOODVELD_HEAD(ItemID.ENSOULED_BLOODVELD_HEAD_13496, "Ensouled Heads", Skill.PRAYER, true), - ENSOULED_TZHAAR_HEAD(ItemID.ENSOULED_TZHAAR_HEAD_13499, "Ensouled Heads", Skill.PRAYER, true), - ENSOULED_DEMON_HEAD(ItemID.ENSOULED_DEMON_HEAD_13502, "Ensouled Heads", Skill.PRAYER, true), - ENSOULED_AVIANSIE_HEAD(ItemID.ENSOULED_AVIANSIE_HEAD_13505, "Ensouled Heads", Skill.PRAYER, true), - ENSOULED_ABYSSAL_HEAD(ItemID.ENSOULED_ABYSSAL_HEAD_13508, "Ensouled Heads", Skill.PRAYER, true), - ENSOULED_DRAGON_HEAD(ItemID.ENSOULED_DRAGON_HEAD_13511, "Ensouled Heads", Skill.PRAYER, true), - - /** - * Cooking Items - */ - RAW_HERRING(ItemID.RAW_HERRING, "Fish", Skill.COOKING), - RAW_MACKEREL(ItemID.RAW_MACKEREL, "Fish", Skill.COOKING), - RAW_TROUT(ItemID.RAW_TROUT, "Fish", Skill.COOKING), - RAW_COD(ItemID.RAW_COD, "Fish", Skill.COOKING), - RAW_PIKE(ItemID.RAW_PIKE, "Fish", Skill.COOKING), - RAW_SALMON(ItemID.RAW_SALMON, "Fish", Skill.COOKING), - RAW_TUNA(ItemID.RAW_TUNA, "Fish", Skill.COOKING), - RAW_KARAMBWAN(ItemID.RAW_KARAMBWAN, "Fish", Skill.COOKING), - RAW_LOBSTER(ItemID.RAW_LOBSTER, "Fish", Skill.COOKING), - RAW_BASS(ItemID.RAW_BASS, "Fish", Skill.COOKING), - RAW_SWORDFISH(ItemID.RAW_SWORDFISH, "Fish", Skill.COOKING), - RAW_MONKFISH(ItemID.RAW_MONKFISH, "Fish", Skill.COOKING), - RAW_SHARK(ItemID.RAW_SHARK, "Fish", Skill.COOKING), - RAW_SEA_TURTLE(ItemID.RAW_SEA_TURTLE, "Fish", Skill.COOKING), - RAW_ANGLERFISH(ItemID.RAW_ANGLERFISH, "Fish", Skill.COOKING), - RAW_DARK_CRAB(ItemID.RAW_DARK_CRAB, "Fish", Skill.COOKING), - RAW_MANTA_RAY(ItemID.RAW_MANTA_RAY, "Fish", Skill.COOKING), - - GRAPES(ItemID.GRAPES, "Other", Skill.COOKING), - - /** - * Crafting Items - */ - WOOL(ItemID.WOOL, "Misc", Skill.CRAFTING), - FLAX(ItemID.FLAX, "Misc", Skill.CRAFTING), - MOLTEN_GLASS(ItemID.MOLTEN_GLASS, "Misc", Skill.CRAFTING), - BATTLESTAFF(ItemID.BATTLESTAFF, "Misc", Skill.CRAFTING), - - // D'hide/Dragon Leather - GREEN_DRAGONHIDE(ItemID.GREEN_DRAGONHIDE, "D'hide", Skill.CRAFTING, ItemID.GREEN_DRAGON_LEATHER), - GREEN_DRAGON_LEATHER(ItemID.GREEN_DRAGON_LEATHER, "D'hide", Skill.CRAFTING), - BLUE_DRAGONHIDE(ItemID.BLUE_DRAGONHIDE, "D'hide", Skill.CRAFTING, ItemID.BLUE_DRAGON_LEATHER), - BLUE_DRAGON_LEATHER(ItemID.BLUE_DRAGON_LEATHER, "D'hide", Skill.CRAFTING), - RED_DRAGONHIDE(ItemID.RED_DRAGONHIDE, "D'hide", Skill.CRAFTING, ItemID.RED_DRAGON_LEATHER), - RED_DRAGON_LEATHER(ItemID.RED_DRAGON_LEATHER, "D'hide", Skill.CRAFTING), - BLACK_DRAGONHIDE(ItemID.BLACK_DRAGONHIDE, "D'hide", Skill.CRAFTING, ItemID.BLACK_DRAGON_LEATHER), - BLACK_DRAGON_LEATHER(ItemID.BLACK_DRAGON_LEATHER, "D'hide", Skill.CRAFTING), - - // Uncut Gems - UNCUT_OPAL(ItemID.UNCUT_OPAL, "Gems", Skill.CRAFTING, ItemID.OPAL), - UNCUT_JADE(ItemID.UNCUT_JADE, "Gems", Skill.CRAFTING, ItemID.JADE), - UNCUT_RED_TOPAZ(ItemID.UNCUT_RED_TOPAZ, "Gems", Skill.CRAFTING, ItemID.RED_TOPAZ), - UNCUT_SAPPHIRE(ItemID.UNCUT_SAPPHIRE, "Gems", Skill.CRAFTING, ItemID.SAPPHIRE), - UNCUT_EMERALD(ItemID.UNCUT_EMERALD, "Gems", Skill.CRAFTING, ItemID.EMERALD), - UNCUT_RUBY(ItemID.UNCUT_RUBY, "Gems", Skill.CRAFTING, ItemID.RUBY), - UNCUT_DIAMOND(ItemID.UNCUT_DIAMOND, "Gems", Skill.CRAFTING, ItemID.DIAMOND), - UNCUT_DRAGONSTONE(ItemID.UNCUT_DRAGONSTONE, "Gems", Skill.CRAFTING, ItemID.DRAGONSTONE), - UNCUT_ONYX(ItemID.UNCUT_ONYX, "Gems", Skill.CRAFTING, ItemID.ONYX), - UNCUT_ZENYTE(ItemID.UNCUT_ZENYTE, "Gems", Skill.CRAFTING, ItemID.ZENYTE), - - // Cut Gems - OPAL(ItemID.OPAL, "Gems", Skill.CRAFTING), - JADE(ItemID.JADE, "Gems", Skill.CRAFTING), - RED_TOPAZ(ItemID.RED_TOPAZ, "Gems", Skill.CRAFTING), - SAPPHIRE(ItemID.SAPPHIRE, "Gems", Skill.CRAFTING), - EMERALD(ItemID.EMERALD, "Gems", Skill.CRAFTING), - RUBY(ItemID.RUBY, "Gems", Skill.CRAFTING), - DIAMOND(ItemID.DIAMOND, "Gems", Skill.CRAFTING), - DRAGONSTONE(ItemID.DRAGONSTONE, "Gems", Skill.CRAFTING), - ONYX(ItemID.ONYX, "Gems", Skill.CRAFTING), - ZENYTE(ItemID.ZENYTE, "Gems", Skill.CRAFTING), - - /** - * Smithing Items - */ - - // Ores - IRON_ORE(ItemID.IRON_ORE, "Ore", Skill.SMITHING), - SILVER_ORE(ItemID.SILVER_ORE, "Ore", Skill.SMITHING), - GOLD_ORE(ItemID.GOLD_ORE, "Ore", Skill.SMITHING), - MITHRIL_ORE(ItemID.MITHRIL_ORE, "Ore", Skill.SMITHING), - ADAMANTITE_ORE(ItemID.ADAMANTITE_ORE, "Ore", Skill.SMITHING), - RUNITE_ORE(ItemID.RUNITE_ORE, "Ore", Skill.SMITHING), - - // Bars - BRONZE_BAR(ItemID.BRONZE_BAR, "Bars", Skill.SMITHING), - IRON_BAR(ItemID.IRON_BAR, "Bars", Skill.SMITHING), - STEEL_BAR(ItemID.STEEL_BAR, "Bars", Skill.SMITHING), - MITHRIL_BAR(ItemID.MITHRIL_BAR, "Bars", Skill.SMITHING), - ADAMANTITE_BAR(ItemID.ADAMANTITE_BAR, "Bars", Skill.SMITHING), - RUNITE_BAR(ItemID.RUNITE_BAR, "Bars", Skill.SMITHING), - - /** - * Farming Items - */ - // Seeds - ACORN(ItemID.ACORN, "Seeds", Skill.FARMING), - WILLOW_SEED(ItemID.WILLOW_SEED, "Seeds", Skill.FARMING), - MAPLE_SEED(ItemID.MAPLE_SEED, "Seeds", Skill.FARMING), - YEW_SEED(ItemID.YEW_SEED, "Seeds", Skill.FARMING), - MAGIC_SEED(ItemID.MAGIC_SEED, "Seeds", Skill.FARMING), - APPLE_TREE_SEED(ItemID.APPLE_TREE_SEED, "Seeds", Skill.FARMING), - BANANA_TREE_SEED(ItemID.BANANA_TREE_SEED, "Seeds", Skill.FARMING), - ORANGE_TREE_SEED(ItemID.ORANGE_TREE_SEED, "Seeds", Skill.FARMING), - CURRY_TREE_SEED(ItemID.CURRY_TREE_SEED, "Seeds", Skill.FARMING), - PINEAPPLE_SEED(ItemID.PINEAPPLE_SEED, "Seeds", Skill.FARMING), - PAPAYA_TREE_SEED(ItemID.PAPAYA_TREE_SEED, "Seeds", Skill.FARMING), - PALM_TREE_SEED(ItemID.PALM_TREE_SEED, "Seeds", Skill.FARMING), - CALQUAT_TREE_SEED(ItemID.CALQUAT_TREE_SEED, "Seeds", Skill.FARMING), - TEAK_SEED(ItemID.TEAK_SEED, "Seeds", Skill.FARMING), - MAHOGANY_SEED(ItemID.MAHOGANY_SEED, "Seeds", Skill.FARMING), - SPIRIT_SEED(ItemID.SPIRIT_SEED, "Seeds", Skill.FARMING), - - // Saplings - OAK_SAPLING(ItemID.OAK_SAPLING, "Saplings", Skill.FARMING, ItemID.ACORN), - WILLOW_SAPLING(ItemID.WILLOW_SAPLING, "Saplings", Skill.FARMING, ItemID.WILLOW_SEED), - MAPLE_SAPLING(ItemID.MAPLE_SAPLING, "Saplings", Skill.FARMING, ItemID.MAPLE_SEED), - YEW_SAPLING(ItemID.YEW_SAPLING, "Saplings", Skill.FARMING, ItemID.YEW_SEED), - MAGIC_SAPLING(ItemID.MAGIC_SAPLING, "Saplings", Skill.FARMING, ItemID.MAGIC_SEED), - APPLE_TREE_SAPLING(ItemID.APPLE_SAPLING, "Saplings", Skill.FARMING, ItemID.APPLE_TREE_SEED), - BANANA_TREE_SAPLING(ItemID.BANANA_SAPLING, "Saplings", Skill.FARMING, ItemID.BANANA_TREE_SEED), - ORANGE_TREE_SAPLING(ItemID.ORANGE_SAPLING, "Saplings", Skill.FARMING, ItemID.ORANGE_TREE_SEED), - CURRY_TREE_SAPLING(ItemID.CURRY_SAPLING, "Saplings", Skill.FARMING, ItemID.CURRY_TREE_SEED), - PINEAPPLE_SAPLING(ItemID.PINEAPPLE_SAPLING, "Saplings", Skill.FARMING, ItemID.PINEAPPLE_SEED), - PAPAYA_TREE_SAPLING(ItemID.PAPAYA_SAPLING, "Saplings", Skill.FARMING, ItemID.PAPAYA_TREE_SEED), - PALM_TREE_SAPLING(ItemID.PALM_SAPLING, "Saplings", Skill.FARMING, ItemID.PALM_TREE_SEED), - CALQUAT_TREE_SAPLING(ItemID.CALQUAT_SAPLING, "Saplings", Skill.FARMING, ItemID.CALQUAT_TREE_SEED), - TEAK_SAPLING(ItemID.TEAK_SAPLING, "Saplings", Skill.FARMING, ItemID.TEAK_SEED), - MAHOGANY_SAPLING(ItemID.MAHOGANY_SAPLING, "Saplings", Skill.FARMING, ItemID.MAHOGANY_SEED), - SPIRIT_SAPLING(ItemID.SPIRIT_SAPLING, "Saplings", Skill.FARMING, ItemID.SPIRIT_SEED), - ; - - @Getter - private final int itemID; - @Getter - private final String category; - @Getter - private final Skill skill; - - /** - * Should be operated on and then treated like this item or does nothing if null. - * Used mostly for things like herblore where you want Grimy, Clean, and UNF to count for creating potions. - * To do this GRIMY links to CLEAN which links to UNFINISHED which links to null - */ - @Getter - private final int linkedItemId; - - @Getter - private boolean ignoreBonus; - - @Getter - private ItemComposition composition; - - CriticalItem(int itemID, String category, Skill skill, int linkedItem) - { - this.itemID = itemID; - this.category = category; - this.skill = skill; - this.linkedItemId = linkedItem; - this.composition = null; - this.ignoreBonus = false; - } - - CriticalItem(int itemID, String category, Skill skill) - { - this(itemID, category, skill, -1); - } - - CriticalItem(int itemID, String category, Skill skill, boolean ignoreBonusXp) - { - this(itemID, category, skill, -1); - this.ignoreBonus = ignoreBonusXp; - } - - // Builds a Map to reduce looping frequency - private static Map> buildSkillItemMap() - { - Map> map = new HashMap<>(); - for (CriticalItem item : values()) - { - map.computeIfAbsent(item.getSkill(), e -> new ArrayList<>()).add(item); - } - - return map; - } - private static final Map> bySkillName = buildSkillItemMap(); - public static ArrayList getBySkillName(Skill skill) - { - return bySkillName.get(skill); - } - - // Builds a Map to reduce looping frequency - private static Map> buildSkillCategoryMap() - { - Map> map = new HashMap<>(); - for (CriticalItem item : values()) - { - map.computeIfAbsent(item.getSkill(), k -> new HashSet<>()).add(item.category); - } - - return map; - } - private static final Map> bySkillCategory = buildSkillCategoryMap(); - public static Set getSkillCategories(Skill skill) - { - return bySkillCategory.get(skill); - } - - // Builds a Map to reduce looping frequency - private static Map> buildItemSkillCategoryMap() - { - Map> map = new HashMap<>(); - for (CriticalItem item : values()) - { - String key = item.getCategory() + item.skill.getName(); - map.computeIfAbsent(key, e -> new ArrayList<>()).add(item); - } - - return map; - } - private static final Map> itemsBySkillCategory = buildItemSkillCategoryMap(); - public static ArrayList getItemsForSkillCategories(Skill skill, String category) - { - return itemsBySkillCategory.get(category + skill.getName()); - } - - // Builds a Map to reduce looping frequency - private static Map buildItemsByIdMap() - { - Map map = new HashMap<>(); - for (CriticalItem item : values()) - { - map.put(item.getItemID(), item); - } - - return map; - } - private static final Map itemsById = buildItemsByIdMap(); - public static CriticalItem getByItemId(int id) - { - return itemsById.get(id); - } - - /** - * Attaches the Item Composition to each Critical Item on client initial load - * @param m ItemManager - */ - public static void prepareItemCompositions(ItemManager m) - { - for (CriticalItem i : values()) - { - i.composition = m.getItemComposition(i.getItemID()); - } - } - - @Override - public String toString() - { - return "CriticalItem=(name=" + this.name() + ",id=" + this.itemID + ",category=" + this.category + ")"; - } -} +/* + * Copyright (c) 2018, 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.skillcalculator.banked; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; +import lombok.Getter; +import net.runelite.api.ItemComposition; +import net.runelite.api.ItemID; +import net.runelite.api.Skill; +import net.runelite.client.game.ItemManager; + +public enum CriticalItem +{ + /** + * Construction Items + */ + // Planks + PLANK(ItemID.PLANK, "Planks", Skill.CONSTRUCTION), + OAK_PLANK(ItemID.OAK_PLANK, "Planks", Skill.CONSTRUCTION), + TEAK_PLANK(ItemID.TEAK_PLANK, "Planks", Skill.CONSTRUCTION), + MAHOGANY_PLANK(ItemID.MAHOGANY_PLANK, "Planks", Skill.CONSTRUCTION), + // Logs + LOGS(ItemID.LOGS, "Logs", Skill.CONSTRUCTION, ItemID.PLANK), + OAK_LOGS(ItemID.OAK_LOGS, "Logs", Skill.CONSTRUCTION, ItemID.OAK_PLANK), + TEAK_LOGS(ItemID.TEAK_LOGS, "Logs", Skill.CONSTRUCTION, ItemID.TEAK_PLANK), + MAHOGANY_LOGS(ItemID.MAHOGANY_LOGS, "Logs", Skill.CONSTRUCTION, ItemID.MAHOGANY_PLANK), + + /** + * Herblore Items + */ + // Grimy Herbs + GRIMY_GUAM_LEAF(ItemID.GRIMY_GUAM_LEAF, "Grimy Herbs", Skill.HERBLORE, ItemID.GUAM_LEAF), + GRIMY_MARRENTILL(ItemID.GRIMY_MARRENTILL, "Grimy Herbs", Skill.HERBLORE, ItemID.MARRENTILL), + GRIMY_TARROMIN(ItemID.GRIMY_TARROMIN, "Grimy Herbs", Skill.HERBLORE, ItemID.TARROMIN), + GRIMY_HARRALANDER(ItemID.GRIMY_HARRALANDER, "Grimy Herbs", Skill.HERBLORE, ItemID.HARRALANDER), + GRIMY_RANARR_WEED(ItemID.GRIMY_RANARR_WEED, "Grimy Herbs", Skill.HERBLORE, ItemID.RANARR_WEED), + GRIMY_TOADFLAX(ItemID.GRIMY_TOADFLAX, "Grimy Herbs", Skill.HERBLORE, ItemID.TOADFLAX), + GRIMY_IRIT_LEAF(ItemID.GRIMY_IRIT_LEAF, "Grimy Herbs", Skill.HERBLORE, ItemID.IRIT_LEAF), + GRIMY_AVANTOE(ItemID.GRIMY_AVANTOE, "Grimy Herbs", Skill.HERBLORE, ItemID.AVANTOE), + GRIMY_KWUARM(ItemID.GRIMY_KWUARM, "Grimy Herbs", Skill.HERBLORE, ItemID.KWUARM), + GRIMY_SNAPDRAGON(ItemID.GRIMY_SNAPDRAGON, "Grimy Herbs", Skill.HERBLORE, ItemID.SNAPDRAGON), + GRIMY_CADANTINE(ItemID.GRIMY_CADANTINE, "Grimy Herbs", Skill.HERBLORE, ItemID.CADANTINE), + GRIMY_LANTADYME(ItemID.GRIMY_LANTADYME, "Grimy Herbs", Skill.HERBLORE, ItemID.LANTADYME), + GRIMY_DWARF_WEED(ItemID.GRIMY_DWARF_WEED, "Grimy Herbs", Skill.HERBLORE, ItemID.DWARF_WEED), + GRIMY_TORSTOL(ItemID.GRIMY_TORSTOL, "Grimy Herbs", Skill.HERBLORE, ItemID.TORSTOL), + // Clean Herbs + GUAM_LEAF(ItemID.GUAM_LEAF, "Cleaned Herbs", Skill.HERBLORE, ItemID.GUAM_POTION_UNF), + MARRENTILL(ItemID.MARRENTILL, "Cleaned Herbs", Skill.HERBLORE, ItemID.MARRENTILL_POTION_UNF), + TARROMIN(ItemID.TARROMIN, "Cleaned Herbs", Skill.HERBLORE, ItemID.TARROMIN_POTION_UNF), + HARRALANDER(ItemID.HARRALANDER, "Cleaned Herbs", Skill.HERBLORE, ItemID.HARRALANDER_POTION_UNF), + RANARR_WEED(ItemID.RANARR_WEED, "Cleaned Herbs", Skill.HERBLORE, ItemID.RANARR_POTION_UNF), + TOADFLAX(ItemID.TOADFLAX, "Cleaned Herbs", Skill.HERBLORE, ItemID.TOADFLAX_POTION_UNF), + IRIT_LEAF(ItemID.IRIT_LEAF, "Cleaned Herbs", Skill.HERBLORE, ItemID.IRIT_POTION_UNF), + AVANTOE(ItemID.AVANTOE, "Cleaned Herbs", Skill.HERBLORE, ItemID.AVANTOE_POTION_UNF), + KWUARM(ItemID.KWUARM, "Cleaned Herbs", Skill.HERBLORE, ItemID.KWUARM_POTION_UNF), + SNAPDRAGON(ItemID.SNAPDRAGON, "Cleaned Herbs", Skill.HERBLORE, ItemID.SNAPDRAGON_POTION_UNF), + CADANTINE(ItemID.CADANTINE, "Cleaned Herbs", Skill.HERBLORE, ItemID.CADANTINE_POTION_UNF), + LANTADYME(ItemID.LANTADYME, "Cleaned Herbs", Skill.HERBLORE, ItemID.LANTADYME_POTION_UNF), + DWARF_WEED(ItemID.DWARF_WEED, "Cleaned Herbs", Skill.HERBLORE, ItemID.DWARF_WEED_POTION_UNF), + TORSTOL(ItemID.TORSTOL, "Cleaned Herbs", Skill.HERBLORE, ItemID.TORSTOL_POTION_UNF), + // Unfinished Potions + GUAM_LEAF_POTION_UNF(ItemID.GUAM_POTION_UNF, "Unfinished Potions", Skill.HERBLORE), + MARRENTILL_POTION_UNF(ItemID.MARRENTILL_POTION_UNF, "Unfinished Potions", Skill.HERBLORE), + TARROMIN_POTION_UNF(ItemID.TARROMIN_POTION_UNF, "Unfinished Potions", Skill.HERBLORE), + HARRALANDER_POTION_UNF(ItemID.HARRALANDER_POTION_UNF, "Unfinished Potions", Skill.HERBLORE), + RANARR_POTION_UNF(ItemID.RANARR_POTION_UNF, "Unfinished Potions", Skill.HERBLORE), + TOADFLAX_POTION_UNF(ItemID.TOADFLAX_POTION_UNF, "Unfinished Potions", Skill.HERBLORE), + IRIT_POTION_UNF(ItemID.IRIT_POTION_UNF, "Unfinished Potions", Skill.HERBLORE), + AVANTOE_POTION_UNF(ItemID.AVANTOE_POTION_UNF, "Unfinished Potions", Skill.HERBLORE), + KWUARM_POTION_UNF(ItemID.KWUARM_POTION_UNF, "Unfinished Potions", Skill.HERBLORE), + SNAPDRAGON_POTION_UNF(ItemID.SNAPDRAGON_POTION_UNF, "Unfinished Potions", Skill.HERBLORE), + CADANTINE_POTION_UNF(ItemID.CADANTINE_POTION_UNF, "Unfinished Potions", Skill.HERBLORE), + LANTADYME_POTION_UNF(ItemID.LANTADYME_POTION_UNF, "Unfinished Potions", Skill.HERBLORE), + DWARF_WEED_POTION_UNF(ItemID.DWARF_WEED_POTION_UNF, "Unfinished Potions", Skill.HERBLORE), + TORSTOL_POTION_UNF(ItemID.TORSTOL_POTION_UNF, "Unfinished Potions", Skill.HERBLORE), + + /** + * Prayer Items + */ + // Bones + BONES(ItemID.BONES, "Bones", Skill.PRAYER), + WOLF_BONES(ItemID.WOLF_BONES, "Bones", Skill.PRAYER), + BURNT_BONES(ItemID.BURNT_BONES, "Bones", Skill.PRAYER), + MONKEY_BONES(ItemID.MONKEY_BONES, "Bones", Skill.PRAYER), + BAT_BONES(ItemID.BAT_BONES, "Bones", Skill.PRAYER), + JOGRE_BONES(ItemID.JOGRE_BONES, "Bones", Skill.PRAYER), + BIG_BONES(ItemID.BIG_BONES, "Bones", Skill.PRAYER), + ZOGRE_BONES(ItemID.ZOGRE_BONES, "Bones", Skill.PRAYER), + SHAIKAHAN_BONES(ItemID.SHAIKAHAN_BONES, "Bones", Skill.PRAYER), + BABYDRAGON_BONES(ItemID.BABYDRAGON_BONES, "Bones", Skill.PRAYER), + WYVERN_BONES(ItemID.WYVERN_BONES, "Bones", Skill.PRAYER), + DRAGON_BONES(ItemID.DRAGON_BONES, "Bones", Skill.PRAYER), + FAYRG_BONES(ItemID.FAYRG_BONES, "Bones", Skill.PRAYER), + LAVA_DRAGON_BONES(ItemID.LAVA_DRAGON_BONES, "Bones", Skill.PRAYER), + RAURG_BONES(ItemID.RAURG_BONES, "Bones", Skill.PRAYER), + DAGANNOTH_BONES(ItemID.DAGANNOTH_BONES, "Bones", Skill.PRAYER), + OURG_BONES(ItemID.OURG_BONES, "Bones", Skill.PRAYER), + SUPERIOR_DRAGON_BONES(ItemID.SUPERIOR_DRAGON_BONES, "Bones", Skill.PRAYER), + // Shade Remains (Pyre Logs) + LOAR_REMAINS(ItemID.LOAR_REMAINS, "Shades", Skill.PRAYER, true), + PHRIN_REMAINS(ItemID.PHRIN_REMAINS, "Shades", Skill.PRAYER, true), + RIYL_REMAINS(ItemID.RIYL_REMAINS, "Shades", Skill.PRAYER, true), + ASYN_REMAINS(ItemID.ASYN_REMAINS, "Shades", Skill.PRAYER, true), + FIYR_REMAINS(ItemID.FIYR_REMAINS, "Shades", Skill.PRAYER, true), + // Ensouled Heads + ENSOULED_GOBLIN_HEAD(ItemID.ENSOULED_GOBLIN_HEAD_13448, "Ensouled Heads", Skill.PRAYER, true), + ENSOULED_MONKEY_HEAD(ItemID.ENSOULED_MONKEY_HEAD_13451, "Ensouled Heads", Skill.PRAYER, true), + ENSOULED_IMP_HEAD(ItemID.ENSOULED_IMP_HEAD_13454, "Ensouled Heads", Skill.PRAYER, true), + ENSOULED_MINOTAUR_HEAD(ItemID.ENSOULED_MINOTAUR_HEAD_13457, "Ensouled Heads", Skill.PRAYER, true), + ENSOULED_SCORPION_HEAD(ItemID.ENSOULED_SCORPION_HEAD_13460, "Ensouled Heads", Skill.PRAYER, true), + ENSOULED_BEAR_HEAD(ItemID.ENSOULED_BEAR_HEAD_13463, "Ensouled Heads", Skill.PRAYER, true), + ENSOULED_UNICORN_HEAD(ItemID.ENSOULED_UNICORN_HEAD_13466, "Ensouled Heads", Skill.PRAYER, true), + ENSOULED_DOG_HEAD(ItemID.ENSOULED_DOG_HEAD_13469, "Ensouled Heads", Skill.PRAYER, true), + ENSOULED_CHAOS_DRUID_HEAD(ItemID.ENSOULED_CHAOS_DRUID_HEAD_13472, "Ensouled Heads", Skill.PRAYER, true), + ENSOULED_GIANT_HEAD(ItemID.ENSOULED_GIANT_HEAD_13475, "Ensouled Heads", Skill.PRAYER, true), + ENSOULED_OGRE_HEAD(ItemID.ENSOULED_OGRE_HEAD_13478, "Ensouled Heads", Skill.PRAYER, true), + ENSOULED_ELF_HEAD(ItemID.ENSOULED_ELF_HEAD_13481, "Ensouled Heads", Skill.PRAYER, true), + ENSOULED_TROLL_HEAD(ItemID.ENSOULED_TROLL_HEAD_13484, "Ensouled Heads", Skill.PRAYER, true), + ENSOULED_HORROR_HEAD(ItemID.ENSOULED_HORROR_HEAD_13487, "Ensouled Heads", Skill.PRAYER, true), + ENSOULED_KALPHITE_HEAD(ItemID.ENSOULED_KALPHITE_HEAD_13490, "Ensouled Heads", Skill.PRAYER, true), + ENSOULED_DAGANNOTH_HEAD(ItemID.ENSOULED_DAGANNOTH_HEAD_13493, "Ensouled Heads", Skill.PRAYER, true), + ENSOULED_BLOODVELD_HEAD(ItemID.ENSOULED_BLOODVELD_HEAD_13496, "Ensouled Heads", Skill.PRAYER, true), + ENSOULED_TZHAAR_HEAD(ItemID.ENSOULED_TZHAAR_HEAD_13499, "Ensouled Heads", Skill.PRAYER, true), + ENSOULED_DEMON_HEAD(ItemID.ENSOULED_DEMON_HEAD_13502, "Ensouled Heads", Skill.PRAYER, true), + ENSOULED_AVIANSIE_HEAD(ItemID.ENSOULED_AVIANSIE_HEAD_13505, "Ensouled Heads", Skill.PRAYER, true), + ENSOULED_ABYSSAL_HEAD(ItemID.ENSOULED_ABYSSAL_HEAD_13508, "Ensouled Heads", Skill.PRAYER, true), + ENSOULED_DRAGON_HEAD(ItemID.ENSOULED_DRAGON_HEAD_13511, "Ensouled Heads", Skill.PRAYER, true), + + /** + * Cooking Items + */ + RAW_HERRING(ItemID.RAW_HERRING, "Fish", Skill.COOKING), + RAW_MACKEREL(ItemID.RAW_MACKEREL, "Fish", Skill.COOKING), + RAW_TROUT(ItemID.RAW_TROUT, "Fish", Skill.COOKING), + RAW_COD(ItemID.RAW_COD, "Fish", Skill.COOKING), + RAW_PIKE(ItemID.RAW_PIKE, "Fish", Skill.COOKING), + RAW_SALMON(ItemID.RAW_SALMON, "Fish", Skill.COOKING), + RAW_TUNA(ItemID.RAW_TUNA, "Fish", Skill.COOKING), + RAW_KARAMBWAN(ItemID.RAW_KARAMBWAN, "Fish", Skill.COOKING), + RAW_LOBSTER(ItemID.RAW_LOBSTER, "Fish", Skill.COOKING), + RAW_BASS(ItemID.RAW_BASS, "Fish", Skill.COOKING), + RAW_SWORDFISH(ItemID.RAW_SWORDFISH, "Fish", Skill.COOKING), + RAW_MONKFISH(ItemID.RAW_MONKFISH, "Fish", Skill.COOKING), + RAW_SHARK(ItemID.RAW_SHARK, "Fish", Skill.COOKING), + RAW_SEA_TURTLE(ItemID.RAW_SEA_TURTLE, "Fish", Skill.COOKING), + RAW_ANGLERFISH(ItemID.RAW_ANGLERFISH, "Fish", Skill.COOKING), + RAW_DARK_CRAB(ItemID.RAW_DARK_CRAB, "Fish", Skill.COOKING), + RAW_MANTA_RAY(ItemID.RAW_MANTA_RAY, "Fish", Skill.COOKING), + + GRAPES(ItemID.GRAPES, "Other", Skill.COOKING), + + /** + * Crafting Items + */ + WOOL(ItemID.WOOL, "Misc", Skill.CRAFTING), + FLAX(ItemID.FLAX, "Misc", Skill.CRAFTING), + MOLTEN_GLASS(ItemID.MOLTEN_GLASS, "Misc", Skill.CRAFTING), + BATTLESTAFF(ItemID.BATTLESTAFF, "Misc", Skill.CRAFTING), + + // D'hide/Dragon Leather + GREEN_DRAGONHIDE(ItemID.GREEN_DRAGONHIDE, "D'hide", Skill.CRAFTING, ItemID.GREEN_DRAGON_LEATHER), + GREEN_DRAGON_LEATHER(ItemID.GREEN_DRAGON_LEATHER, "D'hide", Skill.CRAFTING), + BLUE_DRAGONHIDE(ItemID.BLUE_DRAGONHIDE, "D'hide", Skill.CRAFTING, ItemID.BLUE_DRAGON_LEATHER), + BLUE_DRAGON_LEATHER(ItemID.BLUE_DRAGON_LEATHER, "D'hide", Skill.CRAFTING), + RED_DRAGONHIDE(ItemID.RED_DRAGONHIDE, "D'hide", Skill.CRAFTING, ItemID.RED_DRAGON_LEATHER), + RED_DRAGON_LEATHER(ItemID.RED_DRAGON_LEATHER, "D'hide", Skill.CRAFTING), + BLACK_DRAGONHIDE(ItemID.BLACK_DRAGONHIDE, "D'hide", Skill.CRAFTING, ItemID.BLACK_DRAGON_LEATHER), + BLACK_DRAGON_LEATHER(ItemID.BLACK_DRAGON_LEATHER, "D'hide", Skill.CRAFTING), + + // Uncut Gems + UNCUT_OPAL(ItemID.UNCUT_OPAL, "Gems", Skill.CRAFTING, ItemID.OPAL), + UNCUT_JADE(ItemID.UNCUT_JADE, "Gems", Skill.CRAFTING, ItemID.JADE), + UNCUT_RED_TOPAZ(ItemID.UNCUT_RED_TOPAZ, "Gems", Skill.CRAFTING, ItemID.RED_TOPAZ), + UNCUT_SAPPHIRE(ItemID.UNCUT_SAPPHIRE, "Gems", Skill.CRAFTING, ItemID.SAPPHIRE), + UNCUT_EMERALD(ItemID.UNCUT_EMERALD, "Gems", Skill.CRAFTING, ItemID.EMERALD), + UNCUT_RUBY(ItemID.UNCUT_RUBY, "Gems", Skill.CRAFTING, ItemID.RUBY), + UNCUT_DIAMOND(ItemID.UNCUT_DIAMOND, "Gems", Skill.CRAFTING, ItemID.DIAMOND), + UNCUT_DRAGONSTONE(ItemID.UNCUT_DRAGONSTONE, "Gems", Skill.CRAFTING, ItemID.DRAGONSTONE), + UNCUT_ONYX(ItemID.UNCUT_ONYX, "Gems", Skill.CRAFTING, ItemID.ONYX), + UNCUT_ZENYTE(ItemID.UNCUT_ZENYTE, "Gems", Skill.CRAFTING, ItemID.ZENYTE), + + // Cut Gems + OPAL(ItemID.OPAL, "Gems", Skill.CRAFTING), + JADE(ItemID.JADE, "Gems", Skill.CRAFTING), + RED_TOPAZ(ItemID.RED_TOPAZ, "Gems", Skill.CRAFTING), + SAPPHIRE(ItemID.SAPPHIRE, "Gems", Skill.CRAFTING), + EMERALD(ItemID.EMERALD, "Gems", Skill.CRAFTING), + RUBY(ItemID.RUBY, "Gems", Skill.CRAFTING), + DIAMOND(ItemID.DIAMOND, "Gems", Skill.CRAFTING), + DRAGONSTONE(ItemID.DRAGONSTONE, "Gems", Skill.CRAFTING), + ONYX(ItemID.ONYX, "Gems", Skill.CRAFTING), + ZENYTE(ItemID.ZENYTE, "Gems", Skill.CRAFTING), + + /** + * Smithing Items + */ + + // Ores + IRON_ORE(ItemID.IRON_ORE, "Ore", Skill.SMITHING), + SILVER_ORE(ItemID.SILVER_ORE, "Ore", Skill.SMITHING), + GOLD_ORE(ItemID.GOLD_ORE, "Ore", Skill.SMITHING), + MITHRIL_ORE(ItemID.MITHRIL_ORE, "Ore", Skill.SMITHING), + ADAMANTITE_ORE(ItemID.ADAMANTITE_ORE, "Ore", Skill.SMITHING), + RUNITE_ORE(ItemID.RUNITE_ORE, "Ore", Skill.SMITHING), + + // Bars + BRONZE_BAR(ItemID.BRONZE_BAR, "Bars", Skill.SMITHING), + IRON_BAR(ItemID.IRON_BAR, "Bars", Skill.SMITHING), + STEEL_BAR(ItemID.STEEL_BAR, "Bars", Skill.SMITHING), + MITHRIL_BAR(ItemID.MITHRIL_BAR, "Bars", Skill.SMITHING), + ADAMANTITE_BAR(ItemID.ADAMANTITE_BAR, "Bars", Skill.SMITHING), + RUNITE_BAR(ItemID.RUNITE_BAR, "Bars", Skill.SMITHING), + + /** + * Farming Items + */ + // Seeds + ACORN(ItemID.ACORN, "Seeds", Skill.FARMING), + WILLOW_SEED(ItemID.WILLOW_SEED, "Seeds", Skill.FARMING), + MAPLE_SEED(ItemID.MAPLE_SEED, "Seeds", Skill.FARMING), + YEW_SEED(ItemID.YEW_SEED, "Seeds", Skill.FARMING), + MAGIC_SEED(ItemID.MAGIC_SEED, "Seeds", Skill.FARMING), + APPLE_TREE_SEED(ItemID.APPLE_TREE_SEED, "Seeds", Skill.FARMING), + BANANA_TREE_SEED(ItemID.BANANA_TREE_SEED, "Seeds", Skill.FARMING), + ORANGE_TREE_SEED(ItemID.ORANGE_TREE_SEED, "Seeds", Skill.FARMING), + CURRY_TREE_SEED(ItemID.CURRY_TREE_SEED, "Seeds", Skill.FARMING), + PINEAPPLE_SEED(ItemID.PINEAPPLE_SEED, "Seeds", Skill.FARMING), + PAPAYA_TREE_SEED(ItemID.PAPAYA_TREE_SEED, "Seeds", Skill.FARMING), + PALM_TREE_SEED(ItemID.PALM_TREE_SEED, "Seeds", Skill.FARMING), + CALQUAT_TREE_SEED(ItemID.CALQUAT_TREE_SEED, "Seeds", Skill.FARMING), + TEAK_SEED(ItemID.TEAK_SEED, "Seeds", Skill.FARMING), + MAHOGANY_SEED(ItemID.MAHOGANY_SEED, "Seeds", Skill.FARMING), + SPIRIT_SEED(ItemID.SPIRIT_SEED, "Seeds", Skill.FARMING), + + // Saplings + OAK_SAPLING(ItemID.OAK_SAPLING, "Saplings", Skill.FARMING, ItemID.ACORN), + WILLOW_SAPLING(ItemID.WILLOW_SAPLING, "Saplings", Skill.FARMING, ItemID.WILLOW_SEED), + MAPLE_SAPLING(ItemID.MAPLE_SAPLING, "Saplings", Skill.FARMING, ItemID.MAPLE_SEED), + YEW_SAPLING(ItemID.YEW_SAPLING, "Saplings", Skill.FARMING, ItemID.YEW_SEED), + MAGIC_SAPLING(ItemID.MAGIC_SAPLING, "Saplings", Skill.FARMING, ItemID.MAGIC_SEED), + APPLE_TREE_SAPLING(ItemID.APPLE_SAPLING, "Saplings", Skill.FARMING, ItemID.APPLE_TREE_SEED), + BANANA_TREE_SAPLING(ItemID.BANANA_SAPLING, "Saplings", Skill.FARMING, ItemID.BANANA_TREE_SEED), + ORANGE_TREE_SAPLING(ItemID.ORANGE_SAPLING, "Saplings", Skill.FARMING, ItemID.ORANGE_TREE_SEED), + CURRY_TREE_SAPLING(ItemID.CURRY_SAPLING, "Saplings", Skill.FARMING, ItemID.CURRY_TREE_SEED), + PINEAPPLE_SAPLING(ItemID.PINEAPPLE_SAPLING, "Saplings", Skill.FARMING, ItemID.PINEAPPLE_SEED), + PAPAYA_TREE_SAPLING(ItemID.PAPAYA_SAPLING, "Saplings", Skill.FARMING, ItemID.PAPAYA_TREE_SEED), + PALM_TREE_SAPLING(ItemID.PALM_SAPLING, "Saplings", Skill.FARMING, ItemID.PALM_TREE_SEED), + CALQUAT_TREE_SAPLING(ItemID.CALQUAT_SAPLING, "Saplings", Skill.FARMING, ItemID.CALQUAT_TREE_SEED), + TEAK_SAPLING(ItemID.TEAK_SAPLING, "Saplings", Skill.FARMING, ItemID.TEAK_SEED), + MAHOGANY_SAPLING(ItemID.MAHOGANY_SAPLING, "Saplings", Skill.FARMING, ItemID.MAHOGANY_SEED), + SPIRIT_SAPLING(ItemID.SPIRIT_SAPLING, "Saplings", Skill.FARMING, ItemID.SPIRIT_SEED), + ; + + @Getter + private final int itemID; + @Getter + private final String category; + @Getter + private final Skill skill; + + /** + * Should be operated on and then treated like this item or does nothing if null. + * Used mostly for things like herblore where you want Grimy, Clean, and UNF to count for creating potions. + * To do this GRIMY links to CLEAN which links to UNFINISHED which links to null + */ + @Getter + private final int linkedItemId; + + @Getter + private boolean ignoreBonus; + + @Getter + private ItemComposition composition; + + CriticalItem(int itemID, String category, Skill skill, int linkedItem) + { + this.itemID = itemID; + this.category = category; + this.skill = skill; + this.linkedItemId = linkedItem; + this.composition = null; + this.ignoreBonus = false; + } + + CriticalItem(int itemID, String category, Skill skill) + { + this(itemID, category, skill, -1); + } + + CriticalItem(int itemID, String category, Skill skill, boolean ignoreBonusXp) + { + this(itemID, category, skill, -1); + this.ignoreBonus = ignoreBonusXp; + } + + // Builds a Map to reduce looping frequency + private static Map> buildSkillItemMap() + { + Map> map = new HashMap<>(); + for (CriticalItem item : values()) + { + map.computeIfAbsent(item.getSkill(), e -> new ArrayList<>()).add(item); + } + + return map; + } + + private static final Map> bySkillName = buildSkillItemMap(); + + public static ArrayList getBySkillName(Skill skill) + { + return bySkillName.get(skill); + } + + // Builds a Map to reduce looping frequency + private static Map> buildSkillCategoryMap() + { + Map> map = new HashMap<>(); + for (CriticalItem item : values()) + { + map.computeIfAbsent(item.getSkill(), k -> new HashSet<>()).add(item.category); + } + + return map; + } + + private static final Map> bySkillCategory = buildSkillCategoryMap(); + + public static Set getSkillCategories(Skill skill) + { + return bySkillCategory.get(skill); + } + + // Builds a Map to reduce looping frequency + private static Map> buildItemSkillCategoryMap() + { + Map> map = new HashMap<>(); + for (CriticalItem item : values()) + { + String key = item.getCategory() + item.skill.getName(); + map.computeIfAbsent(key, e -> new ArrayList<>()).add(item); + } + + return map; + } + + private static final Map> itemsBySkillCategory = buildItemSkillCategoryMap(); + + public static ArrayList getItemsForSkillCategories(Skill skill, String category) + { + return itemsBySkillCategory.get(category + skill.getName()); + } + + // Builds a Map to reduce looping frequency + private static Map buildItemsByIdMap() + { + Map map = new HashMap<>(); + for (CriticalItem item : values()) + { + map.put(item.getItemID(), item); + } + + return map; + } + + private static final Map itemsById = buildItemsByIdMap(); + + public static CriticalItem getByItemId(int id) + { + return itemsById.get(id); + } + + /** + * Attaches the Item Composition to each Critical Item on client initial load + * + * @param m ItemManager + */ + public static void prepareItemCompositions(ItemManager m) + { + for (CriticalItem i : values()) + { + i.composition = m.getItemComposition(i.getItemID()); + } + } + + @Override + public String toString() + { + return "CriticalItem=(name=" + this.name() + ",id=" + this.itemID + ",category=" + this.category + ")"; + } +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/skillcalculator/banked/beans/Activity.java b/runelite-client/src/main/java/net/runelite/client/plugins/skillcalculator/banked/beans/Activity.java index 7d82ad720b..e855742667 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/skillcalculator/banked/beans/Activity.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/skillcalculator/banked/beans/Activity.java @@ -1,408 +1,411 @@ -/* - * Copyright (c) 2018, 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.skillcalculator.banked.beans; - -import lombok.Getter; -import net.runelite.api.ItemID; -import net.runelite.api.Skill; -import net.runelite.client.plugins.skillcalculator.banked.CriticalItem; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.Map; - -@Getter -public enum Activity -{ - /** - * Herblore Activities - */ - // Creating Potions - // Guam - GUAM_POTION_UNF(ItemID.GUAM_POTION_UNF, "Unfinished Potion", Skill.HERBLORE, 1, 0, CriticalItem.GUAM_LEAF, ActivitySecondaries.UNFINISHED_POTION), - GUAM_TAR(ItemID.GUAM_TAR, "Guam tar", Skill.HERBLORE, 19, 30, CriticalItem.GUAM_LEAF, ActivitySecondaries.SWAMP_TAR, true), - - ATTACK_POTION(ItemID.ATTACK_POTION4, "Attack Potion", Skill.HERBLORE, 3, 25, CriticalItem.GUAM_LEAF_POTION_UNF, ActivitySecondaries.ATTACK_POTION), - // Marrentil - MARRENTILL_POTION_UNF(ItemID.MARRENTILL_POTION_UNF, "Unfinished Potion", Skill.HERBLORE, 1, 0, CriticalItem.MARRENTILL, ActivitySecondaries.UNFINISHED_POTION), - MARRENTILL_TAR(ItemID.MARRENTILL_TAR, "Marrentill tar", Skill.HERBLORE, 31, 42.5, CriticalItem.MARRENTILL, ActivitySecondaries.SWAMP_TAR, true), - - ANTIPOISON(ItemID.ANTIPOISON4, "Antipoison", Skill.HERBLORE, 5, 37.5, CriticalItem.MARRENTILL_POTION_UNF, ActivitySecondaries.ANTIPOISON), - // Tarromin - TARROMIN_POTION_UNF(ItemID.TARROMIN_POTION_UNF, "Unfinished Potion", Skill.HERBLORE, 1, 0, CriticalItem.TARROMIN, ActivitySecondaries.UNFINISHED_POTION), - TARROMIN_TAR(ItemID.TARROMIN_TAR, "Tarromin tar", Skill.HERBLORE, 39, 55, CriticalItem.TARROMIN, ActivitySecondaries.SWAMP_TAR, true), - - STRENGTH_POTION(ItemID.STRENGTH_POTION4, "Strength potion", Skill.HERBLORE, 12, 50, CriticalItem.TARROMIN_POTION_UNF, ActivitySecondaries.STRENGTH_POTION), - SERUM_207(ItemID.SERUM_207_4, "Serum 207", Skill.HERBLORE, 15, 50, CriticalItem.TARROMIN_POTION_UNF, ActivitySecondaries.SERUM_207), - // Harralander - HARRALANDER_POTION_UNF(ItemID.HARRALANDER_POTION_UNF, "Unfinished Potion", Skill.HERBLORE, 1, 0, CriticalItem.HARRALANDER, ActivitySecondaries.UNFINISHED_POTION), - HARRALANDER_TAR(ItemID.HARRALANDER_TAR, "Harralander tar", Skill.HERBLORE, 44, 72.5, CriticalItem.HARRALANDER, ActivitySecondaries.SWAMP_TAR, true), - - COMPOST_POTION(ItemID.COMPOST_POTION4, "Compost potion", Skill.HERBLORE, 21, 60, CriticalItem.HARRALANDER_POTION_UNF, ActivitySecondaries.COMPOST_POTION), - RESTORE_POTION(ItemID.RESTORE_POTION4, "Restore potion", Skill.HERBLORE, 22, 62.5, CriticalItem.HARRALANDER_POTION_UNF, ActivitySecondaries.RESTORE_POTION), - ENERGY_POTION(ItemID.ENERGY_POTION4, "Energy potion", Skill.HERBLORE, 26, 67.5, CriticalItem.HARRALANDER_POTION_UNF, ActivitySecondaries.ENERGY_POTION), - COMBAT_POTION(ItemID.COMBAT_POTION4, "Combat potion", Skill.HERBLORE, 36, 84, CriticalItem.HARRALANDER_POTION_UNF, ActivitySecondaries.COMBAT_POTION), - // Ranarr Weed - DEFENCE_POTION(ItemID.DEFENCE_POTION4, "Defence potion", Skill.HERBLORE, 30, 75, CriticalItem.RANARR_POTION_UNF, ActivitySecondaries.DEFENCE_POTION), - PRAYER_POTION(ItemID.PRAYER_POTION4, "Prayer potion", Skill.HERBLORE, 38, 87.5, CriticalItem.RANARR_POTION_UNF, ActivitySecondaries.PRAYER_POTION), - // Toadflax - AGILITY_POTION(ItemID.AGILITY_POTION4, "Agility potion", Skill.HERBLORE, 34, 80, CriticalItem.TOADFLAX_POTION_UNF, ActivitySecondaries.AGILITY_POTION), - SARADOMIN_BREW(ItemID.SARADOMIN_BREW4, "Saradomin brew", Skill.HERBLORE, 81, 180, CriticalItem.TOADFLAX_POTION_UNF, ActivitySecondaries.SARADOMIN_BREW), - // Irit - SUPER_ATTACK(ItemID.SUPER_ATTACK4, "Super attack", Skill.HERBLORE, 45, 100, CriticalItem.IRIT_POTION_UNF, ActivitySecondaries.SUPER_ATTACK), - SUPERANTIPOISON(ItemID.SUPERANTIPOISON4, "Superantipoison", Skill.HERBLORE, 48, 106.3, CriticalItem.IRIT_POTION_UNF, ActivitySecondaries.SUPERANTIPOISON), - // Avantoe - FISHING_POTION(ItemID.FISHING_POTION4, "Fishing potion", Skill.HERBLORE, 50, 112.5, CriticalItem.AVANTOE_POTION_UNF, ActivitySecondaries.FISHING_POTION), - SUPER_ENERGY_POTION(ItemID.SUPER_ENERGY3_20549, "Super energy potion", Skill.HERBLORE, 52, 117.5, CriticalItem.AVANTOE_POTION_UNF, ActivitySecondaries.SUPER_ENERGY_POTION), - HUNTER_POTION(ItemID.HUNTER_POTION4, "Hunter potion", Skill.HERBLORE, 53, 120, CriticalItem.AVANTOE_POTION_UNF, ActivitySecondaries.HUNTER_POTION), - // Kwuarm - SUPER_STRENGTH(ItemID.SUPER_STRENGTH4, "Super strength", Skill.HERBLORE, 55, 125, CriticalItem.KWUARM_POTION_UNF, ActivitySecondaries.SUPER_STRENGTH), - // Snapdragon - SUPER_RESTORE(ItemID.SUPER_RESTORE4, "Super restore", Skill.HERBLORE, 63, 142.5, CriticalItem.SNAPDRAGON_POTION_UNF, ActivitySecondaries.SUPER_RESTORE), - SANFEW_SERUM(ItemID.SANFEW_SERUM4, "Sanfew serum", Skill.HERBLORE, 65, 160, CriticalItem.SNAPDRAGON_POTION_UNF, ActivitySecondaries.SANFEW_SERUM), - // Cadantine - SUPER_DEFENCE_POTION(ItemID.SUPER_DEFENCE4, "Super defence", Skill.HERBLORE, 66, 150, CriticalItem.CADANTINE_POTION_UNF, ActivitySecondaries.SUPER_DEFENCE_POTION), - // Lantadyme - ANTIFIRE_POTION(ItemID.ANTIFIRE_POTION4, "Anti-fire potion", Skill.HERBLORE, 69, 157.5, CriticalItem.LANTADYME_POTION_UNF, ActivitySecondaries.ANTIFIRE_POTION), - MAGIC_POTION(ItemID.MAGIC_POTION4, "Magic potion", Skill.HERBLORE, 76, 172.5, CriticalItem.LANTADYME_POTION_UNF, ActivitySecondaries.MAGIC_POTION), - // Dwarf Weed - RANGING_POTION(ItemID.RANGING_POTION4, "Ranging potion", Skill.HERBLORE, 72, 162.5, CriticalItem.DWARF_WEED_POTION_UNF, ActivitySecondaries.RANGING_POTION), - // Torstol - TORSTOL_POTION_UNF(ItemID.TORSTOL_POTION_UNF, "Unfinished Potion", Skill.HERBLORE, 78, 0, CriticalItem.TORSTOL, ActivitySecondaries.UNFINISHED_POTION), - SUPER_COMBAT_POTION(ItemID.SUPER_COMBAT_POTION4, "Super combat", Skill.HERBLORE, 90, 150, CriticalItem.TORSTOL, ActivitySecondaries.SUPER_COMBAT_POTION, true), - ANTIVENOM_PLUS(ItemID.ANTIVENOM4_12913, "Anti-venom+", Skill.HERBLORE, 94, 125, CriticalItem.TORSTOL, ActivitySecondaries.ANTIVENOM_PLUS, true), - - ZAMORAK_BREW(ItemID.ZAMORAK_BREW4, "Zamorak brew", Skill.HERBLORE, 78, 175, CriticalItem.TORSTOL_POTION_UNF, ActivitySecondaries.ZAMORAK_BREW), - - // Cleaning Grimy Herbs - CLEAN_GUAM(ItemID.GUAM_LEAF, "Clean guam", Skill.HERBLORE, 3, 2.5, CriticalItem.GRIMY_GUAM_LEAF), - CLEAN_MARRENTILL(ItemID.MARRENTILL, "Clean marrentill", Skill.HERBLORE, 5, 3.8, CriticalItem.GRIMY_MARRENTILL), - CLEAN_TARROMIN(ItemID.TARROMIN, "Clean tarromin", Skill.HERBLORE, 11, 5, CriticalItem.GRIMY_TARROMIN), - CLEAN_HARRALANDER(ItemID.HARRALANDER, "Clean harralander", Skill.HERBLORE, 20, 6.3, CriticalItem.GRIMY_HARRALANDER), - CLEAN_RANARR_WEED(ItemID.RANARR_WEED, "Clean ranarr weed", Skill.HERBLORE, 25, 7.5, CriticalItem.GRIMY_RANARR_WEED), - CLEAN_TOADFLAX(ItemID.TOADFLAX, "Clean toadflax", Skill.HERBLORE, 30, 8, CriticalItem.GRIMY_TOADFLAX), - CLEAN_IRIT_LEAF(ItemID.IRIT_LEAF, "Clean irit leaf", Skill.HERBLORE, 40, 8.8, CriticalItem.GRIMY_IRIT_LEAF), - CLEAN_AVANTOE(ItemID.AVANTOE, "Clean avantoe", Skill.HERBLORE, 48, 10, CriticalItem.GRIMY_AVANTOE), - CLEAN_KWUARM(ItemID.KWUARM, "Clean kwuarm", Skill.HERBLORE, 54, 11.3, CriticalItem.GRIMY_KWUARM), - CLEAN_SNAPDRAGON(ItemID.SNAPDRAGON, "Clean snapdragon", Skill.HERBLORE, 59, 11.8, CriticalItem.GRIMY_SNAPDRAGON), - CLEAN_CADANTINE(ItemID.CADANTINE, "Clean cadantine", Skill.HERBLORE, 65, 12.5, CriticalItem.GRIMY_CADANTINE), - CLEAN_LANTADYME(ItemID.LANTADYME, "Clean lantadyme", Skill.HERBLORE, 67, 13.1, CriticalItem.GRIMY_LANTADYME), - CLEAN_DWARF_WEED(ItemID.DWARF_WEED, "Clean dwarf weed", Skill.HERBLORE, 70, 13.8, CriticalItem.GRIMY_DWARF_WEED), - CLEAN_TORSTOL(ItemID.TORSTOL, "Clean torstol", Skill.HERBLORE, 75, 15, CriticalItem.GRIMY_TORSTOL), - - /** - * Construction Options - */ - PLANKS(ItemID.PLANK , "Normal Plank Products", Skill.CONSTRUCTION, 1, 29, CriticalItem.PLANK), - OAK_PLANKS(ItemID.OAK_PLANK, "Normal Oak Products", Skill.CONSTRUCTION, 1, 60, CriticalItem.OAK_PLANK), - TEAK_PLANKS(ItemID.TEAK_PLANK, "Normal Teak Products", Skill.CONSTRUCTION, 1, 90, CriticalItem.TEAK_PLANK), - MYTHICAL_CAPE(ItemID.MYTHICAL_CAPE, "Mythical Cape Rakes", Skill.CONSTRUCTION, 1, 123.33, CriticalItem.TEAK_PLANK), - MAHOGANY_PLANKS(ItemID.MAHOGANY_PLANK, "Normal Mahogany Products", Skill.CONSTRUCTION, 1, 140, CriticalItem.MAHOGANY_PLANK), - - /** - * Prayer Options - */ - BONES(ItemID.BONES, "Bones", Skill.PRAYER, 1, 4.5, CriticalItem.BONES), - WOLF_BONES(ItemID.WOLF_BONES, "Bones", Skill.PRAYER, 1, 4.5, CriticalItem.WOLF_BONES), - BURNT_BONES(ItemID.BURNT_BONES, "Bones", Skill.PRAYER, 1, 4.5, CriticalItem.BURNT_BONES), - MONKEY_BONES(ItemID.MONKEY_BONES, "Bones", Skill.PRAYER, 1, 5.0, CriticalItem.MONKEY_BONES), - BAT_BONES(ItemID.BAT_BONES, "Bones", Skill.PRAYER, 1, 5.3, CriticalItem.BAT_BONES), - JOGRE_BONES(ItemID.JOGRE_BONES, "Bones", Skill.PRAYER, 1, 15.0, CriticalItem.JOGRE_BONES), - BIG_BONES(ItemID.BIG_BONES, "Bones", Skill.PRAYER, 1, 15.0, CriticalItem.BIG_BONES), - ZOGRE_BONES(ItemID.ZOGRE_BONES, "Bones", Skill.PRAYER, 1, 22.5, CriticalItem.ZOGRE_BONES), - SHAIKAHAN_BONES(ItemID.SHAIKAHAN_BONES, "Bones", Skill.PRAYER, 1, 25.0, CriticalItem.SHAIKAHAN_BONES), - BABYDRAGON_BONES(ItemID.BABYDRAGON_BONES, "Bones", Skill.PRAYER, 1, 30.0, CriticalItem.BABYDRAGON_BONES), - WYVERN_BONES(ItemID.WYVERN_BONES, "Bones", Skill.PRAYER, 1, 72.0, CriticalItem.WYVERN_BONES), - DRAGON_BONES(ItemID.DRAGON_BONES, "Bones", Skill.PRAYER, 1, 72.0, CriticalItem.DRAGON_BONES), - FAYRG_BONES(ItemID.FAYRG_BONES, "Bones", Skill.PRAYER, 1, 84.0, CriticalItem.FAYRG_BONES), - LAVA_DRAGON_BONES(ItemID.LAVA_DRAGON_BONES, "Bones", Skill.PRAYER, 1, 85.0, CriticalItem.LAVA_DRAGON_BONES), - RAURG_BONES(ItemID.RAURG_BONES, "Bones", Skill.PRAYER, 1, 96.0, CriticalItem.RAURG_BONES), - DAGANNOTH_BONES(ItemID.DAGANNOTH_BONES, "Bones", Skill.PRAYER, 1, 125.0, CriticalItem.DAGANNOTH_BONES), - OURG_BONES(ItemID.OURG_BONES, "Bones", Skill.PRAYER, 1, 140.0, CriticalItem.OURG_BONES), - SUPERIOR_DRAGON_BONES(ItemID.SUPERIOR_DRAGON_BONES, "Bones", Skill.PRAYER, 1, 150.0, CriticalItem.SUPERIOR_DRAGON_BONES), - // Shade Remains (Pyre Logs) - LOAR_REMAINS(ItemID.LOAR_REMAINS, "Shades", Skill.PRAYER, 1, 33.0, CriticalItem.LOAR_REMAINS), - PHRIN_REMAINS(ItemID.PHRIN_REMAINS, "Shades", Skill.PRAYER, 1, 46.5, CriticalItem.PHRIN_REMAINS), - RIYL_REMAINS(ItemID.RIYL_REMAINS, "Shades", Skill.PRAYER, 1, 59.5, CriticalItem.RIYL_REMAINS), - ASYN_REMAINS(ItemID.ASYN_REMAINS, "Shades", Skill.PRAYER, 1, 82.5, CriticalItem.ASYN_REMAINS), - FIYR_REMAINS(ItemID.FIYR_REMAINS, "Shades", Skill.PRAYER, 1, 84.0, CriticalItem.FIYR_REMAINS), - // Ensouled Heads - ENSOULED_GOBLIN_HEAD(ItemID.ENSOULED_GOBLIN_HEAD_13448, "Ensouled Heads", Skill.PRAYER, 1, 130.0, CriticalItem.ENSOULED_GOBLIN_HEAD), - ENSOULED_MONKEY_HEAD(ItemID.ENSOULED_MONKEY_HEAD_13451, "Ensouled Heads", Skill.PRAYER, 1, 182.0, CriticalItem.ENSOULED_MONKEY_HEAD), - ENSOULED_IMP_HEAD(ItemID.ENSOULED_IMP_HEAD_13454, "Ensouled Heads", Skill.PRAYER, 1, 286.0, CriticalItem.ENSOULED_IMP_HEAD), - ENSOULED_MINOTAUR_HEAD(ItemID.ENSOULED_MINOTAUR_HEAD_13457, "Ensouled Heads", Skill.PRAYER, 1, 364.0, CriticalItem.ENSOULED_MINOTAUR_HEAD), - ENSOULED_SCORPION_HEAD(ItemID.ENSOULED_SCORPION_HEAD_13460, "Ensouled Heads", Skill.PRAYER, 1, 454.0, CriticalItem.ENSOULED_SCORPION_HEAD), - ENSOULED_BEAR_HEAD(ItemID.ENSOULED_BEAR_HEAD_13463, "Ensouled Heads", Skill.PRAYER, 1, 480.0, CriticalItem.ENSOULED_BEAR_HEAD), - ENSOULED_UNICORN_HEAD(ItemID.ENSOULED_UNICORN_HEAD_13466, "Ensouled Heads", Skill.PRAYER, 1, 494.0, CriticalItem.ENSOULED_UNICORN_HEAD), - ENSOULED_DOG_HEAD(ItemID.ENSOULED_DOG_HEAD_13469, "Ensouled Heads", Skill.PRAYER, 1, 520.0, CriticalItem.ENSOULED_DOG_HEAD), - ENSOULED_CHAOS_DRUID_HEAD(ItemID.ENSOULED_CHAOS_DRUID_HEAD_13472, "Ensouled Heads", Skill.PRAYER, 1, 584.0, CriticalItem.ENSOULED_CHAOS_DRUID_HEAD), - ENSOULED_GIANT_HEAD(ItemID.ENSOULED_GIANT_HEAD_13475, "Ensouled Heads", Skill.PRAYER, 1, 650.0, CriticalItem.ENSOULED_GIANT_HEAD), - ENSOULED_OGRE_HEAD(ItemID.ENSOULED_OGRE_HEAD_13478, "Ensouled Heads", Skill.PRAYER, 1, 716.0, CriticalItem.ENSOULED_OGRE_HEAD), - ENSOULED_ELF_HEAD(ItemID.ENSOULED_ELF_HEAD_13481, "Ensouled Heads", Skill.PRAYER, 1, 754.0, CriticalItem.ENSOULED_ELF_HEAD), - ENSOULED_TROLL_HEAD(ItemID.ENSOULED_TROLL_HEAD_13484, "Ensouled Heads", Skill.PRAYER, 1, 780.0, CriticalItem.ENSOULED_TROLL_HEAD), - ENSOULED_HORROR_HEAD(ItemID.ENSOULED_HORROR_HEAD_13487, "Ensouled Heads", Skill.PRAYER, 1, 832.0, CriticalItem.ENSOULED_HORROR_HEAD), - ENSOULED_KALPHITE_HEAD(ItemID.ENSOULED_KALPHITE_HEAD_13490, "Ensouled Heads", Skill.PRAYER, 1, 884.0, CriticalItem.ENSOULED_KALPHITE_HEAD), - ENSOULED_DAGANNOTH_HEAD(ItemID.ENSOULED_DAGANNOTH_HEAD_13493, "Ensouled Heads", Skill.PRAYER, 1, 936.0, CriticalItem.ENSOULED_DAGANNOTH_HEAD), - ENSOULED_BLOODVELD_HEAD(ItemID.ENSOULED_BLOODVELD_HEAD_13496, "Ensouled Heads", Skill.PRAYER, 1, 1040.0, CriticalItem.ENSOULED_BLOODVELD_HEAD), - ENSOULED_TZHAAR_HEAD(ItemID.ENSOULED_TZHAAR_HEAD_13499, "Ensouled Heads", Skill.PRAYER, 1, 1104.0, CriticalItem.ENSOULED_TZHAAR_HEAD), - ENSOULED_DEMON_HEAD(ItemID.ENSOULED_DEMON_HEAD_13502, "Ensouled Heads", Skill.PRAYER, 1, 1170.0, CriticalItem.ENSOULED_DEMON_HEAD), - ENSOULED_AVIANSIE_HEAD(ItemID.ENSOULED_AVIANSIE_HEAD_13505, "Ensouled Heads", Skill.PRAYER, 1, 1234.0, CriticalItem.ENSOULED_AVIANSIE_HEAD), - ENSOULED_ABYSSAL_HEAD(ItemID.ENSOULED_ABYSSAL_HEAD_13508, "Ensouled Heads", Skill.PRAYER, 1, 1300.0, CriticalItem.ENSOULED_ABYSSAL_HEAD), - ENSOULED_DRAGON_HEAD(ItemID.ENSOULED_DRAGON_HEAD_13511, "Ensouled Heads", Skill.PRAYER, 1, 1560.0, CriticalItem.ENSOULED_DRAGON_HEAD), - - /* - * Cooking Items - */ - RAW_HERRING(ItemID.RAW_HERRING, "Fish", Skill.COOKING, 5, 50.0, CriticalItem.RAW_HERRING), - RAW_MACKEREL(ItemID.RAW_MACKEREL, "Fish", Skill.COOKING, 10, 60.0, CriticalItem.RAW_MACKEREL), - RAW_TROUT(ItemID.RAW_TROUT, "Fish", Skill.COOKING, 15, 70.0, CriticalItem.RAW_TROUT), - RAW_COD(ItemID.RAW_COD, "Fish", Skill.COOKING, 18, 75.0, CriticalItem.RAW_COD), - RAW_PIKE(ItemID.RAW_PIKE, "Fish", Skill.COOKING, 20, 80.0, CriticalItem.RAW_PIKE), - RAW_SALMON(ItemID.RAW_SALMON, "Fish", Skill.COOKING, 25, 90.0, CriticalItem.RAW_SALMON), - RAW_TUNA(ItemID.RAW_TUNA, "Fish", Skill.COOKING, 30, 100.0, CriticalItem.RAW_TUNA), - RAW_KARAMBWAN(ItemID.RAW_KARAMBWAN, "Fish", Skill.COOKING, 30, 190.0, CriticalItem.RAW_KARAMBWAN), - RAW_LOBSTER(ItemID.RAW_LOBSTER, "Fish", Skill.COOKING, 40, 120.0, CriticalItem.RAW_LOBSTER), - RAW_BASS(ItemID.RAW_BASS, "Fish", Skill.COOKING, 43, 130.0, CriticalItem.RAW_BASS), - RAW_SWORDFISH(ItemID.RAW_SWORDFISH, "Fish", Skill.COOKING, 45, 140.0, CriticalItem.RAW_SWORDFISH), - RAW_MONKFISH(ItemID.RAW_MONKFISH, "Fish", Skill.COOKING, 62, 150.0, CriticalItem.RAW_MONKFISH), - RAW_SHARK(ItemID.RAW_SHARK, "Fish", Skill.COOKING, 80, 210.0, CriticalItem.RAW_SHARK), - RAW_SEA_TURTLE(ItemID.RAW_SEA_TURTLE, "Fish", Skill.COOKING, 82, 211.3, CriticalItem.RAW_SEA_TURTLE), - RAW_ANGLERFISH(ItemID.RAW_ANGLERFISH, "Fish", Skill.COOKING, 84, 230.0, CriticalItem.RAW_ANGLERFISH), - RAW_DARK_CRAB(ItemID.RAW_DARK_CRAB, "Fish", Skill.COOKING, 90, 215.0, CriticalItem.RAW_DARK_CRAB), - RAW_MANTA_RAY(ItemID.RAW_MANTA_RAY, "Fish", Skill.COOKING, 91, 216.2, CriticalItem.RAW_MANTA_RAY), - - WINE(ItemID.JUG_OF_WINE, "Other", Skill.COOKING, 35, 200, CriticalItem.GRAPES, ActivitySecondaries.JUG_OF_WATER), - - /* - * Crafting Items - */ - // Spinning - BALL_OF_WOOL(ItemID.WOOL, "Misc", Skill.CRAFTING, 1, 2.5, CriticalItem.WOOL), - BOW_STRING(ItemID.BOW_STRING, "Misc", Skill.CRAFTING, 1, 15, CriticalItem.FLAX), - // Glass Blowing - BEER_GLASS(ItemID.BEER_GLASS, "Beer Glass", Skill.CRAFTING, 1, 17.5, CriticalItem.MOLTEN_GLASS), - CANDLE_LANTERN(ItemID.CANDLE_LANTERN, "Candle Lantern", Skill.CRAFTING, 4, 19, CriticalItem.MOLTEN_GLASS), - OIL_LAMP(ItemID.OIL_LAMP, "Oil Lamp", Skill.CRAFTING, 12, 25, CriticalItem.MOLTEN_GLASS), - VIAL(ItemID.VIAL, "Vial", Skill.CRAFTING, 33, 35, CriticalItem.MOLTEN_GLASS), - EMPTY_FISHBOWL(ItemID.EMPTY_FISHBOWL, "Empty fishbowl", Skill.CRAFTING, 42, 42.5, CriticalItem.MOLTEN_GLASS), - UNPOWERED_ORB(ItemID.UNPOWERED_ORB, "Unpowered orb", Skill.CRAFTING, 46, 52.5, CriticalItem.MOLTEN_GLASS), - LANTERN_LENS(ItemID.LANTERN_LENS, "Lantern lens", Skill.CRAFTING, 49, 55, CriticalItem.MOLTEN_GLASS), - LIGHT_ORB(ItemID.LIGHT_ORB, "Light orb", Skill.CRAFTING, 87, 70, CriticalItem.MOLTEN_GLASS), - // D'hide/Dragon Leather - GREEN_DRAGON_LEATHER(ItemID.GREEN_DRAGON_LEATHER, "D'hide", Skill.CRAFTING, 57, 62.0, CriticalItem.GREEN_DRAGON_LEATHER), - BLUE_DRAGON_LEATHER(ItemID.BLUE_DRAGON_LEATHER, "D'hide", Skill.CRAFTING, 66, 70.0, CriticalItem.BLUE_DRAGON_LEATHER), - RED_DRAGON_LEATHER(ItemID.RED_DRAGON_LEATHER, "D'hide", Skill.CRAFTING, 73, 78.0, CriticalItem.RED_DRAGON_LEATHER), - BLACK_DRAGON_LEATHER(ItemID.BLACK_DRAGON_LEATHER, "D'hide", Skill.CRAFTING, 79, 86.0, CriticalItem.BLACK_DRAGON_LEATHER), - // Uncut Gems - UNCUT_OPAL(ItemID.UNCUT_OPAL, "Gems", Skill.CRAFTING, 1, 15.0, CriticalItem.UNCUT_OPAL), - UNCUT_JADE(ItemID.UNCUT_JADE, "Gems", Skill.CRAFTING, 13, 20.0, CriticalItem.UNCUT_JADE), - UNCUT_RED_TOPAZ(ItemID.UNCUT_RED_TOPAZ, "Gems", Skill.CRAFTING, 16, 25.0, CriticalItem.UNCUT_RED_TOPAZ), - UNCUT_SAPPHIRE(ItemID.UNCUT_SAPPHIRE, "Gems", Skill.CRAFTING, 20, 50.0, CriticalItem.UNCUT_SAPPHIRE), - UNCUT_EMERALD(ItemID.UNCUT_EMERALD, "Gems", Skill.CRAFTING, 27, 67.5, CriticalItem.UNCUT_EMERALD), - UNCUT_RUBY(ItemID.UNCUT_RUBY, "Gems", Skill.CRAFTING, 34, 85, CriticalItem.UNCUT_RUBY), - UNCUT_DIAMOND(ItemID.UNCUT_DIAMOND, "Gems", Skill.CRAFTING, 43, 107.5, CriticalItem.UNCUT_DIAMOND), - UNCUT_DRAGONSTONE(ItemID.UNCUT_DRAGONSTONE, "Gems", Skill.CRAFTING, 55, 137.5, CriticalItem.UNCUT_DRAGONSTONE), - UNCUT_ONYX(ItemID.UNCUT_ONYX, "Gems", Skill.CRAFTING, 67, 167.5, CriticalItem.UNCUT_ONYX), - UNCUT_ZENYTE(ItemID.UNCUT_ZENYTE, "Gems", Skill.CRAFTING, 89, 200.0, CriticalItem.UNCUT_ZENYTE), - // Silver Jewelery - OPAL_RING(ItemID.OPAL_RING, "Opal ring", Skill.CRAFTING, 1 , 10, CriticalItem.OPAL, ActivitySecondaries.SILVER_BAR), - OPAL_NECKLACE(ItemID.OPAL_NECKLACE, "Opal necklace", Skill.CRAFTING, 16 , 35, CriticalItem.OPAL, ActivitySecondaries.SILVER_BAR), - OPAL_BRACELET(ItemID.OPAL_BRACELET, "Opal bracelet", Skill.CRAFTING, 22 , 45, CriticalItem.OPAL, ActivitySecondaries.SILVER_BAR), - OPAL_AMULET(ItemID.OPAL_AMULET, "Opal amulet", Skill.CRAFTING, 27 , 55, CriticalItem.OPAL, ActivitySecondaries.SILVER_BAR), - JADE_RING(ItemID.JADE_RING, "Jade ring", Skill.CRAFTING, 13 , 32, CriticalItem.JADE, ActivitySecondaries.SILVER_BAR), - JADE_NECKLACE(ItemID.JADE_NECKLACE, "Jade necklace", Skill.CRAFTING, 25 , 54, CriticalItem.JADE, ActivitySecondaries.SILVER_BAR), - JADE_BRACELET(ItemID.JADE_BRACELET, "Jade bracelet", Skill.CRAFTING, 29 , 60, CriticalItem.JADE, ActivitySecondaries.SILVER_BAR), - JADE_AMULET(ItemID.JADE_AMULET, "Jade amulet", Skill.CRAFTING, 34 , 70, CriticalItem.JADE, ActivitySecondaries.SILVER_BAR), - TOPAZ_RING(ItemID.TOPAZ_RING, "Topaz ring", Skill.CRAFTING, 16 , 35, CriticalItem.RED_TOPAZ, ActivitySecondaries.SILVER_BAR), - TOPAZ_NECKLACE(ItemID.TOPAZ_NECKLACE, "Topaz necklace", Skill.CRAFTING, 32 , 70, CriticalItem.RED_TOPAZ, ActivitySecondaries.SILVER_BAR), - TOPAZ_BRACELET(ItemID.TOPAZ_BRACELET, "Topaz bracelet", Skill.CRAFTING, 38 , 75, CriticalItem.RED_TOPAZ, ActivitySecondaries.SILVER_BAR), - TOPAZ_AMULET(ItemID.TOPAZ_AMULET, "Topaz amulet", Skill.CRAFTING, 45 , 80, CriticalItem.RED_TOPAZ, ActivitySecondaries.SILVER_BAR), - // Gold Jewelery - SAPPHIRE_RING(ItemID.SAPPHIRE_RING, "Sapphire ring", Skill.CRAFTING, 20 , 40, CriticalItem.SAPPHIRE, ActivitySecondaries.GOLD_BAR), - SAPPHIRE_NECKLACE(ItemID.SAPPHIRE_NECKLACE, "Sapphire necklace", Skill.CRAFTING, 22 , 55, CriticalItem.SAPPHIRE, ActivitySecondaries.GOLD_BAR), - SAPPHIRE_BRACELET(ItemID.SAPPHIRE_BRACELET, "Sapphire bracelet", Skill.CRAFTING, 23 , 60, CriticalItem.SAPPHIRE, ActivitySecondaries.GOLD_BAR), - SAPPHIRE_AMULET(ItemID.SAPPHIRE_AMULET, "Sapphire amulet", Skill.CRAFTING, 24 , 65, CriticalItem.SAPPHIRE, ActivitySecondaries.GOLD_BAR), - EMERALD_RING(ItemID.EMERALD_RING, "Emerald ring", Skill.CRAFTING, 27 , 55, CriticalItem.EMERALD, ActivitySecondaries.GOLD_BAR), - EMERALD_NECKLACE(ItemID.EMERALD_NECKLACE, "Emerald necklace", Skill.CRAFTING, 29 , 60, CriticalItem.EMERALD, ActivitySecondaries.GOLD_BAR), - EMERALD_BRACELET(ItemID.EMERALD_BRACELET, "Emerald bracelet", Skill.CRAFTING, 30 , 65, CriticalItem.EMERALD, ActivitySecondaries.GOLD_BAR), - EMERALD_AMULET(ItemID.EMERALD_AMULET, "Emerald amulet", Skill.CRAFTING, 31 , 70, CriticalItem.EMERALD, ActivitySecondaries.GOLD_BAR), - RUBY_RING(ItemID.RUBY_RING, "Ruby ring", Skill.CRAFTING, 34 , 70, CriticalItem.RUBY, ActivitySecondaries.GOLD_BAR), - RUBY_NECKLACE(ItemID.RUBY_NECKLACE, "Ruby necklace", Skill.CRAFTING, 40 , 75, CriticalItem.RUBY, ActivitySecondaries.GOLD_BAR), - RUBY_BRACELET(ItemID.RUBY_BRACELET, "Ruby bracelet", Skill.CRAFTING, 42 , 80, CriticalItem.RUBY, ActivitySecondaries.GOLD_BAR), - RUBY_AMULET(ItemID.RUBY_AMULET, "Ruby amulet", Skill.CRAFTING, 50 , 85, CriticalItem.RUBY, ActivitySecondaries.GOLD_BAR), - DIAMOND_RING(ItemID.DIAMOND_RING, "Diamond ring", Skill.CRAFTING, 43 , 85, CriticalItem.DIAMOND, ActivitySecondaries.GOLD_BAR), - DIAMOND_NECKLACE(ItemID.DIAMOND_NECKLACE, "Diamond necklace", Skill.CRAFTING, 56 , 90, CriticalItem.DIAMOND, ActivitySecondaries.GOLD_BAR), - DIAMOND_BRACELET(ItemID.DIAMOND_BRACELET, "Diamond bracelet", Skill.CRAFTING, 58 , 95, CriticalItem.DIAMOND, ActivitySecondaries.GOLD_BAR), - DIAMOND_AMULET(ItemID.DIAMOND_AMULET, "Diamond amulet", Skill.CRAFTING, 70 , 100, CriticalItem.DIAMOND, ActivitySecondaries.GOLD_BAR), - DRAGONSTONE_RING(ItemID.DRAGONSTONE_RING, "Dragonstone ring", Skill.CRAFTING, 55 , 100, CriticalItem.DRAGONSTONE, ActivitySecondaries.GOLD_BAR), - DRAGON_NECKLACE(ItemID.DRAGON_NECKLACE, "Dragon necklace", Skill.CRAFTING, 72 , 105, CriticalItem.DRAGONSTONE, ActivitySecondaries.GOLD_BAR), - DRAGONSTONE_BRACELET(ItemID.DRAGONSTONE_BRACELET, "Dragonstone bracelet", Skill.CRAFTING, 74 , 110, CriticalItem.DRAGONSTONE, ActivitySecondaries.GOLD_BAR), - DRAGONSTONE_AMULET(ItemID.DRAGONSTONE_AMULET, "Dragonstone amulet", Skill.CRAFTING, 80 , 150, CriticalItem.DRAGONSTONE, ActivitySecondaries.GOLD_BAR), - ONYX_RING(ItemID.ONYX_RING, "Onyx ring", Skill.CRAFTING, 67 , 115, CriticalItem.ONYX, ActivitySecondaries.GOLD_BAR), - ONYX_NECKLACE(ItemID.ONYX_NECKLACE, "Onyx necklace", Skill.CRAFTING, 82 , 120, CriticalItem.ONYX, ActivitySecondaries.GOLD_BAR), - REGEN_BRACELET(ItemID.REGEN_BRACELET, "Regen bracelet", Skill.CRAFTING, 84 , 125, CriticalItem.ONYX, ActivitySecondaries.GOLD_BAR), - ONYX_AMULET(ItemID.ONYX_AMULET, "Onyx amulet", Skill.CRAFTING, 90 , 165, CriticalItem.ONYX, ActivitySecondaries.GOLD_BAR), - ZENYTE_RING(ItemID.ZENYTE_RING, "Zenyte ring", Skill.CRAFTING, 89 , 150, CriticalItem.ZENYTE, ActivitySecondaries.GOLD_BAR), - ZENYTE_NECKLACE(ItemID.ZENYTE_NECKLACE, "Zenyte necklace", Skill.CRAFTING, 92 , 165, CriticalItem.ZENYTE, ActivitySecondaries.GOLD_BAR), - ZENYTE_BRACELET(ItemID.ZENYTE_BRACELET, "Zenyte bracelet", Skill.CRAFTING, 95 , 180, CriticalItem.ZENYTE, ActivitySecondaries.GOLD_BAR), - ZENYTE_AMULET(ItemID.ZENYTE_AMULET, "Zenyte amulet", Skill.CRAFTING, 98 , 200 , CriticalItem.ZENYTE, ActivitySecondaries.GOLD_BAR), - // Battle Staves - WATER_BATTLESTAFF(ItemID.WATER_BATTLESTAFF, "Water battlestaff", Skill.CRAFTING, 54, 100, CriticalItem.BATTLESTAFF, ActivitySecondaries.WATER_ORB), - EARTH_BATTLESTAFF(ItemID.EARTH_BATTLESTAFF, "Earth battlestaff", Skill.CRAFTING, 58, 112.5, CriticalItem.BATTLESTAFF, ActivitySecondaries.EARTH_ORB), - FIRE_BATTLESTAFF(ItemID.FIRE_BATTLESTAFF, "Fire battlestaff", Skill.CRAFTING, 62, 125, CriticalItem.BATTLESTAFF, ActivitySecondaries.FIRE_ORB), - AIR_BATTLESTAFF(ItemID.AIR_BATTLESTAFF, "Air battlestaff", Skill.CRAFTING, 66, 137.5, CriticalItem.BATTLESTAFF, ActivitySecondaries.AIR_ORB), - - /* - * Smithing Items - */ - - // Smelting ores (Furnace) - IRON_ORE(ItemID.IRON_BAR, "Iron Bars", Skill.SMITHING, 15, 12.5, CriticalItem.IRON_ORE, ActivitySecondaries.COAL_ORE), - STEEL_ORE(ItemID.STEEL_BAR, "Steel Bars", Skill.SMITHING, 30, 17.5, CriticalItem.IRON_ORE, ActivitySecondaries.COAL_ORE_2), - SILVER_ORE(ItemID.SILVER_ORE, "Bar", Skill.SMITHING, 20, 13.67, CriticalItem.SILVER_ORE), - GOLD_ORE(ItemID.GOLD_BAR, "Regular exp", Skill.SMITHING, 40, 22.5, CriticalItem.GOLD_ORE), - GOLD_ORE_GAUNTLETS(ItemID.GOLDSMITH_GAUNTLETS, "Goldsmith Gauntlets", Skill.SMITHING, 40, 56.2, CriticalItem.GOLD_ORE), - MITHRIL_ORE(ItemID.MITHRIL_ORE, "Bar", Skill.SMITHING, 50, 30, CriticalItem.MITHRIL_ORE, ActivitySecondaries.COAL_ORE_4), - ADAMANTITE_ORE(ItemID.ADAMANTITE_ORE, "Bar", Skill.SMITHING, 70, 37.5, CriticalItem.ADAMANTITE_ORE, ActivitySecondaries.COAL_ORE_6), - RUNITE_ORE(ItemID.RUNITE_ORE, "Bar", Skill.SMITHING, 85, 50, CriticalItem.RUNITE_ORE, ActivitySecondaries.COAL_ORE_8), - - // Smelting bars (Anvil) - BRONZE_BAR(ItemID.BRONZE_BAR, "Bars", Skill.SMITHING, 1, 12.5, CriticalItem.BRONZE_BAR), - IRON_BAR(ItemID.IRON_BAR, "Bars", Skill.SMITHING, 15, 25.0, CriticalItem.IRON_BAR), - STEEL_BAR(ItemID.STEEL_BAR, "Steel Products", Skill.SMITHING, 30, 37.5, CriticalItem.STEEL_BAR), - CANNONBALLS(ItemID.CANNONBALL, "Cannonballs", Skill.SMITHING, 35, 25.5, CriticalItem.STEEL_BAR), - MITHRIL_BAR(ItemID.MITHRIL_BAR, "Bars", Skill.SMITHING, 50, 50.0, CriticalItem.MITHRIL_BAR), - ADAMANTITE_BAR(ItemID.ADAMANTITE_BAR, "Bars", Skill.SMITHING, 70, 62.5, CriticalItem.ADAMANTITE_BAR), - RUNITE_BAR(ItemID.RUNITE_BAR, "Bars", Skill.SMITHING, 85, 75.0, CriticalItem.RUNITE_BAR), - - /** - * Farming Items - */ - ACORN(ItemID.ACORN, "Seeds", Skill.FARMING, 15, 481.3, CriticalItem.ACORN), - WILLOW_SEED(ItemID.WILLOW_SEED, "Seeds", Skill.FARMING, 30, 1481.5, CriticalItem.WILLOW_SEED), - MAPLE_SEED(ItemID.MAPLE_SEED, "Seeds", Skill.FARMING, 45, 3448.4, CriticalItem.MAPLE_SEED), - YEW_SEED(ItemID.YEW_SEED, "Seeds", Skill.FARMING, 60, 7150.9, CriticalItem.YEW_SEED), - MAGIC_SEED(ItemID.MAGIC_SEED, "Seeds", Skill.FARMING, 75, 13913.8, CriticalItem.MAGIC_SEED), - APPLE_TREE_SEED(ItemID.APPLE_TREE_SEED, "Seeds", Skill.FARMING, 27, 1272.5, CriticalItem.APPLE_TREE_SEED), - BANANA_TREE_SEED(ItemID.BANANA_TREE_SEED, "Seeds", Skill.FARMING, 33, 1841.5, CriticalItem.BANANA_TREE_SEED), - ORANGE_TREE_SEED(ItemID.ORANGE_TREE_SEED, "Seeds", Skill.FARMING, 39, 2586.7, CriticalItem.ORANGE_TREE_SEED), - CURRY_TREE_SEED(ItemID.CURRY_TREE_SEED, "Seeds", Skill.FARMING, 42, 3036.9, CriticalItem.CURRY_TREE_SEED), - PINEAPPLE_SEED(ItemID.PINEAPPLE_SEED, "Seeds", Skill.FARMING, 51, 4791.7, CriticalItem.PINEAPPLE_SEED), - PAPAYA_TREE_SEED(ItemID.PAPAYA_TREE_SEED, "Seeds", Skill.FARMING, 57, 6380.4, CriticalItem.PAPAYA_TREE_SEED), - PALM_TREE_SEED(ItemID.PALM_TREE_SEED, "Seeds", Skill.FARMING, 68, 10509.6, CriticalItem.PALM_TREE_SEED), - CALQUAT_TREE_SEED(ItemID.CALQUAT_TREE_SEED, "Seeds", Skill.FARMING, 72, 12516.5, CriticalItem.CALQUAT_TREE_SEED), - TEAK_SEED(ItemID.TEAK_SEED, "Seeds", Skill.FARMING, 35, 7325, CriticalItem.TEAK_SEED), - MAHOGANY_SEED(ItemID.MAHOGANY_SEED, "Seeds", Skill.FARMING, 55, 15783, CriticalItem.MAHOGANY_SEED), - SPIRIT_SEED(ItemID.SPIRIT_SEED, "Seeds", Skill.FARMING, 83, 19500, CriticalItem.SPIRIT_SEED), - ; - - private final int icon; - private final String name; - private final Skill skill; - private final int level; - private final double xp; - private final SecondaryItem[] secondaries; - private final CriticalItem criticalItem; - private final boolean preventLinked; - - Activity(int Icon, String name, Skill skill, int level, double xp, CriticalItem criticalItem) - { - this.icon = Icon; - this.name = name; - this.skill = skill; - this.level = level; - this.xp = xp; - this.criticalItem = criticalItem; - this.secondaries = new SecondaryItem[0]; - this.preventLinked = false; - } - - Activity(int Icon, String name, Skill skill, int level, double xp, CriticalItem criticalItem, ActivitySecondaries secondaries) - { - this.icon = Icon; - this.name = name; - this.skill = skill; - this.level = level; - this.xp = xp; - this.criticalItem = criticalItem; - this.secondaries = secondaries == null ? new SecondaryItem[0] : secondaries.getItems(); - this.preventLinked = false; - } - - Activity(int Icon, String name, Skill skill, int level, double xp, CriticalItem criticalItem, ActivitySecondaries secondaries, boolean preventLinked) - { - this.icon = Icon; - this.name = name; - this.skill = skill; - this.level = level; - this.xp = xp; - this.criticalItem = criticalItem; - this.secondaries = secondaries == null ? new SecondaryItem[0] : secondaries.getItems(); - this.preventLinked = preventLinked; - } - - // Builds a Map to reduce looping frequency - private static Map> buildItemMap() - { - Map> map = new HashMap<>(); - for (Activity item : values()) - { - map.computeIfAbsent(item.getCriticalItem(), e -> new ArrayList()).add(item); - } - - return map; - } - private static final Map> byCriticalItem = buildItemMap(); - public static ArrayList getByCriticalItem(CriticalItem item) - { - - return byCriticalItem.getOrDefault(item, new ArrayList<>()); - } - - /** - * Get all Activities for this CriticalItem - * @param item CriticalItem to check for - * @param limitLevel Level to check Activitiy requirements against. -1 or 0 value disables limits - * @return an empty list if no activities - */ - public static ArrayList getByCriticalItem(CriticalItem item, int limitLevel) - { - ArrayList activities = getByCriticalItem(item); - ArrayList l = new ArrayList<>(); - if (limitLevel <= 0) - { - return l; - } - - for (Activity a : activities) - { - if (!(a.getLevel() > limitLevel)) - { - l.add(a); - } - } - - return l; - } -} +/* + * Copyright (c) 2018, 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.skillcalculator.banked.beans; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Map; +import lombok.Getter; +import net.runelite.api.ItemID; +import net.runelite.api.Skill; +import net.runelite.client.plugins.skillcalculator.banked.CriticalItem; + +@Getter +public enum Activity +{ + /** + * Herblore Activities + */ + // Creating Potions + // Guam + GUAM_POTION_UNF(ItemID.GUAM_POTION_UNF, "Unfinished Potion", Skill.HERBLORE, 1, 0, CriticalItem.GUAM_LEAF, ActivitySecondaries.UNFINISHED_POTION), + GUAM_TAR(ItemID.GUAM_TAR, "Guam tar", Skill.HERBLORE, 19, 30, CriticalItem.GUAM_LEAF, ActivitySecondaries.SWAMP_TAR, true), + + ATTACK_POTION(ItemID.ATTACK_POTION4, "Attack Potion", Skill.HERBLORE, 3, 25, CriticalItem.GUAM_LEAF_POTION_UNF, ActivitySecondaries.ATTACK_POTION), + // Marrentil + MARRENTILL_POTION_UNF(ItemID.MARRENTILL_POTION_UNF, "Unfinished Potion", Skill.HERBLORE, 1, 0, CriticalItem.MARRENTILL, ActivitySecondaries.UNFINISHED_POTION), + MARRENTILL_TAR(ItemID.MARRENTILL_TAR, "Marrentill tar", Skill.HERBLORE, 31, 42.5, CriticalItem.MARRENTILL, ActivitySecondaries.SWAMP_TAR, true), + + ANTIPOISON(ItemID.ANTIPOISON4, "Antipoison", Skill.HERBLORE, 5, 37.5, CriticalItem.MARRENTILL_POTION_UNF, ActivitySecondaries.ANTIPOISON), + // Tarromin + TARROMIN_POTION_UNF(ItemID.TARROMIN_POTION_UNF, "Unfinished Potion", Skill.HERBLORE, 1, 0, CriticalItem.TARROMIN, ActivitySecondaries.UNFINISHED_POTION), + TARROMIN_TAR(ItemID.TARROMIN_TAR, "Tarromin tar", Skill.HERBLORE, 39, 55, CriticalItem.TARROMIN, ActivitySecondaries.SWAMP_TAR, true), + + STRENGTH_POTION(ItemID.STRENGTH_POTION4, "Strength potion", Skill.HERBLORE, 12, 50, CriticalItem.TARROMIN_POTION_UNF, ActivitySecondaries.STRENGTH_POTION), + SERUM_207(ItemID.SERUM_207_4, "Serum 207", Skill.HERBLORE, 15, 50, CriticalItem.TARROMIN_POTION_UNF, ActivitySecondaries.SERUM_207), + // Harralander + HARRALANDER_POTION_UNF(ItemID.HARRALANDER_POTION_UNF, "Unfinished Potion", Skill.HERBLORE, 1, 0, CriticalItem.HARRALANDER, ActivitySecondaries.UNFINISHED_POTION), + HARRALANDER_TAR(ItemID.HARRALANDER_TAR, "Harralander tar", Skill.HERBLORE, 44, 72.5, CriticalItem.HARRALANDER, ActivitySecondaries.SWAMP_TAR, true), + + COMPOST_POTION(ItemID.COMPOST_POTION4, "Compost potion", Skill.HERBLORE, 21, 60, CriticalItem.HARRALANDER_POTION_UNF, ActivitySecondaries.COMPOST_POTION), + RESTORE_POTION(ItemID.RESTORE_POTION4, "Restore potion", Skill.HERBLORE, 22, 62.5, CriticalItem.HARRALANDER_POTION_UNF, ActivitySecondaries.RESTORE_POTION), + ENERGY_POTION(ItemID.ENERGY_POTION4, "Energy potion", Skill.HERBLORE, 26, 67.5, CriticalItem.HARRALANDER_POTION_UNF, ActivitySecondaries.ENERGY_POTION), + COMBAT_POTION(ItemID.COMBAT_POTION4, "Combat potion", Skill.HERBLORE, 36, 84, CriticalItem.HARRALANDER_POTION_UNF, ActivitySecondaries.COMBAT_POTION), + // Ranarr Weed + DEFENCE_POTION(ItemID.DEFENCE_POTION4, "Defence potion", Skill.HERBLORE, 30, 75, CriticalItem.RANARR_POTION_UNF, ActivitySecondaries.DEFENCE_POTION), + PRAYER_POTION(ItemID.PRAYER_POTION4, "Prayer potion", Skill.HERBLORE, 38, 87.5, CriticalItem.RANARR_POTION_UNF, ActivitySecondaries.PRAYER_POTION), + // Toadflax + AGILITY_POTION(ItemID.AGILITY_POTION4, "Agility potion", Skill.HERBLORE, 34, 80, CriticalItem.TOADFLAX_POTION_UNF, ActivitySecondaries.AGILITY_POTION), + SARADOMIN_BREW(ItemID.SARADOMIN_BREW4, "Saradomin brew", Skill.HERBLORE, 81, 180, CriticalItem.TOADFLAX_POTION_UNF, ActivitySecondaries.SARADOMIN_BREW), + // Irit + SUPER_ATTACK(ItemID.SUPER_ATTACK4, "Super attack", Skill.HERBLORE, 45, 100, CriticalItem.IRIT_POTION_UNF, ActivitySecondaries.SUPER_ATTACK), + SUPERANTIPOISON(ItemID.SUPERANTIPOISON4, "Superantipoison", Skill.HERBLORE, 48, 106.3, CriticalItem.IRIT_POTION_UNF, ActivitySecondaries.SUPERANTIPOISON), + // Avantoe + FISHING_POTION(ItemID.FISHING_POTION4, "Fishing potion", Skill.HERBLORE, 50, 112.5, CriticalItem.AVANTOE_POTION_UNF, ActivitySecondaries.FISHING_POTION), + SUPER_ENERGY_POTION(ItemID.SUPER_ENERGY3_20549, "Super energy potion", Skill.HERBLORE, 52, 117.5, CriticalItem.AVANTOE_POTION_UNF, ActivitySecondaries.SUPER_ENERGY_POTION), + HUNTER_POTION(ItemID.HUNTER_POTION4, "Hunter potion", Skill.HERBLORE, 53, 120, CriticalItem.AVANTOE_POTION_UNF, ActivitySecondaries.HUNTER_POTION), + // Kwuarm + SUPER_STRENGTH(ItemID.SUPER_STRENGTH4, "Super strength", Skill.HERBLORE, 55, 125, CriticalItem.KWUARM_POTION_UNF, ActivitySecondaries.SUPER_STRENGTH), + // Snapdragon + SUPER_RESTORE(ItemID.SUPER_RESTORE4, "Super restore", Skill.HERBLORE, 63, 142.5, CriticalItem.SNAPDRAGON_POTION_UNF, ActivitySecondaries.SUPER_RESTORE), + SANFEW_SERUM(ItemID.SANFEW_SERUM4, "Sanfew serum", Skill.HERBLORE, 65, 160, CriticalItem.SNAPDRAGON_POTION_UNF, ActivitySecondaries.SANFEW_SERUM), + // Cadantine + SUPER_DEFENCE_POTION(ItemID.SUPER_DEFENCE4, "Super defence", Skill.HERBLORE, 66, 150, CriticalItem.CADANTINE_POTION_UNF, ActivitySecondaries.SUPER_DEFENCE_POTION), + // Lantadyme + ANTIFIRE_POTION(ItemID.ANTIFIRE_POTION4, "Anti-fire potion", Skill.HERBLORE, 69, 157.5, CriticalItem.LANTADYME_POTION_UNF, ActivitySecondaries.ANTIFIRE_POTION), + MAGIC_POTION(ItemID.MAGIC_POTION4, "Magic potion", Skill.HERBLORE, 76, 172.5, CriticalItem.LANTADYME_POTION_UNF, ActivitySecondaries.MAGIC_POTION), + // Dwarf Weed + RANGING_POTION(ItemID.RANGING_POTION4, "Ranging potion", Skill.HERBLORE, 72, 162.5, CriticalItem.DWARF_WEED_POTION_UNF, ActivitySecondaries.RANGING_POTION), + // Torstol + TORSTOL_POTION_UNF(ItemID.TORSTOL_POTION_UNF, "Unfinished Potion", Skill.HERBLORE, 78, 0, CriticalItem.TORSTOL, ActivitySecondaries.UNFINISHED_POTION), + SUPER_COMBAT_POTION(ItemID.SUPER_COMBAT_POTION4, "Super combat", Skill.HERBLORE, 90, 150, CriticalItem.TORSTOL, ActivitySecondaries.SUPER_COMBAT_POTION, true), + ANTIVENOM_PLUS(ItemID.ANTIVENOM4_12913, "Anti-venom+", Skill.HERBLORE, 94, 125, CriticalItem.TORSTOL, ActivitySecondaries.ANTIVENOM_PLUS, true), + + ZAMORAK_BREW(ItemID.ZAMORAK_BREW4, "Zamorak brew", Skill.HERBLORE, 78, 175, CriticalItem.TORSTOL_POTION_UNF, ActivitySecondaries.ZAMORAK_BREW), + + // Cleaning Grimy Herbs + CLEAN_GUAM(ItemID.GUAM_LEAF, "Clean guam", Skill.HERBLORE, 3, 2.5, CriticalItem.GRIMY_GUAM_LEAF), + CLEAN_MARRENTILL(ItemID.MARRENTILL, "Clean marrentill", Skill.HERBLORE, 5, 3.8, CriticalItem.GRIMY_MARRENTILL), + CLEAN_TARROMIN(ItemID.TARROMIN, "Clean tarromin", Skill.HERBLORE, 11, 5, CriticalItem.GRIMY_TARROMIN), + CLEAN_HARRALANDER(ItemID.HARRALANDER, "Clean harralander", Skill.HERBLORE, 20, 6.3, CriticalItem.GRIMY_HARRALANDER), + CLEAN_RANARR_WEED(ItemID.RANARR_WEED, "Clean ranarr weed", Skill.HERBLORE, 25, 7.5, CriticalItem.GRIMY_RANARR_WEED), + CLEAN_TOADFLAX(ItemID.TOADFLAX, "Clean toadflax", Skill.HERBLORE, 30, 8, CriticalItem.GRIMY_TOADFLAX), + CLEAN_IRIT_LEAF(ItemID.IRIT_LEAF, "Clean irit leaf", Skill.HERBLORE, 40, 8.8, CriticalItem.GRIMY_IRIT_LEAF), + CLEAN_AVANTOE(ItemID.AVANTOE, "Clean avantoe", Skill.HERBLORE, 48, 10, CriticalItem.GRIMY_AVANTOE), + CLEAN_KWUARM(ItemID.KWUARM, "Clean kwuarm", Skill.HERBLORE, 54, 11.3, CriticalItem.GRIMY_KWUARM), + CLEAN_SNAPDRAGON(ItemID.SNAPDRAGON, "Clean snapdragon", Skill.HERBLORE, 59, 11.8, CriticalItem.GRIMY_SNAPDRAGON), + CLEAN_CADANTINE(ItemID.CADANTINE, "Clean cadantine", Skill.HERBLORE, 65, 12.5, CriticalItem.GRIMY_CADANTINE), + CLEAN_LANTADYME(ItemID.LANTADYME, "Clean lantadyme", Skill.HERBLORE, 67, 13.1, CriticalItem.GRIMY_LANTADYME), + CLEAN_DWARF_WEED(ItemID.DWARF_WEED, "Clean dwarf weed", Skill.HERBLORE, 70, 13.8, CriticalItem.GRIMY_DWARF_WEED), + CLEAN_TORSTOL(ItemID.TORSTOL, "Clean torstol", Skill.HERBLORE, 75, 15, CriticalItem.GRIMY_TORSTOL), + + /** + * Construction Options + */ + PLANKS(ItemID.PLANK, "Normal Plank Products", Skill.CONSTRUCTION, 1, 29, CriticalItem.PLANK), + OAK_PLANKS(ItemID.OAK_PLANK, "Normal Oak Products", Skill.CONSTRUCTION, 1, 60, CriticalItem.OAK_PLANK), + TEAK_PLANKS(ItemID.TEAK_PLANK, "Normal Teak Products", Skill.CONSTRUCTION, 1, 90, CriticalItem.TEAK_PLANK), + MYTHICAL_CAPE(ItemID.MYTHICAL_CAPE, "Mythical Cape Rakes", Skill.CONSTRUCTION, 1, 123.33, CriticalItem.TEAK_PLANK), + MAHOGANY_PLANKS(ItemID.MAHOGANY_PLANK, "Normal Mahogany Products", Skill.CONSTRUCTION, 1, 140, CriticalItem.MAHOGANY_PLANK), + + /** + * Prayer Options + */ + BONES(ItemID.BONES, "Bones", Skill.PRAYER, 1, 4.5, CriticalItem.BONES), + WOLF_BONES(ItemID.WOLF_BONES, "Bones", Skill.PRAYER, 1, 4.5, CriticalItem.WOLF_BONES), + BURNT_BONES(ItemID.BURNT_BONES, "Bones", Skill.PRAYER, 1, 4.5, CriticalItem.BURNT_BONES), + MONKEY_BONES(ItemID.MONKEY_BONES, "Bones", Skill.PRAYER, 1, 5.0, CriticalItem.MONKEY_BONES), + BAT_BONES(ItemID.BAT_BONES, "Bones", Skill.PRAYER, 1, 5.3, CriticalItem.BAT_BONES), + JOGRE_BONES(ItemID.JOGRE_BONES, "Bones", Skill.PRAYER, 1, 15.0, CriticalItem.JOGRE_BONES), + BIG_BONES(ItemID.BIG_BONES, "Bones", Skill.PRAYER, 1, 15.0, CriticalItem.BIG_BONES), + ZOGRE_BONES(ItemID.ZOGRE_BONES, "Bones", Skill.PRAYER, 1, 22.5, CriticalItem.ZOGRE_BONES), + SHAIKAHAN_BONES(ItemID.SHAIKAHAN_BONES, "Bones", Skill.PRAYER, 1, 25.0, CriticalItem.SHAIKAHAN_BONES), + BABYDRAGON_BONES(ItemID.BABYDRAGON_BONES, "Bones", Skill.PRAYER, 1, 30.0, CriticalItem.BABYDRAGON_BONES), + WYVERN_BONES(ItemID.WYVERN_BONES, "Bones", Skill.PRAYER, 1, 72.0, CriticalItem.WYVERN_BONES), + DRAGON_BONES(ItemID.DRAGON_BONES, "Bones", Skill.PRAYER, 1, 72.0, CriticalItem.DRAGON_BONES), + FAYRG_BONES(ItemID.FAYRG_BONES, "Bones", Skill.PRAYER, 1, 84.0, CriticalItem.FAYRG_BONES), + LAVA_DRAGON_BONES(ItemID.LAVA_DRAGON_BONES, "Bones", Skill.PRAYER, 1, 85.0, CriticalItem.LAVA_DRAGON_BONES), + RAURG_BONES(ItemID.RAURG_BONES, "Bones", Skill.PRAYER, 1, 96.0, CriticalItem.RAURG_BONES), + DAGANNOTH_BONES(ItemID.DAGANNOTH_BONES, "Bones", Skill.PRAYER, 1, 125.0, CriticalItem.DAGANNOTH_BONES), + OURG_BONES(ItemID.OURG_BONES, "Bones", Skill.PRAYER, 1, 140.0, CriticalItem.OURG_BONES), + SUPERIOR_DRAGON_BONES(ItemID.SUPERIOR_DRAGON_BONES, "Bones", Skill.PRAYER, 1, 150.0, CriticalItem.SUPERIOR_DRAGON_BONES), + // Shade Remains (Pyre Logs) + LOAR_REMAINS(ItemID.LOAR_REMAINS, "Shades", Skill.PRAYER, 1, 33.0, CriticalItem.LOAR_REMAINS), + PHRIN_REMAINS(ItemID.PHRIN_REMAINS, "Shades", Skill.PRAYER, 1, 46.5, CriticalItem.PHRIN_REMAINS), + RIYL_REMAINS(ItemID.RIYL_REMAINS, "Shades", Skill.PRAYER, 1, 59.5, CriticalItem.RIYL_REMAINS), + ASYN_REMAINS(ItemID.ASYN_REMAINS, "Shades", Skill.PRAYER, 1, 82.5, CriticalItem.ASYN_REMAINS), + FIYR_REMAINS(ItemID.FIYR_REMAINS, "Shades", Skill.PRAYER, 1, 84.0, CriticalItem.FIYR_REMAINS), + // Ensouled Heads + ENSOULED_GOBLIN_HEAD(ItemID.ENSOULED_GOBLIN_HEAD_13448, "Ensouled Heads", Skill.PRAYER, 1, 130.0, CriticalItem.ENSOULED_GOBLIN_HEAD), + ENSOULED_MONKEY_HEAD(ItemID.ENSOULED_MONKEY_HEAD_13451, "Ensouled Heads", Skill.PRAYER, 1, 182.0, CriticalItem.ENSOULED_MONKEY_HEAD), + ENSOULED_IMP_HEAD(ItemID.ENSOULED_IMP_HEAD_13454, "Ensouled Heads", Skill.PRAYER, 1, 286.0, CriticalItem.ENSOULED_IMP_HEAD), + ENSOULED_MINOTAUR_HEAD(ItemID.ENSOULED_MINOTAUR_HEAD_13457, "Ensouled Heads", Skill.PRAYER, 1, 364.0, CriticalItem.ENSOULED_MINOTAUR_HEAD), + ENSOULED_SCORPION_HEAD(ItemID.ENSOULED_SCORPION_HEAD_13460, "Ensouled Heads", Skill.PRAYER, 1, 454.0, CriticalItem.ENSOULED_SCORPION_HEAD), + ENSOULED_BEAR_HEAD(ItemID.ENSOULED_BEAR_HEAD_13463, "Ensouled Heads", Skill.PRAYER, 1, 480.0, CriticalItem.ENSOULED_BEAR_HEAD), + ENSOULED_UNICORN_HEAD(ItemID.ENSOULED_UNICORN_HEAD_13466, "Ensouled Heads", Skill.PRAYER, 1, 494.0, CriticalItem.ENSOULED_UNICORN_HEAD), + ENSOULED_DOG_HEAD(ItemID.ENSOULED_DOG_HEAD_13469, "Ensouled Heads", Skill.PRAYER, 1, 520.0, CriticalItem.ENSOULED_DOG_HEAD), + ENSOULED_CHAOS_DRUID_HEAD(ItemID.ENSOULED_CHAOS_DRUID_HEAD_13472, "Ensouled Heads", Skill.PRAYER, 1, 584.0, CriticalItem.ENSOULED_CHAOS_DRUID_HEAD), + ENSOULED_GIANT_HEAD(ItemID.ENSOULED_GIANT_HEAD_13475, "Ensouled Heads", Skill.PRAYER, 1, 650.0, CriticalItem.ENSOULED_GIANT_HEAD), + ENSOULED_OGRE_HEAD(ItemID.ENSOULED_OGRE_HEAD_13478, "Ensouled Heads", Skill.PRAYER, 1, 716.0, CriticalItem.ENSOULED_OGRE_HEAD), + ENSOULED_ELF_HEAD(ItemID.ENSOULED_ELF_HEAD_13481, "Ensouled Heads", Skill.PRAYER, 1, 754.0, CriticalItem.ENSOULED_ELF_HEAD), + ENSOULED_TROLL_HEAD(ItemID.ENSOULED_TROLL_HEAD_13484, "Ensouled Heads", Skill.PRAYER, 1, 780.0, CriticalItem.ENSOULED_TROLL_HEAD), + ENSOULED_HORROR_HEAD(ItemID.ENSOULED_HORROR_HEAD_13487, "Ensouled Heads", Skill.PRAYER, 1, 832.0, CriticalItem.ENSOULED_HORROR_HEAD), + ENSOULED_KALPHITE_HEAD(ItemID.ENSOULED_KALPHITE_HEAD_13490, "Ensouled Heads", Skill.PRAYER, 1, 884.0, CriticalItem.ENSOULED_KALPHITE_HEAD), + ENSOULED_DAGANNOTH_HEAD(ItemID.ENSOULED_DAGANNOTH_HEAD_13493, "Ensouled Heads", Skill.PRAYER, 1, 936.0, CriticalItem.ENSOULED_DAGANNOTH_HEAD), + ENSOULED_BLOODVELD_HEAD(ItemID.ENSOULED_BLOODVELD_HEAD_13496, "Ensouled Heads", Skill.PRAYER, 1, 1040.0, CriticalItem.ENSOULED_BLOODVELD_HEAD), + ENSOULED_TZHAAR_HEAD(ItemID.ENSOULED_TZHAAR_HEAD_13499, "Ensouled Heads", Skill.PRAYER, 1, 1104.0, CriticalItem.ENSOULED_TZHAAR_HEAD), + ENSOULED_DEMON_HEAD(ItemID.ENSOULED_DEMON_HEAD_13502, "Ensouled Heads", Skill.PRAYER, 1, 1170.0, CriticalItem.ENSOULED_DEMON_HEAD), + ENSOULED_AVIANSIE_HEAD(ItemID.ENSOULED_AVIANSIE_HEAD_13505, "Ensouled Heads", Skill.PRAYER, 1, 1234.0, CriticalItem.ENSOULED_AVIANSIE_HEAD), + ENSOULED_ABYSSAL_HEAD(ItemID.ENSOULED_ABYSSAL_HEAD_13508, "Ensouled Heads", Skill.PRAYER, 1, 1300.0, CriticalItem.ENSOULED_ABYSSAL_HEAD), + ENSOULED_DRAGON_HEAD(ItemID.ENSOULED_DRAGON_HEAD_13511, "Ensouled Heads", Skill.PRAYER, 1, 1560.0, CriticalItem.ENSOULED_DRAGON_HEAD), + + /* + * Cooking Items + */ + RAW_HERRING(ItemID.RAW_HERRING, "Fish", Skill.COOKING, 5, 50.0, CriticalItem.RAW_HERRING), + RAW_MACKEREL(ItemID.RAW_MACKEREL, "Fish", Skill.COOKING, 10, 60.0, CriticalItem.RAW_MACKEREL), + RAW_TROUT(ItemID.RAW_TROUT, "Fish", Skill.COOKING, 15, 70.0, CriticalItem.RAW_TROUT), + RAW_COD(ItemID.RAW_COD, "Fish", Skill.COOKING, 18, 75.0, CriticalItem.RAW_COD), + RAW_PIKE(ItemID.RAW_PIKE, "Fish", Skill.COOKING, 20, 80.0, CriticalItem.RAW_PIKE), + RAW_SALMON(ItemID.RAW_SALMON, "Fish", Skill.COOKING, 25, 90.0, CriticalItem.RAW_SALMON), + RAW_TUNA(ItemID.RAW_TUNA, "Fish", Skill.COOKING, 30, 100.0, CriticalItem.RAW_TUNA), + RAW_KARAMBWAN(ItemID.RAW_KARAMBWAN, "Fish", Skill.COOKING, 30, 190.0, CriticalItem.RAW_KARAMBWAN), + RAW_LOBSTER(ItemID.RAW_LOBSTER, "Fish", Skill.COOKING, 40, 120.0, CriticalItem.RAW_LOBSTER), + RAW_BASS(ItemID.RAW_BASS, "Fish", Skill.COOKING, 43, 130.0, CriticalItem.RAW_BASS), + RAW_SWORDFISH(ItemID.RAW_SWORDFISH, "Fish", Skill.COOKING, 45, 140.0, CriticalItem.RAW_SWORDFISH), + RAW_MONKFISH(ItemID.RAW_MONKFISH, "Fish", Skill.COOKING, 62, 150.0, CriticalItem.RAW_MONKFISH), + RAW_SHARK(ItemID.RAW_SHARK, "Fish", Skill.COOKING, 80, 210.0, CriticalItem.RAW_SHARK), + RAW_SEA_TURTLE(ItemID.RAW_SEA_TURTLE, "Fish", Skill.COOKING, 82, 211.3, CriticalItem.RAW_SEA_TURTLE), + RAW_ANGLERFISH(ItemID.RAW_ANGLERFISH, "Fish", Skill.COOKING, 84, 230.0, CriticalItem.RAW_ANGLERFISH), + RAW_DARK_CRAB(ItemID.RAW_DARK_CRAB, "Fish", Skill.COOKING, 90, 215.0, CriticalItem.RAW_DARK_CRAB), + RAW_MANTA_RAY(ItemID.RAW_MANTA_RAY, "Fish", Skill.COOKING, 91, 216.2, CriticalItem.RAW_MANTA_RAY), + + WINE(ItemID.JUG_OF_WINE, "Other", Skill.COOKING, 35, 200, CriticalItem.GRAPES, ActivitySecondaries.JUG_OF_WATER), + + /* + * Crafting Items + */ + // Spinning + BALL_OF_WOOL(ItemID.WOOL, "Misc", Skill.CRAFTING, 1, 2.5, CriticalItem.WOOL), + BOW_STRING(ItemID.BOW_STRING, "Misc", Skill.CRAFTING, 1, 15, CriticalItem.FLAX), + // Glass Blowing + BEER_GLASS(ItemID.BEER_GLASS, "Beer Glass", Skill.CRAFTING, 1, 17.5, CriticalItem.MOLTEN_GLASS), + CANDLE_LANTERN(ItemID.CANDLE_LANTERN, "Candle Lantern", Skill.CRAFTING, 4, 19, CriticalItem.MOLTEN_GLASS), + OIL_LAMP(ItemID.OIL_LAMP, "Oil Lamp", Skill.CRAFTING, 12, 25, CriticalItem.MOLTEN_GLASS), + VIAL(ItemID.VIAL, "Vial", Skill.CRAFTING, 33, 35, CriticalItem.MOLTEN_GLASS), + EMPTY_FISHBOWL(ItemID.EMPTY_FISHBOWL, "Empty fishbowl", Skill.CRAFTING, 42, 42.5, CriticalItem.MOLTEN_GLASS), + UNPOWERED_ORB(ItemID.UNPOWERED_ORB, "Unpowered orb", Skill.CRAFTING, 46, 52.5, CriticalItem.MOLTEN_GLASS), + LANTERN_LENS(ItemID.LANTERN_LENS, "Lantern lens", Skill.CRAFTING, 49, 55, CriticalItem.MOLTEN_GLASS), + LIGHT_ORB(ItemID.LIGHT_ORB, "Light orb", Skill.CRAFTING, 87, 70, CriticalItem.MOLTEN_GLASS), + // D'hide/Dragon Leather + GREEN_DRAGON_LEATHER(ItemID.GREEN_DRAGON_LEATHER, "D'hide", Skill.CRAFTING, 57, 62.0, CriticalItem.GREEN_DRAGON_LEATHER), + BLUE_DRAGON_LEATHER(ItemID.BLUE_DRAGON_LEATHER, "D'hide", Skill.CRAFTING, 66, 70.0, CriticalItem.BLUE_DRAGON_LEATHER), + RED_DRAGON_LEATHER(ItemID.RED_DRAGON_LEATHER, "D'hide", Skill.CRAFTING, 73, 78.0, CriticalItem.RED_DRAGON_LEATHER), + BLACK_DRAGON_LEATHER(ItemID.BLACK_DRAGON_LEATHER, "D'hide", Skill.CRAFTING, 79, 86.0, CriticalItem.BLACK_DRAGON_LEATHER), + // Uncut Gems + UNCUT_OPAL(ItemID.UNCUT_OPAL, "Gems", Skill.CRAFTING, 1, 15.0, CriticalItem.UNCUT_OPAL), + UNCUT_JADE(ItemID.UNCUT_JADE, "Gems", Skill.CRAFTING, 13, 20.0, CriticalItem.UNCUT_JADE), + UNCUT_RED_TOPAZ(ItemID.UNCUT_RED_TOPAZ, "Gems", Skill.CRAFTING, 16, 25.0, CriticalItem.UNCUT_RED_TOPAZ), + UNCUT_SAPPHIRE(ItemID.UNCUT_SAPPHIRE, "Gems", Skill.CRAFTING, 20, 50.0, CriticalItem.UNCUT_SAPPHIRE), + UNCUT_EMERALD(ItemID.UNCUT_EMERALD, "Gems", Skill.CRAFTING, 27, 67.5, CriticalItem.UNCUT_EMERALD), + UNCUT_RUBY(ItemID.UNCUT_RUBY, "Gems", Skill.CRAFTING, 34, 85, CriticalItem.UNCUT_RUBY), + UNCUT_DIAMOND(ItemID.UNCUT_DIAMOND, "Gems", Skill.CRAFTING, 43, 107.5, CriticalItem.UNCUT_DIAMOND), + UNCUT_DRAGONSTONE(ItemID.UNCUT_DRAGONSTONE, "Gems", Skill.CRAFTING, 55, 137.5, CriticalItem.UNCUT_DRAGONSTONE), + UNCUT_ONYX(ItemID.UNCUT_ONYX, "Gems", Skill.CRAFTING, 67, 167.5, CriticalItem.UNCUT_ONYX), + UNCUT_ZENYTE(ItemID.UNCUT_ZENYTE, "Gems", Skill.CRAFTING, 89, 200.0, CriticalItem.UNCUT_ZENYTE), + // Silver Jewelery + OPAL_RING(ItemID.OPAL_RING, "Opal ring", Skill.CRAFTING, 1, 10, CriticalItem.OPAL, ActivitySecondaries.SILVER_BAR), + OPAL_NECKLACE(ItemID.OPAL_NECKLACE, "Opal necklace", Skill.CRAFTING, 16, 35, CriticalItem.OPAL, ActivitySecondaries.SILVER_BAR), + OPAL_BRACELET(ItemID.OPAL_BRACELET, "Opal bracelet", Skill.CRAFTING, 22, 45, CriticalItem.OPAL, ActivitySecondaries.SILVER_BAR), + OPAL_AMULET(ItemID.OPAL_AMULET, "Opal amulet", Skill.CRAFTING, 27, 55, CriticalItem.OPAL, ActivitySecondaries.SILVER_BAR), + JADE_RING(ItemID.JADE_RING, "Jade ring", Skill.CRAFTING, 13, 32, CriticalItem.JADE, ActivitySecondaries.SILVER_BAR), + JADE_NECKLACE(ItemID.JADE_NECKLACE, "Jade necklace", Skill.CRAFTING, 25, 54, CriticalItem.JADE, ActivitySecondaries.SILVER_BAR), + JADE_BRACELET(ItemID.JADE_BRACELET, "Jade bracelet", Skill.CRAFTING, 29, 60, CriticalItem.JADE, ActivitySecondaries.SILVER_BAR), + JADE_AMULET(ItemID.JADE_AMULET, "Jade amulet", Skill.CRAFTING, 34, 70, CriticalItem.JADE, ActivitySecondaries.SILVER_BAR), + TOPAZ_RING(ItemID.TOPAZ_RING, "Topaz ring", Skill.CRAFTING, 16, 35, CriticalItem.RED_TOPAZ, ActivitySecondaries.SILVER_BAR), + TOPAZ_NECKLACE(ItemID.TOPAZ_NECKLACE, "Topaz necklace", Skill.CRAFTING, 32, 70, CriticalItem.RED_TOPAZ, ActivitySecondaries.SILVER_BAR), + TOPAZ_BRACELET(ItemID.TOPAZ_BRACELET, "Topaz bracelet", Skill.CRAFTING, 38, 75, CriticalItem.RED_TOPAZ, ActivitySecondaries.SILVER_BAR), + TOPAZ_AMULET(ItemID.TOPAZ_AMULET, "Topaz amulet", Skill.CRAFTING, 45, 80, CriticalItem.RED_TOPAZ, ActivitySecondaries.SILVER_BAR), + // Gold Jewelery + SAPPHIRE_RING(ItemID.SAPPHIRE_RING, "Sapphire ring", Skill.CRAFTING, 20, 40, CriticalItem.SAPPHIRE, ActivitySecondaries.GOLD_BAR), + SAPPHIRE_NECKLACE(ItemID.SAPPHIRE_NECKLACE, "Sapphire necklace", Skill.CRAFTING, 22, 55, CriticalItem.SAPPHIRE, ActivitySecondaries.GOLD_BAR), + SAPPHIRE_BRACELET(ItemID.SAPPHIRE_BRACELET, "Sapphire bracelet", Skill.CRAFTING, 23, 60, CriticalItem.SAPPHIRE, ActivitySecondaries.GOLD_BAR), + SAPPHIRE_AMULET(ItemID.SAPPHIRE_AMULET, "Sapphire amulet", Skill.CRAFTING, 24, 65, CriticalItem.SAPPHIRE, ActivitySecondaries.GOLD_BAR), + EMERALD_RING(ItemID.EMERALD_RING, "Emerald ring", Skill.CRAFTING, 27, 55, CriticalItem.EMERALD, ActivitySecondaries.GOLD_BAR), + EMERALD_NECKLACE(ItemID.EMERALD_NECKLACE, "Emerald necklace", Skill.CRAFTING, 29, 60, CriticalItem.EMERALD, ActivitySecondaries.GOLD_BAR), + EMERALD_BRACELET(ItemID.EMERALD_BRACELET, "Emerald bracelet", Skill.CRAFTING, 30, 65, CriticalItem.EMERALD, ActivitySecondaries.GOLD_BAR), + EMERALD_AMULET(ItemID.EMERALD_AMULET, "Emerald amulet", Skill.CRAFTING, 31, 70, CriticalItem.EMERALD, ActivitySecondaries.GOLD_BAR), + RUBY_RING(ItemID.RUBY_RING, "Ruby ring", Skill.CRAFTING, 34, 70, CriticalItem.RUBY, ActivitySecondaries.GOLD_BAR), + RUBY_NECKLACE(ItemID.RUBY_NECKLACE, "Ruby necklace", Skill.CRAFTING, 40, 75, CriticalItem.RUBY, ActivitySecondaries.GOLD_BAR), + RUBY_BRACELET(ItemID.RUBY_BRACELET, "Ruby bracelet", Skill.CRAFTING, 42, 80, CriticalItem.RUBY, ActivitySecondaries.GOLD_BAR), + RUBY_AMULET(ItemID.RUBY_AMULET, "Ruby amulet", Skill.CRAFTING, 50, 85, CriticalItem.RUBY, ActivitySecondaries.GOLD_BAR), + DIAMOND_RING(ItemID.DIAMOND_RING, "Diamond ring", Skill.CRAFTING, 43, 85, CriticalItem.DIAMOND, ActivitySecondaries.GOLD_BAR), + DIAMOND_NECKLACE(ItemID.DIAMOND_NECKLACE, "Diamond necklace", Skill.CRAFTING, 56, 90, CriticalItem.DIAMOND, ActivitySecondaries.GOLD_BAR), + DIAMOND_BRACELET(ItemID.DIAMOND_BRACELET, "Diamond bracelet", Skill.CRAFTING, 58, 95, CriticalItem.DIAMOND, ActivitySecondaries.GOLD_BAR), + DIAMOND_AMULET(ItemID.DIAMOND_AMULET, "Diamond amulet", Skill.CRAFTING, 70, 100, CriticalItem.DIAMOND, ActivitySecondaries.GOLD_BAR), + DRAGONSTONE_RING(ItemID.DRAGONSTONE_RING, "Dragonstone ring", Skill.CRAFTING, 55, 100, CriticalItem.DRAGONSTONE, ActivitySecondaries.GOLD_BAR), + DRAGON_NECKLACE(ItemID.DRAGON_NECKLACE, "Dragon necklace", Skill.CRAFTING, 72, 105, CriticalItem.DRAGONSTONE, ActivitySecondaries.GOLD_BAR), + DRAGONSTONE_BRACELET(ItemID.DRAGONSTONE_BRACELET, "Dragonstone bracelet", Skill.CRAFTING, 74, 110, CriticalItem.DRAGONSTONE, ActivitySecondaries.GOLD_BAR), + DRAGONSTONE_AMULET(ItemID.DRAGONSTONE_AMULET, "Dragonstone amulet", Skill.CRAFTING, 80, 150, CriticalItem.DRAGONSTONE, ActivitySecondaries.GOLD_BAR), + ONYX_RING(ItemID.ONYX_RING, "Onyx ring", Skill.CRAFTING, 67, 115, CriticalItem.ONYX, ActivitySecondaries.GOLD_BAR), + ONYX_NECKLACE(ItemID.ONYX_NECKLACE, "Onyx necklace", Skill.CRAFTING, 82, 120, CriticalItem.ONYX, ActivitySecondaries.GOLD_BAR), + REGEN_BRACELET(ItemID.REGEN_BRACELET, "Regen bracelet", Skill.CRAFTING, 84, 125, CriticalItem.ONYX, ActivitySecondaries.GOLD_BAR), + ONYX_AMULET(ItemID.ONYX_AMULET, "Onyx amulet", Skill.CRAFTING, 90, 165, CriticalItem.ONYX, ActivitySecondaries.GOLD_BAR), + ZENYTE_RING(ItemID.ZENYTE_RING, "Zenyte ring", Skill.CRAFTING, 89, 150, CriticalItem.ZENYTE, ActivitySecondaries.GOLD_BAR), + ZENYTE_NECKLACE(ItemID.ZENYTE_NECKLACE, "Zenyte necklace", Skill.CRAFTING, 92, 165, CriticalItem.ZENYTE, ActivitySecondaries.GOLD_BAR), + ZENYTE_BRACELET(ItemID.ZENYTE_BRACELET, "Zenyte bracelet", Skill.CRAFTING, 95, 180, CriticalItem.ZENYTE, ActivitySecondaries.GOLD_BAR), + ZENYTE_AMULET(ItemID.ZENYTE_AMULET, "Zenyte amulet", Skill.CRAFTING, 98, 200, CriticalItem.ZENYTE, ActivitySecondaries.GOLD_BAR), + // Battle Staves + WATER_BATTLESTAFF(ItemID.WATER_BATTLESTAFF, "Water battlestaff", Skill.CRAFTING, 54, 100, CriticalItem.BATTLESTAFF, ActivitySecondaries.WATER_ORB), + EARTH_BATTLESTAFF(ItemID.EARTH_BATTLESTAFF, "Earth battlestaff", Skill.CRAFTING, 58, 112.5, CriticalItem.BATTLESTAFF, ActivitySecondaries.EARTH_ORB), + FIRE_BATTLESTAFF(ItemID.FIRE_BATTLESTAFF, "Fire battlestaff", Skill.CRAFTING, 62, 125, CriticalItem.BATTLESTAFF, ActivitySecondaries.FIRE_ORB), + AIR_BATTLESTAFF(ItemID.AIR_BATTLESTAFF, "Air battlestaff", Skill.CRAFTING, 66, 137.5, CriticalItem.BATTLESTAFF, ActivitySecondaries.AIR_ORB), + + /* + * Smithing Items + */ + + // Smelting ores (Furnace) + IRON_ORE(ItemID.IRON_BAR, "Iron Bars", Skill.SMITHING, 15, 12.5, CriticalItem.IRON_ORE, ActivitySecondaries.COAL_ORE), + STEEL_ORE(ItemID.STEEL_BAR, "Steel Bars", Skill.SMITHING, 30, 17.5, CriticalItem.IRON_ORE, ActivitySecondaries.COAL_ORE_2), + SILVER_ORE(ItemID.SILVER_ORE, "Bar", Skill.SMITHING, 20, 13.67, CriticalItem.SILVER_ORE), + GOLD_ORE(ItemID.GOLD_BAR, "Regular exp", Skill.SMITHING, 40, 22.5, CriticalItem.GOLD_ORE), + GOLD_ORE_GAUNTLETS(ItemID.GOLDSMITH_GAUNTLETS, "Goldsmith Gauntlets", Skill.SMITHING, 40, 56.2, CriticalItem.GOLD_ORE), + MITHRIL_ORE(ItemID.MITHRIL_ORE, "Bar", Skill.SMITHING, 50, 30, CriticalItem.MITHRIL_ORE, ActivitySecondaries.COAL_ORE_4), + ADAMANTITE_ORE(ItemID.ADAMANTITE_ORE, "Bar", Skill.SMITHING, 70, 37.5, CriticalItem.ADAMANTITE_ORE, ActivitySecondaries.COAL_ORE_6), + RUNITE_ORE(ItemID.RUNITE_ORE, "Bar", Skill.SMITHING, 85, 50, CriticalItem.RUNITE_ORE, ActivitySecondaries.COAL_ORE_8), + + // Smelting bars (Anvil) + BRONZE_BAR(ItemID.BRONZE_BAR, "Bars", Skill.SMITHING, 1, 12.5, CriticalItem.BRONZE_BAR), + IRON_BAR(ItemID.IRON_BAR, "Bars", Skill.SMITHING, 15, 25.0, CriticalItem.IRON_BAR), + STEEL_BAR(ItemID.STEEL_BAR, "Steel Products", Skill.SMITHING, 30, 37.5, CriticalItem.STEEL_BAR), + CANNONBALLS(ItemID.CANNONBALL, "Cannonballs", Skill.SMITHING, 35, 25.5, CriticalItem.STEEL_BAR), + MITHRIL_BAR(ItemID.MITHRIL_BAR, "Bars", Skill.SMITHING, 50, 50.0, CriticalItem.MITHRIL_BAR), + ADAMANTITE_BAR(ItemID.ADAMANTITE_BAR, "Bars", Skill.SMITHING, 70, 62.5, CriticalItem.ADAMANTITE_BAR), + RUNITE_BAR(ItemID.RUNITE_BAR, "Bars", Skill.SMITHING, 85, 75.0, CriticalItem.RUNITE_BAR), + + /** + * Farming Items + */ + ACORN(ItemID.ACORN, "Seeds", Skill.FARMING, 15, 481.3, CriticalItem.ACORN), + WILLOW_SEED(ItemID.WILLOW_SEED, "Seeds", Skill.FARMING, 30, 1481.5, CriticalItem.WILLOW_SEED), + MAPLE_SEED(ItemID.MAPLE_SEED, "Seeds", Skill.FARMING, 45, 3448.4, CriticalItem.MAPLE_SEED), + YEW_SEED(ItemID.YEW_SEED, "Seeds", Skill.FARMING, 60, 7150.9, CriticalItem.YEW_SEED), + MAGIC_SEED(ItemID.MAGIC_SEED, "Seeds", Skill.FARMING, 75, 13913.8, CriticalItem.MAGIC_SEED), + APPLE_TREE_SEED(ItemID.APPLE_TREE_SEED, "Seeds", Skill.FARMING, 27, 1272.5, CriticalItem.APPLE_TREE_SEED), + BANANA_TREE_SEED(ItemID.BANANA_TREE_SEED, "Seeds", Skill.FARMING, 33, 1841.5, CriticalItem.BANANA_TREE_SEED), + ORANGE_TREE_SEED(ItemID.ORANGE_TREE_SEED, "Seeds", Skill.FARMING, 39, 2586.7, CriticalItem.ORANGE_TREE_SEED), + CURRY_TREE_SEED(ItemID.CURRY_TREE_SEED, "Seeds", Skill.FARMING, 42, 3036.9, CriticalItem.CURRY_TREE_SEED), + PINEAPPLE_SEED(ItemID.PINEAPPLE_SEED, "Seeds", Skill.FARMING, 51, 4791.7, CriticalItem.PINEAPPLE_SEED), + PAPAYA_TREE_SEED(ItemID.PAPAYA_TREE_SEED, "Seeds", Skill.FARMING, 57, 6380.4, CriticalItem.PAPAYA_TREE_SEED), + PALM_TREE_SEED(ItemID.PALM_TREE_SEED, "Seeds", Skill.FARMING, 68, 10509.6, CriticalItem.PALM_TREE_SEED), + CALQUAT_TREE_SEED(ItemID.CALQUAT_TREE_SEED, "Seeds", Skill.FARMING, 72, 12516.5, CriticalItem.CALQUAT_TREE_SEED), + TEAK_SEED(ItemID.TEAK_SEED, "Seeds", Skill.FARMING, 35, 7325, CriticalItem.TEAK_SEED), + MAHOGANY_SEED(ItemID.MAHOGANY_SEED, "Seeds", Skill.FARMING, 55, 15783, CriticalItem.MAHOGANY_SEED), + SPIRIT_SEED(ItemID.SPIRIT_SEED, "Seeds", Skill.FARMING, 83, 19500, CriticalItem.SPIRIT_SEED), + ; + + private final int icon; + private final String name; + private final Skill skill; + private final int level; + private final double xp; + private final SecondaryItem[] secondaries; + private final CriticalItem criticalItem; + private final boolean preventLinked; + + Activity(int Icon, String name, Skill skill, int level, double xp, CriticalItem criticalItem) + { + this.icon = Icon; + this.name = name; + this.skill = skill; + this.level = level; + this.xp = xp; + this.criticalItem = criticalItem; + this.secondaries = new SecondaryItem[0]; + this.preventLinked = false; + } + + Activity(int Icon, String name, Skill skill, int level, double xp, CriticalItem criticalItem, ActivitySecondaries secondaries) + { + this.icon = Icon; + this.name = name; + this.skill = skill; + this.level = level; + this.xp = xp; + this.criticalItem = criticalItem; + this.secondaries = secondaries == null ? new SecondaryItem[0] : secondaries.getItems(); + this.preventLinked = false; + } + + Activity(int Icon, String name, Skill skill, int level, double xp, CriticalItem criticalItem, ActivitySecondaries secondaries, boolean preventLinked) + { + this.icon = Icon; + this.name = name; + this.skill = skill; + this.level = level; + this.xp = xp; + this.criticalItem = criticalItem; + this.secondaries = secondaries == null ? new SecondaryItem[0] : secondaries.getItems(); + this.preventLinked = preventLinked; + } + + // Builds a Map to reduce looping frequency + private static Map> buildItemMap() + { + Map> map = new HashMap<>(); + for (Activity item : values()) + { + map.computeIfAbsent(item.getCriticalItem(), e -> new ArrayList()).add(item); + } + + return map; + } + + private static final Map> byCriticalItem = buildItemMap(); + + public static ArrayList getByCriticalItem(CriticalItem item) + { + + return byCriticalItem.getOrDefault(item, new ArrayList<>()); + } + + /** + * Get all Activities for this CriticalItem + * + * @param item CriticalItem to check for + * @param limitLevel Level to check Activitiy requirements against. -1 or 0 value disables limits + * @return an empty list if no activities + */ + public static ArrayList getByCriticalItem(CriticalItem item, int limitLevel) + { + ArrayList activities = getByCriticalItem(item); + ArrayList l = new ArrayList<>(); + if (limitLevel <= 0) + { + return l; + } + + for (Activity a : activities) + { + if (!(a.getLevel() > limitLevel)) + { + l.add(a); + } + } + + return l; + } +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/skillcalculator/banked/ui/CriticalItemPanel.java b/runelite-client/src/main/java/net/runelite/client/plugins/skillcalculator/banked/ui/CriticalItemPanel.java index 7214956e80..ddb324e7b0 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/skillcalculator/banked/ui/CriticalItemPanel.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/skillcalculator/banked/ui/CriticalItemPanel.java @@ -1,401 +1,400 @@ -/* - * Copyright (c) 2018, 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.skillcalculator.banked.ui; - -import java.awt.BorderLayout; -import java.awt.Color; -import java.awt.Dimension; -import java.awt.GridBagConstraints; -import java.awt.GridBagLayout; -import java.awt.GridLayout; -import java.awt.Image; -import java.awt.event.MouseAdapter; -import java.awt.event.MouseEvent; -import java.awt.image.BufferedImage; -import java.io.IOException; -import java.text.DecimalFormat; -import java.util.ArrayList; -import java.util.List; -import java.util.Map; -import javax.imageio.ImageIO; -import javax.swing.ImageIcon; -import javax.swing.JLabel; -import javax.swing.JPanel; -import javax.swing.SwingConstants; -import javax.swing.SwingUtilities; -import javax.swing.border.Border; -import javax.swing.border.EmptyBorder; -import javax.swing.border.MatteBorder; -import lombok.Getter; -import lombok.extern.slf4j.Slf4j; -import net.runelite.client.game.AsyncBufferedImage; -import net.runelite.client.game.ItemManager; -import net.runelite.client.plugins.skillcalculator.BankedCalculator; -import net.runelite.client.plugins.skillcalculator.banked.CriticalItem; -import net.runelite.client.plugins.skillcalculator.banked.beans.Activity; -import net.runelite.client.ui.ColorScheme; -import net.runelite.client.ui.FontManager; -import net.runelite.client.ui.components.materialtabs.MaterialTab; -import net.runelite.client.ui.components.materialtabs.MaterialTabGroup; -import net.runelite.client.ui.components.shadowlabel.JShadowedLabel; -import net.runelite.client.util.StackFormatter; - -public class CriticalItemPanel extends JPanel -{ - private static final Dimension ICON_SIZE = new Dimension(36, 36); - private static final DecimalFormat FORMAT_COMMA = new DecimalFormat("#,###.#"); - - private static final BufferedImage ICON_SETTINGS; - - private static final Border PANEL_BORDER = new EmptyBorder(3, 0, 3, 0); - private final static Color BACKGROUND_COLOR = ColorScheme.DARKER_GRAY_COLOR; - private final static Color BUTTON_HOVER_COLOR = ColorScheme.DARKER_GRAY_HOVER_COLOR; - - static - { - BufferedImage i1; - try - { - synchronized (ImageIO.class) - { - i1 = ImageIO.read(BankedCalculator.class.getResourceAsStream("view-more-white.png")); - } - } - catch (IOException e) - { - throw new RuntimeException(e); - } - ICON_SETTINGS = i1; - } - - private final BankedCalculator bankedCalculator; - private final CriticalItem item; - private final ItemManager itemManager; - private double xp; - @Getter - private int amount; - @Getter - private double total; - private Map linkedMap; - private JShadowedLabel labelValue; - - private final JPanel infoContainer; - private final JLabel image; - private boolean infoVisibility = false; - - public CriticalItemPanel(BankedCalculator bankedCalculator, ItemManager itemManager, CriticalItem item, double xp, int amount, Map linkedMap) - { - this.bankedCalculator = bankedCalculator; - this.item = item; - this.xp = xp; - this.amount = amount; - this.total = xp * amount; - this.itemManager = itemManager; - this.linkedMap = linkedMap; - - this.setLayout(new GridBagLayout()); - this.setBorder(PANEL_BORDER); - this.setBackground(ColorScheme.DARK_GRAY_COLOR); - this.setVisible(this.amount > 0); - - infoContainer = new JPanel(); - infoContainer.setLayout(new GridBagLayout()); - infoContainer.setVisible(false); - infoContainer.setBackground(BACKGROUND_COLOR); - infoContainer.setBorder(new MatteBorder(1, 0, 0, 0, Color.GRAY)); - - // Icon - AsyncBufferedImage icon = itemManager.getImage(item.getItemID(), amount, item.getComposition().isStackable() || amount > 1); - image = new JLabel(); - image.setMinimumSize(ICON_SIZE); - image.setMaximumSize(ICON_SIZE); - image.setPreferredSize(ICON_SIZE); - image.setHorizontalAlignment(SwingConstants.CENTER); - image.setBorder(new EmptyBorder(0, 8, 0, 0)); - - Runnable resize = () -> - image.setIcon(new ImageIcon(icon.getScaledInstance((int)ICON_SIZE.getWidth(), (int)ICON_SIZE.getHeight(), Image.SCALE_SMOOTH))); - icon.onChanged(resize); - resize.run(); - - // Container for Info - JPanel uiInfo = new JPanel(new GridLayout(2, 1)); - uiInfo.setBorder(new EmptyBorder(0, 5, 0, 0)); - uiInfo.setBackground(BACKGROUND_COLOR); - - JShadowedLabel labelName = new JShadowedLabel(item.getComposition().getName()); - labelName.setForeground(Color.WHITE); - labelName.setVerticalAlignment(SwingUtilities.BOTTOM); - - labelValue = new JShadowedLabel(); - labelValue.setFont(FontManager.getRunescapeSmallFont()); - labelValue.setVerticalAlignment(SwingUtilities.TOP); - updateXp(xp); - - uiInfo.add(labelName); - uiInfo.add(labelValue); - - // Settings Button - JLabel settingsButton = new JLabel(); - settingsButton.setBorder(new EmptyBorder(0, 5, 0, 5)); - settingsButton.setIcon(new ImageIcon(ICON_SETTINGS)); - settingsButton.setOpaque(true); - settingsButton.setBackground(BACKGROUND_COLOR); - - settingsButton.addMouseListener(new MouseAdapter() - { - @Override - public void mouseEntered(MouseEvent e) - { - settingsButton.setBackground(BUTTON_HOVER_COLOR); - } - - @Override - public void mouseExited(MouseEvent e) - { - settingsButton.setBackground(BACKGROUND_COLOR); - } - - @Override - public void mouseClicked(MouseEvent e) - { - toggleInfo(); - } - }); - - // Create and append elements to container panel - JPanel panel = new JPanel(); - panel.setLayout(new BorderLayout()); - panel.setBackground(BACKGROUND_COLOR); - - panel.add(image, BorderLayout.LINE_START); - panel.add(uiInfo, BorderLayout.CENTER); - - // Only add button if has activity selection options or linked items - List activities = Activity.getByCriticalItem(item); - // If linked map has 1 item and it isn't this item still show breakdown (cleaned herbs into unfinished) - if ( (linkedMap.size() > 1 || (linkedMap.size() == 1 && linkedMap.get(item) == null)) - || activities.size() > 1) - { - panel.add(settingsButton, BorderLayout.LINE_END); - } - - panel.setToolTipText("" + item.getComposition().getName() - + "
xp: " + xp - + "
Total: " + StackFormatter.quantityToStackSize((long) total) + " 1 || (linkedMap.size() == 1 && linkedMap.get(item) == null)) - { - JLabel l = new JLabel("Item Breakdown"); - l.setBorder(new EmptyBorder(3, 0, 3, 0)); - l.setHorizontalAlignment(JLabel.CENTER); - infoContainer.add(l, c); - c.gridy++; - - JPanel con = new JPanel(); - con.setLayout(new GridBagLayout()); - con.setBackground(BACKGROUND_COLOR); - for (Map.Entry e : linkedMap.entrySet()) - { - // Icon - AsyncBufferedImage icon = itemManager.getImage(e.getKey().getItemID(), e.getValue(), e.getKey().getComposition().isStackable() || e.getValue() > 1); - JLabel image = new JLabel(); - image.setMinimumSize(ICON_SIZE); - image.setMaximumSize(ICON_SIZE); - image.setPreferredSize(ICON_SIZE); - image.setHorizontalAlignment(SwingConstants.CENTER); - image.setBorder(new EmptyBorder(0, 8, 0, 0)); - - Runnable resize = () -> - image.setIcon(new ImageIcon(icon.getScaledInstance((int)ICON_SIZE.getWidth(), (int)ICON_SIZE.getHeight(), Image.SCALE_SMOOTH))); - icon.onChanged(resize); - resize.run(); - - image.setToolTipText(e.getKey().getComposition().getName()); - - con.add(image, c); - c.gridx++; - } - c.gridx = 0; - infoContainer.add(con, c); - } - - } - - private JPanel createActivitiesPanel() - { - ArrayList activities = Activity.getByCriticalItem(item); - if (activities == null || activities.size() == 1) - { - return null; - } - - JPanel p = new JPanel(); - p.setBackground(BACKGROUND_COLOR); - p.setLayout(new BorderLayout()); - - JLabel label = new JLabel("Possible training methods"); - - MaterialTabGroup group = new MaterialTabGroup(); - group.setLayout(new GridLayout(0, 6, 0, 2)); - group.setBorder(new MatteBorder(1, 1, 1, 1, Color.BLACK)); - - Activity selected = this.bankedCalculator.getSelectedActivity(this.item); - boolean s = false; - - for (Activity option : activities) - { - AsyncBufferedImage icon = itemManager.getImage(option.getIcon()); - MaterialTab matTab = new MaterialTab("", group, null); - matTab.setHorizontalAlignment(SwingUtilities.RIGHT); - matTab.setToolTipText(option.getName()); - - Runnable resize = () -> - matTab.setIcon(new ImageIcon(icon.getScaledInstance(24, 24, Image.SCALE_SMOOTH))); - icon.onChanged(resize); - resize.run(); - - group.addTab(matTab); - - // Select first option by default - if (!s) - { - s = true; - group.select(matTab); - } - - // Select the option if its their selected activity - if (option.equals(selected)) - { - group.select(matTab); - } - - // Add click event handler now to prevent above code from triggering it. - matTab.setOnSelectEvent(() -> - { - bankedCalculator.activitySelected(item, option); - return true; - }); - } - - p.add(label, BorderLayout.NORTH); - p.add(group, BorderLayout.SOUTH); - - return p; - } - - public void updateXp(double newXpRate) - { - xp = newXpRate; - total = xp * amount; - labelValue.setText(FORMAT_COMMA.format(total) + "xp"); - } - - public void updateAmount(int newAmount, boolean forceVisible) - { - this.setVisible(newAmount > 0 || forceVisible); - this.amount = newAmount; - AsyncBufferedImage icon = itemManager.getImage(item.getItemID(), amount, item.getComposition().isStackable() || amount > 1); - Runnable resize = () -> - image.setIcon(new ImageIcon(icon.getScaledInstance((int)ICON_SIZE.getWidth(), (int)ICON_SIZE.getHeight(), Image.SCALE_SMOOTH))); - icon.onChanged(resize); - resize.run(); - } - - public void updateLinkedMap(Map newLinkedMap) - { - this.linkedMap = newLinkedMap; - - int sum = 0; - for (Integer v : newLinkedMap.values()) - { - sum += v; - } - this.updateAmount(sum, false); - - this.updateXp(xp); - - // Refresh info panel if visible - if (infoVisibility) - { - createInfoPanel(); - } - } - - public void recalculate() - { - updateXp(xp); - } -} +/* + * Copyright (c) 2018, 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.skillcalculator.banked.ui; + +import java.awt.BorderLayout; +import java.awt.Color; +import java.awt.Dimension; +import java.awt.GridBagConstraints; +import java.awt.GridBagLayout; +import java.awt.GridLayout; +import java.awt.Image; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import java.awt.image.BufferedImage; +import java.io.IOException; +import java.text.DecimalFormat; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import javax.imageio.ImageIO; +import javax.swing.ImageIcon; +import javax.swing.JLabel; +import javax.swing.JPanel; +import javax.swing.SwingConstants; +import javax.swing.SwingUtilities; +import javax.swing.border.Border; +import javax.swing.border.EmptyBorder; +import javax.swing.border.MatteBorder; +import lombok.Getter; +import net.runelite.client.game.AsyncBufferedImage; +import net.runelite.client.game.ItemManager; +import net.runelite.client.plugins.skillcalculator.BankedCalculator; +import net.runelite.client.plugins.skillcalculator.banked.CriticalItem; +import net.runelite.client.plugins.skillcalculator.banked.beans.Activity; +import net.runelite.client.ui.ColorScheme; +import net.runelite.client.ui.FontManager; +import net.runelite.client.ui.components.materialtabs.MaterialTab; +import net.runelite.client.ui.components.materialtabs.MaterialTabGroup; +import net.runelite.client.ui.components.shadowlabel.JShadowedLabel; +import net.runelite.client.util.StackFormatter; + +public class CriticalItemPanel extends JPanel +{ + private static final Dimension ICON_SIZE = new Dimension(36, 36); + private static final DecimalFormat FORMAT_COMMA = new DecimalFormat("#,###.#"); + + private static final BufferedImage ICON_SETTINGS; + + private static final Border PANEL_BORDER = new EmptyBorder(3, 0, 3, 0); + private final static Color BACKGROUND_COLOR = ColorScheme.DARKER_GRAY_COLOR; + private final static Color BUTTON_HOVER_COLOR = ColorScheme.DARKER_GRAY_HOVER_COLOR; + + static + { + BufferedImage i1; + try + { + synchronized (ImageIO.class) + { + i1 = ImageIO.read(BankedCalculator.class.getResourceAsStream("view-more-white.png")); + } + } + catch (IOException e) + { + throw new RuntimeException(e); + } + ICON_SETTINGS = i1; + } + + private final BankedCalculator bankedCalculator; + private final CriticalItem item; + private final ItemManager itemManager; + private double xp; + @Getter + private int amount; + @Getter + private double total; + private Map linkedMap; + private JShadowedLabel labelValue; + + private final JPanel infoContainer; + private final JLabel image; + private boolean infoVisibility = false; + + public CriticalItemPanel(BankedCalculator bankedCalculator, ItemManager itemManager, CriticalItem item, double xp, int amount, Map linkedMap) + { + this.bankedCalculator = bankedCalculator; + this.item = item; + this.xp = xp; + this.amount = amount; + this.total = xp * amount; + this.itemManager = itemManager; + this.linkedMap = linkedMap; + + this.setLayout(new GridBagLayout()); + this.setBorder(PANEL_BORDER); + this.setBackground(ColorScheme.DARK_GRAY_COLOR); + this.setVisible(this.amount > 0); + + infoContainer = new JPanel(); + infoContainer.setLayout(new GridBagLayout()); + infoContainer.setVisible(false); + infoContainer.setBackground(BACKGROUND_COLOR); + infoContainer.setBorder(new MatteBorder(1, 0, 0, 0, Color.GRAY)); + + // Icon + AsyncBufferedImage icon = itemManager.getImage(item.getItemID(), amount, item.getComposition().isStackable() || amount > 1); + image = new JLabel(); + image.setMinimumSize(ICON_SIZE); + image.setMaximumSize(ICON_SIZE); + image.setPreferredSize(ICON_SIZE); + image.setHorizontalAlignment(SwingConstants.CENTER); + image.setBorder(new EmptyBorder(0, 8, 0, 0)); + + Runnable resize = () -> + image.setIcon(new ImageIcon(icon.getScaledInstance((int) ICON_SIZE.getWidth(), (int) ICON_SIZE.getHeight(), Image.SCALE_SMOOTH))); + icon.onChanged(resize); + resize.run(); + + // Container for Info + JPanel uiInfo = new JPanel(new GridLayout(2, 1)); + uiInfo.setBorder(new EmptyBorder(0, 5, 0, 0)); + uiInfo.setBackground(BACKGROUND_COLOR); + + JShadowedLabel labelName = new JShadowedLabel(item.getComposition().getName()); + labelName.setForeground(Color.WHITE); + labelName.setVerticalAlignment(SwingUtilities.BOTTOM); + + labelValue = new JShadowedLabel(); + labelValue.setFont(FontManager.getRunescapeSmallFont()); + labelValue.setVerticalAlignment(SwingUtilities.TOP); + updateXp(xp); + + uiInfo.add(labelName); + uiInfo.add(labelValue); + + // Settings Button + JLabel settingsButton = new JLabel(); + settingsButton.setBorder(new EmptyBorder(0, 5, 0, 5)); + settingsButton.setIcon(new ImageIcon(ICON_SETTINGS)); + settingsButton.setOpaque(true); + settingsButton.setBackground(BACKGROUND_COLOR); + + settingsButton.addMouseListener(new MouseAdapter() + { + @Override + public void mouseEntered(MouseEvent e) + { + settingsButton.setBackground(BUTTON_HOVER_COLOR); + } + + @Override + public void mouseExited(MouseEvent e) + { + settingsButton.setBackground(BACKGROUND_COLOR); + } + + @Override + public void mouseClicked(MouseEvent e) + { + toggleInfo(); + } + }); + + // Create and append elements to container panel + JPanel panel = new JPanel(); + panel.setLayout(new BorderLayout()); + panel.setBackground(BACKGROUND_COLOR); + + panel.add(image, BorderLayout.LINE_START); + panel.add(uiInfo, BorderLayout.CENTER); + + // Only add button if has activity selection options or linked items + List activities = Activity.getByCriticalItem(item); + // If linked map has 1 item and it isn't this item still show breakdown (cleaned herbs into unfinished) + if ((linkedMap.size() > 1 || (linkedMap.size() == 1 && linkedMap.get(item) == null)) + || activities.size() > 1) + { + panel.add(settingsButton, BorderLayout.LINE_END); + } + + panel.setToolTipText("" + item.getComposition().getName() + + "
xp: " + xp + + "
Total: " + StackFormatter.quantityToStackSize((long) total) + " 1 || (linkedMap.size() == 1 && linkedMap.get(item) == null)) + { + JLabel l = new JLabel("Item Breakdown"); + l.setBorder(new EmptyBorder(3, 0, 3, 0)); + l.setHorizontalAlignment(JLabel.CENTER); + infoContainer.add(l, c); + c.gridy++; + + JPanel con = new JPanel(); + con.setLayout(new GridBagLayout()); + con.setBackground(BACKGROUND_COLOR); + for (Map.Entry e : linkedMap.entrySet()) + { + // Icon + AsyncBufferedImage icon = itemManager.getImage(e.getKey().getItemID(), e.getValue(), e.getKey().getComposition().isStackable() || e.getValue() > 1); + JLabel image = new JLabel(); + image.setMinimumSize(ICON_SIZE); + image.setMaximumSize(ICON_SIZE); + image.setPreferredSize(ICON_SIZE); + image.setHorizontalAlignment(SwingConstants.CENTER); + image.setBorder(new EmptyBorder(0, 8, 0, 0)); + + Runnable resize = () -> + image.setIcon(new ImageIcon(icon.getScaledInstance((int) ICON_SIZE.getWidth(), (int) ICON_SIZE.getHeight(), Image.SCALE_SMOOTH))); + icon.onChanged(resize); + resize.run(); + + image.setToolTipText(e.getKey().getComposition().getName()); + + con.add(image, c); + c.gridx++; + } + c.gridx = 0; + infoContainer.add(con, c); + } + + } + + private JPanel createActivitiesPanel() + { + ArrayList activities = Activity.getByCriticalItem(item); + if (activities == null || activities.size() == 1) + { + return null; + } + + JPanel p = new JPanel(); + p.setBackground(BACKGROUND_COLOR); + p.setLayout(new BorderLayout()); + + JLabel label = new JLabel("Possible training methods"); + + MaterialTabGroup group = new MaterialTabGroup(); + group.setLayout(new GridLayout(0, 6, 0, 2)); + group.setBorder(new MatteBorder(1, 1, 1, 1, Color.BLACK)); + + Activity selected = this.bankedCalculator.getSelectedActivity(this.item); + boolean s = false; + + for (Activity option : activities) + { + AsyncBufferedImage icon = itemManager.getImage(option.getIcon()); + MaterialTab matTab = new MaterialTab("", group, null); + matTab.setHorizontalAlignment(SwingUtilities.RIGHT); + matTab.setToolTipText(option.getName()); + + Runnable resize = () -> + matTab.setIcon(new ImageIcon(icon.getScaledInstance(24, 24, Image.SCALE_SMOOTH))); + icon.onChanged(resize); + resize.run(); + + group.addTab(matTab); + + // Select first option by default + if (!s) + { + s = true; + group.select(matTab); + } + + // Select the option if its their selected activity + if (option.equals(selected)) + { + group.select(matTab); + } + + // Add click event handler now to prevent above code from triggering it. + matTab.setOnSelectEvent(() -> + { + bankedCalculator.activitySelected(item, option); + return true; + }); + } + + p.add(label, BorderLayout.NORTH); + p.add(group, BorderLayout.SOUTH); + + return p; + } + + public void updateXp(double newXpRate) + { + xp = newXpRate; + total = xp * amount; + labelValue.setText(FORMAT_COMMA.format(total) + "xp"); + } + + public void updateAmount(int newAmount, boolean forceVisible) + { + this.setVisible(newAmount > 0 || forceVisible); + this.amount = newAmount; + AsyncBufferedImage icon = itemManager.getImage(item.getItemID(), amount, item.getComposition().isStackable() || amount > 1); + Runnable resize = () -> + image.setIcon(new ImageIcon(icon.getScaledInstance((int) ICON_SIZE.getWidth(), (int) ICON_SIZE.getHeight(), Image.SCALE_SMOOTH))); + icon.onChanged(resize); + resize.run(); + } + + public void updateLinkedMap(Map newLinkedMap) + { + this.linkedMap = newLinkedMap; + + int sum = 0; + for (Integer v : newLinkedMap.values()) + { + sum += v; + } + this.updateAmount(sum, false); + + this.updateXp(xp); + + // Refresh info panel if visible + if (infoVisibility) + { + createInfoPanel(); + } + } + + public void recalculate() + { + updateXp(xp); + } +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/slayer/KnapsackSolver.java b/runelite-client/src/main/java/net/runelite/client/plugins/slayer/KnapsackSolver.java index e00bef4443..b97e2aa21f 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/slayer/KnapsackSolver.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/slayer/KnapsackSolver.java @@ -30,7 +30,7 @@ import java.util.List; public class KnapsackSolver { - private List reconstructItemsInSack(int [] [] sackMatrix, List items, int i, int w) + private List reconstructItemsInSack(int[][] sackMatrix, List items, int i, int w) { if (i == 0) { @@ -39,7 +39,7 @@ public class KnapsackSolver if (sackMatrix[i][w] > sackMatrix[i - 1][w]) { List list = reconstructItemsInSack(sackMatrix, items, - i - 1, w - items.get(i - 1)); + i - 1, w - items.get(i - 1)); list.add(items.get(i - 1)); return list; } @@ -53,20 +53,20 @@ public class KnapsackSolver { int itemCount = items.size(); - int[] [] sackMatrix = new int[itemCount + 1] [maxWeight + 1]; + int[][] sackMatrix = new int[itemCount + 1][maxWeight + 1]; for (int i = 1; i <= itemCount; i++) { for (int j = 0; j <= maxWeight; j++) { if (items.get(i - 1) > j) { - sackMatrix[i] [j] = sackMatrix[i - 1] [j]; + sackMatrix[i][j] = sackMatrix[i - 1][j]; } else { - sackMatrix[i] [j] = Math.max( - sackMatrix[i - 1] [j], - sackMatrix[i - 1] [j - items.get(i - 1)] + items.get(i - 1) + sackMatrix[i][j] = Math.max( + sackMatrix[i - 1][j], + sackMatrix[i - 1][j - items.get(i - 1)] + items.get(i - 1) ); } } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/slayer/SlayerPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/slayer/SlayerPlugin.java index a9da3d2040..3f44d26d0e 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/slayer/SlayerPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/slayer/SlayerPlugin.java @@ -140,29 +140,29 @@ public class SlayerPlugin extends Plugin // Superiors @VisibleForTesting static List SUPERIOR_SLAYER_MONSTERS = Arrays.asList( - "crushing hand", - "chasm crawler", - "screaming banshee", - "screaming twisted banshee", - "giant rockslug", - "cockathrice", - "flaming pyrelord", - "monstrous basilisk", - "malevolent mage", - "insatiable bloodveld", - "insatiable mutated bloodveld", - "vitreous jelly", - "vitreous warped jelly", - "cave abomination", - "abhorrent spectre", - "repugnant spectre", - "choke devil", - "king kurask", - "marble gargoyle", - "nechryarch", - "greater abyssal demon", - "night beast", - "nuclear smoke devil"); + "crushing hand", + "chasm crawler", + "screaming banshee", + "screaming twisted banshee", + "giant rockslug", + "cockathrice", + "flaming pyrelord", + "monstrous basilisk", + "malevolent mage", + "insatiable bloodveld", + "insatiable mutated bloodveld", + "vitreous jelly", + "vitreous warped jelly", + "cave abomination", + "abhorrent spectre", + "repugnant spectre", + "choke devil", + "king kurask", + "marble gargoyle", + "nechryarch", + "greater abyssal demon", + "night beast", + "nuclear smoke devil"); @Inject private ClientToolbar clientToolbar; @@ -408,7 +408,7 @@ public class SlayerPlugin extends Plugin debugString.append(", "); } log.debug("Estimating kc of xp drop " + gains + " for presences {" + - debugString.toString() + "}"); + debugString.toString() + "}"); // first determine potential xp drops given by all npcs that died this tick by grabbing the slayer xp // info from the map made out of the data in slayer_xp.json @@ -429,7 +429,7 @@ public class SlayerPlugin extends Plugin debugString.append(", "); } log.debug("Determined xp drop " + gains + " can be made of {" + debugString.toString() - + "}"); + + "}"); // we can attempt to determine exactly how many npcs died to give this amount of xp // by using a solver for the knapsack problem @@ -443,8 +443,8 @@ public class SlayerPlugin extends Plugin // and xp drops can have a single number after the decimal point int tenFudgedGains = fudgedGains * 10; List potentialXpDropsAsInts = potentialXpDrops.stream() - .map(xpDrop -> (int) (xpDrop * 10)) - .collect(Collectors.toCollection(ArrayList::new)); + .map(xpDrop -> (int) (xpDrop * 10)) + .collect(Collectors.toCollection(ArrayList::new)); KnapsackSolver solver = new KnapsackSolver(); @@ -593,7 +593,7 @@ public class SlayerPlugin extends Plugin log.debug("Last certain amount was " + currentTask.getLastCertainAmount() + " so error rate is " + currentTask.getAmount() + " in " + currentTask.getLastCertainAmount()); - setTask("", 0, 0, true, 0); + setTask("", 0, 0, true, 0); return; } @@ -625,7 +625,7 @@ public class SlayerPlugin extends Plugin if (bracerProgress.find()) { final int taskAmount = Integer.parseInt(bracerProgress.group(1)); - setTask(currentTask.getTaskName(), taskAmount, currentTask.getInitialAmount(), false, taskAmount); + setTask(currentTask.getTaskName(), taskAmount, currentTask.getInitialAmount(), false, taskAmount); // Avoid race condition (combat brace message goes through first before XP drop) currentTask.setAmount(currentTask.getAmount() + 1); @@ -700,7 +700,8 @@ public class SlayerPlugin extends Plugin @Subscribe public void onInteractingChanged(InteractingChanged event) { - if (client.getLocalPlayer() == null) { + if (client.getLocalPlayer() == null) + { return; } final Actor interacting = client.getLocalPlayer().getInteracting(); @@ -780,7 +781,7 @@ public class SlayerPlugin extends Plugin private boolean doubleTroubleExtraKill() { return WorldPoint.fromLocalInstance(client, client.getLocalPlayer().getLocalLocation()).getRegionID() == GROTESQUE_GUARDIANS_REGION && - SlayerUnlock.GROTESQUE_GARDIAN_DOUBLE_COUNT.isEnabled(client); + SlayerUnlock.GROTESQUE_GARDIAN_DOUBLE_COUNT.isEnabled(client); } // checks if any contiguous subsequence of seq0 exactly matches the String toMatch @@ -810,10 +811,8 @@ public class SlayerPlugin extends Plugin if (composition != null) { List actions = Arrays.asList(composition.getActions()); - if (actions.contains("Attack") || actions.contains("Pick") || actions.contains("Poke")) //Pick action is for zygomite-fungi - { - return true; - } + //Pick action is for zygomite-fungi + return actions.contains("Attack") || actions.contains("Pick") || actions.contains("Poke"); } return false; @@ -940,7 +939,7 @@ public class SlayerPlugin extends Plugin isNewAssignment ? 0 : currentTask.getElapsedKills(), isNewAssignment ? 0 : currentTask.getElapsedXp(), amt, initAmt, lastCertainAmt, location, name, - isNewAssignment ? true : currentTask.isPaused()); + isNewAssignment || currentTask.isPaused()); if (panel != null) { panel.updateCurrentTask(true, currentTask.isPaused(), currentTask, isNewAssignment); @@ -994,7 +993,7 @@ public class SlayerPlugin extends Plugin { taskTooltip += "
" + ColorUtil.wrapWithColorTag("Start:", Color.YELLOW) - + " " + currentTask.getInitialAmount() ; + + " " + currentTask.getInitialAmount(); } counter = new TaskCounter(taskImg, this, currentTask.getAmount()); diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/slayer/SlayerTaskPanel.java b/runelite-client/src/main/java/net/runelite/client/plugins/slayer/SlayerTaskPanel.java index 06684bab67..d40f7955b5 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/slayer/SlayerTaskPanel.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/slayer/SlayerTaskPanel.java @@ -102,7 +102,8 @@ public class SlayerTaskPanel extends PluginPanel playBtn.setIcon(PLAY); playBtn.setToolTipText("Resume the current slayer task"); - playBtn.addMouseListener(new MouseAdapter() { + playBtn.addMouseListener(new MouseAdapter() + { @Override public void mousePressed(MouseEvent mouseEvent) { @@ -137,13 +138,15 @@ public class SlayerTaskPanel extends PluginPanel pauseBtn.setIcon(PAUSE); pauseBtn.setToolTipText("Pause the current slayer task"); - pauseBtn.addMouseListener(new MouseAdapter() { + pauseBtn.addMouseListener(new MouseAdapter() + { @Override public void mousePressed(MouseEvent mouseEvent) { slayerPlugin.setPaused(true); changePauseState(true); } + @Override public void mouseExited(MouseEvent mouseEvent) { diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/slayer/SlayerXpDropLookup.java b/runelite-client/src/main/java/net/runelite/client/plugins/slayer/SlayerXpDropLookup.java index 8973f92bef..a3e3898390 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/slayer/SlayerXpDropLookup.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/slayer/SlayerXpDropLookup.java @@ -52,26 +52,26 @@ public class SlayerXpDropLookup * Finds the xp for a given npc using the xp + combat level data provided * from the JSON - since scrapping from the wiki isn't perfectly accurate * we make some estimations - * + *

* precondition is that xpCombatLevel array is non-null - if it is null * we can simply return -1 to indicate no slayer xp because this npc * has no associated xpCombatLevel array - * + *

* 1. first check to see if anywhere in the xp + combat level data this - * creature name give slayer xp - if it doesn't just return -1 and - * be done with this - if it does give slayer xp then continue + * creature name give slayer xp - if it doesn't just return -1 and + * be done with this - if it does give slayer xp then continue * 2. now check to see if we can find the xp for this combat level where - * that xp is greater than 0. note that we don't just find the xp for - * this combat level - this is because for some monsters the wiki - * only has slayer xp data for some combat levels and has it unknown - * for the other combat levels. this way we only return the combat level - * related xp data for a monster if it is know + * that xp is greater than 0. note that we don't just find the xp for + * this combat level - this is because for some monsters the wiki + * only has slayer xp data for some combat levels and has it unknown + * for the other combat levels. this way we only return the combat level + * related xp data for a monster if it is know * 3. finally if the slayer xp data for the monster was unknown for the given - * level we estimate the slayer xp by using one of the slayer xps for a level - * that does have xp given + * level we estimate the slayer xp by using one of the slayer xps for a level + * that does have xp given * 4. note that if a monster gives no slayer xp for any level it will return - * -1 so we don't accidentally misscount non-slayer targets dying as giving - * slayer xp + * -1 so we don't accidentally misscount non-slayer targets dying as giving + * slayer xp * * @param npc the npc we are estimating slayer xp for * @return our best guess for the slayer xp for this npc @@ -99,7 +99,7 @@ public class SlayerXpDropLookup for (int i = 0; i < xpCombatLevel.size() - 1; i += 2) { if (Math.abs(xpCombatLevel.get(i + 1) - npc.getCombatLevel()) < EPSILON - && xpCombatLevel.get(i) > 0) + && xpCombatLevel.get(i) > 0) { foundCombatLevel = true; } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/slayer/TargetWeaknessOverlay.java b/runelite-client/src/main/java/net/runelite/client/plugins/slayer/TargetWeaknessOverlay.java index 84fa4d8773..08d9d97cd0 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/slayer/TargetWeaknessOverlay.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/slayer/TargetWeaknessOverlay.java @@ -107,7 +107,7 @@ class TargetWeaknessOverlay extends Overlay return -1; } - return (int)((maxHealth * healthRatio / healthScale) + 0.5f); + return (int) ((maxHealth * healthRatio / healthScale) + 0.5f); } private void renderTargetItem(Graphics2D graphics, NPC actor, BufferedImage image) diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/slayer/Task.java b/runelite-client/src/main/java/net/runelite/client/plugins/slayer/Task.java index da2c473f0c..5c32ba6e73 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/slayer/Task.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/slayer/Task.java @@ -26,12 +26,11 @@ package net.runelite.client.plugins.slayer; import com.google.common.base.Preconditions; +import com.google.common.collect.ImmutableMap; import java.util.ArrayList; import static java.util.Arrays.asList; import java.util.Collections; import java.util.List; -import com.google.common.collect.ImmutableMap; -import com.google.common.collect.ImmutableMap; import java.util.Map; import lombok.Getter; import net.runelite.api.ItemID; @@ -103,7 +102,7 @@ enum Task CRAZY_ARCHAEOLOGIST("Crazy Archaeologist", ItemID.FEDORA), CROCODILES("Crocodiles", ItemID.SWAMP_LIZARD), DAGANNOTH("Dagannoth", ItemID.DAGANNOTH, - asList("Dagannoth Rex", "Dagannoth Prime", "Dagannoth Supreme"), Collections.emptyList()), + asList("Dagannoth Rex", "Dagannoth Prime", "Dagannoth Supreme"), Collections.emptyList()), DAGANNOTH_KINGS("Dagannoth Kings", ItemID.PET_DAGANNOTH_PRIME, asList("Dagannoth Rex", "Dagannoth Prime", "Dagannoth Supreme"), Collections.emptyList()), DARK_BEASTS("Dark beasts", ItemID.DARK_BEAST, @@ -311,7 +310,7 @@ enum Task this.checkAsTokens = true; } - Task(String name, int itemSpriteId, List targetNames, List npcIds, int weaknessThreshold, int weaknessItem) + Task(String name, int itemSpriteId, List targetNames, List npcIds, int weaknessThreshold, int weaknessItem) { Preconditions.checkArgument(itemSpriteId >= 0); this.name = name; diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/slayer/TaskData.java b/runelite-client/src/main/java/net/runelite/client/plugins/slayer/TaskData.java index 3e2cec384a..9a641a7a87 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/slayer/TaskData.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/slayer/TaskData.java @@ -6,7 +6,7 @@ import lombok.Data; @Data @AllArgsConstructor -@Builder(toBuilder=true) +@Builder(toBuilder = true) public class TaskData { private long elapsedTime; diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/slayermusiq/QuestGuideLinks.java b/runelite-client/src/main/java/net/runelite/client/plugins/slayermusiq/QuestGuideLinks.java index c61fa5e81c..5d18ff9110 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/slayermusiq/QuestGuideLinks.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/slayermusiq/QuestGuideLinks.java @@ -1,207 +1,217 @@ package net.runelite.client.plugins.slayermusiq; -import net.runelite.client.util.LinkBrowser; import net.runelite.api.ChatMessageType; -import net.runelite.api.events.ChatMessage; import net.runelite.client.chat.ChatColorType; import net.runelite.client.chat.ChatMessageBuilder; import net.runelite.client.chat.ChatMessageManager; import net.runelite.client.chat.QueuedMessage; +import net.runelite.client.util.LinkBrowser; -public class QuestGuideLinks { - private static final Link[] QUEST_GUIDE_LINKS = { - // Free Quests - new Link("Cook's Assistant", "https://www.youtube.com/watch?v=ehmtDRelj3c"), - new Link("Romeo & Juliet", "https://www.youtube.com/watch?v=rH_biWSNWVY"), - new Link("Demon Slayer", "https://www.youtube.com/watch?v=hgACrzJSiQk"), - new Link("Shield of Arrav", "https://www.youtube.com/watch?v=a_imLDKUdzg"), - new Link("Sheep Shearer", "https://www.youtube.com/watch?v=XFG3aNwK68s"), - new Link("The Restless Ghost", "https://www.youtube.com/watch?v=UkWNcsG_pXM"), - new Link("Ernest the Chicken", "https://www.youtube.com/watch?v=cq8NIVhSqh4"), - new Link("Vampire Slayer", "https://www.youtube.com/watch?v=FcEuxsDJWCU"), - new Link("Imp Catcher", "https://www.youtube.com/watch?v=LHgnl0FbOzk"), - new Link("Prince Ali Rescue", "https://www.youtube.com/watch?v=hrSPl1GfFaw"), - new Link("Doric's Quest", "https://www.youtube.com/watch?v=5TYyxHU27a4"), - new Link("Black Knights' Fortress", "https://www.youtube.com/watch?v=aekoZi3f9cU"), - new Link("Witch's Potion", "https://www.youtube.com/watch?v=XV4i5sPUvXo"), - new Link("The Knight's Sword", "https://www.youtube.com/watch?v=UkBWaI0rOqE"), - new Link("Goblin Diplomacy", "https://www.youtube.com/watch?v=P9BKOb_dLoY"), - new Link("Pirate's Treasure", "https://www.youtube.com/watch?v=zcD87PQW8Qk"), - new Link("Dragon Slayer", "https://www.youtube.com/watch?v=bMtCjlFOaBI"), - new Link("Rune Mysteries", "https://www.youtube.com/watch?v=l8ZhaN8uoS0"), - new Link("Misthalin Mystery", "https://www.youtube.com/watch?v=QlFqVAobAlQ"), - new Link("The Corsair Curse", "https://www.youtube.com/watch?v=wi7mUAHExz4"), - new Link("X Marks the Spot", "https://www.youtube.com/watch?v=GhRgvEG5jxQ"), - // Members Quests - new Link("Druidic Ritual", "https://www.youtube.com/watch?v=QIfU6HSmH4w"), - new Link("Lost City", "https://www.youtube.com/watch?v=T-kQNUSjFZI"), - new Link("Witch's House", "https://www.youtube.com/watch?v=TLsg7Wa-LUA"), - new Link("Merlin's Crystal", "https://www.youtube.com/watch?v=ESX-qriNtCE"), - new Link("Heroes' Quest", "https://www.youtube.com/watch?v=hK2N0WLKviE"), - new Link("Scorpion Catcher", "https://www.youtube.com/watch?v=xpqdec7_ZWg"), - new Link("Family Crest", "https://www.youtube.com/watch?v=0mk_Cgjr738"), - new Link("Monk's Friend", "https://www.youtube.com/watch?v=avi4y4G3Hcw"), - new Link("Temple of Ikov", "https://www.youtube.com/watch?v=5K7jDgr_4Z4"), - new Link("Clock Tower", "https://www.youtube.com/watch?v=GUCkkQFzyDw"), - new Link("Holy Grail", "https://www.youtube.com/watch?v=cgXoV1QlYco"), - new Link("Tree Gnome Village", "https://www.youtube.com/watch?v=T6Su__yuyRI"), - new Link("Fight Arena", "https://www.youtube.com/watch?v=4Nqjep2E5pw"), - new Link("Hazeel Cult", "https://www.youtube.com/watch?v=2_fhFJW6cNY"), - new Link("Sheep Herder", "https://www.youtube.com/watch?v=akC9FeYCG1Q"), - new Link("Plague City", "https://www.youtube.com/watch?v=Hf2wQQZL5CU"), - new Link("Waterfall Quest", "https://www.youtube.com/watch?v=xWBSnGkQTi4"), - new Link("Jungle Potion", "https://www.youtube.com/watch?v=xqLKsFz08As"), - new Link("The Grand Tree", "https://www.youtube.com/watch?v=N5e_Jus_E-Y"), - new Link("Underground Pass", "https://www.youtube.com/watch?v=5klGJg1wY8k"), - new Link("Observatory Quest", "https://www.youtube.com/watch?v=yxa9B6svv44"), - new Link("Watchtower", "https://www.youtube.com/watch?v=Vb10GoYP7FE"), - new Link("Dwarf Cannon", "https://www.youtube.com/watch?v=pROFg5jcCR0"), - new Link("Murder Mystery", "https://www.youtube.com/watch?v=P1IDGCA2f9o"), - new Link("The Dig Site", "https://www.youtube.com/watch?v=TOdcWV4MzuU"), - new Link("Gertrude's Cat", "https://www.youtube.com/watch?v=g7S09wA8EAY"), - new Link("Legends' Quest", "https://www.youtube.com/watch?v=Lid8enDEF_U"), - new Link("Death Plateau", "https://www.youtube.com/watch?v=SIQFmTvnb6w"), - new Link("Big Chompy Bird Hunting", "https://www.youtube.com/watch?v=s2fytMOHJXI"), - new Link("Elemental Workshop I", "https://www.youtube.com/watch?v=tbZD2RDqvfQ"), - new Link("Nature Spirit", "https://www.youtube.com/watch?v=Enf8vUWb5o0"), - new Link("Priest in Peril", "https://www.youtube.com/watch?v=fyYri6wUQIU"), - new Link("Regicide", "https://www.youtube.com/watch?v=KkWM-ok3C4Y"), - new Link("Tai Bwo Wannai Trio", "https://www.youtube.com/watch?v=Mdair5mvZL0"), - new Link("Troll Stronghold", "https://www.youtube.com/watch?v=zqmUs-f3AKA"), - new Link("Horror from the Deep", "https://www.youtube.com/watch?v=9htK8kb6DR8"), - new Link("Throne of Miscellania", "https://www.youtube.com/watch?v=fzGMnv2skBE"), - new Link("Monkey Madness I", "https://www.youtube.com/watch?v=VnoRfeBnPFA"), - new Link("Haunted Mine", "https://www.youtube.com/watch?v=cIc6loJHm9Q"), - new Link("Troll Romance", "https://www.youtube.com/watch?v=j2zifZVu7Gc"), - new Link("In Search of the Myreque", "https://www.youtube.com/watch?v=5nmYFHdAXAQ"), - new Link("Creature of Fenkenstrain", "https://www.youtube.com/watch?v=swqUVIs7B7M"), - new Link("Roving Elves", "https://www.youtube.com/watch?v=J3qf9DnT9cA"), - new Link("One Small Favour", "https://www.youtube.com/watch?v=ix_0-W3e9ps"), - new Link("Mountain Daughter", "https://www.youtube.com/watch?v=HETx_LX7aiY"), - new Link("Between a Rock...", "https://www.youtube.com/watch?v=cB11I45EGgA"), - new Link("The Golem", "https://www.youtube.com/watch?v=qpEHpiO6lLw"), - new Link("Desert Treasure", "https://www.youtube.com/watch?v=BuIqulIsICo"), - new Link("Icthlarin's Little Helper", "https://www.youtube.com/watch?v=wpNKm8_vUOM"), - new Link("Tears of Guthix", "https://www.youtube.com/watch?v=EMonDNI0uPk"), - new Link("The Lost Tribe", "https://www.youtube.com/watch?v=spZErjRnCdc"), - new Link("The Giant Dwarf", "https://www.youtube.com/watch?v=Z7PsGpOYgxY"), - new Link("Recruitment Drive", "https://www.youtube.com/watch?v=sOuzMpA_xtw"), - new Link("Mourning's Ends Part I", "https://www.youtube.com/watch?v=vuzAdk-h3c0"), - new Link("Garden of Tranquillity", "https://www.youtube.com/watch?v=7hbCzYnLCsQ"), - new Link("A Tail of Two Cats", "https://www.youtube.com/watch?v=SgN9Yw_YqHk"), - new Link("Wanted!", "https://www.youtube.com/watch?v=ZHZAKDCfXGs"), - new Link("Mourning's Ends Part II", "https://www.youtube.com/watch?v=FK5sLogGbU8"), - new Link("Rum Deal", "https://www.youtube.com/watch?v=I14CIu5x2S8"), - new Link("Shadow of the Storm", "https://www.youtube.com/watch?v=5ZvWd3XCQjI"), - new Link("Ratcatchers", "https://www.youtube.com/watch?v=s7G22fEuhTc"), - new Link("Spirits of the Elid", "https://www.youtube.com/watch?v=A1zAX55hZC0"), - new Link("Devious Minds", "https://www.youtube.com/watch?v=_UtlFmrWt1w"), - new Link("Enakhra's Lament", "https://www.youtube.com/watch?v=Y3kEIPYVaVE"), - new Link("Cabin Fever", "https://www.youtube.com/watch?v=k5DtxNXhOaw"), - new Link("Fairytale I - Growing Pains", "https://www.youtube.com/watch?v=cfGI9qFOmsg"), - new Link("Recipe for Disaster", "https://www.youtube.com/watch?v=hrAyyInJaTA"), - new Link("In Aid of the Myreque", "https://www.youtube.com/watch?v=O2Ru2NmuTaA"), - new Link("A Soul's Bane", "https://www.youtube.com/watch?v=dp8dp79qp6I"), - new Link("Rag and Bone Man", "https://www.youtube.com/watch?v=3owXSeN56W8"), - new Link("Swan Song", "https://www.youtube.com/watch?v=IpmERThXv2g"), - new Link("Royal Trouble", "https://www.youtube.com/watch?v=bVWUlKzNXEg"), - new Link("Death to the Dorgeshuun", "https://www.youtube.com/watch?v=2XJHuLhig98"), - new Link("Fairytale II - Cure a Queen", "https://www.youtube.com/watch?v=P6KkRk4_e3U"), - new Link("Lunar Diplomacy", "https://www.youtube.com/watch?v=vmeSKb7IBgQ"), - new Link("The Eyes of Glouphrie", "https://www.youtube.com/watch?v=0YCPwmZcxKA"), - new Link("Darkness of Hallowvale", "https://www.youtube.com/watch?v=QziKl99qdtU"), - new Link("Elemental Workshop II", "https://www.youtube.com/watch?v=Bb4E7ecIgv0"), - new Link("My Arm's Big Adventure", "https://www.youtube.com/watch?v=xa1KWOewgYA"), - new Link("Enlightened Journey", "https://www.youtube.com/watch?v=XAPthC8d7k0"), - new Link("Eagles' Peak", "https://www.youtube.com/watch?v=KDxIrrwXp7U"), - new Link("Animal Magnetism", "https://www.youtube.com/watch?v=kUyjXA7TaFU"), - new Link("Contact!", "https://www.youtube.com/watch?v=czn-yWABBWs"), - new Link("Cold War", "https://www.youtube.com/watch?v=0m1KpP-qKWI"), - new Link("The Fremennik Isles", "https://www.youtube.com/watch?v=EvxhiOWmraY"), - new Link("The Great Brain Robbery", "https://www.youtube.com/watch?v=ImHFASuNUN8"), - new Link("What Lies Below", "https://www.youtube.com/watch?v=f_9nVMGTtuo"), - new Link("Olaf's Quest", "https://www.youtube.com/watch?v=mXV5bM1NFMM"), - new Link("Dream Mentor", "https://www.youtube.com/watch?v=XDLUu0Kf0sE"), - new Link("Grim Tales", "https://www.youtube.com/watch?v=dFB0Q6v8Apw"), - new Link("King's Ransom", "https://www.youtube.com/watch?v=UJz9ZfF3uCY"), - new Link("Shilo Village", "https://www.youtube.com/watch?v=bDvBi8FT-QI"), - new Link("Biohazard", "https://www.youtube.com/watch?v=n9k87LwOGMk"), - new Link("Tower of Life", "https://www.youtube.com/watch?v=KReMcWpeY3k"), - new Link("Rag and Bone Man II", "https://www.youtube.com/watch?v=KGdHiDDUX_U"), - new Link("Zogre Flesh Eaters", "https://www.youtube.com/watch?v=vzm4949kXP4"), - new Link("Monkey Madness II", "https://www.youtube.com/watch?v=ykE5LbjABaI"), - new Link("Client of Kourend", "https://www.youtube.com/watch?v=Y-KIHF-cL9w"), - new Link("The Queen of Thieves", "https://www.youtube.com/watch?v=W94zFZVrHkQ"), - new Link("Bone Voyage", "https://www.youtube.com/watch?v=-VTR4p8kPmI"), - new Link("Dragon Slayer II", "https://www.youtube.com/watch?v=4BMb3Zwzk_U"), - new Link("The Depths of Despair", "https://www.youtube.com/watch?v=CaVUk2eAsKs"), - new Link("A Taste of Hope", "https://www.youtube.com/watch?v=VjdgEIizdSc"), - new Link("Tale of the Righteous", "https://www.youtube.com/watch?v=99yiv0tPl58"), - new Link("Making Friends with My Arm", "https://www.youtube.com/watch?v=DltzzhIsM_Q"), - new Link("The Ascent of Arceuus", "https://www.youtube.com/watch?v=4VQnfrv6S18"), - new Link("The Forsaken Tower", "https://www.youtube.com/watch?v=con0sXl5NBY"), - new Link("Fishing Contest", "https://www.youtube.com/watch?v=XYSv37A_l5w"), - new Link("Tribal Totem", "https://www.youtube.com/watch?v=XkUEIjr886M"), - new Link("Sea Slug", "https://www.youtube.com/watch?v=oOZVfa5SkVQ"), - new Link("The Tourist Trap", "https://www.youtube.com/watch?v=0bmSCCepMvo"), - new Link("Eadgar's Ruse", "https://www.youtube.com/watch?v=aVQ3DjTElXg"), - new Link("Shades of Mort'ton", "https://www.youtube.com/watch?v=eF05R8OMxgg"), - new Link("The Fremennik Trials", "https://www.youtube.com/watch?v=YUIvEgcvl5c"), - new Link("Ghosts Ahoy", "https://www.youtube.com/watch?v=aNBkLOywDfM"), - new Link("The Feud", "https://www.youtube.com/watch?v=nlBSc9IUklA"), - new Link("Forgettable Tale...", "https://www.youtube.com/watch?v=3HvFd6AxNU0"), - new Link("Making History", "https://www.youtube.com/watch?v=bOTGi2zAuhs"), - new Link("The Hand in the Sand", "https://www.youtube.com/watch?v=gdNLcZ-l1Lw"), - new Link("The Slug Menace", "https://www.youtube.com/watch?v=BRQbdr3JEZ8"), - new Link("Another Slice of H.A.M.", "https://www.youtube.com/watch?v=Yq3db7827Lk") - }; +class QuestGuideLinks +{ + private static final Link[] QUEST_GUIDE_LINKS = { + // Free Quests + new Link("Cook's Assistant", "https://www.youtube.com/watch?v=ehmtDRelj3c"), + new Link("Romeo & Juliet", "https://www.youtube.com/watch?v=rH_biWSNWVY"), + new Link("Demon Slayer", "https://www.youtube.com/watch?v=hgACrzJSiQk"), + new Link("Shield of Arrav", "https://www.youtube.com/watch?v=a_imLDKUdzg"), + new Link("Sheep Shearer", "https://www.youtube.com/watch?v=XFG3aNwK68s"), + new Link("The Restless Ghost", "https://www.youtube.com/watch?v=UkWNcsG_pXM"), + new Link("Ernest the Chicken", "https://www.youtube.com/watch?v=cq8NIVhSqh4"), + new Link("Vampire Slayer", "https://www.youtube.com/watch?v=FcEuxsDJWCU"), + new Link("Imp Catcher", "https://www.youtube.com/watch?v=LHgnl0FbOzk"), + new Link("Prince Ali Rescue", "https://www.youtube.com/watch?v=hrSPl1GfFaw"), + new Link("Doric's Quest", "https://www.youtube.com/watch?v=5TYyxHU27a4"), + new Link("Black Knights' Fortress", "https://www.youtube.com/watch?v=aekoZi3f9cU"), + new Link("Witch's Potion", "https://www.youtube.com/watch?v=XV4i5sPUvXo"), + new Link("The Knight's Sword", "https://www.youtube.com/watch?v=UkBWaI0rOqE"), + new Link("Goblin Diplomacy", "https://www.youtube.com/watch?v=P9BKOb_dLoY"), + new Link("Pirate's Treasure", "https://www.youtube.com/watch?v=zcD87PQW8Qk"), + new Link("Dragon Slayer", "https://www.youtube.com/watch?v=bMtCjlFOaBI"), + new Link("Rune Mysteries", "https://www.youtube.com/watch?v=l8ZhaN8uoS0"), + new Link("Misthalin Mystery", "https://www.youtube.com/watch?v=QlFqVAobAlQ"), + new Link("The Corsair Curse", "https://www.youtube.com/watch?v=wi7mUAHExz4"), + new Link("X Marks the Spot", "https://www.youtube.com/watch?v=GhRgvEG5jxQ"), + // Members Quests + new Link("Druidic Ritual", "https://www.youtube.com/watch?v=QIfU6HSmH4w"), + new Link("Lost City", "https://www.youtube.com/watch?v=T-kQNUSjFZI"), + new Link("Witch's House", "https://www.youtube.com/watch?v=TLsg7Wa-LUA"), + new Link("Merlin's Crystal", "https://www.youtube.com/watch?v=ESX-qriNtCE"), + new Link("Heroes' Quest", "https://www.youtube.com/watch?v=hK2N0WLKviE"), + new Link("Scorpion Catcher", "https://www.youtube.com/watch?v=xpqdec7_ZWg"), + new Link("Family Crest", "https://www.youtube.com/watch?v=0mk_Cgjr738"), + new Link("Monk's Friend", "https://www.youtube.com/watch?v=avi4y4G3Hcw"), + new Link("Temple of Ikov", "https://www.youtube.com/watch?v=5K7jDgr_4Z4"), + new Link("Clock Tower", "https://www.youtube.com/watch?v=GUCkkQFzyDw"), + new Link("Holy Grail", "https://www.youtube.com/watch?v=cgXoV1QlYco"), + new Link("Tree Gnome Village", "https://www.youtube.com/watch?v=T6Su__yuyRI"), + new Link("Fight Arena", "https://www.youtube.com/watch?v=4Nqjep2E5pw"), + new Link("Hazeel Cult", "https://www.youtube.com/watch?v=2_fhFJW6cNY"), + new Link("Sheep Herder", "https://www.youtube.com/watch?v=akC9FeYCG1Q"), + new Link("Plague City", "https://www.youtube.com/watch?v=Hf2wQQZL5CU"), + new Link("Waterfall Quest", "https://www.youtube.com/watch?v=xWBSnGkQTi4"), + new Link("Jungle Potion", "https://www.youtube.com/watch?v=xqLKsFz08As"), + new Link("The Grand Tree", "https://www.youtube.com/watch?v=N5e_Jus_E-Y"), + new Link("Underground Pass", "https://www.youtube.com/watch?v=5klGJg1wY8k"), + new Link("Observatory Quest", "https://www.youtube.com/watch?v=yxa9B6svv44"), + new Link("Watchtower", "https://www.youtube.com/watch?v=Vb10GoYP7FE"), + new Link("Dwarf Cannon", "https://www.youtube.com/watch?v=pROFg5jcCR0"), + new Link("Murder Mystery", "https://www.youtube.com/watch?v=P1IDGCA2f9o"), + new Link("The Dig Site", "https://www.youtube.com/watch?v=TOdcWV4MzuU"), + new Link("Gertrude's Cat", "https://www.youtube.com/watch?v=g7S09wA8EAY"), + new Link("Legends' Quest", "https://www.youtube.com/watch?v=Lid8enDEF_U"), + new Link("Death Plateau", "https://www.youtube.com/watch?v=SIQFmTvnb6w"), + new Link("Big Chompy Bird Hunting", "https://www.youtube.com/watch?v=s2fytMOHJXI"), + new Link("Elemental Workshop I", "https://www.youtube.com/watch?v=tbZD2RDqvfQ"), + new Link("Nature Spirit", "https://www.youtube.com/watch?v=Enf8vUWb5o0"), + new Link("Priest in Peril", "https://www.youtube.com/watch?v=fyYri6wUQIU"), + new Link("Regicide", "https://www.youtube.com/watch?v=KkWM-ok3C4Y"), + new Link("Tai Bwo Wannai Trio", "https://www.youtube.com/watch?v=Mdair5mvZL0"), + new Link("Troll Stronghold", "https://www.youtube.com/watch?v=zqmUs-f3AKA"), + new Link("Horror from the Deep", "https://www.youtube.com/watch?v=9htK8kb6DR8"), + new Link("Throne of Miscellania", "https://www.youtube.com/watch?v=fzGMnv2skBE"), + new Link("Monkey Madness I", "https://www.youtube.com/watch?v=VnoRfeBnPFA"), + new Link("Haunted Mine", "https://www.youtube.com/watch?v=cIc6loJHm9Q"), + new Link("Troll Romance", "https://www.youtube.com/watch?v=j2zifZVu7Gc"), + new Link("In Search of the Myreque", "https://www.youtube.com/watch?v=5nmYFHdAXAQ"), + new Link("Creature of Fenkenstrain", "https://www.youtube.com/watch?v=swqUVIs7B7M"), + new Link("Roving Elves", "https://www.youtube.com/watch?v=J3qf9DnT9cA"), + new Link("One Small Favour", "https://www.youtube.com/watch?v=ix_0-W3e9ps"), + new Link("Mountain Daughter", "https://www.youtube.com/watch?v=HETx_LX7aiY"), + new Link("Between a Rock...", "https://www.youtube.com/watch?v=cB11I45EGgA"), + new Link("The Golem", "https://www.youtube.com/watch?v=qpEHpiO6lLw"), + new Link("Desert Treasure", "https://www.youtube.com/watch?v=BuIqulIsICo"), + new Link("Icthlarin's Little Helper", "https://www.youtube.com/watch?v=wpNKm8_vUOM"), + new Link("Tears of Guthix", "https://www.youtube.com/watch?v=EMonDNI0uPk"), + new Link("The Lost Tribe", "https://www.youtube.com/watch?v=spZErjRnCdc"), + new Link("The Giant Dwarf", "https://www.youtube.com/watch?v=Z7PsGpOYgxY"), + new Link("Recruitment Drive", "https://www.youtube.com/watch?v=sOuzMpA_xtw"), + new Link("Mourning's Ends Part I", "https://www.youtube.com/watch?v=vuzAdk-h3c0"), + new Link("Garden of Tranquillity", "https://www.youtube.com/watch?v=7hbCzYnLCsQ"), + new Link("A Tail of Two Cats", "https://www.youtube.com/watch?v=SgN9Yw_YqHk"), + new Link("Wanted!", "https://www.youtube.com/watch?v=ZHZAKDCfXGs"), + new Link("Mourning's Ends Part II", "https://www.youtube.com/watch?v=FK5sLogGbU8"), + new Link("Rum Deal", "https://www.youtube.com/watch?v=I14CIu5x2S8"), + new Link("Shadow of the Storm", "https://www.youtube.com/watch?v=5ZvWd3XCQjI"), + new Link("Ratcatchers", "https://www.youtube.com/watch?v=s7G22fEuhTc"), + new Link("Spirits of the Elid", "https://www.youtube.com/watch?v=A1zAX55hZC0"), + new Link("Devious Minds", "https://www.youtube.com/watch?v=_UtlFmrWt1w"), + new Link("Enakhra's Lament", "https://www.youtube.com/watch?v=Y3kEIPYVaVE"), + new Link("Cabin Fever", "https://www.youtube.com/watch?v=k5DtxNXhOaw"), + new Link("Fairytale I - Growing Pains", "https://www.youtube.com/watch?v=cfGI9qFOmsg"), + new Link("Recipe for Disaster", "https://www.youtube.com/watch?v=hrAyyInJaTA"), + new Link("In Aid of the Myreque", "https://www.youtube.com/watch?v=O2Ru2NmuTaA"), + new Link("A Soul's Bane", "https://www.youtube.com/watch?v=dp8dp79qp6I"), + new Link("Rag and Bone Man", "https://www.youtube.com/watch?v=3owXSeN56W8"), + new Link("Swan Song", "https://www.youtube.com/watch?v=IpmERThXv2g"), + new Link("Royal Trouble", "https://www.youtube.com/watch?v=bVWUlKzNXEg"), + new Link("Death to the Dorgeshuun", "https://www.youtube.com/watch?v=2XJHuLhig98"), + new Link("Fairytale II - Cure a Queen", "https://www.youtube.com/watch?v=P6KkRk4_e3U"), + new Link("Lunar Diplomacy", "https://www.youtube.com/watch?v=vmeSKb7IBgQ"), + new Link("The Eyes of Glouphrie", "https://www.youtube.com/watch?v=0YCPwmZcxKA"), + new Link("Darkness of Hallowvale", "https://www.youtube.com/watch?v=QziKl99qdtU"), + new Link("Elemental Workshop II", "https://www.youtube.com/watch?v=Bb4E7ecIgv0"), + new Link("My Arm's Big Adventure", "https://www.youtube.com/watch?v=xa1KWOewgYA"), + new Link("Enlightened Journey", "https://www.youtube.com/watch?v=XAPthC8d7k0"), + new Link("Eagles' Peak", "https://www.youtube.com/watch?v=KDxIrrwXp7U"), + new Link("Animal Magnetism", "https://www.youtube.com/watch?v=kUyjXA7TaFU"), + new Link("Contact!", "https://www.youtube.com/watch?v=czn-yWABBWs"), + new Link("Cold War", "https://www.youtube.com/watch?v=0m1KpP-qKWI"), + new Link("The Fremennik Isles", "https://www.youtube.com/watch?v=EvxhiOWmraY"), + new Link("The Great Brain Robbery", "https://www.youtube.com/watch?v=ImHFASuNUN8"), + new Link("What Lies Below", "https://www.youtube.com/watch?v=f_9nVMGTtuo"), + new Link("Olaf's Quest", "https://www.youtube.com/watch?v=mXV5bM1NFMM"), + new Link("Dream Mentor", "https://www.youtube.com/watch?v=XDLUu0Kf0sE"), + new Link("Grim Tales", "https://www.youtube.com/watch?v=dFB0Q6v8Apw"), + new Link("King's Ransom", "https://www.youtube.com/watch?v=UJz9ZfF3uCY"), + new Link("Shilo Village", "https://www.youtube.com/watch?v=bDvBi8FT-QI"), + new Link("Biohazard", "https://www.youtube.com/watch?v=n9k87LwOGMk"), + new Link("Tower of Life", "https://www.youtube.com/watch?v=KReMcWpeY3k"), + new Link("Rag and Bone Man II", "https://www.youtube.com/watch?v=KGdHiDDUX_U"), + new Link("Zogre Flesh Eaters", "https://www.youtube.com/watch?v=vzm4949kXP4"), + new Link("Monkey Madness II", "https://www.youtube.com/watch?v=ykE5LbjABaI"), + new Link("Client of Kourend", "https://www.youtube.com/watch?v=Y-KIHF-cL9w"), + new Link("The Queen of Thieves", "https://www.youtube.com/watch?v=W94zFZVrHkQ"), + new Link("Bone Voyage", "https://www.youtube.com/watch?v=-VTR4p8kPmI"), + new Link("Dragon Slayer II", "https://www.youtube.com/watch?v=4BMb3Zwzk_U"), + new Link("The Depths of Despair", "https://www.youtube.com/watch?v=CaVUk2eAsKs"), + new Link("A Taste of Hope", "https://www.youtube.com/watch?v=VjdgEIizdSc"), + new Link("Tale of the Righteous", "https://www.youtube.com/watch?v=99yiv0tPl58"), + new Link("Making Friends with My Arm", "https://www.youtube.com/watch?v=DltzzhIsM_Q"), + new Link("The Ascent of Arceuus", "https://www.youtube.com/watch?v=4VQnfrv6S18"), + new Link("The Forsaken Tower", "https://www.youtube.com/watch?v=con0sXl5NBY"), + new Link("Fishing Contest", "https://www.youtube.com/watch?v=XYSv37A_l5w"), + new Link("Tribal Totem", "https://www.youtube.com/watch?v=XkUEIjr886M"), + new Link("Sea Slug", "https://www.youtube.com/watch?v=oOZVfa5SkVQ"), + new Link("The Tourist Trap", "https://www.youtube.com/watch?v=0bmSCCepMvo"), + new Link("Eadgar's Ruse", "https://www.youtube.com/watch?v=aVQ3DjTElXg"), + new Link("Shades of Mort'ton", "https://www.youtube.com/watch?v=eF05R8OMxgg"), + new Link("The Fremennik Trials", "https://www.youtube.com/watch?v=YUIvEgcvl5c"), + new Link("Ghosts Ahoy", "https://www.youtube.com/watch?v=aNBkLOywDfM"), + new Link("The Feud", "https://www.youtube.com/watch?v=nlBSc9IUklA"), + new Link("Forgettable Tale...", "https://www.youtube.com/watch?v=3HvFd6AxNU0"), + new Link("Making History", "https://www.youtube.com/watch?v=bOTGi2zAuhs"), + new Link("The Hand in the Sand", "https://www.youtube.com/watch?v=gdNLcZ-l1Lw"), + new Link("The Slug Menace", "https://www.youtube.com/watch?v=BRQbdr3JEZ8"), + new Link("Another Slice of H.A.M.", "https://www.youtube.com/watch?v=Yq3db7827Lk") + }; - private static class Link { + private static class Link + { - private String questName; - private String url; + private String questName; + private String url; - public Link(String questName, String url) { - this.questName = questName; - this.url = url; - } + Link(String questName, String url) + { + this.questName = questName; + this.url = url; + } - public String getQuestName() { - return questName; - } + String getQuestName() + { + return questName; + } - public void openURL() { - LinkBrowser.browse(this.url); - } + void openURL() + { + LinkBrowser.browse(this.url); + } - } + } - private static boolean openGuide(String questName) { - for (Link link : QUEST_GUIDE_LINKS) { - if (link.getQuestName().equals(questName)) { - link.openURL(); - return true; - } - } - return false; - } + private static boolean openGuide(String questName) + { + for (Link link : QUEST_GUIDE_LINKS) + { + if (link.getQuestName().equals(questName)) + { + link.openURL(); + return true; + } + } + return false; + } - private static void logQuestNotFoundError(String questName, ChatMessageManager chatMessageManager) { - String chatMessage = new ChatMessageBuilder() - .append(ChatColorType.HIGHLIGHT) - .append("Could not find Slayermusiq1 guide for " + questName) - .build(); + private static void logQuestNotFoundError(String questName, ChatMessageManager chatMessageManager) + { + String chatMessage = new ChatMessageBuilder() + .append(ChatColorType.HIGHLIGHT) + .append("Could not find Slayermusiq1 guide for " + questName) + .build(); - chatMessageManager.queue(QueuedMessage.builder() - .type(ChatMessageType.GAMEMESSAGE) - .runeLiteFormattedMessage(chatMessage) - .build()); - } + chatMessageManager.queue(QueuedMessage.builder() + .type(ChatMessageType.GAMEMESSAGE) + .runeLiteFormattedMessage(chatMessage) + .build()); + } - public static void tryOpenGuide(String questName, ChatMessageManager chatMessageManager) { - boolean success = openGuide(questName); - if (!success) { - logQuestNotFoundError(questName, chatMessageManager); - } - } + static void tryOpenGuide(String questName, ChatMessageManager chatMessageManager) + { + boolean success = openGuide(questName); + if (!success) + { + logQuestNotFoundError(questName, chatMessageManager); + } + } } \ No newline at end of file diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/slayermusiq/SlayermusiqPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/slayermusiq/SlayermusiqPlugin.java index d828eadd57..d8bca0ca18 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/slayermusiq/SlayermusiqPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/slayermusiq/SlayermusiqPlugin.java @@ -51,30 +51,22 @@ */ package net.runelite.client.plugins.slayermusiq; -import com.google.inject.Provides; import com.google.common.primitives.Ints; -import java.awt.Dimension; -import java.util.ArrayList; import java.util.Arrays; -import java.util.HashMap; -import java.util.List; -import java.util.Map; import javax.inject.Inject; -import javax.swing.SwingUtilities; -import lombok.Getter; import lombok.extern.slf4j.Slf4j; import net.runelite.api.Client; import net.runelite.api.MenuAction; import net.runelite.api.MenuEntry; -import net.runelite.api.widgets.WidgetInfo; import net.runelite.api.events.MenuEntryAdded; import net.runelite.api.events.MenuOptionClicked; -import net.runelite.client.plugins.PluginType; -import net.runelite.client.util.Text; +import net.runelite.api.widgets.WidgetInfo; import net.runelite.client.chat.ChatMessageManager; import net.runelite.client.eventbus.Subscribe; import net.runelite.client.plugins.Plugin; import net.runelite.client.plugins.PluginDescriptor; +import net.runelite.client.plugins.PluginType; +import net.runelite.client.util.Text; @PluginDescriptor( name = "Slayermusiq1 Guides", @@ -118,7 +110,8 @@ public class SlayermusiqPlugin extends Plugin public void onMenuEntryAdded(MenuEntryAdded event) { int widgetID = event.getActionParam1(); - if (Ints.contains(QUESTLIST_WIDGET_IDS, widgetID) && "Read Journal:".equals(event.getOption())) { + if (Ints.contains(QUESTLIST_WIDGET_IDS, widgetID) && "Read Journal:".equals(event.getOption())) + { MenuEntry[] menuEntries = client.getMenuEntries(); MenuEntry newMenuEntry = createSlayermusiqOptionMenuEntry(event); @@ -130,15 +123,18 @@ public class SlayermusiqPlugin extends Plugin } @Subscribe - private void onMenuOptionClicked(MenuOptionClicked ev) { - if (ev.getMenuAction() == MenuAction.RUNELITE && ev.getMenuOption().equals(MENUOP_SLAYERMUSIQ)) { + private void onMenuOptionClicked(MenuOptionClicked ev) + { + if (ev.getMenuAction() == MenuAction.RUNELITE && ev.getMenuOption().equals(MENUOP_SLAYERMUSIQ)) + { ev.consume(); String quest = Text.removeTags(ev.getMenuTarget()); QuestGuideLinks.tryOpenGuide(quest, chatMessageManager); } } - private MenuEntry createSlayermusiqOptionMenuEntry(MenuEntryAdded event) { + private MenuEntry createSlayermusiqOptionMenuEntry(MenuEntryAdded event) + { int widgetIndex = event.getActionParam0(); int widgetID = event.getActionParam1(); diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/smelting/SmeltingOverlay.java b/runelite-client/src/main/java/net/runelite/client/plugins/smelting/SmeltingOverlay.java index 7a49c00144..7b140dbd61 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/smelting/SmeltingOverlay.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/smelting/SmeltingOverlay.java @@ -79,16 +79,16 @@ class SmeltingOverlay extends Overlay if (isSmelting() || Duration.between(session.getLastItemSmelted(), Instant.now()).getSeconds() < SMELT_TIMEOUT) { panelComponent.getChildren().add(TitleComponent.builder() - .text("Smelting") - .color(Color.GREEN) - .build()); + .text("Smelting") + .color(Color.GREEN) + .build()); } else { panelComponent.getChildren().add(TitleComponent.builder() - .text("NOT smelting") - .color(Color.RED) - .build()); + .text("NOT smelting") + .color(Color.RED) + .build()); } int actions = xpTrackerService.getActions(Skill.SMITHING); @@ -97,23 +97,23 @@ class SmeltingOverlay extends Overlay if (plugin.getSession().getBarsSmelted() > 0) { panelComponent.getChildren().add(LineComponent.builder() - .left("Bars:") - .right(Integer.toString(session.getBarsSmelted())) - .build()); + .left("Bars:") + .right(Integer.toString(session.getBarsSmelted())) + .build()); } if (plugin.getSession().getCannonBallsSmelted() > 0) { panelComponent.getChildren().add(LineComponent.builder() - .left("Cannonballs:") - .right(Integer.toString(session.getCannonBallsSmelted())) - .build()); + .left("Cannonballs:") + .right(Integer.toString(session.getCannonBallsSmelted())) + .build()); } if (actions > 2) { panelComponent.getChildren().add(LineComponent.builder() - .left("Actions/hr:") - .right(Integer.toString(xpTrackerService.getActionsHr(Skill.SMITHING))) - .build()); + .left("Actions/hr:") + .right(Integer.toString(xpTrackerService.getActionsHr(Skill.SMITHING))) + .build()); } } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/specbar/SpecBarPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/specbar/SpecBarPlugin.java index 7630f0292a..64622943b8 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/specbar/SpecBarPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/specbar/SpecBarPlugin.java @@ -1,75 +1,74 @@ -package net.runelite.client.plugins.specbar; - -import javax.inject.Inject; -import net.runelite.api.Client; -import net.runelite.api.GameState; -import net.runelite.api.events.GameStateChanged; -import net.runelite.api.events.WidgetHiddenChanged; -import net.runelite.api.widgets.Widget; -import net.runelite.api.widgets.WidgetID; -import net.runelite.api.widgets.WidgetInfo; -import net.runelite.client.eventbus.Subscribe; -import net.runelite.client.plugins.Plugin; -import net.runelite.client.plugins.PluginDescriptor; -import net.runelite.client.plugins.PluginManager; -import net.runelite.client.plugins.PluginType; - -@PluginDescriptor( - name = "Spec Bar", - description = "Adds a spec bar to every weapon", - tags = {"spec bar", "special attack", "spec", "bar", "pklite"}, - enabledByDefault = false, - type = PluginType.PVP -) -public class SpecBarPlugin extends Plugin -{ - - @Inject - private Client client; - - @Override - protected void startUp() throws Exception - { - } - - @Override - protected void shutDown() throws Exception - { - } - - @Subscribe - private void onWidgetHiddenChanged(WidgetHiddenChanged event) - { - if (WidgetInfo.TO_GROUP(event.getWidget().getId()) == WidgetID.COMBAT_GROUP_ID) - { - hideSpecBar(); - } - } - - @Subscribe - private void onGameStateChanged(GameStateChanged event) - { - if (event.getGameState().equals(GameState.LOGGING_IN)) - { - hideSpecBar(); - } - - } - - /** - * Displays the special attack bar - */ - private void hideSpecBar() - { - try - { - Widget specBar = client.getWidget(WidgetInfo.COMBAT_SPECIAL_ATTACK); - specBar.setHidden(false); - specBar.revalidate(); - } - catch (NullPointerException e) - { - // Stops the nulls that occur before the spec bar is loaded by player equipping a spec wep - } - } -} +package net.runelite.client.plugins.specbar; + +import javax.inject.Inject; +import net.runelite.api.Client; +import net.runelite.api.GameState; +import net.runelite.api.events.GameStateChanged; +import net.runelite.api.events.WidgetHiddenChanged; +import net.runelite.api.widgets.Widget; +import net.runelite.api.widgets.WidgetID; +import net.runelite.api.widgets.WidgetInfo; +import net.runelite.client.eventbus.Subscribe; +import net.runelite.client.plugins.Plugin; +import net.runelite.client.plugins.PluginDescriptor; +import net.runelite.client.plugins.PluginType; + +@PluginDescriptor( + name = "Spec Bar", + description = "Adds a spec bar to every weapon", + tags = {"spec bar", "special attack", "spec", "bar", "pklite"}, + enabledByDefault = false, + type = PluginType.PVP +) +public class SpecBarPlugin extends Plugin +{ + + @Inject + private Client client; + + @Override + protected void startUp() throws Exception + { + } + + @Override + protected void shutDown() throws Exception + { + } + + @Subscribe + private void onWidgetHiddenChanged(WidgetHiddenChanged event) + { + if (WidgetInfo.TO_GROUP(event.getWidget().getId()) == WidgetID.COMBAT_GROUP_ID) + { + hideSpecBar(); + } + } + + @Subscribe + private void onGameStateChanged(GameStateChanged event) + { + if (event.getGameState().equals(GameState.LOGGING_IN)) + { + hideSpecBar(); + } + + } + + /** + * Displays the special attack bar + */ + private void hideSpecBar() + { + try + { + Widget specBar = client.getWidget(WidgetInfo.COMBAT_SPECIAL_ATTACK); + specBar.setHidden(false); + specBar.revalidate(); + } + catch (NullPointerException e) + { + // Stops the nulls that occur before the spec bar is loaded by player equipping a spec wep + } + } +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/spellbook/SpellbookPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/spellbook/SpellbookPlugin.java index eaaa975c40..7184f341fe 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/spellbook/SpellbookPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/spellbook/SpellbookPlugin.java @@ -78,10 +78,11 @@ public class SpellbookPlugin extends Plugin private static final String MENU_TARGET = "Reordering"; private static final WidgetMenuOption FIXED_MAGIC_TAB_LOCK = new WidgetMenuOption(LOCK, MENU_TARGET, WidgetInfo.FIXED_VIEWPORT_MAGIC_TAB); private static final WidgetMenuOption FIXED_MAGIC_TAB_UNLOCK = new WidgetMenuOption(UNLOCK, MENU_TARGET, WidgetInfo.FIXED_VIEWPORT_MAGIC_TAB); - private static final WidgetMenuOption RESIZABLE_MAGIC_TAB_LOCK = new WidgetMenuOption(LOCK, MENU_TARGET, WidgetInfo.RESIZABLE_VIEWPORT_MAGIC_TAB); - private static final WidgetMenuOption RESIZABLE_MAGIC_TAB_UNLOCK = new WidgetMenuOption(UNLOCK, MENU_TARGET, WidgetInfo.RESIZABLE_VIEWPORT_MAGIC_TAB); - private static final WidgetMenuOption RESIZABLE_BOTTOM_LINE_MAGIC_TAB_LOCK = new WidgetMenuOption(LOCK, MENU_TARGET, WidgetInfo.RESIZABLE_VIEWPORT_BOTTOM_LINE_MAGIC_TAB); - private static final WidgetMenuOption RESIZABLE_BOTTOM_LINE_MAGIC_TAB_UNLOCK = new WidgetMenuOption(UNLOCK, MENU_TARGET, WidgetInfo.RESIZABLE_VIEWPORT_BOTTOM_LINE_MAGIC_TAB); + private static final WidgetMenuOption RESIZABLE_MAGIC_TAB_LOCK = new WidgetMenuOption(LOCK, MENU_TARGET, WidgetInfo.RESIZABLE_VIEWPORT_MAGIC_TAB); + private static final WidgetMenuOption RESIZABLE_MAGIC_TAB_UNLOCK = new WidgetMenuOption(UNLOCK, MENU_TARGET, WidgetInfo.RESIZABLE_VIEWPORT_MAGIC_TAB); + private static final WidgetMenuOption RESIZABLE_BOTTOM_LINE_MAGIC_TAB_LOCK = new WidgetMenuOption(LOCK, MENU_TARGET, WidgetInfo.RESIZABLE_VIEWPORT_BOTTOM_LINE_MAGIC_TAB); + private static final WidgetMenuOption RESIZABLE_BOTTOM_LINE_MAGIC_TAB_UNLOCK = new WidgetMenuOption(UNLOCK, MENU_TARGET, WidgetInfo.RESIZABLE_VIEWPORT_BOTTOM_LINE_MAGIC_TAB); + private enum WordFilterMode { CONTAINS, @@ -382,9 +383,9 @@ public class SpellbookPlugin extends Plugin int widget = iStack[iStackSize - 1]; int visCount = (int) spells.values().stream() - .map(Spell::getName) - .filter(s -> isUnfiltered(s, tmp)) - .count(); + .map(Spell::getName) + .filter(s -> isUnfiltered(s, tmp)) + .count(); if (visCount > 20 || visCount == 0) { @@ -437,7 +438,9 @@ public class SpellbookPlugin extends Plugin } // CHECKSTYLE:OFF - Collection gson = GSON.fromJson(cfg, new TypeToken>(){}.getType()); + Collection gson = GSON.fromJson(cfg, new TypeToken>() + { + }.getType()); // CHECKSTYLE:ON gson.stream().filter(Objects::nonNull).forEach(s -> spells.put(s.getWidget(), s)); diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/statusbars/StatusBarsPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/statusbars/StatusBarsPlugin.java index e32895d910..bb7b766e50 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/statusbars/StatusBarsPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/statusbars/StatusBarsPlugin.java @@ -1,132 +1,132 @@ -/* - * Copyright (c) 2018, Jos - * 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.statusbars; - -import java.time.Duration; -import java.time.Instant; -import java.util.Arrays; -import java.util.List; -import javax.inject.Inject; -import com.google.inject.Provides; -import lombok.AccessLevel; -import lombok.Getter; -import net.runelite.api.Actor; -import net.runelite.api.Client; -import net.runelite.api.NPC; -import net.runelite.api.NPCComposition; -import net.runelite.api.events.GameTick; -import net.runelite.client.config.ConfigManager; -import net.runelite.client.eventbus.Subscribe; -import net.runelite.client.plugins.Plugin; -import net.runelite.client.plugins.PluginDependency; -import net.runelite.client.plugins.PluginDescriptor; -import net.runelite.client.plugins.itemstats.ItemStatPlugin; -import net.runelite.client.ui.overlay.OverlayManager; - -@PluginDescriptor( - name = "Status Bars", - description = "Draws status bars next to players inventory showing current HP & Prayer and healing amounts", - enabledByDefault = false -) -@PluginDependency(ItemStatPlugin.class) -public class StatusBarsPlugin extends Plugin -{ - @Inject - private StatusBarsOverlay overlay; - - @Inject - private OverlayManager overlayManager; - - @Inject - private Client client; - - @Inject - private StatusBarsConfig config; - - @Getter(AccessLevel.PACKAGE) - private Instant lastCombatAction; - - @Override - protected void startUp() throws Exception - { - } - - void updateLastCombatAction() - { - this.lastCombatAction = Instant.now(); - } - - @Subscribe - public void onGameTick(GameTick gameTick) - { - if (!config.toggleRestorationBars()) - { - overlayManager.add(overlay); - return; - } - else - { - hideStatusBar(); - } - } - - private void hideStatusBar() - { - final Actor interacting = client.getLocalPlayer().getInteracting(); - final boolean isNpc = interacting instanceof NPC; - final int combatTimeout = config.hideStatusBarDelay(); - - if (isNpc) - { - final NPC npc = (NPC) interacting; - final NPCComposition npcComposition = npc.getComposition(); - final List npcMenuActions = Arrays.asList(npcComposition.getActions()); - if (npcMenuActions.contains("Attack") && config.toggleRestorationBars()) - { - updateLastCombatAction(); - overlayManager.add(overlay); - } - } - else if (lastCombatAction != null) - { - if (Duration.between(getLastCombatAction(), Instant.now()).getSeconds() > combatTimeout) - { - overlayManager.remove(overlay); - } - } - } - - @Override - protected void shutDown() throws Exception - { - overlayManager.remove(overlay); - } - - @Provides - StatusBarsConfig provideConfig(ConfigManager configManager) - { - return configManager.getConfig(StatusBarsConfig.class); - } -} +/* + * Copyright (c) 2018, Jos + * 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.statusbars; + +import com.google.inject.Provides; +import java.time.Duration; +import java.time.Instant; +import java.util.Arrays; +import java.util.List; +import javax.inject.Inject; +import lombok.AccessLevel; +import lombok.Getter; +import net.runelite.api.Actor; +import net.runelite.api.Client; +import net.runelite.api.NPC; +import net.runelite.api.NPCComposition; +import net.runelite.api.events.GameTick; +import net.runelite.client.config.ConfigManager; +import net.runelite.client.eventbus.Subscribe; +import net.runelite.client.plugins.Plugin; +import net.runelite.client.plugins.PluginDependency; +import net.runelite.client.plugins.PluginDescriptor; +import net.runelite.client.plugins.itemstats.ItemStatPlugin; +import net.runelite.client.ui.overlay.OverlayManager; + +@PluginDescriptor( + name = "Status Bars", + description = "Draws status bars next to players inventory showing current HP & Prayer and healing amounts", + enabledByDefault = false +) +@PluginDependency(ItemStatPlugin.class) +public class StatusBarsPlugin extends Plugin +{ + @Inject + private StatusBarsOverlay overlay; + + @Inject + private OverlayManager overlayManager; + + @Inject + private Client client; + + @Inject + private StatusBarsConfig config; + + @Getter(AccessLevel.PACKAGE) + private Instant lastCombatAction; + + @Override + protected void startUp() throws Exception + { + } + + void updateLastCombatAction() + { + this.lastCombatAction = Instant.now(); + } + + @Subscribe + public void onGameTick(GameTick gameTick) + { + if (!config.toggleRestorationBars()) + { + overlayManager.add(overlay); + return; + } + else + { + hideStatusBar(); + } + } + + private void hideStatusBar() + { + final Actor interacting = client.getLocalPlayer().getInteracting(); + final boolean isNpc = interacting instanceof NPC; + final int combatTimeout = config.hideStatusBarDelay(); + + if (isNpc) + { + final NPC npc = (NPC) interacting; + final NPCComposition npcComposition = npc.getComposition(); + final List npcMenuActions = Arrays.asList(npcComposition.getActions()); + if (npcMenuActions.contains("Attack") && config.toggleRestorationBars()) + { + updateLastCombatAction(); + overlayManager.add(overlay); + } + } + else if (lastCombatAction != null) + { + if (Duration.between(getLastCombatAction(), Instant.now()).getSeconds() > combatTimeout) + { + overlayManager.remove(overlay); + } + } + } + + @Override + protected void shutDown() throws Exception + { + overlayManager.remove(overlay); + } + + @Provides + StatusBarsConfig provideConfig(ConfigManager configManager) + { + return configManager.getConfig(StatusBarsConfig.class); + } +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/statusbars/Viewport.java b/runelite-client/src/main/java/net/runelite/client/plugins/statusbars/Viewport.java index 737cda9df0..298ba7ea3e 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/statusbars/Viewport.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/statusbars/Viewport.java @@ -1,47 +1,47 @@ -/* - * Copyright (c) 2018, Jos - * 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.statusbars; - -import lombok.AllArgsConstructor; -import lombok.Getter; -import net.runelite.api.Point; -import net.runelite.api.widgets.WidgetInfo; - -@Getter -@AllArgsConstructor -enum Viewport -{ - RESIZED_BOX(WidgetInfo.RESIZABLE_VIEWPORT_OLD_SCHOOL_BOX, WidgetInfo.RESIZABLE_VIEWPORT_INTERFACE_CONTAINER, - new Point(20, -4), new Point( 0, -4)), - RESIZED_BOTTOM(WidgetInfo.RESIZABLE_VIEWPORT_BOTTOM_LINE, WidgetInfo.RESIZABLE_VIEWPORT_BOTTOM_LINE_INTERFACE_CONTAINER, - new Point(61, 8), new Point(35, -12)), - FIXED(WidgetInfo.FIXED_VIEWPORT, WidgetInfo.FIXED_VIEWPORT_INTERFACE_CONTAINER, - new Point(20, -4), new Point(0, -4)); - - private WidgetInfo container; - private WidgetInfo viewport; - private Point offsetLeft; - private Point offsetRight; -} +/* + * Copyright (c) 2018, Jos + * 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.statusbars; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import net.runelite.api.Point; +import net.runelite.api.widgets.WidgetInfo; + +@Getter +@AllArgsConstructor +enum Viewport +{ + RESIZED_BOX(WidgetInfo.RESIZABLE_VIEWPORT_OLD_SCHOOL_BOX, WidgetInfo.RESIZABLE_VIEWPORT_INTERFACE_CONTAINER, + new Point(20, -4), new Point(0, -4)), + RESIZED_BOTTOM(WidgetInfo.RESIZABLE_VIEWPORT_BOTTOM_LINE, WidgetInfo.RESIZABLE_VIEWPORT_BOTTOM_LINE_INTERFACE_CONTAINER, + new Point(61, 8), new Point(35, -12)), + FIXED(WidgetInfo.FIXED_VIEWPORT, WidgetInfo.FIXED_VIEWPORT_INTERFACE_CONTAINER, + new Point(20, -4), new Point(0, -4)); + + private WidgetInfo container; + private WidgetInfo viewport; + private Point offsetLeft; + private Point offsetRight; +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/stretchedmode/TranslateMouseListener.java b/runelite-client/src/main/java/net/runelite/client/plugins/stretchedmode/TranslateMouseListener.java index c99fa20950..00bfba3d8b 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/stretchedmode/TranslateMouseListener.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/stretchedmode/TranslateMouseListener.java @@ -1,98 +1,98 @@ -/* - * Copyright (c) 2018, Lotto - * 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.stretchedmode; - -import java.awt.Component; -import java.awt.Dimension; -import java.awt.event.MouseEvent; -import javax.inject.Inject; -import net.runelite.api.Client; -import net.runelite.client.input.MouseListener; - -public class TranslateMouseListener implements MouseListener -{ - private final Client client; - - @Inject - public TranslateMouseListener(Client client) - { - this.client = client; - } - - @Override - public MouseEvent mouseClicked(MouseEvent mouseEvent) - { - return translateEvent(mouseEvent); - } - - @Override - public MouseEvent mousePressed(MouseEvent mouseEvent) - { - return translateEvent(mouseEvent); - } - - @Override - public MouseEvent mouseReleased(MouseEvent mouseEvent) - { - return translateEvent(mouseEvent); - } - - @Override - public MouseEvent mouseEntered(MouseEvent mouseEvent) - { - return translateEvent(mouseEvent); - } - - @Override - public MouseEvent mouseExited(MouseEvent mouseEvent) - { - return translateEvent(mouseEvent); - } - - @Override - public MouseEvent mouseDragged(MouseEvent mouseEvent) - { - return translateEvent(mouseEvent); - } - - @Override - public MouseEvent mouseMoved(MouseEvent mouseEvent) - { - return translateEvent(mouseEvent); - } - - private MouseEvent translateEvent(MouseEvent e) - { - Dimension stretchedDimensions = client.getStretchedDimensions(); - Dimension realDimensions = client.getRealDimensions(); - - int newX = (int) (e.getX() / (stretchedDimensions.width / realDimensions.getWidth())); - int newY = (int) (e.getY() / (stretchedDimensions.height / realDimensions.getHeight())); - - return new MouseEvent((Component) e.getSource(), e.getID(), e.getWhen(), e.getModifiersEx(), - newX, newY, e.getClickCount(), e.isPopupTrigger(), e.getButton()); - } -} +/* + * Copyright (c) 2018, Lotto + * 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.stretchedmode; + +import java.awt.Component; +import java.awt.Dimension; +import java.awt.event.MouseEvent; +import javax.inject.Inject; +import net.runelite.api.Client; +import net.runelite.client.input.MouseListener; + +public class TranslateMouseListener implements MouseListener +{ + private final Client client; + + @Inject + public TranslateMouseListener(Client client) + { + this.client = client; + } + + @Override + public MouseEvent mouseClicked(MouseEvent mouseEvent) + { + return translateEvent(mouseEvent); + } + + @Override + public MouseEvent mousePressed(MouseEvent mouseEvent) + { + return translateEvent(mouseEvent); + } + + @Override + public MouseEvent mouseReleased(MouseEvent mouseEvent) + { + return translateEvent(mouseEvent); + } + + @Override + public MouseEvent mouseEntered(MouseEvent mouseEvent) + { + return translateEvent(mouseEvent); + } + + @Override + public MouseEvent mouseExited(MouseEvent mouseEvent) + { + return translateEvent(mouseEvent); + } + + @Override + public MouseEvent mouseDragged(MouseEvent mouseEvent) + { + return translateEvent(mouseEvent); + } + + @Override + public MouseEvent mouseMoved(MouseEvent mouseEvent) + { + return translateEvent(mouseEvent); + } + + private MouseEvent translateEvent(MouseEvent e) + { + Dimension stretchedDimensions = client.getStretchedDimensions(); + Dimension realDimensions = client.getRealDimensions(); + + int newX = (int) (e.getX() / (stretchedDimensions.width / realDimensions.getWidth())); + int newY = (int) (e.getY() / (stretchedDimensions.height / realDimensions.getHeight())); + + return new MouseEvent((Component) e.getSource(), e.getID(), e.getWhen(), e.getModifiersEx(), + newX, newY, e.getClickCount(), e.isPopupTrigger(), e.getButton()); + } +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/stretchedmode/TranslateMouseWheelListener.java b/runelite-client/src/main/java/net/runelite/client/plugins/stretchedmode/TranslateMouseWheelListener.java index 1dc12886f5..475a1a4bd4 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/stretchedmode/TranslateMouseWheelListener.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/stretchedmode/TranslateMouseWheelListener.java @@ -1,62 +1,62 @@ -/* - * Copyright (c) 2018, Lotto - * 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.stretchedmode; - -import java.awt.Component; -import java.awt.Dimension; -import java.awt.event.MouseWheelEvent; -import javax.inject.Inject; -import net.runelite.api.Client; -import net.runelite.client.input.MouseWheelListener; - -public class TranslateMouseWheelListener implements MouseWheelListener -{ - private final Client client; - - @Inject - public TranslateMouseWheelListener(Client client) - { - this.client = client; - } - - @Override - public MouseWheelEvent mouseWheelMoved(MouseWheelEvent event) - { - return translateEvent(event); - } - - private MouseWheelEvent translateEvent(MouseWheelEvent e) - { - Dimension stretchedDimensions = client.getStretchedDimensions(); - Dimension realDimensions = client.getRealDimensions(); - - int newX = (int) (e.getX() / (stretchedDimensions.width / realDimensions.getWidth())); - int newY = (int) (e.getY() / (stretchedDimensions.height / realDimensions.getHeight())); - - return new MouseWheelEvent((Component) e.getSource(), e.getID(), e.getWhen(), e.getModifiers(), newX, newY, - e.getClickCount(), e.isPopupTrigger(), e.getScrollType(), e.getScrollAmount(), e.getWheelRotation()); - } -} +/* + * Copyright (c) 2018, Lotto + * 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.stretchedmode; + +import java.awt.Component; +import java.awt.Dimension; +import java.awt.event.MouseWheelEvent; +import javax.inject.Inject; +import net.runelite.api.Client; +import net.runelite.client.input.MouseWheelListener; + +public class TranslateMouseWheelListener implements MouseWheelListener +{ + private final Client client; + + @Inject + public TranslateMouseWheelListener(Client client) + { + this.client = client; + } + + @Override + public MouseWheelEvent mouseWheelMoved(MouseWheelEvent event) + { + return translateEvent(event); + } + + private MouseWheelEvent translateEvent(MouseWheelEvent e) + { + Dimension stretchedDimensions = client.getStretchedDimensions(); + Dimension realDimensions = client.getRealDimensions(); + + int newX = (int) (e.getX() / (stretchedDimensions.width / realDimensions.getWidth())); + int newY = (int) (e.getY() / (stretchedDimensions.height / realDimensions.getHeight())); + + return new MouseWheelEvent((Component) e.getSource(), e.getID(), e.getWhen(), e.getModifiers(), newX, newY, + e.getClickCount(), e.isPopupTrigger(), e.getScrollType(), e.getScrollAmount(), e.getWheelRotation()); + } +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/suppliestracker/ActionType.java b/runelite-client/src/main/java/net/runelite/client/plugins/suppliestracker/ActionType.java index df28bce3b5..c7624dea38 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/suppliestracker/ActionType.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/suppliestracker/ActionType.java @@ -1,34 +1,34 @@ -/* - * Copyright (c) 2018, Davis Cook - * Copyright (c) 2018, Daddy Dozer - * 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.suppliestracker; - -/** - * Type of action performed in a menu - */ -public enum ActionType -{ - CONSUMABLE, TELEPORT, CAST; +/* + * Copyright (c) 2018, Davis Cook + * Copyright (c) 2018, Daddy Dozer + * 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.suppliestracker; + +/** + * Type of action performed in a menu + */ +public enum ActionType +{ + CONSUMABLE, TELEPORT, CAST } \ No newline at end of file diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/suppliestracker/ItemType.java b/runelite-client/src/main/java/net/runelite/client/plugins/suppliestracker/ItemType.java index 8479937589..1d5e5a7137 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/suppliestracker/ItemType.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/suppliestracker/ItemType.java @@ -1,77 +1,78 @@ -/* - * Copyright (c) 2018, Davis Cook - * Copyright (c) 2018, Daddy Dozer - * 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.suppliestracker; - -import lombok.AllArgsConstructor; -import lombok.Getter; - -/** - * The potential types that supplies can be along with a categorization function - * that assigns the supplies to these categories - */ -@AllArgsConstructor -public enum ItemType -{ - FOOD("Food"), - POTION("Potions"), - RUNE("Runes"), - AMMO("Ammo"), - TELEPORT("Teleports"); - - @Getter - private String label; - - /** - * Takes an item and determines what ItemType it should categorize into - * @param item the item to determine category for - * @return our best guess for what category this item goes into - * note that if the guess is wrong (per say) it won't break anything because it will be - * consistently wrong but it could have an item that is clearly not food in the food section - */ - public static ItemType categorize(SuppliesTrackerItem item) - { - if (item.getName().contains("(4)")) - { - return ItemType.POTION; - } - if (item.getName().toLowerCase().contains("bolt") || item.getName().toLowerCase().contains("dart") - || item.getName().toLowerCase().contains("arrow") || item.getName().toLowerCase().contains("javelin") - || item.getName().toLowerCase().contains("knive") || item.getName().toLowerCase().contains("throwing") - || item.getName().toLowerCase().contains("zulrah's scale") || item.getName().toLowerCase().contains("cannonball")) - { - return ItemType.AMMO; - } - if (item.getName().contains("rune")) - { - return ItemType.RUNE; - } - if (item.getName().toLowerCase().contains("teleport")) - { - return ItemType.TELEPORT; - } - return ItemType.FOOD; - } -} +/* + * Copyright (c) 2018, Davis Cook + * Copyright (c) 2018, Daddy Dozer + * 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.suppliestracker; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +/** + * The potential types that supplies can be along with a categorization function + * that assigns the supplies to these categories + */ +@AllArgsConstructor +public enum ItemType +{ + FOOD("Food"), + POTION("Potions"), + RUNE("Runes"), + AMMO("Ammo"), + TELEPORT("Teleports"); + + @Getter + private String label; + + /** + * Takes an item and determines what ItemType it should categorize into + * + * @param item the item to determine category for + * @return our best guess for what category this item goes into + * note that if the guess is wrong (per say) it won't break anything because it will be + * consistently wrong but it could have an item that is clearly not food in the food section + */ + public static ItemType categorize(SuppliesTrackerItem item) + { + if (item.getName().contains("(4)")) + { + return ItemType.POTION; + } + if (item.getName().toLowerCase().contains("bolt") || item.getName().toLowerCase().contains("dart") + || item.getName().toLowerCase().contains("arrow") || item.getName().toLowerCase().contains("javelin") + || item.getName().toLowerCase().contains("knive") || item.getName().toLowerCase().contains("throwing") + || item.getName().toLowerCase().contains("zulrah's scale") || item.getName().toLowerCase().contains("cannonball")) + { + return ItemType.AMMO; + } + if (item.getName().contains("rune")) + { + return ItemType.RUNE; + } + if (item.getName().toLowerCase().contains("teleport")) + { + return ItemType.TELEPORT; + } + return ItemType.FOOD; + } +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/suppliestracker/SuppliesBox.java b/runelite-client/src/main/java/net/runelite/client/plugins/suppliestracker/SuppliesBox.java index c758250c3b..5313462bae 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/suppliestracker/SuppliesBox.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/suppliestracker/SuppliesBox.java @@ -1,344 +1,375 @@ -/* - * Copyright (c) 2018, Davis Cook - * Copyright (c) 2018, Daddy Dozer - * 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.suppliestracker; - -import java.awt.BorderLayout; -import java.awt.Color; -import java.awt.GridLayout; -import java.util.ArrayList; -import java.util.List; -import javax.swing.JLabel; -import javax.swing.JMenuItem; -import javax.swing.JPanel; -import javax.swing.JPopupMenu; -import javax.swing.SwingConstants; -import javax.swing.border.EmptyBorder; -import lombok.AccessLevel; -import lombok.Getter; -import static net.runelite.api.ItemID.*; -import net.runelite.client.game.AsyncBufferedImage; -import net.runelite.client.game.ItemManager; -import net.runelite.client.ui.ColorScheme; -import net.runelite.client.ui.FontManager; -import net.runelite.client.util.StackFormatter; -import net.runelite.client.util.Text; -import net.runelite.http.api.item.ItemPrice; - -class SuppliesBox extends JPanel -{ - private static final int ITEMS_PER_ROW = 5; - - private final JPanel itemContainer = new JPanel(); - private final JLabel priceLabel = new JLabel(); - private final JLabel subTitleLabel = new JLabel(); - private final ItemManager itemManager; - @Getter(AccessLevel.PACKAGE) - private final String id; - private final SuppliesTrackerPlugin plugin; - private final SuppliesTrackerPanel panel; - - @Getter - private final List trackedItems = new ArrayList<>(); - - private long totalPrice; - - @Getter - private final ItemType type; - - SuppliesBox(final ItemManager itemManager, final String id, - final SuppliesTrackerPlugin plugin, final SuppliesTrackerPanel panel, - final ItemType type) - { - this.id = id; - this.itemManager = itemManager; - this.plugin = plugin; - this.panel = panel; - this.type = type; - - setLayout(new BorderLayout(0, 1)); - setBorder(new EmptyBorder(5, 0, 0, 0)); - - final JPanel logTitle = new JPanel(new BorderLayout(5, 0)); - logTitle.setBorder(new EmptyBorder(7, 7, 7, 7)); - logTitle.setBackground(ColorScheme.DARKER_GRAY_COLOR.darker()); - - final JLabel titleLabel = new JLabel(Text.removeTags(id)); - titleLabel.setFont(FontManager.getRunescapeSmallFont()); - titleLabel.setForeground(Color.WHITE); - - logTitle.add(titleLabel, BorderLayout.WEST); - - subTitleLabel.setFont(FontManager.getRunescapeSmallFont()); - subTitleLabel.setForeground(ColorScheme.LIGHT_GRAY_COLOR); - logTitle.add(subTitleLabel, BorderLayout.CENTER); - - priceLabel.setFont(FontManager.getRunescapeSmallFont()); - priceLabel.setForeground(ColorScheme.LIGHT_GRAY_COLOR); - logTitle.add(priceLabel, BorderLayout.EAST); - - add(logTitle, BorderLayout.NORTH); - add(itemContainer, BorderLayout.CENTER); - - // Create popup menu - final JPopupMenu popupMenu = new JPopupMenu(); - popupMenu.setBorder(new EmptyBorder(5, 5, 5, 5)); - setComponentPopupMenu(popupMenu); - - // Create reset menu - final JMenuItem reset = new JMenuItem("Reset Category"); - reset.addActionListener(e -> - { - for (SuppliesTrackerItem item : trackedItems) - { - plugin.clearItem(item.getId()); - } - clearAll(); - rebuild(); - panel.updateOverall(); - }); - - popupMenu.add(reset); - - setVisible(false); - } - - void update(SuppliesTrackerItem item) - { - trackedItems.removeIf(r -> r.getId() == item.getId()); - trackedItems.add(item); - setVisible(trackedItems.size() > 0); - } - - private void remove(SuppliesTrackerItem item) - { - trackedItems.removeIf(r -> r.getId() == item.getId()); - plugin.clearItem(item.getId()); - setVisible(trackedItems.size() > 0); - } - - void clearAll() - { - trackedItems.clear(); - setVisible(false); - } - - long getTotalSupplies() - { - long totalSupplies = 0; - for (SuppliesTrackerItem item : trackedItems) - { - totalSupplies += item.getQuantity(); - } - return totalSupplies; - } - - long getTotalPrice() - { - return totalPrice; - } - - void rebuild() - { - buildItems(); - - priceLabel.setText(StackFormatter.quantityToStackSize(totalPrice) + " gp"); - priceLabel.setToolTipText(StackFormatter.formatNumber(totalPrice) + " gp"); - - final long supplies = getTotalSupplies(); - if (supplies > 0) - { - subTitleLabel.setText("x " + supplies); - } - else - { - subTitleLabel.setText(""); - } - - validate(); - repaint(); - } - - private void buildItems() - { - final List items = new ArrayList<>(trackedItems); - totalPrice = 0; - - for (SuppliesTrackerItem item : items) - { - totalPrice += item.getPrice(); - } - - items.sort((i1, i2) -> Long.compare(i2.getPrice(), i1.getPrice())); - - // calculates how many rows need to be displayed to fit all item - final int rowSize = ((items.size() % ITEMS_PER_ROW == 0) ? 0 : 1) + items.size() / ITEMS_PER_ROW; - - itemContainer.removeAll(); - itemContainer.setLayout(new GridLayout(rowSize, ITEMS_PER_ROW, 1, 1)); - - for (int i = 0; i < rowSize * ITEMS_PER_ROW; i++) - { - final JPanel slotContainer = new JPanel(); - slotContainer.setBackground(ColorScheme.DARKER_GRAY_COLOR); - - if (i < items.size()) - { - final SuppliesTrackerItem item = items.get(i); - final JLabel imageLabel = new JLabel(); - imageLabel.setToolTipText(buildToolTip(item)); - imageLabel.setVerticalAlignment(SwingConstants.CENTER); - imageLabel.setHorizontalAlignment(SwingConstants.CENTER); - - AsyncBufferedImage itemImage = itemManager.getImage(getModifiedItemId(item.getName(), item.getId()), item.getQuantity(), item.getQuantity() > 1); - itemImage.addTo(imageLabel); - slotContainer.add(imageLabel); - - // create popup menu - final JPopupMenu popupMenu = new JPopupMenu(); - popupMenu.setBorder(new EmptyBorder(5, 5, 5, 5)); - slotContainer.setComponentPopupMenu(popupMenu); - - final JMenuItem reset = new JMenuItem("Reset"); - reset.addActionListener(e -> - { - remove(item); - rebuild(); - panel.updateOverall(); - }); - - popupMenu.add(reset); - } - itemContainer.add(slotContainer); - } - itemContainer.repaint(); - } - - private int getModifiedItemId(String name, int itemId) - { - if (SuppliesTrackerPlugin.isPotion(name)) - { - return getSingleDose(name); - } - if (SuppliesTrackerPlugin.isCake(name, itemId)) - { - return getSlice(itemId); - } - if (SuppliesTrackerPlugin.isPizzaPie(name)) - { - return getHalf(itemId); - } - - return itemId; - } - - //Switches full cake ids to get the image for slice - private int getSlice(int itemId) - { - switch (itemId) - { - case CAKE: - itemId = SLICE_OF_CAKE; - break; - case CHOCOLATE_CAKE: - itemId = CHOCOLATE_SLICE; - break; - } - return itemId; - } - - //Switches full pizza and pie ids to get the image for half - private int getHalf(int itemId) - { - switch (itemId) - { - case ANCHOVY_PIZZA: - itemId = _12_ANCHOVY_PIZZA; - break; - case MEAT_PIZZA: - itemId = _12_MEAT_PIZZA; - break; - case PINEAPPLE_PIZZA: - itemId = _12_PINEAPPLE_PIZZA; - break; - case PLAIN_PIZZA: - itemId = _12_PLAIN_PIZZA; - break; - case REDBERRY_PIE: - itemId = HALF_A_REDBERRY_PIE; - break; - case GARDEN_PIE: - itemId = HALF_A_GARDEN_PIE; - break; - case SUMMER_PIE: - itemId = HALF_A_SUMMER_PIE; - break; - case FISH_PIE: - itemId = HALF_A_FISH_PIE; - break; - case BOTANICAL_PIE: - itemId = HALF_A_BOTANICAL_PIE; - break; - case MUSHROOM_PIE: - itemId = HALF_A_MUSHROOM_PIE; - break; - case ADMIRAL_PIE: - itemId = HALF_AN_ADMIRAL_PIE; - break; - case WILD_PIE: - itemId = HALF_A_WILD_PIE; - break; - case APPLE_PIE: - itemId = HALF_AN_APPLE_PIE; - break; - case MEAT_PIE: - itemId = HALF_A_MEAT_PIE; - break; - - } - return itemId; - } - - private int getSingleDose(String name) - { - String nameModified = name.replace("(4)", "(1)"); - int itemId = 0; - List itemList = itemManager.search(nameModified); - for (ItemPrice item: itemList) - { - itemId = item.getId(); - } - return itemId; - } - - private static String buildToolTip(SuppliesTrackerItem item) - { - final String name = item.getName(); - final int quantity = item.getQuantity(); - final long price = item.getPrice(); - return name + " x " + quantity + " (" + StackFormatter.quantityToStackSize(price) + ") "; - } - -} +/* + * Copyright (c) 2018, Davis Cook + * Copyright (c) 2018, Daddy Dozer + * 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.suppliestracker; + +import java.awt.BorderLayout; +import java.awt.Color; +import java.awt.GridLayout; +import java.util.ArrayList; +import java.util.List; +import javax.swing.JLabel; +import javax.swing.JMenuItem; +import javax.swing.JPanel; +import javax.swing.JPopupMenu; +import javax.swing.SwingConstants; +import javax.swing.border.EmptyBorder; +import lombok.AccessLevel; +import lombok.Getter; +import static net.runelite.api.ItemID.ADMIRAL_PIE; +import static net.runelite.api.ItemID.ANCHOVY_PIZZA; +import static net.runelite.api.ItemID.APPLE_PIE; +import static net.runelite.api.ItemID.BOTANICAL_PIE; +import static net.runelite.api.ItemID.CAKE; +import static net.runelite.api.ItemID.CHOCOLATE_CAKE; +import static net.runelite.api.ItemID.CHOCOLATE_SLICE; +import static net.runelite.api.ItemID.FISH_PIE; +import static net.runelite.api.ItemID.GARDEN_PIE; +import static net.runelite.api.ItemID.HALF_AN_ADMIRAL_PIE; +import static net.runelite.api.ItemID.HALF_AN_APPLE_PIE; +import static net.runelite.api.ItemID.HALF_A_BOTANICAL_PIE; +import static net.runelite.api.ItemID.HALF_A_FISH_PIE; +import static net.runelite.api.ItemID.HALF_A_GARDEN_PIE; +import static net.runelite.api.ItemID.HALF_A_MEAT_PIE; +import static net.runelite.api.ItemID.HALF_A_MUSHROOM_PIE; +import static net.runelite.api.ItemID.HALF_A_REDBERRY_PIE; +import static net.runelite.api.ItemID.HALF_A_SUMMER_PIE; +import static net.runelite.api.ItemID.HALF_A_WILD_PIE; +import static net.runelite.api.ItemID.MEAT_PIE; +import static net.runelite.api.ItemID.MEAT_PIZZA; +import static net.runelite.api.ItemID.MUSHROOM_PIE; +import static net.runelite.api.ItemID.PINEAPPLE_PIZZA; +import static net.runelite.api.ItemID.PLAIN_PIZZA; +import static net.runelite.api.ItemID.REDBERRY_PIE; +import static net.runelite.api.ItemID.SLICE_OF_CAKE; +import static net.runelite.api.ItemID.SUMMER_PIE; +import static net.runelite.api.ItemID.WILD_PIE; +import static net.runelite.api.ItemID._12_ANCHOVY_PIZZA; +import static net.runelite.api.ItemID._12_MEAT_PIZZA; +import static net.runelite.api.ItemID._12_PINEAPPLE_PIZZA; +import static net.runelite.api.ItemID._12_PLAIN_PIZZA; +import net.runelite.client.game.AsyncBufferedImage; +import net.runelite.client.game.ItemManager; +import net.runelite.client.ui.ColorScheme; +import net.runelite.client.ui.FontManager; +import net.runelite.client.util.StackFormatter; +import net.runelite.client.util.Text; +import net.runelite.http.api.item.ItemPrice; + +class SuppliesBox extends JPanel +{ + private static final int ITEMS_PER_ROW = 5; + + private final JPanel itemContainer = new JPanel(); + private final JLabel priceLabel = new JLabel(); + private final JLabel subTitleLabel = new JLabel(); + private final ItemManager itemManager; + @Getter(AccessLevel.PACKAGE) + private final String id; + private final SuppliesTrackerPlugin plugin; + private final SuppliesTrackerPanel panel; + + @Getter + private final List trackedItems = new ArrayList<>(); + + private long totalPrice; + + @Getter + private final ItemType type; + + SuppliesBox(final ItemManager itemManager, final String id, + final SuppliesTrackerPlugin plugin, final SuppliesTrackerPanel panel, + final ItemType type) + { + this.id = id; + this.itemManager = itemManager; + this.plugin = plugin; + this.panel = panel; + this.type = type; + + setLayout(new BorderLayout(0, 1)); + setBorder(new EmptyBorder(5, 0, 0, 0)); + + final JPanel logTitle = new JPanel(new BorderLayout(5, 0)); + logTitle.setBorder(new EmptyBorder(7, 7, 7, 7)); + logTitle.setBackground(ColorScheme.DARKER_GRAY_COLOR.darker()); + + final JLabel titleLabel = new JLabel(Text.removeTags(id)); + titleLabel.setFont(FontManager.getRunescapeSmallFont()); + titleLabel.setForeground(Color.WHITE); + + logTitle.add(titleLabel, BorderLayout.WEST); + + subTitleLabel.setFont(FontManager.getRunescapeSmallFont()); + subTitleLabel.setForeground(ColorScheme.LIGHT_GRAY_COLOR); + logTitle.add(subTitleLabel, BorderLayout.CENTER); + + priceLabel.setFont(FontManager.getRunescapeSmallFont()); + priceLabel.setForeground(ColorScheme.LIGHT_GRAY_COLOR); + logTitle.add(priceLabel, BorderLayout.EAST); + + add(logTitle, BorderLayout.NORTH); + add(itemContainer, BorderLayout.CENTER); + + // Create popup menu + final JPopupMenu popupMenu = new JPopupMenu(); + popupMenu.setBorder(new EmptyBorder(5, 5, 5, 5)); + setComponentPopupMenu(popupMenu); + + // Create reset menu + final JMenuItem reset = new JMenuItem("Reset Category"); + reset.addActionListener(e -> + { + for (SuppliesTrackerItem item : trackedItems) + { + plugin.clearItem(item.getId()); + } + clearAll(); + rebuild(); + panel.updateOverall(); + }); + + popupMenu.add(reset); + + setVisible(false); + } + + void update(SuppliesTrackerItem item) + { + trackedItems.removeIf(r -> r.getId() == item.getId()); + trackedItems.add(item); + setVisible(trackedItems.size() > 0); + } + + private void remove(SuppliesTrackerItem item) + { + trackedItems.removeIf(r -> r.getId() == item.getId()); + plugin.clearItem(item.getId()); + setVisible(trackedItems.size() > 0); + } + + void clearAll() + { + trackedItems.clear(); + setVisible(false); + } + + long getTotalSupplies() + { + long totalSupplies = 0; + for (SuppliesTrackerItem item : trackedItems) + { + totalSupplies += item.getQuantity(); + } + return totalSupplies; + } + + long getTotalPrice() + { + return totalPrice; + } + + void rebuild() + { + buildItems(); + + priceLabel.setText(StackFormatter.quantityToStackSize(totalPrice) + " gp"); + priceLabel.setToolTipText(StackFormatter.formatNumber(totalPrice) + " gp"); + + final long supplies = getTotalSupplies(); + if (supplies > 0) + { + subTitleLabel.setText("x " + supplies); + } + else + { + subTitleLabel.setText(""); + } + + validate(); + repaint(); + } + + private void buildItems() + { + final List items = new ArrayList<>(trackedItems); + totalPrice = 0; + + for (SuppliesTrackerItem item : items) + { + totalPrice += item.getPrice(); + } + + items.sort((i1, i2) -> Long.compare(i2.getPrice(), i1.getPrice())); + + // calculates how many rows need to be displayed to fit all item + final int rowSize = ((items.size() % ITEMS_PER_ROW == 0) ? 0 : 1) + items.size() / ITEMS_PER_ROW; + + itemContainer.removeAll(); + itemContainer.setLayout(new GridLayout(rowSize, ITEMS_PER_ROW, 1, 1)); + + for (int i = 0; i < rowSize * ITEMS_PER_ROW; i++) + { + final JPanel slotContainer = new JPanel(); + slotContainer.setBackground(ColorScheme.DARKER_GRAY_COLOR); + + if (i < items.size()) + { + final SuppliesTrackerItem item = items.get(i); + final JLabel imageLabel = new JLabel(); + imageLabel.setToolTipText(buildToolTip(item)); + imageLabel.setVerticalAlignment(SwingConstants.CENTER); + imageLabel.setHorizontalAlignment(SwingConstants.CENTER); + + AsyncBufferedImage itemImage = itemManager.getImage(getModifiedItemId(item.getName(), item.getId()), item.getQuantity(), item.getQuantity() > 1); + itemImage.addTo(imageLabel); + slotContainer.add(imageLabel); + + // create popup menu + final JPopupMenu popupMenu = new JPopupMenu(); + popupMenu.setBorder(new EmptyBorder(5, 5, 5, 5)); + slotContainer.setComponentPopupMenu(popupMenu); + + final JMenuItem reset = new JMenuItem("Reset"); + reset.addActionListener(e -> + { + remove(item); + rebuild(); + panel.updateOverall(); + }); + + popupMenu.add(reset); + } + itemContainer.add(slotContainer); + } + itemContainer.repaint(); + } + + private int getModifiedItemId(String name, int itemId) + { + if (SuppliesTrackerPlugin.isPotion(name)) + { + return getSingleDose(name); + } + if (SuppliesTrackerPlugin.isCake(name, itemId)) + { + return getSlice(itemId); + } + if (SuppliesTrackerPlugin.isPizzaPie(name)) + { + return getHalf(itemId); + } + + return itemId; + } + + //Switches full cake ids to get the image for slice + private int getSlice(int itemId) + { + switch (itemId) + { + case CAKE: + itemId = SLICE_OF_CAKE; + break; + case CHOCOLATE_CAKE: + itemId = CHOCOLATE_SLICE; + break; + } + return itemId; + } + + //Switches full pizza and pie ids to get the image for half + private int getHalf(int itemId) + { + switch (itemId) + { + case ANCHOVY_PIZZA: + itemId = _12_ANCHOVY_PIZZA; + break; + case MEAT_PIZZA: + itemId = _12_MEAT_PIZZA; + break; + case PINEAPPLE_PIZZA: + itemId = _12_PINEAPPLE_PIZZA; + break; + case PLAIN_PIZZA: + itemId = _12_PLAIN_PIZZA; + break; + case REDBERRY_PIE: + itemId = HALF_A_REDBERRY_PIE; + break; + case GARDEN_PIE: + itemId = HALF_A_GARDEN_PIE; + break; + case SUMMER_PIE: + itemId = HALF_A_SUMMER_PIE; + break; + case FISH_PIE: + itemId = HALF_A_FISH_PIE; + break; + case BOTANICAL_PIE: + itemId = HALF_A_BOTANICAL_PIE; + break; + case MUSHROOM_PIE: + itemId = HALF_A_MUSHROOM_PIE; + break; + case ADMIRAL_PIE: + itemId = HALF_AN_ADMIRAL_PIE; + break; + case WILD_PIE: + itemId = HALF_A_WILD_PIE; + break; + case APPLE_PIE: + itemId = HALF_AN_APPLE_PIE; + break; + case MEAT_PIE: + itemId = HALF_A_MEAT_PIE; + break; + + } + return itemId; + } + + private int getSingleDose(String name) + { + String nameModified = name.replace("(4)", "(1)"); + int itemId = 0; + List itemList = itemManager.search(nameModified); + for (ItemPrice item : itemList) + { + itemId = item.getId(); + } + return itemId; + } + + private static String buildToolTip(SuppliesTrackerItem item) + { + final String name = item.getName(); + final int quantity = item.getQuantity(); + final long price = item.getPrice(); + return name + " x " + quantity + " (" + StackFormatter.quantityToStackSize(price) + ") "; + } + +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/suppliestracker/SuppliesTrackerPanel.java b/runelite-client/src/main/java/net/runelite/client/plugins/suppliestracker/SuppliesTrackerPanel.java index 8568eabbc2..dd7660393b 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/suppliestracker/SuppliesTrackerPanel.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/suppliestracker/SuppliesTrackerPanel.java @@ -1,209 +1,212 @@ -/* - * Copyright (c) 2018, Psikoi - * Copyright (c) 2018, Tomas Slusny - * Copyright (c) 2018, Daddy Dozer - * 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.suppliestracker; - -import java.awt.BorderLayout; -import java.awt.GridLayout; -import java.awt.image.BufferedImage; -import java.util.ArrayList; -import java.util.List; -import javax.swing.BoxLayout; -import javax.swing.ImageIcon; -import javax.swing.JLabel; -import javax.swing.JMenuItem; -import javax.swing.JPanel; -import javax.swing.JPopupMenu; -import javax.swing.border.EmptyBorder; -import net.runelite.client.game.ItemManager; -import net.runelite.client.ui.ColorScheme; -import net.runelite.client.ui.FontManager; -import net.runelite.client.ui.PluginPanel; -import net.runelite.client.ui.components.PluginErrorPanel; -import net.runelite.client.util.ColorUtil; -import net.runelite.client.util.StackFormatter; - - -class SuppliesTrackerPanel extends PluginPanel -{ - private static final String HTML_LABEL_TEMPLATE = - "%s%s"; - - // Handle loot logs - private final JPanel logsContainer = new JPanel(); - - private final List boxList = new ArrayList<>(); - - private final PluginErrorPanel errorPanel = new PluginErrorPanel(); - - // Handle overall session data - private final JPanel overallPanel = new JPanel(); - private final JLabel overallSuppliesUsedLabel = new JLabel(); - private final JLabel overallCostLabel = new JLabel(); - private final JLabel overallIcon = new JLabel(); - private int overallSuppliesUsed; - private int overallCost; - - SuppliesTrackerPanel(final ItemManager itemManager, SuppliesTrackerPlugin plugin) - { - setBorder(new EmptyBorder(6, 6, 6, 6)); - setBackground(ColorScheme.DARK_GRAY_COLOR); - setLayout(new BorderLayout()); - - // Create layout panel for wrapping - final JPanel layoutPanel = new JPanel(); - layoutPanel.setLayout(new BoxLayout(layoutPanel, BoxLayout.Y_AXIS)); - add(layoutPanel, BorderLayout.NORTH); - - // Create panel that will contain overall data - overallPanel.setBorder(new EmptyBorder(10, 10, 10, 10)); - overallPanel.setBackground(ColorScheme.DARKER_GRAY_COLOR); - overallPanel.setLayout(new BorderLayout()); - overallPanel.setVisible(true); - - // Add icon and contents - final JPanel overallInfo = new JPanel(); - overallInfo.setBackground(ColorScheme.DARKER_GRAY_COLOR); - overallInfo.setLayout(new GridLayout(2, 1)); - overallInfo.setBorder(new EmptyBorder(0, 10, 0, 0)); - overallSuppliesUsedLabel.setFont(FontManager.getRunescapeSmallFont()); - overallCostLabel.setFont(FontManager.getRunescapeSmallFont()); - overallInfo.add(overallSuppliesUsedLabel); - overallInfo.add(overallCostLabel); - overallPanel.add(overallIcon, BorderLayout.WEST); - overallPanel.add(overallInfo, BorderLayout.CENTER); - - for (ItemType type : ItemType.values()) - { - SuppliesBox newBox = new SuppliesBox(itemManager, type.getLabel(), plugin, this, type); - logsContainer.add(newBox); - boxList.add(newBox); - } - - // Create reset all menu - final JMenuItem reset = new JMenuItem("Reset All"); - reset.addActionListener(e -> - { - overallSuppliesUsed = 0; - overallCost = 0; - plugin.clearSupplies(); - for (SuppliesBox box : boxList) - { - box.clearAll(); - } - updateOverall(); - logsContainer.repaint(); - }); - - // Create popup menu - final JPopupMenu popupMenu = new JPopupMenu(); - popupMenu.setBorder(new EmptyBorder(5, 5, 5, 5)); - popupMenu.add(reset); - overallPanel.setComponentPopupMenu(popupMenu); - - // Create Supply Rows wrapper - logsContainer.setLayout(new BoxLayout(logsContainer, BoxLayout.Y_AXIS)); - layoutPanel.add(overallPanel); - layoutPanel.add(logsContainer); - - errorPanel.setContent("Supply trackers", "You have not used any supplies yet."); - add(errorPanel); - overallPanel.setVisible(false); - } - - /** - * loads an img to the icon on the header - * @param img the img for the header icon - */ - void loadHeaderIcon(BufferedImage img) - { - overallIcon.setIcon(new ImageIcon(img)); - } - - /** - * convert key value pair to html formatting needed to display nicely - * @param key key - * @param value value - * @return key: value in html - */ - private static String htmlLabel(String key, long value) - { - final String valueStr = StackFormatter.quantityToStackSize(value); - return String.format(HTML_LABEL_TEMPLATE, ColorUtil.toHexColor(ColorScheme.LIGHT_GRAY_COLOR), key, valueStr); - } - - /** - * Add an item to the supply panel by placing it into the correct box - * @param item the item to add - */ - void addItem(SuppliesTrackerItem item) - { - ItemType category = ItemType.categorize(item); - for (SuppliesBox box : boxList) - { - if (box.getType() == category) - { - box.update(item); - box.rebuild(); - break; - } - } - updateOverall(); - } - - /** - * Updates overall stats to calculate overall used and overall cost from - * the info in each box - */ - void updateOverall() - { - overallSuppliesUsed = 0; - for (SuppliesBox box : boxList) - { - overallSuppliesUsed += box.getTotalSupplies(); - } - - overallCost = 0; - for (SuppliesBox box : boxList) - { - overallCost += box.getTotalPrice(); - } - - overallSuppliesUsedLabel.setText(htmlLabel("Total Supplies: ", overallSuppliesUsed)); - overallCostLabel.setText(htmlLabel("Total Cost: ", overallCost)); - - if (overallSuppliesUsed <= 0) - { - add(errorPanel); - overallPanel.setVisible(false); - } - else - { - remove(errorPanel); - overallPanel.setVisible(true); - } - } -} +/* + * Copyright (c) 2018, Psikoi + * Copyright (c) 2018, Tomas Slusny + * Copyright (c) 2018, Daddy Dozer + * 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.suppliestracker; + +import java.awt.BorderLayout; +import java.awt.GridLayout; +import java.awt.image.BufferedImage; +import java.util.ArrayList; +import java.util.List; +import javax.swing.BoxLayout; +import javax.swing.ImageIcon; +import javax.swing.JLabel; +import javax.swing.JMenuItem; +import javax.swing.JPanel; +import javax.swing.JPopupMenu; +import javax.swing.border.EmptyBorder; +import net.runelite.client.game.ItemManager; +import net.runelite.client.ui.ColorScheme; +import net.runelite.client.ui.FontManager; +import net.runelite.client.ui.PluginPanel; +import net.runelite.client.ui.components.PluginErrorPanel; +import net.runelite.client.util.ColorUtil; +import net.runelite.client.util.StackFormatter; + + +class SuppliesTrackerPanel extends PluginPanel +{ + private static final String HTML_LABEL_TEMPLATE = + "%s%s"; + + // Handle loot logs + private final JPanel logsContainer = new JPanel(); + + private final List boxList = new ArrayList<>(); + + private final PluginErrorPanel errorPanel = new PluginErrorPanel(); + + // Handle overall session data + private final JPanel overallPanel = new JPanel(); + private final JLabel overallSuppliesUsedLabel = new JLabel(); + private final JLabel overallCostLabel = new JLabel(); + private final JLabel overallIcon = new JLabel(); + private int overallSuppliesUsed; + private int overallCost; + + SuppliesTrackerPanel(final ItemManager itemManager, SuppliesTrackerPlugin plugin) + { + setBorder(new EmptyBorder(6, 6, 6, 6)); + setBackground(ColorScheme.DARK_GRAY_COLOR); + setLayout(new BorderLayout()); + + // Create layout panel for wrapping + final JPanel layoutPanel = new JPanel(); + layoutPanel.setLayout(new BoxLayout(layoutPanel, BoxLayout.Y_AXIS)); + add(layoutPanel, BorderLayout.NORTH); + + // Create panel that will contain overall data + overallPanel.setBorder(new EmptyBorder(10, 10, 10, 10)); + overallPanel.setBackground(ColorScheme.DARKER_GRAY_COLOR); + overallPanel.setLayout(new BorderLayout()); + overallPanel.setVisible(true); + + // Add icon and contents + final JPanel overallInfo = new JPanel(); + overallInfo.setBackground(ColorScheme.DARKER_GRAY_COLOR); + overallInfo.setLayout(new GridLayout(2, 1)); + overallInfo.setBorder(new EmptyBorder(0, 10, 0, 0)); + overallSuppliesUsedLabel.setFont(FontManager.getRunescapeSmallFont()); + overallCostLabel.setFont(FontManager.getRunescapeSmallFont()); + overallInfo.add(overallSuppliesUsedLabel); + overallInfo.add(overallCostLabel); + overallPanel.add(overallIcon, BorderLayout.WEST); + overallPanel.add(overallInfo, BorderLayout.CENTER); + + for (ItemType type : ItemType.values()) + { + SuppliesBox newBox = new SuppliesBox(itemManager, type.getLabel(), plugin, this, type); + logsContainer.add(newBox); + boxList.add(newBox); + } + + // Create reset all menu + final JMenuItem reset = new JMenuItem("Reset All"); + reset.addActionListener(e -> + { + overallSuppliesUsed = 0; + overallCost = 0; + plugin.clearSupplies(); + for (SuppliesBox box : boxList) + { + box.clearAll(); + } + updateOverall(); + logsContainer.repaint(); + }); + + // Create popup menu + final JPopupMenu popupMenu = new JPopupMenu(); + popupMenu.setBorder(new EmptyBorder(5, 5, 5, 5)); + popupMenu.add(reset); + overallPanel.setComponentPopupMenu(popupMenu); + + // Create Supply Rows wrapper + logsContainer.setLayout(new BoxLayout(logsContainer, BoxLayout.Y_AXIS)); + layoutPanel.add(overallPanel); + layoutPanel.add(logsContainer); + + errorPanel.setContent("Supply trackers", "You have not used any supplies yet."); + add(errorPanel); + overallPanel.setVisible(false); + } + + /** + * loads an img to the icon on the header + * + * @param img the img for the header icon + */ + void loadHeaderIcon(BufferedImage img) + { + overallIcon.setIcon(new ImageIcon(img)); + } + + /** + * convert key value pair to html formatting needed to display nicely + * + * @param key key + * @param value value + * @return key: value in html + */ + private static String htmlLabel(String key, long value) + { + final String valueStr = StackFormatter.quantityToStackSize(value); + return String.format(HTML_LABEL_TEMPLATE, ColorUtil.toHexColor(ColorScheme.LIGHT_GRAY_COLOR), key, valueStr); + } + + /** + * Add an item to the supply panel by placing it into the correct box + * + * @param item the item to add + */ + void addItem(SuppliesTrackerItem item) + { + ItemType category = ItemType.categorize(item); + for (SuppliesBox box : boxList) + { + if (box.getType() == category) + { + box.update(item); + box.rebuild(); + break; + } + } + updateOverall(); + } + + /** + * Updates overall stats to calculate overall used and overall cost from + * the info in each box + */ + void updateOverall() + { + overallSuppliesUsed = 0; + for (SuppliesBox box : boxList) + { + overallSuppliesUsed += box.getTotalSupplies(); + } + + overallCost = 0; + for (SuppliesBox box : boxList) + { + overallCost += box.getTotalPrice(); + } + + overallSuppliesUsedLabel.setText(htmlLabel("Total Supplies: ", overallSuppliesUsed)); + overallCostLabel.setText(htmlLabel("Total Cost: ", overallCost)); + + if (overallSuppliesUsed <= 0) + { + add(errorPanel); + overallPanel.setVisible(false); + } + else + { + remove(errorPanel); + overallPanel.setVisible(true); + } + } +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/suppliestracker/SuppliesTrackerPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/suppliestracker/SuppliesTrackerPlugin.java index 653792dc86..c758da9357 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/suppliestracker/SuppliesTrackerPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/suppliestracker/SuppliesTrackerPlugin.java @@ -1,777 +1,897 @@ -/* - * Copyright (c) 2018, Psikoi - * Copyright (c) 2018, Adam - * Copyright (c) 2018, Sir Girion - * Copyright (c) 2018, Davis Cook - * Copyright (c) 2018, Daddy Dozer - * 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.suppliestracker; - - -import com.google.inject.Provides; -import java.awt.image.BufferedImage; -import java.util.ArrayDeque; -import java.util.Deque; -import java.util.HashMap; -import java.util.List; -import java.util.Random; -import java.util.regex.Pattern; -import javax.inject.Inject; -import javax.swing.SwingUtilities; -import lombok.extern.slf4j.Slf4j; -import static net.runelite.api.AnimationID.BLOWPIPE_ATTACK; -import static net.runelite.api.AnimationID.HIGH_LEVEL_MAGIC_ATTACK; -import static net.runelite.api.AnimationID.LOW_LEVEL_MAGIC_ATTACK; -import net.runelite.api.Client; -import net.runelite.api.EquipmentInventorySlot; -import net.runelite.api.InventoryID; -import net.runelite.api.Item; -import net.runelite.api.ItemComposition; -import net.runelite.api.ItemContainer; -import net.runelite.api.ItemID; -import static net.runelite.api.ItemID.*; -import net.runelite.api.Player; -import net.runelite.api.VarPlayer; -import net.runelite.api.events.AnimationChanged; -import net.runelite.api.events.CannonballFired; -import net.runelite.api.events.GameTick; -import net.runelite.api.events.ItemContainerChanged; -import net.runelite.api.events.MenuOptionClicked; -import net.runelite.api.events.VarbitChanged; -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.plugins.PluginType; -import static net.runelite.client.plugins.suppliestracker.ActionType.CAST; -import static net.runelite.client.plugins.suppliestracker.ActionType.CONSUMABLE; -import static net.runelite.client.plugins.suppliestracker.ActionType.TELEPORT; -import net.runelite.client.ui.ClientToolbar; -import net.runelite.client.ui.NavigationButton; -import net.runelite.client.util.ImageUtil; -import net.runelite.http.api.item.ItemPrice; - - -@PluginDescriptor( - name = "Supplies Used Tracker", - description = "Tracks supplies used during the session", - tags = {"cost"}, - type = PluginType.UTILITY, - enabledByDefault = false -) -@Slf4j -public class SuppliesTrackerPlugin extends Plugin -{ - private static final String POTION_PATTERN = "[(]\\d[)]"; - - private static final String EAT_PATTERN = "^eat"; - private static final String DRINK_PATTERN = "^drink"; - private static final String TELEPORT_PATTERN = "^teleport"; - private static final String TELETAB_PATTERN = "^break"; - private static final String SPELL_PATTERN = "^cast|^grand\\sexchange|^outside|^seers|^yanille"; - - private static final int EQUIPMENT_MAINHAND_SLOT = EquipmentInventorySlot.WEAPON.getSlotIdx(); - private static final int EQUIPMENT_AMMO_SLOT = EquipmentInventorySlot.AMMO.getSlotIdx(); - private static final int EQUIPMENT_CAPE_SLOT = EquipmentInventorySlot.CAPE.getSlotIdx(); - - private static final double NO_AVAS_PERCENT = 1.0; - private static final double ASSEMBLER_PERCENT = 0.20; - private static final double ACCUMULATOR_PERCENT = 0.28; - private static final double ATTRACTOR_PERCENT = 0.40; - - private static final int BLOWPIPE_TICKS_RAPID_PVM = 2; - private static final int BLOWPIPE_TICKS_RAPID_PVP = 3; - private static final int BLOWPIPE_TICKS_NORMAL_PVM = 3; - private static final int BLOWPIPE_TICKS_NORMAL_PVP = 4; - - private static final double SCALES_PERCENT = 0.66; - - private static final int POTION_DOSES = 4, CAKE_DOSES = 3, PIZZA_PIE_DOSES = 2; - - private static final Random random = new Random(); - - private static final int[] THROWING_IDS = new int[]{BRONZE_DART, IRON_DART, STEEL_DART, BLACK_DART, MITHRIL_DART, ADAMANT_DART, RUNE_DART, DRAGON_DART, BRONZE_KNIFE, IRON_KNIFE, STEEL_KNIFE, BLACK_KNIFE, MITHRIL_KNIFE, ADAMANT_KNIFE, RUNE_KNIFE, BRONZE_THROWNAXE, IRON_THROWNAXE, STEEL_THROWNAXE, MITHRIL_THROWNAXE, ADAMANT_THROWNAXE, RUNE_THROWNAXE, DRAGON_KNIFE, DRAGON_KNIFE_22812, DRAGON_KNIFE_22814, DRAGON_KNIFEP_22808, DRAGON_KNIFEP_22810, DRAGON_KNIFEP , DRAGON_THROWNAXE, CHINCHOMPA_10033, RED_CHINCHOMPA_10034, BLACK_CHINCHOMPA}; - private static final int[] RUNE_IDS = new int[]{AIR_RUNE, WATER_RUNE, EARTH_RUNE, MIND_RUNE, BODY_RUNE, COSMIC_RUNE, CHAOS_RUNE, NATURE_RUNE, LAW_RUNE, DEATH_RUNE, ASTRAL_RUNE, BLOOD_RUNE, SOUL_RUNE, WRATH_RUNE, MIST_RUNE, DUST_RUNE, MUD_RUNE, SMOKE_RUNE, STEAM_RUNE, LAVA_RUNE}; - - //Hold Supply Data - private static HashMap suppliesEntry = new HashMap<>(); - private ItemContainer old; - private Deque actionStack = new ArrayDeque<>(); - private int ammoId = 0; - private int ammoAmount = 0; - private int thrownId = 0; - private int thrownAmount = 0; - private boolean ammoLoaded = false; - private boolean throwingAmmoLoaded = false; - private boolean mainHandThrowing = false; - private int mainHand = 0; - private SuppliesTrackerPanel panel; - private NavigationButton navButton; - private String[] RAIDS_CONSUMABLES = new String[]{"xeric's", "elder", "twisted", "revitalisation", "overload", "prayer enhance", "pysk", "suphi", "leckish", "brawk", "mycil", "roqed", "kyren", "guanic", "prael", "giral", "phluxia", "kryket", "murng", "psykk"}; - - private int attackStyleVarbit = -1; - private int ticks = 0; - private int ticksInAnimation; - - @Inject - private ClientToolbar clientToolbar; - - @Inject - private ItemManager itemManager; - - @Inject - private SuppliesTrackerConfig config; - - @Inject - private Client client; - - - @Override - protected void startUp() throws Exception - { - panel = new SuppliesTrackerPanel(itemManager, this); - final BufferedImage header = ImageUtil.getResourceStreamFromClass(getClass(), "panel_icon.png"); - panel.loadHeaderIcon(header); - final BufferedImage icon = ImageUtil.getResourceStreamFromClass(getClass(), "panel_icon.png"); - - navButton = NavigationButton.builder() - .tooltip("Supplies Tracker") - .icon(icon) - .priority(5) - .panel(panel) - .build(); - - clientToolbar.addNavigation(navButton); - } - - @Override - protected void shutDown() - { - clientToolbar.removeNavigation(navButton); - } - - @Provides - SuppliesTrackerConfig provideConfig(ConfigManager configManager) - { - return configManager.getConfig(SuppliesTrackerConfig.class); - } - - @Subscribe - public void onGameTick(GameTick tick) - { - Player player = client.getLocalPlayer(); - if (player.getAnimation() == BLOWPIPE_ATTACK) - { - ticks++; - } - if (ticks == ticksInAnimation && (player.getAnimation() == BLOWPIPE_ATTACK)) - { - double ava_percent = getAccumulatorPercent(); - // randomize the usage of supplies since we CANNOT actually get real supplies used - if (random.nextDouble() <= ava_percent) - { - buildEntries(config.blowpipeAmmo().getDartID()); - - } - if (random.nextDouble() <= SCALES_PERCENT) - { - buildEntries(ZULRAHS_SCALES); - } - ticks = 0; - } - } - - /** - * checks the player's cape slot to determine what percent of their darts are lost - * - where lost means either break or drop to floor - * @return the percent lost - */ - private double getAccumulatorPercent() - { - double percent = NO_AVAS_PERCENT; - ItemContainer equipment = client.getItemContainer(InventoryID.EQUIPMENT); - if (equipment != null && equipment.getItems().length > EQUIPMENT_CAPE_SLOT) - { - int capeID = equipment.getItems()[EQUIPMENT_CAPE_SLOT].getId(); - switch (capeID) - { - case AVAS_ASSEMBLER: - case ASSEMBLER_MAX_CAPE: - percent = ASSEMBLER_PERCENT; - break; - case AVAS_ACCUMULATOR: - case ACCUMULATOR_MAX_CAPE: - // TODO: the ranging cape can be used as an attractor so this could be wrong - case RANGING_CAPE: - percent = ACCUMULATOR_PERCENT; - break; - case AVAS_ATTRACTOR: - percent = ATTRACTOR_PERCENT; - break; - } - } - return percent; - } - - @Subscribe - public void onVarbitChanged(VarbitChanged event) - { - if (attackStyleVarbit == -1 || attackStyleVarbit != client.getVar(VarPlayer.ATTACK_STYLE)) - { - attackStyleVarbit = client.getVar(VarPlayer.ATTACK_STYLE); - if (attackStyleVarbit == 0 || attackStyleVarbit == 3) - { - ticksInAnimation = BLOWPIPE_TICKS_NORMAL_PVM; - if (client.getLocalPlayer() != null && - client.getLocalPlayer().getInteracting() instanceof Player) { - ticksInAnimation = BLOWPIPE_TICKS_NORMAL_PVP; - } - } - else if (attackStyleVarbit == 1) - { - ticksInAnimation = BLOWPIPE_TICKS_RAPID_PVM; - if (client.getLocalPlayer() != null && - client.getLocalPlayer().getInteracting() instanceof Player) { - ticksInAnimation = BLOWPIPE_TICKS_RAPID_PVP; - } - } - } - } - - /** - * Checks for changes between the provided inventories in runes specifically to add those runes - * to the supply tracker - * - * we can't in general just check for when inventory slots change but this method is only run - * immediately after the player performs a cast animation or cast menu click/entry - * @param itemContainer the new inventory - * @param oldInv the old inventory - */ - private void checkUsedRunes(ItemContainer itemContainer, Item[] oldInv) - { - try - { - for (int i = 0; i < itemContainer.getItems().length; i++) - { - Item newItem = itemContainer.getItems()[i]; - Item oldItem = oldInv[i]; - boolean isRune = false; - for (int runeId : RUNE_IDS) - { - if (oldItem.getId() == runeId) - { - isRune = true; - } - } - if (isRune && (newItem.getId() != oldItem.getId() || newItem.getQuantity() != oldItem.getQuantity())) - { - int quantity = oldItem.getQuantity(); - if (newItem.getId() == oldItem.getId()) - { - quantity -= newItem.getQuantity(); - } - buildEntries(oldItem.getId(), quantity); - } - } - } - catch (IndexOutOfBoundsException ignored) {} - } - - @Subscribe - public void onCannonballFired(CannonballFired cannonballFired) - { - buildEntries(CANNONBALL); - } - - @Subscribe - public void onAnimationChanged(AnimationChanged animationChanged) - { - if (animationChanged.getActor() == client.getLocalPlayer()) - { - if (animationChanged.getActor().getAnimation() == HIGH_LEVEL_MAGIC_ATTACK) - { - //Trident of the seas - if (mainHand == TRIDENT_OF_THE_SEAS || mainHand == TRIDENT_OF_THE_SEAS_E || mainHand == TRIDENT_OF_THE_SEAS_FULL ) - { - buildEntries(CHAOS_RUNE); - buildEntries(DEATH_RUNE); - buildEntries(FIRE_RUNE, 5); - buildEntries(COINS_995, 10); - } - //Trident of the swamp - else if (mainHand == TRIDENT_OF_THE_SWAMP_E || mainHand == TRIDENT_OF_THE_SWAMP || mainHand == UNCHARGED_TOXIC_TRIDENT_E || mainHand == UNCHARGED_TOXIC_TRIDENT) - { - buildEntries(CHAOS_RUNE); - buildEntries(DEATH_RUNE); - buildEntries(FIRE_RUNE, 5); - buildEntries(ZULRAHS_SCALES); - } - //Sang Staff - else if (mainHand == SANGUINESTI_STAFF || mainHand == SANGUINESTI_STAFF_UNCHARGED) - { - buildEntries(BLOOD_RUNE, 3); - } - else - { - old = client.getItemContainer(InventoryID.INVENTORY); - - if (old != null && old.getItems() != null && actionStack.stream().noneMatch(a -> - a.getType() == CAST)) - { - MenuAction newAction = new MenuAction(CAST, old.getItems()); - actionStack.push(newAction); - } - } - } - else if (animationChanged.getActor().getAnimation() == LOW_LEVEL_MAGIC_ATTACK) - { - old = client.getItemContainer(InventoryID.INVENTORY); - - if (old != null && old.getItems() != null && actionStack.stream().noneMatch(a -> - a.getType() == CAST)) - { - MenuAction newAction = new MenuAction(CAST, old.getItems()); - actionStack.push(newAction); - } - } - } - } - - @Subscribe - public void onItemContainerChanged(ItemContainerChanged itemContainerChanged) - { - ItemContainer itemContainer = itemContainerChanged.getItemContainer(); - - if (itemContainer == client.getItemContainer(InventoryID.INVENTORY) && old != null && !actionStack.isEmpty()) - { - while (!actionStack.isEmpty()) - { - MenuAction frame = actionStack.pop(); - ActionType type = frame.getType(); - MenuAction.ItemAction itemFrame; - Item[] oldInv = frame.getOldInventory(); - switch (type) - { - case CONSUMABLE: - itemFrame = (MenuAction.ItemAction) frame; - int nextItem = itemFrame.getItemID(); - int nextSlot = itemFrame.getSlot(); - if (itemContainer.getItems()[nextSlot].getId() != oldInv[nextSlot].getId()) - { - buildEntries(nextItem); - } - break; - case TELEPORT: - itemFrame = (MenuAction.ItemAction) frame; - int teleid = itemFrame.getItemID(); - int slot = itemFrame.getSlot(); - if (itemContainer.getItems()[slot].getId() != oldInv[slot].getId() || itemContainer.getItems()[slot].getQuantity() != oldInv[slot].getQuantity()) - { - buildEntries(teleid); - } - break; - case CAST: - checkUsedRunes(itemContainer, oldInv); - break; - } - } - } - - if (itemContainer == client.getItemContainer(InventoryID.EQUIPMENT)) - { - //set mainhand for trident tracking - if (itemContainer.getItems().length > EQUIPMENT_MAINHAND_SLOT) - { - mainHand = itemContainer.getItems()[EQUIPMENT_MAINHAND_SLOT].getId(); - net.runelite.api.Item mainHandItem = itemContainer.getItems()[EQUIPMENT_MAINHAND_SLOT]; - for (int throwingIDs: THROWING_IDS) - { - if (mainHand == throwingIDs) - { - mainHandThrowing = true; - break; - } - else - { - mainHandThrowing = false; - } - } - if (mainHandThrowing) - { - if (throwingAmmoLoaded) - { - if (thrownId == mainHandItem.getId()) - { - if (thrownAmount - 1 == mainHandItem.getQuantity()) - { - buildEntries(mainHandItem.getId()); - thrownAmount = mainHandItem.getQuantity(); - } - else - { - thrownAmount = mainHandItem.getQuantity(); - } - } - else - { - thrownId = mainHandItem.getId(); - thrownAmount = mainHandItem.getQuantity(); - } - } - else - { - thrownId = mainHandItem.getId(); - thrownAmount = mainHandItem.getQuantity(); - throwingAmmoLoaded = true; - } - } - } - //Ammo tracking - if (itemContainer.getItems().length > EQUIPMENT_AMMO_SLOT) - { - net.runelite.api.Item ammoSlot = itemContainer.getItems()[EQUIPMENT_AMMO_SLOT]; - if (ammoSlot != null) - { - if (ammoLoaded) - { - if (ammoId == ammoSlot.getId()) - { - if (ammoAmount - 1 == ammoSlot.getQuantity()) - { - buildEntries(ammoSlot.getId()); - ammoAmount = ammoSlot.getQuantity(); - } - else - { - ammoAmount = ammoSlot.getQuantity(); - } - } - else - { - ammoId = ammoSlot.getId(); - ammoAmount = ammoSlot.getQuantity(); - } - } - else - { - ammoId = ammoSlot.getId(); - ammoAmount = ammoSlot.getQuantity(); - ammoLoaded = true; - } - } - } - - } - } - - @Subscribe - public void onMenuOptionClicked(final MenuOptionClicked event) - { - // Uses stacks to push/pop for tick eating - // Create pattern to find eat/drink at beginning - Pattern eatPattern = Pattern.compile(EAT_PATTERN); - Pattern drinkPattern = Pattern.compile(DRINK_PATTERN); - if (eatPattern.matcher(event.getMenuTarget().toLowerCase()).find() || drinkPattern.matcher(event.getMenuTarget().toLowerCase()).find()) - { - if (actionStack.stream().noneMatch(a -> - { - if (a instanceof MenuAction.ItemAction) - { - MenuAction.ItemAction i = (MenuAction.ItemAction) a; - return i.getItemID() == event.getId(); - } - return false; - })) - { - old = client.getItemContainer(InventoryID.INVENTORY); - int slot = event.getActionParam(); - if (old.getItems() != null) - { - int pushItem = old.getItems()[event.getActionParam()].getId(); - MenuAction newAction = new MenuAction.ItemAction(CONSUMABLE, old.getItems(), pushItem, slot); - actionStack.push(newAction); - } - } - } - - // Create pattern for teleport scrolls and tabs - Pattern teleportPattern = Pattern.compile(TELEPORT_PATTERN); - Pattern teletabPattern = Pattern.compile(TELETAB_PATTERN); - if (teleportPattern.matcher(event.getMenuTarget().toLowerCase()).find() || - teletabPattern.matcher(event.getMenuTarget().toLowerCase()).find()) - { - old = client.getItemContainer(InventoryID.INVENTORY); - - // Makes stack only contains one teleport type to stop from adding multiple of one teleport - if (old != null && old.getItems() != null && actionStack.stream().noneMatch(a -> - a.getType() == TELEPORT)) - { - int teleid = event.getId(); - MenuAction newAction = new MenuAction.ItemAction(TELEPORT, old.getItems(), teleid, event.getActionParam()); - actionStack.push(newAction); - } - } - - // Create pattern for spell cast - Pattern spellPattern = Pattern.compile(SPELL_PATTERN); - // note that here we look at the menuOption not menuTarget b/c the option for all spells is cast - // but the target differs based on each spell name - if (spellPattern.matcher(event.getMenuOption().toLowerCase()).find()) - { - old = client.getItemContainer(InventoryID.INVENTORY); - - if (old != null && old.getItems() != null && actionStack.stream().noneMatch(a -> - a.getType() == CAST)) - { - MenuAction newAction = new MenuAction(CAST, old.getItems()); - actionStack.push(newAction); - } - } - } - - /** - * Checks if item name is potion - * @param name the name of the item - * @return if the item is a potion - i.e. has a (1) (2) (3) or (4) in the name - */ - static boolean isPotion(String name) - { - return name.contains("(4)") || name.contains("(3)") || name.contains("(2)") || name.contains("(1)"); - } - - /** - * Checks if item name is pizza or pie - * @param name the name of the item - * @return if the item is a pizza or a pie - i.e. has pizza or pie in the name - */ - static boolean isPizzaPie(String name) - { - return name.toLowerCase().contains("pizza") || name.toLowerCase().contains(" pie"); - } - - static boolean isCake(String name, int itemId) - { - return name.toLowerCase().contains("cake") || itemId == ItemID.CHOCOLATE_SLICE; - } - - /** - * correct prices for potions, pizzas pies, and cakes - * tracker tracks each dose of a potion/pizza/pie/cake as an entire one - * so must divide price by total amount of doses in each - * this is necessary b/c the most correct/accurate price for these resources is the - * full price not the 1-dose price - * @param name the item name - * @param itemId the item id - * @param price the current calculated price - * @return the price modified by the number of doses - */ - private long scalePriceByDoses(String name, int itemId, long price) - { - if (isPotion(name)) - { - return price / POTION_DOSES; - } - if (isPizzaPie(name)) - { - return price / PIZZA_PIE_DOSES; - } - if (isCake(name, itemId)) - { - return price / CAKE_DOSES; - } - return price; - } - - /** - * Add an item to the supply tracker (with 1 count for that item) - * @param itemId the id of the item - */ - private void buildEntries(int itemId) - { - buildEntries(itemId, 1); - } - - /** - * Add an item to the supply tracker - * @param itemId the id of the item - * @param count the amount of the item to add to the tracker - */ - private void buildEntries(int itemId, int count) - { - final ItemComposition itemComposition = itemManager.getItemComposition(itemId); - String name = itemComposition.getName(); - long calculatedPrice; - - for (String raidsConsumables: RAIDS_CONSUMABLES) - { - if (name.toLowerCase().contains(raidsConsumables)) return; - } - - // convert potions, pizzas/pies, and cakes to their full equivalents - // e.g. a half pizza becomes full pizza, 3 dose potion becomes 4, etc... - if (isPotion(name)) - { - name = name.replaceAll(POTION_PATTERN, "(4)"); - itemId = getPotionID(name); - } - if (isPizzaPie(name)) - { - itemId = getFullVersionItemID(itemId); - name = itemManager.getItemComposition(itemId).getName(); - } - if (isCake(name, itemId)) - { - itemId = getFullVersionItemID(itemId); - name = itemManager.getItemComposition(itemId).getName(); - } - - int newQuantity; - if (suppliesEntry.containsKey(itemId)) - { - newQuantity = suppliesEntry.get(itemId).getQuantity() + count; - } - else - { - newQuantity = count; - } - - // calculate price for amount of doses used - calculatedPrice = ((long) itemManager.getItemPrice(itemId)) * ((long) newQuantity); - calculatedPrice = scalePriceByDoses(name, itemId, calculatedPrice); - - // write the new quantity and calculated price for this entry - SuppliesTrackerItem newEntry = new SuppliesTrackerItem( - itemId, - name, - newQuantity, - calculatedPrice); - - suppliesEntry.put(itemId, newEntry); - SwingUtilities.invokeLater(() -> - panel.addItem(newEntry)); - } - - /** - * reset all item stacks - */ - void clearSupplies() - { - suppliesEntry.clear(); - } - - /** - * reset an individual item stack - * @param itemId the id of the item stack - */ - void clearItem(int itemId) - { - suppliesEntry.remove(itemId); - } - - /** - * Gets the item id that matches the provided name within the itemManager - * @param name the given name - * @return the item id for this name - */ - private int getPotionID(String name) - { - int itemId = 0; - - List items = itemManager.search(name); - for (ItemPrice item: items) - { - if (item.getName().contains(name)) - { - itemId = item.getId(); - } - } - return itemId; - } - - /** - * Takes the item id of a partial item (e.g. 1 dose potion, 1/2 a pizza, etc...) and returns - * the corresponding full item - * @param itemId the partial item id - * @return the full item id - */ - private int getFullVersionItemID(int itemId) - { - switch (itemId) - { - case _12_ANCHOVY_PIZZA: - itemId = ANCHOVY_PIZZA; - break; - case _12_MEAT_PIZZA: - itemId = MEAT_PIZZA; - break; - case _12_PINEAPPLE_PIZZA: - itemId = PINEAPPLE_PIZZA; - break; - case _12_PLAIN_PIZZA: - itemId = PLAIN_PIZZA; - break; - case HALF_A_REDBERRY_PIE: - itemId = REDBERRY_PIE; - break; - case HALF_A_GARDEN_PIE: - itemId = GARDEN_PIE; - break; - case HALF_A_SUMMER_PIE: - itemId = SUMMER_PIE; - break; - case HALF_A_FISH_PIE: - itemId = FISH_PIE; - break; - case HALF_A_BOTANICAL_PIE: - itemId = BOTANICAL_PIE; - break; - case HALF_A_MUSHROOM_PIE: - itemId = MUSHROOM_PIE; - break; - case HALF_AN_ADMIRAL_PIE: - itemId = ADMIRAL_PIE; - break; - case HALF_A_WILD_PIE: - itemId = WILD_PIE; - break; - case HALF_AN_APPLE_PIE: - itemId = APPLE_PIE; - break; - case HALF_A_MEAT_PIE: - itemId = MEAT_PIE; - break; - // note behavior of case means both below cases return CAKE - case _23_CAKE: - case SLICE_OF_CAKE: - itemId = CAKE; - break; - case _23_CHOCOLATE_CAKE: - case CHOCOLATE_SLICE: - itemId = CHOCOLATE_CAKE; - break; - } - return itemId; - } -} +/* + * Copyright (c) 2018, Psikoi + * Copyright (c) 2018, Adam + * Copyright (c) 2018, Sir Girion + * Copyright (c) 2018, Davis Cook + * Copyright (c) 2018, Daddy Dozer + * 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.suppliestracker; + + +import com.google.inject.Provides; +import java.awt.image.BufferedImage; +import java.util.ArrayDeque; +import java.util.Deque; +import java.util.HashMap; +import java.util.List; +import java.util.Random; +import java.util.regex.Pattern; +import javax.inject.Inject; +import javax.swing.SwingUtilities; +import lombok.extern.slf4j.Slf4j; +import static net.runelite.api.AnimationID.BLOWPIPE_ATTACK; +import static net.runelite.api.AnimationID.HIGH_LEVEL_MAGIC_ATTACK; +import static net.runelite.api.AnimationID.LOW_LEVEL_MAGIC_ATTACK; +import net.runelite.api.Client; +import net.runelite.api.EquipmentInventorySlot; +import net.runelite.api.InventoryID; +import net.runelite.api.Item; +import net.runelite.api.ItemComposition; +import net.runelite.api.ItemContainer; +import net.runelite.api.ItemID; +import static net.runelite.api.ItemID.ACCUMULATOR_MAX_CAPE; +import static net.runelite.api.ItemID.ADAMANT_DART; +import static net.runelite.api.ItemID.ADAMANT_KNIFE; +import static net.runelite.api.ItemID.ADAMANT_THROWNAXE; +import static net.runelite.api.ItemID.ADMIRAL_PIE; +import static net.runelite.api.ItemID.AIR_RUNE; +import static net.runelite.api.ItemID.ANCHOVY_PIZZA; +import static net.runelite.api.ItemID.APPLE_PIE; +import static net.runelite.api.ItemID.ASSEMBLER_MAX_CAPE; +import static net.runelite.api.ItemID.ASTRAL_RUNE; +import static net.runelite.api.ItemID.AVAS_ACCUMULATOR; +import static net.runelite.api.ItemID.AVAS_ASSEMBLER; +import static net.runelite.api.ItemID.AVAS_ATTRACTOR; +import static net.runelite.api.ItemID.BLACK_CHINCHOMPA; +import static net.runelite.api.ItemID.BLACK_DART; +import static net.runelite.api.ItemID.BLACK_KNIFE; +import static net.runelite.api.ItemID.BLOOD_RUNE; +import static net.runelite.api.ItemID.BODY_RUNE; +import static net.runelite.api.ItemID.BOTANICAL_PIE; +import static net.runelite.api.ItemID.BRONZE_DART; +import static net.runelite.api.ItemID.BRONZE_KNIFE; +import static net.runelite.api.ItemID.BRONZE_THROWNAXE; +import static net.runelite.api.ItemID.CAKE; +import static net.runelite.api.ItemID.CANNONBALL; +import static net.runelite.api.ItemID.CHAOS_RUNE; +import static net.runelite.api.ItemID.CHINCHOMPA_10033; +import static net.runelite.api.ItemID.CHOCOLATE_CAKE; +import static net.runelite.api.ItemID.CHOCOLATE_SLICE; +import static net.runelite.api.ItemID.COINS_995; +import static net.runelite.api.ItemID.COSMIC_RUNE; +import static net.runelite.api.ItemID.DEATH_RUNE; +import static net.runelite.api.ItemID.DRAGON_DART; +import static net.runelite.api.ItemID.DRAGON_KNIFE; +import static net.runelite.api.ItemID.DRAGON_KNIFEP; +import static net.runelite.api.ItemID.DRAGON_KNIFEP_22808; +import static net.runelite.api.ItemID.DRAGON_KNIFEP_22810; +import static net.runelite.api.ItemID.DRAGON_KNIFE_22812; +import static net.runelite.api.ItemID.DRAGON_KNIFE_22814; +import static net.runelite.api.ItemID.DRAGON_THROWNAXE; +import static net.runelite.api.ItemID.DUST_RUNE; +import static net.runelite.api.ItemID.EARTH_RUNE; +import static net.runelite.api.ItemID.FIRE_RUNE; +import static net.runelite.api.ItemID.FISH_PIE; +import static net.runelite.api.ItemID.GARDEN_PIE; +import static net.runelite.api.ItemID.HALF_AN_ADMIRAL_PIE; +import static net.runelite.api.ItemID.HALF_AN_APPLE_PIE; +import static net.runelite.api.ItemID.HALF_A_BOTANICAL_PIE; +import static net.runelite.api.ItemID.HALF_A_FISH_PIE; +import static net.runelite.api.ItemID.HALF_A_GARDEN_PIE; +import static net.runelite.api.ItemID.HALF_A_MEAT_PIE; +import static net.runelite.api.ItemID.HALF_A_MUSHROOM_PIE; +import static net.runelite.api.ItemID.HALF_A_REDBERRY_PIE; +import static net.runelite.api.ItemID.HALF_A_SUMMER_PIE; +import static net.runelite.api.ItemID.HALF_A_WILD_PIE; +import static net.runelite.api.ItemID.IRON_DART; +import static net.runelite.api.ItemID.IRON_KNIFE; +import static net.runelite.api.ItemID.IRON_THROWNAXE; +import static net.runelite.api.ItemID.LAVA_RUNE; +import static net.runelite.api.ItemID.LAW_RUNE; +import static net.runelite.api.ItemID.MEAT_PIE; +import static net.runelite.api.ItemID.MEAT_PIZZA; +import static net.runelite.api.ItemID.MIND_RUNE; +import static net.runelite.api.ItemID.MIST_RUNE; +import static net.runelite.api.ItemID.MITHRIL_DART; +import static net.runelite.api.ItemID.MITHRIL_KNIFE; +import static net.runelite.api.ItemID.MITHRIL_THROWNAXE; +import static net.runelite.api.ItemID.MUD_RUNE; +import static net.runelite.api.ItemID.MUSHROOM_PIE; +import static net.runelite.api.ItemID.NATURE_RUNE; +import static net.runelite.api.ItemID.PINEAPPLE_PIZZA; +import static net.runelite.api.ItemID.PLAIN_PIZZA; +import static net.runelite.api.ItemID.RANGING_CAPE; +import static net.runelite.api.ItemID.REDBERRY_PIE; +import static net.runelite.api.ItemID.RED_CHINCHOMPA_10034; +import static net.runelite.api.ItemID.RUNE_DART; +import static net.runelite.api.ItemID.RUNE_KNIFE; +import static net.runelite.api.ItemID.RUNE_THROWNAXE; +import static net.runelite.api.ItemID.SANGUINESTI_STAFF; +import static net.runelite.api.ItemID.SANGUINESTI_STAFF_UNCHARGED; +import static net.runelite.api.ItemID.SLICE_OF_CAKE; +import static net.runelite.api.ItemID.SMOKE_RUNE; +import static net.runelite.api.ItemID.SOUL_RUNE; +import static net.runelite.api.ItemID.STEAM_RUNE; +import static net.runelite.api.ItemID.STEEL_DART; +import static net.runelite.api.ItemID.STEEL_KNIFE; +import static net.runelite.api.ItemID.STEEL_THROWNAXE; +import static net.runelite.api.ItemID.SUMMER_PIE; +import static net.runelite.api.ItemID.TRIDENT_OF_THE_SEAS; +import static net.runelite.api.ItemID.TRIDENT_OF_THE_SEAS_E; +import static net.runelite.api.ItemID.TRIDENT_OF_THE_SEAS_FULL; +import static net.runelite.api.ItemID.TRIDENT_OF_THE_SWAMP; +import static net.runelite.api.ItemID.TRIDENT_OF_THE_SWAMP_E; +import static net.runelite.api.ItemID.UNCHARGED_TOXIC_TRIDENT; +import static net.runelite.api.ItemID.UNCHARGED_TOXIC_TRIDENT_E; +import static net.runelite.api.ItemID.WATER_RUNE; +import static net.runelite.api.ItemID.WILD_PIE; +import static net.runelite.api.ItemID.WRATH_RUNE; +import static net.runelite.api.ItemID.ZULRAHS_SCALES; +import static net.runelite.api.ItemID._12_ANCHOVY_PIZZA; +import static net.runelite.api.ItemID._12_MEAT_PIZZA; +import static net.runelite.api.ItemID._12_PINEAPPLE_PIZZA; +import static net.runelite.api.ItemID._12_PLAIN_PIZZA; +import static net.runelite.api.ItemID._23_CAKE; +import static net.runelite.api.ItemID._23_CHOCOLATE_CAKE; +import net.runelite.api.Player; +import net.runelite.api.VarPlayer; +import net.runelite.api.events.AnimationChanged; +import net.runelite.api.events.CannonballFired; +import net.runelite.api.events.GameTick; +import net.runelite.api.events.ItemContainerChanged; +import net.runelite.api.events.MenuOptionClicked; +import net.runelite.api.events.VarbitChanged; +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.plugins.PluginType; +import static net.runelite.client.plugins.suppliestracker.ActionType.CAST; +import static net.runelite.client.plugins.suppliestracker.ActionType.CONSUMABLE; +import static net.runelite.client.plugins.suppliestracker.ActionType.TELEPORT; +import net.runelite.client.ui.ClientToolbar; +import net.runelite.client.ui.NavigationButton; +import net.runelite.client.util.ImageUtil; +import net.runelite.http.api.item.ItemPrice; + + +@PluginDescriptor( + name = "Supplies Used Tracker", + description = "Tracks supplies used during the session", + tags = {"cost"}, + type = PluginType.UTILITY, + enabledByDefault = false +) +@Slf4j +public class SuppliesTrackerPlugin extends Plugin +{ + private static final String POTION_PATTERN = "[(]\\d[)]"; + + private static final String EAT_PATTERN = "^eat"; + private static final String DRINK_PATTERN = "^drink"; + private static final String TELEPORT_PATTERN = "^teleport"; + private static final String TELETAB_PATTERN = "^break"; + private static final String SPELL_PATTERN = "^cast|^grand\\sexchange|^outside|^seers|^yanille"; + + private static final int EQUIPMENT_MAINHAND_SLOT = EquipmentInventorySlot.WEAPON.getSlotIdx(); + private static final int EQUIPMENT_AMMO_SLOT = EquipmentInventorySlot.AMMO.getSlotIdx(); + private static final int EQUIPMENT_CAPE_SLOT = EquipmentInventorySlot.CAPE.getSlotIdx(); + + private static final double NO_AVAS_PERCENT = 1.0; + private static final double ASSEMBLER_PERCENT = 0.20; + private static final double ACCUMULATOR_PERCENT = 0.28; + private static final double ATTRACTOR_PERCENT = 0.40; + + private static final int BLOWPIPE_TICKS_RAPID_PVM = 2; + private static final int BLOWPIPE_TICKS_RAPID_PVP = 3; + private static final int BLOWPIPE_TICKS_NORMAL_PVM = 3; + private static final int BLOWPIPE_TICKS_NORMAL_PVP = 4; + + private static final double SCALES_PERCENT = 0.66; + + private static final int POTION_DOSES = 4, CAKE_DOSES = 3, PIZZA_PIE_DOSES = 2; + + private static final Random random = new Random(); + + private static final int[] THROWING_IDS = new int[]{BRONZE_DART, IRON_DART, STEEL_DART, BLACK_DART, MITHRIL_DART, ADAMANT_DART, RUNE_DART, DRAGON_DART, BRONZE_KNIFE, IRON_KNIFE, STEEL_KNIFE, BLACK_KNIFE, MITHRIL_KNIFE, ADAMANT_KNIFE, RUNE_KNIFE, BRONZE_THROWNAXE, IRON_THROWNAXE, STEEL_THROWNAXE, MITHRIL_THROWNAXE, ADAMANT_THROWNAXE, RUNE_THROWNAXE, DRAGON_KNIFE, DRAGON_KNIFE_22812, DRAGON_KNIFE_22814, DRAGON_KNIFEP_22808, DRAGON_KNIFEP_22810, DRAGON_KNIFEP, DRAGON_THROWNAXE, CHINCHOMPA_10033, RED_CHINCHOMPA_10034, BLACK_CHINCHOMPA}; + private static final int[] RUNE_IDS = new int[]{AIR_RUNE, WATER_RUNE, EARTH_RUNE, MIND_RUNE, BODY_RUNE, COSMIC_RUNE, CHAOS_RUNE, NATURE_RUNE, LAW_RUNE, DEATH_RUNE, ASTRAL_RUNE, BLOOD_RUNE, SOUL_RUNE, WRATH_RUNE, MIST_RUNE, DUST_RUNE, MUD_RUNE, SMOKE_RUNE, STEAM_RUNE, LAVA_RUNE}; + + //Hold Supply Data + private static HashMap suppliesEntry = new HashMap<>(); + private ItemContainer old; + private Deque actionStack = new ArrayDeque<>(); + private int ammoId = 0; + private int ammoAmount = 0; + private int thrownId = 0; + private int thrownAmount = 0; + private boolean ammoLoaded = false; + private boolean throwingAmmoLoaded = false; + private boolean mainHandThrowing = false; + private int mainHand = 0; + private SuppliesTrackerPanel panel; + private NavigationButton navButton; + private String[] RAIDS_CONSUMABLES = new String[]{"xeric's", "elder", "twisted", "revitalisation", "overload", "prayer enhance", "pysk", "suphi", "leckish", "brawk", "mycil", "roqed", "kyren", "guanic", "prael", "giral", "phluxia", "kryket", "murng", "psykk"}; + + private int attackStyleVarbit = -1; + private int ticks = 0; + private int ticksInAnimation; + + @Inject + private ClientToolbar clientToolbar; + + @Inject + private ItemManager itemManager; + + @Inject + private SuppliesTrackerConfig config; + + @Inject + private Client client; + + + @Override + protected void startUp() throws Exception + { + panel = new SuppliesTrackerPanel(itemManager, this); + final BufferedImage header = ImageUtil.getResourceStreamFromClass(getClass(), "panel_icon.png"); + panel.loadHeaderIcon(header); + final BufferedImage icon = ImageUtil.getResourceStreamFromClass(getClass(), "panel_icon.png"); + + navButton = NavigationButton.builder() + .tooltip("Supplies Tracker") + .icon(icon) + .priority(5) + .panel(panel) + .build(); + + clientToolbar.addNavigation(navButton); + } + + @Override + protected void shutDown() + { + clientToolbar.removeNavigation(navButton); + } + + @Provides + SuppliesTrackerConfig provideConfig(ConfigManager configManager) + { + return configManager.getConfig(SuppliesTrackerConfig.class); + } + + @Subscribe + public void onGameTick(GameTick tick) + { + Player player = client.getLocalPlayer(); + if (player.getAnimation() == BLOWPIPE_ATTACK) + { + ticks++; + } + if (ticks == ticksInAnimation && (player.getAnimation() == BLOWPIPE_ATTACK)) + { + double ava_percent = getAccumulatorPercent(); + // randomize the usage of supplies since we CANNOT actually get real supplies used + if (random.nextDouble() <= ava_percent) + { + buildEntries(config.blowpipeAmmo().getDartID()); + + } + if (random.nextDouble() <= SCALES_PERCENT) + { + buildEntries(ZULRAHS_SCALES); + } + ticks = 0; + } + } + + /** + * checks the player's cape slot to determine what percent of their darts are lost + * - where lost means either break or drop to floor + * + * @return the percent lost + */ + private double getAccumulatorPercent() + { + double percent = NO_AVAS_PERCENT; + ItemContainer equipment = client.getItemContainer(InventoryID.EQUIPMENT); + if (equipment != null && equipment.getItems().length > EQUIPMENT_CAPE_SLOT) + { + int capeID = equipment.getItems()[EQUIPMENT_CAPE_SLOT].getId(); + switch (capeID) + { + case AVAS_ASSEMBLER: + case ASSEMBLER_MAX_CAPE: + percent = ASSEMBLER_PERCENT; + break; + case AVAS_ACCUMULATOR: + case ACCUMULATOR_MAX_CAPE: + // TODO: the ranging cape can be used as an attractor so this could be wrong + case RANGING_CAPE: + percent = ACCUMULATOR_PERCENT; + break; + case AVAS_ATTRACTOR: + percent = ATTRACTOR_PERCENT; + break; + } + } + return percent; + } + + @Subscribe + public void onVarbitChanged(VarbitChanged event) + { + if (attackStyleVarbit == -1 || attackStyleVarbit != client.getVar(VarPlayer.ATTACK_STYLE)) + { + attackStyleVarbit = client.getVar(VarPlayer.ATTACK_STYLE); + if (attackStyleVarbit == 0 || attackStyleVarbit == 3) + { + ticksInAnimation = BLOWPIPE_TICKS_NORMAL_PVM; + if (client.getLocalPlayer() != null && + client.getLocalPlayer().getInteracting() instanceof Player) + { + ticksInAnimation = BLOWPIPE_TICKS_NORMAL_PVP; + } + } + else if (attackStyleVarbit == 1) + { + ticksInAnimation = BLOWPIPE_TICKS_RAPID_PVM; + if (client.getLocalPlayer() != null && + client.getLocalPlayer().getInteracting() instanceof Player) + { + ticksInAnimation = BLOWPIPE_TICKS_RAPID_PVP; + } + } + } + } + + /** + * Checks for changes between the provided inventories in runes specifically to add those runes + * to the supply tracker + *

+ * we can't in general just check for when inventory slots change but this method is only run + * immediately after the player performs a cast animation or cast menu click/entry + * + * @param itemContainer the new inventory + * @param oldInv the old inventory + */ + private void checkUsedRunes(ItemContainer itemContainer, Item[] oldInv) + { + try + { + for (int i = 0; i < itemContainer.getItems().length; i++) + { + Item newItem = itemContainer.getItems()[i]; + Item oldItem = oldInv[i]; + boolean isRune = false; + for (int runeId : RUNE_IDS) + { + if (oldItem.getId() == runeId) + { + isRune = true; + } + } + if (isRune && (newItem.getId() != oldItem.getId() || newItem.getQuantity() != oldItem.getQuantity())) + { + int quantity = oldItem.getQuantity(); + if (newItem.getId() == oldItem.getId()) + { + quantity -= newItem.getQuantity(); + } + buildEntries(oldItem.getId(), quantity); + } + } + } + catch (IndexOutOfBoundsException ignored) + { + } + } + + @Subscribe + public void onCannonballFired(CannonballFired cannonballFired) + { + buildEntries(CANNONBALL); + } + + @Subscribe + public void onAnimationChanged(AnimationChanged animationChanged) + { + if (animationChanged.getActor() == client.getLocalPlayer()) + { + if (animationChanged.getActor().getAnimation() == HIGH_LEVEL_MAGIC_ATTACK) + { + //Trident of the seas + if (mainHand == TRIDENT_OF_THE_SEAS || mainHand == TRIDENT_OF_THE_SEAS_E || mainHand == TRIDENT_OF_THE_SEAS_FULL) + { + buildEntries(CHAOS_RUNE); + buildEntries(DEATH_RUNE); + buildEntries(FIRE_RUNE, 5); + buildEntries(COINS_995, 10); + } + //Trident of the swamp + else if (mainHand == TRIDENT_OF_THE_SWAMP_E || mainHand == TRIDENT_OF_THE_SWAMP || mainHand == UNCHARGED_TOXIC_TRIDENT_E || mainHand == UNCHARGED_TOXIC_TRIDENT) + { + buildEntries(CHAOS_RUNE); + buildEntries(DEATH_RUNE); + buildEntries(FIRE_RUNE, 5); + buildEntries(ZULRAHS_SCALES); + } + //Sang Staff + else if (mainHand == SANGUINESTI_STAFF || mainHand == SANGUINESTI_STAFF_UNCHARGED) + { + buildEntries(BLOOD_RUNE, 3); + } + else + { + old = client.getItemContainer(InventoryID.INVENTORY); + + if (old != null && old.getItems() != null && actionStack.stream().noneMatch(a -> + a.getType() == CAST)) + { + MenuAction newAction = new MenuAction(CAST, old.getItems()); + actionStack.push(newAction); + } + } + } + else if (animationChanged.getActor().getAnimation() == LOW_LEVEL_MAGIC_ATTACK) + { + old = client.getItemContainer(InventoryID.INVENTORY); + + if (old != null && old.getItems() != null && actionStack.stream().noneMatch(a -> + a.getType() == CAST)) + { + MenuAction newAction = new MenuAction(CAST, old.getItems()); + actionStack.push(newAction); + } + } + } + } + + @Subscribe + public void onItemContainerChanged(ItemContainerChanged itemContainerChanged) + { + ItemContainer itemContainer = itemContainerChanged.getItemContainer(); + + if (itemContainer == client.getItemContainer(InventoryID.INVENTORY) && old != null && !actionStack.isEmpty()) + { + while (!actionStack.isEmpty()) + { + MenuAction frame = actionStack.pop(); + ActionType type = frame.getType(); + MenuAction.ItemAction itemFrame; + Item[] oldInv = frame.getOldInventory(); + switch (type) + { + case CONSUMABLE: + itemFrame = (MenuAction.ItemAction) frame; + int nextItem = itemFrame.getItemID(); + int nextSlot = itemFrame.getSlot(); + if (itemContainer.getItems()[nextSlot].getId() != oldInv[nextSlot].getId()) + { + buildEntries(nextItem); + } + break; + case TELEPORT: + itemFrame = (MenuAction.ItemAction) frame; + int teleid = itemFrame.getItemID(); + int slot = itemFrame.getSlot(); + if (itemContainer.getItems()[slot].getId() != oldInv[slot].getId() || itemContainer.getItems()[slot].getQuantity() != oldInv[slot].getQuantity()) + { + buildEntries(teleid); + } + break; + case CAST: + checkUsedRunes(itemContainer, oldInv); + break; + } + } + } + + if (itemContainer == client.getItemContainer(InventoryID.EQUIPMENT)) + { + //set mainhand for trident tracking + if (itemContainer.getItems().length > EQUIPMENT_MAINHAND_SLOT) + { + mainHand = itemContainer.getItems()[EQUIPMENT_MAINHAND_SLOT].getId(); + net.runelite.api.Item mainHandItem = itemContainer.getItems()[EQUIPMENT_MAINHAND_SLOT]; + for (int throwingIDs : THROWING_IDS) + { + if (mainHand == throwingIDs) + { + mainHandThrowing = true; + break; + } + else + { + mainHandThrowing = false; + } + } + if (mainHandThrowing) + { + if (throwingAmmoLoaded) + { + if (thrownId == mainHandItem.getId()) + { + if (thrownAmount - 1 == mainHandItem.getQuantity()) + { + buildEntries(mainHandItem.getId()); + thrownAmount = mainHandItem.getQuantity(); + } + else + { + thrownAmount = mainHandItem.getQuantity(); + } + } + else + { + thrownId = mainHandItem.getId(); + thrownAmount = mainHandItem.getQuantity(); + } + } + else + { + thrownId = mainHandItem.getId(); + thrownAmount = mainHandItem.getQuantity(); + throwingAmmoLoaded = true; + } + } + } + //Ammo tracking + if (itemContainer.getItems().length > EQUIPMENT_AMMO_SLOT) + { + net.runelite.api.Item ammoSlot = itemContainer.getItems()[EQUIPMENT_AMMO_SLOT]; + if (ammoSlot != null) + { + if (ammoLoaded) + { + if (ammoId == ammoSlot.getId()) + { + if (ammoAmount - 1 == ammoSlot.getQuantity()) + { + buildEntries(ammoSlot.getId()); + ammoAmount = ammoSlot.getQuantity(); + } + else + { + ammoAmount = ammoSlot.getQuantity(); + } + } + else + { + ammoId = ammoSlot.getId(); + ammoAmount = ammoSlot.getQuantity(); + } + } + else + { + ammoId = ammoSlot.getId(); + ammoAmount = ammoSlot.getQuantity(); + ammoLoaded = true; + } + } + } + + } + } + + @Subscribe + public void onMenuOptionClicked(final MenuOptionClicked event) + { + // Uses stacks to push/pop for tick eating + // Create pattern to find eat/drink at beginning + Pattern eatPattern = Pattern.compile(EAT_PATTERN); + Pattern drinkPattern = Pattern.compile(DRINK_PATTERN); + if (eatPattern.matcher(event.getMenuTarget().toLowerCase()).find() || drinkPattern.matcher(event.getMenuTarget().toLowerCase()).find()) + { + if (actionStack.stream().noneMatch(a -> + { + if (a instanceof MenuAction.ItemAction) + { + MenuAction.ItemAction i = (MenuAction.ItemAction) a; + return i.getItemID() == event.getId(); + } + return false; + })) + { + old = client.getItemContainer(InventoryID.INVENTORY); + int slot = event.getActionParam(); + if (old.getItems() != null) + { + int pushItem = old.getItems()[event.getActionParam()].getId(); + MenuAction newAction = new MenuAction.ItemAction(CONSUMABLE, old.getItems(), pushItem, slot); + actionStack.push(newAction); + } + } + } + + // Create pattern for teleport scrolls and tabs + Pattern teleportPattern = Pattern.compile(TELEPORT_PATTERN); + Pattern teletabPattern = Pattern.compile(TELETAB_PATTERN); + if (teleportPattern.matcher(event.getMenuTarget().toLowerCase()).find() || + teletabPattern.matcher(event.getMenuTarget().toLowerCase()).find()) + { + old = client.getItemContainer(InventoryID.INVENTORY); + + // Makes stack only contains one teleport type to stop from adding multiple of one teleport + if (old != null && old.getItems() != null && actionStack.stream().noneMatch(a -> + a.getType() == TELEPORT)) + { + int teleid = event.getId(); + MenuAction newAction = new MenuAction.ItemAction(TELEPORT, old.getItems(), teleid, event.getActionParam()); + actionStack.push(newAction); + } + } + + // Create pattern for spell cast + Pattern spellPattern = Pattern.compile(SPELL_PATTERN); + // note that here we look at the menuOption not menuTarget b/c the option for all spells is cast + // but the target differs based on each spell name + if (spellPattern.matcher(event.getMenuOption().toLowerCase()).find()) + { + old = client.getItemContainer(InventoryID.INVENTORY); + + if (old != null && old.getItems() != null && actionStack.stream().noneMatch(a -> + a.getType() == CAST)) + { + MenuAction newAction = new MenuAction(CAST, old.getItems()); + actionStack.push(newAction); + } + } + } + + /** + * Checks if item name is potion + * + * @param name the name of the item + * @return if the item is a potion - i.e. has a (1) (2) (3) or (4) in the name + */ + static boolean isPotion(String name) + { + return name.contains("(4)") || name.contains("(3)") || name.contains("(2)") || name.contains("(1)"); + } + + /** + * Checks if item name is pizza or pie + * + * @param name the name of the item + * @return if the item is a pizza or a pie - i.e. has pizza or pie in the name + */ + static boolean isPizzaPie(String name) + { + return name.toLowerCase().contains("pizza") || name.toLowerCase().contains(" pie"); + } + + static boolean isCake(String name, int itemId) + { + return name.toLowerCase().contains("cake") || itemId == ItemID.CHOCOLATE_SLICE; + } + + /** + * correct prices for potions, pizzas pies, and cakes + * tracker tracks each dose of a potion/pizza/pie/cake as an entire one + * so must divide price by total amount of doses in each + * this is necessary b/c the most correct/accurate price for these resources is the + * full price not the 1-dose price + * + * @param name the item name + * @param itemId the item id + * @param price the current calculated price + * @return the price modified by the number of doses + */ + private long scalePriceByDoses(String name, int itemId, long price) + { + if (isPotion(name)) + { + return price / POTION_DOSES; + } + if (isPizzaPie(name)) + { + return price / PIZZA_PIE_DOSES; + } + if (isCake(name, itemId)) + { + return price / CAKE_DOSES; + } + return price; + } + + /** + * Add an item to the supply tracker (with 1 count for that item) + * + * @param itemId the id of the item + */ + private void buildEntries(int itemId) + { + buildEntries(itemId, 1); + } + + /** + * Add an item to the supply tracker + * + * @param itemId the id of the item + * @param count the amount of the item to add to the tracker + */ + private void buildEntries(int itemId, int count) + { + final ItemComposition itemComposition = itemManager.getItemComposition(itemId); + String name = itemComposition.getName(); + long calculatedPrice; + + for (String raidsConsumables : RAIDS_CONSUMABLES) + { + if (name.toLowerCase().contains(raidsConsumables)) + { + return; + } + } + + // convert potions, pizzas/pies, and cakes to their full equivalents + // e.g. a half pizza becomes full pizza, 3 dose potion becomes 4, etc... + if (isPotion(name)) + { + name = name.replaceAll(POTION_PATTERN, "(4)"); + itemId = getPotionID(name); + } + if (isPizzaPie(name)) + { + itemId = getFullVersionItemID(itemId); + name = itemManager.getItemComposition(itemId).getName(); + } + if (isCake(name, itemId)) + { + itemId = getFullVersionItemID(itemId); + name = itemManager.getItemComposition(itemId).getName(); + } + + int newQuantity; + if (suppliesEntry.containsKey(itemId)) + { + newQuantity = suppliesEntry.get(itemId).getQuantity() + count; + } + else + { + newQuantity = count; + } + + // calculate price for amount of doses used + calculatedPrice = ((long) itemManager.getItemPrice(itemId)) * ((long) newQuantity); + calculatedPrice = scalePriceByDoses(name, itemId, calculatedPrice); + + // write the new quantity and calculated price for this entry + SuppliesTrackerItem newEntry = new SuppliesTrackerItem( + itemId, + name, + newQuantity, + calculatedPrice); + + suppliesEntry.put(itemId, newEntry); + SwingUtilities.invokeLater(() -> + panel.addItem(newEntry)); + } + + /** + * reset all item stacks + */ + void clearSupplies() + { + suppliesEntry.clear(); + } + + /** + * reset an individual item stack + * + * @param itemId the id of the item stack + */ + void clearItem(int itemId) + { + suppliesEntry.remove(itemId); + } + + /** + * Gets the item id that matches the provided name within the itemManager + * + * @param name the given name + * @return the item id for this name + */ + private int getPotionID(String name) + { + int itemId = 0; + + List items = itemManager.search(name); + for (ItemPrice item : items) + { + if (item.getName().contains(name)) + { + itemId = item.getId(); + } + } + return itemId; + } + + /** + * Takes the item id of a partial item (e.g. 1 dose potion, 1/2 a pizza, etc...) and returns + * the corresponding full item + * + * @param itemId the partial item id + * @return the full item id + */ + private int getFullVersionItemID(int itemId) + { + switch (itemId) + { + case _12_ANCHOVY_PIZZA: + itemId = ANCHOVY_PIZZA; + break; + case _12_MEAT_PIZZA: + itemId = MEAT_PIZZA; + break; + case _12_PINEAPPLE_PIZZA: + itemId = PINEAPPLE_PIZZA; + break; + case _12_PLAIN_PIZZA: + itemId = PLAIN_PIZZA; + break; + case HALF_A_REDBERRY_PIE: + itemId = REDBERRY_PIE; + break; + case HALF_A_GARDEN_PIE: + itemId = GARDEN_PIE; + break; + case HALF_A_SUMMER_PIE: + itemId = SUMMER_PIE; + break; + case HALF_A_FISH_PIE: + itemId = FISH_PIE; + break; + case HALF_A_BOTANICAL_PIE: + itemId = BOTANICAL_PIE; + break; + case HALF_A_MUSHROOM_PIE: + itemId = MUSHROOM_PIE; + break; + case HALF_AN_ADMIRAL_PIE: + itemId = ADMIRAL_PIE; + break; + case HALF_A_WILD_PIE: + itemId = WILD_PIE; + break; + case HALF_AN_APPLE_PIE: + itemId = APPLE_PIE; + break; + case HALF_A_MEAT_PIE: + itemId = MEAT_PIE; + break; + // note behavior of case means both below cases return CAKE + case _23_CAKE: + case SLICE_OF_CAKE: + itemId = CAKE; + break; + case _23_CHOCOLATE_CAKE: + case CHOCOLATE_SLICE: + itemId = CHOCOLATE_CAKE; + break; + } + return itemId; + } +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/tarnslair/Obstacles.java b/runelite-client/src/main/java/net/runelite/client/plugins/tarnslair/Obstacles.java index b26823c4a8..43e82d076b 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/tarnslair/Obstacles.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/tarnslair/Obstacles.java @@ -1,131 +1,217 @@ -/* - * Copyright (c) 2018, Shaun Dreclin - * 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.tarnslair; - -import com.google.common.collect.Sets; -import java.util.Set; -import static net.runelite.api.NullObjectID.NULL_20575; -import static net.runelite.api.ObjectID.*; - -class Obstacles -{ - static final Set STAIRCASE_IDS = Sets.newHashSet( - PASSAGEWAY_15770, /*Wall staircase*/ - PASSAGEWAY_15771, /*Wall staircase*/ - PASSAGEWAY_15772, /*Wall staircase*/ - PASSAGEWAY_15773, /*Wall staircase*/ - PASSAGEWAY_15774, /*Wall staircase*/ - PASSAGEWAY_16129, /*Wall staircase*/ - PASSAGEWAY_16130, /*Wall staircase*/ - PASSAGEWAY_16131, /*Wall staircase*/ - PASSAGEWAY_16132, /*Wall staircase*/ - PASSAGEWAY_16133, /*Wall staircase*/ - PASSAGEWAY_16134, /*Wall staircase*/ - PASSAGEWAY_18307, /*Wall staircase*/ - PASSAGEWAY_18308, /*Wall staircase*/ - PASSAGEWAY_18309, /*Wall staircase*/ - PASSAGEWAY_18310, /*Wall staircase*/ - PASSAGEWAY_18311, /*Wall staircase*/ - PASSAGEWAY_20488, /*Wall staircase*/ - PASSAGEWAY_20489, /*Wall staircase*/ - PASSAGEWAY_20490, /*Wall staircase*/ - PASSAGEWAY_20491, /*Wall staircase*/ - PASSAGEWAY_20492, /*Wall staircase*/ - PASSAGEWAY_20493, /*Wall staircase*/ - PASSAGEWAY_20495, /*Wall staircase*/ - PASSAGEWAY_20497, /*Wall staircase*/ - PASSAGEWAY_20498, /*Wall staircase*/ - PASSAGEWAY_20499, /*Wall staircase*/ - PASSAGEWAY_20500, /*Wall staircase*/ - PASSAGEWAY_20501, /*Wall staircase*/ - PASSAGEWAY_20502, /*Wall staircase*/ - PASSAGEWAY_20503, /*Wall staircase*/ - PASSAGEWAY_20504, /*Wall staircase*/ - PASSAGEWAY_20505, /*Wall staircase*/ - PASSAGEWAY_20506, /*Wall staircase*/ - PASSAGEWAY_20506, /*Wall staircase*/ - PASSAGEWAY_20507, /*Wall staircase*/ - PASSAGEWAY_20509, /*Wall staircase*/ - PASSAGEWAY_20510, /*Wall staircase*/ - PASSAGEWAY_20511, /*Wall staircase*/ - PASSAGEWAY_20512, /*Wall staircase*/ - PASSAGEWAY_20513, /*Wall staircase*/ - PASSAGEWAY_20514, /*Wall staircase*/ - PASSAGEWAY_20515, /*Wall staircase*/ - PASSAGEWAY_20516, /*Wall staircase*/ - PASSAGEWAY_20517, /*Wall staircase*/ - PASSAGEWAY_20518, /*Wall staircase*/ - PASSAGEWAY_20519, /*Wall staircase*/ - PASSAGEWAY_20520, /*Wall staircase*/ - PASSAGEWAY_20521, /*Wall staircase*/ - PASSAGEWAY_20522, /*Wall staircase*/ - PASSAGEWAY_20523, /*Wall staircase*/ - PASSAGEWAY_20524, /*Wall staircase*/ - PASSAGEWAY_20525, /*Wall staircase*/ - PASSAGEWAY_20526, /*Wall staircase*/ - PASSAGEWAY_20527, /*Wall staircase*/ - PASSAGEWAY_20528, /*Wall staircase*/ - PASSAGEWAY_20529, /*Wall staircase*/ - PASSAGEWAY_20530, /*Wall staircase*/ - PASSAGEWAY_20531, /*Wall staircase*/ - PASSAGEWAY_20532, /*Wall staircase*/ - PASSAGEWAY_20533, /*Wall staircase*/ - PASSAGEWAY_20534, /*Wall staircase*/ - PASSAGEWAY_20535, /*Wall staircase*/ - PASSAGEWAY_20536, /*Wall staircase*/ - PASSAGEWAY_20537, /*Wall staircase*/ - PASSAGEWAY_20538, /*Wall staircase*/ - PASSAGEWAY_20539, /*Wall staircase*/ - STAIRS_17098, /*Floor staircase*/ - STAIRS_17099, /*Floor staircase*/ - STAIRS_18973, /*Floor staircase*/ - STAIRS_18974 /*Floor staircase*/ - ); - - static final Set WALL_TRAP_IDS = Sets.newHashSet( - WALL_20590, /*Wall spikes*/ - WALL_20592, /*Wall spikes*/ - WALL_20594, /*Wall spikes*/ - WALL_20596, /*Wall spikes*/ - WALL_20588, /*Wall spikes*/ - WALL_20613, /*Wall pusher*/ - WALL_20615, /*Wall pusher*/ - WALL_20616, /*Wall pusher*/ - WALL_20618, /*Wall pusher*/ - HANGING_LOG_20571, /*Hanging log*/ - HANGING_LOG_20572, /*Hanging log*/ - HANGING_LOG_20573, /*Hanging log*/ - HANGING_LOG_20574 /*Hanging log*/ - ); - - static final Set FLOOR_TRAP_IDS = Sets.newHashSet( - FLOOR_20583, /*Floor spikes*/ - FLOOR_20584, /*Floor spikes*/ - NULL_20575, /*Floor spikes (visible)*/ - FLOOR_20628, /*Trapdoor*/ - FLOOR_20634, /*Floor button*/ - FLOOR_20636 /*Floor button*/ - ); -} +/* + * Copyright (c) 2018, Shaun Dreclin + * 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.tarnslair; + +import com.google.common.collect.Sets; +import java.util.Set; +import static net.runelite.api.NullObjectID.NULL_20575; +import static net.runelite.api.ObjectID.FLOOR_20583; +import static net.runelite.api.ObjectID.FLOOR_20584; +import static net.runelite.api.ObjectID.FLOOR_20628; +import static net.runelite.api.ObjectID.FLOOR_20634; +import static net.runelite.api.ObjectID.FLOOR_20636; +import static net.runelite.api.ObjectID.HANGING_LOG_20571; +import static net.runelite.api.ObjectID.HANGING_LOG_20572; +import static net.runelite.api.ObjectID.HANGING_LOG_20573; +import static net.runelite.api.ObjectID.HANGING_LOG_20574; +import static net.runelite.api.ObjectID.PASSAGEWAY_15770; +import static net.runelite.api.ObjectID.PASSAGEWAY_15771; +import static net.runelite.api.ObjectID.PASSAGEWAY_15772; +import static net.runelite.api.ObjectID.PASSAGEWAY_15773; +import static net.runelite.api.ObjectID.PASSAGEWAY_15774; +import static net.runelite.api.ObjectID.PASSAGEWAY_16129; +import static net.runelite.api.ObjectID.PASSAGEWAY_16130; +import static net.runelite.api.ObjectID.PASSAGEWAY_16131; +import static net.runelite.api.ObjectID.PASSAGEWAY_16132; +import static net.runelite.api.ObjectID.PASSAGEWAY_16133; +import static net.runelite.api.ObjectID.PASSAGEWAY_16134; +import static net.runelite.api.ObjectID.PASSAGEWAY_18307; +import static net.runelite.api.ObjectID.PASSAGEWAY_18308; +import static net.runelite.api.ObjectID.PASSAGEWAY_18309; +import static net.runelite.api.ObjectID.PASSAGEWAY_18310; +import static net.runelite.api.ObjectID.PASSAGEWAY_18311; +import static net.runelite.api.ObjectID.PASSAGEWAY_20488; +import static net.runelite.api.ObjectID.PASSAGEWAY_20489; +import static net.runelite.api.ObjectID.PASSAGEWAY_20490; +import static net.runelite.api.ObjectID.PASSAGEWAY_20491; +import static net.runelite.api.ObjectID.PASSAGEWAY_20492; +import static net.runelite.api.ObjectID.PASSAGEWAY_20493; +import static net.runelite.api.ObjectID.PASSAGEWAY_20495; +import static net.runelite.api.ObjectID.PASSAGEWAY_20497; +import static net.runelite.api.ObjectID.PASSAGEWAY_20498; +import static net.runelite.api.ObjectID.PASSAGEWAY_20499; +import static net.runelite.api.ObjectID.PASSAGEWAY_20500; +import static net.runelite.api.ObjectID.PASSAGEWAY_20501; +import static net.runelite.api.ObjectID.PASSAGEWAY_20502; +import static net.runelite.api.ObjectID.PASSAGEWAY_20503; +import static net.runelite.api.ObjectID.PASSAGEWAY_20504; +import static net.runelite.api.ObjectID.PASSAGEWAY_20505; +import static net.runelite.api.ObjectID.PASSAGEWAY_20506; +import static net.runelite.api.ObjectID.PASSAGEWAY_20507; +import static net.runelite.api.ObjectID.PASSAGEWAY_20509; +import static net.runelite.api.ObjectID.PASSAGEWAY_20510; +import static net.runelite.api.ObjectID.PASSAGEWAY_20511; +import static net.runelite.api.ObjectID.PASSAGEWAY_20512; +import static net.runelite.api.ObjectID.PASSAGEWAY_20513; +import static net.runelite.api.ObjectID.PASSAGEWAY_20514; +import static net.runelite.api.ObjectID.PASSAGEWAY_20515; +import static net.runelite.api.ObjectID.PASSAGEWAY_20516; +import static net.runelite.api.ObjectID.PASSAGEWAY_20517; +import static net.runelite.api.ObjectID.PASSAGEWAY_20518; +import static net.runelite.api.ObjectID.PASSAGEWAY_20519; +import static net.runelite.api.ObjectID.PASSAGEWAY_20520; +import static net.runelite.api.ObjectID.PASSAGEWAY_20521; +import static net.runelite.api.ObjectID.PASSAGEWAY_20522; +import static net.runelite.api.ObjectID.PASSAGEWAY_20523; +import static net.runelite.api.ObjectID.PASSAGEWAY_20524; +import static net.runelite.api.ObjectID.PASSAGEWAY_20525; +import static net.runelite.api.ObjectID.PASSAGEWAY_20526; +import static net.runelite.api.ObjectID.PASSAGEWAY_20527; +import static net.runelite.api.ObjectID.PASSAGEWAY_20528; +import static net.runelite.api.ObjectID.PASSAGEWAY_20529; +import static net.runelite.api.ObjectID.PASSAGEWAY_20530; +import static net.runelite.api.ObjectID.PASSAGEWAY_20531; +import static net.runelite.api.ObjectID.PASSAGEWAY_20532; +import static net.runelite.api.ObjectID.PASSAGEWAY_20533; +import static net.runelite.api.ObjectID.PASSAGEWAY_20534; +import static net.runelite.api.ObjectID.PASSAGEWAY_20535; +import static net.runelite.api.ObjectID.PASSAGEWAY_20536; +import static net.runelite.api.ObjectID.PASSAGEWAY_20537; +import static net.runelite.api.ObjectID.PASSAGEWAY_20538; +import static net.runelite.api.ObjectID.PASSAGEWAY_20539; +import static net.runelite.api.ObjectID.STAIRS_17098; +import static net.runelite.api.ObjectID.STAIRS_17099; +import static net.runelite.api.ObjectID.STAIRS_18973; +import static net.runelite.api.ObjectID.STAIRS_18974; +import static net.runelite.api.ObjectID.WALL_20588; +import static net.runelite.api.ObjectID.WALL_20590; +import static net.runelite.api.ObjectID.WALL_20592; +import static net.runelite.api.ObjectID.WALL_20594; +import static net.runelite.api.ObjectID.WALL_20596; +import static net.runelite.api.ObjectID.WALL_20613; +import static net.runelite.api.ObjectID.WALL_20615; +import static net.runelite.api.ObjectID.WALL_20616; +import static net.runelite.api.ObjectID.WALL_20618; + +class Obstacles +{ + static final Set STAIRCASE_IDS = Sets.newHashSet( + PASSAGEWAY_15770, /*Wall staircase*/ + PASSAGEWAY_15771, /*Wall staircase*/ + PASSAGEWAY_15772, /*Wall staircase*/ + PASSAGEWAY_15773, /*Wall staircase*/ + PASSAGEWAY_15774, /*Wall staircase*/ + PASSAGEWAY_16129, /*Wall staircase*/ + PASSAGEWAY_16130, /*Wall staircase*/ + PASSAGEWAY_16131, /*Wall staircase*/ + PASSAGEWAY_16132, /*Wall staircase*/ + PASSAGEWAY_16133, /*Wall staircase*/ + PASSAGEWAY_16134, /*Wall staircase*/ + PASSAGEWAY_18307, /*Wall staircase*/ + PASSAGEWAY_18308, /*Wall staircase*/ + PASSAGEWAY_18309, /*Wall staircase*/ + PASSAGEWAY_18310, /*Wall staircase*/ + PASSAGEWAY_18311, /*Wall staircase*/ + PASSAGEWAY_20488, /*Wall staircase*/ + PASSAGEWAY_20489, /*Wall staircase*/ + PASSAGEWAY_20490, /*Wall staircase*/ + PASSAGEWAY_20491, /*Wall staircase*/ + PASSAGEWAY_20492, /*Wall staircase*/ + PASSAGEWAY_20493, /*Wall staircase*/ + PASSAGEWAY_20495, /*Wall staircase*/ + PASSAGEWAY_20497, /*Wall staircase*/ + PASSAGEWAY_20498, /*Wall staircase*/ + PASSAGEWAY_20499, /*Wall staircase*/ + PASSAGEWAY_20500, /*Wall staircase*/ + PASSAGEWAY_20501, /*Wall staircase*/ + PASSAGEWAY_20502, /*Wall staircase*/ + PASSAGEWAY_20503, /*Wall staircase*/ + PASSAGEWAY_20504, /*Wall staircase*/ + PASSAGEWAY_20505, /*Wall staircase*/ + PASSAGEWAY_20506, /*Wall staircase*/ + PASSAGEWAY_20506, /*Wall staircase*/ + PASSAGEWAY_20507, /*Wall staircase*/ + PASSAGEWAY_20509, /*Wall staircase*/ + PASSAGEWAY_20510, /*Wall staircase*/ + PASSAGEWAY_20511, /*Wall staircase*/ + PASSAGEWAY_20512, /*Wall staircase*/ + PASSAGEWAY_20513, /*Wall staircase*/ + PASSAGEWAY_20514, /*Wall staircase*/ + PASSAGEWAY_20515, /*Wall staircase*/ + PASSAGEWAY_20516, /*Wall staircase*/ + PASSAGEWAY_20517, /*Wall staircase*/ + PASSAGEWAY_20518, /*Wall staircase*/ + PASSAGEWAY_20519, /*Wall staircase*/ + PASSAGEWAY_20520, /*Wall staircase*/ + PASSAGEWAY_20521, /*Wall staircase*/ + PASSAGEWAY_20522, /*Wall staircase*/ + PASSAGEWAY_20523, /*Wall staircase*/ + PASSAGEWAY_20524, /*Wall staircase*/ + PASSAGEWAY_20525, /*Wall staircase*/ + PASSAGEWAY_20526, /*Wall staircase*/ + PASSAGEWAY_20527, /*Wall staircase*/ + PASSAGEWAY_20528, /*Wall staircase*/ + PASSAGEWAY_20529, /*Wall staircase*/ + PASSAGEWAY_20530, /*Wall staircase*/ + PASSAGEWAY_20531, /*Wall staircase*/ + PASSAGEWAY_20532, /*Wall staircase*/ + PASSAGEWAY_20533, /*Wall staircase*/ + PASSAGEWAY_20534, /*Wall staircase*/ + PASSAGEWAY_20535, /*Wall staircase*/ + PASSAGEWAY_20536, /*Wall staircase*/ + PASSAGEWAY_20537, /*Wall staircase*/ + PASSAGEWAY_20538, /*Wall staircase*/ + PASSAGEWAY_20539, /*Wall staircase*/ + STAIRS_17098, /*Floor staircase*/ + STAIRS_17099, /*Floor staircase*/ + STAIRS_18973, /*Floor staircase*/ + STAIRS_18974 /*Floor staircase*/ + ); + + static final Set WALL_TRAP_IDS = Sets.newHashSet( + WALL_20590, /*Wall spikes*/ + WALL_20592, /*Wall spikes*/ + WALL_20594, /*Wall spikes*/ + WALL_20596, /*Wall spikes*/ + WALL_20588, /*Wall spikes*/ + WALL_20613, /*Wall pusher*/ + WALL_20615, /*Wall pusher*/ + WALL_20616, /*Wall pusher*/ + WALL_20618, /*Wall pusher*/ + HANGING_LOG_20571, /*Hanging log*/ + HANGING_LOG_20572, /*Hanging log*/ + HANGING_LOG_20573, /*Hanging log*/ + HANGING_LOG_20574 /*Hanging log*/ + ); + + static final Set FLOOR_TRAP_IDS = Sets.newHashSet( + FLOOR_20583, /*Floor spikes*/ + FLOOR_20584, /*Floor spikes*/ + NULL_20575, /*Floor spikes (visible)*/ + FLOOR_20628, /*Trapdoor*/ + FLOOR_20634, /*Floor button*/ + FLOOR_20636 /*Floor button*/ + ); +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/teamcapes/TeamCapesPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/teamcapes/TeamCapesPlugin.java index 103129d64f..45a7b10a87 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/teamcapes/TeamCapesPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/teamcapes/TeamCapesPlugin.java @@ -1,126 +1,126 @@ -/* - * Copyright (c) 2017, Devin French - * 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.teamcapes; - -import com.google.inject.Provides; -import java.time.temporal.ChronoUnit; -import java.util.Comparator; -import java.util.HashMap; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Map; -import java.util.stream.Collectors; -import javax.inject.Inject; -import net.runelite.api.Client; -import net.runelite.api.GameState; -import net.runelite.api.Player; -import net.runelite.client.config.ConfigManager; -import net.runelite.client.plugins.Plugin; -import net.runelite.client.plugins.PluginDescriptor; -import net.runelite.client.task.Schedule; -import net.runelite.client.ui.overlay.OverlayManager; - -@PluginDescriptor( - name = "Team Capes", - description = "Show the different team capes in your area and the amount of each", - tags = {"overlay", "players"}, - enabledByDefault = false -) -public class TeamCapesPlugin extends Plugin -{ - @Inject - private Client client; - - @Inject - private OverlayManager overlayManager; - - @Inject - private TeamCapesOverlay overlay; - - // Hashmap of team capes: Key is the teamCape #, Value is the count of teamcapes in the area. - private Map teams = new HashMap<>(); - - @Provides - TeamCapesConfig provideConfig(ConfigManager configManager) - { - return configManager.getConfig(TeamCapesConfig.class); - } - - @Override - protected void startUp() throws Exception - { - overlayManager.add(overlay); - } - - @Override - protected void shutDown() throws Exception - { - overlayManager.remove(overlay); - teams.clear(); - } - - @Schedule( - period = 1800, - unit = ChronoUnit.MILLIS - ) - public void update() - { - if (client.getGameState() != GameState.LOGGED_IN) - { - return; - } - List players = client.getPlayers(); - teams.clear(); - for (Player player : players) - { - int team = player.getTeam(); - if (team > 0) - { - if (teams.containsKey(team)) - { - teams.put(team, teams.get(team) + 1); - } - else - { - teams.put(team, 1); - } - } - } - - // Sort teams by value in descending order and then by key in ascending order, limited to 5 entries - teams = teams.entrySet().stream() - .sorted( - Comparator.comparing(Map.Entry::getValue, Comparator.reverseOrder()) - .thenComparingInt(Map.Entry::getKey) - ) - .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, (e1, e2) -> e1, LinkedHashMap::new)); - } - - public Map getTeams() - { - return teams; - } - -} +/* + * Copyright (c) 2017, Devin French + * 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.teamcapes; + +import com.google.inject.Provides; +import java.time.temporal.ChronoUnit; +import java.util.Comparator; +import java.util.HashMap; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; +import javax.inject.Inject; +import net.runelite.api.Client; +import net.runelite.api.GameState; +import net.runelite.api.Player; +import net.runelite.client.config.ConfigManager; +import net.runelite.client.plugins.Plugin; +import net.runelite.client.plugins.PluginDescriptor; +import net.runelite.client.task.Schedule; +import net.runelite.client.ui.overlay.OverlayManager; + +@PluginDescriptor( + name = "Team Capes", + description = "Show the different team capes in your area and the amount of each", + tags = {"overlay", "players"}, + enabledByDefault = false +) +public class TeamCapesPlugin extends Plugin +{ + @Inject + private Client client; + + @Inject + private OverlayManager overlayManager; + + @Inject + private TeamCapesOverlay overlay; + + // Hashmap of team capes: Key is the teamCape #, Value is the count of teamcapes in the area. + private Map teams = new HashMap<>(); + + @Provides + TeamCapesConfig provideConfig(ConfigManager configManager) + { + return configManager.getConfig(TeamCapesConfig.class); + } + + @Override + protected void startUp() throws Exception + { + overlayManager.add(overlay); + } + + @Override + protected void shutDown() throws Exception + { + overlayManager.remove(overlay); + teams.clear(); + } + + @Schedule( + period = 1800, + unit = ChronoUnit.MILLIS + ) + public void update() + { + if (client.getGameState() != GameState.LOGGED_IN) + { + return; + } + List players = client.getPlayers(); + teams.clear(); + for (Player player : players) + { + int team = player.getTeam(); + if (team > 0) + { + if (teams.containsKey(team)) + { + teams.put(team, teams.get(team) + 1); + } + else + { + teams.put(team, 1); + } + } + } + + // Sort teams by value in descending order and then by key in ascending order, limited to 5 entries + teams = teams.entrySet().stream() + .sorted( + Comparator.comparing(Map.Entry::getValue, Comparator.reverseOrder()) + .thenComparingInt(Map.Entry::getKey) + ) + .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, (e1, e2) -> e1, LinkedHashMap::new)); + } + + public Map getTeams() + { + return teams; + } + +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/tickcounter/TickCounterOverlay.java b/runelite-client/src/main/java/net/runelite/client/plugins/tickcounter/TickCounterOverlay.java index de80c99739..d33084be37 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/tickcounter/TickCounterOverlay.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/tickcounter/TickCounterOverlay.java @@ -3,7 +3,6 @@ package net.runelite.client.plugins.tickcounter; import java.awt.Dimension; import java.awt.Graphics2D; import java.util.ArrayList; -import java.util.Comparator; import java.util.List; import java.util.Map.Entry; import javax.inject.Inject; diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/timers/TimersPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/timers/TimersPlugin.java index 889feb3bba..2d1c8b16e2 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/timers/TimersPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/timers/TimersPlugin.java @@ -74,7 +74,41 @@ import net.runelite.client.game.SpriteManager; import net.runelite.client.plugins.Plugin; import net.runelite.client.plugins.PluginDescriptor; import static net.runelite.client.plugins.timers.GameIndicator.VENGEANCE_ACTIVE; -import static net.runelite.client.plugins.timers.GameTimer.*; +import static net.runelite.client.plugins.timers.GameTimer.ABYSSAL_SIRE_STUN; +import static net.runelite.client.plugins.timers.GameTimer.ANTIFIRE; +import static net.runelite.client.plugins.timers.GameTimer.ANTIPOISON; +import static net.runelite.client.plugins.timers.GameTimer.ANTIVENOM; +import static net.runelite.client.plugins.timers.GameTimer.BIND; +import static net.runelite.client.plugins.timers.GameTimer.CANNON; +import static net.runelite.client.plugins.timers.GameTimer.CHARGE; +import static net.runelite.client.plugins.timers.GameTimer.DMM_FULLTB; +import static net.runelite.client.plugins.timers.GameTimer.DMM_HALFTB; +import static net.runelite.client.plugins.timers.GameTimer.ENTANGLE; +import static net.runelite.client.plugins.timers.GameTimer.EXANTIFIRE; +import static net.runelite.client.plugins.timers.GameTimer.EXSUPERANTIFIRE; +import static net.runelite.client.plugins.timers.GameTimer.FULLTB; +import static net.runelite.client.plugins.timers.GameTimer.GOD_WARS_ALTAR; +import static net.runelite.client.plugins.timers.GameTimer.HALFBIND; +import static net.runelite.client.plugins.timers.GameTimer.HALFENTANGLE; +import static net.runelite.client.plugins.timers.GameTimer.HALFSNARE; +import static net.runelite.client.plugins.timers.GameTimer.HALFTB; +import static net.runelite.client.plugins.timers.GameTimer.HOME_TELEPORT; +import static net.runelite.client.plugins.timers.GameTimer.ICEBARRAGE; +import static net.runelite.client.plugins.timers.GameTimer.ICEBLITZ; +import static net.runelite.client.plugins.timers.GameTimer.ICEBURST; +import static net.runelite.client.plugins.timers.GameTimer.ICERUSH; +import static net.runelite.client.plugins.timers.GameTimer.IMBUEDHEART; +import static net.runelite.client.plugins.timers.GameTimer.MAGICIMBUE; +import static net.runelite.client.plugins.timers.GameTimer.MINIGAME_TELEPORT; +import static net.runelite.client.plugins.timers.GameTimer.OVERLOAD; +import static net.runelite.client.plugins.timers.GameTimer.OVERLOAD_RAID; +import static net.runelite.client.plugins.timers.GameTimer.PRAYER_ENHANCE; +import static net.runelite.client.plugins.timers.GameTimer.SKULL; +import static net.runelite.client.plugins.timers.GameTimer.SNARE; +import static net.runelite.client.plugins.timers.GameTimer.STAFF_OF_THE_DEAD; +import static net.runelite.client.plugins.timers.GameTimer.STAMINA; +import static net.runelite.client.plugins.timers.GameTimer.SUPERANTIFIRE; +import static net.runelite.client.plugins.timers.GameTimer.VENGEANCE; import net.runelite.client.ui.overlay.infobox.InfoBoxManager; @PluginDescriptor( diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/timetracking/OverviewTabPanel.java b/runelite-client/src/main/java/net/runelite/client/plugins/timetracking/OverviewTabPanel.java index f736c49fef..633d548750 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/timetracking/OverviewTabPanel.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/timetracking/OverviewTabPanel.java @@ -1,150 +1,150 @@ -/* - * Copyright (c) 2018, Daniel Teo - * 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.timetracking; - -import com.google.common.collect.ImmutableMap; -import java.awt.Color; -import java.awt.GridLayout; -import java.time.Instant; -import java.util.Map; -import java.util.function.Function; -import java.util.stream.Stream; -import net.runelite.client.game.ItemManager; -import net.runelite.client.plugins.timetracking.clocks.ClockManager; -import net.runelite.client.plugins.timetracking.farming.FarmingTracker; -import net.runelite.client.plugins.timetracking.hunter.BirdHouseTracker; -import net.runelite.client.ui.ColorScheme; - -class OverviewTabPanel extends TabContentPanel -{ - private final TimeTrackingConfig config; - private final FarmingTracker farmingTracker; - private final BirdHouseTracker birdHouseTracker; - private final ClockManager clockManager; - - private final OverviewItemPanel timerOverview; - private final OverviewItemPanel stopwatchOverview; - private final Map farmingOverviews; - private final OverviewItemPanel birdHouseOverview; - - OverviewTabPanel(ItemManager itemManager, TimeTrackingConfig config, TimeTrackingPanel pluginPanel, - FarmingTracker farmingTracker, BirdHouseTracker birdHouseTracker, ClockManager clockManager) - { - this.config = config; - this.farmingTracker = farmingTracker; - this.birdHouseTracker = birdHouseTracker; - this.clockManager = clockManager; - - setLayout(new GridLayout(0, 1, 0, 8)); - setBackground(ColorScheme.DARK_GRAY_COLOR); - - timerOverview = new OverviewItemPanel(itemManager, pluginPanel, Tab.CLOCK, "Timers"); - add(timerOverview); - - stopwatchOverview = new OverviewItemPanel(itemManager, pluginPanel, Tab.CLOCK, "Stopwatches"); - add(stopwatchOverview); - - birdHouseOverview = new OverviewItemPanel(itemManager, pluginPanel, Tab.BIRD_HOUSE, "Bird Houses"); - add(birdHouseOverview); - - farmingOverviews = Stream.of(Tab.FARMING_TABS) - .filter(v -> v != Tab.OVERVIEW) - .collect(ImmutableMap.toImmutableMap( - Function.identity(), - t -> - { - OverviewItemPanel p = new OverviewItemPanel(itemManager, pluginPanel, t, t.getName()); - add(p); - return p; - } - )); - } - - @Override - public int getUpdateInterval() - { - return 50; // 10 seconds - } - - @Override - public void update() - { - final long timers = clockManager.getActiveTimerCount(); - final long stopwatches = clockManager.getActiveStopwatchCount(); - - if (timers == 0) - { - timerOverview.updateStatus("No active timers", Color.GRAY); - } - else - { - timerOverview.updateStatus(timers + " active timer" + (timers == 1 ? "" : "s"), ColorScheme.PROGRESS_COMPLETE_COLOR); - } - - if (stopwatches == 0) - { - stopwatchOverview.updateStatus("No active stopwatches", Color.GRAY); - } - else - { - stopwatchOverview.updateStatus(stopwatches + " active stopwatch" + (stopwatches == 1 ? "" : "es"), ColorScheme.PROGRESS_COMPLETE_COLOR); - } - - farmingOverviews.forEach((patchType, panel) -> - updateItemPanel(panel, farmingTracker.getSummary(patchType), farmingTracker.getCompletionTime(patchType))); - - updateItemPanel(birdHouseOverview, birdHouseTracker.getSummary(), birdHouseTracker.getCompletionTime()); - } - - private void updateItemPanel(OverviewItemPanel panel, SummaryState summary, long completionTime) - { - switch (summary) - { - case COMPLETED: - case IN_PROGRESS: - { - long duration = completionTime - Instant.now().getEpochSecond(); - - if (duration <= 0) - { - panel.updateStatus("Ready", ColorScheme.PROGRESS_COMPLETE_COLOR); - } - else - { - panel.updateStatus("Ready " + getFormattedEstimate(duration, config.estimateRelative()), Color.GRAY); - } - - break; - } - case EMPTY: - panel.updateStatus("Empty", Color.GRAY); - break; - case UNKNOWN: - default: - panel.updateStatus("Unknown", Color.GRAY); - break; - } - } -} +/* + * Copyright (c) 2018, Daniel Teo + * 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.timetracking; + +import com.google.common.collect.ImmutableMap; +import java.awt.Color; +import java.awt.GridLayout; +import java.time.Instant; +import java.util.Map; +import java.util.function.Function; +import java.util.stream.Stream; +import net.runelite.client.game.ItemManager; +import net.runelite.client.plugins.timetracking.clocks.ClockManager; +import net.runelite.client.plugins.timetracking.farming.FarmingTracker; +import net.runelite.client.plugins.timetracking.hunter.BirdHouseTracker; +import net.runelite.client.ui.ColorScheme; + +class OverviewTabPanel extends TabContentPanel +{ + private final TimeTrackingConfig config; + private final FarmingTracker farmingTracker; + private final BirdHouseTracker birdHouseTracker; + private final ClockManager clockManager; + + private final OverviewItemPanel timerOverview; + private final OverviewItemPanel stopwatchOverview; + private final Map farmingOverviews; + private final OverviewItemPanel birdHouseOverview; + + OverviewTabPanel(ItemManager itemManager, TimeTrackingConfig config, TimeTrackingPanel pluginPanel, + FarmingTracker farmingTracker, BirdHouseTracker birdHouseTracker, ClockManager clockManager) + { + this.config = config; + this.farmingTracker = farmingTracker; + this.birdHouseTracker = birdHouseTracker; + this.clockManager = clockManager; + + setLayout(new GridLayout(0, 1, 0, 8)); + setBackground(ColorScheme.DARK_GRAY_COLOR); + + timerOverview = new OverviewItemPanel(itemManager, pluginPanel, Tab.CLOCK, "Timers"); + add(timerOverview); + + stopwatchOverview = new OverviewItemPanel(itemManager, pluginPanel, Tab.CLOCK, "Stopwatches"); + add(stopwatchOverview); + + birdHouseOverview = new OverviewItemPanel(itemManager, pluginPanel, Tab.BIRD_HOUSE, "Bird Houses"); + add(birdHouseOverview); + + farmingOverviews = Stream.of(Tab.FARMING_TABS) + .filter(v -> v != Tab.OVERVIEW) + .collect(ImmutableMap.toImmutableMap( + Function.identity(), + t -> + { + OverviewItemPanel p = new OverviewItemPanel(itemManager, pluginPanel, t, t.getName()); + add(p); + return p; + } + )); + } + + @Override + public int getUpdateInterval() + { + return 50; // 10 seconds + } + + @Override + public void update() + { + final long timers = clockManager.getActiveTimerCount(); + final long stopwatches = clockManager.getActiveStopwatchCount(); + + if (timers == 0) + { + timerOverview.updateStatus("No active timers", Color.GRAY); + } + else + { + timerOverview.updateStatus(timers + " active timer" + (timers == 1 ? "" : "s"), ColorScheme.PROGRESS_COMPLETE_COLOR); + } + + if (stopwatches == 0) + { + stopwatchOverview.updateStatus("No active stopwatches", Color.GRAY); + } + else + { + stopwatchOverview.updateStatus(stopwatches + " active stopwatch" + (stopwatches == 1 ? "" : "es"), ColorScheme.PROGRESS_COMPLETE_COLOR); + } + + farmingOverviews.forEach((patchType, panel) -> + updateItemPanel(panel, farmingTracker.getSummary(patchType), farmingTracker.getCompletionTime(patchType))); + + updateItemPanel(birdHouseOverview, birdHouseTracker.getSummary(), birdHouseTracker.getCompletionTime()); + } + + private void updateItemPanel(OverviewItemPanel panel, SummaryState summary, long completionTime) + { + switch (summary) + { + case COMPLETED: + case IN_PROGRESS: + { + long duration = completionTime - Instant.now().getEpochSecond(); + + if (duration <= 0) + { + panel.updateStatus("Ready", ColorScheme.PROGRESS_COMPLETE_COLOR); + } + else + { + panel.updateStatus("Ready " + getFormattedEstimate(duration, config.estimateRelative()), Color.GRAY); + } + + break; + } + case EMPTY: + panel.updateStatus("Empty", Color.GRAY); + break; + case UNKNOWN: + default: + panel.updateStatus("Unknown", Color.GRAY); + break; + } + } +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/timetracking/TimeTrackingPanel.java b/runelite-client/src/main/java/net/runelite/client/plugins/timetracking/TimeTrackingPanel.java index 6deb64e30c..54b863f4b0 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/timetracking/TimeTrackingPanel.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/timetracking/TimeTrackingPanel.java @@ -1,178 +1,178 @@ -/* - * Copyright (c) 2018 Abex - * Copyright (c) 2018, Psikoi - * 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.timetracking; - -import java.awt.BorderLayout; -import java.awt.Dimension; -import java.awt.GridLayout; -import java.awt.Image; -import java.awt.image.BufferedImage; -import java.util.HashMap; -import java.util.Map; -import javax.annotation.Nullable; -import javax.swing.ImageIcon; -import javax.swing.JPanel; -import javax.swing.JScrollPane; -import javax.swing.SwingUtilities; -import javax.swing.border.EmptyBorder; -import net.runelite.client.game.AsyncBufferedImage; -import net.runelite.client.game.ItemManager; -import net.runelite.client.plugins.timetracking.clocks.ClockManager; -import net.runelite.client.plugins.timetracking.farming.FarmingTracker; -import net.runelite.client.plugins.timetracking.hunter.BirdHouseTracker; -import net.runelite.client.ui.ColorScheme; -import net.runelite.client.ui.PluginPanel; -import net.runelite.client.ui.components.materialtabs.MaterialTab; -import net.runelite.client.ui.components.materialtabs.MaterialTabGroup; - -class TimeTrackingPanel extends PluginPanel -{ - private final ItemManager itemManager; - private final TimeTrackingConfig config; - - /* This is the panel the tabs' respective panels will be displayed on. */ - private final JPanel display = new JPanel(); - private final Map uiTabs = new HashMap<>(); - private final MaterialTabGroup tabGroup = new MaterialTabGroup(display); - - private boolean active; - - @Nullable - private TabContentPanel activeTabPanel = null; - - TimeTrackingPanel(ItemManager itemManager, TimeTrackingConfig config, - FarmingTracker farmingTracker, BirdHouseTracker birdHouseTracker, ClockManager clockManager) - { - super(false); - - this.itemManager = itemManager; - this.config = config; - - setLayout(new BorderLayout()); - setBackground(ColorScheme.DARK_GRAY_COLOR); - - display.setBorder(new EmptyBorder(10, 10, 8, 10)); - - tabGroup.setLayout(new GridLayout(0, 6, 7, 7)); - tabGroup.setBorder(new EmptyBorder(10, 10, 0, 10)); - - add(tabGroup, BorderLayout.NORTH); - add(display, BorderLayout.CENTER); - - addTab(Tab.OVERVIEW, new OverviewTabPanel(itemManager, config, this, farmingTracker, birdHouseTracker, clockManager)); - addTab(Tab.CLOCK, clockManager.getClockTabPanel()); - addTab(Tab.BIRD_HOUSE, birdHouseTracker.createBirdHouseTabPanel()); - - for (Tab tab : Tab.FARMING_TABS) - { - addTab(tab, farmingTracker.createTabPanel(tab)); - } - } - - private void addTab(Tab tab, TabContentPanel tabContentPanel) - { - JPanel wrapped = new JPanel(new BorderLayout()); - wrapped.add(tabContentPanel, BorderLayout.NORTH); - wrapped.setBackground(ColorScheme.DARK_GRAY_COLOR); - - JScrollPane scroller = new JScrollPane(wrapped); - scroller.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_NEVER); - scroller.getVerticalScrollBar().setPreferredSize(new Dimension(16, 0)); - scroller.getVerticalScrollBar().setBorder(new EmptyBorder(0, 9, 0, 0)); - scroller.setBackground(ColorScheme.DARK_GRAY_COLOR); - - // Use a placeholder icon until the async image gets loaded - MaterialTab materialTab = new MaterialTab(new ImageIcon(), tabGroup, scroller); - materialTab.setPreferredSize(new Dimension(30, 27)); - materialTab.setName(tab.getName()); - materialTab.setToolTipText(tab.getName()); - - AsyncBufferedImage icon = itemManager.getImage(tab.getItemID()); - Runnable resize = () -> - { - BufferedImage subIcon = icon.getSubimage(0, 0, 32, 32); - materialTab.setIcon(new ImageIcon(subIcon.getScaledInstance(24, 24, Image.SCALE_SMOOTH))); - }; - icon.onChanged(resize); - resize.run(); - - materialTab.setOnSelectEvent(() -> - { - config.setActiveTab(tab); - activeTabPanel = tabContentPanel; - - tabContentPanel.update(); - return true; - }); - - uiTabs.put(tab, materialTab); - tabGroup.addTab(materialTab); - - if (config.activeTab() == tab) - { - tabGroup.select(materialTab); - } - } - - void switchTab(Tab tab) - { - tabGroup.select(uiTabs.get(tab)); - } - - /** - * Gets the update interval of the active tab panel, in units of 200 milliseconds. - */ - int getUpdateInterval() - { - return activeTabPanel == null ? Integer.MAX_VALUE : activeTabPanel.getUpdateInterval(); - } - - /** - * Updates the active tab panel, if this plugin panel is displayed. - */ - void update() - { - if (!active || activeTabPanel == null) - { - return; - } - - SwingUtilities.invokeLater(activeTabPanel::update); - } - - @Override - public void onActivate() - { - active = true; - update(); - } - - @Override - public void onDeactivate() - { - active = false; - } -} +/* + * Copyright (c) 2018 Abex + * Copyright (c) 2018, Psikoi + * 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.timetracking; + +import java.awt.BorderLayout; +import java.awt.Dimension; +import java.awt.GridLayout; +import java.awt.Image; +import java.awt.image.BufferedImage; +import java.util.HashMap; +import java.util.Map; +import javax.annotation.Nullable; +import javax.swing.ImageIcon; +import javax.swing.JPanel; +import javax.swing.JScrollPane; +import javax.swing.SwingUtilities; +import javax.swing.border.EmptyBorder; +import net.runelite.client.game.AsyncBufferedImage; +import net.runelite.client.game.ItemManager; +import net.runelite.client.plugins.timetracking.clocks.ClockManager; +import net.runelite.client.plugins.timetracking.farming.FarmingTracker; +import net.runelite.client.plugins.timetracking.hunter.BirdHouseTracker; +import net.runelite.client.ui.ColorScheme; +import net.runelite.client.ui.PluginPanel; +import net.runelite.client.ui.components.materialtabs.MaterialTab; +import net.runelite.client.ui.components.materialtabs.MaterialTabGroup; + +class TimeTrackingPanel extends PluginPanel +{ + private final ItemManager itemManager; + private final TimeTrackingConfig config; + + /* This is the panel the tabs' respective panels will be displayed on. */ + private final JPanel display = new JPanel(); + private final Map uiTabs = new HashMap<>(); + private final MaterialTabGroup tabGroup = new MaterialTabGroup(display); + + private boolean active; + + @Nullable + private TabContentPanel activeTabPanel = null; + + TimeTrackingPanel(ItemManager itemManager, TimeTrackingConfig config, + FarmingTracker farmingTracker, BirdHouseTracker birdHouseTracker, ClockManager clockManager) + { + super(false); + + this.itemManager = itemManager; + this.config = config; + + setLayout(new BorderLayout()); + setBackground(ColorScheme.DARK_GRAY_COLOR); + + display.setBorder(new EmptyBorder(10, 10, 8, 10)); + + tabGroup.setLayout(new GridLayout(0, 6, 7, 7)); + tabGroup.setBorder(new EmptyBorder(10, 10, 0, 10)); + + add(tabGroup, BorderLayout.NORTH); + add(display, BorderLayout.CENTER); + + addTab(Tab.OVERVIEW, new OverviewTabPanel(itemManager, config, this, farmingTracker, birdHouseTracker, clockManager)); + addTab(Tab.CLOCK, clockManager.getClockTabPanel()); + addTab(Tab.BIRD_HOUSE, birdHouseTracker.createBirdHouseTabPanel()); + + for (Tab tab : Tab.FARMING_TABS) + { + addTab(tab, farmingTracker.createTabPanel(tab)); + } + } + + private void addTab(Tab tab, TabContentPanel tabContentPanel) + { + JPanel wrapped = new JPanel(new BorderLayout()); + wrapped.add(tabContentPanel, BorderLayout.NORTH); + wrapped.setBackground(ColorScheme.DARK_GRAY_COLOR); + + JScrollPane scroller = new JScrollPane(wrapped); + scroller.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_NEVER); + scroller.getVerticalScrollBar().setPreferredSize(new Dimension(16, 0)); + scroller.getVerticalScrollBar().setBorder(new EmptyBorder(0, 9, 0, 0)); + scroller.setBackground(ColorScheme.DARK_GRAY_COLOR); + + // Use a placeholder icon until the async image gets loaded + MaterialTab materialTab = new MaterialTab(new ImageIcon(), tabGroup, scroller); + materialTab.setPreferredSize(new Dimension(30, 27)); + materialTab.setName(tab.getName()); + materialTab.setToolTipText(tab.getName()); + + AsyncBufferedImage icon = itemManager.getImage(tab.getItemID()); + Runnable resize = () -> + { + BufferedImage subIcon = icon.getSubimage(0, 0, 32, 32); + materialTab.setIcon(new ImageIcon(subIcon.getScaledInstance(24, 24, Image.SCALE_SMOOTH))); + }; + icon.onChanged(resize); + resize.run(); + + materialTab.setOnSelectEvent(() -> + { + config.setActiveTab(tab); + activeTabPanel = tabContentPanel; + + tabContentPanel.update(); + return true; + }); + + uiTabs.put(tab, materialTab); + tabGroup.addTab(materialTab); + + if (config.activeTab() == tab) + { + tabGroup.select(materialTab); + } + } + + void switchTab(Tab tab) + { + tabGroup.select(uiTabs.get(tab)); + } + + /** + * Gets the update interval of the active tab panel, in units of 200 milliseconds. + */ + int getUpdateInterval() + { + return activeTabPanel == null ? Integer.MAX_VALUE : activeTabPanel.getUpdateInterval(); + } + + /** + * Updates the active tab panel, if this plugin panel is displayed. + */ + void update() + { + if (!active || activeTabPanel == null) + { + return; + } + + SwingUtilities.invokeLater(activeTabPanel::update); + } + + @Override + public void onActivate() + { + active = true; + update(); + } + + @Override + public void onDeactivate() + { + active = false; + } +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/timetracking/farming/FarmingTracker.java b/runelite-client/src/main/java/net/runelite/client/plugins/timetracking/farming/FarmingTracker.java index aa4027b98e..3d6d926126 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/timetracking/farming/FarmingTracker.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/timetracking/farming/FarmingTracker.java @@ -1,309 +1,309 @@ -/* - * Copyright (c) 2018 Abex - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package net.runelite.client.plugins.timetracking.farming; - -import com.google.inject.Inject; -import com.google.inject.Singleton; -import java.time.Instant; -import java.util.EnumMap; -import java.util.Map; -import java.util.Set; -import javax.annotation.Nullable; -import net.runelite.api.Client; -import net.runelite.api.Varbits; -import net.runelite.api.coords.WorldPoint; -import net.runelite.api.vars.Autoweed; -import net.runelite.client.config.ConfigManager; -import net.runelite.client.game.ItemManager; -import net.runelite.client.plugins.timetracking.SummaryState; -import net.runelite.client.plugins.timetracking.Tab; -import net.runelite.client.plugins.timetracking.TimeTrackingConfig; - -@Singleton -public class FarmingTracker -{ - private final Client client; - private final ItemManager itemManager; - private final ConfigManager configManager; - private final TimeTrackingConfig config; - private final FarmingWorld farmingWorld; - - private final Map summaries = new EnumMap<>(Tab.class); - - /** - * The time at which all patches of a particular type will be ready to be harvested, - * or {@code -1} if we have no data about any patch of the given type. - */ - private final Map completionTimes = new EnumMap<>(Tab.class); - - @Inject - private FarmingTracker(Client client, ItemManager itemManager, ConfigManager configManager, - TimeTrackingConfig config, FarmingWorld farmingWorld) - { - this.client = client; - this.itemManager = itemManager; - this.configManager = configManager; - this.config = config; - this.farmingWorld = farmingWorld; - } - - - public FarmingTabPanel createTabPanel(Tab tab) - { - return new FarmingTabPanel(this, itemManager, config, farmingWorld.getTabs().get(tab)); - } - - /** - * Updates tracker data for the current region. Returns true if any data was changed. - */ - public boolean updateData(WorldPoint location) - { - boolean changed = false; - - { - String group = TimeTrackingConfig.CONFIG_GROUP + "." + client.getUsername(); - String autoweed = Integer.toString(client.getVar(Varbits.AUTOWEED)); - if (!autoweed.equals(configManager.getConfiguration(group, TimeTrackingConfig.AUTOWEED))) - { - configManager.setConfiguration(group, TimeTrackingConfig.AUTOWEED, autoweed); - changed = true; - } - } - - FarmingRegion region = farmingWorld.getRegions().get(location.getRegionID()); - if (region != null && region.isInBounds(location)) - { - // Write config with new varbits - // timetracking...=: - String group = TimeTrackingConfig.CONFIG_GROUP + "." + client.getUsername() + "." + region.getRegionID(); - long unixNow = Instant.now().getEpochSecond(); - for (FarmingPatch patch : region.getPatches()) - { - // Write the config value if it doesn't match what is current, or it is more than 5 minutes old - Varbits varbit = patch.getVarbit(); - String key = Integer.toString(varbit.getId()); - String strVarbit = Integer.toString(client.getVar(varbit)); - String storedValue = configManager.getConfiguration(group, key); - - if (storedValue != null) - { - String[] parts = storedValue.split(":"); - if (parts.length == 2 && parts[0].equals(strVarbit)) - { - long unixTime = 0; - try - { - unixTime = Long.parseLong(parts[1]); - } - catch (NumberFormatException e) - { - // ignored - } - if (unixTime + (5 * 60) > unixNow && unixNow + 30 > unixTime) - { - continue; - } - } - } - - String value = strVarbit + ":" + unixNow; - configManager.setConfiguration(group, key, value); - changed = true; - } - } - - if (changed) - { - updateCompletionTime(); - } - - return changed; - } - - @Nullable - public PatchPrediction predictPatch(FarmingPatch patch) - { - long unixNow = Instant.now().getEpochSecond(); - - boolean autoweed; - { - String group = TimeTrackingConfig.CONFIG_GROUP + "." + client.getUsername(); - autoweed = Integer.toString(Autoweed.ON.ordinal()) - .equals(configManager.getConfiguration(group, TimeTrackingConfig.AUTOWEED)); - } - - String group = TimeTrackingConfig.CONFIG_GROUP + "." + client.getUsername() + "." + patch.getRegion().getRegionID(); - String key = Integer.toString(patch.getVarbit().getId()); - String storedValue = configManager.getConfiguration(group, key); - - if (storedValue == null) - { - return null; - } - - long unixTime = 0; - int value = 0; - { - String[] parts = storedValue.split(":"); - if (parts.length == 2) - { - try - { - value = Integer.parseInt(parts[0]); - unixTime = Long.parseLong(parts[1]); - } - catch (NumberFormatException e) - { - } - } - } - - if (unixTime <= 0) - { - return null; - } - - PatchState state = patch.getImplementation().forVarbitValue(value); - - int stage = state.getStage(); - int stages = state.getStages(); - int tickrate = state.getTickRate() * 60; - - if (autoweed && state.getProduce() == Produce.WEEDS) - { - stage = 0; - stages = 1; - tickrate = 0; - } - - long doneEstimate = 0; - if (tickrate > 0) - { - long tickNow = (unixNow + (5 * 60)) / tickrate; - long tickTime = (unixTime + (5 * 60)) / tickrate; - int delta = (int) (tickNow - tickTime); - - doneEstimate = ((stages - 1 - stage) + tickTime) * tickrate + (5 * 60); - - stage += delta; - if (stage >= stages) - { - stage = stages - 1; - } - } - - return new PatchPrediction( - state.getProduce(), - state.getCropState(), - doneEstimate, - stage, - stages - ); - } - - public void loadCompletionTimes() - { - summaries.clear(); - completionTimes.clear(); - updateCompletionTime(); - } - - public SummaryState getSummary(Tab patchType) - { - SummaryState summary = summaries.get(patchType); - return summary == null ? SummaryState.UNKNOWN : summary; - } - - /** - * Gets the overall completion time for the given patch type. - * - * @see #completionTimes - */ - public long getCompletionTime(Tab patchType) - { - Long completionTime = completionTimes.get(patchType); - return completionTime == null ? -1 : completionTime; - } - - /** - * Updates the overall completion time for the given patch type. - * - * @see #completionTimes - */ - private void updateCompletionTime() - { - for (Map.Entry> tab : farmingWorld.getTabs().entrySet()) - { - long maxCompletionTime = 0; - boolean allUnknown = true; - boolean allEmpty = true; - - for (FarmingPatch patch : tab.getValue()) - { - PatchPrediction prediction = predictPatch(patch); - if (prediction == null || prediction.getProduce().getItemID() < 0) - { - continue; // unknown state - } - - allUnknown = false; - - if (prediction.getProduce() != Produce.WEEDS && prediction.getProduce() != Produce.SCARECROW) - { - allEmpty = false; - - // update max duration if this patch takes longer to grow - maxCompletionTime = Math.max(maxCompletionTime, prediction.getDoneEstimate()); - } - } - - final SummaryState state; - final long completionTime; - - if (allUnknown) - { - state = SummaryState.UNKNOWN; - completionTime = -1L; - } - else if (allEmpty) - { - state = SummaryState.EMPTY; - completionTime = -1L; - } - else if (maxCompletionTime <= Instant.now().getEpochSecond()) - { - state = SummaryState.COMPLETED; - completionTime = 0; - } - else - { - state = SummaryState.IN_PROGRESS; - completionTime = maxCompletionTime; - } - summaries.put(tab.getKey(), state); - completionTimes.put(tab.getKey(), completionTime); - } - } -} +/* + * Copyright (c) 2018 Abex + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package net.runelite.client.plugins.timetracking.farming; + +import com.google.inject.Inject; +import com.google.inject.Singleton; +import java.time.Instant; +import java.util.EnumMap; +import java.util.Map; +import java.util.Set; +import javax.annotation.Nullable; +import net.runelite.api.Client; +import net.runelite.api.Varbits; +import net.runelite.api.coords.WorldPoint; +import net.runelite.api.vars.Autoweed; +import net.runelite.client.config.ConfigManager; +import net.runelite.client.game.ItemManager; +import net.runelite.client.plugins.timetracking.SummaryState; +import net.runelite.client.plugins.timetracking.Tab; +import net.runelite.client.plugins.timetracking.TimeTrackingConfig; + +@Singleton +public class FarmingTracker +{ + private final Client client; + private final ItemManager itemManager; + private final ConfigManager configManager; + private final TimeTrackingConfig config; + private final FarmingWorld farmingWorld; + + private final Map summaries = new EnumMap<>(Tab.class); + + /** + * The time at which all patches of a particular type will be ready to be harvested, + * or {@code -1} if we have no data about any patch of the given type. + */ + private final Map completionTimes = new EnumMap<>(Tab.class); + + @Inject + private FarmingTracker(Client client, ItemManager itemManager, ConfigManager configManager, + TimeTrackingConfig config, FarmingWorld farmingWorld) + { + this.client = client; + this.itemManager = itemManager; + this.configManager = configManager; + this.config = config; + this.farmingWorld = farmingWorld; + } + + + public FarmingTabPanel createTabPanel(Tab tab) + { + return new FarmingTabPanel(this, itemManager, config, farmingWorld.getTabs().get(tab)); + } + + /** + * Updates tracker data for the current region. Returns true if any data was changed. + */ + public boolean updateData(WorldPoint location) + { + boolean changed = false; + + { + String group = TimeTrackingConfig.CONFIG_GROUP + "." + client.getUsername(); + String autoweed = Integer.toString(client.getVar(Varbits.AUTOWEED)); + if (!autoweed.equals(configManager.getConfiguration(group, TimeTrackingConfig.AUTOWEED))) + { + configManager.setConfiguration(group, TimeTrackingConfig.AUTOWEED, autoweed); + changed = true; + } + } + + FarmingRegion region = farmingWorld.getRegions().get(location.getRegionID()); + if (region != null && region.isInBounds(location)) + { + // Write config with new varbits + // timetracking...=: + String group = TimeTrackingConfig.CONFIG_GROUP + "." + client.getUsername() + "." + region.getRegionID(); + long unixNow = Instant.now().getEpochSecond(); + for (FarmingPatch patch : region.getPatches()) + { + // Write the config value if it doesn't match what is current, or it is more than 5 minutes old + Varbits varbit = patch.getVarbit(); + String key = Integer.toString(varbit.getId()); + String strVarbit = Integer.toString(client.getVar(varbit)); + String storedValue = configManager.getConfiguration(group, key); + + if (storedValue != null) + { + String[] parts = storedValue.split(":"); + if (parts.length == 2 && parts[0].equals(strVarbit)) + { + long unixTime = 0; + try + { + unixTime = Long.parseLong(parts[1]); + } + catch (NumberFormatException e) + { + // ignored + } + if (unixTime + (5 * 60) > unixNow && unixNow + 30 > unixTime) + { + continue; + } + } + } + + String value = strVarbit + ":" + unixNow; + configManager.setConfiguration(group, key, value); + changed = true; + } + } + + if (changed) + { + updateCompletionTime(); + } + + return changed; + } + + @Nullable + public PatchPrediction predictPatch(FarmingPatch patch) + { + long unixNow = Instant.now().getEpochSecond(); + + boolean autoweed; + { + String group = TimeTrackingConfig.CONFIG_GROUP + "." + client.getUsername(); + autoweed = Integer.toString(Autoweed.ON.ordinal()) + .equals(configManager.getConfiguration(group, TimeTrackingConfig.AUTOWEED)); + } + + String group = TimeTrackingConfig.CONFIG_GROUP + "." + client.getUsername() + "." + patch.getRegion().getRegionID(); + String key = Integer.toString(patch.getVarbit().getId()); + String storedValue = configManager.getConfiguration(group, key); + + if (storedValue == null) + { + return null; + } + + long unixTime = 0; + int value = 0; + { + String[] parts = storedValue.split(":"); + if (parts.length == 2) + { + try + { + value = Integer.parseInt(parts[0]); + unixTime = Long.parseLong(parts[1]); + } + catch (NumberFormatException e) + { + } + } + } + + if (unixTime <= 0) + { + return null; + } + + PatchState state = patch.getImplementation().forVarbitValue(value); + + int stage = state.getStage(); + int stages = state.getStages(); + int tickrate = state.getTickRate() * 60; + + if (autoweed && state.getProduce() == Produce.WEEDS) + { + stage = 0; + stages = 1; + tickrate = 0; + } + + long doneEstimate = 0; + if (tickrate > 0) + { + long tickNow = (unixNow + (5 * 60)) / tickrate; + long tickTime = (unixTime + (5 * 60)) / tickrate; + int delta = (int) (tickNow - tickTime); + + doneEstimate = ((stages - 1 - stage) + tickTime) * tickrate + (5 * 60); + + stage += delta; + if (stage >= stages) + { + stage = stages - 1; + } + } + + return new PatchPrediction( + state.getProduce(), + state.getCropState(), + doneEstimate, + stage, + stages + ); + } + + public void loadCompletionTimes() + { + summaries.clear(); + completionTimes.clear(); + updateCompletionTime(); + } + + public SummaryState getSummary(Tab patchType) + { + SummaryState summary = summaries.get(patchType); + return summary == null ? SummaryState.UNKNOWN : summary; + } + + /** + * Gets the overall completion time for the given patch type. + * + * @see #completionTimes + */ + public long getCompletionTime(Tab patchType) + { + Long completionTime = completionTimes.get(patchType); + return completionTime == null ? -1 : completionTime; + } + + /** + * Updates the overall completion time for the given patch type. + * + * @see #completionTimes + */ + private void updateCompletionTime() + { + for (Map.Entry> tab : farmingWorld.getTabs().entrySet()) + { + long maxCompletionTime = 0; + boolean allUnknown = true; + boolean allEmpty = true; + + for (FarmingPatch patch : tab.getValue()) + { + PatchPrediction prediction = predictPatch(patch); + if (prediction == null || prediction.getProduce().getItemID() < 0) + { + continue; // unknown state + } + + allUnknown = false; + + if (prediction.getProduce() != Produce.WEEDS && prediction.getProduce() != Produce.SCARECROW) + { + allEmpty = false; + + // update max duration if this patch takes longer to grow + maxCompletionTime = Math.max(maxCompletionTime, prediction.getDoneEstimate()); + } + } + + final SummaryState state; + final long completionTime; + + if (allUnknown) + { + state = SummaryState.UNKNOWN; + completionTime = -1L; + } + else if (allEmpty) + { + state = SummaryState.EMPTY; + completionTime = -1L; + } + else if (maxCompletionTime <= Instant.now().getEpochSecond()) + { + state = SummaryState.COMPLETED; + completionTime = 0; + } + else + { + state = SummaryState.IN_PROGRESS; + completionTime = maxCompletionTime; + } + summaries.put(tab.getKey(), state); + completionTimes.put(tab.getKey(), completionTime); + } + } +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/timetracking/hunter/BirdHouseTracker.java b/runelite-client/src/main/java/net/runelite/client/plugins/timetracking/hunter/BirdHouseTracker.java index c61b952cee..bef011cea4 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/timetracking/hunter/BirdHouseTracker.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/timetracking/hunter/BirdHouseTracker.java @@ -1,253 +1,254 @@ -/* - * Copyright (c) 2018 Abex - * Copyright (c) 2018, Daniel Teo - * 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.timetracking.hunter; - -import com.google.common.collect.ImmutableSet; -import com.google.inject.Inject; -import com.google.inject.Singleton; -import java.time.Duration; -import java.time.Instant; -import java.util.HashMap; -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ConcurrentMap; -import lombok.AccessLevel; -import lombok.Getter; -import net.runelite.api.Client; -import net.runelite.api.coords.WorldPoint; -import net.runelite.client.Notifier; -import net.runelite.client.config.ConfigManager; -import net.runelite.client.game.ItemManager; -import net.runelite.client.plugins.timetracking.SummaryState; -import net.runelite.client.plugins.timetracking.TimeTrackingConfig; - -@Singleton -public class BirdHouseTracker -{ - // average time taken to harvest 10 birds, in seconds - static final int BIRD_HOUSE_DURATION = (int) Duration.ofMinutes(50).getSeconds(); - - private static ImmutableSet FOSSIL_ISLAND_REGIONS = ImmutableSet.of(14650, 14651, 14652, 14906, 14907, 15162, 15163); - - private final Client client; - private final ItemManager itemManager; - private final ConfigManager configManager; - private final TimeTrackingConfig config; - private final Notifier notifier; - - @Getter(AccessLevel.PACKAGE) - private final ConcurrentMap birdHouseData = new ConcurrentHashMap<>(); - - @Getter - private SummaryState summary = SummaryState.UNKNOWN; - - /** - * The time at which all the bird houses will be ready to be dismantled, - * or {@code -1} if we have no data about any of the bird house spaces. - */ - @Getter - private long completionTime = -1; - - @Inject - private BirdHouseTracker(Client client, ItemManager itemManager, ConfigManager configManager, - TimeTrackingConfig config, Notifier notifier) - { - this.client = client; - this.itemManager = itemManager; - this.configManager = configManager; - this.config = config; - this.notifier = notifier; - } - - public BirdHouseTabPanel createBirdHouseTabPanel() - { - return new BirdHouseTabPanel(itemManager, this, config); - } - - public void loadFromConfig() - { - birdHouseData.clear(); - - final String group = TimeTrackingConfig.CONFIG_GROUP + "." + client.getUsername() + "." + TimeTrackingConfig.BIRD_HOUSE; - - for (BirdHouseSpace space : BirdHouseSpace.values()) - { - String key = Integer.toString(space.getVarp().getId()); - String storedValue = configManager.getConfiguration(group, key); - - if (storedValue != null) - { - String[] parts = storedValue.split(":"); - if (parts.length == 2) - { - try - { - int varp = Integer.parseInt(parts[0]); - long timestamp = Long.parseLong(parts[1]); - birdHouseData.put(space, new BirdHouseData(space, varp, timestamp)); - } - catch (NumberFormatException e) - { - // ignored - } - } - } - } - - updateCompletionTime(); - } - - /** - * Updates tracker data if player is within range of any bird house. Returns true if any data was changed. - */ - public boolean updateData(WorldPoint location) - { - boolean changed = false; - - if (FOSSIL_ISLAND_REGIONS.contains(location.getRegionID()) && location.getPlane() == 0) - { - final Map newData = new HashMap<>(); - final long currentTime = Instant.now().getEpochSecond(); - int removalCount = 0; - - for (BirdHouseSpace space : BirdHouseSpace.values()) - { - int varp = client.getVar(space.getVarp()); - BirdHouseData oldData = birdHouseData.get(space); - int oldVarp = oldData == null ? -1 : oldData.getVarp(); - - // update data if there isn't one, or if the varp doesn't match - if (varp != oldVarp) - { - newData.put(space, new BirdHouseData(space, varp, currentTime)); - changed = true; - } - - if (varp <= 0 && oldVarp > 0) - { - removalCount++; - } - } - - // Prevent the resetting of bird house data that could occur if the varps have not been updated yet - // after the player enters the region. We assume that players would generally have 3 or 4 bird houses - // built at any time, and that dropping from 3/4 to 0 built bird houses is not normally possible. - if (removalCount > 2) - { - return false; - } - - if (changed) - { - birdHouseData.putAll(newData); - updateCompletionTime(); - saveToConfig(newData); - } - } - - return changed; - } - - /** - * Checks if the bird houses have become ready to be dismantled, - * and sends a notification if required. - */ - public boolean checkCompletion() - { - if (summary == SummaryState.IN_PROGRESS && completionTime < Instant.now().getEpochSecond()) - { - summary = SummaryState.COMPLETED; - completionTime = 0; - - if (config.birdHouseNotification()) - { - notifier.notify("Your bird houses are ready to be dismantled."); - } - - return true; - } - - return false; - } - - /** - * Updates the overall completion time of the bird houses. - * @see #completionTime - */ - private void updateCompletionTime() - { - if (birdHouseData.isEmpty()) - { - summary = SummaryState.UNKNOWN; - completionTime = -1; - return; - } - - boolean allEmpty = true; - long maxCompletionTime = 0; - for (BirdHouseData data : birdHouseData.values()) - { - final BirdHouseState state = BirdHouseState.fromVarpValue(data.getVarp()); - - if (state != BirdHouseState.EMPTY) - { - allEmpty = false; - } - - if (state == BirdHouseState.SEEDED) - { - maxCompletionTime = Math.max(maxCompletionTime, data.getTimestamp() + BIRD_HOUSE_DURATION); - } - } - - if (allEmpty) - { - summary = SummaryState.EMPTY; - completionTime = 0; - } - else if (maxCompletionTime <= Instant.now().getEpochSecond()) - { - summary = SummaryState.COMPLETED; - completionTime = 0; - } - else - { - summary = SummaryState.IN_PROGRESS; - completionTime = maxCompletionTime; - } - } - - private void saveToConfig(Map updatedData) - { - final String group = TimeTrackingConfig.CONFIG_GROUP + "." + client.getUsername() + "." + TimeTrackingConfig.BIRD_HOUSE; - - for (BirdHouseData data : updatedData.values()) - { - String key = Integer.toString(data.getSpace().getVarp().getId()); - configManager.setConfiguration(group, key, data.getVarp() + ":" + data.getTimestamp()); - } - } -} +/* + * Copyright (c) 2018 Abex + * Copyright (c) 2018, Daniel Teo + * 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.timetracking.hunter; + +import com.google.common.collect.ImmutableSet; +import com.google.inject.Inject; +import com.google.inject.Singleton; +import java.time.Duration; +import java.time.Instant; +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; +import lombok.AccessLevel; +import lombok.Getter; +import net.runelite.api.Client; +import net.runelite.api.coords.WorldPoint; +import net.runelite.client.Notifier; +import net.runelite.client.config.ConfigManager; +import net.runelite.client.game.ItemManager; +import net.runelite.client.plugins.timetracking.SummaryState; +import net.runelite.client.plugins.timetracking.TimeTrackingConfig; + +@Singleton +public class BirdHouseTracker +{ + // average time taken to harvest 10 birds, in seconds + static final int BIRD_HOUSE_DURATION = (int) Duration.ofMinutes(50).getSeconds(); + + private static ImmutableSet FOSSIL_ISLAND_REGIONS = ImmutableSet.of(14650, 14651, 14652, 14906, 14907, 15162, 15163); + + private final Client client; + private final ItemManager itemManager; + private final ConfigManager configManager; + private final TimeTrackingConfig config; + private final Notifier notifier; + + @Getter(AccessLevel.PACKAGE) + private final ConcurrentMap birdHouseData = new ConcurrentHashMap<>(); + + @Getter + private SummaryState summary = SummaryState.UNKNOWN; + + /** + * The time at which all the bird houses will be ready to be dismantled, + * or {@code -1} if we have no data about any of the bird house spaces. + */ + @Getter + private long completionTime = -1; + + @Inject + private BirdHouseTracker(Client client, ItemManager itemManager, ConfigManager configManager, + TimeTrackingConfig config, Notifier notifier) + { + this.client = client; + this.itemManager = itemManager; + this.configManager = configManager; + this.config = config; + this.notifier = notifier; + } + + public BirdHouseTabPanel createBirdHouseTabPanel() + { + return new BirdHouseTabPanel(itemManager, this, config); + } + + public void loadFromConfig() + { + birdHouseData.clear(); + + final String group = TimeTrackingConfig.CONFIG_GROUP + "." + client.getUsername() + "." + TimeTrackingConfig.BIRD_HOUSE; + + for (BirdHouseSpace space : BirdHouseSpace.values()) + { + String key = Integer.toString(space.getVarp().getId()); + String storedValue = configManager.getConfiguration(group, key); + + if (storedValue != null) + { + String[] parts = storedValue.split(":"); + if (parts.length == 2) + { + try + { + int varp = Integer.parseInt(parts[0]); + long timestamp = Long.parseLong(parts[1]); + birdHouseData.put(space, new BirdHouseData(space, varp, timestamp)); + } + catch (NumberFormatException e) + { + // ignored + } + } + } + } + + updateCompletionTime(); + } + + /** + * Updates tracker data if player is within range of any bird house. Returns true if any data was changed. + */ + public boolean updateData(WorldPoint location) + { + boolean changed = false; + + if (FOSSIL_ISLAND_REGIONS.contains(location.getRegionID()) && location.getPlane() == 0) + { + final Map newData = new HashMap<>(); + final long currentTime = Instant.now().getEpochSecond(); + int removalCount = 0; + + for (BirdHouseSpace space : BirdHouseSpace.values()) + { + int varp = client.getVar(space.getVarp()); + BirdHouseData oldData = birdHouseData.get(space); + int oldVarp = oldData == null ? -1 : oldData.getVarp(); + + // update data if there isn't one, or if the varp doesn't match + if (varp != oldVarp) + { + newData.put(space, new BirdHouseData(space, varp, currentTime)); + changed = true; + } + + if (varp <= 0 && oldVarp > 0) + { + removalCount++; + } + } + + // Prevent the resetting of bird house data that could occur if the varps have not been updated yet + // after the player enters the region. We assume that players would generally have 3 or 4 bird houses + // built at any time, and that dropping from 3/4 to 0 built bird houses is not normally possible. + if (removalCount > 2) + { + return false; + } + + if (changed) + { + birdHouseData.putAll(newData); + updateCompletionTime(); + saveToConfig(newData); + } + } + + return changed; + } + + /** + * Checks if the bird houses have become ready to be dismantled, + * and sends a notification if required. + */ + public boolean checkCompletion() + { + if (summary == SummaryState.IN_PROGRESS && completionTime < Instant.now().getEpochSecond()) + { + summary = SummaryState.COMPLETED; + completionTime = 0; + + if (config.birdHouseNotification()) + { + notifier.notify("Your bird houses are ready to be dismantled."); + } + + return true; + } + + return false; + } + + /** + * Updates the overall completion time of the bird houses. + * + * @see #completionTime + */ + private void updateCompletionTime() + { + if (birdHouseData.isEmpty()) + { + summary = SummaryState.UNKNOWN; + completionTime = -1; + return; + } + + boolean allEmpty = true; + long maxCompletionTime = 0; + for (BirdHouseData data : birdHouseData.values()) + { + final BirdHouseState state = BirdHouseState.fromVarpValue(data.getVarp()); + + if (state != BirdHouseState.EMPTY) + { + allEmpty = false; + } + + if (state == BirdHouseState.SEEDED) + { + maxCompletionTime = Math.max(maxCompletionTime, data.getTimestamp() + BIRD_HOUSE_DURATION); + } + } + + if (allEmpty) + { + summary = SummaryState.EMPTY; + completionTime = 0; + } + else if (maxCompletionTime <= Instant.now().getEpochSecond()) + { + summary = SummaryState.COMPLETED; + completionTime = 0; + } + else + { + summary = SummaryState.IN_PROGRESS; + completionTime = maxCompletionTime; + } + } + + private void saveToConfig(Map updatedData) + { + final String group = TimeTrackingConfig.CONFIG_GROUP + "." + client.getUsername() + "." + TimeTrackingConfig.BIRD_HOUSE; + + for (BirdHouseData data : updatedData.values()) + { + String key = Integer.toString(data.getSpace().getVarp().getId()); + configManager.setConfiguration(group, key, data.getVarp() + ":" + data.getTimestamp()); + } + } +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/tobdamagecount/DamageCounterPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/tobdamagecount/DamageCounterPlugin.java index 2225ebde17..1228ebca02 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/tobdamagecount/DamageCounterPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/tobdamagecount/DamageCounterPlugin.java @@ -1,358 +1,360 @@ -/* - * Copyright (c) 2018, Bryan Chau(RSN:Laura Brehm) - * 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.tobdamagecount; - -import javax.inject.Inject; -import java.text.DecimalFormat; - -import net.runelite.api.Client; -import net.runelite.api.GameState; -import net.runelite.api.NPC; -import net.runelite.api.NpcID; -import net.runelite.api.Skill; -import net.runelite.api.ChatMessageType; -import net.runelite.api.Actor; -import net.runelite.api.Player; -import net.runelite.api.coords.WorldPoint; -import net.runelite.api.events.HitsplatApplied; -import net.runelite.api.events.GameTick; -import net.runelite.api.events.GameStateChanged; -import net.runelite.api.events.NpcDespawned; -import net.runelite.api.events.LocalPlayerDeath; -import net.runelite.client.chat.ChatColorType; -import net.runelite.client.chat.ChatMessageBuilder; -import net.runelite.client.chat.ChatMessageManager; -import net.runelite.client.chat.QueuedMessage; -import net.runelite.client.plugins.Plugin; -import net.runelite.client.plugins.PluginDescriptor; -import net.runelite.client.eventbus.Subscribe; -import net.runelite.client.plugins.PluginType; - - -@PluginDescriptor( - name = "ToB Damage Counter", - description = "Gives you an estimation damage on a boss and taken after the fight is done" + - "the damage will be posted in the chat", - tags = {"combat", "npcs", "tob", "damage"}, - type = PluginType.PVM, - enabledByDefault = false -) - -public class DamageCounterPlugin extends Plugin -{ - private int currentWorld = -1; - private int DamageCount = 0; - private int currenthpxp = -1; // checking the current hp xp so be easier to find - private String BossName = null; //to ID the boss to calculate the damage - private int DamageTaken = 0; - private boolean status = true; //default boolean alive = true, dead = false - //formatting the number for damage taken and dealt with to look beeter - private static final DecimalFormat DAMAGEFORMAT = new DecimalFormat("#,###"); - private static final double XP_RATIO = 1.3333; - private static final double BOSS_MODIFIER = 1.05; - private static final int MAIDENHP = 3500; - private static final int BLOATHP = 2000; - private static final int NYLOHP = 2500; - private static final int SOTHP = 4000; - private static final int XARPUSHP = 5080; - private static final int VERZIKHP = 8500; - private static final boolean ALIVE = true; // - private static final boolean DEAD = false; //if they're dead they cannot "recreate" the message of being alive - //locations at ToB - private static final int MAIDEN_REGION = 12613; - private static final int MAIDEN_REGION_1 = 12869; - private static final int BLOAT_REGION = 13125; - private static final int NYLOCAS_REGION = 13122; - private static final int SOTETSEG_REGION = 13123; - private static final int SOTETSEG_REGION2 = 13379; - private static final int XARPUS_REGION = 12612; - private static final int VERZIK_REGION = 12611; - private static final int[] ToB_Region = {MAIDEN_REGION, MAIDEN_REGION_1, BLOAT_REGION, NYLOCAS_REGION, - SOTETSEG_REGION, SOTETSEG_REGION2, XARPUS_REGION, VERZIK_REGION}; - //setting up the array for a check list - private static int[] NPCARRAY = {NpcID.THE_MAIDEN_OF_SUGADINTI, NpcID.THE_MAIDEN_OF_SUGADINTI_8361, - NpcID.THE_MAIDEN_OF_SUGADINTI_8362, NpcID.THE_MAIDEN_OF_SUGADINTI_8363, NpcID.THE_MAIDEN_OF_SUGADINTI_8364, - NpcID.THE_MAIDEN_OF_SUGADINTI_8365, NpcID.PESTILENT_BLOAT, NpcID.NYLOCAS_VASILIAS, - NpcID.NYLOCAS_VASILIAS_8355, NpcID.NYLOCAS_VASILIAS_8356, NpcID.NYLOCAS_VASILIAS_8357, NpcID.SOTETSEG, - NpcID.SOTETSEG_8388, NpcID.XARPUS, NpcID.XARPUS_8339, NpcID.XARPUS_8340, NpcID.XARPUS_8341, - NpcID.VERZIK_VITUR, NpcID.VERZIK_VITUR_8369, NpcID.VERZIK_VITUR_8370, NpcID.VERZIK_VITUR_8371, - NpcID.VERZIK_VITUR_8372, NpcID.VERZIK_VITUR_8373, NpcID.VERZIK_VITUR_8374, NpcID.VERZIK_VITUR_8375}; - - private int[] HEALTHARRAY = {MAIDENHP, NYLOHP, VERZIKHP}; - - @Inject - private Client client; - @Inject - private ChatMessageManager chatMessangerManager; - //every game tick it will go through methods - @Subscribe - private void onGameTick(GameTick tick) - { - if (client.getGameState() != GameState.LOGGED_IN) - { - ResetCounter(); - return; - } - checkInterAction(); - DamageCounting(); - currenthpxp = client.getSkillExperience(Skill.HITPOINTS); - } - //checks for npcID and put the boss name into a string be easier to ID it - //once the boss is found it will never check it - private void checkInterAction() - { - Player localPlayer = client.getLocalPlayer(); - Actor interacting = localPlayer.getInteracting(); - if (client.getGameState() == GameState.LOGGED_IN) - { - if (BossName == null) - { - if (interacting instanceof NPC) - { - int interactingId = ((NPC) interacting).getId(); - String interactingName = interacting.getName(); - for (int aNPCARRAY : NPCARRAY) - { - if (aNPCARRAY == interactingId) - { - BossName = interactingName; - } - } - } - } - } - } - - @Subscribe - //if you hop it will reset the counter - public void onGameStateChanged(GameStateChanged event) - { - if (event.getGameState() == GameState.LOGGED_IN) - { - if (currentWorld == -1) - { - currentWorld = client.getWorld(); - } - else if (currentWorld != client.getWorld()) - { - currentWorld = client.getWorld(); - ResetCounter(); - } - } - } - - //grabbing the xp and calculating the damage - private int XPtoDamage() - { - int NewXp; - double damageOutput = 0; - int XPdrop; - if (currenthpxp != -1) - { - XPdrop = client.getSkillExperience(Skill.HITPOINTS); - NewXp = XPdrop - currenthpxp; - currenthpxp = -1; - damageOutput = NewXp / XP_RATIO; - } - //returns the damage you have done - return (int) Math.floor(damageOutput); - } - - //adding up the damage for the print message checks every tick(aka attack tick) - private void DamageCounting() - { - Player localPlayer = client.getLocalPlayer(); - Actor interacting = localPlayer.getInteracting(); - if (client.getGameState() == GameState.LOGGED_IN) - { - if (interacting instanceof NPC) - { - String interactingName = interacting.getName(); - int NPC = ((NPC) interacting).getId(); - if (interactingName.equals(BossName)) - { - DamageCount += (XPtoDamage() * BOSS_MODIFIER); - - } - } - } - } - - - @Subscribe - //will add the damage that you have taken from the current boss fight - private void onHitsplatApplied(HitsplatApplied Hit) - { - if (Hit.getActor().equals(client.getLocalPlayer())) - { - DamageTaken += Hit.getHitsplat().getAmount(); - } - - } - - //will check for the monster if it died works only on ToB Bosses - /*Verzik has three phases so the program will add up all the damage and prints it into one message - because every time she phases she "dies" so making sure the counter doesn't print out the damage for phase 1, 2, - and 3. - */ - @Subscribe - public void onNpcDespawned(NpcDespawned npc) - { - NPC actor = npc.getNpc(); - double Percent = calculatePercent(WorldPoint.fromLocalInstance(client, - client.getLocalPlayer().getLocalLocation()).getRegionID()); - if (actor.isDead() && actor.getId() == NpcID.VERZIK_VITUR_8375 && status) - { - DamagePrint(actor, Percent); - ResetCounter(); - } - else if (actor.isDead() && actor.getName().equals(BossName) && actor.getId() != NpcID.VERZIK_VITUR_8374 && - actor.getId() != NpcID.VERZIK_VITUR_8372 && actor.getId() != NpcID.VERZIK_VITUR_8370 && - status) - { - DamagePrint(actor, Percent); - ResetCounter(); - } - //will reset the counter after the boss dies and if you died during the fight - else if (actor.isDead() && actor.getName().equals(BossName) && !status) - { - ResetCounter(); - } - } - - private double calculatePercent(int id) - { - double percent = 0; - if (DamageCount != 0) { - if (id == MAIDEN_REGION || id == MAIDEN_REGION_1) - { - percent = (DamageCount / (double) MAIDENHP) * 100; - } - else if (id == BLOAT_REGION) - { - percent = (DamageCount / (double) BLOATHP) * 100; - } - else if (id == NYLOCAS_REGION) - { - percent = (DamageCount / (double) NYLOHP) * 100; - } - else if (id == SOTETSEG_REGION || id == SOTETSEG_REGION2) - { - percent = (DamageCount / (double) SOTHP) * 100; - } - else if (id == XARPUS_REGION) - { - percent = (DamageCount / (double) XARPUSHP) * 100; - } - else if (id == VERZIK_REGION) - { - percent = (DamageCount / (double) VERZIKHP) * 100; - } - } - return percent; - } - - //just reset the counter for the next fight and status - private void ResetCounter() - { - DamageCount = 0; - DamageTaken = 0; - BossName = null; - status = ALIVE; - } - - //print out the damage after the boss have died - //prevent people from spectating to get the damage message, it is impossible for them to get damage - private void DamagePrint(NPC actor, double percent) - { - String MessageDamage; - if (percent >= 50) - { - MessageDamage = "Well done carrying the team!" + - "WOWIE!! You did" + DAMAGEFORMAT.format(DamageCount) + " damage to " + - actor.getName() + "! You did %" + String.format("%.2f", percent) + " of the damage"; - } - else if (percent >= 25) - { - MessageDamage = "Well done carrying some dead weight in your team! " + - "Awesome! You did " + DAMAGEFORMAT.format(DamageCount) + " damage to " + - actor.getName() + "! You did %" + String.format("%.2f", percent) + " of the damage"; - } - else if (percent >= 1) - { - MessageDamage = "Well done everyone is pulling their weight! " + - "You did " + DAMAGEFORMAT.format(DamageCount) + " damage to " + - actor.getName() + "! You did %" + String.format("%.2f", percent) + " of the damage"; - } - else - { - MessageDamage = "Didn't do much" + - "Fucking leech did " + DAMAGEFORMAT.format(DamageCount) + " damage to " + - actor.getName() + "! You did %" + String.format("%.2f", percent) + " of the damage"; - } - - sendChatMessage(MessageDamage); - String MessageTaken = "You have taken " + DAMAGEFORMAT.format(DamageTaken) + " damage from this fight!"; - sendChatMessage(MessageTaken); - } - - @Subscribe - //whenever you have died in tob you will get a death message with damage - // made sure the message works at ToB area or else it will message every where - private void onLocalPlayerDeath(LocalPlayerDeath death) - { - String DeathMessage = "You have died! You did " + DAMAGEFORMAT.format(DamageCount) + " damage to " + - BossName + "!"; - String MessageTaken = "You have taken " + DAMAGEFORMAT.format(DamageTaken) + " damage from this fight!"; - for (int i = 0; i < ToB_Region.length; i++) - { - if (WorldPoint.fromLocalInstance(client, - client.getLocalPlayer().getLocalLocation()).getRegionID() == ToB_Region[i]) - { - sendChatMessage(DeathMessage); - sendChatMessage(MessageTaken); - ResetCounter(); - //status will become "dead" after you died in the fight - status = DEAD; - } - } - } - - //sends a message saying this "You have done XYZ damage to boss name! or the death message - // "Well done! you have done your best, you have done XYZ damage to boss name - private void sendChatMessage(String chatMessage) - { - final String message = new ChatMessageBuilder() - .append(ChatColorType.HIGHLIGHT) - .append(chatMessage) - .build(); - chatMessangerManager.queue( - QueuedMessage.builder() - .type(ChatMessageType.CONSOLE) - .runeLiteFormattedMessage(message) - .build()); - } +/* + * Copyright (c) 2018, Bryan Chau(RSN:Laura Brehm) + * 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.tobdamagecount; + +import java.text.DecimalFormat; +import javax.inject.Inject; +import net.runelite.api.Actor; +import net.runelite.api.ChatMessageType; +import net.runelite.api.Client; +import net.runelite.api.GameState; +import net.runelite.api.NPC; +import net.runelite.api.NpcID; +import net.runelite.api.Player; +import net.runelite.api.Skill; +import net.runelite.api.coords.WorldPoint; +import net.runelite.api.events.GameStateChanged; +import net.runelite.api.events.GameTick; +import net.runelite.api.events.HitsplatApplied; +import net.runelite.api.events.LocalPlayerDeath; +import net.runelite.api.events.NpcDespawned; +import net.runelite.client.chat.ChatColorType; +import net.runelite.client.chat.ChatMessageBuilder; +import net.runelite.client.chat.ChatMessageManager; +import net.runelite.client.chat.QueuedMessage; +import net.runelite.client.eventbus.Subscribe; +import net.runelite.client.plugins.Plugin; +import net.runelite.client.plugins.PluginDescriptor; +import net.runelite.client.plugins.PluginType; + + +@PluginDescriptor( + name = "ToB Damage Counter", + description = "Gives you an estimation damage on a boss and taken after the fight is done" + + "the damage will be posted in the chat", + tags = {"combat", "npcs", "tob", "damage"}, + type = PluginType.PVM, + enabledByDefault = false +) + +public class DamageCounterPlugin extends Plugin +{ + private int currentWorld = -1; + private int DamageCount = 0; + private int currenthpxp = -1; // checking the current hp xp so be easier to find + private String BossName = null; //to ID the boss to calculate the damage + private int DamageTaken = 0; + private boolean status = true; //default boolean alive = true, dead = false + //formatting the number for damage taken and dealt with to look beeter + private static final DecimalFormat DAMAGEFORMAT = new DecimalFormat("#,###"); + private static final double XP_RATIO = 1.3333; + private static final double BOSS_MODIFIER = 1.05; + private static final int MAIDENHP = 3500; + private static final int BLOATHP = 2000; + private static final int NYLOHP = 2500; + private static final int SOTHP = 4000; + private static final int XARPUSHP = 5080; + private static final int VERZIKHP = 8500; + private static final boolean ALIVE = true; // + private static final boolean DEAD = false; //if they're dead they cannot "recreate" the message of being alive + //locations at ToB + private static final int MAIDEN_REGION = 12613; + private static final int MAIDEN_REGION_1 = 12869; + private static final int BLOAT_REGION = 13125; + private static final int NYLOCAS_REGION = 13122; + private static final int SOTETSEG_REGION = 13123; + private static final int SOTETSEG_REGION2 = 13379; + private static final int XARPUS_REGION = 12612; + private static final int VERZIK_REGION = 12611; + private static final int[] ToB_Region = {MAIDEN_REGION, MAIDEN_REGION_1, BLOAT_REGION, NYLOCAS_REGION, + SOTETSEG_REGION, SOTETSEG_REGION2, XARPUS_REGION, VERZIK_REGION}; + //setting up the array for a check list + private static int[] NPCARRAY = {NpcID.THE_MAIDEN_OF_SUGADINTI, NpcID.THE_MAIDEN_OF_SUGADINTI_8361, + NpcID.THE_MAIDEN_OF_SUGADINTI_8362, NpcID.THE_MAIDEN_OF_SUGADINTI_8363, NpcID.THE_MAIDEN_OF_SUGADINTI_8364, + NpcID.THE_MAIDEN_OF_SUGADINTI_8365, NpcID.PESTILENT_BLOAT, NpcID.NYLOCAS_VASILIAS, + NpcID.NYLOCAS_VASILIAS_8355, NpcID.NYLOCAS_VASILIAS_8356, NpcID.NYLOCAS_VASILIAS_8357, NpcID.SOTETSEG, + NpcID.SOTETSEG_8388, NpcID.XARPUS, NpcID.XARPUS_8339, NpcID.XARPUS_8340, NpcID.XARPUS_8341, + NpcID.VERZIK_VITUR, NpcID.VERZIK_VITUR_8369, NpcID.VERZIK_VITUR_8370, NpcID.VERZIK_VITUR_8371, + NpcID.VERZIK_VITUR_8372, NpcID.VERZIK_VITUR_8373, NpcID.VERZIK_VITUR_8374, NpcID.VERZIK_VITUR_8375}; + + private int[] HEALTHARRAY = {MAIDENHP, NYLOHP, VERZIKHP}; + + @Inject + private Client client; + @Inject + private ChatMessageManager chatMessangerManager; + + //every game tick it will go through methods + @Subscribe + private void onGameTick(GameTick tick) + { + if (client.getGameState() != GameState.LOGGED_IN) + { + ResetCounter(); + return; + } + checkInterAction(); + DamageCounting(); + currenthpxp = client.getSkillExperience(Skill.HITPOINTS); + } + + //checks for npcID and put the boss name into a string be easier to ID it + //once the boss is found it will never check it + private void checkInterAction() + { + Player localPlayer = client.getLocalPlayer(); + Actor interacting = localPlayer.getInteracting(); + if (client.getGameState() == GameState.LOGGED_IN) + { + if (BossName == null) + { + if (interacting instanceof NPC) + { + int interactingId = ((NPC) interacting).getId(); + String interactingName = interacting.getName(); + for (int aNPCARRAY : NPCARRAY) + { + if (aNPCARRAY == interactingId) + { + BossName = interactingName; + } + } + } + } + } + } + + @Subscribe + //if you hop it will reset the counter + public void onGameStateChanged(GameStateChanged event) + { + if (event.getGameState() == GameState.LOGGED_IN) + { + if (currentWorld == -1) + { + currentWorld = client.getWorld(); + } + else if (currentWorld != client.getWorld()) + { + currentWorld = client.getWorld(); + ResetCounter(); + } + } + } + + //grabbing the xp and calculating the damage + private int XPtoDamage() + { + int NewXp; + double damageOutput = 0; + int XPdrop; + if (currenthpxp != -1) + { + XPdrop = client.getSkillExperience(Skill.HITPOINTS); + NewXp = XPdrop - currenthpxp; + currenthpxp = -1; + damageOutput = NewXp / XP_RATIO; + } + //returns the damage you have done + return (int) Math.floor(damageOutput); + } + + //adding up the damage for the print message checks every tick(aka attack tick) + private void DamageCounting() + { + Player localPlayer = client.getLocalPlayer(); + Actor interacting = localPlayer.getInteracting(); + if (client.getGameState() == GameState.LOGGED_IN) + { + if (interacting instanceof NPC) + { + String interactingName = interacting.getName(); + int NPC = ((NPC) interacting).getId(); + if (interactingName.equals(BossName)) + { + DamageCount += (XPtoDamage() * BOSS_MODIFIER); + + } + } + } + } + + + @Subscribe + //will add the damage that you have taken from the current boss fight + private void onHitsplatApplied(HitsplatApplied Hit) + { + if (Hit.getActor().equals(client.getLocalPlayer())) + { + DamageTaken += Hit.getHitsplat().getAmount(); + } + + } + + //will check for the monster if it died works only on ToB Bosses + /*Verzik has three phases so the program will add up all the damage and prints it into one message + because every time she phases she "dies" so making sure the counter doesn't print out the damage for phase 1, 2, + and 3. + */ + @Subscribe + public void onNpcDespawned(NpcDespawned npc) + { + NPC actor = npc.getNpc(); + double Percent = calculatePercent(WorldPoint.fromLocalInstance(client, + client.getLocalPlayer().getLocalLocation()).getRegionID()); + if (actor.isDead() && actor.getId() == NpcID.VERZIK_VITUR_8375 && status) + { + DamagePrint(actor, Percent); + ResetCounter(); + } + else if (actor.isDead() && actor.getName().equals(BossName) && actor.getId() != NpcID.VERZIK_VITUR_8374 && + actor.getId() != NpcID.VERZIK_VITUR_8372 && actor.getId() != NpcID.VERZIK_VITUR_8370 && + status) + { + DamagePrint(actor, Percent); + ResetCounter(); + } + //will reset the counter after the boss dies and if you died during the fight + else if (actor.isDead() && actor.getName().equals(BossName) && !status) + { + ResetCounter(); + } + } + + private double calculatePercent(int id) + { + double percent = 0; + if (DamageCount != 0) + { + if (id == MAIDEN_REGION || id == MAIDEN_REGION_1) + { + percent = (DamageCount / (double) MAIDENHP) * 100; + } + else if (id == BLOAT_REGION) + { + percent = (DamageCount / (double) BLOATHP) * 100; + } + else if (id == NYLOCAS_REGION) + { + percent = (DamageCount / (double) NYLOHP) * 100; + } + else if (id == SOTETSEG_REGION || id == SOTETSEG_REGION2) + { + percent = (DamageCount / (double) SOTHP) * 100; + } + else if (id == XARPUS_REGION) + { + percent = (DamageCount / (double) XARPUSHP) * 100; + } + else if (id == VERZIK_REGION) + { + percent = (DamageCount / (double) VERZIKHP) * 100; + } + } + return percent; + } + + //just reset the counter for the next fight and status + private void ResetCounter() + { + DamageCount = 0; + DamageTaken = 0; + BossName = null; + status = ALIVE; + } + + //print out the damage after the boss have died + //prevent people from spectating to get the damage message, it is impossible for them to get damage + private void DamagePrint(NPC actor, double percent) + { + String MessageDamage; + if (percent >= 50) + { + MessageDamage = "Well done carrying the team!" + + "WOWIE!! You did" + DAMAGEFORMAT.format(DamageCount) + " damage to " + + actor.getName() + "! You did %" + String.format("%.2f", percent) + " of the damage"; + } + else if (percent >= 25) + { + MessageDamage = "Well done carrying some dead weight in your team! " + + "Awesome! You did " + DAMAGEFORMAT.format(DamageCount) + " damage to " + + actor.getName() + "! You did %" + String.format("%.2f", percent) + " of the damage"; + } + else if (percent >= 1) + { + MessageDamage = "Well done everyone is pulling their weight! " + + "You did " + DAMAGEFORMAT.format(DamageCount) + " damage to " + + actor.getName() + "! You did %" + String.format("%.2f", percent) + " of the damage"; + } + else + { + MessageDamage = "Didn't do much" + + "Fucking leech did " + DAMAGEFORMAT.format(DamageCount) + " damage to " + + actor.getName() + "! You did %" + String.format("%.2f", percent) + " of the damage"; + } + + sendChatMessage(MessageDamage); + String MessageTaken = "You have taken " + DAMAGEFORMAT.format(DamageTaken) + " damage from this fight!"; + sendChatMessage(MessageTaken); + } + + @Subscribe + //whenever you have died in tob you will get a death message with damage + // made sure the message works at ToB area or else it will message every where + private void onLocalPlayerDeath(LocalPlayerDeath death) + { + String DeathMessage = "You have died! You did " + DAMAGEFORMAT.format(DamageCount) + " damage to " + + BossName + "!"; + String MessageTaken = "You have taken " + DAMAGEFORMAT.format(DamageTaken) + " damage from this fight!"; + for (int i = 0; i < ToB_Region.length; i++) + { + if (WorldPoint.fromLocalInstance(client, + client.getLocalPlayer().getLocalLocation()).getRegionID() == ToB_Region[i]) + { + sendChatMessage(DeathMessage); + sendChatMessage(MessageTaken); + ResetCounter(); + //status will become "dead" after you died in the fight + status = DEAD; + } + } + } + + //sends a message saying this "You have done XYZ damage to boss name! or the death message + // "Well done! you have done your best, you have done XYZ damage to boss name + private void sendChatMessage(String chatMessage) + { + final String message = new ChatMessageBuilder() + .append(ChatColorType.HIGHLIGHT) + .append(chatMessage) + .build(); + chatMessangerManager.queue( + QueuedMessage.builder() + .type(ChatMessageType.CONSOLE) + .runeLiteFormattedMessage(message) + .build()); + } } \ No newline at end of file diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/twitch/irc/Message.java b/runelite-client/src/main/java/net/runelite/client/plugins/twitch/irc/Message.java index 604b7a2b46..9b4587cd37 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/twitch/irc/Message.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/twitch/irc/Message.java @@ -1,108 +1,111 @@ -/* - * Copyright (c) 2018, Adam - * 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.twitch.irc; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import lombok.Getter; - -@Getter -class Message -{ - private final Map tags = new HashMap<>(); - private String source; - private String command; - private String[] arguments; - - public static Message parse(String in) - { - Message message = new Message(); - if (in.startsWith("@")) - { - String[] tags = in.substring(1) - .split(";"); - for (String tag : tags) - { - int eq = tag.indexOf('='); - if (eq == -1) continue; - - String key = tag.substring(0, eq); - String value = tag.substring(eq + 1) - .replace("\\:", ";") - .replace("\\s", " ") - .replace("\\\\", "\\") - .replace("\\r", "\r") - .replace("\\n", "\n"); - - message.tags.put(key, value); - } - - int sp = in.indexOf(' '); - in = in.substring(sp + 1); - } - - if (in.startsWith(":")) - { - int sp = in.indexOf(' '); - message.source = in.substring(1, sp); - - in = in.substring(sp + 1); - } - - int sp = in.indexOf(' '); - if (sp == -1) - { - message.command = in; - message.arguments = new String[0]; - return message; - } - - message.command = in.substring(0, sp); - - String args = in.substring(sp + 1); - List argList = new ArrayList<>(); - do - { - String arg; - if (args.startsWith(":")) - { - arg = args.substring(1); - sp = -1; - } - else - { - sp = args.indexOf(' '); - arg = sp == -1 ? args : args.substring(0, sp); - } - args = args.substring(sp + 1); - argList.add(arg); - } while (sp != -1); - - message.arguments = argList.toArray(new String[0]); - return message; - } -} +/* + * Copyright (c) 2018, Adam + * 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.twitch.irc; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import lombok.Getter; + +@Getter +class Message +{ + private final Map tags = new HashMap<>(); + private String source; + private String command; + private String[] arguments; + + public static Message parse(String in) + { + Message message = new Message(); + if (in.startsWith("@")) + { + String[] tags = in.substring(1) + .split(";"); + for (String tag : tags) + { + int eq = tag.indexOf('='); + if (eq == -1) + { + continue; + } + + String key = tag.substring(0, eq); + String value = tag.substring(eq + 1) + .replace("\\:", ";") + .replace("\\s", " ") + .replace("\\\\", "\\") + .replace("\\r", "\r") + .replace("\\n", "\n"); + + message.tags.put(key, value); + } + + int sp = in.indexOf(' '); + in = in.substring(sp + 1); + } + + if (in.startsWith(":")) + { + int sp = in.indexOf(' '); + message.source = in.substring(1, sp); + + in = in.substring(sp + 1); + } + + int sp = in.indexOf(' '); + if (sp == -1) + { + message.command = in; + message.arguments = new String[0]; + return message; + } + + message.command = in.substring(0, sp); + + String args = in.substring(sp + 1); + List argList = new ArrayList<>(); + do + { + String arg; + if (args.startsWith(":")) + { + arg = args.substring(1); + sp = -1; + } + else + { + sp = args.indexOf(' '); + arg = sp == -1 ? args : args.substring(0, sp); + } + args = args.substring(sp + 1); + argList.add(arg); + } while (sp != -1); + + message.arguments = argList.toArray(new String[0]); + return message; + } +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/vanguards/VanguardOverlay.java b/runelite-client/src/main/java/net/runelite/client/plugins/vanguards/VanguardOverlay.java index 88b8207336..e81b96b6df 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/vanguards/VanguardOverlay.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/vanguards/VanguardOverlay.java @@ -1,142 +1,140 @@ -/* - * Copyright (c) 2018, https://runelitepl.us - * 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.vanguards; - -import java.awt.Color; -import java.awt.Dimension; -import java.awt.Graphics2D; - -import net.runelite.api.Actor; -import net.runelite.api.NPC; -import net.runelite.api.Player; -import net.runelite.api.Client; -import net.runelite.client.game.NPCManager; -import net.runelite.client.ui.overlay.Overlay; -import net.runelite.client.ui.overlay.OverlayPosition; -import net.runelite.client.ui.overlay.components.LineComponent; -import net.runelite.client.ui.overlay.components.PanelComponent; -import net.runelite.client.ui.overlay.components.TitleComponent; - -import net.runelite.client.plugins.opponentinfo.OpponentInfoPlugin; -//import net.runelite.client.plugins.opponentinfo.OpponentInfoOverlay; - -import javax.inject.Inject; - -public class VanguardOverlay extends Overlay { - - private VanguardPlugin plugin; - private final PanelComponent panelComponent = new PanelComponent(); - - private static final int MAGE_VANGUARD_ID = 7529; - private static final int RANGE_VANGUARD_ID = 7528; - private static final int MELEE_VANGUARD_ID = 7527; - //private final NPCManager npcManager; - - private int mageHp = -1; - private float magePercent = 0; - - private int rangeHp = -1; - private float rangePercent = 0; - - private int meleeHp = -1; - private float meleePercent = 0; - - public String right_mage_str, right_range_str, right_melee_str = ""; - - @Inject - private Client client; - - - @Inject - public VanguardOverlay(VanguardPlugin plugin) { - super(plugin);//? - this.plugin = plugin; - - setPosition(OverlayPosition.ABOVE_CHATBOX_RIGHT); - //this.opponentInfoPlugin = opponentInfoPlugin; - } - - @Override - public Dimension render(Graphics2D graphics) - { - Player p = client.getLocalPlayer(); //local player aka me - Actor opponent = p.getInteracting(); //get entity i am interacting with - //how to find its Id since it's an Actor not NPC specifically - //if(opponent.getName().equals("Vanguard") && opponent.getHealth() > 0)//might wana double check the name - //{ - if(opponent instanceof NPC) - { - int id = ((NPC) opponent).getId(); - String name = opponent.getName(); - - if(id == MAGE_VANGUARD_ID) //maybe check name.equals("Vanguard") - { - magePercent = (float)opponent.getHealthRatio() / opponent.getHealth() * 100; - mageHp = (int)magePercent; - right_mage_str = Integer.toString(mageHp); - System.out.println("mager"); - } - else if (id == RANGE_VANGUARD_ID) - { - rangePercent = (float)opponent.getHealthRatio() / opponent.getHealth() * 100; - rangeHp = (int)rangePercent; - right_range_str = Integer.toString(rangeHp); - - System.out.println("ranger"); - } - else if (id == MELEE_VANGUARD_ID) - { - meleePercent = (float)opponent.getHealthRatio()/opponent.getHealth() * 100; - meleeHp = (int)meleePercent; - right_melee_str = Integer.toString(meleeHp); - - - System.out.println("meleer"); - } - } - //} - - - //if (opponent == null) { - //} - - - panelComponent.getChildren().clear(); - String overlayTitle = "Vanguard HP"; - //title - panelComponent.getChildren().add(TitleComponent.builder().text(overlayTitle).color(Color.RED).build()); - - //size (width) - panelComponent.setPreferredSize(new Dimension(graphics.getFontMetrics().stringWidth(overlayTitle) + 30, 0)); - - panelComponent.getChildren().add(LineComponent.builder().left("Mage:").right(right_mage_str).build()); - - panelComponent.getChildren().add(LineComponent.builder().left("Range:").right(right_range_str).build()); - - panelComponent.getChildren().add(LineComponent.builder().left("Melee:").right(right_melee_str).build()); - - return panelComponent.render(graphics); - } +/* + * Copyright (c) 2018, https://runelitepl.us + * 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.vanguards; + +import java.awt.Color; +import java.awt.Dimension; +import java.awt.Graphics2D; +import javax.inject.Inject; +import net.runelite.api.Actor; +import net.runelite.api.Client; +import net.runelite.api.NPC; +import net.runelite.api.Player; +import net.runelite.client.ui.overlay.Overlay; +import net.runelite.client.ui.overlay.OverlayPosition; +import net.runelite.client.ui.overlay.components.LineComponent; +import net.runelite.client.ui.overlay.components.PanelComponent; +import net.runelite.client.ui.overlay.components.TitleComponent; + +//import net.runelite.client.plugins.opponentinfo.OpponentInfoOverlay; + +public class VanguardOverlay extends Overlay +{ + + private VanguardPlugin plugin; + private final PanelComponent panelComponent = new PanelComponent(); + + private static final int MAGE_VANGUARD_ID = 7529; + private static final int RANGE_VANGUARD_ID = 7528; + private static final int MELEE_VANGUARD_ID = 7527; + //private final NPCManager npcManager; + + private int mageHp = -1; + private float magePercent = 0; + + private int rangeHp = -1; + private float rangePercent = 0; + + private int meleeHp = -1; + private float meleePercent = 0; + + public String right_mage_str, right_range_str, right_melee_str = ""; + + @Inject + private Client client; + + + @Inject + public VanguardOverlay(VanguardPlugin plugin) + { + super(plugin);//? + this.plugin = plugin; + + setPosition(OverlayPosition.ABOVE_CHATBOX_RIGHT); + //this.opponentInfoPlugin = opponentInfoPlugin; + } + + @Override + public Dimension render(Graphics2D graphics) + { + Player p = client.getLocalPlayer(); //local player aka me + Actor opponent = p.getInteracting(); //get entity i am interacting with + //how to find its Id since it's an Actor not NPC specifically + //if(opponent.getName().equals("Vanguard") && opponent.getHealth() > 0)//might wana double check the name + //{ + if (opponent instanceof NPC) + { + int id = ((NPC) opponent).getId(); + String name = opponent.getName(); + + if (id == MAGE_VANGUARD_ID) //maybe check name.equals("Vanguard") + { + magePercent = (float) opponent.getHealthRatio() / opponent.getHealth() * 100; + mageHp = (int) magePercent; + right_mage_str = Integer.toString(mageHp); + System.out.println("mager"); + } + else if (id == RANGE_VANGUARD_ID) + { + rangePercent = (float) opponent.getHealthRatio() / opponent.getHealth() * 100; + rangeHp = (int) rangePercent; + right_range_str = Integer.toString(rangeHp); + + System.out.println("ranger"); + } + else if (id == MELEE_VANGUARD_ID) + { + meleePercent = (float) opponent.getHealthRatio() / opponent.getHealth() * 100; + meleeHp = (int) meleePercent; + right_melee_str = Integer.toString(meleeHp); + + + System.out.println("meleer"); + } + } + //} + + + //if (opponent == null) { + //} + + + panelComponent.getChildren().clear(); + String overlayTitle = "Vanguard HP"; + //title + panelComponent.getChildren().add(TitleComponent.builder().text(overlayTitle).color(Color.RED).build()); + + //size (width) + panelComponent.setPreferredSize(new Dimension(graphics.getFontMetrics().stringWidth(overlayTitle) + 30, 0)); + + panelComponent.getChildren().add(LineComponent.builder().left("Mage:").right(right_mage_str).build()); + + panelComponent.getChildren().add(LineComponent.builder().left("Range:").right(right_range_str).build()); + + panelComponent.getChildren().add(LineComponent.builder().left("Melee:").right(right_melee_str).build()); + + return panelComponent.render(graphics); + } } \ No newline at end of file diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/vanguards/VanguardPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/vanguards/VanguardPlugin.java index 44c4818ba6..59f0f36b85 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/vanguards/VanguardPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/vanguards/VanguardPlugin.java @@ -1,69 +1,70 @@ -/* - * Copyright (c) 2018, https://runelitepl.us - * 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.vanguards; - -import javax.inject.Inject; -import net.runelite.client.plugins.Plugin; -import net.runelite.client.plugins.PluginDescriptor; -import net.runelite.client.plugins.PluginType; -import net.runelite.client.ui.overlay.OverlayManager; - -@PluginDescriptor( - name= "Vanguard HP Overlay", - description= "tracks HP of all three vanguards", - tags= {"overlay", "vangs", "cox"}, - enabledByDefault = false, - type = PluginType.PVM -) -public class VanguardPlugin extends Plugin { - private static final int MAGE_VANGUARD_ID = 7526; //i think - private static final int RANGE_VANGUARD_ID = 7527; - private static final int MELEE_VANGUARD_ID = 7528; - - - @Inject - private OverlayManager overlayManager; - - @Inject - private VanguardOverlay overlay; - - @Override - protected void startUp() throws Exception - { - overlayManager.add(overlay); - } - - @Override - protected void shutDown() throws Exception - { - overlayManager.remove(overlay); - overlay.right_mage_str = "-"; - overlay.right_range_str = "-"; - overlay.right_melee_str = "-"; - } - - -} - +/* + * Copyright (c) 2018, https://runelitepl.us + * 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.vanguards; + +import javax.inject.Inject; +import net.runelite.client.plugins.Plugin; +import net.runelite.client.plugins.PluginDescriptor; +import net.runelite.client.plugins.PluginType; +import net.runelite.client.ui.overlay.OverlayManager; + +@PluginDescriptor( + name = "Vanguard HP Overlay", + description = "tracks HP of all three vanguards", + tags = {"overlay", "vangs", "cox"}, + enabledByDefault = false, + type = PluginType.PVM +) +public class VanguardPlugin extends Plugin +{ + private static final int MAGE_VANGUARD_ID = 7526; //i think + private static final int RANGE_VANGUARD_ID = 7527; + private static final int MELEE_VANGUARD_ID = 7528; + + + @Inject + private OverlayManager overlayManager; + + @Inject + private VanguardOverlay overlay; + + @Override + protected void startUp() throws Exception + { + overlayManager.add(overlay); + } + + @Override + protected void shutDown() throws Exception + { + overlayManager.remove(overlay); + overlay.right_mage_str = "-"; + overlay.right_range_str = "-"; + overlay.right_melee_str = "-"; + } + + +} + diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/vetion/VetionPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/vetion/VetionPlugin.java index 6e03740426..a17bef71c6 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/vetion/VetionPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/vetion/VetionPlugin.java @@ -24,7 +24,6 @@ */ package net.runelite.client.plugins.vetion; -import com.google.inject.Provides; import java.time.Instant; import java.util.HashMap; import java.util.Map; @@ -32,9 +31,7 @@ import javax.inject.Inject; import lombok.Getter; import net.runelite.api.Actor; import net.runelite.api.AnimationID; -import net.runelite.api.Client; import net.runelite.api.events.AnimationChanged; -import net.runelite.client.config.ConfigManager; import net.runelite.client.eventbus.Subscribe; import net.runelite.client.plugins.Plugin; import net.runelite.client.plugins.PluginDescriptor; diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/warindicators/WarIndicatorPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/warindicators/WarIndicatorPlugin.java index 736599eea1..f627e45dc4 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/warindicators/WarIndicatorPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/warindicators/WarIndicatorPlugin.java @@ -28,7 +28,18 @@ import com.google.inject.Provides; import java.awt.Color; import javax.inject.Inject; import net.runelite.api.Client; -import static net.runelite.api.MenuAction.*; +import static net.runelite.api.MenuAction.FOLLOW; +import static net.runelite.api.MenuAction.ITEM_USE_ON_PLAYER; +import static net.runelite.api.MenuAction.PLAYER_EIGTH_OPTION; +import static net.runelite.api.MenuAction.PLAYER_FIFTH_OPTION; +import static net.runelite.api.MenuAction.PLAYER_FIRST_OPTION; +import static net.runelite.api.MenuAction.PLAYER_FOURTH_OPTION; +import static net.runelite.api.MenuAction.PLAYER_SECOND_OPTION; +import static net.runelite.api.MenuAction.PLAYER_SEVENTH_OPTION; +import static net.runelite.api.MenuAction.PLAYER_SIXTH_OPTION; +import static net.runelite.api.MenuAction.PLAYER_THIRD_OPTION; +import static net.runelite.api.MenuAction.SPELL_CAST_ON_PLAYER; +import static net.runelite.api.MenuAction.TRADE; import net.runelite.api.MenuEntry; import net.runelite.api.Player; import net.runelite.api.events.MenuEntryAdded; diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/wasdcamera/WASDCameraPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/wasdcamera/WASDCameraPlugin.java index f975021369..a60a389674 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/wasdcamera/WASDCameraPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/wasdcamera/WASDCameraPlugin.java @@ -1,210 +1,206 @@ -/*' - * Copyright (c) 2018, Adam - * Copyright (c) 2018, Abexlry - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package net.runelite.client.plugins.wasdcamera; - -import com.google.inject.Provides; -import java.awt.Color; -import javax.inject.Inject; -import lombok.AccessLevel; -import lombok.Getter; -import lombok.Setter; -import net.runelite.api.Client; -import net.runelite.api.GameState; -import net.runelite.api.IconID; -import net.runelite.api.VarClientInt; -import net.runelite.api.VarClientStr; -import net.runelite.api.Varbits; -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.input.KeyManager; -import net.runelite.client.plugins.Plugin; -import net.runelite.client.plugins.PluginDescriptor; -import net.runelite.client.ui.JagexColors; -import net.runelite.client.util.ColorUtil; - -@PluginDescriptor( - name = "WASD Camera", - description = "Allows use of WASD keys for camera movement with 'Press Enter to Chat'", - tags = {"enter", "chat"}, - enabledByDefault = false -) -public class WASDCameraPlugin extends Plugin -{ - private static final String PRESS_ENTER_TO_CHAT = "Press Enter to Chat..."; - private static final String SCRIPT_EVENT_SET_CHATBOX_INPUT = "setChatboxInput"; - private static final String SCRIPT_EVENT_BLOCK_CHAT_INPUT = "blockChatInput"; - - @Inject - private Client client; - - @Inject - private ClientThread clientThread; - - @Inject - private KeyManager keyManager; - - @Inject - private WASDCameraListener inputListener; - - @Getter(AccessLevel.PACKAGE) - @Setter(AccessLevel.PACKAGE) - private boolean typing; - - @Override - protected void startUp() throws Exception - { - typing = false; - keyManager.registerKeyListener(inputListener); - - clientThread.invoke(() -> - { - if (client.getGameState() == GameState.LOGGED_IN) - { - lockChat(); - } - }); - } - - @Override - protected void shutDown() throws Exception - { - clientThread.invoke(() -> - { - if (client.getGameState() == GameState.LOGGED_IN) - { - unlockChat(); - } - }); - - keyManager.unregisterKeyListener(inputListener); - } - - @Provides - WASDCameraConfig getConfig(ConfigManager configManager) - { - return configManager.getConfig(WASDCameraConfig.class); - } - - boolean chatboxFocused() - { - Widget chatboxParent = client.getWidget(WidgetInfo.CHATBOX_PARENT); - if (chatboxParent == null || chatboxParent.getOnKeyListener() == null) - { - return false; - } - - // the search box on the world map can be focused, and chat input goes there, even - // though the chatbox still has its key listener. - Widget worldMapSearch = client.getWidget(WidgetInfo.WORLD_MAP_SEARCH); - if (worldMapSearch != null && client.getVar(VarClientInt.WORLD_MAP_SEARCH_FOCUSED) == 1) - { - return false; - } - - return true; - } - - @Subscribe - public void onScriptCallbackEvent(ScriptCallbackEvent scriptCallbackEvent) - { - switch (scriptCallbackEvent.getEventName()) - { - case SCRIPT_EVENT_SET_CHATBOX_INPUT: - Widget chatboxInput = client.getWidget(WidgetInfo.CHATBOX_INPUT); - if (chatboxInput != null) - { - if (chatboxFocused() && !typing) - { - chatboxInput.setText(getPlayerNameWithIcon() + ": " + PRESS_ENTER_TO_CHAT); - } - } - break; - case SCRIPT_EVENT_BLOCK_CHAT_INPUT: - if (!typing) - { - int[] intStack = client.getIntStack(); - int intStackSize = client.getIntStackSize(); - intStack[intStackSize - 1] = 1; - } - break; - } - } - - void lockChat() - { - Widget chatboxParent = client.getWidget(WidgetInfo.CHATBOX_PARENT); - if (chatboxParent != null && chatboxParent.getOnKeyListener() != null) - { - Widget chatboxInput = client.getWidget(WidgetInfo.CHATBOX_INPUT); - if (chatboxInput != null) - { - chatboxInput.setText(getPlayerNameWithIcon() + ": " + PRESS_ENTER_TO_CHAT); - } - } - } - - void unlockChat() - { - Widget chatboxParent = client.getWidget(WidgetInfo.CHATBOX_PARENT); - if (chatboxParent != null) - { - Widget chatboxInput = client.getWidget(WidgetInfo.CHATBOX_INPUT); - if (chatboxInput != null) - { - if (client.getGameState() == GameState.LOGGED_IN) - { - final boolean isChatboxTransparent = client.isResized() && client.getVar(Varbits.TRANSPARENT_CHATBOX) == 1; - final Color textColor = isChatboxTransparent ? JagexColors.CHAT_TYPED_TEXT_TRANSPARENT_BACKGROUND : JagexColors.CHAT_TYPED_TEXT_OPAQUE_BACKGROUND; - chatboxInput.setText(getPlayerNameWithIcon() + ": " + ColorUtil.wrapWithColorTag(client.getVar(VarClientStr.CHATBOX_TYPED_TEXT) + "*", textColor)); - } - } - } - } - - private String getPlayerNameWithIcon() - { - IconID icon; - switch (client.getAccountType()) - { - case IRONMAN: - icon = IconID.IRONMAN; - break; - case ULTIMATE_IRONMAN: - icon = IconID.ULTIMATE_IRONMAN; - break; - case HARDCORE_IRONMAN: - icon = IconID.HARDCORE_IRONMAN; - break; - default: - return client.getLocalPlayer().getName(); - } - return icon + client.getLocalPlayer().getName(); - } -} +/*' + * Copyright (c) 2018, Adam + * Copyright (c) 2018, Abexlry + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package net.runelite.client.plugins.wasdcamera; + +import com.google.inject.Provides; +import java.awt.Color; +import javax.inject.Inject; +import lombok.AccessLevel; +import lombok.Getter; +import lombok.Setter; +import net.runelite.api.Client; +import net.runelite.api.GameState; +import net.runelite.api.IconID; +import net.runelite.api.VarClientInt; +import net.runelite.api.VarClientStr; +import net.runelite.api.Varbits; +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.input.KeyManager; +import net.runelite.client.plugins.Plugin; +import net.runelite.client.plugins.PluginDescriptor; +import net.runelite.client.ui.JagexColors; +import net.runelite.client.util.ColorUtil; + +@PluginDescriptor( + name = "WASD Camera", + description = "Allows use of WASD keys for camera movement with 'Press Enter to Chat'", + tags = {"enter", "chat"}, + enabledByDefault = false +) +public class WASDCameraPlugin extends Plugin +{ + private static final String PRESS_ENTER_TO_CHAT = "Press Enter to Chat..."; + private static final String SCRIPT_EVENT_SET_CHATBOX_INPUT = "setChatboxInput"; + private static final String SCRIPT_EVENT_BLOCK_CHAT_INPUT = "blockChatInput"; + + @Inject + private Client client; + + @Inject + private ClientThread clientThread; + + @Inject + private KeyManager keyManager; + + @Inject + private WASDCameraListener inputListener; + + @Getter(AccessLevel.PACKAGE) + @Setter(AccessLevel.PACKAGE) + private boolean typing; + + @Override + protected void startUp() throws Exception + { + typing = false; + keyManager.registerKeyListener(inputListener); + + clientThread.invoke(() -> + { + if (client.getGameState() == GameState.LOGGED_IN) + { + lockChat(); + } + }); + } + + @Override + protected void shutDown() throws Exception + { + clientThread.invoke(() -> + { + if (client.getGameState() == GameState.LOGGED_IN) + { + unlockChat(); + } + }); + + keyManager.unregisterKeyListener(inputListener); + } + + @Provides + WASDCameraConfig getConfig(ConfigManager configManager) + { + return configManager.getConfig(WASDCameraConfig.class); + } + + boolean chatboxFocused() + { + Widget chatboxParent = client.getWidget(WidgetInfo.CHATBOX_PARENT); + if (chatboxParent == null || chatboxParent.getOnKeyListener() == null) + { + return false; + } + + // the search box on the world map can be focused, and chat input goes there, even + // though the chatbox still has its key listener. + Widget worldMapSearch = client.getWidget(WidgetInfo.WORLD_MAP_SEARCH); + return worldMapSearch == null || client.getVar(VarClientInt.WORLD_MAP_SEARCH_FOCUSED) != 1; + + } + + @Subscribe + public void onScriptCallbackEvent(ScriptCallbackEvent scriptCallbackEvent) + { + switch (scriptCallbackEvent.getEventName()) + { + case SCRIPT_EVENT_SET_CHATBOX_INPUT: + Widget chatboxInput = client.getWidget(WidgetInfo.CHATBOX_INPUT); + if (chatboxInput != null) + { + if (chatboxFocused() && !typing) + { + chatboxInput.setText(getPlayerNameWithIcon() + ": " + PRESS_ENTER_TO_CHAT); + } + } + break; + case SCRIPT_EVENT_BLOCK_CHAT_INPUT: + if (!typing) + { + int[] intStack = client.getIntStack(); + int intStackSize = client.getIntStackSize(); + intStack[intStackSize - 1] = 1; + } + break; + } + } + + void lockChat() + { + Widget chatboxParent = client.getWidget(WidgetInfo.CHATBOX_PARENT); + if (chatboxParent != null && chatboxParent.getOnKeyListener() != null) + { + Widget chatboxInput = client.getWidget(WidgetInfo.CHATBOX_INPUT); + if (chatboxInput != null) + { + chatboxInput.setText(getPlayerNameWithIcon() + ": " + PRESS_ENTER_TO_CHAT); + } + } + } + + void unlockChat() + { + Widget chatboxParent = client.getWidget(WidgetInfo.CHATBOX_PARENT); + if (chatboxParent != null) + { + Widget chatboxInput = client.getWidget(WidgetInfo.CHATBOX_INPUT); + if (chatboxInput != null) + { + if (client.getGameState() == GameState.LOGGED_IN) + { + final boolean isChatboxTransparent = client.isResized() && client.getVar(Varbits.TRANSPARENT_CHATBOX) == 1; + final Color textColor = isChatboxTransparent ? JagexColors.CHAT_TYPED_TEXT_TRANSPARENT_BACKGROUND : JagexColors.CHAT_TYPED_TEXT_OPAQUE_BACKGROUND; + chatboxInput.setText(getPlayerNameWithIcon() + ": " + ColorUtil.wrapWithColorTag(client.getVar(VarClientStr.CHATBOX_TYPED_TEXT) + "*", textColor)); + } + } + } + } + + private String getPlayerNameWithIcon() + { + IconID icon; + switch (client.getAccountType()) + { + case IRONMAN: + icon = IconID.IRONMAN; + break; + case ULTIMATE_IRONMAN: + icon = IconID.ULTIMATE_IRONMAN; + break; + case HARDCORE_IRONMAN: + icon = IconID.HARDCORE_IRONMAN; + break; + default: + return client.getLocalPlayer().getName(); + } + return icon + client.getLocalPlayer().getName(); + } +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/whalewatchers/WhaleWatchersConfig.java b/runelite-client/src/main/java/net/runelite/client/plugins/whalewatchers/WhaleWatchersConfig.java index 57542c9771..4645107069 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/whalewatchers/WhaleWatchersConfig.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/whalewatchers/WhaleWatchersConfig.java @@ -1,7 +1,5 @@ package net.runelite.client.plugins.whalewatchers; -import java.awt.Color; -import net.runelite.client.config.Alpha; import net.runelite.client.config.Config; import net.runelite.client.config.ConfigGroup; import net.runelite.client.config.ConfigItem; diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/whalewatchers/WhaleWatchersGloryOverlay.java b/runelite-client/src/main/java/net/runelite/client/plugins/whalewatchers/WhaleWatchersGloryOverlay.java index 035433e280..b15b87c431 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/whalewatchers/WhaleWatchersGloryOverlay.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/whalewatchers/WhaleWatchersGloryOverlay.java @@ -15,7 +15,6 @@ import java.awt.Graphics2D; import javax.inject.Inject; import net.runelite.api.Client; import net.runelite.api.ItemID; -import net.runelite.api.kit.KitType; import net.runelite.client.game.AsyncBufferedImage; import net.runelite.client.game.ItemManager; import net.runelite.client.ui.overlay.Overlay; diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/whalewatchers/WhaleWatchersOverlay.java b/runelite-client/src/main/java/net/runelite/client/plugins/whalewatchers/WhaleWatchersOverlay.java index af2be6cb8a..1354054295 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/whalewatchers/WhaleWatchersOverlay.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/whalewatchers/WhaleWatchersOverlay.java @@ -85,7 +85,7 @@ public class WhaleWatchersOverlay extends Overlay else { panelComponent.getChildren().clear(); - + } return panelComponent.render(graphics); } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/whalewatchers/WhaleWatchersPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/whalewatchers/WhaleWatchersPlugin.java index 84bd388644..0ed7fe4e0b 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/whalewatchers/WhaleWatchersPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/whalewatchers/WhaleWatchersPlugin.java @@ -149,14 +149,7 @@ public class WhaleWatchersPlugin extends Plugin { final int amuletID = ObjectUtils.defaultIfNull(client.getLocalPlayer() .getPlayerComposition().getEquipmentId(KitType.AMULET), 0); - if (amuletID == ItemID.AMULET_OF_GLORY) - { - displayGloryOverlay = true; - } - else - { - displayGloryOverlay = false; - } + displayGloryOverlay = amuletID == ItemID.AMULET_OF_GLORY; } else { @@ -254,6 +247,7 @@ public class WhaleWatchersPlugin extends Plugin /** * Checks to see if client is attacking another player + * * @return returns true if they are, false otherwise */ private boolean isAttackingPlayer() diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/whalewatchers/WhaleWatchersProtOverlay.java b/runelite-client/src/main/java/net/runelite/client/plugins/whalewatchers/WhaleWatchersProtOverlay.java index 2b025b1063..ecfc3c3b37 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/whalewatchers/WhaleWatchersProtOverlay.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/whalewatchers/WhaleWatchersProtOverlay.java @@ -1,4 +1,3 @@ - /******************************************************************************* * Copyright (c) 2019. PKLite * Redistributions and modifications of this software are permitted as long as this notice remains in its original unmodified state at the top of this file. diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/whalewatchers/WhaleWatchersSmiteableOverlay.java b/runelite-client/src/main/java/net/runelite/client/plugins/whalewatchers/WhaleWatchersSmiteableOverlay.java index 55b0ef23c7..4be28dce80 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/whalewatchers/WhaleWatchersSmiteableOverlay.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/whalewatchers/WhaleWatchersSmiteableOverlay.java @@ -1,4 +1,3 @@ - /******************************************************************************* * Copyright (c) 2019. PKLite * Redistributions and modifications of this software are permitted as long as this notice remains in its original unmodified state at the top of this file. @@ -59,7 +58,7 @@ public class WhaleWatchersSmiteableOverlay extends Overlay .build()); panelComponent.setPreferredSize(new Dimension(graphics.getFontMetrics().stringWidth(subText) - + 20 , 0)); + + 20, 0)); } else { diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/wiki/WikiSearchChatboxTextInput.java b/runelite-client/src/main/java/net/runelite/client/plugins/wiki/WikiSearchChatboxTextInput.java index ef3b91f9a0..37814ade62 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/wiki/WikiSearchChatboxTextInput.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/wiki/WikiSearchChatboxTextInput.java @@ -1,306 +1,306 @@ -/* - * Copyright (c) 2018 Abex - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package net.runelite.client.plugins.wiki; - -import com.google.common.collect.ImmutableList; -import com.google.common.reflect.TypeToken; -import com.google.gson.Gson; -import com.google.gson.JsonArray; -import com.google.gson.JsonParseException; -import com.google.gson.JsonParser; -import com.google.inject.Inject; -import java.awt.event.KeyEvent; -import java.io.IOException; -import java.util.List; -import java.util.concurrent.Future; -import java.util.concurrent.ScheduledExecutorService; -import java.util.concurrent.TimeUnit; -import javax.inject.Named; -import lombok.extern.slf4j.Slf4j; -import net.runelite.api.widgets.JavaScriptCallback; -import net.runelite.api.widgets.Widget; -import net.runelite.api.widgets.WidgetPositionMode; -import net.runelite.api.widgets.WidgetSizeMode; -import net.runelite.api.widgets.WidgetTextAlignment; -import net.runelite.api.widgets.WidgetType; -import net.runelite.client.callback.ClientThread; -import net.runelite.client.game.chatbox.ChatboxPanelManager; -import net.runelite.client.game.chatbox.ChatboxTextInput; -import net.runelite.client.util.LinkBrowser; -import net.runelite.http.api.RuneLiteAPI; -import okhttp3.Call; -import okhttp3.Callback; -import okhttp3.HttpUrl; -import okhttp3.Request; -import okhttp3.Response; - -@Slf4j -public class WikiSearchChatboxTextInput extends ChatboxTextInput -{ - private static final int LINE_HEIGHT = 20; - private static final int CHATBOX_HEIGHT = 120; - private static final int MAX_NUM_PREDICTIONS = (CHATBOX_HEIGHT / LINE_HEIGHT) - 2; // 1 title, 1 edit - - private static final int PREDICTION_DEBOUNCE_DELAY_MS = 200; - - private final ChatboxPanelManager chatboxPanelManager; - private final Gson gson = new Gson(); - - private Future runningRequest = null; - private List predictions = ImmutableList.of(); - - private int selectedPrediction = -1; - private String offPrediction = null; - - @Inject - public WikiSearchChatboxTextInput(ChatboxPanelManager chatboxPanelManager, ClientThread clientThread, - ScheduledExecutorService scheduledExecutorService, @Named("developerMode") final boolean developerMode) - { - super(chatboxPanelManager, clientThread); - this.chatboxPanelManager = chatboxPanelManager; - - lines(1); - prompt("OSRS Wiki Search"); - onDone(string -> - { - if (string != null && string.length() > 0) - { - search(string); - } - }); - onChanged(searchString -> - { - selectedPrediction = -1; - Future rr = runningRequest; - if (rr != null) - { - rr.cancel(false); - } - if (searchString.length() <= 1) - { - runningRequest = null; - clientThread.invokeLater(() -> - { - predictions = ImmutableList.of(); - update(); - }); - return; - } - runningRequest = scheduledExecutorService.schedule(() -> - { - HttpUrl url = WikiPlugin.WIKI_API.newBuilder() - .addQueryParameter("action", "opensearch") - .addQueryParameter("search", searchString) - .addQueryParameter("redirects", "resolve") - .addQueryParameter("format", "json") - .addQueryParameter("warningsaserror", Boolean.toString(developerMode)) - .build(); - - Request req = new Request.Builder() - .url(url) - .build(); - - RuneLiteAPI.CLIENT.newCall(req).enqueue(new Callback() - { - @Override - public void onFailure(Call call, IOException e) - { - log.warn("error searching wiki", e); - } - - @Override - public void onResponse(Call call, Response response) throws IOException - { - String body = response.body().string(); - try - { - JsonArray jar = new JsonParser().parse(body).getAsJsonArray(); - List apredictions = gson.fromJson(jar.get(1), new TypeToken>() - { - }.getType()); - - if (apredictions.size() > MAX_NUM_PREDICTIONS) - { - apredictions = apredictions.subList(0, MAX_NUM_PREDICTIONS); - } - - final List bpredictions = apredictions; - - clientThread.invokeLater(() -> - { - predictions = bpredictions; - update(); - }); - } - catch (JsonParseException | IllegalStateException | IndexOutOfBoundsException e) - { - log.warn("error parsing wiki response {}", body, e); - } - finally - { - response.close(); - } - } - }); - - runningRequest = null; - }, PREDICTION_DEBOUNCE_DELAY_MS, TimeUnit.MILLISECONDS); - }); - } - - @Override - protected void update() - { - Widget container = chatboxPanelManager.getContainerWidget(); - container.deleteAllChildren(); - - Widget promptWidget = container.createChild(-1, WidgetType.TEXT); - promptWidget.setText(getPrompt()); - promptWidget.setTextColor(0x800000); - promptWidget.setFontId(getFontID()); - promptWidget.setXPositionMode(WidgetPositionMode.ABSOLUTE_CENTER); - promptWidget.setOriginalX(0); - promptWidget.setYPositionMode(WidgetPositionMode.ABSOLUTE_TOP); - promptWidget.setOriginalY(5); - promptWidget.setOriginalHeight(LINE_HEIGHT); - promptWidget.setXTextAlignment(WidgetTextAlignment.CENTER); - promptWidget.setYTextAlignment(WidgetTextAlignment.CENTER); - promptWidget.setWidthMode(WidgetSizeMode.MINUS); - promptWidget.revalidate(); - - buildEdit(0, 5 + LINE_HEIGHT, container.getWidth(), LINE_HEIGHT); - - Widget separator = container.createChild(-1, WidgetType.LINE); - separator.setXPositionMode(WidgetPositionMode.ABSOLUTE_CENTER); - separator.setOriginalX(0); - separator.setYPositionMode(WidgetPositionMode.ABSOLUTE_TOP); - separator.setOriginalY(4 + (LINE_HEIGHT * 2)); - separator.setOriginalHeight(0); - separator.setOriginalWidth(16); - separator.setWidthMode(WidgetSizeMode.MINUS); - separator.revalidate(); - - for (int i = 0; i < predictions.size(); i++) - { - String pred = predictions.get(i); - int y = 6 + (LINE_HEIGHT * (2 + i)); - - Widget bg = container.createChild(-1, WidgetType.RECTANGLE); - bg.setTextColor(0x4444DD); - bg.setFilled(true); - bg.setXPositionMode(WidgetPositionMode.ABSOLUTE_CENTER); - bg.setOriginalX(1); - bg.setYPositionMode(WidgetPositionMode.ABSOLUTE_TOP); - bg.setOriginalY(y); - bg.setOriginalHeight(LINE_HEIGHT); - bg.setOriginalWidth(16); - bg.setWidthMode(WidgetSizeMode.MINUS); - bg.revalidate(); - bg.setName("" + pred); - bg.setAction(0, "Open"); - bg.setHasListener(true); - bg.setOnOpListener((JavaScriptCallback) ev -> search(pred)); - - Widget text = container.createChild(-1, WidgetType.TEXT); - text.setText(pred); - text.setFontId(getFontID()); - text.setXPositionMode(WidgetPositionMode.ABSOLUTE_CENTER); - text.setOriginalX(0); - text.setYPositionMode(WidgetPositionMode.ABSOLUTE_TOP); - text.setOriginalY(y); - text.setOriginalHeight(LINE_HEIGHT); - text.setXTextAlignment(WidgetTextAlignment.CENTER); - text.setYTextAlignment(WidgetTextAlignment.CENTER); - text.setWidthMode(WidgetSizeMode.MINUS); - text.revalidate(); - - if (i == selectedPrediction) - { - text.setTextColor(0xFFFFFF); - } - else - { - bg.setOpacity(255); - text.setTextColor(0x000000); - bg.setOnMouseRepeatListener((JavaScriptCallback) ev -> text.setTextColor(0xFFFFFF)); - bg.setOnMouseLeaveListener((JavaScriptCallback) ev -> text.setTextColor(0x000000)); - } - } - } - - @Override - public void keyPressed(KeyEvent ev) - { - switch (ev.getKeyCode()) - { - case KeyEvent.VK_UP: - ev.consume(); - if (selectedPrediction > -1) - { - selectedPrediction--; - if (selectedPrediction == -1) - { - value(offPrediction); - } - else - { - value(predictions.get(selectedPrediction)); - } - } - break; - case KeyEvent.VK_DOWN: - ev.consume(); - - if (selectedPrediction == -1) - { - offPrediction = getValue(); - } - - selectedPrediction++; - if (selectedPrediction >= predictions.size()) - { - selectedPrediction = predictions.size() - 1; - } - - if (selectedPrediction != -1) - { - value(predictions.get(selectedPrediction)); - } - break; - default: - super.keyPressed(ev); - } - } - - private void search(String search) - { - LinkBrowser.browse(WikiPlugin.WIKI_BASE.newBuilder() - .addQueryParameter("search", search) - .addQueryParameter(WikiPlugin.UTM_SORUCE_KEY, WikiPlugin.UTM_SORUCE_VALUE) - .build() - .toString()); - chatboxPanelManager.close(); - } -} +/* + * Copyright (c) 2018 Abex + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package net.runelite.client.plugins.wiki; + +import com.google.common.collect.ImmutableList; +import com.google.common.reflect.TypeToken; +import com.google.gson.Gson; +import com.google.gson.JsonArray; +import com.google.gson.JsonParseException; +import com.google.gson.JsonParser; +import com.google.inject.Inject; +import java.awt.event.KeyEvent; +import java.io.IOException; +import java.util.List; +import java.util.concurrent.Future; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.TimeUnit; +import javax.inject.Named; +import lombok.extern.slf4j.Slf4j; +import net.runelite.api.widgets.JavaScriptCallback; +import net.runelite.api.widgets.Widget; +import net.runelite.api.widgets.WidgetPositionMode; +import net.runelite.api.widgets.WidgetSizeMode; +import net.runelite.api.widgets.WidgetTextAlignment; +import net.runelite.api.widgets.WidgetType; +import net.runelite.client.callback.ClientThread; +import net.runelite.client.game.chatbox.ChatboxPanelManager; +import net.runelite.client.game.chatbox.ChatboxTextInput; +import net.runelite.client.util.LinkBrowser; +import net.runelite.http.api.RuneLiteAPI; +import okhttp3.Call; +import okhttp3.Callback; +import okhttp3.HttpUrl; +import okhttp3.Request; +import okhttp3.Response; + +@Slf4j +public class WikiSearchChatboxTextInput extends ChatboxTextInput +{ + private static final int LINE_HEIGHT = 20; + private static final int CHATBOX_HEIGHT = 120; + private static final int MAX_NUM_PREDICTIONS = (CHATBOX_HEIGHT / LINE_HEIGHT) - 2; // 1 title, 1 edit + + private static final int PREDICTION_DEBOUNCE_DELAY_MS = 200; + + private final ChatboxPanelManager chatboxPanelManager; + private final Gson gson = new Gson(); + + private Future runningRequest = null; + private List predictions = ImmutableList.of(); + + private int selectedPrediction = -1; + private String offPrediction = null; + + @Inject + public WikiSearchChatboxTextInput(ChatboxPanelManager chatboxPanelManager, ClientThread clientThread, + ScheduledExecutorService scheduledExecutorService, @Named("developerMode") final boolean developerMode) + { + super(chatboxPanelManager, clientThread); + this.chatboxPanelManager = chatboxPanelManager; + + lines(1); + prompt("OSRS Wiki Search"); + onDone(string -> + { + if (string != null && string.length() > 0) + { + search(string); + } + }); + onChanged(searchString -> + { + selectedPrediction = -1; + Future rr = runningRequest; + if (rr != null) + { + rr.cancel(false); + } + if (searchString.length() <= 1) + { + runningRequest = null; + clientThread.invokeLater(() -> + { + predictions = ImmutableList.of(); + update(); + }); + return; + } + runningRequest = scheduledExecutorService.schedule(() -> + { + HttpUrl url = WikiPlugin.WIKI_API.newBuilder() + .addQueryParameter("action", "opensearch") + .addQueryParameter("search", searchString) + .addQueryParameter("redirects", "resolve") + .addQueryParameter("format", "json") + .addQueryParameter("warningsaserror", Boolean.toString(developerMode)) + .build(); + + Request req = new Request.Builder() + .url(url) + .build(); + + RuneLiteAPI.CLIENT.newCall(req).enqueue(new Callback() + { + @Override + public void onFailure(Call call, IOException e) + { + log.warn("error searching wiki", e); + } + + @Override + public void onResponse(Call call, Response response) throws IOException + { + String body = response.body().string(); + try + { + JsonArray jar = new JsonParser().parse(body).getAsJsonArray(); + List apredictions = gson.fromJson(jar.get(1), new TypeToken>() + { + }.getType()); + + if (apredictions.size() > MAX_NUM_PREDICTIONS) + { + apredictions = apredictions.subList(0, MAX_NUM_PREDICTIONS); + } + + final List bpredictions = apredictions; + + clientThread.invokeLater(() -> + { + predictions = bpredictions; + update(); + }); + } + catch (JsonParseException | IllegalStateException | IndexOutOfBoundsException e) + { + log.warn("error parsing wiki response {}", body, e); + } + finally + { + response.close(); + } + } + }); + + runningRequest = null; + }, PREDICTION_DEBOUNCE_DELAY_MS, TimeUnit.MILLISECONDS); + }); + } + + @Override + protected void update() + { + Widget container = chatboxPanelManager.getContainerWidget(); + container.deleteAllChildren(); + + Widget promptWidget = container.createChild(-1, WidgetType.TEXT); + promptWidget.setText(getPrompt()); + promptWidget.setTextColor(0x800000); + promptWidget.setFontId(getFontID()); + promptWidget.setXPositionMode(WidgetPositionMode.ABSOLUTE_CENTER); + promptWidget.setOriginalX(0); + promptWidget.setYPositionMode(WidgetPositionMode.ABSOLUTE_TOP); + promptWidget.setOriginalY(5); + promptWidget.setOriginalHeight(LINE_HEIGHT); + promptWidget.setXTextAlignment(WidgetTextAlignment.CENTER); + promptWidget.setYTextAlignment(WidgetTextAlignment.CENTER); + promptWidget.setWidthMode(WidgetSizeMode.MINUS); + promptWidget.revalidate(); + + buildEdit(0, 5 + LINE_HEIGHT, container.getWidth(), LINE_HEIGHT); + + Widget separator = container.createChild(-1, WidgetType.LINE); + separator.setXPositionMode(WidgetPositionMode.ABSOLUTE_CENTER); + separator.setOriginalX(0); + separator.setYPositionMode(WidgetPositionMode.ABSOLUTE_TOP); + separator.setOriginalY(4 + (LINE_HEIGHT * 2)); + separator.setOriginalHeight(0); + separator.setOriginalWidth(16); + separator.setWidthMode(WidgetSizeMode.MINUS); + separator.revalidate(); + + for (int i = 0; i < predictions.size(); i++) + { + String pred = predictions.get(i); + int y = 6 + (LINE_HEIGHT * (2 + i)); + + Widget bg = container.createChild(-1, WidgetType.RECTANGLE); + bg.setTextColor(0x4444DD); + bg.setFilled(true); + bg.setXPositionMode(WidgetPositionMode.ABSOLUTE_CENTER); + bg.setOriginalX(1); + bg.setYPositionMode(WidgetPositionMode.ABSOLUTE_TOP); + bg.setOriginalY(y); + bg.setOriginalHeight(LINE_HEIGHT); + bg.setOriginalWidth(16); + bg.setWidthMode(WidgetSizeMode.MINUS); + bg.revalidate(); + bg.setName("" + pred); + bg.setAction(0, "Open"); + bg.setHasListener(true); + bg.setOnOpListener((JavaScriptCallback) ev -> search(pred)); + + Widget text = container.createChild(-1, WidgetType.TEXT); + text.setText(pred); + text.setFontId(getFontID()); + text.setXPositionMode(WidgetPositionMode.ABSOLUTE_CENTER); + text.setOriginalX(0); + text.setYPositionMode(WidgetPositionMode.ABSOLUTE_TOP); + text.setOriginalY(y); + text.setOriginalHeight(LINE_HEIGHT); + text.setXTextAlignment(WidgetTextAlignment.CENTER); + text.setYTextAlignment(WidgetTextAlignment.CENTER); + text.setWidthMode(WidgetSizeMode.MINUS); + text.revalidate(); + + if (i == selectedPrediction) + { + text.setTextColor(0xFFFFFF); + } + else + { + bg.setOpacity(255); + text.setTextColor(0x000000); + bg.setOnMouseRepeatListener((JavaScriptCallback) ev -> text.setTextColor(0xFFFFFF)); + bg.setOnMouseLeaveListener((JavaScriptCallback) ev -> text.setTextColor(0x000000)); + } + } + } + + @Override + public void keyPressed(KeyEvent ev) + { + switch (ev.getKeyCode()) + { + case KeyEvent.VK_UP: + ev.consume(); + if (selectedPrediction > -1) + { + selectedPrediction--; + if (selectedPrediction == -1) + { + value(offPrediction); + } + else + { + value(predictions.get(selectedPrediction)); + } + } + break; + case KeyEvent.VK_DOWN: + ev.consume(); + + if (selectedPrediction == -1) + { + offPrediction = getValue(); + } + + selectedPrediction++; + if (selectedPrediction >= predictions.size()) + { + selectedPrediction = predictions.size() - 1; + } + + if (selectedPrediction != -1) + { + value(predictions.get(selectedPrediction)); + } + break; + default: + super.keyPressed(ev); + } + } + + private void search(String search) + { + LinkBrowser.browse(WikiPlugin.WIKI_BASE.newBuilder() + .addQueryParameter("search", search) + .addQueryParameter(WikiPlugin.UTM_SORUCE_KEY, WikiPlugin.UTM_SORUCE_VALUE) + .build() + .toString()); + chatboxPanelManager.close(); + } +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/wildernesslocations/WildernessLocationsConfig.java b/runelite-client/src/main/java/net/runelite/client/plugins/wildernesslocations/WildernessLocationsConfig.java index 91545b3074..f7365e32e1 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/wildernesslocations/WildernessLocationsConfig.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/wildernesslocations/WildernessLocationsConfig.java @@ -6,7 +6,7 @@ * Written by PKLite(ST0NEWALL, others) , 2019 * */ - + package net.runelite.client.plugins.wildernesslocations; import net.runelite.client.config.Config; @@ -17,7 +17,7 @@ import net.runelite.client.config.Keybind; @ConfigGroup("wildernesslocations") public interface WildernessLocationsConfig extends Config { - + @ConfigItem( keyName = "drawOverlay", name = "Draw Overlay", @@ -28,7 +28,7 @@ public interface WildernessLocationsConfig extends Config { return true; } - + @ConfigItem( keyName = "keybind", name = "Send to CC", @@ -39,5 +39,5 @@ public interface WildernessLocationsConfig extends Config { return Keybind.NOT_SET; } - + } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/wildernesslocations/WildernessLocationsOverlay.java b/runelite-client/src/main/java/net/runelite/client/plugins/wildernesslocations/WildernessLocationsOverlay.java index 8bae506748..41ad66e7d2 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/wildernesslocations/WildernessLocationsOverlay.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/wildernesslocations/WildernessLocationsOverlay.java @@ -6,13 +6,12 @@ * Written by PKLite(ST0NEWALL, others) , 2019 * */ - + package net.runelite.client.plugins.wildernesslocations; import java.awt.Dimension; import java.awt.Graphics2D; import javax.inject.Inject; -import net.runelite.api.Client; import net.runelite.client.ui.overlay.Overlay; import net.runelite.client.ui.overlay.OverlayLayer; import net.runelite.client.ui.overlay.OverlayPosition; @@ -23,7 +22,7 @@ public class WildernessLocationsOverlay extends Overlay { private final WildernessLocationsPlugin plugin; private TextComponent textComponent; - + @Inject private WildernessLocationsConfig wildyConfig; diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/worldhopper/WorldHopperConfig.java b/runelite-client/src/main/java/net/runelite/client/plugins/worldhopper/WorldHopperConfig.java index bce9a3ef15..ea770dadda 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/worldhopper/WorldHopperConfig.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/worldhopper/WorldHopperConfig.java @@ -1,126 +1,126 @@ -/* - * Copyright (c) 2018, Lotto - * 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.worldhopper; - -import java.awt.event.InputEvent; -import java.awt.event.KeyEvent; -import net.runelite.client.config.Config; -import net.runelite.client.config.ConfigGroup; -import net.runelite.client.config.ConfigItem; -import net.runelite.client.config.Keybind; - -@ConfigGroup(WorldHopperConfig.GROUP) -public interface WorldHopperConfig extends Config -{ - String GROUP = "worldhopper"; - - @ConfigItem( - keyName = "previousKey", - name = "Quick-hop previous", - description = "When you press this key you'll hop to the previous world", - position = 0 - ) - default Keybind previousKey() - { - return new Keybind(KeyEvent.VK_LEFT, InputEvent.CTRL_DOWN_MASK | InputEvent.SHIFT_DOWN_MASK); - } - - @ConfigItem( - keyName = "nextKey", - name = "Quick-hop next", - description = "When you press this key you'll hop to the next world", - position = 1 - ) - default Keybind nextKey() - { - return new Keybind(KeyEvent.VK_RIGHT, InputEvent.CTRL_DOWN_MASK | InputEvent.SHIFT_DOWN_MASK); - } - - @ConfigItem( - keyName = "quickhopOutOfDanger", - name = "Quick-hop out of dangerous worlds", - description = "Don't hop to a PVP/high risk world when quick-hopping", - position = 2 - ) - default boolean quickhopOutOfDanger() - { - return true; - } - - @ConfigItem( - keyName = "showSidebar", - name = "Show world hopper sidebar", - description = "Show sidebar containing all worlds that mimics in-game interface", - position = 3 - ) - default boolean showSidebar() - { - return true; - } - - @ConfigItem( - keyName = "ping", - name = "Show world ping", - description = "Shows ping to each game world", - position = 4 - ) - default boolean ping() - { - return true; - } - - @ConfigItem( - keyName = "showMessage", - name = "Show world hop message in chat", - description = "Shows what world is being hopped to in the chat", - position = 5 - ) - default boolean showWorldHopMessage() - { - return true; - } - - @ConfigItem( - keyName = "subscriptionFilter", - name = "Show subscription types", - description = "Only show free worlds, member worlds, or both types of worlds in sidebar", - position = 6 - ) - default SubscriptionFilterMode subscriptionFilter() - { - return SubscriptionFilterMode.BOTH; - } - - @ConfigItem( - keyName = "showHistory", - name = "Show history tab", - description = "Shows the history tab", - position = 7 - ) - default boolean showHistory() - { - return true; - } -} +/* + * Copyright (c) 2018, Lotto + * 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.worldhopper; + +import java.awt.event.InputEvent; +import java.awt.event.KeyEvent; +import net.runelite.client.config.Config; +import net.runelite.client.config.ConfigGroup; +import net.runelite.client.config.ConfigItem; +import net.runelite.client.config.Keybind; + +@ConfigGroup(WorldHopperConfig.GROUP) +public interface WorldHopperConfig extends Config +{ + String GROUP = "worldhopper"; + + @ConfigItem( + keyName = "previousKey", + name = "Quick-hop previous", + description = "When you press this key you'll hop to the previous world", + position = 0 + ) + default Keybind previousKey() + { + return new Keybind(KeyEvent.VK_LEFT, InputEvent.CTRL_DOWN_MASK | InputEvent.SHIFT_DOWN_MASK); + } + + @ConfigItem( + keyName = "nextKey", + name = "Quick-hop next", + description = "When you press this key you'll hop to the next world", + position = 1 + ) + default Keybind nextKey() + { + return new Keybind(KeyEvent.VK_RIGHT, InputEvent.CTRL_DOWN_MASK | InputEvent.SHIFT_DOWN_MASK); + } + + @ConfigItem( + keyName = "quickhopOutOfDanger", + name = "Quick-hop out of dangerous worlds", + description = "Don't hop to a PVP/high risk world when quick-hopping", + position = 2 + ) + default boolean quickhopOutOfDanger() + { + return true; + } + + @ConfigItem( + keyName = "showSidebar", + name = "Show world hopper sidebar", + description = "Show sidebar containing all worlds that mimics in-game interface", + position = 3 + ) + default boolean showSidebar() + { + return true; + } + + @ConfigItem( + keyName = "ping", + name = "Show world ping", + description = "Shows ping to each game world", + position = 4 + ) + default boolean ping() + { + return true; + } + + @ConfigItem( + keyName = "showMessage", + name = "Show world hop message in chat", + description = "Shows what world is being hopped to in the chat", + position = 5 + ) + default boolean showWorldHopMessage() + { + return true; + } + + @ConfigItem( + keyName = "subscriptionFilter", + name = "Show subscription types", + description = "Only show free worlds, member worlds, or both types of worlds in sidebar", + position = 6 + ) + default SubscriptionFilterMode subscriptionFilter() + { + return SubscriptionFilterMode.BOTH; + } + + @ConfigItem( + keyName = "showHistory", + name = "Show history tab", + description = "Shows the history tab", + position = 7 + ) + default boolean showHistory() + { + return true; + } +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/worldhopper/WorldHopperPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/worldhopper/WorldHopperPlugin.java index 64a7806666..33852bc40f 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/worldhopper/WorldHopperPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/worldhopper/WorldHopperPlugin.java @@ -75,13 +75,13 @@ import net.runelite.client.eventbus.Subscribe; import net.runelite.client.input.KeyManager; import net.runelite.client.plugins.Plugin; import net.runelite.client.plugins.PluginDescriptor; -import net.runelite.client.util.ping.Ping; import net.runelite.client.ui.ClientToolbar; import net.runelite.client.ui.NavigationButton; import net.runelite.client.util.ExecutorServiceExceptionLogger; import net.runelite.client.util.HotkeyListener; import net.runelite.client.util.Text; import net.runelite.client.util.WorldUtil; +import net.runelite.client.util.ping.Ping; import net.runelite.http.api.worlds.World; import net.runelite.http.api.worlds.WorldClient; import net.runelite.http.api.worlds.WorldResult; diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/worldhopper/WorldSwitcherPanel.java b/runelite-client/src/main/java/net/runelite/client/plugins/worldhopper/WorldSwitcherPanel.java index 28f299ed0e..acfd4b25ea 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/worldhopper/WorldSwitcherPanel.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/worldhopper/WorldSwitcherPanel.java @@ -1,645 +1,644 @@ -/* - * Copyright (c) 2018, Psikoi - * 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.worldhopper; - -import java.awt.Component; -import java.awt.GridBagConstraints; -import java.awt.GridLayout; -import java.awt.GridBagLayout; -import java.awt.Color; -import java.awt.BorderLayout; -import java.awt.Dimension; -import java.awt.event.MouseAdapter; -import java.awt.event.MouseEvent; -import java.util.List; -import java.util.ArrayList; -import java.util.Map; -import java.util.Iterator; -import java.util.LinkedHashMap; -import java.util.HashMap; -import java.util.stream.Collectors; -import javax.swing.JPanel; -import javax.swing.JButton; -import javax.swing.JTabbedPane; -import javax.swing.border.Border; -import javax.swing.BorderFactory; -import javax.swing.SwingUtilities; -import lombok.AccessLevel; -import lombok.Setter; - -import lombok.extern.slf4j.Slf4j; -import net.runelite.client.ui.ColorScheme; -import net.runelite.client.ui.DynamicGridLayout; -import net.runelite.client.ui.PluginPanel; -import net.runelite.http.api.worlds.World; -import net.runelite.http.api.worlds.WorldType; - -@Slf4j -class WorldSwitcherPanel extends PluginPanel -{ - private static final Color ODD_ROW = new Color(44, 44, 44); - - private static final int WORLD_COLUMN_WIDTH = 60; - private static final int PLAYERS_COLUMN_WIDTH = 40; - private static final int PING_COLUMN_WIDTH = 47; - - private final JPanel headerContainer; - private final JPanel headerHistContainer; - private final JPanel listContainer = new JPanel(); - private final JPanel histContainer = new JPanel(); - - private WorldTableHeader worldHeader; - private WorldTableHeader playersHeader; - private WorldTableHeader activityHeader; - private WorldTableHeader pingHeader; - - private WorldOrder orderIndex = WorldOrder.WORLD; - private boolean ascendingOrder = true; - - private ArrayList rows = new ArrayList<>(); - private ArrayList histRows = new ArrayList<>(); - private WorldHopperPlugin plugin; - @Setter(AccessLevel.PACKAGE) - private SubscriptionFilterMode filterMode; - - WorldSwitcherPanel(WorldHopperPlugin plugin) - { - this.plugin = plugin; - - setBorder(null); - setLayout(new DynamicGridLayout(0, 1)); - - headerContainer = buildHeader(); - headerHistContainer = buildHistoryHeader(); - - listContainer.setLayout(new GridLayout(0, 1)); - histContainer.setLayout(new GridLayout(0, 1)); - - updateLayout(); - } - - void updateLayout() - { - if (this.getComponentCount() > 0) - { - for (Component c : this.getComponents()) - { - this.remove(c); - } - } - - if (plugin.showHistory()) - { - Component tabs = createTabs(); - add(tabs); - } - else - { - add(headerContainer); - add(listContainer); - } - } - - void switchCurrentHighlight(int newWorld, int lastWorld) - { - for (WorldTableRow row : rows) - { - if (row.getWorld().getId() == newWorld) - { - row.recolour(true); - } - else if (row.getWorld().getId() == lastWorld) - { - row.recolour(false); - } - } - - for (WorldTableRow row : histRows) - { - if (row.getWorld().getId() == newWorld) - { - row.recolour(true); - } - else if (row.getWorld().getId() == lastWorld) - { - row.recolour(false); - } - } - } - - void updateListData(Map worldData) - { - for (WorldTableRow worldTableRow : rows) - { - World world = worldTableRow.getWorld(); - Integer playerCount = worldData.get(world.getId()); - if (playerCount != null) - { - worldTableRow.updatePlayerCount(playerCount); - } - } - - for (WorldTableRow worldTableRow : histRows) - { - World world = worldTableRow.getWorld(); - Integer playerCount = worldData.get(world.getId()); - if (playerCount != null) - { - worldTableRow.updatePlayerCount(playerCount); - } - } - - // If the list is being ordered by player count, then it has to be re-painted - // to properly display the new data - if (orderIndex == WorldOrder.PLAYERS) - { - updateList(); - } - } - - void updatePing(int world, int ping) - { - for (WorldTableRow worldTableRow : rows) - { - if (worldTableRow.getWorld().getId() == world) - { - worldTableRow.setPing(ping); - - // If the panel is sorted by ping, re-sort it - if (orderIndex == WorldOrder.PING) - { - updateList(); - } - break; - } - } - - for (WorldTableRow worldTableRow : histRows) - { - if (worldTableRow.getWorld().getId() == world) - { - worldTableRow.setPing(ping); - - // If the panel is sorted by ping, re-sort it - if (orderIndex == WorldOrder.PING) - { - updateList(); - } - break; - } - } - } - - void hidePing() - { - for (WorldTableRow worldTableRow : rows) - { - worldTableRow.hidePing(); - } - - for (WorldTableRow worldTableRow : histRows) - { - worldTableRow.hidePing(); - } - } - - void showPing() - { - for (WorldTableRow worldTableRow : rows) - { - worldTableRow.showPing(); - } - - for (WorldTableRow worldTableRow : histRows) - { - worldTableRow.showPing(); - } - } - - void updateList() - { - rows.sort((r1, r2) -> - { - switch (orderIndex) - { - case PING: - return Integer.compare(r1.getPing(), r2.getPing()) * (ascendingOrder ? 1 : -1); - case WORLD: - return Integer.compare(r1.getWorld().getId(), r2.getWorld().getId()) * (ascendingOrder ? 1 : -1); - case PLAYERS: - return Integer.compare(r1.getUpdatedPlayerCount(), r2.getUpdatedPlayerCount()) * (ascendingOrder ? 1 : -1); - case ACTIVITY: - return r1.getWorld().getActivity().compareTo(r2.getWorld().getActivity()) * -1 * (ascendingOrder ? 1 : -1); - default: - return 0; - } - }); - - // Leave empty activity worlds on the bottom of the list - if (orderIndex == WorldOrder.ACTIVITY) - { - rows.sort((r1, r2) -> r1.getWorld().getActivity().equals("-") ? 1 : -1); - } - - rows.sort((r1, r2) -> - { - boolean b1 = plugin.isFavorite(r1.getWorld()); - boolean b2 = plugin.isFavorite(r2.getWorld()); - return Boolean.compare(b2, b1); - }); - - listContainer.removeAll(); - histContainer.removeAll(); - - Map history = plugin.getHistory(); - Map matchedHist = new HashMap<>(); - for (int i = 0; i < rows.size(); i++) - { - WorldTableRow row = rows.get(i); - row.setBackground(i % 2 == 0 ? ODD_ROW : ColorScheme.DARK_GRAY_COLOR); - listContainer.add(row); - - String worldNum = String.valueOf(row.getWorld().getId()); - if (history.containsKey(worldNum)) - { - // Add toa list that we can sort later - matchedHist.put(worldNum, history.get(worldNum)); - } - } - - // Sort by ascending - matchedHist = matchedHist.entrySet().stream() - .sorted(Map.Entry.comparingByValue().reversed()) - .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, - (e1, e2) -> e1, LinkedHashMap::new)); - - // Add matched rows to history list - Iterator it = matchedHist.entrySet().iterator(); - int histRowCount = 0; - while (it.hasNext()) - { - Map.Entry pair = (Map.Entry)it.next(); - for (WorldTableRow r : rows) - { - WorldTableRow histRow = r; - histRow.setBackground(histRowCount % 2 == 0 ? ODD_ROW : ColorScheme.DARK_GRAY_COLOR); - if (String.valueOf(r.getWorld().getId()).equals(pair.getKey())) - { - histContainer.add(r); - histRowCount++; - break; - } - } - it.remove(); - } - - listContainer.revalidate(); - listContainer.repaint(); - histContainer.revalidate(); - histContainer.repaint(); - } - - Component createTabs() - { - // Constraints for GB Layout - GridBagConstraints listConst = new GridBagConstraints(); - listConst.gridx = 0; - listConst.gridy = 1; - listConst.fill = GridBagConstraints.HORIZONTAL; - GridBagConstraints headConst = new GridBagConstraints(); - headConst.gridx = 0; - headConst.gridy = 0; - headConst.fill = GridBagConstraints.HORIZONTAL; - GridBagConstraints resetConst = new GridBagConstraints(); - resetConst.gridx = 0; - resetConst.gridy = 2; - resetConst.fill = GridBagConstraints.HORIZONTAL; - - // Border so that the scrollbar doesn't go over ping - Border paddingBorder = BorderFactory.createEmptyBorder(0, 0, 0, 5); - - // Clear history button - JButton resetBtn = new JButton("Clear History"); - resetBtn.addActionListener(e -> - { - plugin.clearHistory(); - plugin.addToHistory(); - updateList(); - }); - - // World Selector page - JPanel worldPanel = new JPanel(); - worldPanel.setBorder(paddingBorder); - worldPanel.setLayout(new GridBagLayout()); - worldPanel.add(headerContainer, headConst); - worldPanel.add(listContainer, listConst); - - // History page - JPanel histPanel = new JPanel(); - histPanel.setBorder(paddingBorder); - histPanel.setLayout(new GridBagLayout()); - histPanel.add(headerHistContainer, headConst); - histPanel.add(histContainer, listConst); - histPanel.add(resetBtn, resetConst); - - JTabbedPane worldTabs = new JTabbedPane(); - worldTabs.setName("tabs"); - worldTabs.addTab("Worlds", worldPanel); - worldTabs.addTab("History", histPanel); - - // This is a fix for preventing stretching of WorldTableRows - worldTabs.addChangeListener(e -> - { - switch (worldTabs.getSelectedIndex()) - { - case 0: - histPanel.remove(histContainer); - if (worldPanel.getComponentCount() < 2) - { - worldPanel.add(listContainer, listConst); - } - break; - case 1: - worldPanel.remove(listContainer); - if (histPanel.getComponentCount() < 3) - { - histPanel.add(histContainer, listConst); - } - break; - } - }); - - return worldTabs; - } - - void updateFavoriteMenu(int world, boolean favorite) - { - for (WorldTableRow row : rows) - { - if (row.getWorld().getId() == world) - { - row.setFavoriteMenu(favorite); - } - } - - for (WorldTableRow row : histRows) - { - if (row.getWorld().getId() == world) - { - row.setFavoriteMenu(favorite); - } - } - } - - void resetAllFavoriteMenus() - { - for (WorldTableRow row : rows) - { - row.setFavoriteMenu(false); - } - - for (WorldTableRow row : histRows) - { - row.setFavoriteMenu(false); - } - } - - void populate(List worlds) - { - Map pingHistory = new HashMap<>(); - - for (WorldTableRow row : rows) - { - pingHistory.put(row.getWorld().getId(), row.getPing()); - } - - rows.clear(); - - for (int i = 0; i < worlds.size(); i++) - { - World world = worlds.get(i); - - switch (filterMode) - { - case FREE: - if (world.getTypes().contains(WorldType.MEMBERS)) - { - continue; - } - break; - case MEMBERS: - if (!world.getTypes().contains(WorldType.MEMBERS)) - { - continue; - } - break; - } - - Integer ping = pingHistory.getOrDefault(world.getId(), 0); - rows.add(buildRow(world, i % 2 == 0, world.getId() == plugin.getCurrentWorld() && plugin.getLastWorld() != 0, plugin.isFavorite(world), ping)); - } - - updateList(); - } - - private void orderBy(WorldOrder order) - { - pingHeader.highlight(false, ascendingOrder); - worldHeader.highlight(false, ascendingOrder); - playersHeader.highlight(false, ascendingOrder); - activityHeader.highlight(false, ascendingOrder); - - switch (order) - { - case PING: - pingHeader.highlight(true, ascendingOrder); - break; - case WORLD: - worldHeader.highlight(true, ascendingOrder); - break; - case PLAYERS: - playersHeader.highlight(true, ascendingOrder); - break; - case ACTIVITY: - activityHeader.highlight(true, ascendingOrder); - break; - } - - orderIndex = order; - updateList(); - } - - /** - * Builds the entire table header. - */ - private JPanel buildHistoryHeader() - { - JPanel header = new JPanel(new BorderLayout()); - JPanel leftSide = new JPanel(new BorderLayout()); - JPanel rightSide = new JPanel(new BorderLayout()); - - WorldTableHeader pingHeader = new WorldTableHeader("Ping", false, ascendingOrder, plugin::refresh); - pingHeader.setPreferredSize(new Dimension(PING_COLUMN_WIDTH, 0)); - - WorldTableHeader worldHeader = new WorldTableHeader("World", false, ascendingOrder, plugin::refresh); - worldHeader.setPreferredSize(new Dimension(WORLD_COLUMN_WIDTH, 0)); - - WorldTableHeader playersHeader = new WorldTableHeader("#", false, ascendingOrder, plugin::refresh); - playersHeader.setPreferredSize(new Dimension(PLAYERS_COLUMN_WIDTH, 0)); - - WorldTableHeader activityHeader = new WorldTableHeader("Activity", false, ascendingOrder, plugin::refresh); - - leftSide.add(worldHeader, BorderLayout.WEST); - leftSide.add(playersHeader, BorderLayout.CENTER); - - rightSide.add(activityHeader, BorderLayout.CENTER); - rightSide.add(pingHeader, BorderLayout.EAST); - - header.add(leftSide, BorderLayout.WEST); - header.add(rightSide, BorderLayout.CENTER); - - return header; - } - - private JPanel buildHeader() - { - JPanel header = new JPanel(new BorderLayout()); - JPanel leftSide = new JPanel(new BorderLayout()); - JPanel rightSide = new JPanel(new BorderLayout()); - - pingHeader = new WorldTableHeader("Ping", orderIndex == WorldOrder.PING, ascendingOrder, plugin::refresh); - pingHeader.setPreferredSize(new Dimension(PING_COLUMN_WIDTH, 0)); - pingHeader.addMouseListener(new MouseAdapter() - { - @Override - public void mousePressed(MouseEvent mouseEvent) - { - if (SwingUtilities.isRightMouseButton(mouseEvent)) - { - return; - } - ascendingOrder = orderIndex != WorldOrder.PING || !ascendingOrder; - orderBy(WorldOrder.PING); - } - }); - - worldHeader = new WorldTableHeader("World", orderIndex == WorldOrder.WORLD, ascendingOrder, plugin::refresh); - worldHeader.setPreferredSize(new Dimension(WORLD_COLUMN_WIDTH, 0)); - worldHeader.addMouseListener(new MouseAdapter() - { - @Override - public void mousePressed(MouseEvent mouseEvent) - { - if (SwingUtilities.isRightMouseButton(mouseEvent)) - { - return; - } - ascendingOrder = orderIndex != WorldOrder.WORLD || !ascendingOrder; - orderBy(WorldOrder.WORLD); - } - }); - - playersHeader = new WorldTableHeader("#", orderIndex == WorldOrder.PLAYERS, ascendingOrder, plugin::refresh); - playersHeader.setPreferredSize(new Dimension(PLAYERS_COLUMN_WIDTH, 0)); - playersHeader.addMouseListener(new MouseAdapter() - { - @Override - public void mousePressed(MouseEvent mouseEvent) - { - if (SwingUtilities.isRightMouseButton(mouseEvent)) - { - return; - } - ascendingOrder = orderIndex != WorldOrder.PLAYERS || !ascendingOrder; - orderBy(WorldOrder.PLAYERS); - } - }); - - activityHeader = new WorldTableHeader("Activity", orderIndex == WorldOrder.ACTIVITY, ascendingOrder, plugin::refresh); - activityHeader.addMouseListener(new MouseAdapter() - { - @Override - public void mousePressed(MouseEvent mouseEvent) - { - if (SwingUtilities.isRightMouseButton(mouseEvent)) - { - return; - } - ascendingOrder = orderIndex != WorldOrder.ACTIVITY || !ascendingOrder; - orderBy(WorldOrder.ACTIVITY); - } - }); - - leftSide.add(worldHeader, BorderLayout.WEST); - leftSide.add(playersHeader, BorderLayout.CENTER); - - rightSide.add(activityHeader, BorderLayout.CENTER); - rightSide.add(pingHeader, BorderLayout.EAST); - - header.add(leftSide, BorderLayout.WEST); - header.add(rightSide, BorderLayout.CENTER); - - return header; - } - - /** - * Builds a table row, that displays the world's information. - */ - private WorldTableRow buildRow(World world, boolean stripe, boolean current, boolean favorite, Integer ping) - { - WorldTableRow row = new WorldTableRow(world, current, favorite, - world1 -> - { - plugin.hopTo(world1); - }, - (world12, add) -> - { - if (add) - { - plugin.addToFavorites(world12); - } - else - { - plugin.removeFromFavorites(world12); - } - - updateList(); - } - ); - row.setBackground(stripe ? ODD_ROW : ColorScheme.DARK_GRAY_COLOR); - return row; - } - - /** - * Enumerates the multiple ordering options for the world list. - */ - private enum WorldOrder - { - WORLD, - PLAYERS, - ACTIVITY, - PING - } -} +/* + * Copyright (c) 2018, Psikoi + * 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.worldhopper; + +import java.awt.BorderLayout; +import java.awt.Color; +import java.awt.Component; +import java.awt.Dimension; +import java.awt.GridBagConstraints; +import java.awt.GridBagLayout; +import java.awt.GridLayout; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Iterator; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; +import javax.swing.BorderFactory; +import javax.swing.JButton; +import javax.swing.JPanel; +import javax.swing.JTabbedPane; +import javax.swing.SwingUtilities; +import javax.swing.border.Border; +import lombok.AccessLevel; +import lombok.Setter; +import lombok.extern.slf4j.Slf4j; +import net.runelite.client.ui.ColorScheme; +import net.runelite.client.ui.DynamicGridLayout; +import net.runelite.client.ui.PluginPanel; +import net.runelite.http.api.worlds.World; +import net.runelite.http.api.worlds.WorldType; + +@Slf4j +class WorldSwitcherPanel extends PluginPanel +{ + private static final Color ODD_ROW = new Color(44, 44, 44); + + private static final int WORLD_COLUMN_WIDTH = 60; + private static final int PLAYERS_COLUMN_WIDTH = 40; + private static final int PING_COLUMN_WIDTH = 47; + + private final JPanel headerContainer; + private final JPanel headerHistContainer; + private final JPanel listContainer = new JPanel(); + private final JPanel histContainer = new JPanel(); + + private WorldTableHeader worldHeader; + private WorldTableHeader playersHeader; + private WorldTableHeader activityHeader; + private WorldTableHeader pingHeader; + + private WorldOrder orderIndex = WorldOrder.WORLD; + private boolean ascendingOrder = true; + + private ArrayList rows = new ArrayList<>(); + private ArrayList histRows = new ArrayList<>(); + private WorldHopperPlugin plugin; + @Setter(AccessLevel.PACKAGE) + private SubscriptionFilterMode filterMode; + + WorldSwitcherPanel(WorldHopperPlugin plugin) + { + this.plugin = plugin; + + setBorder(null); + setLayout(new DynamicGridLayout(0, 1)); + + headerContainer = buildHeader(); + headerHistContainer = buildHistoryHeader(); + + listContainer.setLayout(new GridLayout(0, 1)); + histContainer.setLayout(new GridLayout(0, 1)); + + updateLayout(); + } + + void updateLayout() + { + if (this.getComponentCount() > 0) + { + for (Component c : this.getComponents()) + { + this.remove(c); + } + } + + if (plugin.showHistory()) + { + Component tabs = createTabs(); + add(tabs); + } + else + { + add(headerContainer); + add(listContainer); + } + } + + void switchCurrentHighlight(int newWorld, int lastWorld) + { + for (WorldTableRow row : rows) + { + if (row.getWorld().getId() == newWorld) + { + row.recolour(true); + } + else if (row.getWorld().getId() == lastWorld) + { + row.recolour(false); + } + } + + for (WorldTableRow row : histRows) + { + if (row.getWorld().getId() == newWorld) + { + row.recolour(true); + } + else if (row.getWorld().getId() == lastWorld) + { + row.recolour(false); + } + } + } + + void updateListData(Map worldData) + { + for (WorldTableRow worldTableRow : rows) + { + World world = worldTableRow.getWorld(); + Integer playerCount = worldData.get(world.getId()); + if (playerCount != null) + { + worldTableRow.updatePlayerCount(playerCount); + } + } + + for (WorldTableRow worldTableRow : histRows) + { + World world = worldTableRow.getWorld(); + Integer playerCount = worldData.get(world.getId()); + if (playerCount != null) + { + worldTableRow.updatePlayerCount(playerCount); + } + } + + // If the list is being ordered by player count, then it has to be re-painted + // to properly display the new data + if (orderIndex == WorldOrder.PLAYERS) + { + updateList(); + } + } + + void updatePing(int world, int ping) + { + for (WorldTableRow worldTableRow : rows) + { + if (worldTableRow.getWorld().getId() == world) + { + worldTableRow.setPing(ping); + + // If the panel is sorted by ping, re-sort it + if (orderIndex == WorldOrder.PING) + { + updateList(); + } + break; + } + } + + for (WorldTableRow worldTableRow : histRows) + { + if (worldTableRow.getWorld().getId() == world) + { + worldTableRow.setPing(ping); + + // If the panel is sorted by ping, re-sort it + if (orderIndex == WorldOrder.PING) + { + updateList(); + } + break; + } + } + } + + void hidePing() + { + for (WorldTableRow worldTableRow : rows) + { + worldTableRow.hidePing(); + } + + for (WorldTableRow worldTableRow : histRows) + { + worldTableRow.hidePing(); + } + } + + void showPing() + { + for (WorldTableRow worldTableRow : rows) + { + worldTableRow.showPing(); + } + + for (WorldTableRow worldTableRow : histRows) + { + worldTableRow.showPing(); + } + } + + void updateList() + { + rows.sort((r1, r2) -> + { + switch (orderIndex) + { + case PING: + return Integer.compare(r1.getPing(), r2.getPing()) * (ascendingOrder ? 1 : -1); + case WORLD: + return Integer.compare(r1.getWorld().getId(), r2.getWorld().getId()) * (ascendingOrder ? 1 : -1); + case PLAYERS: + return Integer.compare(r1.getUpdatedPlayerCount(), r2.getUpdatedPlayerCount()) * (ascendingOrder ? 1 : -1); + case ACTIVITY: + return r1.getWorld().getActivity().compareTo(r2.getWorld().getActivity()) * -1 * (ascendingOrder ? 1 : -1); + default: + return 0; + } + }); + + // Leave empty activity worlds on the bottom of the list + if (orderIndex == WorldOrder.ACTIVITY) + { + rows.sort((r1, r2) -> r1.getWorld().getActivity().equals("-") ? 1 : -1); + } + + rows.sort((r1, r2) -> + { + boolean b1 = plugin.isFavorite(r1.getWorld()); + boolean b2 = plugin.isFavorite(r2.getWorld()); + return Boolean.compare(b2, b1); + }); + + listContainer.removeAll(); + histContainer.removeAll(); + + Map history = plugin.getHistory(); + Map matchedHist = new HashMap<>(); + for (int i = 0; i < rows.size(); i++) + { + WorldTableRow row = rows.get(i); + row.setBackground(i % 2 == 0 ? ODD_ROW : ColorScheme.DARK_GRAY_COLOR); + listContainer.add(row); + + String worldNum = String.valueOf(row.getWorld().getId()); + if (history.containsKey(worldNum)) + { + // Add toa list that we can sort later + matchedHist.put(worldNum, history.get(worldNum)); + } + } + + // Sort by ascending + matchedHist = matchedHist.entrySet().stream() + .sorted(Map.Entry.comparingByValue().reversed()) + .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, + (e1, e2) -> e1, LinkedHashMap::new)); + + // Add matched rows to history list + Iterator it = matchedHist.entrySet().iterator(); + int histRowCount = 0; + while (it.hasNext()) + { + Map.Entry pair = (Map.Entry) it.next(); + for (WorldTableRow r : rows) + { + WorldTableRow histRow = r; + histRow.setBackground(histRowCount % 2 == 0 ? ODD_ROW : ColorScheme.DARK_GRAY_COLOR); + if (String.valueOf(r.getWorld().getId()).equals(pair.getKey())) + { + histContainer.add(r); + histRowCount++; + break; + } + } + it.remove(); + } + + listContainer.revalidate(); + listContainer.repaint(); + histContainer.revalidate(); + histContainer.repaint(); + } + + Component createTabs() + { + // Constraints for GB Layout + GridBagConstraints listConst = new GridBagConstraints(); + listConst.gridx = 0; + listConst.gridy = 1; + listConst.fill = GridBagConstraints.HORIZONTAL; + GridBagConstraints headConst = new GridBagConstraints(); + headConst.gridx = 0; + headConst.gridy = 0; + headConst.fill = GridBagConstraints.HORIZONTAL; + GridBagConstraints resetConst = new GridBagConstraints(); + resetConst.gridx = 0; + resetConst.gridy = 2; + resetConst.fill = GridBagConstraints.HORIZONTAL; + + // Border so that the scrollbar doesn't go over ping + Border paddingBorder = BorderFactory.createEmptyBorder(0, 0, 0, 5); + + // Clear history button + JButton resetBtn = new JButton("Clear History"); + resetBtn.addActionListener(e -> + { + plugin.clearHistory(); + plugin.addToHistory(); + updateList(); + }); + + // World Selector page + JPanel worldPanel = new JPanel(); + worldPanel.setBorder(paddingBorder); + worldPanel.setLayout(new GridBagLayout()); + worldPanel.add(headerContainer, headConst); + worldPanel.add(listContainer, listConst); + + // History page + JPanel histPanel = new JPanel(); + histPanel.setBorder(paddingBorder); + histPanel.setLayout(new GridBagLayout()); + histPanel.add(headerHistContainer, headConst); + histPanel.add(histContainer, listConst); + histPanel.add(resetBtn, resetConst); + + JTabbedPane worldTabs = new JTabbedPane(); + worldTabs.setName("tabs"); + worldTabs.addTab("Worlds", worldPanel); + worldTabs.addTab("History", histPanel); + + // This is a fix for preventing stretching of WorldTableRows + worldTabs.addChangeListener(e -> + { + switch (worldTabs.getSelectedIndex()) + { + case 0: + histPanel.remove(histContainer); + if (worldPanel.getComponentCount() < 2) + { + worldPanel.add(listContainer, listConst); + } + break; + case 1: + worldPanel.remove(listContainer); + if (histPanel.getComponentCount() < 3) + { + histPanel.add(histContainer, listConst); + } + break; + } + }); + + return worldTabs; + } + + void updateFavoriteMenu(int world, boolean favorite) + { + for (WorldTableRow row : rows) + { + if (row.getWorld().getId() == world) + { + row.setFavoriteMenu(favorite); + } + } + + for (WorldTableRow row : histRows) + { + if (row.getWorld().getId() == world) + { + row.setFavoriteMenu(favorite); + } + } + } + + void resetAllFavoriteMenus() + { + for (WorldTableRow row : rows) + { + row.setFavoriteMenu(false); + } + + for (WorldTableRow row : histRows) + { + row.setFavoriteMenu(false); + } + } + + void populate(List worlds) + { + Map pingHistory = new HashMap<>(); + + for (WorldTableRow row : rows) + { + pingHistory.put(row.getWorld().getId(), row.getPing()); + } + + rows.clear(); + + for (int i = 0; i < worlds.size(); i++) + { + World world = worlds.get(i); + + switch (filterMode) + { + case FREE: + if (world.getTypes().contains(WorldType.MEMBERS)) + { + continue; + } + break; + case MEMBERS: + if (!world.getTypes().contains(WorldType.MEMBERS)) + { + continue; + } + break; + } + + Integer ping = pingHistory.getOrDefault(world.getId(), 0); + rows.add(buildRow(world, i % 2 == 0, world.getId() == plugin.getCurrentWorld() && plugin.getLastWorld() != 0, plugin.isFavorite(world), ping)); + } + + updateList(); + } + + private void orderBy(WorldOrder order) + { + pingHeader.highlight(false, ascendingOrder); + worldHeader.highlight(false, ascendingOrder); + playersHeader.highlight(false, ascendingOrder); + activityHeader.highlight(false, ascendingOrder); + + switch (order) + { + case PING: + pingHeader.highlight(true, ascendingOrder); + break; + case WORLD: + worldHeader.highlight(true, ascendingOrder); + break; + case PLAYERS: + playersHeader.highlight(true, ascendingOrder); + break; + case ACTIVITY: + activityHeader.highlight(true, ascendingOrder); + break; + } + + orderIndex = order; + updateList(); + } + + /** + * Builds the entire table header. + */ + private JPanel buildHistoryHeader() + { + JPanel header = new JPanel(new BorderLayout()); + JPanel leftSide = new JPanel(new BorderLayout()); + JPanel rightSide = new JPanel(new BorderLayout()); + + WorldTableHeader pingHeader = new WorldTableHeader("Ping", false, ascendingOrder, plugin::refresh); + pingHeader.setPreferredSize(new Dimension(PING_COLUMN_WIDTH, 0)); + + WorldTableHeader worldHeader = new WorldTableHeader("World", false, ascendingOrder, plugin::refresh); + worldHeader.setPreferredSize(new Dimension(WORLD_COLUMN_WIDTH, 0)); + + WorldTableHeader playersHeader = new WorldTableHeader("#", false, ascendingOrder, plugin::refresh); + playersHeader.setPreferredSize(new Dimension(PLAYERS_COLUMN_WIDTH, 0)); + + WorldTableHeader activityHeader = new WorldTableHeader("Activity", false, ascendingOrder, plugin::refresh); + + leftSide.add(worldHeader, BorderLayout.WEST); + leftSide.add(playersHeader, BorderLayout.CENTER); + + rightSide.add(activityHeader, BorderLayout.CENTER); + rightSide.add(pingHeader, BorderLayout.EAST); + + header.add(leftSide, BorderLayout.WEST); + header.add(rightSide, BorderLayout.CENTER); + + return header; + } + + private JPanel buildHeader() + { + JPanel header = new JPanel(new BorderLayout()); + JPanel leftSide = new JPanel(new BorderLayout()); + JPanel rightSide = new JPanel(new BorderLayout()); + + pingHeader = new WorldTableHeader("Ping", orderIndex == WorldOrder.PING, ascendingOrder, plugin::refresh); + pingHeader.setPreferredSize(new Dimension(PING_COLUMN_WIDTH, 0)); + pingHeader.addMouseListener(new MouseAdapter() + { + @Override + public void mousePressed(MouseEvent mouseEvent) + { + if (SwingUtilities.isRightMouseButton(mouseEvent)) + { + return; + } + ascendingOrder = orderIndex != WorldOrder.PING || !ascendingOrder; + orderBy(WorldOrder.PING); + } + }); + + worldHeader = new WorldTableHeader("World", orderIndex == WorldOrder.WORLD, ascendingOrder, plugin::refresh); + worldHeader.setPreferredSize(new Dimension(WORLD_COLUMN_WIDTH, 0)); + worldHeader.addMouseListener(new MouseAdapter() + { + @Override + public void mousePressed(MouseEvent mouseEvent) + { + if (SwingUtilities.isRightMouseButton(mouseEvent)) + { + return; + } + ascendingOrder = orderIndex != WorldOrder.WORLD || !ascendingOrder; + orderBy(WorldOrder.WORLD); + } + }); + + playersHeader = new WorldTableHeader("#", orderIndex == WorldOrder.PLAYERS, ascendingOrder, plugin::refresh); + playersHeader.setPreferredSize(new Dimension(PLAYERS_COLUMN_WIDTH, 0)); + playersHeader.addMouseListener(new MouseAdapter() + { + @Override + public void mousePressed(MouseEvent mouseEvent) + { + if (SwingUtilities.isRightMouseButton(mouseEvent)) + { + return; + } + ascendingOrder = orderIndex != WorldOrder.PLAYERS || !ascendingOrder; + orderBy(WorldOrder.PLAYERS); + } + }); + + activityHeader = new WorldTableHeader("Activity", orderIndex == WorldOrder.ACTIVITY, ascendingOrder, plugin::refresh); + activityHeader.addMouseListener(new MouseAdapter() + { + @Override + public void mousePressed(MouseEvent mouseEvent) + { + if (SwingUtilities.isRightMouseButton(mouseEvent)) + { + return; + } + ascendingOrder = orderIndex != WorldOrder.ACTIVITY || !ascendingOrder; + orderBy(WorldOrder.ACTIVITY); + } + }); + + leftSide.add(worldHeader, BorderLayout.WEST); + leftSide.add(playersHeader, BorderLayout.CENTER); + + rightSide.add(activityHeader, BorderLayout.CENTER); + rightSide.add(pingHeader, BorderLayout.EAST); + + header.add(leftSide, BorderLayout.WEST); + header.add(rightSide, BorderLayout.CENTER); + + return header; + } + + /** + * Builds a table row, that displays the world's information. + */ + private WorldTableRow buildRow(World world, boolean stripe, boolean current, boolean favorite, Integer ping) + { + WorldTableRow row = new WorldTableRow(world, current, favorite, + world1 -> + { + plugin.hopTo(world1); + }, + (world12, add) -> + { + if (add) + { + plugin.addToFavorites(world12); + } + else + { + plugin.removeFromFavorites(world12); + } + + updateList(); + } + ); + row.setBackground(stripe ? ODD_ROW : ColorScheme.DARK_GRAY_COLOR); + return row; + } + + /** + * Enumerates the multiple ordering options for the world list. + */ + private enum WorldOrder + { + WORLD, + PLAYERS, + ACTIVITY, + PING + } +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/worldhopper/WorldTableHeader.java b/runelite-client/src/main/java/net/runelite/client/plugins/worldhopper/WorldTableHeader.java index 2b62fa4d88..2d7ef01406 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/worldhopper/WorldTableHeader.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/worldhopper/WorldTableHeader.java @@ -31,7 +31,12 @@ import java.awt.event.MouseEvent; import java.awt.event.MouseListener; import java.awt.image.BufferedImage; import javax.annotation.Nonnull; -import javax.swing.*; +import javax.swing.BorderFactory; +import javax.swing.ImageIcon; +import javax.swing.JLabel; +import javax.swing.JMenuItem; +import javax.swing.JPanel; +import javax.swing.JPopupMenu; import javax.swing.border.CompoundBorder; import javax.swing.border.EmptyBorder; import net.runelite.client.ui.ColorScheme; @@ -116,7 +121,7 @@ class WorldTableHeader extends JPanel add(textLabel, BorderLayout.WEST); add(arrowLabel, BorderLayout.EAST); -} + } /** * The labels inherit the parent's mouse listeners. diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/worldhopper/WorldTableRow.java b/runelite-client/src/main/java/net/runelite/client/plugins/worldhopper/WorldTableRow.java index a450c36b89..6dd39ccfeb 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/worldhopper/WorldTableRow.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/worldhopper/WorldTableRow.java @@ -98,7 +98,7 @@ class WorldTableRow extends JPanel this.updatedPlayerCount = world.getPlayers(); this. - setLayout(new BorderLayout()); + setLayout(new BorderLayout()); setBorder(new EmptyBorder(2, 0, 2, 0)); addMouseListener(new MouseAdapter() diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/worldmap/AgilityShortcutPoint.java b/runelite-client/src/main/java/net/runelite/client/plugins/worldmap/AgilityShortcutPoint.java index c99979f103..724f83753d 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/worldmap/AgilityShortcutPoint.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/worldmap/AgilityShortcutPoint.java @@ -1,43 +1,43 @@ -/* - * Copyright (c) 2018, Morgan Lewis - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package net.runelite.client.plugins.worldmap; - -import java.awt.image.BufferedImage; -import net.runelite.client.ui.overlay.worldmap.WorldMapPoint; -import net.runelite.client.game.AgilityShortcut; - -class AgilityShortcutPoint extends WorldMapPoint -{ - AgilityShortcutPoint(AgilityShortcut data, BufferedImage icon, boolean showTooltip) - { - super(data.getWorldMapLocation(), icon); - - if (showTooltip) - { - setTooltip(data.getTooltip()); - } - } -} +/* + * Copyright (c) 2018, Morgan Lewis + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package net.runelite.client.plugins.worldmap; + +import java.awt.image.BufferedImage; +import net.runelite.client.game.AgilityShortcut; +import net.runelite.client.ui.overlay.worldmap.WorldMapPoint; + +class AgilityShortcutPoint extends WorldMapPoint +{ + AgilityShortcutPoint(AgilityShortcut data, BufferedImage icon, boolean showTooltip) + { + super(data.getWorldMapLocation(), icon); + + if (showTooltip) + { + setTooltip(data.getTooltip()); + } + } +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/worldmap/QuestStartPoint.java b/runelite-client/src/main/java/net/runelite/client/plugins/worldmap/QuestStartPoint.java index 14f1842f62..bf62004c59 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/worldmap/QuestStartPoint.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/worldmap/QuestStartPoint.java @@ -1,39 +1,39 @@ -/* - * Copyright (c) 2018, John James Hamilton - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package net.runelite.client.plugins.worldmap; - -import net.runelite.client.ui.overlay.worldmap.WorldMapPoint; -import java.awt.image.BufferedImage; - -class QuestStartPoint extends WorldMapPoint -{ - QuestStartPoint(QuestStartLocation data, BufferedImage icon) - { - super(data.getLocation(), icon); - - setTooltip(data.getTooltip()); - } -} +/* + * Copyright (c) 2018, John James Hamilton + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package net.runelite.client.plugins.worldmap; + +import java.awt.image.BufferedImage; +import net.runelite.client.ui.overlay.worldmap.WorldMapPoint; + +class QuestStartPoint extends WorldMapPoint +{ + QuestStartPoint(QuestStartLocation data, BufferedImage icon) + { + super(data.getLocation(), icon); + + setTooltip(data.getTooltip()); + } +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/worldmap/RareTreePoint.java b/runelite-client/src/main/java/net/runelite/client/plugins/worldmap/RareTreePoint.java index 0dd42013bd..1d4155c4d0 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/worldmap/RareTreePoint.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/worldmap/RareTreePoint.java @@ -1,44 +1,43 @@ -/* - * Copyright (c) 2018, Spedwards - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package net.runelite.client.plugins.worldmap; - -import net.runelite.api.coords.WorldPoint; -import net.runelite.client.ui.overlay.worldmap.WorldMapPoint; - -import java.awt.image.BufferedImage; - -class RareTreePoint extends WorldMapPoint -{ - RareTreePoint(WorldPoint point, String tooltip, BufferedImage icon, boolean showTooltip) - { - super(point, icon); - - if (showTooltip) - { - setTooltip(tooltip); - } - } -} +/* + * Copyright (c) 2018, Spedwards + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package net.runelite.client.plugins.worldmap; + +import java.awt.image.BufferedImage; +import net.runelite.api.coords.WorldPoint; +import net.runelite.client.ui.overlay.worldmap.WorldMapPoint; + +class RareTreePoint extends WorldMapPoint +{ + RareTreePoint(WorldPoint point, String tooltip, BufferedImage icon, boolean showTooltip) + { + super(point, icon); + + if (showTooltip) + { + setTooltip(tooltip); + } + } +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/worldmap/TeleportLocationData.java b/runelite-client/src/main/java/net/runelite/client/plugins/worldmap/TeleportLocationData.java index b877be8810..b8bb51e3f3 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/worldmap/TeleportLocationData.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/worldmap/TeleportLocationData.java @@ -72,46 +72,46 @@ enum TeleportLocationData APE_ATOLL_ARCEUUS(TeleportType.ARCEUUS_MAGIC, "Ape Atoll", 90, new WorldPoint(2770, 2703, 0), "ape_atoll_teleport_icon_arceuus.png"), // Jewellery - BARBARIAN_ASSAULT(TeleportType.JEWELLERY, "Games Necklace" , "Barbarian Assault", new WorldPoint(2520, 3571, 0), "games_necklace_teleport_icon.png"), - BURTHORPE_GAMES_ROOM(TeleportType.JEWELLERY, "Games Necklace" , "Burthorpe Games Room", new WorldPoint(2898, 3554, 0), "games_necklace_teleport_icon.png"), - TEARS_OF_GUTHIX(TeleportType.JEWELLERY, "Games Necklace" , "Tears of Guthix", new WorldPoint(3245, 9500, 0), "games_necklace_teleport_icon.png"), - CORPOREAL_BEAST(TeleportType.JEWELLERY, "Games Necklace" , "Corporeal Beast", new WorldPoint(2967, 4384, 0), "games_necklace_teleport_icon.png"), - WINTERTODT_CAMP(TeleportType.JEWELLERY, "Games Necklace" , "Wintertodt Camp", new WorldPoint(1624, 3938, 0), "games_necklace_teleport_icon.png"), - DUEL_ARENA(TeleportType.JEWELLERY, "Ring of Dueling" , "Duel Arena", new WorldPoint(3315, 3235, 0), "ring_of_dueling_teleport_icon.png"), - CLAN_WARS(TeleportType.JEWELLERY, "Ring of Dueling" , "Clan Wars", new WorldPoint(3387, 3158, 0), "ring_of_dueling_teleport_icon.png"), - CASTLE_WARS(TeleportType.JEWELLERY, "Ring of Dueling" , "Castle Wars", new WorldPoint(2441, 3091, 0), "ring_of_dueling_teleport_icon.png"), - WARRIORS_GUILD(TeleportType.JEWELLERY, "Combat Bracelet" , "Warriors' Guild", new WorldPoint(2883, 3549, 0), "combat_bracelet_teleport_icon.png"), - CHAMPIONS_GUILD(TeleportType.JEWELLERY, "Combat Bracelet" , "Champions' Guild", new WorldPoint(3189, 3368, 0), "combat_bracelet_teleport_icon.png"), - EDGEVILLE_MONASTERY(TeleportType.JEWELLERY, "Combat Bracelet" , "Edgeville Monastery", new WorldPoint(3053, 3487, 0), "combat_bracelet_teleport_icon.png"), - RANGING_GUILD(TeleportType.JEWELLERY, "Combat Bracelet" , "Ranging Guild", new WorldPoint(2654, 3441, 0), "combat_bracelet_teleport_icon.png"), - FISHING_GUILD_NECK(TeleportType.JEWELLERY, "Skills Necklace" , "Fishing Guild", new WorldPoint(2613, 3390, 0), "skills_necklace_teleport_icon.png"), - MINING_GUILD(TeleportType.JEWELLERY, "Skills Necklace" , "Mining Guild", new WorldPoint(3049, 9762, 0), "skills_necklace_teleport_icon.png"), - CRAFTING_GUILD(TeleportType.JEWELLERY, "Skills Necklace" , "Crafting Guild", new WorldPoint(2934, 3294, 0), "skills_necklace_teleport_icon.png"), - COOKING_GUILD(TeleportType.JEWELLERY, "Skills Necklace" , "Cooking Guild", new WorldPoint(3145, 3438, 0), "skills_necklace_teleport_icon.png"), - WOODCUTTING_GUILD(TeleportType.JEWELLERY, "Skills Necklace" , "Woodcutting Guild", new WorldPoint(1662, 3505, 0), "skills_necklace_teleport_icon.png"), - FARMING_GUILD(TeleportType.JEWELLERY, "Skills Necklace" , "Farming Guild", new WorldPoint(1249, 3717, 0), "skills_necklace_teleport_icon.png"), - EDGEVILLE(TeleportType.JEWELLERY, "Amulet of Glory" , "Edgeville", new WorldPoint(3087, 3496, 0), "amulet_of_glory_teleport_icon.png"), - KARAMJA(TeleportType.JEWELLERY, "Amulet of Glory" , "Karamja", new WorldPoint(2918, 3176, 0), "amulet_of_glory_teleport_icon.png"), - DRAYNOR_VILLAGE(TeleportType.JEWELLERY, "Amulet of Glory" , "Draynor Village", new WorldPoint(3105, 3251, 0), "amulet_of_glory_teleport_icon.png"), - AL_KHARID(TeleportType.JEWELLERY, "Amulet of Glory" , "Al-Kharid", new WorldPoint(3293, 3163, 0), "amulet_of_glory_teleport_icon.png"), - MISCELLANIA(TeleportType.JEWELLERY, "Ring of Wealth" , "Miscellania", new WorldPoint(2535, 3862, 0), "ring_of_wealth_teleport_icon.png"), - GRAND_EXCHANGE(TeleportType.JEWELLERY, "Ring of Wealth" , "Grand Exchange", new WorldPoint(3162, 3480, 0), "ring_of_wealth_teleport_icon.png"), - FALADOR_PARK(TeleportType.JEWELLERY, "Ring of Wealth" , "Falador Park", new WorldPoint(2995, 3375, 0), "ring_of_wealth_teleport_icon.png"), - DONDAKAN(TeleportType.JEWELLERY, "Ring of Wealth" , "Dondakan", new WorldPoint(2831, 10165, 0), "ring_of_wealth_teleport_icon.png"), - SLAYER_TOWER(TeleportType.JEWELLERY, "Slayer Ring" , "Slayer Tower", new WorldPoint(3429, 3531, 0), "slayer_ring_teleport_icon.png"), - FREMENNIK_SLAYER_DUNGEON(TeleportType.JEWELLERY, "Slayer Ring" , "Fremennik Slayer Dungeon", new WorldPoint(2800, 9998, 0), "slayer_ring_teleport_icon.png"), - TARNS_LAIR(TeleportType.JEWELLERY, "Slayer Ring" , "Tarn's Lair", new WorldPoint(3187, 4601, 0), "slayer_ring_teleport_icon.png"), - STRONGHOLD_SLAYER_CAVE(TeleportType.JEWELLERY, "Slayer Ring" , "Stronghold Slayer Cave", new WorldPoint(2433, 3421, 0), "slayer_ring_teleport_icon.png"), - DARK_BEASTS(TeleportType.JEWELLERY, "Slayer Ring" , "Dark Beasts", new WorldPoint(2028, 4638, 0), "slayer_ring_teleport_icon.png"), - DIGSITE(TeleportType.JEWELLERY, "Digsite Pendant" , "Digsite", new WorldPoint(3339, 3445, 0), "digsite_pendant_teleport_icon.png"), - HOUSE_ON_THE_HILL(TeleportType.JEWELLERY, "Digsite Pendant" , "House on the Hill", new WorldPoint(3763, 3869, 0), "digsite_pendant_teleport_icon.png"), - LITHKREN(TeleportType.JEWELLERY, "Digsite Pendant" , "Lithkren", new WorldPoint(3547, 10456, 0), "digsite_pendant_teleport_icon.png"), - WIZARDS_TOWER(TeleportType.JEWELLERY, "Necklace of Passage" , "Wizards' Tower", new WorldPoint(3114, 3181, 0), "necklace_of_passage_teleport_icon.png"), - JORRALS_OUTPOST(TeleportType.JEWELLERY, "Necklace of Passage" , "Jorral's Outpost", new WorldPoint(2431, 3348, 0), "necklace_of_passage_teleport_icon.png"), - DESERT_EAGLE_STATION(TeleportType.JEWELLERY, "Necklace of Passage" , "Desert eagle station of the eagle transport system", new WorldPoint(3406, 3157, 0), "necklace_of_passage_teleport_icon.png"), - CHAOS_TEMPLE(TeleportType.JEWELLERY, "Burning Amulet" , "Chaos Temple (lvl 15)", new WorldPoint(3234, 3637, 0), "burning_amulet_teleport_icon.png"), - BANDIT_CAMP(TeleportType.JEWELLERY, "Burning Amulet" , "Bandit Camp (lvl 17)", new WorldPoint(3038, 3651, 0), "burning_amulet_teleport_icon.png"), - LAVA_MAZE(TeleportType.JEWELLERY, "Burning Amulet" , "Lava Maze (lvl 41)", new WorldPoint(3028, 3840, 0), "burning_amulet_teleport_icon.png"), + BARBARIAN_ASSAULT(TeleportType.JEWELLERY, "Games Necklace", "Barbarian Assault", new WorldPoint(2520, 3571, 0), "games_necklace_teleport_icon.png"), + BURTHORPE_GAMES_ROOM(TeleportType.JEWELLERY, "Games Necklace", "Burthorpe Games Room", new WorldPoint(2898, 3554, 0), "games_necklace_teleport_icon.png"), + TEARS_OF_GUTHIX(TeleportType.JEWELLERY, "Games Necklace", "Tears of Guthix", new WorldPoint(3245, 9500, 0), "games_necklace_teleport_icon.png"), + CORPOREAL_BEAST(TeleportType.JEWELLERY, "Games Necklace", "Corporeal Beast", new WorldPoint(2967, 4384, 0), "games_necklace_teleport_icon.png"), + WINTERTODT_CAMP(TeleportType.JEWELLERY, "Games Necklace", "Wintertodt Camp", new WorldPoint(1624, 3938, 0), "games_necklace_teleport_icon.png"), + DUEL_ARENA(TeleportType.JEWELLERY, "Ring of Dueling", "Duel Arena", new WorldPoint(3315, 3235, 0), "ring_of_dueling_teleport_icon.png"), + CLAN_WARS(TeleportType.JEWELLERY, "Ring of Dueling", "Clan Wars", new WorldPoint(3387, 3158, 0), "ring_of_dueling_teleport_icon.png"), + CASTLE_WARS(TeleportType.JEWELLERY, "Ring of Dueling", "Castle Wars", new WorldPoint(2441, 3091, 0), "ring_of_dueling_teleport_icon.png"), + WARRIORS_GUILD(TeleportType.JEWELLERY, "Combat Bracelet", "Warriors' Guild", new WorldPoint(2883, 3549, 0), "combat_bracelet_teleport_icon.png"), + CHAMPIONS_GUILD(TeleportType.JEWELLERY, "Combat Bracelet", "Champions' Guild", new WorldPoint(3189, 3368, 0), "combat_bracelet_teleport_icon.png"), + EDGEVILLE_MONASTERY(TeleportType.JEWELLERY, "Combat Bracelet", "Edgeville Monastery", new WorldPoint(3053, 3487, 0), "combat_bracelet_teleport_icon.png"), + RANGING_GUILD(TeleportType.JEWELLERY, "Combat Bracelet", "Ranging Guild", new WorldPoint(2654, 3441, 0), "combat_bracelet_teleport_icon.png"), + FISHING_GUILD_NECK(TeleportType.JEWELLERY, "Skills Necklace", "Fishing Guild", new WorldPoint(2613, 3390, 0), "skills_necklace_teleport_icon.png"), + MINING_GUILD(TeleportType.JEWELLERY, "Skills Necklace", "Mining Guild", new WorldPoint(3049, 9762, 0), "skills_necklace_teleport_icon.png"), + CRAFTING_GUILD(TeleportType.JEWELLERY, "Skills Necklace", "Crafting Guild", new WorldPoint(2934, 3294, 0), "skills_necklace_teleport_icon.png"), + COOKING_GUILD(TeleportType.JEWELLERY, "Skills Necklace", "Cooking Guild", new WorldPoint(3145, 3438, 0), "skills_necklace_teleport_icon.png"), + WOODCUTTING_GUILD(TeleportType.JEWELLERY, "Skills Necklace", "Woodcutting Guild", new WorldPoint(1662, 3505, 0), "skills_necklace_teleport_icon.png"), + FARMING_GUILD(TeleportType.JEWELLERY, "Skills Necklace", "Farming Guild", new WorldPoint(1249, 3717, 0), "skills_necklace_teleport_icon.png"), + EDGEVILLE(TeleportType.JEWELLERY, "Amulet of Glory", "Edgeville", new WorldPoint(3087, 3496, 0), "amulet_of_glory_teleport_icon.png"), + KARAMJA(TeleportType.JEWELLERY, "Amulet of Glory", "Karamja", new WorldPoint(2918, 3176, 0), "amulet_of_glory_teleport_icon.png"), + DRAYNOR_VILLAGE(TeleportType.JEWELLERY, "Amulet of Glory", "Draynor Village", new WorldPoint(3105, 3251, 0), "amulet_of_glory_teleport_icon.png"), + AL_KHARID(TeleportType.JEWELLERY, "Amulet of Glory", "Al-Kharid", new WorldPoint(3293, 3163, 0), "amulet_of_glory_teleport_icon.png"), + MISCELLANIA(TeleportType.JEWELLERY, "Ring of Wealth", "Miscellania", new WorldPoint(2535, 3862, 0), "ring_of_wealth_teleport_icon.png"), + GRAND_EXCHANGE(TeleportType.JEWELLERY, "Ring of Wealth", "Grand Exchange", new WorldPoint(3162, 3480, 0), "ring_of_wealth_teleport_icon.png"), + FALADOR_PARK(TeleportType.JEWELLERY, "Ring of Wealth", "Falador Park", new WorldPoint(2995, 3375, 0), "ring_of_wealth_teleport_icon.png"), + DONDAKAN(TeleportType.JEWELLERY, "Ring of Wealth", "Dondakan", new WorldPoint(2831, 10165, 0), "ring_of_wealth_teleport_icon.png"), + SLAYER_TOWER(TeleportType.JEWELLERY, "Slayer Ring", "Slayer Tower", new WorldPoint(3429, 3531, 0), "slayer_ring_teleport_icon.png"), + FREMENNIK_SLAYER_DUNGEON(TeleportType.JEWELLERY, "Slayer Ring", "Fremennik Slayer Dungeon", new WorldPoint(2800, 9998, 0), "slayer_ring_teleport_icon.png"), + TARNS_LAIR(TeleportType.JEWELLERY, "Slayer Ring", "Tarn's Lair", new WorldPoint(3187, 4601, 0), "slayer_ring_teleport_icon.png"), + STRONGHOLD_SLAYER_CAVE(TeleportType.JEWELLERY, "Slayer Ring", "Stronghold Slayer Cave", new WorldPoint(2433, 3421, 0), "slayer_ring_teleport_icon.png"), + DARK_BEASTS(TeleportType.JEWELLERY, "Slayer Ring", "Dark Beasts", new WorldPoint(2028, 4638, 0), "slayer_ring_teleport_icon.png"), + DIGSITE(TeleportType.JEWELLERY, "Digsite Pendant", "Digsite", new WorldPoint(3339, 3445, 0), "digsite_pendant_teleport_icon.png"), + HOUSE_ON_THE_HILL(TeleportType.JEWELLERY, "Digsite Pendant", "House on the Hill", new WorldPoint(3763, 3869, 0), "digsite_pendant_teleport_icon.png"), + LITHKREN(TeleportType.JEWELLERY, "Digsite Pendant", "Lithkren", new WorldPoint(3547, 10456, 0), "digsite_pendant_teleport_icon.png"), + WIZARDS_TOWER(TeleportType.JEWELLERY, "Necklace of Passage", "Wizards' Tower", new WorldPoint(3114, 3181, 0), "necklace_of_passage_teleport_icon.png"), + JORRALS_OUTPOST(TeleportType.JEWELLERY, "Necklace of Passage", "Jorral's Outpost", new WorldPoint(2431, 3348, 0), "necklace_of_passage_teleport_icon.png"), + DESERT_EAGLE_STATION(TeleportType.JEWELLERY, "Necklace of Passage", "Desert eagle station of the eagle transport system", new WorldPoint(3406, 3157, 0), "necklace_of_passage_teleport_icon.png"), + CHAOS_TEMPLE(TeleportType.JEWELLERY, "Burning Amulet", "Chaos Temple (lvl 15)", new WorldPoint(3234, 3637, 0), "burning_amulet_teleport_icon.png"), + BANDIT_CAMP(TeleportType.JEWELLERY, "Burning Amulet", "Bandit Camp (lvl 17)", new WorldPoint(3038, 3651, 0), "burning_amulet_teleport_icon.png"), + LAVA_MAZE(TeleportType.JEWELLERY, "Burning Amulet", "Lava Maze (lvl 41)", new WorldPoint(3028, 3840, 0), "burning_amulet_teleport_icon.png"), // Misc XERICS_LOOKOUT(TeleportType.OTHER, "Xeric's Talisman", "Xeric's Lookout", new WorldPoint(1576, 3528, 0), "xerics_talisman_teleport_icon.png"), @@ -127,7 +127,7 @@ enum TeleportLocationData RELLEKKKA_LYRE(TeleportType.OTHER, "Enchanted Lyre", "Rellekka", new WorldPoint(2664, 3643, 0), "enchanted_lyre_teleport_icon.png"), WATERBIRTH_ISLAND_LYRE(TeleportType.OTHER, "Enchanted Lyre", "Waterbirth Island", new WorldPoint(2550, 3756, 0), "enchanted_lyre_teleport_icon.png"), NEITIZNOT_LYRE(TeleportType.OTHER, "Enchanted Lyre", "Neitiznot", new WorldPoint(2336, 3801, 0), "enchanted_lyre_teleport_icon.png"), - JATIZSO_LYRE(TeleportType.OTHER, "Enchanted Lyre", "Jatizso", new WorldPoint(2409, 3809, 0), "enchanted_lyre_teleport_icon.png"), + JATIZSO_LYRE(TeleportType.OTHER, "Enchanted Lyre", "Jatizso", new WorldPoint(2409, 3809, 0), "enchanted_lyre_teleport_icon.png"), WEISS_ICY_BASALT(TeleportType.OTHER, "Icy Basalt", "Weiss", new WorldPoint(2846, 3940, 0), "icy_basalt_teleport_icon.png"), TROLL_STRONGHOLD_STONY_BASALT(TeleportType.OTHER, "Stony Basalt", "Troll Stronghold", new WorldPoint(2838, 3693, 0), "stony_basalt_teleport_icon.png"), KHAREDSTS_MEMOIRS_HOSIDIUS(TeleportType.OTHER, "Kharedst's Memoirs", "Lunch by the Lancalliums (Hosidius)", new WorldPoint(1713, 3612, 0), "kharedsts_memoirs_teleport_icon.png"), @@ -150,19 +150,19 @@ enum TeleportLocationData // Achievement Diary ARDOUGNE_CLOAK_MONASTERY(TeleportType.OTHER, "Ardougne Cloak", "Monastery", new WorldPoint(2606, 3222, 0), "ardougne_cloak_icon.png"), ARDOUGNE_CLOAK_FARM(TeleportType.OTHER, "Ardougne Cloak", "Farm", new WorldPoint(2673, 3375, 0), "ardougne_cloak_icon.png"), - EXPLORERS_RING(TeleportType.OTHER, "Explorer's Ring", new WorldPoint(3052, 3292, 0), "explorers_ring_icon.png"), + EXPLORERS_RING(TeleportType.OTHER, "Explorer's Ring", new WorldPoint(3052, 3292, 0), "explorers_ring_icon.png"), KARAMJA_GLOVES_GEM_MINE(TeleportType.OTHER, "Karamja Gloves", "Gem Mine (Underground)", new WorldPoint(2827, 2997, 0), "karamja_gloves_icon.png"), KARAMJA_GLOVES_DURADEL(TeleportType.OTHER, "Karamja Gloves", "Duradel", new WorldPoint(2870, 2981, 0), "karamja_gloves_icon.png"), DESERT_AMULET_NARDAH(TeleportType.OTHER, "Desert Amulet", "Nardah", new WorldPoint(3432, 2914, 0), "desert_amulet_icon.png"), DESERT_AMULKT_KALPHITE_CAVE(TeleportType.OTHER, "Desert Amulet", "Kalphite Cave", new WorldPoint(3322, 3122, 0), "desert_amulet_icon.png"), MORYTANIA_LEGS_SLIME_PIT(TeleportType.OTHER, "Morytania Legs", "Slime Pit (Underground)", new WorldPoint(3654, 3516, 0), "morytania_legs_icon.png"), MORYTANIA_LEGS_BURGH_DE_ROTT(TeleportType.OTHER, "Morytania Legs", "Burgh de Rott", new WorldPoint(3482, 3231, 0), "morytania_legs_icon.png"), - FREMENNIK_SEA_BOOTS(TeleportType.OTHER, "Fremennik Sea Boots", new WorldPoint(2640, 3675, 0), "fremennik_boots_icon.png"), - KANDARIN_HEADGEAR(TeleportType.OTHER, "Kandarin Headgear", new WorldPoint(2729, 3411, 0), "kandarin_headgear_icon.png"), + FREMENNIK_SEA_BOOTS(TeleportType.OTHER, "Fremennik Sea Boots", new WorldPoint(2640, 3675, 0), "fremennik_boots_icon.png"), + KANDARIN_HEADGEAR(TeleportType.OTHER, "Kandarin Headgear", new WorldPoint(2729, 3411, 0), "kandarin_headgear_icon.png"), WILDERNESS_SWORD(TeleportType.OTHER, "Wilderness Sword", new WorldPoint(3377, 3891, 0), "wilderness_sword_icon.png"), - WESTERN_BANNER(TeleportType.OTHER, "Western Banner", new WorldPoint(2329, 3685, 0), "western_banner_icon.png"), - RADAS_BLESSING_MOUNT_KARUULM(TeleportType.OTHER, "Rada's Blessing", new WorldPoint(1311, 3795, 0), "radas_blessing_icon.png"), - RADAS_BLESSING_WOODLANG(TeleportType.OTHER, "Rada's Blessing", new WorldPoint(1553, 3454, 0), "radas_blessing_icon.png"), + WESTERN_BANNER(TeleportType.OTHER, "Western Banner", new WorldPoint(2329, 3685, 0), "western_banner_icon.png"), + RADAS_BLESSING_MOUNT_KARUULM(TeleportType.OTHER, "Rada's Blessing", new WorldPoint(1311, 3795, 0), "radas_blessing_icon.png"), + RADAS_BLESSING_WOODLANG(TeleportType.OTHER, "Rada's Blessing", new WorldPoint(1553, 3454, 0), "radas_blessing_icon.png"), // Scrolls DIGSITE_SCROLL(TeleportType.SCROLL, "Digsite Teleport", new WorldPoint(3324, 3412, 0), "scroll_teleport_icon.png"), diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/worldmap/TransportationPoint.java b/runelite-client/src/main/java/net/runelite/client/plugins/worldmap/TransportationPoint.java index 57fce253e9..fc868331b1 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/worldmap/TransportationPoint.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/worldmap/TransportationPoint.java @@ -1,40 +1,40 @@ -/* - * Copyright (c) 2019, Kyle Sergio - * Copyright (c) 2019, Bryce Altomare - * Copyright (c) 2019, Kyle Stead - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package net.runelite.client.plugins.worldmap; - -import net.runelite.client.ui.overlay.worldmap.WorldMapPoint; -import java.awt.image.BufferedImage; - -class TransportationPoint extends WorldMapPoint -{ - TransportationPoint(TransportationPointLocation data, BufferedImage icon) - { - super(data.getLocation(), icon); - setTooltip(data.getTooltip()); - } -} +/* + * Copyright (c) 2019, Kyle Sergio + * Copyright (c) 2019, Bryce Altomare + * Copyright (c) 2019, Kyle Stead + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package net.runelite.client.plugins.worldmap; + +import java.awt.image.BufferedImage; +import net.runelite.client.ui.overlay.worldmap.WorldMapPoint; + +class TransportationPoint extends WorldMapPoint +{ + TransportationPoint(TransportationPointLocation data, BufferedImage icon) + { + super(data.getLocation(), icon); + setTooltip(data.getTooltip()); + } +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/worldmap/TransportationPointLocation.java b/runelite-client/src/main/java/net/runelite/client/plugins/worldmap/TransportationPointLocation.java index 54bd7adfdc..9e045e4f1a 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/worldmap/TransportationPointLocation.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/worldmap/TransportationPointLocation.java @@ -1,193 +1,193 @@ -/* - * Copyright (c) 2019, Kyle Sergio - * Copyright (c) 2019, Bryce Altomare - * Copyright (c) 2019, Kyle Stead - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package net.runelite.client.plugins.worldmap; - -import lombok.AllArgsConstructor; -import lombok.Getter; -import net.runelite.api.coords.WorldPoint; - -@Getter -@AllArgsConstructor -enum TransportationPointLocation -{ - //Ships - ARDOUGNE_TO_BRIMHAVEN("Ship to Brimhaven", new WorldPoint(2675, 3275, 0)), - ARDOUGNE_TO_FISHINGPLAT("Ship to Fishing Platform", new WorldPoint(2722, 3304, 0)), - BRIMHAVEN_TO_ARDOUGNE("Ship to Ardougne", new WorldPoint(2772, 3234, 0)), - CATHERBY_TO_KEEP_LE_FAYE("Ship to Keep Le Faye", new WorldPoint(2804, 3421, 0)), - CORSAIR_TO_RIMMINGTON("Ship to Rimmington", new WorldPoint(2577, 2839, 0)), - DRAGONTOOTH_TO_PHASMATYS("Ship to Port Phasmatys", new WorldPoint(3791, 3561, 0)), - DIGSITE_TO_FOSSIL("Ship to Fossil Island", new WorldPoint(3361, 3448, 0)), - ENTRANA_TO_PORTSARIM("Ship to Port Sarim", new WorldPoint(2833, 3334, 0)), - FISHINGPLAT_TO_ARDOUGNE("Ship to Ardougne", new WorldPoint(2779, 3271, 0)), - HARMLESS_TO_PORT_PHASMATYS("Ship to Port Phasmatys", new WorldPoint(3682, 2951, 0)), - ICEBERG_TO_RELLEKKA("Ship to Rellekka", new WorldPoint(2657, 3988, 0)), - ISLAND_TO_APE_ATOLL("Ship to Ape Atoll", new WorldPoint(2891, 2726, 0)), - JATIZSO_TO_RELLEKKA("Ship to Rellekka", new WorldPoint(2420, 3780, 0)), - KARAMJA_TO_PORT_SARIM("Ship to Port Sarim", new WorldPoint(2955, 3144, 0)), - KARAMJA_TO_PORT_KHAZARD("Ship to Port Khazard", new WorldPoint(2763, 2957, 0)), - LANDSEND_TO_PORTSARIM_PORTPISCARILIUS("Ship to Port Sarim/Port Piscarilius", new WorldPoint(1503, 3398, 0)), - LUNAR_ISLE_TO_PIRATES_COVE("Ship to Pirates' Cove", new WorldPoint(2137, 3899, 0)), - MISCELLANIA_TO_RELLEKKA("Ship to Rellekka", new WorldPoint(2579, 3846, 0)), - NEITIZNOT_TO_RELLEKKA("Ship to Rellekka", new WorldPoint(2310, 3779, 0)), - PESTCONTROL_TO_PORTSARIM("Ship to Port Sarim", new WorldPoint(2659, 2675, 0)), - PIRATES_COVE_TO_LUNAR_ISLE("Ship to Lunar Isle", new WorldPoint(2223, 3796, 0)), - PIRATES_COVE_TO_RELLEKKA("Ship to Rellekka", new WorldPoint(2212, 3794, 0)), - PORT_PHASMATYS_TO_DRAGONTOOTH("Ship to Dragontooth Island", new WorldPoint(3703, 3487, 0)), - PORT_PHASMATYS_TO_HARMLESS("Ship to Mos Le'Harmless", new WorldPoint(3709, 3497, 0)), - PORT_PISCARILIUS_TO_PORTSARIM_LANDSEND("Ship to Port Sarim/Land's End", new WorldPoint(1823, 3692, 0)), - PORTSARIM_TO_GREAT_KOUREND("Ship to Great Kourend", new WorldPoint(3054, 3244, 0)), - PORTSARIM_TO_ENTRANA("Ship to Entrana", new WorldPoint(3046, 3233, 0)), - PORTSARIM_TO_KARAMJA("Ship to Karamja", new WorldPoint(3029, 3218, 0)), - PORTSARIM_TO_CRANDOR("Ship to Crandor", new WorldPoint(3045, 3205, 0)), - PORTSARIM_TO_PEST_CONTROL("Ship to Pest Control", new WorldPoint(3039, 3201, 0)), - RELLEKKA_TO_JATIZSO_NEITIZNOT("Ship to Jatizso/Neitiznot", new WorldPoint(2639, 3710, 0)), - RELLEKKA_TO_MISCELLANIA("Ship to Miscellania", new WorldPoint(2627, 3692, 0)), - RELLEKKA_TO_WATERBIRTH("Ship to Waterbirth", new WorldPoint(2621, 3683, 0)), - RELLEKKA_TO_WEISS_ICEBERG("Ship to Weiss/Iceberg", new WorldPoint(2707, 3735, 0)), - RELLEKKA_TO_UNGAEL("Ship to Ungael", new WorldPoint(2638, 3698, 0)), - RIMMINGTON_TO_CORSAIR_COVE("Ship to Corsair Cove", new WorldPoint(2909, 3227, 0 )), - WATERBIRTH_TO_RELLEKKA("Ship to Rellekka", new WorldPoint(2549, 3758, 0)), - WEISS_TO_RELLEKKA("Ship to Rellekka", new WorldPoint(2847, 3967, 0)), - UNGAEL_TO_RELLEKKA("Ship to Rellekka", new WorldPoint(2276, 4034, 0)), - - //Row Boats - ROW_BOAT_BATTLEFRONT("Rowboat to Molch/Molch Island/Shayzien", new WorldPoint(1383, 3663, 0)), - ROW_BOAT_BRAIN_DEATH("Rowboat to Port Phasmatys", new WorldPoint(2161, 5117, 0)), - ROW_BOAT_BURGH_DE_ROTT("Rowboat to Meiyerditch", new WorldPoint(3522, 3168, 0)), - ROW_BOAT_CRABCLAW("Rowboat to Hosidius", new WorldPoint(1780, 3417, 0)), - ROW_BOAT_DIVING_ISLAND("Rowboat to Barge/Camp/North of Island", new WorldPoint(3764, 3901, 0)), - ROW_BOAT_FISHING_GUILD("Rowboat to Hemenster", new WorldPoint(2598, 3426, 0)), - ROW_BOAT_GNOME_STRONGHOLD("Rowboat to Fishing Colony", new WorldPoint(2368, 3487, 0)), - ROW_BOAT_FISHING_COLONY("Rowboat to Gnome Stronghold", new WorldPoint(2356, 3641, 0)), - ROW_BOAT_HEMENSTER("Rowboat to Fishing Guild", new WorldPoint(2613, 3439, 0)), - ROW_BOAT_HOSIDIUS("Rowboat to Crabclaw Isle", new WorldPoint(1779, 3457, 0)), - ROW_BOAT_LITHKREN("Rowboat to Mushroom Forest", new WorldPoint(3582, 3973, 0)), - ROW_BOAT_LUMBRIDGE("Rowboat to Misthalin Mystery", new WorldPoint(3238, 3141, 0)), - ROW_BOAT_MOLCH("Rowboat to Molch Island/Shayzien/Battlefront", new WorldPoint(1343, 3646, 0)), - ROW_BOAT_MOLCH_ISLAND("Rowboat to Molch/Shayzien/Battlefront", new WorldPoint(1368, 3641, 0)), - ROW_BOAT_MORT("Rowboat to Mort Myre", new WorldPoint(3518, 3284, 0)), - ROW_BOAT_MORT_SWAMP("Rowboat to Mort'ton", new WorldPoint(3498, 3380, 0)), - ROW_BOAT_MUSEUM_CAMP("Rowboat to Barge/Digsite/North of Island", new WorldPoint(3723, 3807, 0)), - ROW_BOAT_MUSHROOM_FOREST_WEST("Rowboat to Lithkren", new WorldPoint(3659, 3849, 0)), - ROW_BOAT_MUSHROOM_FOREST_NE("Rowboat to Barge/Camp/Sea", new WorldPoint(3733, 3894, 0)), - ROW_BOAT_PORT_PHASMATYS_NORTH("Rowboat to Slepe", new WorldPoint(3670, 3545, 0)), - ROW_BOAT_PORT_PHASMATYS_EAST("Rowboat to Braindeath Island", new WorldPoint(3680, 3538, 0)), - ROW_BOAT_SHAYZIEN("Rowboat to Molch/Molch Island/Battlefront", new WorldPoint(1405, 3612, 0)), - ROW_BOAT_SLEPE("Rowboat to Port Phasmatys", new WorldPoint(3661, 3279, 0)), - OGRE_BOAT_FELDIP("Ogre Boat to Karamja", new WorldPoint(2653, 2964, 0)), - OGRE_BOAT_KARAMJA("Ogre Boat to Feldip", new WorldPoint(2757, 3085, 0)), - - //Charter ships - CHARTER_BRIMHAVEN("Charter Ship", new WorldPoint(2760, 3238, 0)), - CHARTER_CATHERBY("Charter Ship", new WorldPoint(2791, 3415, 0)), - CHARTER_CORSAIR_("Charter Ship", new WorldPoint(2589, 2851, 0)), - CHARTER_KARAMJA_NORTH("Charter Ship", new WorldPoint(2954, 3159, 0)), - CHARTER_KARAMJA_EAST("Charter Ship", new WorldPoint(2999, 3032, 0)), - CHARTER_KHAZARD("Charter Ship", new WorldPoint(2673, 3143, 0)), - CHARTER_MOSLE_HARMLESS("Charter Ship", new WorldPoint(3669, 2931, 0)), - CHARTER_PORT_PHASMATYS("Charter Ship", new WorldPoint(3702, 3503, 0)), - CHARTER_PORTSARIM("Charter Ship", new WorldPoint(3037, 3191, 0)), - CHARTER_TYRAS("Charter Ship", new WorldPoint(2141, 3123, 0)), - - //Minecarts/Carts - MINE_CART_ARCEUUS("Minecart", new WorldPoint(1673, 3832, 0)), - MINE_CART_GRANDEXCHANGE("Minecart to Keldagrim", new WorldPoint(3139, 3504, 0)), - MINE_CART_HOSIDIUS("Minecart", new WorldPoint(1656, 3542, 0)), - MINE_CART_KELDAGRIM("Minecart", new WorldPoint(2908, 10170, 0)), - MINE_CART_LOVAKENGJ("Minecart", new WorldPoint(1524, 3721, 0)), - MINE_CART_PORT_PISCARILIUS("Minecart", new WorldPoint(1760, 3708, 0)), - MINE_CART_QUIDAMORTEM("Minecart", new WorldPoint(1253, 3550, 0)), - MINE_CART_SHAYZIEN("Minecart", new WorldPoint(1586, 3622, 0)), - MINE_CART_TAVERLEY_UNDERGROUND("Minecart", new WorldPoint(2874, 9870, 0)), - CART_TO_BRIMHAVEN("Cart to Brimhaven", new WorldPoint(2833, 2958, 0)), - CART_TO_SHILO("Cart to Shilo", new WorldPoint(2780, 3214, 0)), - - //Canoes - CANOE_BARBVILLAGE("Canoe", new WorldPoint(3111, 3409, 0)), - CANOE_CHAMPIONSGUILD("Canoe", new WorldPoint(3202, 3344, 0)), - CANOE_EDGEVILLE("Canoe", new WorldPoint(3130, 3509, 0)), - CANOE_LUMBRIDGE("Canoe", new WorldPoint(3241, 3238, 0)), - - //Gnome Gliders - GNOME_GLIDER_KHARID("Gnome Glider", new WorldPoint(3278, 3213, 0)), - GNOME_GLIDER_APE_ATOLL("Gnome Glider", new WorldPoint(2712, 2804, 0)), - GNOME_GLIDER_KARAMJA("Gnome Glider", new WorldPoint(2971, 2974, 0)), - GNOME_GLIDER_FELDIP("Gnome Glider", new WorldPoint(2540, 2969, 0)), - GNOME_GLIDER_GNOMESTRONGHOLD("Gnome Glider", new WorldPoint(2460, 3502, 0)), - GNOME_GLIDER_WHITEWOLF("Gnome Glider", new WorldPoint(2845, 3501, 0)), - - //Balloons - BALLOON_VARROCK("Hot Air Balloon", new WorldPoint(3298, 3480, 0)), - BALLOON_YANILLE("Hot Air Balloon", new WorldPoint(2458, 3108, 0)), - BALLOON_GNOMESTRONGHOLD("Hot Air Balloon", new WorldPoint(2478, 3459, 0)), - BALLOON_TAVERLEY("Hot Air Balloon", new WorldPoint(2936, 3422, 0)), - BALLOON_FALADOR("Hot Air Balloon", new WorldPoint(2921, 3301, 0)), - - //Spirit Tree - SPIRITTREE_ARDOUGNE("Spirit Tree", new WorldPoint(2554, 3259, 0)), - SPIRITTREE_CORSAIR("Spirit Tree", new WorldPoint(2485, 2850, 0)), - SPIRITTREE_GNOMESTRONGHOLD("Spirit Tree", new WorldPoint(2459, 3446, 0)), - SPIRITTREE_GNOMEVILLAGE("Spirit Tree", new WorldPoint(2538, 3166, 0)), - SPIRITTREE_GRANDEXCHANGE("Spirit Tree", new WorldPoint(3184, 3510, 0)), - - //Carpets - CARPET_KHARID("Carpet to Bedabin/Pollnivneach/Uzer", new WorldPoint(3311, 3107, 0)), - CARPET_BEDABIN("Carpet to Shantay Pass", new WorldPoint(3183, 3042, 0)), - CARPET_POLLNIVNEACH_NORTH("Carpet to Shantay Pass", new WorldPoint(3351, 3001, 0)), - CARPET_POLLNIVNEACH_SOUTH("Carpet to Nardah/Sophanem/Menaphos", new WorldPoint(3345, 2943, 0)), - CARPET_NARDAH("Carpet to Pollnivneach", new WorldPoint(3399, 2916, 0)), - CARPET_SOPHANEM("Carpet to Pollnivneach", new WorldPoint(3288, 2814, 0)), - CARPET_MENAPHOS("Carpet to Pollnivneach", new WorldPoint(3244, 2812, 0)), - CARPET_UZER("Carpet to Shantay Pass", new WorldPoint(3468, 3111, 0)), - - //Teleports - TELEPORT_ARCHIVE_FROM_ARCEUUS("Teleport to Library Archive", new WorldPoint(1623, 3808, 0)), - TELEPORT_HARMLESS_FROM_HARMONY("Teleport to Mos Le'Harmless", new WorldPoint(3784, 2828, 0)), - TELEPORT_RUNE_ARDOUGNE("Teleport to Rune Essence", new WorldPoint(2681, 3325, 0)), - TELEPORT_RUNE_YANILLE("Teleport to Rune Essence", new WorldPoint(2592, 3089, 0)), - TELEPORT_SORCERESS_GARDEN("Teleport to Sorceress's Garden", new WorldPoint(3320, 3141, 0)), - - //Other - ALTER_KOUREND_UNDERGROUND("Altar to Skotizo", new WorldPoint(1662, 10047, 0)), - FAIRY_RING_ZANARIS_TO_KHARID("Fairy Ring to Al Kharid", new WorldPoint(2483, 4471, 0)), - FAIRY_RING_ZANARIS_TO_SHACK("Fairy Ring to Shack", new WorldPoint(2451, 4471, 0)), - MOUNTAIN_GUIDE_QUIDAMORTEM("Mountain Guide", new WorldPoint(1275, 3559, 0)), - MOUNTAIN_GUIDE_WALL("Mountain Guide", new WorldPoint(1400, 3538, 0)), - MUSHTREE_MUSHROOM_FOREST("Mushtree", new WorldPoint(3674, 3871, 0)), - MUSHTREE_TAR_SWAMP("Mushtree", new WorldPoint(3676, 3755, 0)), - MUSHTREE_VERDANT_VALLEY("Mushtree", new WorldPoint(3757, 3756, 0)), - MYTHS_GUILD_PORTAL("Portal to Guilds", new WorldPoint(2456, 2856, 0)), - TRAIN_KELDAGRIM("Railway Station", new WorldPoint(2941, 10179, 0)), - WILDERNESS_LEVER_ARDOUGNE("Wilderness Lever", new WorldPoint(2559, 3309, 0)), - WILDERNESS_LEVER_EDGEVILLE("Wilderness Lever", new WorldPoint(3088, 3474, 0)), - WILDERNESS_LEVER_WILDERNESS("Wilderness Lever", new WorldPoint(3154, 3924, 0)); - - private final String tooltip; - private final WorldPoint location; -} +/* + * Copyright (c) 2019, Kyle Sergio + * Copyright (c) 2019, Bryce Altomare + * Copyright (c) 2019, Kyle Stead + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package net.runelite.client.plugins.worldmap; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import net.runelite.api.coords.WorldPoint; + +@Getter +@AllArgsConstructor +enum TransportationPointLocation +{ + //Ships + ARDOUGNE_TO_BRIMHAVEN("Ship to Brimhaven", new WorldPoint(2675, 3275, 0)), + ARDOUGNE_TO_FISHINGPLAT("Ship to Fishing Platform", new WorldPoint(2722, 3304, 0)), + BRIMHAVEN_TO_ARDOUGNE("Ship to Ardougne", new WorldPoint(2772, 3234, 0)), + CATHERBY_TO_KEEP_LE_FAYE("Ship to Keep Le Faye", new WorldPoint(2804, 3421, 0)), + CORSAIR_TO_RIMMINGTON("Ship to Rimmington", new WorldPoint(2577, 2839, 0)), + DRAGONTOOTH_TO_PHASMATYS("Ship to Port Phasmatys", new WorldPoint(3791, 3561, 0)), + DIGSITE_TO_FOSSIL("Ship to Fossil Island", new WorldPoint(3361, 3448, 0)), + ENTRANA_TO_PORTSARIM("Ship to Port Sarim", new WorldPoint(2833, 3334, 0)), + FISHINGPLAT_TO_ARDOUGNE("Ship to Ardougne", new WorldPoint(2779, 3271, 0)), + HARMLESS_TO_PORT_PHASMATYS("Ship to Port Phasmatys", new WorldPoint(3682, 2951, 0)), + ICEBERG_TO_RELLEKKA("Ship to Rellekka", new WorldPoint(2657, 3988, 0)), + ISLAND_TO_APE_ATOLL("Ship to Ape Atoll", new WorldPoint(2891, 2726, 0)), + JATIZSO_TO_RELLEKKA("Ship to Rellekka", new WorldPoint(2420, 3780, 0)), + KARAMJA_TO_PORT_SARIM("Ship to Port Sarim", new WorldPoint(2955, 3144, 0)), + KARAMJA_TO_PORT_KHAZARD("Ship to Port Khazard", new WorldPoint(2763, 2957, 0)), + LANDSEND_TO_PORTSARIM_PORTPISCARILIUS("Ship to Port Sarim/Port Piscarilius", new WorldPoint(1503, 3398, 0)), + LUNAR_ISLE_TO_PIRATES_COVE("Ship to Pirates' Cove", new WorldPoint(2137, 3899, 0)), + MISCELLANIA_TO_RELLEKKA("Ship to Rellekka", new WorldPoint(2579, 3846, 0)), + NEITIZNOT_TO_RELLEKKA("Ship to Rellekka", new WorldPoint(2310, 3779, 0)), + PESTCONTROL_TO_PORTSARIM("Ship to Port Sarim", new WorldPoint(2659, 2675, 0)), + PIRATES_COVE_TO_LUNAR_ISLE("Ship to Lunar Isle", new WorldPoint(2223, 3796, 0)), + PIRATES_COVE_TO_RELLEKKA("Ship to Rellekka", new WorldPoint(2212, 3794, 0)), + PORT_PHASMATYS_TO_DRAGONTOOTH("Ship to Dragontooth Island", new WorldPoint(3703, 3487, 0)), + PORT_PHASMATYS_TO_HARMLESS("Ship to Mos Le'Harmless", new WorldPoint(3709, 3497, 0)), + PORT_PISCARILIUS_TO_PORTSARIM_LANDSEND("Ship to Port Sarim/Land's End", new WorldPoint(1823, 3692, 0)), + PORTSARIM_TO_GREAT_KOUREND("Ship to Great Kourend", new WorldPoint(3054, 3244, 0)), + PORTSARIM_TO_ENTRANA("Ship to Entrana", new WorldPoint(3046, 3233, 0)), + PORTSARIM_TO_KARAMJA("Ship to Karamja", new WorldPoint(3029, 3218, 0)), + PORTSARIM_TO_CRANDOR("Ship to Crandor", new WorldPoint(3045, 3205, 0)), + PORTSARIM_TO_PEST_CONTROL("Ship to Pest Control", new WorldPoint(3039, 3201, 0)), + RELLEKKA_TO_JATIZSO_NEITIZNOT("Ship to Jatizso/Neitiznot", new WorldPoint(2639, 3710, 0)), + RELLEKKA_TO_MISCELLANIA("Ship to Miscellania", new WorldPoint(2627, 3692, 0)), + RELLEKKA_TO_WATERBIRTH("Ship to Waterbirth", new WorldPoint(2621, 3683, 0)), + RELLEKKA_TO_WEISS_ICEBERG("Ship to Weiss/Iceberg", new WorldPoint(2707, 3735, 0)), + RELLEKKA_TO_UNGAEL("Ship to Ungael", new WorldPoint(2638, 3698, 0)), + RIMMINGTON_TO_CORSAIR_COVE("Ship to Corsair Cove", new WorldPoint(2909, 3227, 0)), + WATERBIRTH_TO_RELLEKKA("Ship to Rellekka", new WorldPoint(2549, 3758, 0)), + WEISS_TO_RELLEKKA("Ship to Rellekka", new WorldPoint(2847, 3967, 0)), + UNGAEL_TO_RELLEKKA("Ship to Rellekka", new WorldPoint(2276, 4034, 0)), + + //Row Boats + ROW_BOAT_BATTLEFRONT("Rowboat to Molch/Molch Island/Shayzien", new WorldPoint(1383, 3663, 0)), + ROW_BOAT_BRAIN_DEATH("Rowboat to Port Phasmatys", new WorldPoint(2161, 5117, 0)), + ROW_BOAT_BURGH_DE_ROTT("Rowboat to Meiyerditch", new WorldPoint(3522, 3168, 0)), + ROW_BOAT_CRABCLAW("Rowboat to Hosidius", new WorldPoint(1780, 3417, 0)), + ROW_BOAT_DIVING_ISLAND("Rowboat to Barge/Camp/North of Island", new WorldPoint(3764, 3901, 0)), + ROW_BOAT_FISHING_GUILD("Rowboat to Hemenster", new WorldPoint(2598, 3426, 0)), + ROW_BOAT_GNOME_STRONGHOLD("Rowboat to Fishing Colony", new WorldPoint(2368, 3487, 0)), + ROW_BOAT_FISHING_COLONY("Rowboat to Gnome Stronghold", new WorldPoint(2356, 3641, 0)), + ROW_BOAT_HEMENSTER("Rowboat to Fishing Guild", new WorldPoint(2613, 3439, 0)), + ROW_BOAT_HOSIDIUS("Rowboat to Crabclaw Isle", new WorldPoint(1779, 3457, 0)), + ROW_BOAT_LITHKREN("Rowboat to Mushroom Forest", new WorldPoint(3582, 3973, 0)), + ROW_BOAT_LUMBRIDGE("Rowboat to Misthalin Mystery", new WorldPoint(3238, 3141, 0)), + ROW_BOAT_MOLCH("Rowboat to Molch Island/Shayzien/Battlefront", new WorldPoint(1343, 3646, 0)), + ROW_BOAT_MOLCH_ISLAND("Rowboat to Molch/Shayzien/Battlefront", new WorldPoint(1368, 3641, 0)), + ROW_BOAT_MORT("Rowboat to Mort Myre", new WorldPoint(3518, 3284, 0)), + ROW_BOAT_MORT_SWAMP("Rowboat to Mort'ton", new WorldPoint(3498, 3380, 0)), + ROW_BOAT_MUSEUM_CAMP("Rowboat to Barge/Digsite/North of Island", new WorldPoint(3723, 3807, 0)), + ROW_BOAT_MUSHROOM_FOREST_WEST("Rowboat to Lithkren", new WorldPoint(3659, 3849, 0)), + ROW_BOAT_MUSHROOM_FOREST_NE("Rowboat to Barge/Camp/Sea", new WorldPoint(3733, 3894, 0)), + ROW_BOAT_PORT_PHASMATYS_NORTH("Rowboat to Slepe", new WorldPoint(3670, 3545, 0)), + ROW_BOAT_PORT_PHASMATYS_EAST("Rowboat to Braindeath Island", new WorldPoint(3680, 3538, 0)), + ROW_BOAT_SHAYZIEN("Rowboat to Molch/Molch Island/Battlefront", new WorldPoint(1405, 3612, 0)), + ROW_BOAT_SLEPE("Rowboat to Port Phasmatys", new WorldPoint(3661, 3279, 0)), + OGRE_BOAT_FELDIP("Ogre Boat to Karamja", new WorldPoint(2653, 2964, 0)), + OGRE_BOAT_KARAMJA("Ogre Boat to Feldip", new WorldPoint(2757, 3085, 0)), + + //Charter ships + CHARTER_BRIMHAVEN("Charter Ship", new WorldPoint(2760, 3238, 0)), + CHARTER_CATHERBY("Charter Ship", new WorldPoint(2791, 3415, 0)), + CHARTER_CORSAIR_("Charter Ship", new WorldPoint(2589, 2851, 0)), + CHARTER_KARAMJA_NORTH("Charter Ship", new WorldPoint(2954, 3159, 0)), + CHARTER_KARAMJA_EAST("Charter Ship", new WorldPoint(2999, 3032, 0)), + CHARTER_KHAZARD("Charter Ship", new WorldPoint(2673, 3143, 0)), + CHARTER_MOSLE_HARMLESS("Charter Ship", new WorldPoint(3669, 2931, 0)), + CHARTER_PORT_PHASMATYS("Charter Ship", new WorldPoint(3702, 3503, 0)), + CHARTER_PORTSARIM("Charter Ship", new WorldPoint(3037, 3191, 0)), + CHARTER_TYRAS("Charter Ship", new WorldPoint(2141, 3123, 0)), + + //Minecarts/Carts + MINE_CART_ARCEUUS("Minecart", new WorldPoint(1673, 3832, 0)), + MINE_CART_GRANDEXCHANGE("Minecart to Keldagrim", new WorldPoint(3139, 3504, 0)), + MINE_CART_HOSIDIUS("Minecart", new WorldPoint(1656, 3542, 0)), + MINE_CART_KELDAGRIM("Minecart", new WorldPoint(2908, 10170, 0)), + MINE_CART_LOVAKENGJ("Minecart", new WorldPoint(1524, 3721, 0)), + MINE_CART_PORT_PISCARILIUS("Minecart", new WorldPoint(1760, 3708, 0)), + MINE_CART_QUIDAMORTEM("Minecart", new WorldPoint(1253, 3550, 0)), + MINE_CART_SHAYZIEN("Minecart", new WorldPoint(1586, 3622, 0)), + MINE_CART_TAVERLEY_UNDERGROUND("Minecart", new WorldPoint(2874, 9870, 0)), + CART_TO_BRIMHAVEN("Cart to Brimhaven", new WorldPoint(2833, 2958, 0)), + CART_TO_SHILO("Cart to Shilo", new WorldPoint(2780, 3214, 0)), + + //Canoes + CANOE_BARBVILLAGE("Canoe", new WorldPoint(3111, 3409, 0)), + CANOE_CHAMPIONSGUILD("Canoe", new WorldPoint(3202, 3344, 0)), + CANOE_EDGEVILLE("Canoe", new WorldPoint(3130, 3509, 0)), + CANOE_LUMBRIDGE("Canoe", new WorldPoint(3241, 3238, 0)), + + //Gnome Gliders + GNOME_GLIDER_KHARID("Gnome Glider", new WorldPoint(3278, 3213, 0)), + GNOME_GLIDER_APE_ATOLL("Gnome Glider", new WorldPoint(2712, 2804, 0)), + GNOME_GLIDER_KARAMJA("Gnome Glider", new WorldPoint(2971, 2974, 0)), + GNOME_GLIDER_FELDIP("Gnome Glider", new WorldPoint(2540, 2969, 0)), + GNOME_GLIDER_GNOMESTRONGHOLD("Gnome Glider", new WorldPoint(2460, 3502, 0)), + GNOME_GLIDER_WHITEWOLF("Gnome Glider", new WorldPoint(2845, 3501, 0)), + + //Balloons + BALLOON_VARROCK("Hot Air Balloon", new WorldPoint(3298, 3480, 0)), + BALLOON_YANILLE("Hot Air Balloon", new WorldPoint(2458, 3108, 0)), + BALLOON_GNOMESTRONGHOLD("Hot Air Balloon", new WorldPoint(2478, 3459, 0)), + BALLOON_TAVERLEY("Hot Air Balloon", new WorldPoint(2936, 3422, 0)), + BALLOON_FALADOR("Hot Air Balloon", new WorldPoint(2921, 3301, 0)), + + //Spirit Tree + SPIRITTREE_ARDOUGNE("Spirit Tree", new WorldPoint(2554, 3259, 0)), + SPIRITTREE_CORSAIR("Spirit Tree", new WorldPoint(2485, 2850, 0)), + SPIRITTREE_GNOMESTRONGHOLD("Spirit Tree", new WorldPoint(2459, 3446, 0)), + SPIRITTREE_GNOMEVILLAGE("Spirit Tree", new WorldPoint(2538, 3166, 0)), + SPIRITTREE_GRANDEXCHANGE("Spirit Tree", new WorldPoint(3184, 3510, 0)), + + //Carpets + CARPET_KHARID("Carpet to Bedabin/Pollnivneach/Uzer", new WorldPoint(3311, 3107, 0)), + CARPET_BEDABIN("Carpet to Shantay Pass", new WorldPoint(3183, 3042, 0)), + CARPET_POLLNIVNEACH_NORTH("Carpet to Shantay Pass", new WorldPoint(3351, 3001, 0)), + CARPET_POLLNIVNEACH_SOUTH("Carpet to Nardah/Sophanem/Menaphos", new WorldPoint(3345, 2943, 0)), + CARPET_NARDAH("Carpet to Pollnivneach", new WorldPoint(3399, 2916, 0)), + CARPET_SOPHANEM("Carpet to Pollnivneach", new WorldPoint(3288, 2814, 0)), + CARPET_MENAPHOS("Carpet to Pollnivneach", new WorldPoint(3244, 2812, 0)), + CARPET_UZER("Carpet to Shantay Pass", new WorldPoint(3468, 3111, 0)), + + //Teleports + TELEPORT_ARCHIVE_FROM_ARCEUUS("Teleport to Library Archive", new WorldPoint(1623, 3808, 0)), + TELEPORT_HARMLESS_FROM_HARMONY("Teleport to Mos Le'Harmless", new WorldPoint(3784, 2828, 0)), + TELEPORT_RUNE_ARDOUGNE("Teleport to Rune Essence", new WorldPoint(2681, 3325, 0)), + TELEPORT_RUNE_YANILLE("Teleport to Rune Essence", new WorldPoint(2592, 3089, 0)), + TELEPORT_SORCERESS_GARDEN("Teleport to Sorceress's Garden", new WorldPoint(3320, 3141, 0)), + + //Other + ALTER_KOUREND_UNDERGROUND("Altar to Skotizo", new WorldPoint(1662, 10047, 0)), + FAIRY_RING_ZANARIS_TO_KHARID("Fairy Ring to Al Kharid", new WorldPoint(2483, 4471, 0)), + FAIRY_RING_ZANARIS_TO_SHACK("Fairy Ring to Shack", new WorldPoint(2451, 4471, 0)), + MOUNTAIN_GUIDE_QUIDAMORTEM("Mountain Guide", new WorldPoint(1275, 3559, 0)), + MOUNTAIN_GUIDE_WALL("Mountain Guide", new WorldPoint(1400, 3538, 0)), + MUSHTREE_MUSHROOM_FOREST("Mushtree", new WorldPoint(3674, 3871, 0)), + MUSHTREE_TAR_SWAMP("Mushtree", new WorldPoint(3676, 3755, 0)), + MUSHTREE_VERDANT_VALLEY("Mushtree", new WorldPoint(3757, 3756, 0)), + MYTHS_GUILD_PORTAL("Portal to Guilds", new WorldPoint(2456, 2856, 0)), + TRAIN_KELDAGRIM("Railway Station", new WorldPoint(2941, 10179, 0)), + WILDERNESS_LEVER_ARDOUGNE("Wilderness Lever", new WorldPoint(2559, 3309, 0)), + WILDERNESS_LEVER_EDGEVILLE("Wilderness Lever", new WorldPoint(3088, 3474, 0)), + WILDERNESS_LEVER_WILDERNESS("Wilderness Lever", new WorldPoint(3154, 3924, 0)); + + private final String tooltip; + private final WorldPoint location; +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/worldmap/WorldMapPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/worldmap/WorldMapPlugin.java index 5fd38d5ff2..4392a64a54 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/worldmap/WorldMapPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/worldmap/WorldMapPlugin.java @@ -1,274 +1,274 @@ -/* - * Copyright (c) 2018, Morgan Lewis - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package net.runelite.client.plugins.worldmap; - -import com.google.inject.Inject; -import com.google.inject.Provides; -import java.awt.image.BufferedImage; -import java.util.Arrays; -import net.runelite.api.Client; -import net.runelite.api.Experience; -import net.runelite.api.Skill; -import net.runelite.api.events.ConfigChanged; -import net.runelite.api.events.ExperienceChanged; -import net.runelite.client.config.ConfigManager; -import net.runelite.client.eventbus.Subscribe; -import net.runelite.client.game.AgilityShortcut; -import net.runelite.client.plugins.Plugin; -import net.runelite.client.plugins.PluginDescriptor; -import net.runelite.client.ui.overlay.worldmap.WorldMapPointManager; -import net.runelite.client.util.ImageUtil; - -@PluginDescriptor( - name = "World Map", - description = "Enhance the world map to display additional information", - tags = {"agility", "fairy", "farming", "rings", "teleports"} -) -public class WorldMapPlugin extends Plugin -{ - static final BufferedImage BLANK_ICON; - private static final BufferedImage FAIRY_TRAVEL_ICON; - private static final BufferedImage NOPE_ICON; - - static final String CONFIG_KEY = "worldmap"; - static final String CONFIG_KEY_FAIRY_RING_TOOLTIPS = "fairyRingTooltips"; - static final String CONFIG_KEY_FAIRY_RING_ICON = "fairyRingIcon"; - static final String CONFIG_KEY_AGILITY_SHORTCUT_TOOLTIPS = "agilityShortcutTooltips"; - static final String CONFIG_KEY_AGILITY_SHORTCUT_LEVEL_ICON = "agilityShortcutIcon"; - static final String CONFIG_KEY_NORMAL_TELEPORT_ICON = "standardSpellbookIcon"; - static final String CONFIG_KEY_ANCIENT_TELEPORT_ICON = "ancientSpellbookIcon"; - static final String CONFIG_KEY_LUNAR_TELEPORT_ICON = "lunarSpellbookIcon"; - static final String CONFIG_KEY_ARCEUUS_TELEPORT_ICON = "arceuusSpellbookIcon"; - static final String CONFIG_KEY_JEWELLERY_TELEPORT_ICON = "jewelleryIcon"; - static final String CONFIG_KEY_SCROLL_TELEPORT_ICON = "scrollIcon"; - static final String CONFIG_KEY_MISC_TELEPORT_ICON = "miscellaneousTeleportIcon"; - static final String CONFIG_KEY_QUEST_START_TOOLTIPS = "questStartTooltips"; - static final String CONFIG_KEY_MINIGAME_TOOLTIP = "minigameTooltip"; - static final String CONFIG_KEY_FARMING_PATCH_TOOLTIPS = "farmingpatchTooltips"; - static final String CONFIG_KEY_RARE_TREE_TOOLTIPS = "rareTreeTooltips"; - static final String CONFIG_KEY_RARE_TREE_LEVEL_ICON = "rareTreeIcon"; - static final String CONFIG_KEY_TRANSPORATION_TELEPORT_TOOLTIPS = "transportationTooltips"; - - static - { - //A size of 17 gives us a buffer when triggering tooltips - final int iconBufferSize = 17; - - BLANK_ICON = new BufferedImage(iconBufferSize, iconBufferSize, BufferedImage.TYPE_INT_ARGB); - - FAIRY_TRAVEL_ICON = new BufferedImage(iconBufferSize, iconBufferSize, BufferedImage.TYPE_INT_ARGB); - final BufferedImage fairyTravelIcon = ImageUtil.getResourceStreamFromClass(WorldMapPlugin.class, "fairy_ring_travel.png"); - FAIRY_TRAVEL_ICON.getGraphics().drawImage(fairyTravelIcon, 1, 1, null); - - NOPE_ICON = new BufferedImage(iconBufferSize, iconBufferSize, BufferedImage.TYPE_INT_ARGB); - final BufferedImage nopeImage = ImageUtil.getResourceStreamFromClass(WorldMapPlugin.class, "nope_icon.png"); - NOPE_ICON.getGraphics().drawImage(nopeImage, 1, 1, null); - } - - @Inject - private Client client; - - @Inject - private WorldMapConfig config; - - @Inject - private WorldMapPointManager worldMapPointManager; - - private int agilityLevel = 0; - private int woodcuttingLevel = 0; - - @Provides - WorldMapConfig provideConfig(ConfigManager configManager) - { - return configManager.getConfig(WorldMapConfig.class); - } - - @Override - protected void startUp() throws Exception - { - agilityLevel = client.getRealSkillLevel(Skill.AGILITY); - woodcuttingLevel = client.getRealSkillLevel(Skill.WOODCUTTING); - updateShownIcons(); - } - - @Override - protected void shutDown() throws Exception - { - worldMapPointManager.removeIf(FairyRingPoint.class::isInstance); - worldMapPointManager.removeIf(AgilityShortcutPoint.class::isInstance); - worldMapPointManager.removeIf(QuestStartPoint.class::isInstance); - worldMapPointManager.removeIf(TeleportPoint.class::isInstance); - worldMapPointManager.removeIf(TransportationPoint.class::isInstance); - worldMapPointManager.removeIf(MinigamePoint.class::isInstance); - worldMapPointManager.removeIf(FarmingPatchPoint.class::isInstance); - worldMapPointManager.removeIf(RareTreePoint.class::isInstance); - agilityLevel = 0; - woodcuttingLevel = 0; - } - - @Subscribe - public void onConfigChanged(ConfigChanged event) - { - if (!event.getGroup().equals(CONFIG_KEY)) - { - return; - } - - updateShownIcons(); - } - - @Subscribe - public void onExperienceChanged(ExperienceChanged event) - { - if (event.getSkill() == Skill.AGILITY) - { - int newAgilityLevel = Experience.getLevelForXp(client.getSkillExperience(Skill.AGILITY)); - if (newAgilityLevel != agilityLevel) - { - agilityLevel = newAgilityLevel; - updateAgilityIcons(); - } - } - - if (event.getSkill() == Skill.WOODCUTTING) - { - int newWoodcutLevel = Experience.getLevelForXp(client.getSkillExperience(Skill.WOODCUTTING)); - if (newWoodcutLevel != woodcuttingLevel) - { - woodcuttingLevel = newWoodcutLevel; - updateRareTreeIcons(); - } - } - } - - private void updateAgilityIcons() - { - worldMapPointManager.removeIf(AgilityShortcutPoint.class::isInstance); - - if (config.agilityShortcutLevelIcon() || config.agilityShortcutTooltips()) - { - Arrays.stream(AgilityShortcut.values()) - .filter(value -> value.getWorldMapLocation() != null) - .map(value -> new AgilityShortcutPoint(value, - agilityLevel > 0 && config.agilityShortcutLevelIcon() && value.getLevel() > agilityLevel ? NOPE_ICON : BLANK_ICON, - config.agilityShortcutTooltips())) - .forEach(worldMapPointManager::add); - } - } - - private void updateRareTreeIcons() - { - worldMapPointManager.removeIf(RareTreePoint.class::isInstance); - - if (config.rareTreeLevelIcon() || config.rareTreeTooltips()) - { - Arrays.stream(RareTreeLocation.values()).forEach(rareTree -> - Arrays.stream(rareTree.getLocations()) - .map(point -> new RareTreePoint(point, - rareTree.getTooltip(), - woodcuttingLevel > 0 && config.rareTreeLevelIcon() && - rareTree.getLevelReq() > woodcuttingLevel ? NOPE_ICON : BLANK_ICON, - config.rareTreeTooltips())) - .forEach(worldMapPointManager::add)); - } - } - - private void updateShownIcons() - { - updateAgilityIcons(); - updateRareTreeIcons(); - - worldMapPointManager.removeIf(FairyRingPoint.class::isInstance); - if (config.fairyRingIcon() || config.fairyRingTooltips()) - { - Arrays.stream(FairyRingLocation.values()) - .map(value -> new FairyRingPoint(value, - config.fairyRingIcon() ? FAIRY_TRAVEL_ICON : BLANK_ICON, - config.fairyRingTooltips())) - .forEach(worldMapPointManager::add); - } - - worldMapPointManager.removeIf(MinigamePoint.class::isInstance); - if (config.minigameTooltip()) - { - Arrays.stream(MinigameLocation.values()) - .map(value -> new MinigamePoint(value, BLANK_ICON)) - .forEach(worldMapPointManager::add); - } - - worldMapPointManager.removeIf(QuestStartPoint.class::isInstance); - if (config.questStartTooltips()) - { - Arrays.stream(QuestStartLocation.values()) - .map(value -> new QuestStartPoint(value, BLANK_ICON)) - .forEach(worldMapPointManager::add); - } - - worldMapPointManager.removeIf(TransportationPoint.class::isInstance); - if (config.transportationTeleportTooltips()) - { - Arrays.stream(TransportationPointLocation.values()) - .map(value -> new TransportationPoint(value, BLANK_ICON)) - .forEach((worldMapPointManager::add)); - } - - worldMapPointManager.removeIf(FarmingPatchPoint.class::isInstance); - if (config.farmingPatchTooltips()) - { - Arrays.stream(FarmingPatchLocation.values()).forEach(location -> - Arrays.stream(location.getLocations()) - .map(point -> new FarmingPatchPoint(point, location.getTooltip(), BLANK_ICON)) - .forEach(worldMapPointManager::add) - ); - } - - worldMapPointManager.removeIf(TeleportPoint.class::isInstance); - Arrays.stream(TeleportLocationData.values()) - .filter(data -> - { - switch (data.getType()) - { - case NORMAL_MAGIC: - return config.normalTeleportIcon(); - case ANCIENT_MAGICKS: - return config.ancientTeleportIcon(); - case LUNAR_MAGIC: - return config.lunarTeleportIcon(); - case ARCEUUS_MAGIC: - return config.arceuusTeleportIcon(); - case JEWELLERY: - return config.jewelleryTeleportIcon(); - case SCROLL: - return config.scrollTeleportIcon(); - case OTHER: - return config.miscellaneousTeleportIcon(); - default: - return false; - } - }).map(TeleportPoint::new) - .forEach(worldMapPointManager::add); - } -} +/* + * Copyright (c) 2018, Morgan Lewis + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package net.runelite.client.plugins.worldmap; + +import com.google.inject.Inject; +import com.google.inject.Provides; +import java.awt.image.BufferedImage; +import java.util.Arrays; +import net.runelite.api.Client; +import net.runelite.api.Experience; +import net.runelite.api.Skill; +import net.runelite.api.events.ConfigChanged; +import net.runelite.api.events.ExperienceChanged; +import net.runelite.client.config.ConfigManager; +import net.runelite.client.eventbus.Subscribe; +import net.runelite.client.game.AgilityShortcut; +import net.runelite.client.plugins.Plugin; +import net.runelite.client.plugins.PluginDescriptor; +import net.runelite.client.ui.overlay.worldmap.WorldMapPointManager; +import net.runelite.client.util.ImageUtil; + +@PluginDescriptor( + name = "World Map", + description = "Enhance the world map to display additional information", + tags = {"agility", "fairy", "farming", "rings", "teleports"} +) +public class WorldMapPlugin extends Plugin +{ + static final BufferedImage BLANK_ICON; + private static final BufferedImage FAIRY_TRAVEL_ICON; + private static final BufferedImage NOPE_ICON; + + static final String CONFIG_KEY = "worldmap"; + static final String CONFIG_KEY_FAIRY_RING_TOOLTIPS = "fairyRingTooltips"; + static final String CONFIG_KEY_FAIRY_RING_ICON = "fairyRingIcon"; + static final String CONFIG_KEY_AGILITY_SHORTCUT_TOOLTIPS = "agilityShortcutTooltips"; + static final String CONFIG_KEY_AGILITY_SHORTCUT_LEVEL_ICON = "agilityShortcutIcon"; + static final String CONFIG_KEY_NORMAL_TELEPORT_ICON = "standardSpellbookIcon"; + static final String CONFIG_KEY_ANCIENT_TELEPORT_ICON = "ancientSpellbookIcon"; + static final String CONFIG_KEY_LUNAR_TELEPORT_ICON = "lunarSpellbookIcon"; + static final String CONFIG_KEY_ARCEUUS_TELEPORT_ICON = "arceuusSpellbookIcon"; + static final String CONFIG_KEY_JEWELLERY_TELEPORT_ICON = "jewelleryIcon"; + static final String CONFIG_KEY_SCROLL_TELEPORT_ICON = "scrollIcon"; + static final String CONFIG_KEY_MISC_TELEPORT_ICON = "miscellaneousTeleportIcon"; + static final String CONFIG_KEY_QUEST_START_TOOLTIPS = "questStartTooltips"; + static final String CONFIG_KEY_MINIGAME_TOOLTIP = "minigameTooltip"; + static final String CONFIG_KEY_FARMING_PATCH_TOOLTIPS = "farmingpatchTooltips"; + static final String CONFIG_KEY_RARE_TREE_TOOLTIPS = "rareTreeTooltips"; + static final String CONFIG_KEY_RARE_TREE_LEVEL_ICON = "rareTreeIcon"; + static final String CONFIG_KEY_TRANSPORATION_TELEPORT_TOOLTIPS = "transportationTooltips"; + + static + { + //A size of 17 gives us a buffer when triggering tooltips + final int iconBufferSize = 17; + + BLANK_ICON = new BufferedImage(iconBufferSize, iconBufferSize, BufferedImage.TYPE_INT_ARGB); + + FAIRY_TRAVEL_ICON = new BufferedImage(iconBufferSize, iconBufferSize, BufferedImage.TYPE_INT_ARGB); + final BufferedImage fairyTravelIcon = ImageUtil.getResourceStreamFromClass(WorldMapPlugin.class, "fairy_ring_travel.png"); + FAIRY_TRAVEL_ICON.getGraphics().drawImage(fairyTravelIcon, 1, 1, null); + + NOPE_ICON = new BufferedImage(iconBufferSize, iconBufferSize, BufferedImage.TYPE_INT_ARGB); + final BufferedImage nopeImage = ImageUtil.getResourceStreamFromClass(WorldMapPlugin.class, "nope_icon.png"); + NOPE_ICON.getGraphics().drawImage(nopeImage, 1, 1, null); + } + + @Inject + private Client client; + + @Inject + private WorldMapConfig config; + + @Inject + private WorldMapPointManager worldMapPointManager; + + private int agilityLevel = 0; + private int woodcuttingLevel = 0; + + @Provides + WorldMapConfig provideConfig(ConfigManager configManager) + { + return configManager.getConfig(WorldMapConfig.class); + } + + @Override + protected void startUp() throws Exception + { + agilityLevel = client.getRealSkillLevel(Skill.AGILITY); + woodcuttingLevel = client.getRealSkillLevel(Skill.WOODCUTTING); + updateShownIcons(); + } + + @Override + protected void shutDown() throws Exception + { + worldMapPointManager.removeIf(FairyRingPoint.class::isInstance); + worldMapPointManager.removeIf(AgilityShortcutPoint.class::isInstance); + worldMapPointManager.removeIf(QuestStartPoint.class::isInstance); + worldMapPointManager.removeIf(TeleportPoint.class::isInstance); + worldMapPointManager.removeIf(TransportationPoint.class::isInstance); + worldMapPointManager.removeIf(MinigamePoint.class::isInstance); + worldMapPointManager.removeIf(FarmingPatchPoint.class::isInstance); + worldMapPointManager.removeIf(RareTreePoint.class::isInstance); + agilityLevel = 0; + woodcuttingLevel = 0; + } + + @Subscribe + public void onConfigChanged(ConfigChanged event) + { + if (!event.getGroup().equals(CONFIG_KEY)) + { + return; + } + + updateShownIcons(); + } + + @Subscribe + public void onExperienceChanged(ExperienceChanged event) + { + if (event.getSkill() == Skill.AGILITY) + { + int newAgilityLevel = Experience.getLevelForXp(client.getSkillExperience(Skill.AGILITY)); + if (newAgilityLevel != agilityLevel) + { + agilityLevel = newAgilityLevel; + updateAgilityIcons(); + } + } + + if (event.getSkill() == Skill.WOODCUTTING) + { + int newWoodcutLevel = Experience.getLevelForXp(client.getSkillExperience(Skill.WOODCUTTING)); + if (newWoodcutLevel != woodcuttingLevel) + { + woodcuttingLevel = newWoodcutLevel; + updateRareTreeIcons(); + } + } + } + + private void updateAgilityIcons() + { + worldMapPointManager.removeIf(AgilityShortcutPoint.class::isInstance); + + if (config.agilityShortcutLevelIcon() || config.agilityShortcutTooltips()) + { + Arrays.stream(AgilityShortcut.values()) + .filter(value -> value.getWorldMapLocation() != null) + .map(value -> new AgilityShortcutPoint(value, + agilityLevel > 0 && config.agilityShortcutLevelIcon() && value.getLevel() > agilityLevel ? NOPE_ICON : BLANK_ICON, + config.agilityShortcutTooltips())) + .forEach(worldMapPointManager::add); + } + } + + private void updateRareTreeIcons() + { + worldMapPointManager.removeIf(RareTreePoint.class::isInstance); + + if (config.rareTreeLevelIcon() || config.rareTreeTooltips()) + { + Arrays.stream(RareTreeLocation.values()).forEach(rareTree -> + Arrays.stream(rareTree.getLocations()) + .map(point -> new RareTreePoint(point, + rareTree.getTooltip(), + woodcuttingLevel > 0 && config.rareTreeLevelIcon() && + rareTree.getLevelReq() > woodcuttingLevel ? NOPE_ICON : BLANK_ICON, + config.rareTreeTooltips())) + .forEach(worldMapPointManager::add)); + } + } + + private void updateShownIcons() + { + updateAgilityIcons(); + updateRareTreeIcons(); + + worldMapPointManager.removeIf(FairyRingPoint.class::isInstance); + if (config.fairyRingIcon() || config.fairyRingTooltips()) + { + Arrays.stream(FairyRingLocation.values()) + .map(value -> new FairyRingPoint(value, + config.fairyRingIcon() ? FAIRY_TRAVEL_ICON : BLANK_ICON, + config.fairyRingTooltips())) + .forEach(worldMapPointManager::add); + } + + worldMapPointManager.removeIf(MinigamePoint.class::isInstance); + if (config.minigameTooltip()) + { + Arrays.stream(MinigameLocation.values()) + .map(value -> new MinigamePoint(value, BLANK_ICON)) + .forEach(worldMapPointManager::add); + } + + worldMapPointManager.removeIf(QuestStartPoint.class::isInstance); + if (config.questStartTooltips()) + { + Arrays.stream(QuestStartLocation.values()) + .map(value -> new QuestStartPoint(value, BLANK_ICON)) + .forEach(worldMapPointManager::add); + } + + worldMapPointManager.removeIf(TransportationPoint.class::isInstance); + if (config.transportationTeleportTooltips()) + { + Arrays.stream(TransportationPointLocation.values()) + .map(value -> new TransportationPoint(value, BLANK_ICON)) + .forEach((worldMapPointManager::add)); + } + + worldMapPointManager.removeIf(FarmingPatchPoint.class::isInstance); + if (config.farmingPatchTooltips()) + { + Arrays.stream(FarmingPatchLocation.values()).forEach(location -> + Arrays.stream(location.getLocations()) + .map(point -> new FarmingPatchPoint(point, location.getTooltip(), BLANK_ICON)) + .forEach(worldMapPointManager::add) + ); + } + + worldMapPointManager.removeIf(TeleportPoint.class::isInstance); + Arrays.stream(TeleportLocationData.values()) + .filter(data -> + { + switch (data.getType()) + { + case NORMAL_MAGIC: + return config.normalTeleportIcon(); + case ANCIENT_MAGICKS: + return config.ancientTeleportIcon(); + case LUNAR_MAGIC: + return config.lunarTeleportIcon(); + case ARCEUUS_MAGIC: + return config.arceuusTeleportIcon(); + case JEWELLERY: + return config.jewelleryTeleportIcon(); + case SCROLL: + return config.scrollTeleportIcon(); + case OTHER: + return config.miscellaneousTeleportIcon(); + default: + return false; + } + }).map(TeleportPoint::new) + .forEach(worldMapPointManager::add); + } +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/xpglobes/XpGlobesPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/xpglobes/XpGlobesPlugin.java index ea2aabc2b5..3cd1489d9e 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/xpglobes/XpGlobesPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/xpglobes/XpGlobesPlugin.java @@ -1,187 +1,187 @@ -/* - * Copyright (c) 2017, Steve - * 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.xpglobes; - -import com.google.inject.Provides; -import java.time.Instant; -import java.time.temporal.ChronoUnit; -import java.util.ArrayList; -import java.util.Iterator; -import java.util.List; -import javax.inject.Inject; -import lombok.Getter; -import net.runelite.api.Client; -import net.runelite.api.Experience; -import net.runelite.api.Skill; -import net.runelite.api.events.ExperienceChanged; -import net.runelite.api.events.GameStateChanged; -import net.runelite.client.config.ConfigManager; -import net.runelite.client.eventbus.Subscribe; -import net.runelite.client.plugins.Plugin; -import net.runelite.client.plugins.PluginDependency; -import net.runelite.client.plugins.PluginDescriptor; -import net.runelite.client.plugins.xptracker.XpTrackerPlugin; -import net.runelite.client.task.Schedule; -import net.runelite.client.ui.overlay.OverlayManager; - -@PluginDescriptor( - name = "XP Globes", - description = "Show XP globes for the respective skill when gaining XP", - tags = {"experience", "levels", "overlay"}, - enabledByDefault = false -) -@PluginDependency(XpTrackerPlugin.class) -public class XpGlobesPlugin extends Plugin -{ - private static final int MAXIMUM_SHOWN_GLOBES = 5; - - private XpGlobe[] globeCache = new XpGlobe[Skill.values().length - 1]; //overall does not trigger xp change event - - @Getter - private final List xpGlobes = new ArrayList<>(); - - @Inject - private Client client; - - @Inject - private XpGlobesConfig config; - - @Inject - private OverlayManager overlayManager; - - @Inject - private XpGlobesOverlay overlay; - - @Provides - XpGlobesConfig getConfig(ConfigManager configManager) - { - return configManager.getConfig(XpGlobesConfig.class); - } - - @Override - protected void startUp() throws Exception - { - overlayManager.add(overlay); - } - - @Override - protected void shutDown() throws Exception - { - overlayManager.remove(overlay); - } - - @Subscribe - public void onExperienceChanged(ExperienceChanged event) - { - Skill skill = event.getSkill(); - int currentXp = client.getSkillExperience(skill); - int currentLevel = Experience.getLevelForXp(currentXp); - int skillIdx = skill.ordinal(); - XpGlobe cachedGlobe = globeCache[skillIdx]; - - // ExperienceChanged event occurs when stats drain/boost check we have an change to actual xp - if (cachedGlobe != null && (cachedGlobe.getCurrentXp() >= currentXp)) - { - return; - } - - if (config.hideMaxed() && currentLevel >= Experience.MAX_REAL_LEVEL) - { - return; - } - - if (cachedGlobe != null) - { - cachedGlobe.setSkill(skill); - cachedGlobe.setCurrentXp(currentXp); - cachedGlobe.setCurrentLevel(currentLevel); - cachedGlobe.setTime(Instant.now()); - this.addXpGlobe(globeCache[skillIdx], MAXIMUM_SHOWN_GLOBES); - } - else - { - // dont draw non cached globes, this is triggered on login to setup all of the initial values - globeCache[skillIdx] = new XpGlobe(skill, currentXp, currentLevel, Instant.now()); - } - } - - private void addXpGlobe(XpGlobe xpGlobe, int maxLength) - { - //remove the old globe, allowing it to be readded as the most recent (right) side when drawn - xpGlobes.remove(xpGlobe); - if (getXpGlobesSize() >= maxLength) - { - xpGlobes.remove(0); - } - xpGlobes.add(xpGlobe); - } - - int getXpGlobesSize() - { - return xpGlobes.size(); - } - - @Schedule( - period = 1, - unit = ChronoUnit.SECONDS - ) - public void removeExpiredXpGlobes() - { - if (!xpGlobes.isEmpty()) - { - Instant currentTime = Instant.now(); - for (Iterator it = xpGlobes.iterator(); it.hasNext();) - { - XpGlobe globe = it.next(); - Instant globeCreationTime = globe.getTime(); - if (currentTime.isBefore(globeCreationTime.plusSeconds(config.xpOrbDuration()))) - { - //if a globe is not expired, stop checking newer globes - return; - } - it.remove(); - } - } - } - - private void resetGlobeState() - { - xpGlobes.clear(); - globeCache = new XpGlobe[Skill.values().length - 1]; - } - - @Subscribe - public void onGameStateChanged(GameStateChanged event) - { - switch (event.getGameState()) - { - case HOPPING: - case LOGGING_IN: - resetGlobeState(); - break; - } - } - -} +/* + * Copyright (c) 2017, Steve + * 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.xpglobes; + +import com.google.inject.Provides; +import java.time.Instant; +import java.time.temporal.ChronoUnit; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import javax.inject.Inject; +import lombok.Getter; +import net.runelite.api.Client; +import net.runelite.api.Experience; +import net.runelite.api.Skill; +import net.runelite.api.events.ExperienceChanged; +import net.runelite.api.events.GameStateChanged; +import net.runelite.client.config.ConfigManager; +import net.runelite.client.eventbus.Subscribe; +import net.runelite.client.plugins.Plugin; +import net.runelite.client.plugins.PluginDependency; +import net.runelite.client.plugins.PluginDescriptor; +import net.runelite.client.plugins.xptracker.XpTrackerPlugin; +import net.runelite.client.task.Schedule; +import net.runelite.client.ui.overlay.OverlayManager; + +@PluginDescriptor( + name = "XP Globes", + description = "Show XP globes for the respective skill when gaining XP", + tags = {"experience", "levels", "overlay"}, + enabledByDefault = false +) +@PluginDependency(XpTrackerPlugin.class) +public class XpGlobesPlugin extends Plugin +{ + private static final int MAXIMUM_SHOWN_GLOBES = 5; + + private XpGlobe[] globeCache = new XpGlobe[Skill.values().length - 1]; //overall does not trigger xp change event + + @Getter + private final List xpGlobes = new ArrayList<>(); + + @Inject + private Client client; + + @Inject + private XpGlobesConfig config; + + @Inject + private OverlayManager overlayManager; + + @Inject + private XpGlobesOverlay overlay; + + @Provides + XpGlobesConfig getConfig(ConfigManager configManager) + { + return configManager.getConfig(XpGlobesConfig.class); + } + + @Override + protected void startUp() throws Exception + { + overlayManager.add(overlay); + } + + @Override + protected void shutDown() throws Exception + { + overlayManager.remove(overlay); + } + + @Subscribe + public void onExperienceChanged(ExperienceChanged event) + { + Skill skill = event.getSkill(); + int currentXp = client.getSkillExperience(skill); + int currentLevel = Experience.getLevelForXp(currentXp); + int skillIdx = skill.ordinal(); + XpGlobe cachedGlobe = globeCache[skillIdx]; + + // ExperienceChanged event occurs when stats drain/boost check we have an change to actual xp + if (cachedGlobe != null && (cachedGlobe.getCurrentXp() >= currentXp)) + { + return; + } + + if (config.hideMaxed() && currentLevel >= Experience.MAX_REAL_LEVEL) + { + return; + } + + if (cachedGlobe != null) + { + cachedGlobe.setSkill(skill); + cachedGlobe.setCurrentXp(currentXp); + cachedGlobe.setCurrentLevel(currentLevel); + cachedGlobe.setTime(Instant.now()); + this.addXpGlobe(globeCache[skillIdx], MAXIMUM_SHOWN_GLOBES); + } + else + { + // dont draw non cached globes, this is triggered on login to setup all of the initial values + globeCache[skillIdx] = new XpGlobe(skill, currentXp, currentLevel, Instant.now()); + } + } + + private void addXpGlobe(XpGlobe xpGlobe, int maxLength) + { + //remove the old globe, allowing it to be readded as the most recent (right) side when drawn + xpGlobes.remove(xpGlobe); + if (getXpGlobesSize() >= maxLength) + { + xpGlobes.remove(0); + } + xpGlobes.add(xpGlobe); + } + + int getXpGlobesSize() + { + return xpGlobes.size(); + } + + @Schedule( + period = 1, + unit = ChronoUnit.SECONDS + ) + public void removeExpiredXpGlobes() + { + if (!xpGlobes.isEmpty()) + { + Instant currentTime = Instant.now(); + for (Iterator it = xpGlobes.iterator(); it.hasNext(); ) + { + XpGlobe globe = it.next(); + Instant globeCreationTime = globe.getTime(); + if (currentTime.isBefore(globeCreationTime.plusSeconds(config.xpOrbDuration()))) + { + //if a globe is not expired, stop checking newer globes + return; + } + it.remove(); + } + } + } + + private void resetGlobeState() + { + xpGlobes.clear(); + globeCache = new XpGlobe[Skill.values().length - 1]; + } + + @Subscribe + public void onGameStateChanged(GameStateChanged event) + { + switch (event.getGameState()) + { + case HOPPING: + case LOGGING_IN: + resetGlobeState(); + break; + } + } + +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/xptracker/XpInfoBoxOverlay.java b/runelite-client/src/main/java/net/runelite/client/plugins/xptracker/XpInfoBoxOverlay.java index 5ff11871e5..3455af4916 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/xptracker/XpInfoBoxOverlay.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/xptracker/XpInfoBoxOverlay.java @@ -33,10 +33,12 @@ import java.awt.image.BufferedImage; import lombok.AccessLevel; import lombok.Getter; import net.runelite.api.Experience; +import static net.runelite.api.MenuAction.RUNELITE_OVERLAY_CONFIG; import net.runelite.api.Skill; import net.runelite.client.ui.FontManager; import net.runelite.client.ui.SkillColor; import net.runelite.client.ui.overlay.Overlay; +import static net.runelite.client.ui.overlay.OverlayManager.OPTION_CONFIGURE; import net.runelite.client.ui.overlay.OverlayMenuEntry; import net.runelite.client.ui.overlay.components.ComponentOrientation; import net.runelite.client.ui.overlay.components.ImageComponent; @@ -45,8 +47,6 @@ import net.runelite.client.ui.overlay.components.PanelComponent; import net.runelite.client.ui.overlay.components.ProgressBarComponent; import net.runelite.client.ui.overlay.components.SplitComponent; import net.runelite.client.util.StackFormatter; -import static net.runelite.api.MenuAction.RUNELITE_OVERLAY_CONFIG; -import static net.runelite.client.ui.overlay.OverlayManager.OPTION_CONFIGURE; class XpInfoBoxOverlay extends Overlay { @@ -126,23 +126,23 @@ class XpInfoBoxOverlay extends Overlay .build(); final LineComponent xpHour = LineComponent.builder() - .left("XP/Hour:") - .right(StackFormatter.quantityToRSDecimalStack(snapshot.getXpPerHour(), true)) - .build(); + .left("XP/Hour:") + .right(StackFormatter.quantityToRSDecimalStack(snapshot.getXpPerHour(), true)) + .build(); final SplitComponent xpSplit = SplitComponent.builder() - .first(xpLine) - .second(xpHour) - .orientation(ComponentOrientation.VERTICAL) - .build(); + .first(xpLine) + .second(xpHour) + .orientation(ComponentOrientation.VERTICAL) + .build(); final ImageComponent imageComponent = new ImageComponent(icon); final SplitComponent iconXpSplit = SplitComponent.builder() - .first(imageComponent) - .second(xpSplit) - .orientation(ComponentOrientation.HORIZONTAL) - .gap(new Point(XP_AND_ICON_GAP, 0)) - .build(); + .first(imageComponent) + .second(xpSplit) + .orientation(ComponentOrientation.HORIZONTAL) + .gap(new Point(XP_AND_ICON_GAP, 0)) + .build(); iconXpSplitPanel.getChildren().add(iconXpSplit); diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/xptracker/XpState.java b/runelite-client/src/main/java/net/runelite/client/plugins/xptracker/XpState.java index 16602b0cb4..4bf50a75f1 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/xptracker/XpState.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/xptracker/XpState.java @@ -1,233 +1,240 @@ -/* - * Copyright (c) 2018, Levi - * 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.xptracker; - -import java.util.EnumMap; -import java.util.Map; -import lombok.NonNull; -import net.runelite.api.NPC; -import net.runelite.api.Skill; - -/** - * Internal state for the XpTrackerPlugin - * - * Note: This class's operations are not currently synchronized. - * It is intended to be called by the XpTrackerPlugin on the client thread. - */ -class XpState -{ - private static final double DEFAULT_XP_MODIFIER = 4.0; - private static final double SHARED_XP_MODIFIER = DEFAULT_XP_MODIFIER / 3.0; - private final Map xpSkills = new EnumMap<>(Skill.class); - private NPC interactedNPC; - - /** - * Destroys all internal state, however any XpSnapshotSingle or XpSnapshotTotal remain unaffected. - */ - void reset() - { - xpSkills.clear(); - } - - /** - * Resets a single skill - * @param skill Skill to reset - * @param currentXp Current XP to set to, if unknown set to -1 - */ - void resetSkill(Skill skill, long currentXp) - { - xpSkills.remove(skill); - xpSkills.put(skill, new XpStateSingle(skill, currentXp)); - } - - /** - * Updates a skill with the current known XP. - * When the result of this operation is XpUpdateResult.UPDATED, the UI should be updated accordingly. - * This is to distinguish events that reload all the skill's current values (such as world hopping) - * and also first-login when the skills are not initialized (the start XP will be -1 in this case). - * @param skill Skill to update - * @param currentXp Current known XP for this skill - * @param goalStartXp Possible XP start goal - * @param goalEndXp Possible XP end goal - * @return Whether or not the skill has been initialized, there was no change, or it has been updated - */ - XpUpdateResult updateSkill(Skill skill, long currentXp, int goalStartXp, int goalEndXp) - { - XpStateSingle state = getSkill(skill); - - if (state.getStartXp() == -1) - { - if (currentXp >= 0) - { - initializeSkill(skill, currentXp); - return XpUpdateResult.INITIALIZED; - } - else - { - return XpUpdateResult.NO_CHANGE; - } - } - else - { - long startXp = state.getStartXp(); - int gainedXp = state.getXpGained(); - - if (startXp + gainedXp > currentXp) - { - // Reinitialize with lesser currentXp, this can happen with negative xp lamps - initializeSkill(skill, currentXp); - return XpUpdateResult.INITIALIZED; - } - else - { - return state.update(currentXp, goalStartXp, goalEndXp) ? XpUpdateResult.UPDATED : XpUpdateResult.NO_CHANGE; - } - } - } - - private double getCombatXPModifier(Skill skill) - { - if (skill == Skill.HITPOINTS) - { - return SHARED_XP_MODIFIER; - } - - return DEFAULT_XP_MODIFIER; - } - - /** - * Updates skill with average actions based on currently interacted NPC. - * @param skill experience gained skill - * @param npc currently interacted NPC - * @param npcHealth health of currently interacted NPC - */ - void updateNpcExperience(Skill skill, NPC npc, Integer npcHealth) - { - if (npc == null || npc.getCombatLevel() <= 0 || npcHealth == null) - { - return; - } - - final XpStateSingle state = getSkill(skill); - final int actionExp = (int) (npcHealth * getCombatXPModifier(skill)); - final XpAction action = state.getXpAction(XpActionType.ACTOR_HEALTH); - - if (action.isActionsHistoryInitialized()) - { - action.getActionExps()[action.getActionExpIndex()] = actionExp; - - if (interactedNPC != npc) - { - action.setActionExpIndex((action.getActionExpIndex() + 1) % action.getActionExps().length); - } - } - else - { - // So we have a decent average off the bat, lets populate all values with what we see. - for (int i = 0; i < action.getActionExps().length; i++) - { - action.getActionExps()[i] = actionExp; - } - - action.setActionsHistoryInitialized(true); - } - - interactedNPC = npc; - state.setActionType(XpActionType.ACTOR_HEALTH); - } - - /** - * Update number of actions performed for skill (e.g amount of kills in this case) if last interacted - * NPC died - * @param skill skill to update actions for - * @param npc npc that just died - * @param npcHealth max health of npc that just died - * @return UPDATED in case new kill was successfully added - */ - XpUpdateResult updateNpcKills(Skill skill, NPC npc, Integer npcHealth) - { - XpStateSingle state = getSkill(skill); - - if (state.getXpGained() <= 0 || npcHealth == null || npc != interactedNPC) - { - return XpUpdateResult.NO_CHANGE; - } - - final XpAction xpAction = state.getXpAction(XpActionType.ACTOR_HEALTH); - xpAction.setActions(xpAction.getActions() + 1); - return xpAction.isActionsHistoryInitialized() ? XpUpdateResult.UPDATED : XpUpdateResult.NO_CHANGE; - } - - void tick(Skill skill, long delta) - { - getSkill(skill).tick(delta); - } - - /** - * Forcefully initialize a skill with a known start XP from the current XP. - * This is used in resetAndInitState by the plugin. It should not result in showing the XP in the UI. - * @param skill Skill to initialize - * @param currentXp Current known XP for the skill - */ - void initializeSkill(Skill skill, long currentXp) - { - xpSkills.put(skill, new XpStateSingle(skill, currentXp)); - } - - boolean isInitialized(Skill skill) - { - XpStateSingle xpStateSingle = xpSkills.get(skill); - return xpStateSingle != null && xpStateSingle.getStartXp() != -1; - } - - @NonNull - XpStateSingle getSkill(Skill skill) - { - return xpSkills.computeIfAbsent(skill, (s) -> new XpStateSingle(s, -1)); - } - - /** - * Obtain an immutable snapshot of the provided skill - * intended for use with the UI which operates on another thread - * @param skill Skill to obtain the snapshot for - * @return An immutable snapshot of the specified skill for this session since first login or last reset - */ - @NonNull - XpSnapshotSingle getSkillSnapshot(Skill skill) - { - return getSkill(skill).snapshot(); - } - - /** - * Obtain an immutable snapshot of the provided skill - * intended for use with the UI which operates on another thread - * @return An immutable snapshot of total information for this session since first login or last reset - */ - @NonNull - XpSnapshotSingle getTotalSnapshot() - { - return getSkill(Skill.OVERALL).snapshot(); - } -} +/* + * Copyright (c) 2018, Levi + * 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.xptracker; + +import java.util.EnumMap; +import java.util.Map; +import lombok.NonNull; +import net.runelite.api.NPC; +import net.runelite.api.Skill; + +/** + * Internal state for the XpTrackerPlugin + *

+ * Note: This class's operations are not currently synchronized. + * It is intended to be called by the XpTrackerPlugin on the client thread. + */ +class XpState +{ + private static final double DEFAULT_XP_MODIFIER = 4.0; + private static final double SHARED_XP_MODIFIER = DEFAULT_XP_MODIFIER / 3.0; + private final Map xpSkills = new EnumMap<>(Skill.class); + private NPC interactedNPC; + + /** + * Destroys all internal state, however any XpSnapshotSingle or XpSnapshotTotal remain unaffected. + */ + void reset() + { + xpSkills.clear(); + } + + /** + * Resets a single skill + * + * @param skill Skill to reset + * @param currentXp Current XP to set to, if unknown set to -1 + */ + void resetSkill(Skill skill, long currentXp) + { + xpSkills.remove(skill); + xpSkills.put(skill, new XpStateSingle(skill, currentXp)); + } + + /** + * Updates a skill with the current known XP. + * When the result of this operation is XpUpdateResult.UPDATED, the UI should be updated accordingly. + * This is to distinguish events that reload all the skill's current values (such as world hopping) + * and also first-login when the skills are not initialized (the start XP will be -1 in this case). + * + * @param skill Skill to update + * @param currentXp Current known XP for this skill + * @param goalStartXp Possible XP start goal + * @param goalEndXp Possible XP end goal + * @return Whether or not the skill has been initialized, there was no change, or it has been updated + */ + XpUpdateResult updateSkill(Skill skill, long currentXp, int goalStartXp, int goalEndXp) + { + XpStateSingle state = getSkill(skill); + + if (state.getStartXp() == -1) + { + if (currentXp >= 0) + { + initializeSkill(skill, currentXp); + return XpUpdateResult.INITIALIZED; + } + else + { + return XpUpdateResult.NO_CHANGE; + } + } + else + { + long startXp = state.getStartXp(); + int gainedXp = state.getXpGained(); + + if (startXp + gainedXp > currentXp) + { + // Reinitialize with lesser currentXp, this can happen with negative xp lamps + initializeSkill(skill, currentXp); + return XpUpdateResult.INITIALIZED; + } + else + { + return state.update(currentXp, goalStartXp, goalEndXp) ? XpUpdateResult.UPDATED : XpUpdateResult.NO_CHANGE; + } + } + } + + private double getCombatXPModifier(Skill skill) + { + if (skill == Skill.HITPOINTS) + { + return SHARED_XP_MODIFIER; + } + + return DEFAULT_XP_MODIFIER; + } + + /** + * Updates skill with average actions based on currently interacted NPC. + * + * @param skill experience gained skill + * @param npc currently interacted NPC + * @param npcHealth health of currently interacted NPC + */ + void updateNpcExperience(Skill skill, NPC npc, Integer npcHealth) + { + if (npc == null || npc.getCombatLevel() <= 0 || npcHealth == null) + { + return; + } + + final XpStateSingle state = getSkill(skill); + final int actionExp = (int) (npcHealth * getCombatXPModifier(skill)); + final XpAction action = state.getXpAction(XpActionType.ACTOR_HEALTH); + + if (action.isActionsHistoryInitialized()) + { + action.getActionExps()[action.getActionExpIndex()] = actionExp; + + if (interactedNPC != npc) + { + action.setActionExpIndex((action.getActionExpIndex() + 1) % action.getActionExps().length); + } + } + else + { + // So we have a decent average off the bat, lets populate all values with what we see. + for (int i = 0; i < action.getActionExps().length; i++) + { + action.getActionExps()[i] = actionExp; + } + + action.setActionsHistoryInitialized(true); + } + + interactedNPC = npc; + state.setActionType(XpActionType.ACTOR_HEALTH); + } + + /** + * Update number of actions performed for skill (e.g amount of kills in this case) if last interacted + * NPC died + * + * @param skill skill to update actions for + * @param npc npc that just died + * @param npcHealth max health of npc that just died + * @return UPDATED in case new kill was successfully added + */ + XpUpdateResult updateNpcKills(Skill skill, NPC npc, Integer npcHealth) + { + XpStateSingle state = getSkill(skill); + + if (state.getXpGained() <= 0 || npcHealth == null || npc != interactedNPC) + { + return XpUpdateResult.NO_CHANGE; + } + + final XpAction xpAction = state.getXpAction(XpActionType.ACTOR_HEALTH); + xpAction.setActions(xpAction.getActions() + 1); + return xpAction.isActionsHistoryInitialized() ? XpUpdateResult.UPDATED : XpUpdateResult.NO_CHANGE; + } + + void tick(Skill skill, long delta) + { + getSkill(skill).tick(delta); + } + + /** + * Forcefully initialize a skill with a known start XP from the current XP. + * This is used in resetAndInitState by the plugin. It should not result in showing the XP in the UI. + * + * @param skill Skill to initialize + * @param currentXp Current known XP for the skill + */ + void initializeSkill(Skill skill, long currentXp) + { + xpSkills.put(skill, new XpStateSingle(skill, currentXp)); + } + + boolean isInitialized(Skill skill) + { + XpStateSingle xpStateSingle = xpSkills.get(skill); + return xpStateSingle != null && xpStateSingle.getStartXp() != -1; + } + + @NonNull + XpStateSingle getSkill(Skill skill) + { + return xpSkills.computeIfAbsent(skill, (s) -> new XpStateSingle(s, -1)); + } + + /** + * Obtain an immutable snapshot of the provided skill + * intended for use with the UI which operates on another thread + * + * @param skill Skill to obtain the snapshot for + * @return An immutable snapshot of the specified skill for this session since first login or last reset + */ + @NonNull + XpSnapshotSingle getSkillSnapshot(Skill skill) + { + return getSkill(skill).snapshot(); + } + + /** + * Obtain an immutable snapshot of the provided skill + * intended for use with the UI which operates on another thread + * + * @return An immutable snapshot of total information for this session since first login or last reset + */ + @NonNull + XpSnapshotSingle getTotalSnapshot() + { + return getSkill(Skill.OVERALL).snapshot(); + } +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/xptracker/XpTrackerPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/xptracker/XpTrackerPlugin.java index 7d3006ddc9..3baf12962e 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/xptracker/XpTrackerPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/xptracker/XpTrackerPlugin.java @@ -275,6 +275,7 @@ public class XpTrackerPlugin extends Plugin /** * Reset an individual skill with the client's current known state of the skill * Will also clear the skill from the UI. + * * @param skill Skill to reset */ void resetSkillState(Skill skill) @@ -287,6 +288,7 @@ public class XpTrackerPlugin extends Plugin /** * Reset all skills except for the one provided + * * @param skill Skill to ignore during reset */ void resetOtherSkillState(Skill skill) diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/zoom/ZoomPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/zoom/ZoomPlugin.java index e799837e67..a1961b2085 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/zoom/ZoomPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/zoom/ZoomPlugin.java @@ -52,7 +52,7 @@ public class ZoomPlugin extends Plugin implements KeyListener { /** * The largest (most zoomed in) value that can be used without the client crashing. - * + *

* Larger values trigger an overflow in the engine's fov to scale code. */ private static final int INNER_ZOOM_LIMIT = 1004; @@ -90,7 +90,7 @@ public class ZoomPlugin extends Plugin implements KeyListener int[] intStack = client.getIntStack(); int intStackSize = client.getIntStackSize(); - if ("scrollWheelZoom".equals(event.getEventName()) && zoomConfig.controlFunction() == ControlFunction.CONTROL_TO_ZOOM && !controlDown) + if ("scrollWheelZoom".equals(event.getEventName()) && zoomConfig.controlFunction() == ControlFunction.CONTROL_TO_ZOOM && !controlDown) { intStack[intStackSize - 1] = 1; } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/ztob/BloatTimerOverlay.java b/runelite-client/src/main/java/net/runelite/client/plugins/ztob/BloatTimerOverlay.java index 731604122a..698203f54c 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/ztob/BloatTimerOverlay.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/ztob/BloatTimerOverlay.java @@ -1,102 +1,105 @@ -package net.runelite.client.plugins.ztob; - -import java.awt.BasicStroke; -import java.awt.Color; -import java.awt.Dimension; -import java.awt.Font; -import java.awt.Graphics2D; -import java.awt.Polygon; -import javax.inject.Inject; -import net.runelite.api.Client; -import net.runelite.api.Perspective; -import net.runelite.api.Point; -import net.runelite.api.coords.LocalPoint; -import net.runelite.api.coords.WorldPoint; -import net.runelite.client.ui.overlay.Overlay; -import net.runelite.client.ui.overlay.OverlayLayer; -import net.runelite.client.ui.overlay.OverlayPosition; -import net.runelite.client.ui.overlay.OverlayPriority; -import net.runelite.client.ui.overlay.OverlayUtil; - -public class BloatTimerOverlay extends Overlay { - - private final Client client; - private final TheatrePlugin plugin; - private final TheatreConfig config; - - @Inject - private BloatTimerOverlay(Client client, TheatrePlugin plugin, TheatreConfig config) { - this.client = client; - this.plugin = plugin; - this.config = config; - setPosition(OverlayPosition.DYNAMIC); - setPriority(OverlayPriority.HIGH); - setLayer(OverlayLayer.ABOVE_SCENE); - } - - public Dimension render(Graphics2D graphics) - { - - if (config.bloatTimer()) - { - final String tickCounter = String.valueOf(plugin.bloatTimer); - int secondConversion = (int) (plugin.bloatTimer * .6); - if (plugin.getBloat_NPC() != null) - { - Point canvasPoint = plugin.getBloat_NPC().getCanvasTextLocation(graphics, tickCounter, 60); - if (plugin.bloatTimer <= 37) - { - renderTextLocation(graphics, tickCounter + "( " + secondConversion + " )", 15, Font.BOLD, Color.WHITE, canvasPoint); - } - else - { - renderTextLocation(graphics, tickCounter + "( " + secondConversion + " )", 15, Font.BOLD, Color.RED, canvasPoint); - } - } - } - - - - - - return null; - } - - private void drawTile(Graphics2D graphics, WorldPoint point, Color color, int strokeWidth, int outlineAlpha, int fillAlpha) { - WorldPoint playerLocation = client.getLocalPlayer().getWorldLocation(); - if (point.distanceTo(playerLocation) >= 32) { - return; - } - LocalPoint lp = LocalPoint.fromWorld(client, point); - if (lp == null) { - return; - } - - Polygon poly = Perspective.getCanvasTilePoly(client, lp); - if (poly == null) { - return; - } - //OverlayUtil.renderPolygon(graphics, poly, color); - graphics.setColor(new Color(color.getRed(), color.getGreen(), color.getBlue(), outlineAlpha)); - graphics.setStroke(new BasicStroke(strokeWidth)); - graphics.draw(poly); - graphics.setColor(new Color(color.getRed(), color.getGreen(), color.getBlue(), fillAlpha)); - graphics.fill(poly); - } - - private void renderTextLocation(Graphics2D graphics, String txtString, int fontSize, int fontStyle, Color fontColor, net.runelite.api.Point canvasPoint) - { - graphics.setFont(new Font("Arial", fontStyle, fontSize)); - if (canvasPoint != null) - { - final net.runelite.api.Point canvasCenterPoint = new net.runelite.api.Point( - canvasPoint.getX(), - canvasPoint.getY()); - final net.runelite.api.Point canvasCenterPoint_shadow = new Point( - canvasPoint.getX() + 1, - canvasPoint.getY() + 1); - OverlayUtil.renderTextLocation(graphics, canvasCenterPoint_shadow, txtString, Color.BLACK); - OverlayUtil.renderTextLocation(graphics, canvasCenterPoint, txtString, fontColor); - } - } -} +package net.runelite.client.plugins.ztob; + +import java.awt.BasicStroke; +import java.awt.Color; +import java.awt.Dimension; +import java.awt.Font; +import java.awt.Graphics2D; +import java.awt.Polygon; +import javax.inject.Inject; +import net.runelite.api.Client; +import net.runelite.api.Perspective; +import net.runelite.api.Point; +import net.runelite.api.coords.LocalPoint; +import net.runelite.api.coords.WorldPoint; +import net.runelite.client.ui.overlay.Overlay; +import net.runelite.client.ui.overlay.OverlayLayer; +import net.runelite.client.ui.overlay.OverlayPosition; +import net.runelite.client.ui.overlay.OverlayPriority; +import net.runelite.client.ui.overlay.OverlayUtil; + +public class BloatTimerOverlay extends Overlay +{ + + private final Client client; + private final TheatrePlugin plugin; + private final TheatreConfig config; + + @Inject + private BloatTimerOverlay(Client client, TheatrePlugin plugin, TheatreConfig config) + { + this.client = client; + this.plugin = plugin; + this.config = config; + setPosition(OverlayPosition.DYNAMIC); + setPriority(OverlayPriority.HIGH); + setLayer(OverlayLayer.ABOVE_SCENE); + } + + public Dimension render(Graphics2D graphics) + { + + if (config.bloatTimer()) + { + final String tickCounter = String.valueOf(plugin.bloatTimer); + int secondConversion = (int) (plugin.bloatTimer * .6); + if (plugin.getBloat_NPC() != null) + { + Point canvasPoint = plugin.getBloat_NPC().getCanvasTextLocation(graphics, tickCounter, 60); + if (plugin.bloatTimer <= 37) + { + renderTextLocation(graphics, tickCounter + "( " + secondConversion + " )", 15, Font.BOLD, Color.WHITE, canvasPoint); + } + else + { + renderTextLocation(graphics, tickCounter + "( " + secondConversion + " )", 15, Font.BOLD, Color.RED, canvasPoint); + } + } + } + + + return null; + } + + private void drawTile(Graphics2D graphics, WorldPoint point, Color color, int strokeWidth, int outlineAlpha, int fillAlpha) + { + WorldPoint playerLocation = client.getLocalPlayer().getWorldLocation(); + if (point.distanceTo(playerLocation) >= 32) + { + return; + } + LocalPoint lp = LocalPoint.fromWorld(client, point); + if (lp == null) + { + return; + } + + Polygon poly = Perspective.getCanvasTilePoly(client, lp); + if (poly == null) + { + return; + } + //OverlayUtil.renderPolygon(graphics, poly, color); + graphics.setColor(new Color(color.getRed(), color.getGreen(), color.getBlue(), outlineAlpha)); + graphics.setStroke(new BasicStroke(strokeWidth)); + graphics.draw(poly); + graphics.setColor(new Color(color.getRed(), color.getGreen(), color.getBlue(), fillAlpha)); + graphics.fill(poly); + } + + private void renderTextLocation(Graphics2D graphics, String txtString, int fontSize, int fontStyle, Color fontColor, net.runelite.api.Point canvasPoint) + { + graphics.setFont(new Font("Arial", fontStyle, fontSize)); + if (canvasPoint != null) + { + final net.runelite.api.Point canvasCenterPoint = new net.runelite.api.Point( + canvasPoint.getX(), + canvasPoint.getY()); + final net.runelite.api.Point canvasCenterPoint_shadow = new Point( + canvasPoint.getX() + 1, + canvasPoint.getY() + 1); + OverlayUtil.renderTextLocation(graphics, canvasCenterPoint_shadow, txtString, Color.BLACK); + OverlayUtil.renderTextLocation(graphics, canvasCenterPoint, txtString, fontColor); + } + } +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/ztob/TheatreConfig.java b/runelite-client/src/main/java/net/runelite/client/plugins/ztob/TheatreConfig.java index 963a2dcbe0..3403635411 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/ztob/TheatreConfig.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/ztob/TheatreConfig.java @@ -11,101 +11,100 @@ package net.runelite.client.plugins.ztob; import net.runelite.client.config.Config; import net.runelite.client.config.ConfigGroup; import net.runelite.client.config.ConfigItem; -import net.runelite.client.config.Range; @ConfigGroup("Theatre") public interface TheatreConfig extends Config { - @ConfigItem( - position = 0, - keyName = "MaidenBlood", - name = "Maiden blood attack", - description = "" - ) + @ConfigItem( + position = 0, + keyName = "MaidenBlood", + name = "Maiden blood attack", + description = "" + ) default boolean MaidenBlood() { return true; } - @ConfigItem( - position = 1, - keyName = "MaidenSpawns", - name = "Maiden blood spawns", - description = "" - ) + @ConfigItem( + position = 1, + keyName = "MaidenSpawns", + name = "Maiden blood spawns", + description = "" + ) default boolean MaidenSpawns() { return true; } - @ConfigItem( - position = 2, - keyName = "BloatIndicator", - name = "Bloat Indicator", - description = "" - ) + @ConfigItem( + position = 2, + keyName = "BloatIndicator", + name = "Bloat Indicator", + description = "" + ) default boolean BloatIndicator() { return true; } - @ConfigItem( - position = 3, - keyName = "bloat Timer", - name = "Bloat Timer", - description = "" - ) + @ConfigItem( + position = 3, + keyName = "bloat Timer", + name = "Bloat Timer", + description = "" + ) default boolean bloatTimer() { return true; } - @ConfigItem( - position = 4, - keyName = "bloatFeet", - name = "Bloat Feet", - description = "" - ) + @ConfigItem( + position = 4, + keyName = "bloatFeet", + name = "Bloat Feet", + description = "" + ) default boolean bloatFeetIndicator() { return true; } - @ConfigItem( - position = 5, - keyName = "NyloPillars", - name = "Nylocas pillar health", - description = "" - ) + @ConfigItem( + position = 5, + keyName = "NyloPillars", + name = "Nylocas pillar health", + description = "" + ) default boolean NyloPillars() { return true; } - - @ConfigItem( - position = 6, - keyName = "NyloBlasts", - name = "Nylocas explosions", - description = "" - ) + @ConfigItem( + position = 6, + keyName = "NyloBlasts", + name = "Nylocas explosions", + description = "" + ) default boolean NyloBlasts() { return true; } - @ConfigItem( - position = 7, - keyName = "NyloMenu", - name = "Hide Attack options for Nylocas", - description = "" - ) + @ConfigItem( + position = 7, + keyName = "NyloMenu", + name = "Hide Attack options for Nylocas", + description = "" + ) - default boolean NyloMenu() { - return true; - } + default boolean NyloMenu() + { + return true; + } @ConfigItem( position = 8, @@ -118,107 +117,107 @@ public interface TheatreConfig extends Config return true; } - @ConfigItem( - position = 9, - keyName = "SotetsegMaze1", - name = "Sotetseg maze", - description = "" - ) + @ConfigItem( + position = 9, + keyName = "SotetsegMaze1", + name = "Sotetseg maze", + description = "" + ) default boolean SotetsegMaze1() { return true; } - @ConfigItem( - position = 10, - keyName = "SotetsegMaze2", - name = "Sotetseg maze (solo mode)", - description = "" - ) + @ConfigItem( + position = 10, + keyName = "SotetsegMaze2", + name = "Sotetseg maze (solo mode)", + description = "" + ) default boolean SotetsegMaze2() { return true; } - @ConfigItem( - position = 11, - keyName = "XarpusExhumed", - name = "Xarpus Exhumed", - description = "" - ) + @ConfigItem( + position = 11, + keyName = "XarpusExhumed", + name = "Xarpus Exhumed", + description = "" + ) default boolean XarpusExhumed() { return true; } - @ConfigItem( - position = 12, - keyName = "XarpusTick", - name = "Xarpus Tick", - description = "" - ) + @ConfigItem( + position = 12, + keyName = "XarpusTick", + name = "Xarpus Tick", + description = "" + ) default boolean XarpusTick() { return false; } - @ConfigItem( - position = 13, - keyName = "xarpusExhumes", - name = "Xarpus Exhume Counter", - description = "" - ) + @ConfigItem( + position = 13, + keyName = "xarpusExhumes", + name = "Xarpus Exhume Counter", + description = "" + ) default boolean XarpusExhumeOverlay() { return false; } - @ConfigItem( - position = 14, - keyName = "VerzikCupcakes", - name = "Verzik Projectile Markers", - description = "" - ) + @ConfigItem( + position = 14, + keyName = "VerzikCupcakes", + name = "Verzik Projectile Markers", + description = "" + ) default boolean VerzikCupcakes() { return false; } - @ConfigItem( - position = 15, - keyName = "VerzikTick", - name = "Verzik P3 Tick", - description = "" - ) + @ConfigItem( + position = 15, + keyName = "VerzikTick", + name = "Verzik P3 Tick", + description = "" + ) default boolean VerzikTick() { return false; } - @ConfigItem( - position = 16, - keyName = "VerzikMelee", - name = "Verzik P3 Melee Range", - description = "" - ) + @ConfigItem( + position = 16, + keyName = "VerzikMelee", + name = "Verzik P3 Melee Range", + description = "" + ) default boolean VerzikMelee() { return false; } - @ConfigItem( - position = 17, - keyName = "VerzikYellow", - name = "Verzik Yellow Timing", - description = "" - ) + @ConfigItem( + position = 17, + keyName = "VerzikYellow", + name = "Verzik Yellow Timing", + description = "" + ) default boolean VerzikYellow() { return false; } - @ConfigItem( - position = 18, + @ConfigItem( + position = 18, keyName = "Verzik Nylo", name = "Verzik Nylo Overlay", description = "" @@ -228,17 +227,16 @@ public interface TheatreConfig extends Config return false; } - @ConfigItem( - position = 19, - keyName = "VerzikTankTile", - name = "Verzik P3 Tile Overlay", - description = "" - ) + @ConfigItem( + position = 19, + keyName = "VerzikTankTile", + name = "Verzik P3 Tile Overlay", + description = "" + ) default boolean verzikTankTile() { return true; } - } \ No newline at end of file diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/ztob/TheatreOverlay.java b/runelite-client/src/main/java/net/runelite/client/plugins/ztob/TheatreOverlay.java index 14a158f136..222e83d8ac 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/ztob/TheatreOverlay.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/ztob/TheatreOverlay.java @@ -35,22 +35,24 @@ import net.runelite.client.ui.overlay.OverlayPosition; import net.runelite.client.ui.overlay.OverlayPriority; import net.runelite.client.ui.overlay.OverlayUtil; -public class TheatreOverlay extends Overlay { - private final Client client; - private final TheatrePlugin plugin; - private final TheatreConfig config; +public class TheatreOverlay extends Overlay +{ + private final Client client; + private final TheatrePlugin plugin; + private final TheatreConfig config; - @Inject - private TheatreOverlay(Client client, TheatrePlugin plugin, TheatreConfig config) { - this.client = client; - this.plugin = plugin; - this.config = config; - setPosition(OverlayPosition.DYNAMIC); - setPriority(OverlayPriority.HIGH); - setLayer(OverlayLayer.ABOVE_SCENE); - } + @Inject + private TheatreOverlay(Client client, TheatrePlugin plugin, TheatreConfig config) + { + this.client = client; + this.plugin = plugin; + this.config = config; + setPosition(OverlayPosition.DYNAMIC); + setPriority(OverlayPriority.HIGH); + setLayer(OverlayLayer.ABOVE_SCENE); + } - @Override + @Override public Dimension render(Graphics2D graphics) { if (plugin.isRunMaiden()) @@ -59,22 +61,22 @@ public class TheatreOverlay extends Overlay { { for (WorldPoint point : plugin.getMaiden_BloodSpatters()) { - drawTile(graphics, point, new Color(36, 248, 229), 2, 150, 10); - } - } + drawTile(graphics, point, new Color(36, 248, 229), 2, 150, 10); + } + } if (config.MaidenSpawns()) { for (WorldPoint point : plugin.getMaiden_SpawnLocations()) { - drawTile(graphics, point, new Color(36, 248, 229), 2, 180, 20); - } + drawTile(graphics, point, new Color(36, 248, 229), 2, 180, 20); + } for (WorldPoint point : plugin.getMaiden_SpawnLocations2()) { drawTile(graphics, point, new Color(36, 248, 229), 1, 120, 10); - } - } - } + } + } + } if (plugin.isRunBloat() && config.BloatIndicator()) { @@ -107,64 +109,67 @@ public class TheatreOverlay extends Overlay { } } - } - NPC bloat = plugin.getBloat_NPC(); - int state = plugin.getBloat_State(); + } + NPC bloat = plugin.getBloat_NPC(); + int state = plugin.getBloat_State(); if (bloat == null) { - return null; - } + return null; + } switch (state) { - case 2: - renderNpcOverlay(graphics, bloat, Color.GREEN, 3, 150, 0); - break; - case 3: - renderNpcOverlay(graphics, bloat, Color.YELLOW, 3, 150, 0); - break; - default: - renderNpcOverlay(graphics, bloat, new Color(223, 109, 255), 3, 150, 0); - break; - } - } + case 2: + renderNpcOverlay(graphics, bloat, Color.GREEN, 3, 150, 0); + break; + case 3: + renderNpcOverlay(graphics, bloat, Color.YELLOW, 3, 150, 0); + break; + default: + renderNpcOverlay(graphics, bloat, new Color(223, 109, 255), 3, 150, 0); + break; + } + } if (plugin.isRunNylocas()) { if (config.NyloPillars()) { - Map pillars = plugin.getNylocas_Pillars(); - for (NPC npc : pillars.keySet()) { - final int health = pillars.get(npc); - final String healthStr = health + "%"; - WorldPoint p = npc.getWorldLocation(); - LocalPoint lp = LocalPoint.fromWorld(client, p.getX() + 1, p.getY() + 1); - final double rMod = 130.0 * health / 100.0; - final double gMod = 255.0 * health / 100.0; - final double bMod = 125.0 * health / 100.0; - final Color c = new Color((int) (255 - rMod), (int) (0 + gMod), (int) (0 + bMod)); - Point canvasPoint = Perspective.localToCanvas(client, lp, client.getPlane(), - 65); - renderTextLocation(graphics, healthStr, 13, Font.BOLD, c, canvasPoint); - } - } + Map pillars = plugin.getNylocas_Pillars(); + for (NPC npc : pillars.keySet()) + { + final int health = pillars.get(npc); + final String healthStr = health + "%"; + WorldPoint p = npc.getWorldLocation(); + LocalPoint lp = LocalPoint.fromWorld(client, p.getX() + 1, p.getY() + 1); + final double rMod = 130.0 * health / 100.0; + final double gMod = 255.0 * health / 100.0; + final double bMod = 125.0 * health / 100.0; + final Color c = new Color((int) (255 - rMod), (int) (0 + gMod), (int) (0 + bMod)); + Point canvasPoint = Perspective.localToCanvas(client, lp, client.getPlane(), + 65); + renderTextLocation(graphics, healthStr, 13, Font.BOLD, c, canvasPoint); + } + } if (config.NyloBlasts()) { - final Map npcMap = plugin.getNylocas_Map(); + final Map npcMap = plugin.getNylocas_Map(); for (NPC npc : npcMap.keySet()) { - int ticksLeft = npcMap.get(npc); - if (ticksLeft > -1) { - if (ticksLeft <= 6) { + int ticksLeft = npcMap.get(npc); + if (ticksLeft > -1) + { + if (ticksLeft <= 6) + { Color color = new Color(255, 255, 0, 180); - int outlineWidth = 2; - int outlineAlpha = 150; - renderNpcOverlay(graphics, npc, color, outlineWidth, outlineAlpha, 15); - } - } - } - } - } + int outlineWidth = 2; + int outlineAlpha = 150; + renderNpcOverlay(graphics, npc, color, outlineWidth, outlineAlpha, 15); + } + } + } + } + } if (plugin.isRunSotetseg()) { @@ -199,82 +204,81 @@ public class TheatreOverlay extends Overlay { if (config.SotetsegMaze1()) { - int i = 1; + int i = 1; for (GroundObject o : plugin.getRedTiles().keySet()) { - Polygon poly = o.getCanvasTilePoly(); + Polygon poly = o.getCanvasTilePoly(); if (poly != null) { - graphics.setColor(Color.WHITE); - graphics.setStroke(new BasicStroke(2)); - graphics.draw(poly); - } - Point textLocation = o.getCanvasTextLocation(graphics, String.valueOf(i), 0); + graphics.setColor(Color.WHITE); + graphics.setStroke(new BasicStroke(2)); + graphics.draw(poly); + } + Point textLocation = o.getCanvasTextLocation(graphics, String.valueOf(i), 0); if (textLocation != null) { - OverlayUtil.renderTextLocation(graphics, textLocation, String.valueOf(i), Color.WHITE); - } + OverlayUtil.renderTextLocation(graphics, textLocation, String.valueOf(i), Color.WHITE); + } - i++; - } - } + i++; + } + } if (config.SotetsegMaze2()) { for (WorldPoint p : plugin.getRedTilesOverworld()) { - drawTile(graphics, p, Color.WHITE, 2, 255, 10); - } - } - } + drawTile(graphics, p, Color.WHITE, 2, 255, 10); + } + } + } if (plugin.isRunXarpus()) { - NPC boss = plugin.getXarpus_NPC(); + NPC boss = plugin.getXarpus_NPC(); if (boss.getId() == NpcID.XARPUS_8340 && !plugin.isXarpus_Stare() && config.XarpusTick()) { - int tick = plugin.getXarpus_TicksUntilShoot(); + int tick = plugin.getXarpus_TicksUntilShoot(); if (tick < 1) { - tick = tick % 4 + 4; - } - final String ticksLeftStr = String.valueOf(tick); - Point canvasPoint = boss.getCanvasTextLocation(graphics, ticksLeftStr, 130); - renderTextLocation(graphics, ticksLeftStr, 12, Font.BOLD, Color.WHITE, canvasPoint); - } + tick = tick % 4 + 4; + } + final String ticksLeftStr = String.valueOf(tick); + Point canvasPoint = boss.getCanvasTextLocation(graphics, ticksLeftStr, 130); + renderTextLocation(graphics, ticksLeftStr, 12, Font.BOLD, Color.WHITE, canvasPoint); + } if (boss.getId() == NpcID.XARPUS_8339 && config.XarpusExhumed()) { for (GroundObject o : plugin.getXarpus_Exhumeds().keySet()) { - - Polygon poly = o.getCanvasTilePoly(); + Polygon poly = o.getCanvasTilePoly(); if (poly != null) { - graphics.setColor(new Color(0, 255, 0, 130)); - graphics.setStroke(new BasicStroke(1)); - graphics.draw(poly); - } - } + graphics.setColor(new Color(0, 255, 0, 130)); + graphics.setStroke(new BasicStroke(1)); + graphics.draw(poly); + } + } for (Map.Entry exhumes : plugin.getXarpusExhumedsTimer().entrySet()) { - final String ticksremaining = String.valueOf(exhumes.getValue()); + final String ticksremaining = String.valueOf(exhumes.getValue()); if (Integer.valueOf(ticksremaining) > 0) { - GroundObject ex = exhumes.getKey(); - Point point = ex.getCanvasTextLocation(graphics, ticksremaining, 0); - renderTextLocation(graphics, ticksremaining, 12, Font.BOLD, Color.white, point); - } + GroundObject ex = exhumes.getKey(); + Point point = ex.getCanvasTextLocation(graphics, ticksremaining, 0); + renderTextLocation(graphics, ticksremaining, 12, Font.BOLD, Color.white, point); + } - } + } - } + } - } + } if (plugin.isRunVerzik()) @@ -285,147 +289,151 @@ public class TheatreOverlay extends Overlay { { for (WorldPoint p : plugin.getVerzik_RangeProjectiles().values()) { - drawTile(graphics, p, Color.RED, 2, 180, 50); - } - } + drawTile(graphics, p, Color.RED, 2, 180, 50); + } + } if (config.VerzikYellow()) { for (WorldPoint p : plugin.getVerzik_YellowTiles()) { drawTile(graphics, p, Color.YELLOW, 3, 255, 0); - Projectile yellowBall = plugin.getVerzik_YellowBall(); + Projectile yellowBall = plugin.getVerzik_YellowBall(); if (yellowBall != null) { final int ticksToImpact = yellowBall.getRemainingCycles() / 30; - final String countdownStr = String.valueOf(ticksToImpact); - Point canvasPoint = Perspective.getCanvasTextLocation(client, graphics, LocalPoint.fromWorld(client, p), countdownStr, 0); - renderTextLocation(graphics, countdownStr, 12, Font.BOLD, Color.WHITE, canvasPoint); + final String countdownStr = String.valueOf(ticksToImpact); + Point canvasPoint = Perspective.getCanvasTextLocation(client, graphics, LocalPoint.fromWorld(client, p), countdownStr, 0); + renderTextLocation(graphics, countdownStr, 12, Font.BOLD, Color.WHITE, canvasPoint); - } - } - } + } + } + } - final NPC boss = plugin.getVerzik_NPC(); + final NPC boss = plugin.getVerzik_NPC(); if (boss.getId() == NpcID.VERZIK_VITUR_8374) { if (config.verzikTankTile()) { renderNpcOverlay(graphics, boss, new Color(75, 0, 130), 1, 255, 0); - } + } if (config.VerzikTick()) { - final int ticksLeft = plugin.getP3_TicksUntilAttack(); + final int ticksLeft = plugin.getP3_TicksUntilAttack(); if (ticksLeft > 0 && ticksLeft < 8) { - final String ticksLeftStr = String.valueOf(ticksLeft); - Point canvasPoint = boss.getCanvasTextLocation(graphics, ticksLeftStr, 60); - renderTextLocation(graphics, ticksLeftStr, 15, Font.BOLD, Color.WHITE, canvasPoint); - } - } + final String ticksLeftStr = String.valueOf(ticksLeft); + Point canvasPoint = boss.getCanvasTextLocation(graphics, ticksLeftStr, 60); + renderTextLocation(graphics, ticksLeftStr, 15, Font.BOLD, Color.WHITE, canvasPoint); + } + } if (config.VerzikMelee()) { - List meleeRange = getHitSquares(boss.getWorldLocation(), 7, 1, false); + List meleeRange = getHitSquares(boss.getWorldLocation(), 7, 1, false); for (WorldPoint p : meleeRange) { drawTile(graphics, p, Color.WHITE, 1, 155, 10); - } - } - } + } + } + } if (boss.getAnimation() == 8117) { - final int ticksLeft = plugin.getRedCrabsTimer(); + final int ticksLeft = plugin.getRedCrabsTimer(); if (ticksLeft > 0) { - final String ticksLeftStr = String.valueOf(ticksLeft); - Point canvasPoint = boss.getCanvasTextLocation(graphics, ticksLeftStr, 60); - renderTextLocation(graphics, ticksLeftStr, 15, Font.BOLD, Color.WHITE, canvasPoint); - } - } + final String ticksLeftStr = String.valueOf(ticksLeft); + Point canvasPoint = boss.getCanvasTextLocation(graphics, ticksLeftStr, 60); + renderTextLocation(graphics, ticksLeftStr, 15, Font.BOLD, Color.WHITE, canvasPoint); + } + } - } + } - return null; - } + return null; + } - private void drawTile(Graphics2D graphics, WorldPoint point, Color color, int strokeWidth, int outlineAlpha, int fillAlpha) { - WorldPoint playerLocation = client.getLocalPlayer().getWorldLocation(); - if (point.distanceTo(playerLocation) >= 32) { - return; - } - LocalPoint lp = LocalPoint.fromWorld(client, point); - if (lp == null) { - return; - } + private void drawTile(Graphics2D graphics, WorldPoint point, Color color, int strokeWidth, int outlineAlpha, int fillAlpha) + { + WorldPoint playerLocation = client.getLocalPlayer().getWorldLocation(); + if (point.distanceTo(playerLocation) >= 32) + { + return; + } + LocalPoint lp = LocalPoint.fromWorld(client, point); + if (lp == null) + { + return; + } - Polygon poly = Perspective.getCanvasTilePoly(client, lp); - if (poly == null) { - return; - } - //OverlayUtil.renderPolygon(graphics, poly, color); - graphics.setColor(new Color(color.getRed(), color.getGreen(), color.getBlue(), outlineAlpha)); - graphics.setStroke(new BasicStroke(strokeWidth)); - graphics.draw(poly); - graphics.setColor(new Color(color.getRed(), color.getGreen(), color.getBlue(), fillAlpha)); - graphics.fill(poly); - } + Polygon poly = Perspective.getCanvasTilePoly(client, lp); + if (poly == null) + { + return; + } + //OverlayUtil.renderPolygon(graphics, poly, color); + graphics.setColor(new Color(color.getRed(), color.getGreen(), color.getBlue(), outlineAlpha)); + graphics.setStroke(new BasicStroke(strokeWidth)); + graphics.draw(poly); + graphics.setColor(new Color(color.getRed(), color.getGreen(), color.getBlue(), fillAlpha)); + graphics.fill(poly); + } private void renderNpcOverlay(Graphics2D graphics, NPC actor, Color color, int outlineWidth, int outlineAlpha, int fillAlpha) { - int size = 1; - NPCComposition composition = actor.getTransformedComposition(); + int size = 1; + NPCComposition composition = actor.getTransformedComposition(); if (composition != null) { - size = composition.getSize(); - } - LocalPoint lp = actor.getLocalLocation(); - Polygon tilePoly = Perspective.getCanvasTileAreaPoly(client, lp, size); + size = composition.getSize(); + } + LocalPoint lp = actor.getLocalLocation(); + Polygon tilePoly = Perspective.getCanvasTileAreaPoly(client, lp, size); if (tilePoly != null) { - graphics.setColor(new Color(color.getRed(), color.getGreen(), color.getBlue(), outlineAlpha)); - graphics.setStroke(new BasicStroke(outlineWidth)); - graphics.draw(tilePoly); - graphics.setColor(new Color(color.getRed(), color.getGreen(), color.getBlue(), fillAlpha)); - graphics.fill(tilePoly); - } - } + graphics.setColor(new Color(color.getRed(), color.getGreen(), color.getBlue(), outlineAlpha)); + graphics.setStroke(new BasicStroke(outlineWidth)); + graphics.draw(tilePoly); + graphics.setColor(new Color(color.getRed(), color.getGreen(), color.getBlue(), fillAlpha)); + graphics.fill(tilePoly); + } + } private void renderTextLocation(Graphics2D graphics, String txtString, int fontSize, int fontStyle, Color fontColor, Point canvasPoint) { - graphics.setFont(new Font("Arial", fontStyle, fontSize)); + graphics.setFont(new Font("Arial", fontStyle, fontSize)); if (canvasPoint != null) { - final Point canvasCenterPoint = new Point( - canvasPoint.getX(), - canvasPoint.getY()); - final Point canvasCenterPoint_shadow = new Point( - canvasPoint.getX() + 1, + final Point canvasCenterPoint = new Point( + canvasPoint.getX(), + canvasPoint.getY()); + final Point canvasCenterPoint_shadow = new Point( + canvasPoint.getX() + 1, canvasPoint.getY() + 1); - OverlayUtil.renderTextLocation(graphics, canvasCenterPoint_shadow, txtString, Color.BLACK); - OverlayUtil.renderTextLocation(graphics, canvasCenterPoint, txtString, fontColor); - } - } + OverlayUtil.renderTextLocation(graphics, canvasCenterPoint_shadow, txtString, Color.BLACK); + OverlayUtil.renderTextLocation(graphics, canvasCenterPoint, txtString, fontColor); + } + } private List getHitSquares(WorldPoint npcLoc, int npcSize, int thickness, boolean includeUnder) { - List little = new WorldArea(npcLoc, npcSize, npcSize).toWorldPointList(); + List little = new WorldArea(npcLoc, npcSize, npcSize).toWorldPointList(); List big = new WorldArea(npcLoc.getX() - thickness, npcLoc.getY() - thickness, npcSize + (thickness * 2), npcSize + (thickness * 2), npcLoc.getPlane()).toWorldPointList(); if (!includeUnder) { for (Iterator it = big.iterator(); it.hasNext(); ) { - WorldPoint p = it.next(); + WorldPoint p = it.next(); if (little.contains(p)) { - it.remove(); - } - } - } - return big; - } + it.remove(); + } + } + } + return big; + } } \ No newline at end of file diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/ztob/TheatrePlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/ztob/TheatrePlugin.java index 1735ae360c..ccc43cae1e 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/ztob/TheatrePlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/ztob/TheatrePlugin.java @@ -53,140 +53,141 @@ import net.runelite.client.ui.overlay.OverlayManager; import net.runelite.client.util.Text; @PluginDescriptor( - name = "Theater of Blood", - description = "All-in-one plugin for Theatre of Blood", + name = "Theater of Blood", + description = "All-in-one plugin for Theatre of Blood", tags = {"ToB", "theatre", "blood"}, - enabledByDefault = false, + enabledByDefault = false, type = PluginType.PVM ) -public class TheatrePlugin extends Plugin { - private static final int GRAPHICSOBJECT_ID_MAIDEN = 1579; - private static final int NPCID_NYLOCAS_PILLAR = 8358; - private static final int GROUNDOBJECT_ID_BLACKMAZE = 33034; - private static final int GROUNDOBJECT_ID_REDMAZE = 33035; - private static final int GROUNDOBJECT_ID_EXHUMED = 32743; - private static final int ANIMATION_ID_XARPUS = 8059; - private static final int GRAPHICSOBJECT_ID_YELLOW = 1595; - private static final int PROJECTILE_ID_P2RANGE = 1583; - private static final int PROJECTILE_ID_YELLOW = 1596; - private static final int ANIMATION_ID_P3_WEB = 8127; - private static final int ANIMATION_ID_P3_YELLOW = 8126; - private static final int ANIMATION_ID_P3_MELEE = 8123; - private static final int ANIMATION_ID_P3_MAGE = 8124; - private static final int ANIMATION_ID_P3_RANGE = 8125; - private static final int VERZIK_ID_P3 = NpcID.VERZIK_VITUR_8374; - private static final int NPC_ID_TORNADO = 8386; - private static final int PROJECTILE_ID_P3_GREEN = 1598; +public class TheatrePlugin extends Plugin +{ + private static final int GRAPHICSOBJECT_ID_MAIDEN = 1579; + private static final int NPCID_NYLOCAS_PILLAR = 8358; + private static final int GROUNDOBJECT_ID_BLACKMAZE = 33034; + private static final int GROUNDOBJECT_ID_REDMAZE = 33035; + private static final int GROUNDOBJECT_ID_EXHUMED = 32743; + private static final int ANIMATION_ID_XARPUS = 8059; + private static final int GRAPHICSOBJECT_ID_YELLOW = 1595; + private static final int PROJECTILE_ID_P2RANGE = 1583; + private static final int PROJECTILE_ID_YELLOW = 1596; + private static final int ANIMATION_ID_P3_WEB = 8127; + private static final int ANIMATION_ID_P3_YELLOW = 8126; + private static final int ANIMATION_ID_P3_MELEE = 8123; + private static final int ANIMATION_ID_P3_MAGE = 8124; + private static final int ANIMATION_ID_P3_RANGE = 8125; + private static final int VERZIK_ID_P3 = NpcID.VERZIK_VITUR_8374; + private static final int NPC_ID_TORNADO = 8386; + private static final int PROJECTILE_ID_P3_GREEN = 1598; - @Getter - int exhumecount; + @Getter + int exhumecount; @Getter(AccessLevel.PACKAGE) private final Map xarpusExhumedsTimer = new HashMap<>(); - @Getter - int bloatTimer = 0; + @Getter + int bloatTimer = 0; - int bloatFeetTimer = 0; - - @Getter - private Set bloatTiles = new HashSet<>(); - - @Getter - private Set temp = new HashSet<>(); + int bloatFeetTimer = 0; @Getter - private Set temp2 = new HashSet<>(); + private Set bloatTiles = new HashSet<>(); @Getter - private Set localTemp = new HashSet<>(); + private Set temp = new HashSet<>(); + + @Getter + private Set temp2 = new HashSet<>(); + + @Getter + private Set localTemp = new HashSet<>(); NPC BossNylo = null; private boolean bloatFlag = false; - //@Getter - //private List bloatTiles = new ArrayList<>(); + //@Getter + //private List bloatTiles = new ArrayList<>(); - @Getter(AccessLevel.PACKAGE) - private boolean runMaiden; + @Getter(AccessLevel.PACKAGE) + private boolean runMaiden; - @Getter(AccessLevel.PACKAGE) - private List Maiden_BloodSpatters = new ArrayList<>(); + @Getter(AccessLevel.PACKAGE) + private List Maiden_BloodSpatters = new ArrayList<>(); - private List Maiden_Spawns = new ArrayList<>(); + private List Maiden_Spawns = new ArrayList<>(); - @Getter(AccessLevel.PACKAGE) - private List Maiden_SpawnLocations = new ArrayList<>(); + @Getter(AccessLevel.PACKAGE) + private List Maiden_SpawnLocations = new ArrayList<>(); - @Getter(AccessLevel.PACKAGE) - private List Maiden_SpawnLocations2 = new ArrayList<>(); + @Getter(AccessLevel.PACKAGE) + private List Maiden_SpawnLocations2 = new ArrayList<>(); - @Getter(AccessLevel.PACKAGE) - private boolean runBloat; + @Getter(AccessLevel.PACKAGE) + private boolean runBloat; - @Getter(AccessLevel.PACKAGE) - private NPC Bloat_NPC; + @Getter(AccessLevel.PACKAGE) + private NPC Bloat_NPC; - private int Bloat_downCount; + private int Bloat_downCount; - @Getter(AccessLevel.PACKAGE) - private Integer Bloat_State; + @Getter(AccessLevel.PACKAGE) + private Integer Bloat_State; - @Getter(AccessLevel.PACKAGE) - private boolean runNylocas; + @Getter(AccessLevel.PACKAGE) + private boolean runNylocas; - @Getter(AccessLevel.PACKAGE) - private Map Nylocas_Pillars = new HashMap<>(); + @Getter(AccessLevel.PACKAGE) + private Map Nylocas_Pillars = new HashMap<>(); - @Getter(AccessLevel.PACKAGE) - private Map Nylocas_Map = new HashMap<>(); + @Getter(AccessLevel.PACKAGE) + private Map Nylocas_Map = new HashMap<>(); - @Getter(AccessLevel.PACKAGE) - private boolean runSotetseg; + @Getter(AccessLevel.PACKAGE) + private boolean runSotetseg; - @Getter(AccessLevel.PACKAGE) - private final Map RedTiles = new LinkedHashMap<>(); + @Getter(AccessLevel.PACKAGE) + private final Map RedTiles = new LinkedHashMap<>(); - @Getter(AccessLevel.PACKAGE) - private List RedTilesOverworld = new ArrayList<>(); + @Getter(AccessLevel.PACKAGE) + private List RedTilesOverworld = new ArrayList<>(); - private List BlackTilesOverworld = new ArrayList<>(); - @Getter - private boolean tempFlag = false; - @Getter - private boolean temp2Flag = false; + private List BlackTilesOverworld = new ArrayList<>(); + @Getter + private boolean tempFlag = false; + @Getter + private boolean temp2Flag = false; - private List GridPath = new ArrayList<>(); - private List BlackTilesUnderworld = new ArrayList<>(); + private List GridPath = new ArrayList<>(); + private List BlackTilesUnderworld = new ArrayList<>(); - @Getter(AccessLevel.PACKAGE) - private boolean runXarpus; + @Getter(AccessLevel.PACKAGE) + private boolean runXarpus; - private int Xarpus_previousAnimation; + private int Xarpus_previousAnimation; - @Getter(AccessLevel.PACKAGE) - private boolean Xarpus_Stare; + @Getter(AccessLevel.PACKAGE) + private boolean Xarpus_Stare; - @Getter(AccessLevel.PACKAGE) - private final Map Xarpus_Exhumeds = new HashMap<>(); - private List RedTilesUnderworld = new ArrayList<>(); + @Getter(AccessLevel.PACKAGE) + private final Map Xarpus_Exhumeds = new HashMap<>(); + private List RedTilesUnderworld = new ArrayList<>(); - @Getter(AccessLevel.PACKAGE) - private int Xarpus_TicksUntilShoot = 9; + @Getter(AccessLevel.PACKAGE) + private int Xarpus_TicksUntilShoot = 9; - @Getter(AccessLevel.PACKAGE) - private NPC Xarpus_NPC; + @Getter(AccessLevel.PACKAGE) + private NPC Xarpus_NPC; - @Getter(AccessLevel.PACKAGE) - private boolean runVerzik; + @Getter(AccessLevel.PACKAGE) + private boolean runVerzik; - @Getter(AccessLevel.PACKAGE) - private final Map Verzik_RangeProjectiles = new HashMap<>(); + @Getter(AccessLevel.PACKAGE) + private final Map Verzik_RangeProjectiles = new HashMap<>(); @Getter(AccessLevel.PACKAGE) private final List Sotetseg_MageProjectiles = new ArrayList<>(); @@ -194,860 +195,1036 @@ public class TheatrePlugin extends Plugin { @Getter(AccessLevel.PACKAGE) private final List Sotetseg_RangeProjectiles = new ArrayList<>(); - @Getter(AccessLevel.PACKAGE) - private int P3_TicksUntilAttack = -1; - - @Getter(AccessLevel.PACKAGE) - private Projectile Verzik_YellowBall; - - @Getter(AccessLevel.PACKAGE) - private List Verzik_YellowTiles = new ArrayList<>(); - - @Getter(AccessLevel.PACKAGE) - private NPC Verzik_NPC; + @Getter(AccessLevel.PACKAGE) + private int P3_TicksUntilAttack = -1; @Getter(AccessLevel.PACKAGE) - private List tornadoList; + private Projectile Verzik_YellowBall; - @Getter(AccessLevel.PACKAGE) - private List crabList; + @Getter(AccessLevel.PACKAGE) + private List Verzik_YellowTiles = new ArrayList<>(); - @Getter - private int redCrabsTimer; + @Getter(AccessLevel.PACKAGE) + private NPC Verzik_NPC; - private int P3_attacksLeft; + @Getter(AccessLevel.PACKAGE) + private List tornadoList; - @Inject - private Client client; + @Getter(AccessLevel.PACKAGE) + private List crabList; - @Inject - private OverlayManager overlayManager; + @Getter + private int redCrabsTimer; - @Inject - private TheatreOverlay overlay; + private int P3_attacksLeft; - @Inject - private TheatreConfig config; + @Inject + private Client client; - @Inject - private TheatreXarpusOverlay xarpusOverlay; + @Inject + private OverlayManager overlayManager; - @Inject - private ChatMessageManager chatMessageManager; + @Inject + private TheatreOverlay overlay; - @Inject - private VerzikNyloOverlay verzikNyloOverlay; + @Inject + private TheatreConfig config; - @Inject - private BloatTimerOverlay bloatTimerOverlay; + @Inject + private TheatreXarpusOverlay xarpusOverlay; - @Provides - TheatreConfig getConfig(ConfigManager configManager) { - return configManager.getConfig(TheatreConfig.class); - } + @Inject + private ChatMessageManager chatMessageManager; - @Override - protected void startUp() { - overlayManager.add(overlay); - overlayManager.add(xarpusOverlay); - overlayManager.add(verzikNyloOverlay); - overlayManager.add(bloatTimerOverlay); - } + @Inject + private VerzikNyloOverlay verzikNyloOverlay; - @Override - protected void shutDown() { - overlayManager.remove(overlay); - overlayManager.remove(xarpusOverlay); - overlayManager.remove(xarpusOverlay); - overlayManager.remove(bloatTimerOverlay); - } + @Inject + private BloatTimerOverlay bloatTimerOverlay; - @Subscribe - public void onMenuEntryAdded(MenuEntryAdded event) { - if (client.getGameState() != GameState.LOGGED_IN || !config.NyloMenu() || !runNylocas) { - return; - } + @Provides + TheatreConfig getConfig(ConfigManager configManager) + { + return configManager.getConfig(TheatreConfig.class); + } - final String pOptionToReplace = Text.removeTags(event.getOption()).toUpperCase(); + @Override + protected void startUp() + { + overlayManager.add(overlay); + overlayManager.add(xarpusOverlay); + overlayManager.add(verzikNyloOverlay); + overlayManager.add(bloatTimerOverlay); + } - int attackType = 0; //0=idk 1= melee 2= range 3= mage + @Override + protected void shutDown() + { + overlayManager.remove(overlay); + overlayManager.remove(xarpusOverlay); + overlayManager.remove(xarpusOverlay); + overlayManager.remove(bloatTimerOverlay); + } - for (KitType kitType : KitType.values()) { - int itemId = client.getLocalPlayer().getPlayerComposition().getEquipmentId(kitType); - switch (itemId) { - case ItemID.DRAGON_CLAWS: - case ItemID.SCYTHE_OF_VITUR: - case ItemID.SCYTHE_OF_VITUR_UNCHARGED: - case ItemID.SCYTHE_10735: - case ItemID.SCYTHE_OF_VITUR_22664: - case ItemID.HAM_JOINT: - case ItemID.EVENT_RPG: - case ItemID.ABYSSAL_WHIP: - case ItemID.ABYSSAL_TENTACLE: - case ItemID.FROZEN_ABYSSAL_WHIP: - case ItemID.VOLCANIC_ABYSSAL_WHIP: - case ItemID.GHRAZI_RAPIER: - case ItemID.DRAGON_WARHAMMER: - case ItemID.DRAGON_WARHAMMER_20785: - case ItemID.BANDOS_GODSWORD: - case ItemID.BANDOS_GODSWORD_OR: - case ItemID.BANDOS_GODSWORD_20782: - case ItemID.BANDOS_GODSWORD_21060: - case ItemID.CRYSTAL_HALBERD_510: - case ItemID.CRYSTAL_HALBERD_510_I: - case ItemID.CRYSTAL_HALBERD_610: - case ItemID.CRYSTAL_HALBERD_610_I: - case ItemID.CRYSTAL_HALBERD_710_I: - case ItemID.CRYSTAL_HALBERD_710: - case ItemID.CRYSTAL_HALBERD_110: - case ItemID.CRYSTAL_HALBERD_110_I: - case ItemID.CRYSTAL_HALBERD_210: - case ItemID.CRYSTAL_HALBERD_310: - case ItemID.CRYSTAL_HALBERD_310_I: - case ItemID.CRYSTAL_HALBERD_410: - case ItemID.CRYSTAL_HALBERD_410_I: - case ItemID.CRYSTAL_HALBERD_810: - case ItemID.CRYSTAL_HALBERD_810_I: - case ItemID.CRYSTAL_HALBERD_910: - case ItemID.CRYSTAL_HALBERD_910_I: - attackType = 1; - break; - case ItemID.TOXIC_BLOWPIPE: - case ItemID.TOXIC_BLOWPIPE_EMPTY: - case ItemID.RED_CHINCHOMPA_10034: - case ItemID.BLACK_CHINCHOMPA: - case ItemID.CHINCHOMPA_10033: - case ItemID.TWISTED_BOW: - attackType = 2; - break; - case ItemID.SANGUINESTI_STAFF: - case ItemID.TOXIC_STAFF_OF_THE_DEAD: - case ItemID.TRIDENT_OF_THE_SWAMP: - case ItemID.TRIDENT_OF_THE_SEAS_E: - case ItemID.TRIDENT_OF_THE_SEAS: - case ItemID.TRIDENT_OF_THE_SWAMP_E: - case ItemID.KODAI_WAND: - case ItemID.MASTER_WAND: - case ItemID.MASTER_WAND_20560: - attackType = 3; - break; - } - if (attackType != 0) { - break; - } + @Subscribe + public void onMenuEntryAdded(MenuEntryAdded event) + { + if (client.getGameState() != GameState.LOGGED_IN || !config.NyloMenu() || !runNylocas) + { + return; + } - } + final String pOptionToReplace = Text.removeTags(event.getOption()).toUpperCase(); - if (!pOptionToReplace.equals("ATTACK")) { - return; - } - int Id = 0; - if (BossNylo != null) { - Id = BossNylo.getId(); - } - String target = Text.removeTags(event.getTarget()).toLowerCase(); - if (attackType != 0) { - stripEntries(attackType, target, Id); - } + int attackType = 0; //0=idk 1= melee 2= range 3= mage - } + for (KitType kitType : KitType.values()) + { + int itemId = client.getLocalPlayer().getPlayerComposition().getEquipmentId(kitType); + switch (itemId) + { + case ItemID.DRAGON_CLAWS: + case ItemID.SCYTHE_OF_VITUR: + case ItemID.SCYTHE_OF_VITUR_UNCHARGED: + case ItemID.SCYTHE_10735: + case ItemID.SCYTHE_OF_VITUR_22664: + case ItemID.HAM_JOINT: + case ItemID.EVENT_RPG: + case ItemID.ABYSSAL_WHIP: + case ItemID.ABYSSAL_TENTACLE: + case ItemID.FROZEN_ABYSSAL_WHIP: + case ItemID.VOLCANIC_ABYSSAL_WHIP: + case ItemID.GHRAZI_RAPIER: + case ItemID.DRAGON_WARHAMMER: + case ItemID.DRAGON_WARHAMMER_20785: + case ItemID.BANDOS_GODSWORD: + case ItemID.BANDOS_GODSWORD_OR: + case ItemID.BANDOS_GODSWORD_20782: + case ItemID.BANDOS_GODSWORD_21060: + case ItemID.CRYSTAL_HALBERD_510: + case ItemID.CRYSTAL_HALBERD_510_I: + case ItemID.CRYSTAL_HALBERD_610: + case ItemID.CRYSTAL_HALBERD_610_I: + case ItemID.CRYSTAL_HALBERD_710_I: + case ItemID.CRYSTAL_HALBERD_710: + case ItemID.CRYSTAL_HALBERD_110: + case ItemID.CRYSTAL_HALBERD_110_I: + case ItemID.CRYSTAL_HALBERD_210: + case ItemID.CRYSTAL_HALBERD_310: + case ItemID.CRYSTAL_HALBERD_310_I: + case ItemID.CRYSTAL_HALBERD_410: + case ItemID.CRYSTAL_HALBERD_410_I: + case ItemID.CRYSTAL_HALBERD_810: + case ItemID.CRYSTAL_HALBERD_810_I: + case ItemID.CRYSTAL_HALBERD_910: + case ItemID.CRYSTAL_HALBERD_910_I: + attackType = 1; + break; + case ItemID.TOXIC_BLOWPIPE: + case ItemID.TOXIC_BLOWPIPE_EMPTY: + case ItemID.RED_CHINCHOMPA_10034: + case ItemID.BLACK_CHINCHOMPA: + case ItemID.CHINCHOMPA_10033: + case ItemID.TWISTED_BOW: + attackType = 2; + break; + case ItemID.SANGUINESTI_STAFF: + case ItemID.TOXIC_STAFF_OF_THE_DEAD: + case ItemID.TRIDENT_OF_THE_SWAMP: + case ItemID.TRIDENT_OF_THE_SEAS_E: + case ItemID.TRIDENT_OF_THE_SEAS: + case ItemID.TRIDENT_OF_THE_SWAMP_E: + case ItemID.KODAI_WAND: + case ItemID.MASTER_WAND: + case ItemID.MASTER_WAND_20560: + attackType = 3; + break; + } + if (attackType != 0) + { + break; + } - @Subscribe - public void onNpcSpawned(NpcSpawned npcSpawned) { + } - NPC npc = npcSpawned.getNpc(); - switch (npc.getId()) { - case NpcID.THE_MAIDEN_OF_SUGADINTI: - case NpcID.THE_MAIDEN_OF_SUGADINTI_8361: - case NpcID.THE_MAIDEN_OF_SUGADINTI_8362: - case NpcID.THE_MAIDEN_OF_SUGADINTI_8363: - case NpcID.THE_MAIDEN_OF_SUGADINTI_8364: - case NpcID.THE_MAIDEN_OF_SUGADINTI_8365: - runMaiden = true; - break; - case NpcID.BLOOD_SPAWN: - Maiden_Spawns.add(npc); - break; - case NpcID.PESTILENT_BLOAT: - runBloat = true; - Bloat_NPC = npc; - bloatTimer = 0; - bloatFlag = false; - break; - case NpcID.NYLOCAS_VASILIAS: - case NpcID.NYLOCAS_VASILIAS_8355: - case NpcID.NYLOCAS_VASILIAS_8356: - case NpcID.NYLOCAS_VASILIAS_8357: - BossNylo = npc; - break; - case NPCID_NYLOCAS_PILLAR: - runNylocas = true; - if (!Nylocas_Pillars.keySet().contains(npc)) { - Nylocas_Pillars.put(npc, 100); - } - break; - case 8342: - case 8343: - case 8344: - case 8345: - case 8346: - case 8347: - case 8348: - case 8349: - case 8350: - case 8351: - case 8352: - case 8353: - if (runNylocas) { - Nylocas_Map.put(npc, 52); - } - break; - case NpcID.SOTETSEG: - case NpcID.SOTETSEG_8388: - runSotetseg = true; - RedTiles.clear(); - break; - case NpcID.XARPUS: - case NpcID.XARPUS_8339: - case NpcID.XARPUS_8340: - case NpcID.XARPUS_8341: - runXarpus = true; - exhumecount = 25; - Xarpus_NPC = npc; - Xarpus_Stare = false; - Xarpus_TicksUntilShoot = 9; - Xarpus_previousAnimation = -1; - break; - case NpcID.VERZIK_VITUR_8369: - case NpcID.VERZIK_VITUR_8370: - case NpcID.VERZIK_VITUR_8371: - case NpcID.VERZIK_VITUR_8372: - case NpcID.VERZIK_VITUR_8373: - case NpcID.VERZIK_VITUR_8374: - case NpcID.VERZIK_VITUR_8375: - P3_TicksUntilAttack = -1; - P3_attacksLeft = 9; - redCrabsTimer = 13; - Verzik_NPC = npc; - runVerzik = true; - tornadoList = new ArrayList<>(); - crabList = new ArrayList<>(); - break; - } - } + if (!pOptionToReplace.equals("ATTACK")) + { + return; + } + int Id = 0; + if (BossNylo != null) + { + Id = BossNylo.getId(); + } + String target = Text.removeTags(event.getTarget()).toLowerCase(); + if (attackType != 0) + { + stripEntries(attackType, target, Id); + } - @Subscribe - public void onNpcDespawned(NpcDespawned npcDespawned) { - NPC npc = npcDespawned.getNpc(); - switch (npc.getId()) { - case NpcID.THE_MAIDEN_OF_SUGADINTI: - case NpcID.THE_MAIDEN_OF_SUGADINTI_8361: - case NpcID.THE_MAIDEN_OF_SUGADINTI_8362: - case NpcID.THE_MAIDEN_OF_SUGADINTI_8363: - case NpcID.THE_MAIDEN_OF_SUGADINTI_8364: - case NpcID.THE_MAIDEN_OF_SUGADINTI_8365: - runMaiden = false; - Maiden_Spawns.clear(); - break; - case NpcID.BLOOD_SPAWN: - Maiden_Spawns.remove(npc); - break; - case NpcID.PESTILENT_BLOAT: - runBloat = false; - Bloat_NPC = null; - bloatTimer = 0; - break; - case NPCID_NYLOCAS_PILLAR: - if (Nylocas_Pillars.keySet().contains(npc)) { - Nylocas_Pillars.remove(npc); - } - break; - case 8342: - case 8343: - case 8344: - case 8345: - case 8346: - case 8347: - case 8348: - case 8349: - case 8350: - case 8351: - case 8352: - case 8353: - if (Nylocas_Map.keySet().contains(npc)) { - Nylocas_Map.remove(npc); - } - break; - case NpcID.SOTETSEG: - case NpcID.SOTETSEG_8388: - RedTiles.clear(); - if (client.getPlane() != 3) { - runSotetseg = false; - } - break; - case NpcID.XARPUS: - case NpcID.XARPUS_8339: - case NpcID.XARPUS_8340: - case NpcID.XARPUS_8341: - runXarpus = false; - Xarpus_NPC = null; - Xarpus_Stare = false; - Xarpus_TicksUntilShoot = 9; - Xarpus_previousAnimation = -1; - Xarpus_Exhumeds.clear(); - exhumecount = 0; - break; - case NpcID.VERZIK_VITUR_8369: - case NpcID.VERZIK_VITUR_8370: - case NpcID.VERZIK_VITUR_8371: - case NpcID.VERZIK_VITUR_8372: - case NpcID.VERZIK_VITUR_8373: - case NpcID.VERZIK_VITUR_8374: - case NpcID.VERZIK_VITUR_8375: - runVerzik = false; - redCrabsTimer = 0; - Verzik_NPC = null; - break; - } + } - } + @Subscribe + public void onNpcSpawned(NpcSpawned npcSpawned) + { - @Subscribe - public void onGroundObjectSpawned(GroundObjectSpawned event) { - if (runSotetseg) { - GroundObject o = event.getGroundObject(); - if (o.getId() == GROUNDOBJECT_ID_BLACKMAZE) { - Tile t = event.getTile(); - WorldPoint p = t.getWorldLocation(); - if (t.getPlane() == 0) { - if (!BlackTilesOverworld.contains(p)) - BlackTilesOverworld.add(p); - } else { - if (!BlackTilesUnderworld.contains(p)) - BlackTilesUnderworld.add(p); - } - } + NPC npc = npcSpawned.getNpc(); + switch (npc.getId()) + { + case NpcID.THE_MAIDEN_OF_SUGADINTI: + case NpcID.THE_MAIDEN_OF_SUGADINTI_8361: + case NpcID.THE_MAIDEN_OF_SUGADINTI_8362: + case NpcID.THE_MAIDEN_OF_SUGADINTI_8363: + case NpcID.THE_MAIDEN_OF_SUGADINTI_8364: + case NpcID.THE_MAIDEN_OF_SUGADINTI_8365: + runMaiden = true; + break; + case NpcID.BLOOD_SPAWN: + Maiden_Spawns.add(npc); + break; + case NpcID.PESTILENT_BLOAT: + runBloat = true; + Bloat_NPC = npc; + bloatTimer = 0; + bloatFlag = false; + break; + case NpcID.NYLOCAS_VASILIAS: + case NpcID.NYLOCAS_VASILIAS_8355: + case NpcID.NYLOCAS_VASILIAS_8356: + case NpcID.NYLOCAS_VASILIAS_8357: + BossNylo = npc; + break; + case NPCID_NYLOCAS_PILLAR: + runNylocas = true; + if (!Nylocas_Pillars.keySet().contains(npc)) + { + Nylocas_Pillars.put(npc, 100); + } + break; + case 8342: + case 8343: + case 8344: + case 8345: + case 8346: + case 8347: + case 8348: + case 8349: + case 8350: + case 8351: + case 8352: + case 8353: + if (runNylocas) + { + Nylocas_Map.put(npc, 52); + } + break; + case NpcID.SOTETSEG: + case NpcID.SOTETSEG_8388: + runSotetseg = true; + RedTiles.clear(); + break; + case NpcID.XARPUS: + case NpcID.XARPUS_8339: + case NpcID.XARPUS_8340: + case NpcID.XARPUS_8341: + runXarpus = true; + exhumecount = 25; + Xarpus_NPC = npc; + Xarpus_Stare = false; + Xarpus_TicksUntilShoot = 9; + Xarpus_previousAnimation = -1; + break; + case NpcID.VERZIK_VITUR_8369: + case NpcID.VERZIK_VITUR_8370: + case NpcID.VERZIK_VITUR_8371: + case NpcID.VERZIK_VITUR_8372: + case NpcID.VERZIK_VITUR_8373: + case NpcID.VERZIK_VITUR_8374: + case NpcID.VERZIK_VITUR_8375: + P3_TicksUntilAttack = -1; + P3_attacksLeft = 9; + redCrabsTimer = 13; + Verzik_NPC = npc; + runVerzik = true; + tornadoList = new ArrayList<>(); + crabList = new ArrayList<>(); + break; + } + } - if (o.getId() == GROUNDOBJECT_ID_REDMAZE) { - Tile t = event.getTile(); - WorldPoint p = t.getWorldLocation(); - if (p.getPlane() == 0) { - if (!RedTiles.containsValue(t)) { - RedTiles.put(o, t); - } - } else { - if (!RedTilesUnderworld.contains(p)) - RedTilesUnderworld.add(p); - } - } - } + @Subscribe + public void onNpcDespawned(NpcDespawned npcDespawned) + { + NPC npc = npcDespawned.getNpc(); + switch (npc.getId()) + { + case NpcID.THE_MAIDEN_OF_SUGADINTI: + case NpcID.THE_MAIDEN_OF_SUGADINTI_8361: + case NpcID.THE_MAIDEN_OF_SUGADINTI_8362: + case NpcID.THE_MAIDEN_OF_SUGADINTI_8363: + case NpcID.THE_MAIDEN_OF_SUGADINTI_8364: + case NpcID.THE_MAIDEN_OF_SUGADINTI_8365: + runMaiden = false; + Maiden_Spawns.clear(); + break; + case NpcID.BLOOD_SPAWN: + Maiden_Spawns.remove(npc); + break; + case NpcID.PESTILENT_BLOAT: + runBloat = false; + Bloat_NPC = null; + bloatTimer = 0; + break; + case NPCID_NYLOCAS_PILLAR: + if (Nylocas_Pillars.keySet().contains(npc)) + { + Nylocas_Pillars.remove(npc); + } + break; + case 8342: + case 8343: + case 8344: + case 8345: + case 8346: + case 8347: + case 8348: + case 8349: + case 8350: + case 8351: + case 8352: + case 8353: + if (Nylocas_Map.keySet().contains(npc)) + { + Nylocas_Map.remove(npc); + } + break; + case NpcID.SOTETSEG: + case NpcID.SOTETSEG_8388: + RedTiles.clear(); + if (client.getPlane() != 3) + { + runSotetseg = false; + } + break; + case NpcID.XARPUS: + case NpcID.XARPUS_8339: + case NpcID.XARPUS_8340: + case NpcID.XARPUS_8341: + runXarpus = false; + Xarpus_NPC = null; + Xarpus_Stare = false; + Xarpus_TicksUntilShoot = 9; + Xarpus_previousAnimation = -1; + Xarpus_Exhumeds.clear(); + exhumecount = 0; + break; + case NpcID.VERZIK_VITUR_8369: + case NpcID.VERZIK_VITUR_8370: + case NpcID.VERZIK_VITUR_8371: + case NpcID.VERZIK_VITUR_8372: + case NpcID.VERZIK_VITUR_8373: + case NpcID.VERZIK_VITUR_8374: + case NpcID.VERZIK_VITUR_8375: + runVerzik = false; + redCrabsTimer = 0; + Verzik_NPC = null; + break; + } - if (runXarpus) { - GroundObject o = event.getGroundObject(); - if (o.getId() == GROUNDOBJECT_ID_EXHUMED) { + } - xarpusExhumedsTimer.put(o, 11); + @Subscribe + public void onGroundObjectSpawned(GroundObjectSpawned event) + { + if (runSotetseg) + { + GroundObject o = event.getGroundObject(); + if (o.getId() == GROUNDOBJECT_ID_BLACKMAZE) + { + Tile t = event.getTile(); + WorldPoint p = t.getWorldLocation(); + if (t.getPlane() == 0) + { + if (!BlackTilesOverworld.contains(p)) + { + BlackTilesOverworld.add(p); + } + } + else + { + if (!BlackTilesUnderworld.contains(p)) + { + BlackTilesUnderworld.add(p); + } + } + } - Xarpus_Exhumeds.put(o, 11); + if (o.getId() == GROUNDOBJECT_ID_REDMAZE) + { + Tile t = event.getTile(); + WorldPoint p = t.getWorldLocation(); + if (p.getPlane() == 0) + { + if (!RedTiles.containsValue(t)) + { + RedTiles.put(o, t); + } + } + else + { + if (!RedTilesUnderworld.contains(p)) + { + RedTilesUnderworld.add(p); + } + } + } + } - } + if (runXarpus) + { + GroundObject o = event.getGroundObject(); + if (o.getId() == GROUNDOBJECT_ID_EXHUMED) + { - } - } + xarpusExhumedsTimer.put(o, 11); - @Subscribe - public void onProjectileMoved(ProjectileMoved event) { - if (runVerzik) { - Projectile projectile = event.getProjectile(); - if (projectile.getId() == PROJECTILE_ID_P2RANGE) { - WorldPoint p = WorldPoint.fromLocal(client, event.getPosition()); - Verzik_RangeProjectiles.put(projectile, p); - } - } - if (runSotetseg) + Xarpus_Exhumeds.put(o, 11); + + } + + } + } + + @Subscribe + public void onProjectileMoved(ProjectileMoved event) + { + if (runVerzik) { Projectile projectile = event.getProjectile(); - if (projectile.getId() == 1606) { + if (projectile.getId() == PROJECTILE_ID_P2RANGE) + { + WorldPoint p = WorldPoint.fromLocal(client, event.getPosition()); + Verzik_RangeProjectiles.put(projectile, p); + } + } + if (runSotetseg) + { + Projectile projectile = event.getProjectile(); + if (projectile.getId() == 1606) + { Sotetseg_MageProjectiles.add(projectile); } - if (projectile.getId() == 1607) { + if (projectile.getId() == 1607) + { Sotetseg_RangeProjectiles.add(projectile); } } - } + } - @Subscribe - public void onAnimationChanged(AnimationChanged event) { - if (runVerzik) { - if (event.getActor().getAnimation() == 8117) { - redCrabsTimer = 11; - } - } - } + @Subscribe + public void onAnimationChanged(AnimationChanged event) + { + if (runVerzik) + { + if (event.getActor().getAnimation() == 8117) + { + redCrabsTimer = 11; + } + } + } - @Subscribe - public void onVarbitChanged(VarbitChanged event) { - if (runBloat) { + @Subscribe + public void onVarbitChanged(VarbitChanged event) + { + if (runBloat) + { - if (client.getVar(Varbits.BLOAT_ENTERED_ROOM) == 1) { - if (!bloatFlag) { - bloatTimer = 0; - bloatFlag = true; - } - } - } - } + if (client.getVar(Varbits.BLOAT_ENTERED_ROOM) == 1) + { + if (!bloatFlag) + { + bloatTimer = 0; + bloatFlag = true; + } + } + } + } - @Subscribe - public void onGraphicsObjectCreated(GraphicsObjectCreated event) { - GraphicsObject obj = event.getGraphicsObject(); - if (obj.getId() == 1570 || obj.getId() == 1571 || obj.getId() == 1572 || obj.getId() == 1573 || obj.getId() == 1574 || obj.getId() == 1575 || obj.getId() == 1576) { - WorldPoint p = WorldPoint.fromLocal(client, obj.getLocation()); - if (temp.size() == 0) { + @Subscribe + public void onGraphicsObjectCreated(GraphicsObjectCreated event) + { + GraphicsObject obj = event.getGraphicsObject(); + if (obj.getId() == 1570 || obj.getId() == 1571 || obj.getId() == 1572 || obj.getId() == 1573 || obj.getId() == 1574 || obj.getId() == 1575 || obj.getId() == 1576) + { + WorldPoint p = WorldPoint.fromLocal(client, obj.getLocation()); + if (temp.size() == 0) + { - } else { + } + else + { - } - } - } + } + } + } - @Subscribe - public void onGameTick(GameTick event) { - if (runMaiden) { - Maiden_BloodSpatters.clear(); - for (GraphicsObject o : client.getGraphicsObjects()) { - if (o.getId() == GRAPHICSOBJECT_ID_MAIDEN) { - Maiden_BloodSpatters.add(WorldPoint.fromLocal(client, o.getLocation())); - } - } + @Subscribe + public void onGameTick(GameTick event) + { + if (runMaiden) + { + Maiden_BloodSpatters.clear(); + for (GraphicsObject o : client.getGraphicsObjects()) + { + if (o.getId() == GRAPHICSOBJECT_ID_MAIDEN) + { + Maiden_BloodSpatters.add(WorldPoint.fromLocal(client, o.getLocation())); + } + } - Maiden_SpawnLocations2.clear(); - Maiden_SpawnLocations2.addAll(Maiden_SpawnLocations); - Maiden_SpawnLocations.clear(); - for (NPC spawn : Maiden_Spawns) { - Maiden_SpawnLocations.add(spawn.getWorldLocation()); - } - } + Maiden_SpawnLocations2.clear(); + Maiden_SpawnLocations2.addAll(Maiden_SpawnLocations); + Maiden_SpawnLocations.clear(); + for (NPC spawn : Maiden_Spawns) + { + Maiden_SpawnLocations.add(spawn.getWorldLocation()); + } + } - if (runBloat) { + if (runBloat) + { - localTemp.clear(); + localTemp.clear(); - //System.out.println("Temp flag" + tempFlag); - //System.out.println("Temp2 flag" + temp2Flag); + //System.out.println("Temp flag" + tempFlag); + //System.out.println("Temp2 flag" + temp2Flag); - for (GraphicsObject obj : client.getGraphicsObjects()) { - if (obj.getId() == 1570 || obj.getId() == 1571 || obj.getId() == 1572 || obj.getId() == 1573 || obj.getId() == 1574 || obj.getId() == 1575 || obj.getId() == 1576) { - WorldPoint p = WorldPoint.fromLocal(client, obj.getLocation()); - //Already have some feet in temp Set - if (temp.size() > 0) { - //System.out.println("temp size > 0, tempflag set false, tempflag2 set true"); - tempFlag = false; - temp2Flag = true; - } else { - //System.out.println("temp size 0, tempflag set true, tempflag2 set false"); - tempFlag = true; - temp2Flag = false; + for (GraphicsObject obj : client.getGraphicsObjects()) + { + if (obj.getId() == 1570 || obj.getId() == 1571 || obj.getId() == 1572 || obj.getId() == 1573 || obj.getId() == 1574 || obj.getId() == 1575 || obj.getId() == 1576) + { + WorldPoint p = WorldPoint.fromLocal(client, obj.getLocation()); + //Already have some feet in temp Set + if (temp.size() > 0) + { + //System.out.println("temp size > 0, tempflag set false, tempflag2 set true"); + tempFlag = false; + temp2Flag = true; + } + else + { + //System.out.println("temp size 0, tempflag set true, tempflag2 set false"); + tempFlag = true; + temp2Flag = false; - } - localTemp.add(p); - } - } + } + localTemp.add(p); + } + } - if (tempFlag) { - temp2.clear(); - temp2Flag = false; - temp.addAll(localTemp); + if (tempFlag) + { + temp2.clear(); + temp2Flag = false; + temp.addAll(localTemp); - //System.out.println("temp2 cleared, temp2flag set false, added to temp set"); - } else if (temp2Flag) { - temp.clear(); - tempFlag = false; - temp2.addAll(localTemp); - //System.out.println("temp cleared, tempflag set false, added to temp2 set"); + //System.out.println("temp2 cleared, temp2flag set false, added to temp set"); + } + else if (temp2Flag) + { + temp.clear(); + tempFlag = false; + temp2.addAll(localTemp); + //System.out.println("temp cleared, tempflag set false, added to temp2 set"); - } + } - Bloat_downCount++; + Bloat_downCount++; - if (Bloat_NPC.getAnimation() == -1) //1 = up; 2 = down; 3 = warn; - { - bloatTimer++; - Bloat_downCount = 0; - if (Bloat_NPC.getHealth() == 0) { - Bloat_State = 2; - } else - Bloat_State = 1; - } else { - if (25 < Bloat_downCount && Bloat_downCount < 35) { - Bloat_State = 3; - } else if (Bloat_downCount < 26) { - tempFlag = false; - temp2Flag = false; - temp2.clear(); - temp.clear(); - Bloat_State = 2; - bloatTimer = 0; - } else if (Bloat_NPC.getModelHeight() == 568) { - tempFlag = false; - temp2Flag = false; - temp2.clear(); - temp.clear(); - Bloat_State = 2; - } else - Bloat_State = 1; + if (Bloat_NPC.getAnimation() == -1) //1 = up; 2 = down; 3 = warn; + { + bloatTimer++; + Bloat_downCount = 0; + if (Bloat_NPC.getHealth() == 0) + { + Bloat_State = 2; + } + else + { + Bloat_State = 1; + } + } + else + { + if (25 < Bloat_downCount && Bloat_downCount < 35) + { + Bloat_State = 3; + } + else if (Bloat_downCount < 26) + { + tempFlag = false; + temp2Flag = false; + temp2.clear(); + temp.clear(); + Bloat_State = 2; + bloatTimer = 0; + } + else if (Bloat_NPC.getModelHeight() == 568) + { + tempFlag = false; + temp2Flag = false; + temp2.clear(); + temp.clear(); + Bloat_State = 2; + } + else + { + Bloat_State = 1; + } - } - } + } + } - if (runNylocas) { - for (Iterator it = Nylocas_Map.keySet().iterator(); it.hasNext(); ) { - NPC npc = it.next(); - int ticksLeft = Nylocas_Map.get(npc); + if (runNylocas) + { + for (Iterator it = Nylocas_Map.keySet().iterator(); it.hasNext(); ) + { + NPC npc = it.next(); + int ticksLeft = Nylocas_Map.get(npc); - if (ticksLeft < 0) { - it.remove(); - continue; - } - Nylocas_Map.replace(npc, ticksLeft - 1); - } + if (ticksLeft < 0) + { + it.remove(); + continue; + } + Nylocas_Map.replace(npc, ticksLeft - 1); + } - for (NPC pillar : Nylocas_Pillars.keySet()) { - int healthPercent = pillar.getHealthRatio(); - if (healthPercent > -1) { - Nylocas_Pillars.replace(pillar, healthPercent); - } - } - for (NPC npc : client.getNpcs()) { - if (npc.getId() == 8358) { - runNylocas = true; - break; - } - runNylocas = false; - BossNylo = null; - } - } + for (NPC pillar : Nylocas_Pillars.keySet()) + { + int healthPercent = pillar.getHealthRatio(); + if (healthPercent > -1) + { + Nylocas_Pillars.replace(pillar, healthPercent); + } + } + for (NPC npc : client.getNpcs()) + { + if (npc.getId() == 8358) + { + runNylocas = true; + break; + } + runNylocas = false; + BossNylo = null; + } + } - if (runSotetseg) { - boolean sotetsegFighting = false; - for (NPC npc : client.getNpcs()) { - if (npc.getId() == NpcID.SOTETSEG_8388) { - BlackTilesUnderworld.clear(); - BlackTilesOverworld.clear(); - RedTilesOverworld.clear(); - RedTilesUnderworld.clear(); - GridPath.clear(); - sotetsegFighting = true; - RedTiles.clear(); - break; - } - } + if (runSotetseg) + { + boolean sotetsegFighting = false; + for (NPC npc : client.getNpcs()) + { + if (npc.getId() == NpcID.SOTETSEG_8388) + { + BlackTilesUnderworld.clear(); + BlackTilesOverworld.clear(); + RedTilesOverworld.clear(); + RedTilesUnderworld.clear(); + GridPath.clear(); + sotetsegFighting = true; + RedTiles.clear(); + break; + } + } - if (!getSotetseg_MageProjectiles().isEmpty()) { - for (Iterator it = Sotetseg_MageProjectiles.iterator(); it.hasNext(); ) { + if (!getSotetseg_MageProjectiles().isEmpty()) + { + for (Iterator it = Sotetseg_MageProjectiles.iterator(); it.hasNext(); ) + { Projectile projectile = it.next(); - if (projectile.getRemainingCycles() < 1) { + if (projectile.getRemainingCycles() < 1) + { it.remove(); } } } - if (!getSotetseg_RangeProjectiles().isEmpty()) { - for (Iterator it = Sotetseg_RangeProjectiles.iterator(); it.hasNext(); ) { + if (!getSotetseg_RangeProjectiles().isEmpty()) + { + for (Iterator it = Sotetseg_RangeProjectiles.iterator(); it.hasNext(); ) + { Projectile projectile = it.next(); - if (projectile.getRemainingCycles() < 1) { + if (projectile.getRemainingCycles() < 1) + { it.remove(); } } } - if (!sotetsegFighting) { - if (!BlackTilesUnderworld.isEmpty() && !RedTilesUnderworld.isEmpty() && GridPath.isEmpty()) { - int minX = 99999; - int minY = 99999; - for (WorldPoint p : BlackTilesUnderworld) { - int x = p.getX(); - int y = p.getY(); - if (x < minX) { - minX = x; - } - if (y < minY) { - minY = y; - } - } + if (!sotetsegFighting) + { + if (!BlackTilesUnderworld.isEmpty() && !RedTilesUnderworld.isEmpty() && GridPath.isEmpty()) + { + int minX = 99999; + int minY = 99999; + for (WorldPoint p : BlackTilesUnderworld) + { + int x = p.getX(); + int y = p.getY(); + if (x < minX) + { + minX = x; + } + if (y < minY) + { + minY = y; + } + } - boolean messageSent = false; - for (WorldPoint p : RedTilesUnderworld) { - WorldPoint pN = new WorldPoint(p.getX(), p.getY() + 1, p.getPlane()); - WorldPoint pS = new WorldPoint(p.getX(), p.getY() - 1, p.getPlane()); - WorldPoint pE = new WorldPoint(p.getX() + 1, p.getY(), p.getPlane()); - WorldPoint pW = new WorldPoint(p.getX() - 1, p.getY(), p.getPlane()); + boolean messageSent = false; + for (WorldPoint p : RedTilesUnderworld) + { + WorldPoint pN = new WorldPoint(p.getX(), p.getY() + 1, p.getPlane()); + WorldPoint pS = new WorldPoint(p.getX(), p.getY() - 1, p.getPlane()); + WorldPoint pE = new WorldPoint(p.getX() + 1, p.getY(), p.getPlane()); + WorldPoint pW = new WorldPoint(p.getX() - 1, p.getY(), p.getPlane()); - if (!((RedTilesUnderworld.contains(pN) && RedTilesUnderworld.contains(pS)) || - (RedTilesUnderworld.contains(pE) && RedTilesUnderworld.contains(pW)))) { - GridPath.add(new Point(p.getX() - minX, p.getY() - minY)); - if (!messageSent) { - //client.addChatMessage(ChatMessageType.SERVER, "", "Maze path acquired.", null); - messageSent = true; - } - } + if (!((RedTilesUnderworld.contains(pN) && RedTilesUnderworld.contains(pS)) || + (RedTilesUnderworld.contains(pE) && RedTilesUnderworld.contains(pW)))) + { + GridPath.add(new Point(p.getX() - minX, p.getY() - minY)); + if (!messageSent) + { + //client.addChatMessage(ChatMessageType.SERVER, "", "Maze path acquired.", null); + messageSent = true; + } + } - } - } + } + } - if (!BlackTilesOverworld.isEmpty() && !GridPath.isEmpty() && RedTilesOverworld.isEmpty()) { - int minX = 99999; - int minY = 99999; - for (WorldPoint p : BlackTilesOverworld) { - int x = p.getX(); - int y = p.getY(); - if (x < minX) { - minX = x; - } - if (y < minY) { - minY = y; - } - } - for (Point p : GridPath) { - RedTilesOverworld.add(new WorldPoint(minX + p.getX(), minY + p.getY(), 0)); - } - } - } - } + if (!BlackTilesOverworld.isEmpty() && !GridPath.isEmpty() && RedTilesOverworld.isEmpty()) + { + int minX = 99999; + int minY = 99999; + for (WorldPoint p : BlackTilesOverworld) + { + int x = p.getX(); + int y = p.getY(); + if (x < minX) + { + minX = x; + } + if (y < minY) + { + minY = y; + } + } + for (Point p : GridPath) + { + RedTilesOverworld.add(new WorldPoint(minX + p.getX(), minY + p.getY(), 0)); + } + } + } + } - if (runXarpus) { - int size = xarpusExhumedsTimer.size(); - for (Map.Entry exhumes : xarpusExhumedsTimer.entrySet()) { - if (size > 0) { - exhumes.setValue(exhumes.getValue() - 1); - } + if (runXarpus) + { + int size = xarpusExhumedsTimer.size(); + for (Map.Entry exhumes : xarpusExhumedsTimer.entrySet()) + { + if (size > 0) + { + exhumes.setValue(exhumes.getValue() - 1); + } - } - for (Iterator it = Xarpus_Exhumeds.keySet().iterator(); it.hasNext(); ) { - GroundObject key = it.next(); - Xarpus_Exhumeds.replace(key, Xarpus_Exhumeds.get(key) - 1); - if (Xarpus_Exhumeds.get(key) < 0) { - it.remove(); - exhumecount--; - } - } - if ((Xarpus_NPC.getComposition().getOverheadIcon() != null)) { - Xarpus_Stare = true; - } - if (Xarpus_Stare) { - //dont hit xarpus if it looking at u - } else if (Xarpus_NPC.getId() == NpcID.XARPUS_8340) { - Xarpus_TicksUntilShoot--; - //if (Xarpus_NPC.getAnimation() == ANIMATION_ID_XARPUS && Xarpus_previousAnimation != ANIMATION_ID_XARPUS) - //{ - //Xarpus_TicksUntilShoot = 3; - //} - //Xarpus_previousAnimation = Xarpus_NPC.getAnimation(); - } + } + for (Iterator it = Xarpus_Exhumeds.keySet().iterator(); it.hasNext(); ) + { + GroundObject key = it.next(); + Xarpus_Exhumeds.replace(key, Xarpus_Exhumeds.get(key) - 1); + if (Xarpus_Exhumeds.get(key) < 0) + { + it.remove(); + exhumecount--; + } + } + if ((Xarpus_NPC.getComposition().getOverheadIcon() != null)) + { + Xarpus_Stare = true; + } + if (Xarpus_Stare) + { + //dont hit xarpus if it looking at u + } + else if (Xarpus_NPC.getId() == NpcID.XARPUS_8340) + { + Xarpus_TicksUntilShoot--; + //if (Xarpus_NPC.getAnimation() == ANIMATION_ID_XARPUS && Xarpus_previousAnimation != ANIMATION_ID_XARPUS) + //{ + //Xarpus_TicksUntilShoot = 3; + //} + //Xarpus_previousAnimation = Xarpus_NPC.getAnimation(); + } - } + } - if (runVerzik) { - crabList.clear(); - for (NPC npc : client.getNpcs()) { + if (runVerzik) + { + crabList.clear(); + for (NPC npc : client.getNpcs()) + { - if (npc.getName().toLowerCase().contains("nylo")) { - crabList.add(npc); - } - } + if (npc.getName().toLowerCase().contains("nylo")) + { + crabList.add(npc); + } + } - if (Verzik_NPC.getAnimation() == 8117) { - redCrabsTimer = redCrabsTimer - 1; - } - if (!Verzik_RangeProjectiles.isEmpty()) { - for (Iterator it = Verzik_RangeProjectiles.keySet().iterator(); it.hasNext(); ) { - Projectile projectile = it.next(); - if (projectile.getRemainingCycles() < 1) { - it.remove(); - } - } - } + if (Verzik_NPC.getAnimation() == 8117) + { + redCrabsTimer = redCrabsTimer - 1; + } + if (!Verzik_RangeProjectiles.isEmpty()) + { + for (Iterator it = Verzik_RangeProjectiles.keySet().iterator(); it.hasNext(); ) + { + Projectile projectile = it.next(); + if (projectile.getRemainingCycles() < 1) + { + it.remove(); + } + } + } - Verzik_YellowBall = null; - Verzik_YellowTiles.clear(); + Verzik_YellowBall = null; + Verzik_YellowTiles.clear(); - for (Projectile projectile : client.getProjectiles()) { - if (projectile.getId() == PROJECTILE_ID_YELLOW) { - Verzik_YellowBall = projectile; - break; - } - } - for (GraphicsObject o : client.getGraphicsObjects()) { - if (o.getId() == GRAPHICSOBJECT_ID_YELLOW) { + for (Projectile projectile : client.getProjectiles()) + { + if (projectile.getId() == PROJECTILE_ID_YELLOW) + { + Verzik_YellowBall = projectile; + break; + } + } + for (GraphicsObject o : client.getGraphicsObjects()) + { + if (o.getId() == GRAPHICSOBJECT_ID_YELLOW) + { - Verzik_YellowTiles.add(WorldPoint.fromLocal(client, o.getLocation())); - } - } + Verzik_YellowTiles.add(WorldPoint.fromLocal(client, o.getLocation())); + } + } - if (Verzik_NPC.getId() == VERZIK_ID_P3) { - boolean tornadosActive = false; - for (NPC npc : client.getNpcs()) { - if (npc.getId() == NPC_ID_TORNADO) { - tornadoList.add(npc); - tornadosActive = true; - break; - } - } + if (Verzik_NPC.getId() == VERZIK_ID_P3) + { + boolean tornadosActive = false; + for (NPC npc : client.getNpcs()) + { + if (npc.getId() == NPC_ID_TORNADO) + { + tornadoList.add(npc); + tornadosActive = true; + break; + } + } - boolean isGreenBall = false; - for (Projectile projectile : client.getProjectiles()) { - if (projectile.getId() == PROJECTILE_ID_P3_GREEN) { - isGreenBall = projectile.getRemainingCycles() > 210; - break; - } - } + boolean isGreenBall = false; + for (Projectile projectile : client.getProjectiles()) + { + if (projectile.getId() == PROJECTILE_ID_P3_GREEN) + { + isGreenBall = projectile.getRemainingCycles() > 210; + break; + } + } - P3_TicksUntilAttack--; + P3_TicksUntilAttack--; - switch (Verzik_NPC.getAnimation()) { - case ANIMATION_ID_P3_MAGE: - if (P3_TicksUntilAttack < 2) { - P3_attacksLeft--; - if (tornadosActive) { - P3_TicksUntilAttack = 5; - } else { - P3_TicksUntilAttack = 7; - } - if (P3_attacksLeft < 1) { - P3_TicksUntilAttack = 24; - } - } - break; - case ANIMATION_ID_P3_RANGE: - if (P3_TicksUntilAttack < 2) { - P3_attacksLeft--; - if (tornadosActive) { - P3_TicksUntilAttack = 5; - } else { - P3_TicksUntilAttack = 7; - } - if (P3_attacksLeft < 1) { - P3_TicksUntilAttack = 30; - } - if (isGreenBall) { - P3_TicksUntilAttack = 12; - } - } - break; - case ANIMATION_ID_P3_MELEE: - if (P3_TicksUntilAttack < 2) { - P3_attacksLeft--; - if (tornadosActive) { - P3_TicksUntilAttack = 5; - } else { - P3_TicksUntilAttack = 7; - } - if (P3_attacksLeft < 1) { - P3_TicksUntilAttack = 24; - } - } - break; - case ANIMATION_ID_P3_WEB: - P3_attacksLeft = 4; - P3_TicksUntilAttack = 11; // - break; - case ANIMATION_ID_P3_YELLOW: - P3_attacksLeft = 14; - P3_TicksUntilAttack = 11; - break; - } - } + switch (Verzik_NPC.getAnimation()) + { + case ANIMATION_ID_P3_MAGE: + if (P3_TicksUntilAttack < 2) + { + P3_attacksLeft--; + if (tornadosActive) + { + P3_TicksUntilAttack = 5; + } + else + { + P3_TicksUntilAttack = 7; + } + if (P3_attacksLeft < 1) + { + P3_TicksUntilAttack = 24; + } + } + break; + case ANIMATION_ID_P3_RANGE: + if (P3_TicksUntilAttack < 2) + { + P3_attacksLeft--; + if (tornadosActive) + { + P3_TicksUntilAttack = 5; + } + else + { + P3_TicksUntilAttack = 7; + } + if (P3_attacksLeft < 1) + { + P3_TicksUntilAttack = 30; + } + if (isGreenBall) + { + P3_TicksUntilAttack = 12; + } + } + break; + case ANIMATION_ID_P3_MELEE: + if (P3_TicksUntilAttack < 2) + { + P3_attacksLeft--; + if (tornadosActive) + { + P3_TicksUntilAttack = 5; + } + else + { + P3_TicksUntilAttack = 7; + } + if (P3_attacksLeft < 1) + { + P3_TicksUntilAttack = 24; + } + } + break; + case ANIMATION_ID_P3_WEB: + P3_attacksLeft = 4; + P3_TicksUntilAttack = 11; // + break; + case ANIMATION_ID_P3_YELLOW: + P3_attacksLeft = 14; + P3_TicksUntilAttack = 11; + break; + } + } - } + } - } + } - private void stripEntries(int style, String target, int NyloID) { - String Keep = null; - if (NyloID == 0) { - switch (style) { - case 1: - Keep = "Nylocas Ischyros"; - break; - case 2: + private void stripEntries(int style, String target, int NyloID) + { + String Keep = null; + if (NyloID == 0) + { + switch (style) + { + case 1: + Keep = "Nylocas Ischyros"; + break; + case 2: Keep = "Nylocas Toxobolos"; - break; - case 3: - Keep = "Nylocas Hagios"; - break; - } - } else { - Keep = "fuckaadamhypocrticalpos"; - switch (NyloID) { - case 8356://0=idk 1= melee 2= range 3= mage - if (style == 3) { + break; + case 3: + Keep = "Nylocas Hagios"; + break; + } + } + else + { + Keep = "fuckaadamhypocrticalpos"; + switch (NyloID) + { + case 8356://0=idk 1= melee 2= range 3= mage + if (style == 3) + { - Keep = "Nylocas Vasilias"; - } - break; - case 8357: - if (style == 2) { - Keep = "Nylocas Vasilias"; - } - break; - default: - if (style == 1) { - Keep = "Nylocas Vasilias"; - } - } + Keep = "Nylocas Vasilias"; + } + break; + case 8357: + if (style == 2) + { + Keep = "Nylocas Vasilias"; + } + break; + default: + if (style == 1) + { + Keep = "Nylocas Vasilias"; + } + } - } - int entryLength = 0; - List entryList = new ArrayList<>(); - for (MenuEntry entry : client.getMenuEntries()) { - if (Text.removeTags(entry.getTarget()).contains(Keep) && entry.getOption().equals("Attack")) { + } + int entryLength = 0; + List entryList = new ArrayList<>(); + for (MenuEntry entry : client.getMenuEntries()) + { + if (Text.removeTags(entry.getTarget()).contains(Keep) && entry.getOption().equals("Attack")) + { - entryList.add(entry); - entryLength++; - } - if (entry.getOption().equalsIgnoreCase("walk here") || entry.getOption().equalsIgnoreCase("pass") || entry.getOption().equalsIgnoreCase("take")) { - entryList.add(entry); - entryLength++; - } - } + entryList.add(entry); + entryLength++; + } + if (entry.getOption().equalsIgnoreCase("walk here") || entry.getOption().equalsIgnoreCase("pass") || entry.getOption().equalsIgnoreCase("take")) + { + entryList.add(entry); + entryLength++; + } + } - //System.out.println("i see " + entryLength + " good options using style" + style); - if (entryLength != 0) { - MenuEntry[] newEntries = new MenuEntry[entryLength]; + //System.out.println("i see " + entryLength + " good options using style" + style); + if (entryLength != 0) + { + MenuEntry[] newEntries = new MenuEntry[entryLength]; - for (int i = 0; i < (entryLength); i++) { - newEntries[i] = entryList.get(i); - } - client.setMenuEntries(newEntries); - } + for (int i = 0; i < (entryLength); i++) + { + newEntries[i] = entryList.get(i); + } + client.setMenuEntries(newEntries); + } - } + } - private int searchIndex(MenuEntry[] entries, String option, String target, boolean strict) { - for (int i = entries.length - 1; i >= 0; i--) { - MenuEntry entry = entries[i]; - String entryOption = Text.removeTags(entry.getOption()).toLowerCase(); - String entryTarget = Text.removeTags(entry.getTarget()).toLowerCase(); + private int searchIndex(MenuEntry[] entries, String option, String target, boolean strict) + { + for (int i = entries.length - 1; i >= 0; i--) + { + MenuEntry entry = entries[i]; + String entryOption = Text.removeTags(entry.getOption()).toLowerCase(); + String entryTarget = Text.removeTags(entry.getTarget()).toLowerCase(); - if (strict) { - if (entryOption.equals(option) && entryTarget.equals(target)) { - return i; - } - } else { - if (entryOption.contains(option.toLowerCase()) && entryTarget.equals(target)) { - return i; - } - } - } + if (strict) + { + if (entryOption.equals(option) && entryTarget.equals(target)) + { + return i; + } + } + else + { + if (entryOption.contains(option.toLowerCase()) && entryTarget.equals(target)) + { + return i; + } + } + } - return -1; - } + return -1; + } } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/ztob/TheatreXarpusOverlay.java b/runelite-client/src/main/java/net/runelite/client/plugins/ztob/TheatreXarpusOverlay.java index f5b0db1508..a9aad8eaf9 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/ztob/TheatreXarpusOverlay.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/ztob/TheatreXarpusOverlay.java @@ -1,69 +1,74 @@ -package net.runelite.client.plugins.ztob; - -import com.google.inject.Inject; -import java.awt.Color; -import java.awt.Dimension; -import java.awt.Graphics2D; -import static net.runelite.api.MenuAction.RUNELITE_OVERLAY_CONFIG; -import net.runelite.client.ui.overlay.Overlay; -import static net.runelite.client.ui.overlay.OverlayManager.OPTION_CONFIGURE; -import net.runelite.client.ui.overlay.OverlayMenuEntry; -import net.runelite.client.ui.overlay.OverlayPosition; -import net.runelite.client.ui.overlay.components.LineComponent; -import net.runelite.client.ui.overlay.components.PanelComponent; -import net.runelite.client.ui.overlay.components.TitleComponent; - -public class TheatreXarpusOverlay extends Overlay { - private final TheatrePlugin plugin; - private final TheatreConfig config; - PanelComponent panelComponent = new PanelComponent(); - - @Inject - private TheatreXarpusOverlay(TheatrePlugin plugin, TheatreConfig config) - { - super(plugin); - setPosition(OverlayPosition.ABOVE_CHATBOX_RIGHT); - setPosition(OverlayPosition.DYNAMIC); - setPosition(OverlayPosition.DETACHED); - this.plugin = plugin; - this.config = config; - getMenuEntries().add(new OverlayMenuEntry(RUNELITE_OVERLAY_CONFIG, OPTION_CONFIGURE, "Theatre xarpus overlay")); - - } - @Override - public Dimension render(Graphics2D graphics) { - if (plugin.isRunXarpus()) - { - if (config.XarpusExhumeOverlay()) { - if (plugin.getXarpus_NPC().getId() == 8339) { - panelComponent.getChildren().clear(); - String overlayTitle = "Exhume Counter"; - - - // Build overlay title - panelComponent.getChildren().add(TitleComponent.builder() - .text(overlayTitle) - .color(Color.GREEN) - .build()); - - //Set the size of overlay - panelComponent.setPreferredSize(new Dimension( - graphics.getFontMetrics().stringWidth(overlayTitle) + 30, 0 - )); - - panelComponent.getChildren().add(LineComponent.builder() - .left("Exhumes: ") - .right(String.valueOf(plugin.getExhumecount())) - .build()); - } - } - return panelComponent.render(graphics); - } - - return null; - - } - - -} - +package net.runelite.client.plugins.ztob; + +import com.google.inject.Inject; +import java.awt.Color; +import java.awt.Dimension; +import java.awt.Graphics2D; +import static net.runelite.api.MenuAction.RUNELITE_OVERLAY_CONFIG; +import net.runelite.client.ui.overlay.Overlay; +import static net.runelite.client.ui.overlay.OverlayManager.OPTION_CONFIGURE; +import net.runelite.client.ui.overlay.OverlayMenuEntry; +import net.runelite.client.ui.overlay.OverlayPosition; +import net.runelite.client.ui.overlay.components.LineComponent; +import net.runelite.client.ui.overlay.components.PanelComponent; +import net.runelite.client.ui.overlay.components.TitleComponent; + +public class TheatreXarpusOverlay extends Overlay +{ + private final TheatrePlugin plugin; + private final TheatreConfig config; + PanelComponent panelComponent = new PanelComponent(); + + @Inject + private TheatreXarpusOverlay(TheatrePlugin plugin, TheatreConfig config) + { + super(plugin); + setPosition(OverlayPosition.ABOVE_CHATBOX_RIGHT); + setPosition(OverlayPosition.DYNAMIC); + setPosition(OverlayPosition.DETACHED); + this.plugin = plugin; + this.config = config; + getMenuEntries().add(new OverlayMenuEntry(RUNELITE_OVERLAY_CONFIG, OPTION_CONFIGURE, "Theatre xarpus overlay")); + + } + + @Override + public Dimension render(Graphics2D graphics) + { + if (plugin.isRunXarpus()) + { + if (config.XarpusExhumeOverlay()) + { + if (plugin.getXarpus_NPC().getId() == 8339) + { + panelComponent.getChildren().clear(); + String overlayTitle = "Exhume Counter"; + + + // Build overlay title + panelComponent.getChildren().add(TitleComponent.builder() + .text(overlayTitle) + .color(Color.GREEN) + .build()); + + //Set the size of overlay + panelComponent.setPreferredSize(new Dimension( + graphics.getFontMetrics().stringWidth(overlayTitle) + 30, 0 + )); + + panelComponent.getChildren().add(LineComponent.builder() + .left("Exhumes: ") + .right(String.valueOf(plugin.getExhumecount())) + .build()); + } + } + return panelComponent.render(graphics); + } + + return null; + + } + + +} + diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/ztob/VerzikNyloOverlay.java b/runelite-client/src/main/java/net/runelite/client/plugins/ztob/VerzikNyloOverlay.java index 14294a82cf..dc3cfc9d31 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/ztob/VerzikNyloOverlay.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/ztob/VerzikNyloOverlay.java @@ -1,102 +1,104 @@ -package net.runelite.client.plugins.ztob; - -import java.awt.Color; -import java.awt.Dimension; -import java.awt.Font; -import java.awt.Graphics2D; -import javax.inject.Inject; -import net.runelite.api.Client; -import net.runelite.api.NPC; -import net.runelite.api.Point; -import net.runelite.client.ui.overlay.Overlay; -import net.runelite.client.ui.overlay.OverlayLayer; -import net.runelite.client.ui.overlay.OverlayPosition; -import net.runelite.client.ui.overlay.OverlayPriority; -import net.runelite.client.ui.overlay.OverlayUtil; - -public class VerzikNyloOverlay extends Overlay { - - private final Client client; - private final TheatrePlugin plugin; - private final TheatreConfig config; - - @Inject - private VerzikNyloOverlay(Client client, TheatrePlugin plugin, TheatreConfig config) { - this.client = client; - this.plugin = plugin; - this.config = config; - setPosition(OverlayPosition.DYNAMIC); - setPriority(OverlayPriority.HIGH); - setLayer(OverlayLayer.ABOVE_SCENE); - } - - public Dimension render(Graphics2D graphics) - { - - if (plugin.isRunVerzik()) - { - if (config.NyloTargetOverlay()) - { - if (plugin.getCrabList().size() > 0) - { - - for (NPC npc : plugin.getCrabList()) - { - if (npc.isDead()) - { - continue; - } - String renderText = ""; - if (npc.getInteracting() != null) - { - - renderText = npc.getInteracting().getName(); - Point point = npc.getCanvasTextLocation(graphics, npc.getInteracting().getName(), 0); - - - if (npc.getInteracting().getName().toLowerCase().equals(client.getLocalPlayer().getName().toLowerCase())) - { - point = npc.getCanvasTextLocation(graphics, client.getLocalPlayer().getName(), 0); - renderText = "YOU NIGGA RUN!"; - - } - else if (npc.getInteracting().getName().toLowerCase().equals("afyy")) - { - point = npc.getCanvasTextLocation(graphics, "Ricecup", 0); - renderText = "Ricecup"; - } - if (renderText.equals("YOU NIGGA RUN!")) - { - renderTextLocation(graphics, renderText, 12, Font.BOLD, Color.RED, point); - } - else - { - renderTextLocation(graphics, renderText, 12, Font.BOLD, Color.GREEN, point); - } - } - - } - } - - } - } - - return null; - } - - private void renderTextLocation(Graphics2D graphics, String txtString, int fontSize, int fontStyle, Color fontColor, Point canvasPoint) - { - graphics.setFont(new Font("Arial", fontStyle, fontSize)); - if (canvasPoint != null) - { - final Point canvasCenterPoint = new Point( - canvasPoint.getX(), - canvasPoint.getY()); - final Point canvasCenterPoint_shadow = new Point( - canvasPoint.getX() + 1, - canvasPoint.getY() + 1); - OverlayUtil.renderTextLocation(graphics, canvasCenterPoint_shadow, txtString, Color.BLACK); - OverlayUtil.renderTextLocation(graphics, canvasCenterPoint, txtString, fontColor); - } - } -} +package net.runelite.client.plugins.ztob; + +import java.awt.Color; +import java.awt.Dimension; +import java.awt.Font; +import java.awt.Graphics2D; +import javax.inject.Inject; +import net.runelite.api.Client; +import net.runelite.api.NPC; +import net.runelite.api.Point; +import net.runelite.client.ui.overlay.Overlay; +import net.runelite.client.ui.overlay.OverlayLayer; +import net.runelite.client.ui.overlay.OverlayPosition; +import net.runelite.client.ui.overlay.OverlayPriority; +import net.runelite.client.ui.overlay.OverlayUtil; + +public class VerzikNyloOverlay extends Overlay +{ + + private final Client client; + private final TheatrePlugin plugin; + private final TheatreConfig config; + + @Inject + private VerzikNyloOverlay(Client client, TheatrePlugin plugin, TheatreConfig config) + { + this.client = client; + this.plugin = plugin; + this.config = config; + setPosition(OverlayPosition.DYNAMIC); + setPriority(OverlayPriority.HIGH); + setLayer(OverlayLayer.ABOVE_SCENE); + } + + public Dimension render(Graphics2D graphics) + { + + if (plugin.isRunVerzik()) + { + if (config.NyloTargetOverlay()) + { + if (plugin.getCrabList().size() > 0) + { + + for (NPC npc : plugin.getCrabList()) + { + if (npc.isDead()) + { + continue; + } + String renderText = ""; + if (npc.getInteracting() != null) + { + + renderText = npc.getInteracting().getName(); + Point point = npc.getCanvasTextLocation(graphics, npc.getInteracting().getName(), 0); + + + if (npc.getInteracting().getName().toLowerCase().equals(client.getLocalPlayer().getName().toLowerCase())) + { + point = npc.getCanvasTextLocation(graphics, client.getLocalPlayer().getName(), 0); + renderText = "YOU NIGGA RUN!"; + + } + else if (npc.getInteracting().getName().toLowerCase().equals("afyy")) + { + point = npc.getCanvasTextLocation(graphics, "Ricecup", 0); + renderText = "Ricecup"; + } + if (renderText.equals("YOU NIGGA RUN!")) + { + renderTextLocation(graphics, renderText, 12, Font.BOLD, Color.RED, point); + } + else + { + renderTextLocation(graphics, renderText, 12, Font.BOLD, Color.GREEN, point); + } + } + + } + } + + } + } + + return null; + } + + private void renderTextLocation(Graphics2D graphics, String txtString, int fontSize, int fontStyle, Color fontColor, Point canvasPoint) + { + graphics.setFont(new Font("Arial", fontStyle, fontSize)); + if (canvasPoint != null) + { + final Point canvasCenterPoint = new Point( + canvasPoint.getX(), + canvasPoint.getY()); + final Point canvasCenterPoint_shadow = new Point( + canvasPoint.getX() + 1, + canvasPoint.getY() + 1); + OverlayUtil.renderTextLocation(graphics, canvasCenterPoint_shadow, txtString, Color.BLACK); + OverlayUtil.renderTextLocation(graphics, canvasCenterPoint, txtString, fontColor); + } + } +}