From cee98c8da1ba8e3dd62fccdfce1e9b951a7da564 Mon Sep 17 00:00:00 2001 From: Seth Date: Sun, 14 Jan 2018 18:57:17 -0600 Subject: [PATCH] Add Cannon plugin Shows a count of cannonballs atop the cannon --- .../java/net/runelite/api/AnimationID.java | 1 + .../java/net/runelite/api/ProjectileID.java | 2 + .../client/plugins/cannon/CannonConfig.java | 57 ++++++ .../client/plugins/cannon/CannonOverlay.java | 97 ++++++++++ .../client/plugins/cannon/CannonPlugin.java | 182 ++++++++++++++++++ 5 files changed, 339 insertions(+) create mode 100644 runelite-client/src/main/java/net/runelite/client/plugins/cannon/CannonConfig.java create mode 100644 runelite-client/src/main/java/net/runelite/client/plugins/cannon/CannonOverlay.java create mode 100644 runelite-client/src/main/java/net/runelite/client/plugins/cannon/CannonPlugin.java diff --git a/runelite-api/src/main/java/net/runelite/api/AnimationID.java b/runelite-api/src/main/java/net/runelite/api/AnimationID.java index ec3feb24bf..7b6a24e35c 100644 --- a/runelite-api/src/main/java/net/runelite/api/AnimationID.java +++ b/runelite-api/src/main/java/net/runelite/api/AnimationID.java @@ -102,6 +102,7 @@ public final class AnimationID public static final int MINING_MOTHERLODE_INFERNAL = 4481; public static final int HERBLORE_POTIONMAKING = 363; //used for both herb and secondary public static final int MAGIC_CHARGING_ORBS = 726; + public static final int BURYING_BONES = 827; // NPC animations public static final int TZTOK_JAD_MAGIC_ATTACK = 2656; diff --git a/runelite-api/src/main/java/net/runelite/api/ProjectileID.java b/runelite-api/src/main/java/net/runelite/api/ProjectileID.java index c0d29ab835..0e5c8060f6 100644 --- a/runelite-api/src/main/java/net/runelite/api/ProjectileID.java +++ b/runelite-api/src/main/java/net/runelite/api/ProjectileID.java @@ -26,6 +26,8 @@ package net.runelite.api; public class ProjectileID { + public static final int CANNONBALL = 53; + public static final int LIZARDMAN_SHAMAN_AOE = 1293; public static final int CRAZY_ARCHAEOLOGIST_AOE = 1260; public static final int ICE_DEMON_RANGED_AOE = 1324; diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/cannon/CannonConfig.java b/runelite-client/src/main/java/net/runelite/client/plugins/cannon/CannonConfig.java new file mode 100644 index 0000000000..e067e553fd --- /dev/null +++ b/runelite-client/src/main/java/net/runelite/client/plugins/cannon/CannonConfig.java @@ -0,0 +1,57 @@ +/* + * 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 net.runelite.client.config.Config; +import net.runelite.client.config.ConfigGroup; +import net.runelite.client.config.ConfigItem; + +@ConfigGroup( + keyName = "cannon", + name = "Cannon Plugin", + description = "Configuration for the Cannon plugin" +) +public interface CannonConfig extends Config +{ + @ConfigItem( + keyName = "enabled", + name = "Enabled", + description = "Configures whether or not the Cannon plugin is displayed" + ) + default boolean enabled() + { + return true; + } + + @ConfigItem( + keyName = "showEmptyCannonNotification", + name = "Empty cannon notification", + description = "Configures whether to notify you that the cannon is empty" + ) + default boolean showEmptyCannonNotification() + { + return true; + } +} 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 new file mode 100644 index 0000000000..d05d1245a2 --- /dev/null +++ b/runelite-client/src/main/java/net/runelite/client/plugins/cannon/CannonOverlay.java @@ -0,0 +1,97 @@ +/* + * 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 static java.awt.Color.GREEN; +import static java.awt.Color.ORANGE; +import static java.awt.Color.RED; +import java.awt.Dimension; +import java.awt.Graphics2D; +import java.awt.Point; +import javax.inject.Inject; +import net.runelite.api.Client; +import net.runelite.api.Perspective; +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; +import net.runelite.client.ui.overlay.components.TextComponent; + +class CannonOverlay extends Overlay +{ + 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); + setLayer(OverlayLayer.UNDER_WIDGETS); + this.client = client; + this.config = config; + this.plugin = plugin; + } + + @Override + public Dimension render(Graphics2D graphics, Point parent) + { + if (!plugin.cannonPlaced || plugin.myCannon == null || !config.enabled()) + { + return null; + } + + net.runelite.api.Point cannonLoc = Perspective.getCanvasTextLocation(client, + graphics, + Perspective.worldToLocal(client, plugin.myCannon), + String.valueOf(plugin.cballsLeft), 200); + + Widget viewport = client.getViewportWidget(); + + if (viewport != null && cannonLoc != null && viewport.contains(cannonLoc)) + { + textComponent.setText(String.valueOf(plugin.cballsLeft)); + textComponent.setPosition(new Point(cannonLoc.getX(), cannonLoc.getY())); + + if (plugin.cballsLeft > 15) + { + textComponent.setColor(GREEN);; + } + else if (plugin.cballsLeft > 5) + { + textComponent.setColor(ORANGE); + } + else + { + textComponent.setColor(RED); + } + + textComponent.render(graphics, parent); + } + + return null; + } +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/cannon/CannonPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/cannon/CannonPlugin.java new file mode 100644 index 0000000000..018cfeddb4 --- /dev/null +++ b/runelite-client/src/main/java/net/runelite/client/plugins/cannon/CannonPlugin.java @@ -0,0 +1,182 @@ +/* + * 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 com.google.common.eventbus.Subscribe; +import com.google.inject.Binder; +import com.google.inject.Provides; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import javax.inject.Inject; +import net.runelite.api.AnimationID; +import net.runelite.api.ChatMessageType; +import net.runelite.api.Client; +import net.runelite.api.GameObject; +import static net.runelite.api.ObjectID.CANNON_BASE; +import net.runelite.api.Perspective; +import net.runelite.api.Player; +import net.runelite.api.Projectile; +import static net.runelite.api.ProjectileID.CANNONBALL; +import net.runelite.api.events.ChatMessage; +import net.runelite.api.events.GameObjectsChanged; +import net.runelite.api.events.ProjectileMoved; +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.ui.overlay.Overlay; + +@PluginDescriptor( + name = "Cannon plugin" +) +public class CannonPlugin extends Plugin +{ + private static final Pattern LOAD_CANNON_PATTERN = Pattern.compile("([0-9]+)"); + private static final int MAX_CBALLS = 30; + + int cballsLeft = 0; + + boolean cannonPlaced = false; + + net.runelite.api.Point myCannon; + + @Inject + Notifier notifier; + + @Inject + CannonOverlay cannonOverlay; + + @Inject + CannonConfig config; + + @Inject + private Client client; + + @Override + public void configure(Binder binder) + { + binder.bind(CannonOverlay.class); + } + + @Provides + CannonConfig provideConfig(ConfigManager configManager) + { + return configManager.getConfig(CannonConfig.class); + } + + @Override + public Overlay getOverlay() + { + return cannonOverlay; + } + + @Subscribe + public void onGameObjectsChanged(GameObjectsChanged event) + { + GameObject gameObject = event.getGameObject(); + + Player localPlayer = client.getLocalPlayer(); + if (gameObject.getId() == CANNON_BASE && !cannonPlaced) + { + if (localPlayer.getWorldLocation().distanceTo(gameObject.getWorldLocation()) <= 2 + && localPlayer.getAnimation() == AnimationID.BURYING_BONES) + { + myCannon = gameObject.getWorldLocation(); + } + } + } + + @Subscribe + public void onProjectileMoved(ProjectileMoved event) + { + Projectile projectile = event.getProjectile(); + + if (projectile.getId() == CANNONBALL && myCannon != null) + { + net.runelite.api.Point projectileLoc = Perspective.localToWorld(client, new net.runelite.api.Point(projectile.getX1(), projectile.getY1())); + + //Check to see if projectile x,y is 0 else it will continuously decrease while ball is flying. + if (projectileLoc.equals(myCannon) && projectile.getX() == 0 && projectile.getY() == 0) + { + cballsLeft--; + } + } + } + + @Subscribe + public void onChatMessage(ChatMessage event) + { + if (event.getType() != ChatMessageType.FILTERED && event.getType() != ChatMessageType.SERVER) + { + return; + } + + if (event.getMessage().equals("You add the furnace.")) + { + cannonPlaced = true; + cballsLeft = 0; + } + + if (event.getMessage().contains("You pick up the cannon")) + { + cannonPlaced = false; + cballsLeft = 0; + } + + if (event.getMessage().startsWith("You load the cannon with")) + { + Matcher m = LOAD_CANNON_PATTERN.matcher(event.getMessage()); + if (m.find()) + { + int amt = Integer.valueOf(m.group()); + + // make sure cballs doesn't go above MAX_CBALLS + if (amt + cballsLeft > MAX_CBALLS) + { + cballsLeft = MAX_CBALLS; + } + else + { + cballsLeft += amt; + } + } + } + + if (event.getMessage().equals("You load the cannon with one cannonball.")) + { + cballsLeft++; + } + + if (event.getMessage().contains("Your cannon is out of ammo!")) + { + cballsLeft = 0; + + if (config.showEmptyCannonNotification()) + { + notifier.notify("Your cannon is out of ammo!"); + } + } + } +}