diff --git a/runelite-api/src/main/java/net/runelite/api/Perspective.java b/runelite-api/src/main/java/net/runelite/api/Perspective.java index bc1b52270f..36a05a2283 100644 --- a/runelite-api/src/main/java/net/runelite/api/Perspective.java +++ b/runelite-api/src/main/java/net/runelite/api/Perspective.java @@ -244,13 +244,41 @@ public class Perspective */ public static Polygon getCanvasTilePoly(Client client, Point localLocation) { - int plane = client.getPlane(); - int halfTile = Perspective.LOCAL_TILE_SIZE / 2; + return getCanvasTileAreaPoly(client, localLocation, 1); + } - Point p1 = Perspective.worldToCanvas(client, localLocation.getX() - halfTile, localLocation.getY() - halfTile, plane); - Point p2 = Perspective.worldToCanvas(client, localLocation.getX() - halfTile, localLocation.getY() + halfTile, plane); - Point p3 = Perspective.worldToCanvas(client, localLocation.getX() + halfTile, localLocation.getY() + halfTile, plane); - Point p4 = Perspective.worldToCanvas(client, localLocation.getX() + halfTile, localLocation.getY() - halfTile, plane); + /** + * Returns a polygon representing an area. + * + * @param client + * @param localLocation Center location of the AoE + * @param size size of the area. Ex. Lizardman Shaman AoE is a 3x3, so + * size = 3 + * @return a polygon representing the tiles in the area + */ + public static Polygon getCanvasTileAreaPoly(Client client, Point localLocation, int size) + { + int plane = client.getPlane(); + int halfTile = LOCAL_TILE_SIZE / 2; + + // If the size is 5, we need to shift it up and left 2 units, then expand by 5 units to make a 5x5 + int aoeSize = size / 2; + + // Shift over one half tile as localLocation is the center point of the tile, and then shift the area size + Point topLeft = new Point(localLocation.getX() - (aoeSize * LOCAL_TILE_SIZE) - halfTile, + localLocation.getY() - (aoeSize * LOCAL_TILE_SIZE) - halfTile); + // expand by size + Point bottomRight = new Point(topLeft.getX() + size * LOCAL_TILE_SIZE, + topLeft.getY() + size * LOCAL_TILE_SIZE); + // Take the x of top left and the y of bottom right to create bottom left + Point bottomLeft = new Point(topLeft.getX(), bottomRight.getY()); + // Similarly for top right + Point topRight = new Point(bottomRight.getX(), topLeft.getY()); + + Point p1 = worldToCanvas(client, topLeft.getX(), topLeft.getY(), plane); + Point p2 = worldToCanvas(client, topRight.getX(), topRight.getY(), plane); + Point p3 = worldToCanvas(client, bottomRight.getX(), bottomRight.getY(), plane); + Point p4 = worldToCanvas(client, bottomLeft.getX(), bottomLeft.getY(), plane); if (p1 == null || p2 == null || p3 == null || p4 == null) { diff --git a/runelite-api/src/main/java/net/runelite/api/ProjectileID.java b/runelite-api/src/main/java/net/runelite/api/ProjectileID.java new file mode 100644 index 0000000000..994a551ffc --- /dev/null +++ b/runelite-api/src/main/java/net/runelite/api/ProjectileID.java @@ -0,0 +1,35 @@ +/* + * 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.api; + +public class ProjectileID +{ + public static final int LIZARDMAN_SHAMAN_AOE = 1293; + public static final int ICE_DEMON_RANGED_AOE = 1324; + public static final int ICE_DEMON_ICE_BARRAGE_AOE = 366; + public static final int VASA_AWAKEN_AOE = 1327; + public static final int VASA_RANGED_AOE = 1329; + public static final int TEKTON_METEOR_AOE = 660; +} diff --git a/runelite-client/src/main/java/net/runelite/client/callback/Hooks.java b/runelite-client/src/main/java/net/runelite/client/callback/Hooks.java index e3d0606ee4..314fdfbcc6 100644 --- a/runelite-client/src/main/java/net/runelite/client/callback/Hooks.java +++ b/runelite-client/src/main/java/net/runelite/client/callback/Hooks.java @@ -34,6 +34,8 @@ import net.runelite.api.MainBufferProvider; import net.runelite.api.MenuAction; import net.runelite.api.MessageNode; import net.runelite.api.PacketBuffer; +import net.runelite.api.Point; +import net.runelite.api.Projectile; import net.runelite.api.Skill; import net.runelite.client.RuneLite; import net.runelite.client.events.*; @@ -186,7 +188,7 @@ public class Hooks public static void menuActionHook(int var0, int widgetId, int menuAction, int id, String menuOption, String menuTarget, int var6, int var7) { /* Along the way, the RuneScape client may change a menuAction by incrementing it with 2000. - * I have no idea why, but it does. Their code contains the same conditional statement. + * I have no idea why, but it does. Their code contains the same conditional statement. */ if (menuAction >= 2000) { @@ -231,6 +233,27 @@ public class Hooks eventBus.post(chatMessage); } + /** + * Called when a projectile is set to move towards a point. For + * projectiles that target the ground, like AoE projectiles from + * Lizardman Shamans, this is only called once + * + * @param projectile The projectile being moved + * @param targetX X position of where the projectile is being moved to + * @param targetY Y position of where the projectile is being moved to + * @param targetZ Z position of where the projectile is being moved to + * @param cycle + */ + public static void projectileMoved(Projectile projectile, int targetX, int targetY, int targetZ, int cycle) + { + Point position = new Point(targetX, targetY); + ProjectileMoved projectileMoved = new ProjectileMoved(); + projectileMoved.setProjectile(projectile); + projectileMoved.setPosition(position); + projectileMoved.setPlane(targetZ); + eventBus.post(projectileMoved); + } + public static void setMessage(MessageNode messageNode, int type, String name, String sender, String value) { // Hook is fired prior to actually setting these on the MessageNode, so send them diff --git a/runelite-client/src/main/java/net/runelite/client/events/ProjectileMoved.java b/runelite-client/src/main/java/net/runelite/client/events/ProjectileMoved.java new file mode 100644 index 0000000000..c38ee996d1 --- /dev/null +++ b/runelite-client/src/main/java/net/runelite/client/events/ProjectileMoved.java @@ -0,0 +1,65 @@ +/* + * 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.events; + +import net.runelite.api.Point; +import net.runelite.api.Projectile; + +public class ProjectileMoved +{ + private Projectile projectile; + private Point position; + private int plane; + + public Projectile getProjectile() + { + return projectile; + } + + public void setProjectile(Projectile projectile) + { + this.projectile = projectile; + } + + public Point getPosition() + { + return position; + } + + public void setPosition(Point position) + { + this.position = position; + } + + public int getPlane() + { + return plane; + } + + public void setPlane(int plane) + { + this.plane = plane; + } +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/aoewarnings/AoeProjectile.java b/runelite-client/src/main/java/net/runelite/client/plugins/aoewarnings/AoeProjectile.java new file mode 100644 index 0000000000..c65d2b6b42 --- /dev/null +++ b/runelite-client/src/main/java/net/runelite/client/plugins/aoewarnings/AoeProjectile.java @@ -0,0 +1,57 @@ +/* + * 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.aoewarnings; + +import java.time.Instant; +import net.runelite.api.Point; + +public class AoeProjectile +{ + private final Instant startTime; + private final Point targetPoint; + private final AoeProjectileInfo aoeProjectileInfo; + + public AoeProjectile(Instant startTime, Point targetPoint, AoeProjectileInfo aoeProjectileInfo) + { + this.startTime = startTime; + this.targetPoint = targetPoint; + this.aoeProjectileInfo = aoeProjectileInfo; + } + + public Instant getStartTime() + { + return startTime; + } + + public Point getTargetPoint() + { + return targetPoint; + } + + public AoeProjectileInfo getAoeProjectileInfo() + { + return aoeProjectileInfo; + } +} 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 new file mode 100644 index 0000000000..1fce1189f5 --- /dev/null +++ b/runelite-client/src/main/java/net/runelite/client/plugins/aoewarnings/AoeProjectileInfo.java @@ -0,0 +1,96 @@ +/* + * 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.aoewarnings; + +import java.time.Duration; +import net.runelite.api.ProjectileID; + +public enum AoeProjectileInfo +{ + LIZARDMAN_SHAMAN_AOE(ProjectileID.LIZARDMAN_SHAMAN_AOE, 3000, 3), + ICE_DEMON_RANGED_AOE(ProjectileID.ICE_DEMON_RANGED_AOE, 3000, 3), + /** + * When you don't have pray range on ice demon does an ice barrage + */ + ICE_DEMON_ICE_BARRAGE_AOE(ProjectileID.ICE_DEMON_ICE_BARRAGE_AOE, 3000, 3), + /** + * The AOE when vasa first starts + */ + VASA_AWAKEN_AOE(ProjectileID.VASA_AWAKEN_AOE, 4500, 3), + VASA_RANGED_AOE(ProjectileID.VASA_RANGED_AOE, 3000, 3), + TEKTON_METEOR_AOE(ProjectileID.TEKTON_METEOR_AOE, 4000, 3); + + /** + * The id of the projectile to trigger this AoE warning + */ + private final int id; + + /** + * How long the indicator should last for this AoE warning This might + * need to be a bit longer than the projectile actually takes to land as + * there is a fade effect on the warning + */ + private final Duration lifeTime; + + /** + * The size of the splash radius of the AoE warning Ex. Lizardman shaman + * AoE is a 3x3, so aoeSize = 3 + */ + private final int aoeSize; + + AoeProjectileInfo(int id, int lifeTimeMillis, int aoeSize) + { + this.id = id; + this.lifeTime = Duration.ofMillis(lifeTimeMillis); + this.aoeSize = aoeSize; + } + + public Duration getLifeTime() + { + return lifeTime; + } + + public int getId() + { + return id; + } + + public int getAoeSize() + { + return aoeSize; + } + + public static AoeProjectileInfo getById(int id) + { + for (AoeProjectileInfo aoeProjectileInfo : values()) + { + if (id == aoeProjectileInfo.getId()) + { + return aoeProjectileInfo; + } + } + return null; + } +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/aoewarnings/AoeWarningConfig.java b/runelite-client/src/main/java/net/runelite/client/plugins/aoewarnings/AoeWarningConfig.java new file mode 100644 index 0000000000..33a84b9d34 --- /dev/null +++ b/runelite-client/src/main/java/net/runelite/client/plugins/aoewarnings/AoeWarningConfig.java @@ -0,0 +1,97 @@ +/* + * 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.aoewarnings; + +import net.runelite.client.config.Config; +import net.runelite.client.config.ConfigGroup; +import net.runelite.client.config.ConfigItem; + +@ConfigGroup( + keyName = "aoewarning", + name = "AoE Projectile Warnings", + description = "Configuration for the AoE Projectile Warnings plugin" +) +public interface AoeWarningConfig extends Config +{ + @ConfigItem( + keyName = "enabled", + name = "AoE Warnings Enabled", + description = "Configures whether or not AoE Projectile Warnings plugin is displayed" + ) + default boolean enabled() + { + return true; + } + + @ConfigItem( + keyName = "lizardmanaoe", + name = "Lizardman Shamans", + description = "Configures whether or not AoE Projectile Warnings for Lizardman Shamans is displayed" + ) + default boolean isShamansEnabled() + { + return true; + } + + @ConfigItem( + keyName = "icedemon", + name = "Ice Demon", + description = "Configures whether or not AoE Projectile Warnings for Ice Demon is displayed" + ) + default boolean isIceDemonEnabled() + { + return true; + } + + @ConfigItem( + keyName = "vasa", + name = "Vasa", + description = "Configures whether or not AoE Projectile Warnings for Vasa is displayed" + ) + default boolean isVasaEnabled() + { + return true; + } + + @ConfigItem( + keyName = "tekton", + name = "Tekton", + description = "Configures whether or not AoE Projectile Warnings for Tekton is displayed" + ) + default boolean isTektonEnabled() + { + return true; + } + + @ConfigItem( + keyName = "outline", + name = "Display Outline", + description = "Configures whether or not AoE Projectile Warnings have an outline" + ) + default boolean isOutlineEnabled() + { + return true; + } +} 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 new file mode 100644 index 0000000000..608579380e --- /dev/null +++ b/runelite-client/src/main/java/net/runelite/client/plugins/aoewarnings/AoeWarningOverlay.java @@ -0,0 +1,122 @@ +/* + * 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.aoewarnings; + +import java.awt.Color; +import java.awt.Dimension; +import java.awt.Graphics2D; +import java.awt.Polygon; +import java.time.Instant; +import java.util.Iterator; +import java.util.Map; +import javax.annotation.Nullable; +import javax.inject.Inject; +import net.runelite.api.Client; +import net.runelite.api.GameState; +import net.runelite.api.Perspective; +import net.runelite.api.Projectile; +import net.runelite.client.ui.overlay.Overlay; +import net.runelite.client.ui.overlay.OverlayPosition; + +public class AoeWarningOverlay extends Overlay +{ + private static final int FILL_START_ALPHA = 25; + private static final int OUTLINE_START_ALPHA = 255; + + private final Client client; + private final AoeWarningPlugin plugin; + private final AoeWarningConfig config; + + @Inject + public AoeWarningOverlay(@Nullable Client client, AoeWarningPlugin plugin, AoeWarningConfig config) + { + super(OverlayPosition.DYNAMIC); + this.client = client; + this.plugin = plugin; + this.config = config; + } + + @Override + public Dimension render(Graphics2D graphics) + { + if (client.getGameState() != GameState.LOGGED_IN || !config.enabled()) + { + return null; + } + + Instant now = Instant.now(); + Map projectiles = plugin.getProjectiles(); + for (Iterator it = projectiles.values().iterator(); it.hasNext();) + { + AoeProjectile aoeProjectile = it.next(); + + if (now.isAfter(aoeProjectile.getStartTime().plus(aoeProjectile.getAoeProjectileInfo().getLifeTime()))) + { + it.remove(); + continue; + } + + Polygon tilePoly = Perspective.getCanvasTileAreaPoly(client, aoeProjectile.getTargetPoint(), aoeProjectile.getAoeProjectileInfo().getAoeSize()); + if (tilePoly == null) + { + continue; + } + + // how far through the projectiles lifetime between 0-1. + double progress = (System.currentTimeMillis() - aoeProjectile.getStartTime().toEpochMilli()) / (double) aoeProjectile.getAoeProjectileInfo().getLifeTime().toMillis(); + + int fillAlpha = (int) ((1 - progress) * FILL_START_ALPHA);//alpha drop off over lifetime + int outlineAlpha = (int) ((1 - progress) * OUTLINE_START_ALPHA); + + if (fillAlpha < 0) + { + fillAlpha = 0; + } + if (outlineAlpha < 0) + { + outlineAlpha = 0; + } + + if (fillAlpha > 255) + { + fillAlpha = 255; + } + if (outlineAlpha > 255) + { + outlineAlpha = 255;//Make sure we don't pass in an invalid alpha + } + + if (config.isOutlineEnabled()) + { + graphics.setColor(new Color(255, 0, 0, outlineAlpha)); + graphics.drawPolygon(tilePoly); + } + + graphics.setColor(new Color(255, 0, 0, fillAlpha)); + graphics.fillPolygon(tilePoly); + } + return null; + } +} 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 new file mode 100644 index 0000000000..9fb76481a8 --- /dev/null +++ b/runelite-client/src/main/java/net/runelite/client/plugins/aoewarnings/AoeWarningPlugin.java @@ -0,0 +1,130 @@ +/* + * 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.aoewarnings; + +import com.google.common.eventbus.Subscribe; +import com.google.inject.Binder; +import com.google.inject.Provides; +import java.time.Instant; +import java.util.HashMap; +import java.util.Map; +import javax.inject.Inject; +import net.runelite.api.Point; +import net.runelite.api.Projectile; +import net.runelite.client.config.ConfigManager; +import net.runelite.client.events.ProjectileMoved; +import net.runelite.client.plugins.Plugin; +import net.runelite.client.plugins.PluginDescriptor; +import net.runelite.client.ui.overlay.Overlay; + +@PluginDescriptor( + name = "AoE projectile warning plugin" +) +public class AoeWarningPlugin extends Plugin +{ + @Inject + AoeWarningOverlay overlay; + + @Inject + AoeWarningConfig config; + + private final Map projectiles = new HashMap<>(); + + @Override + public void configure(Binder binder) + { + binder.bind(AoeWarningOverlay.class); + } + + @Provides + AoeWarningConfig getConfig(ConfigManager configManager) + { + return configManager.getConfig(AoeWarningConfig.class); + } + + @Override + public Overlay getOverlay() + { + return overlay; + } + + public Map getProjectiles() + { + return projectiles; + } + + /** + * Called when a projectile is set to move towards a point. For + * projectiles that target the ground, like AoE projectiles from + * Lizardman Shamans, this is only called once + * + * @param event Projectile moved event + */ + @Subscribe + public void onProjectileMoved(ProjectileMoved event) + { + Projectile projectile = event.getProjectile(); + + // AoE projectiles do not target anything + if (projectile.getInteracting() != null) + { + return; + } + + int projectileId = projectile.getId(); + AoeProjectileInfo aoeProjectileInfo = AoeProjectileInfo.getById(projectileId); + if (aoeProjectileInfo != null && isConfigEnabledForProjectileId(projectileId)) + { + Point targetPoint = event.getPosition(); + AoeProjectile aoeProjectile = new AoeProjectile(Instant.now(), targetPoint, aoeProjectileInfo); + projectiles.put(projectile, aoeProjectile); + } + } + + private boolean isConfigEnabledForProjectileId(int projectileId) + { + AoeProjectileInfo projectileInfo = AoeProjectileInfo.getById(projectileId); + if (projectileInfo == null) + { + return false; + } + + switch (projectileInfo) + { + case LIZARDMAN_SHAMAN_AOE: + return config.isShamansEnabled(); + case ICE_DEMON_RANGED_AOE: + case ICE_DEMON_ICE_BARRAGE_AOE: + return config.isIceDemonEnabled(); + case VASA_AWAKEN_AOE: + case VASA_RANGED_AOE: + return config.isVasaEnabled(); + case TEKTON_METEOR_AOE: + return config.isTektonEnabled(); + } + + return false; + } +}