diff --git a/cache/src/main/java/net/runelite/cache/item/SpritePixels.java b/cache/src/main/java/net/runelite/cache/item/SpritePixels.java index ed8be85a18..a1b3c026b9 100644 --- a/cache/src/main/java/net/runelite/cache/item/SpritePixels.java +++ b/cache/src/main/java/net/runelite/cache/item/SpritePixels.java @@ -108,7 +108,7 @@ class Sprite } - public void drawAtOn(Rasterizer2D graphics, int x, int y) + public void drawAtOn(Rasterizer2D graphics, int x, int y) { x += this.offsetX; y += this.offsetY; diff --git a/cache/src/test/java/net/runelite/cache/AreaDumper.java b/cache/src/test/java/net/runelite/cache/AreaDumper.java index b789d78a0d..0b276fcce1 100644 --- a/cache/src/test/java/net/runelite/cache/AreaDumper.java +++ b/cache/src/test/java/net/runelite/cache/AreaDumper.java @@ -64,7 +64,7 @@ public class AreaDumper for (AreaDefinition area : areaManager.getAreas()) { - Files.write(gson.toJson(area), new File(outDir, area.id + ".json"), Charset.defaultCharset()); + Files.asCharSink(new File(outDir, area.id + ".json"), Charset.defaultCharset()).write(gson.toJson(area)); ++count; } } diff --git a/cache/src/test/java/net/runelite/cache/EnumDumperTest.java b/cache/src/test/java/net/runelite/cache/EnumDumperTest.java index a094b9fc24..705356b0b5 100644 --- a/cache/src/test/java/net/runelite/cache/EnumDumperTest.java +++ b/cache/src/test/java/net/runelite/cache/EnumDumperTest.java @@ -80,7 +80,7 @@ public class EnumDumperTest if (def != null) { - Files.write(gson.toJson(def), new File(dumpDir, file.getFileId() + ".json"), Charset.defaultCharset()); + Files.asCharSink(new File(dumpDir, file.getFileId() + ".json"), Charset.defaultCharset()).write(gson.toJson(def)); ++count; } } diff --git a/cache/src/test/java/net/runelite/cache/FrameDumper.java b/cache/src/test/java/net/runelite/cache/FrameDumper.java index 2bd7e2ca17..8e856cd2f8 100644 --- a/cache/src/test/java/net/runelite/cache/FrameDumper.java +++ b/cache/src/test/java/net/runelite/cache/FrameDumper.java @@ -101,7 +101,7 @@ public class FrameDumper frames.add(frame); } - Files.write(gson.toJson(frames), new File(outDir, archive.getArchiveId() + ".json"), Charset.defaultCharset()); + Files.asCharSink(new File(outDir, archive.getArchiveId() + ".json"), Charset.defaultCharset()).write(gson.toJson(frames)); ++count; } } diff --git a/cache/src/test/java/net/runelite/cache/FramemapDumper.java b/cache/src/test/java/net/runelite/cache/FramemapDumper.java index 4513bf3dfb..f95e92c9fa 100644 --- a/cache/src/test/java/net/runelite/cache/FramemapDumper.java +++ b/cache/src/test/java/net/runelite/cache/FramemapDumper.java @@ -74,7 +74,7 @@ public class FramemapDumper FramemapLoader loader = new FramemapLoader(); FramemapDefinition framemap = loader.load(0, contents); - Files.write(gson.toJson(framemap), new File(outDir, archive.getArchiveId() + ".json"), Charset.defaultCharset()); + Files.asCharSink(new File(outDir, archive.getArchiveId() + ".json"), Charset.defaultCharset()).write(gson.toJson(framemap)); ++count; } } diff --git a/cache/src/test/java/net/runelite/cache/InventoryDumper.java b/cache/src/test/java/net/runelite/cache/InventoryDumper.java index 4caf464141..f74c4ce188 100644 --- a/cache/src/test/java/net/runelite/cache/InventoryDumper.java +++ b/cache/src/test/java/net/runelite/cache/InventoryDumper.java @@ -77,7 +77,7 @@ public class InventoryDumper InventoryLoader loader = new InventoryLoader(); InventoryDefinition inv = loader.load(file.getFileId(), file.getContents()); - Files.write(gson.toJson(inv), new File(outDir, inv.id + ".json"), Charset.defaultCharset()); + Files.asCharSink(new File(outDir, inv.id + ".json"), Charset.defaultCharset()).write(gson.toJson(inv)); ++count; } } diff --git a/cache/src/test/java/net/runelite/cache/KitDumperTest.java b/cache/src/test/java/net/runelite/cache/KitDumperTest.java index 286ca6ea8e..4db1267506 100644 --- a/cache/src/test/java/net/runelite/cache/KitDumperTest.java +++ b/cache/src/test/java/net/runelite/cache/KitDumperTest.java @@ -78,7 +78,7 @@ public class KitDumperTest KitDefinition def = loader.load(file.getFileId(), b); - Files.write(gson.toJson(def), new File(dumpDir, file.getFileId() + ".json"), Charset.defaultCharset()); + Files.asCharSink(new File(dumpDir, file.getFileId() + ".json"), Charset.defaultCharset()).write(gson.toJson(def)); ++count; } } diff --git a/cache/src/test/java/net/runelite/cache/OverlayDumper.java b/cache/src/test/java/net/runelite/cache/OverlayDumper.java index 4ac4b53a7c..51457192b7 100644 --- a/cache/src/test/java/net/runelite/cache/OverlayDumper.java +++ b/cache/src/test/java/net/runelite/cache/OverlayDumper.java @@ -77,7 +77,7 @@ public class OverlayDumper OverlayLoader loader = new OverlayLoader(); OverlayDefinition overlay = loader.load(file.getFileId(), file.getContents()); - Files.write(gson.toJson(overlay), new File(outDir, file.getFileId() + ".json"), Charset.defaultCharset()); + Files.asCharSink(new File(outDir, file.getFileId() + ".json"), Charset.defaultCharset()).write(gson.toJson(overlay)); ++count; } } diff --git a/cache/src/test/java/net/runelite/cache/SequenceDumper.java b/cache/src/test/java/net/runelite/cache/SequenceDumper.java index 94dd175bbb..485bd3d84f 100644 --- a/cache/src/test/java/net/runelite/cache/SequenceDumper.java +++ b/cache/src/test/java/net/runelite/cache/SequenceDumper.java @@ -77,7 +77,7 @@ public class SequenceDumper SequenceLoader loader = new SequenceLoader(); SequenceDefinition seq = loader.load(file.getFileId(), file.getContents()); - Files.write(gson.toJson(seq), new File(outDir, file.getFileId() + ".json"), Charset.defaultCharset()); + Files.asCharSink(new File(outDir, file.getFileId() + ".json"), Charset.defaultCharset()).write(gson.toJson(seq)); ++count; } } diff --git a/cache/src/test/java/net/runelite/cache/SoundEffectsDumperTest.java b/cache/src/test/java/net/runelite/cache/SoundEffectsDumperTest.java index c2a420c0de..5ac0c9e1c5 100644 --- a/cache/src/test/java/net/runelite/cache/SoundEffectsDumperTest.java +++ b/cache/src/test/java/net/runelite/cache/SoundEffectsDumperTest.java @@ -71,7 +71,7 @@ public class SoundEffectsDumperTest SoundEffectLoader soundEffectLoader = new SoundEffectLoader(); SoundEffectDefinition soundEffect = soundEffectLoader.load(contents); - Files.write(gson.toJson(soundEffect), new File(dumpDir, archive.getArchiveId() + ".json"), Charset.defaultCharset()); + Files.asCharSink(new File(dumpDir, archive.getArchiveId() + ".json"), Charset.defaultCharset()).write(gson.toJson(soundEffect)); ++count; } } diff --git a/cache/src/test/java/net/runelite/cache/StructManagerTest.java b/cache/src/test/java/net/runelite/cache/StructManagerTest.java index 470df61bc0..f1a1fb22ca 100644 --- a/cache/src/test/java/net/runelite/cache/StructManagerTest.java +++ b/cache/src/test/java/net/runelite/cache/StructManagerTest.java @@ -64,7 +64,7 @@ public class StructManagerTest { StructDefinition def = struct.getValue(); - Files.write(gson.toJson(def), new File(dumpDir, struct.getKey() + ".json"), Charset.defaultCharset()); + Files.asCharSink(new File(dumpDir, struct.getKey() + ".json"), Charset.defaultCharset()).write(gson.toJson(def)); ++count; } } diff --git a/cache/src/test/java/net/runelite/cache/TextureDumper.java b/cache/src/test/java/net/runelite/cache/TextureDumper.java index cdcdbd9f6a..0aba683504 100644 --- a/cache/src/test/java/net/runelite/cache/TextureDumper.java +++ b/cache/src/test/java/net/runelite/cache/TextureDumper.java @@ -64,7 +64,7 @@ public class TextureDumper for (TextureDefinition texture : tm.getTextures()) { - Files.write(gson.toJson(texture), new File(outDir, texture.getId() + ".json"), Charset.defaultCharset()); + Files.asCharSink(new File(outDir, texture.getId() + ".json"), Charset.defaultCharset()).write(gson.toJson(texture)); ++count; } } diff --git a/cache/src/test/java/net/runelite/cache/UnderlayDumper.java b/cache/src/test/java/net/runelite/cache/UnderlayDumper.java index db735d40cf..04f2997530 100644 --- a/cache/src/test/java/net/runelite/cache/UnderlayDumper.java +++ b/cache/src/test/java/net/runelite/cache/UnderlayDumper.java @@ -77,7 +77,7 @@ public class UnderlayDumper UnderlayLoader loader = new UnderlayLoader(); UnderlayDefinition underlay = loader.load(file.getFileId(), file.getContents()); - Files.write(gson.toJson(underlay), new File(outDir, file.getFileId() + ".json"), Charset.defaultCharset()); + Files.asCharSink(new File(outDir, file.getFileId() + ".json"), Charset.defaultCharset()).write(gson.toJson(underlay)); ++count; } } diff --git a/cache/src/test/java/net/runelite/cache/VarbitDumper.java b/cache/src/test/java/net/runelite/cache/VarbitDumper.java index 5f75c7a157..9bcdcf9237 100644 --- a/cache/src/test/java/net/runelite/cache/VarbitDumper.java +++ b/cache/src/test/java/net/runelite/cache/VarbitDumper.java @@ -77,7 +77,7 @@ public class VarbitDumper VarbitLoader loader = new VarbitLoader(); VarbitDefinition varbit = loader.load(file.getFileId(), file.getContents()); - Files.write(gson.toJson(varbit), new File(outDir, file.getFileId() + ".json"), Charset.defaultCharset()); + Files.asCharSink(new File(outDir, file.getFileId() + ".json"), Charset.defaultCharset()).write(gson.toJson(varbit)); ++count; } } diff --git a/cache/src/test/java/net/runelite/cache/WorldMapDumperTest.java b/cache/src/test/java/net/runelite/cache/WorldMapDumperTest.java index 8d8dd956c4..92b2582a91 100644 --- a/cache/src/test/java/net/runelite/cache/WorldMapDumperTest.java +++ b/cache/src/test/java/net/runelite/cache/WorldMapDumperTest.java @@ -77,7 +77,7 @@ public class WorldMapDumperTest WorldMapLoader loader = new WorldMapLoader(); WorldMapDefinition def = loader.load(file.getContents(), file.getFileId()); - Files.write(gson.toJson(def), new File(outDir, file.getFileId() + ".json"), Charset.defaultCharset()); + Files.asCharSink(new File(outDir, file.getFileId() + ".json"), Charset.defaultCharset()).write(gson.toJson(def)); ++count; } } diff --git a/http-api/src/main/java/net/runelite/http/api/chat/ChatClient.java b/http-api/src/main/java/net/runelite/http/api/chat/ChatClient.java index 3e9ffe3fd9..bd8c83f5ef 100644 --- a/http-api/src/main/java/net/runelite/http/api/chat/ChatClient.java +++ b/http-api/src/main/java/net/runelite/http/api/chat/ChatClient.java @@ -39,8 +39,8 @@ import okhttp3.Response; public class ChatClient { private static final Predicate LAYOUT_VALIDATOR = Pattern - .compile("\\[[A-Z]+]:(\\s*\\w+\\s*(\\([A-Za-z]+\\))?,?)+") - .asPredicate(); + .compile("\\[[A-Z]+]:(\\s*\\w+\\s*(\\([A-Za-z]+\\))?,?)+") + .asPredicate(); public boolean submitKc(String username, String boss, int kc) throws IOException { @@ -237,7 +237,7 @@ public class ChatClient .url(url) .build(); - try (Response response = RuneLiteAPI.RLP_CLIENT.newCall(request).execute()) + try (Response response = RuneLiteAPI.CLIENT.newCall(request).execute()) { return response.isSuccessful(); } @@ -273,16 +273,16 @@ public class ChatClient } HttpUrl url = RuneLiteAPI.getPlusApiBase().newBuilder() - .addPathSegment("chat") - .addPathSegment("layout") - .addQueryParameter("name", username) - .addQueryParameter("layout", layout) - .build(); + .addPathSegment("chat") + .addPathSegment("layout") + .addQueryParameter("name", username) + .addQueryParameter("layout", layout) + .build(); Request request = new Request.Builder() - .post(RequestBody.create(null, new byte[0])) - .url(url) - .build(); + .post(RequestBody.create(null, new byte[0])) + .url(url) + .build(); try (Response response = RuneLiteAPI.RLP_CLIENT.newCall(request).execute()) { @@ -290,17 +290,40 @@ public class ChatClient } } + public boolean submitDuels(String username, int wins, int losses, int winningStreak, int losingStreak) throws IOException + { + HttpUrl url = RuneLiteAPI.getApiBase().newBuilder() + .addPathSegment("chat") + .addPathSegment("duels") + .addQueryParameter("name", username) + .addQueryParameter("wins", Integer.toString(wins)) + .addQueryParameter("losses", Integer.toString(losses)) + .addQueryParameter("winningStreak", Integer.toString(winningStreak)) + .addQueryParameter("losingStreak", Integer.toString(losingStreak)) + .build(); + + Request request = new Request.Builder() + .post(RequestBody.create(null, new byte[0])) + .url(url) + .build(); + + try (Response response = RuneLiteAPI.CLIENT.newCall(request).execute()) + { + return response.isSuccessful(); + } + } + public String getLayout(String username) throws IOException { HttpUrl url = RuneLiteAPI.getPlusApiBase().newBuilder() - .addPathSegment("chat") - .addPathSegment("layout") - .addQueryParameter("name", username) - .build(); + .addPathSegment("chat") + .addPathSegment("layout") + .addQueryParameter("name", username) + .build(); Request request = new Request.Builder() - .url(url) - .build(); + .url(url) + .build(); try (Response response = RuneLiteAPI.RLP_CLIENT.newCall(request).execute()) { @@ -328,15 +351,15 @@ public class ChatClient public House[] getHosts(int world, String location) throws IOException { HttpUrl url = RuneLiteAPI.getPlusApiBase().newBuilder() - .addPathSegment("chat") - .addPathSegment("hosts") - .addQueryParameter("world", Integer.toString(world)) - .addQueryParameter("location", location) - .build(); + .addPathSegment("chat") + .addPathSegment("hosts") + .addQueryParameter("world", Integer.toString(world)) + .addQueryParameter("location", location) + .build(); Request request = new Request.Builder() - .url(url) - .build(); + .url(url) + .build(); try (Response response = RuneLiteAPI.RLP_CLIENT.newCall(request).execute()) { @@ -347,6 +370,35 @@ public class ChatClient InputStream in = response.body().byteStream(); return RuneLiteAPI.GSON.fromJson(new InputStreamReader(in), House[].class); + + } + catch (JsonParseException ex) + { + throw new IOException(ex); + } + } + + public Duels getDuels(String username) throws IOException + { + HttpUrl url = RuneLiteAPI.getApiBase().newBuilder() + .addPathSegment("chat") + .addPathSegment("duels") + .addQueryParameter("name", username) + .build(); + + Request request = new Request.Builder() + .url(url) + .build(); + + try (Response response = RuneLiteAPI.CLIENT.newCall(request).execute()) + { + if (!response.isSuccessful()) + { + throw new IOException("Unable to look up duels!"); + } + + InputStream in = response.body().byteStream(); + return RuneLiteAPI.GSON.fromJson(new InputStreamReader(in), Duels.class); } catch (JsonParseException ex) { @@ -357,24 +409,24 @@ public class ChatClient public boolean submitHost(int world, String location, House house) throws IOException { HttpUrl url = RuneLiteAPI.getPlusApiBase().newBuilder() - .addPathSegment("chat") - .addPathSegment("hosts") - .addQueryParameter("world", Integer.toString(world)) - .addQueryParameter("location", location) - .addQueryParameter("owner", house.getOwner()) - .addQueryParameter("guildedAltar", Boolean.toString(house.isGuildedAltarPresent())) - .addQueryParameter("occultAltar", Boolean.toString(house.isOccultAltarPresent())) - .addQueryParameter("spiritTree", Boolean.toString(house.isSpiritTreePresent())) - .addQueryParameter("fairyRing", Boolean.toString(house.isFairyRingPresent())) - .addQueryParameter("wildernessObelisk", Boolean.toString(house.isWildernessObeliskPresent())) - .addQueryParameter("repairStand", Boolean.toString(house.isRepairStandPresent())) - .addQueryParameter("combatDummy", Boolean.toString(house.isCombatDummyPresent())) - .build(); + .addPathSegment("chat") + .addPathSegment("hosts") + .addQueryParameter("world", Integer.toString(world)) + .addQueryParameter("location", location) + .addQueryParameter("owner", house.getOwner()) + .addQueryParameter("guildedAltar", Boolean.toString(house.isGuildedAltarPresent())) + .addQueryParameter("occultAltar", Boolean.toString(house.isOccultAltarPresent())) + .addQueryParameter("spiritTree", Boolean.toString(house.isSpiritTreePresent())) + .addQueryParameter("fairyRing", Boolean.toString(house.isFairyRingPresent())) + .addQueryParameter("wildernessObelisk", Boolean.toString(house.isWildernessObeliskPresent())) + .addQueryParameter("repairStand", Boolean.toString(house.isRepairStandPresent())) + .addQueryParameter("combatDummy", Boolean.toString(house.isCombatDummyPresent())) + .build(); Request request = new Request.Builder() - .post(RequestBody.create(null, new byte[0])) - .url(url) - .build(); + .post(RequestBody.create(null, new byte[0])) + .url(url) + .build(); try (Response response = RuneLiteAPI.RLP_CLIENT.newCall(request).execute()) { @@ -385,29 +437,29 @@ public class ChatClient public boolean removeHost(int world, String location, House house) throws IOException { HttpUrl url = RuneLiteAPI.getPlusApiBase().newBuilder() - .addPathSegment("chat") - .addPathSegment("hosts") - .addQueryParameter("world", Integer.toString(world)) - .addQueryParameter("location", location) - .addQueryParameter("owner", house.getOwner()) - .addQueryParameter("guildedAltar", Boolean.toString(house.isGuildedAltarPresent())) - .addQueryParameter("occultAltar", Boolean.toString(house.isOccultAltarPresent())) - .addQueryParameter("spiritTree", Boolean.toString(house.isSpiritTreePresent())) - .addQueryParameter("fairyRing", Boolean.toString(house.isFairyRingPresent())) - .addQueryParameter("wildernessObelisk", Boolean.toString(house.isWildernessObeliskPresent())) - .addQueryParameter("repairStand", Boolean.toString(house.isRepairStandPresent())) - .addQueryParameter("combatDummy", Boolean.toString(house.isCombatDummyPresent())) - .addQueryParameter("remove", Boolean.toString(true)) - .build(); + .addPathSegment("chat") + .addPathSegment("hosts") + .addQueryParameter("world", Integer.toString(world)) + .addQueryParameter("location", location) + .addQueryParameter("owner", house.getOwner()) + .addQueryParameter("guildedAltar", Boolean.toString(house.isGuildedAltarPresent())) + .addQueryParameter("occultAltar", Boolean.toString(house.isOccultAltarPresent())) + .addQueryParameter("spiritTree", Boolean.toString(house.isSpiritTreePresent())) + .addQueryParameter("fairyRing", Boolean.toString(house.isFairyRingPresent())) + .addQueryParameter("wildernessObelisk", Boolean.toString(house.isWildernessObeliskPresent())) + .addQueryParameter("repairStand", Boolean.toString(house.isRepairStandPresent())) + .addQueryParameter("combatDummy", Boolean.toString(house.isCombatDummyPresent())) + .addQueryParameter("remove", Boolean.toString(true)) + .build(); Request request = new Request.Builder() - .post(RequestBody.create(null, new byte[0])) - .url(url) - .build(); + .post(RequestBody.create(null, new byte[0])) + .url(url) + .build(); try (Response response = RuneLiteAPI.RLP_CLIENT.newCall(request).execute()) { return response.isSuccessful(); } } -} +} \ No newline at end of file diff --git a/http-api/src/main/java/net/runelite/http/api/chat/Duels.java b/http-api/src/main/java/net/runelite/http/api/chat/Duels.java new file mode 100644 index 0000000000..ba117a526a --- /dev/null +++ b/http-api/src/main/java/net/runelite/http/api/chat/Duels.java @@ -0,0 +1,36 @@ +/* + * 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.http.api.chat; + +import lombok.Data; + +@Data +public class Duels +{ + private int wins; + private int losses; + private int winningStreak; + private int losingStreak; +} diff --git a/http-service/src/main/java/net/runelite/http/service/animation/AnimationController.java b/http-service/src/main/java/net/runelite/http/service/animation/AnimationController.java deleted file mode 100644 index c588b8193d..0000000000 --- a/http-service/src/main/java/net/runelite/http/service/animation/AnimationController.java +++ /dev/null @@ -1,92 +0,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.http.service.animation; - -import java.util.List; -import java.util.stream.Collectors; -import net.runelite.http.api.animation.AnimationKey; -import net.runelite.http.api.animation.AnimationRequest; -import net.runelite.http.service.util.exception.NotFoundException; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.PathVariable; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RequestMapping; -import static org.springframework.web.bind.annotation.RequestMethod.POST; -import org.springframework.web.bind.annotation.RestController; - -@RestController -@RequestMapping("/animation") -public class AnimationController -{ - @Autowired - private AnimationEndpoint animationService; - - @RequestMapping(method = POST) - public void submit(@RequestBody AnimationRequest animationRequest) - { - animationService.submit(animationRequest); - } - - @GetMapping - public List get() - { - return animationService.get().stream() - .map(AnimationController::entryToKey) - .collect(Collectors.toList()); - } - - @GetMapping("/{npcid}") - public AnimationKey getRegion(@PathVariable int npcid) - { - AnimationEntry animationEntry = animationService.getNPC(npcid); - if (animationEntry == null) - { - throw new NotFoundException(); - } - - return entryToKey(animationEntry); - } - - private static AnimationKey entryToKey(AnimationEntry xe) - { - AnimationKey animationKey = new AnimationKey(); - animationKey.setNPCId(xe.getNPCId()); - animationKey.setAnimations(new int[] - { - xe.getAnimations()[0], - xe.getAnimations()[1], - xe.getAnimations()[2], - xe.getAnimations()[3], - xe.getAnimations()[4], - xe.getAnimations()[5], - xe.getAnimations()[6], - xe.getAnimations()[7], - xe.getAnimations()[8], - xe.getAnimations()[9], - }); - return animationKey; - } -} diff --git a/http-service/src/main/java/net/runelite/http/service/chat/ChatController.java b/http-service/src/main/java/net/runelite/http/service/chat/ChatController.java index 5aa1b8144b..df287e6512 100644 --- a/http-service/src/main/java/net/runelite/http/service/chat/ChatController.java +++ b/http-service/src/main/java/net/runelite/http/service/chat/ChatController.java @@ -100,4 +100,4 @@ public class ChatController { return chatService.getHosts(world, location); } -} +} \ No newline at end of file diff --git a/http-service/src/main/java/net/runelite/http/service/chat/ChatService.java b/http-service/src/main/java/net/runelite/http/service/chat/ChatService.java index ebce4c49a0..aa23d3f18d 100644 --- a/http-service/src/main/java/net/runelite/http/service/chat/ChatService.java +++ b/http-service/src/main/java/net/runelite/http/service/chat/ChatService.java @@ -117,4 +117,4 @@ public class ChatService jedis.lrem(key, 0, json); } } -} +} \ No newline at end of file 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 8ff7fcd3cc..45ce683b6e 100644 --- a/runelite-api/src/main/java/net/runelite/api/AnimationID.java +++ b/runelite-api/src/main/java/net/runelite/api/AnimationID.java @@ -22,7 +22,7 @@ * (INCLUDING NEGLIGENCE OR 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;; +package net.runelite.api; /** * Utility class used for mapping animation IDs. @@ -166,8 +166,15 @@ public final class AnimationID public static final int BLOCK_UNARMED = 424; // Same Animation as failed pickpocked // NPC animations - public static final int TZTOK_JAD_MAGIC_ATTACK = 2656; public static final int TZTOK_JAD_RANGE_ATTACK = 2652; + public static final int TZTOK_JAD_MELEE_ATTACK = 2655; + public static final int TZTOK_JAD_MAGIC_ATTACK = 2656; + public static final int TOK_XIL_RANGE_ATTACK = 2633; + public static final int TOK_XIL_MELEE_ATTACK = 2628; + public static final int KET_ZEK_MELEE_ATTACK = 2644; + public static final int KET_ZEK_MAGE_ATTACK = 2647; + public static final int MEJ_KOT_MELEE_ATTACK = 2637; + public static final int MEJ_KOT_HEAL_ATTACK = 2639; public static final int HELLHOUND_DEFENCE = 6566; public static final int VORKATH_WAKE_UP = 7950; public static final int VORKATH_DEATH = 7949; diff --git a/runelite-api/src/main/java/net/runelite/api/Client.java b/runelite-api/src/main/java/net/runelite/api/Client.java index 604478d6f3..3be392090f 100644 --- a/runelite-api/src/main/java/net/runelite/api/Client.java +++ b/runelite-api/src/main/java/net/runelite/api/Client.java @@ -1627,6 +1627,11 @@ public interface Client extends GameShell */ NodeCache getItemDefinitionCache(); + /** + * Returns the array of cross sprites that appear and animate when left-clicking + */ + Sprite[] getCrossSprites(); + EnumDefinition getEnum(int id); void draw2010Menu(); diff --git a/runelite-api/src/main/java/net/runelite/api/GraphicID.java b/runelite-api/src/main/java/net/runelite/api/GraphicID.java index 5a6f7054bb..3aa58d8b64 100644 --- a/runelite-api/src/main/java/net/runelite/api/GraphicID.java +++ b/runelite-api/src/main/java/net/runelite/api/GraphicID.java @@ -51,9 +51,10 @@ public class GraphicID public static final int IMBUED_HEART = 1316; public static final int FLYING_FISH = 1387; public static final int OLM_BURN = 1351; + public static final int OLM_LIGHTNING = 1356; public static final int OLM_TELEPORT = 1359; public static final int OLM_HEAL = 1363; public static final int OLM_CRYSTAL = 1447; public static final int XERIC_TELEPORT = 1612; public static final int HYDRA_LIGHTNING = 1666; -} +} \ No newline at end of file diff --git a/runelite-api/src/main/java/net/runelite/api/coords/WorldArea.java b/runelite-api/src/main/java/net/runelite/api/coords/WorldArea.java index 105bf9fa89..7156045eb8 100644 --- a/runelite-api/src/main/java/net/runelite/api/coords/WorldArea.java +++ b/runelite-api/src/main/java/net/runelite/api/coords/WorldArea.java @@ -184,6 +184,25 @@ public class WorldArea return isInMeleeDistance(new WorldArea(other, 1, 1)); } + /** + * Checks whether this area is within melee distance of another without blocking in-between. + * + * @param client the client to test in + * @param other the other area + * @return true if in melee distance without blocking, false otherwise + */ + public boolean canMelee(Client client, WorldArea other) + { + if (isInMeleeDistance(other)) + { + Point p1 = this.getComparisonPoint(other); + Point p2 = other.getComparisonPoint(this); + WorldArea w1 = new WorldArea(p1.getX(), p1.getY() , 1, 1, this.getPlane()); + return (w1.canTravelInDirection(client, p2.getX() - p1.getX(), p2.getY() - p1.getY())); + } + return false; + } + /** * Checks whether this area intersects with another. * diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/fightcave/NPCContainer.java b/runelite-api/src/main/java/net/runelite/api/events/NpcDefinitionChanged.java similarity index 62% rename from runelite-client/src/main/java/net/runelite/client/plugins/fightcave/NPCContainer.java rename to runelite-api/src/main/java/net/runelite/api/events/NpcDefinitionChanged.java index 9ad21108f4..7d9569f5bd 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/fightcave/NPCContainer.java +++ b/runelite-api/src/main/java/net/runelite/api/events/NpcDefinitionChanged.java @@ -1,6 +1,5 @@ /* * Copyright (c) 2018, Woox - * Copyright (c) 2019, Ganom * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -23,55 +22,19 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package net.runelite.client.plugins.fightcave; +package net.runelite.api.events; -import lombok.Getter; -import lombok.Setter; -import net.runelite.api.Actor; +import lombok.Value; import net.runelite.api.NPC; -import net.runelite.api.NPCDefinition; -class NPCContainer +/** + * Fires after the composition of an {@link NPC} changes. + */ +@Value +public class NpcDefinitionChanged { - - @Getter - private NPC npc; - - @Getter - private int npcIndex; - - @Getter - private String npcName; - - @Getter - private int npcSize; - - @Setter - @Getter - private int TicksUntilAttack; - - @Setter - @Getter - private int npcSpeed; - - @Setter - @Getter - private Actor npcInteracting; - - - NPCContainer(NPC npc) - { - this.npc = npc; - this.npcName = npc.getName(); - this.npcIndex = npc.getIndex(); - this.npcInteracting = npc.getInteracting(); - this.npcSpeed = 0; - this.TicksUntilAttack = 0; - final NPCDefinition composition = npc.getTransformedDefinition(); - - if (composition != null) - { - this.npcSize = composition.getSize(); - } - } + /** + * The NPC of which the composition changed. + */ + private final NPC npc; } \ No newline at end of file diff --git a/runelite-client/pom.xml b/runelite-client/pom.xml index 70c5c83000..98b1c9529c 100644 --- a/runelite-client/pom.xml +++ b/runelite-client/pom.xml @@ -284,6 +284,11 @@ asm-all 6.0_BETA + + org.json + json + 20180813 + diff --git a/runelite-client/src/main/java/net/runelite/client/config/ChatColorConfig.java b/runelite-client/src/main/java/net/runelite/client/config/ChatColorConfig.java index 0bcf67341c..c9a3e40d3d 100644 --- a/runelite-client/src/main/java/net/runelite/client/config/ChatColorConfig.java +++ b/runelite-client/src/main/java/net/runelite/client/config/ChatColorConfig.java @@ -451,7 +451,7 @@ public interface ChatColorConfig extends Config ) default Color transparentExamineHighlight() { - return Color.decode("#0000FF"); + return Color.GREEN; } @ConfigItem( diff --git a/runelite-client/src/main/java/net/runelite/client/config/ConfigInvocationHandler.java b/runelite-client/src/main/java/net/runelite/client/config/ConfigInvocationHandler.java index 62cd38a8d1..330551c37f 100644 --- a/runelite-client/src/main/java/net/runelite/client/config/ConfigInvocationHandler.java +++ b/runelite-client/src/main/java/net/runelite/client/config/ConfigInvocationHandler.java @@ -28,6 +28,8 @@ import java.lang.invoke.MethodHandles; import java.lang.reflect.Constructor; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; +import java.util.HashMap; +import java.util.Map; import java.util.Objects; import lombok.extern.slf4j.Slf4j; @@ -36,26 +38,49 @@ class ConfigInvocationHandler implements InvocationHandler { private final ConfigManager manager; + // Caches for annotation values + private static final Map, String> groupValueCache = new HashMap<>(); + private static final Map methodKeyNameCache = new HashMap<>(); + public ConfigInvocationHandler(ConfigManager manager) { this.manager = manager; } + private static String groupValueFromProxy(Class proxyClass) + { + Class iface = proxyClass.getInterfaces()[0]; + ConfigGroup group = iface.getAnnotation(ConfigGroup.class); + + return group == null ? null : group.value(); + } + + private static String keyNameFromMethod(Method method) + { + ConfigItem item = method.getAnnotation(ConfigItem.class); + + return item == null ? null : item.keyName(); + } + @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { - Class iface = proxy.getClass().getInterfaces()[0]; - - ConfigGroup group = iface.getAnnotation(ConfigGroup.class); - ConfigItem item = method.getAnnotation(ConfigItem.class); - - if (group == null) + String itemKeyName, groupValue; + try + { + groupValue = groupValueCache.computeIfAbsent(proxy.getClass(), ConfigInvocationHandler::groupValueFromProxy); + } + catch (NullPointerException e) { log.warn("Configuration proxy class {} has no @ConfigGroup!", proxy.getClass()); return null; } - if (item == null) + try + { + itemKeyName = methodKeyNameCache.computeIfAbsent(method, ConfigInvocationHandler::keyNameFromMethod); + } + catch (NullPointerException e) { log.warn("Configuration method {} has no @ConfigItem!", method); return null; @@ -64,38 +89,43 @@ class ConfigInvocationHandler implements InvocationHandler if (args == null) { // Getting configuration item - String value = manager.getConfiguration(group.value(), item.keyName()); - - if (value == null) + return manager.getConfigObjectFromCacheOrElse(groupValue, itemKeyName, (value) -> { - if (method.isDefault()) + try { - return callDefaultMethod(proxy, method, null); + value = manager.getConfiguration(value); + if (value == null) + { + if (method.isDefault()) + { + return callDefaultMethod(proxy, method, null); + } + return null; + } + + // Convert value to return type + Class returnType = method.getReturnType(); + + try + { + return ConfigManager.stringToObject(value, returnType); + } + catch (Exception e) + { + log.warn("Unable to unmarshal {}.{} ", groupValue, itemKeyName, e); + if (method.isDefault()) + { + return callDefaultMethod(proxy, method, null); + } + return null; + } } - - return null; - } - - // Convert value to return type - Class returnType = method.getReturnType(); - - try - { - return ConfigManager.stringToObject(value, returnType); - } - catch (Exception e) - { - log.warn("Unable to unmarshal {}.{} ", group.value(), item.keyName(), e); - if (method.isDefault()) + catch (Throwable throwable) { - Object defaultValue = callDefaultMethod(proxy, method, null); - - manager.setConfiguration(group.value(), item.keyName(), defaultValue); - - return defaultValue; + log.error("Unable to resolve configuration value {}.{}", groupValue, itemKeyName, throwable); + return null; } - return null; - } + }); } else { @@ -103,13 +133,13 @@ class ConfigInvocationHandler implements InvocationHandler if (args.length != 1) { - throw new RuntimeException("Invalid number of arguents to configuration method"); + throw new RuntimeException("Invalid number of arguments to configuration method"); } Object newValue = args[0]; Class type = method.getParameterTypes()[0]; - Object oldValue = manager.getConfiguration(group.value(), item.keyName(), type); + Object oldValue = manager.getConfiguration(groupValue, itemKeyName, type); if (Objects.equals(oldValue, newValue)) { @@ -124,19 +154,19 @@ class ConfigInvocationHandler implements InvocationHandler if (Objects.equals(newValue, defaultValue)) { // Just unset if it goes back to the default - manager.unsetConfiguration(group.value(), item.keyName()); + manager.unsetConfiguration(groupValue, itemKeyName); return null; } } if (newValue == null) { - manager.unsetConfiguration(group.value(), item.keyName()); + manager.unsetConfiguration(groupValue, itemKeyName); } else { String newValueStr = ConfigManager.objectToString(newValue); - manager.setConfiguration(group.value(), item.keyName(), newValueStr); + manager.setConfiguration(groupValue, itemKeyName, newValueStr); } return null; } diff --git a/runelite-client/src/main/java/net/runelite/client/config/ConfigManager.java b/runelite-client/src/main/java/net/runelite/client/config/ConfigManager.java index 8bb63b5a4f..c81c25bd0e 100644 --- a/runelite-client/src/main/java/net/runelite/client/config/ConfigManager.java +++ b/runelite-client/src/main/java/net/runelite/client/config/ConfigManager.java @@ -55,6 +55,7 @@ import java.util.Objects; import java.util.Properties; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; +import java.util.function.Function; import java.util.stream.Collectors; import javax.inject.Inject; import javax.inject.Singleton; @@ -81,6 +82,7 @@ public class ConfigManager private final ScheduledExecutorService executor; private final ConfigInvocationHandler handler = new ConfigInvocationHandler(this); private final Properties properties = new Properties(); + private final Map configObjectCache = new HashMap<>(); private final Map pendingChanges = new HashMap<>(); @Inject @@ -220,6 +222,20 @@ public class ConfigManager } } + // Attempts to fetch the config value from the cache if present. Otherwise it calls the get value function and caches the result + Object getConfigObjectFromCacheOrElse(String groupName, String key, Function getValue) + { + String configItemKey = groupName + "." + key; + return configObjectCache.computeIfAbsent(configItemKey, getValue); + } + + // Posts the configchanged event to the event bus and remove the changed key from the cache + private void postConfigChanged(ConfigChanged configChanged) + { + configObjectCache.remove(configChanged.getGroup() + "." + configChanged.getKey()); + eventBus.post(configChanged); + } + public T getConfig(Class clazz) { if (!Modifier.isPublic(clazz.getModifiers())) @@ -245,6 +261,11 @@ public class ConfigManager return properties.getProperty(groupName + "." + key); } + public String getConfiguration(String propertyKey) + { + return properties.getProperty(propertyKey); + } + public T getConfiguration(String groupName, String key, Class clazz) { String value = getConfiguration(groupName, key); @@ -284,7 +305,7 @@ public class ConfigManager configChanged.setOldValue(oldValue); configChanged.setNewValue(value); - eventBus.post(configChanged); + postConfigChanged(configChanged); } public void setConfiguration(String groupName, String key, Object value) diff --git a/runelite-client/src/main/java/net/runelite/client/game/AgilityShortcut.java b/runelite-client/src/main/java/net/runelite/client/game/AgilityShortcut.java index 96a55f3e86..9c20fb9b8f 100644 --- a/runelite-client/src/main/java/net/runelite/client/game/AgilityShortcut.java +++ b/runelite-client/src/main/java/net/runelite/client/game/AgilityShortcut.java @@ -288,7 +288,7 @@ public enum AgilityShortcut GOBLIN_VILLAGE_WALL(14, "Wall", new WorldPoint(2925, 3523, 0), TIGHTGAP), CORSAIR_COVE_DUNGEON_PILLAR(15, "Pillar Jump", new WorldPoint(1980, 8996, 0), PILLAR_31809), EDGEVILLE_DUNGEON_MONKEYBARS(15, "Monkey Bars", null, MONKEYBARS_23566), - TROLLHEIM_ROCKS(15, "Rocks", null, new WorldPoint(2838, 3614, 0), ROCKS_3748), // No fixed world map location, but rocks near death plateau have a requirement of 15 + TROLLHEIM_ROCKS(15, "Rocks", null, new WorldPoint(2838, 3614, 0), ROCKS_3748), // No fixed world map location, but rocks near death plateau have a requirement of 15 YANILLE_UNDERWALL_TUNNEL(16, "Underwall Tunnel", new WorldPoint(2574, 3109, 0), HOLE_16520, CASTLE_WALL), YANILLE_WATCHTOWER_TRELLIS(18, "Trellis", null, TRELLIS_20056), COAL_TRUCKS_LOG_BALANCE(20, "Log Balance", new WorldPoint(2598, 3475, 0), LOG_BALANCE_23274), 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 3512baacfe..69a54cc971 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 @@ -37,33 +37,66 @@ import net.runelite.client.config.ModifierlessKeybind; @ConfigGroup("antiDrag") public interface AntiDragConfig extends Config { + @ConfigItem( - keyName = "dragDelay", - name = "Drag Delay", - description = "Configures the inventory drag delay in client ticks (20ms)", - position = 1 + position = 0, + keyName = "alwaysOn", + name = "Always On", + description = "Makes the anti-drag always active and disables the hotkey toggle", + disabledBy = "keybind", + hide = "keybind" ) - default int dragDelay() + default boolean alwaysOn() { - return Constants.GAME_TICK_LENGTH / Constants.CLIENT_TICK_LENGTH; // one game tick + return false; } @ConfigItem( + position = 1, keyName = "keybind", - name = "keybind", + name = "Toggle with Keybind", + description = "Toggle anti drag on and off, rather than always on.", + disabledBy = "alwaysOn", + hide = "alwaysOn" + ) + default boolean keybind() + { + return false; + } + + @ConfigItem( + keyName = "key", + name = "Keybind", description = "The keybind you want to use for antidrag", - position = 2 + position = 2, + hidden = true, + unhide = "keybind" ) default Keybind key() { return new ModifierlessKeybind(KeyEvent.VK_SHIFT, 0); } + @ConfigItem( + keyName = "dragDelay", + name = "Drag Delay", + description = "Configures the inventory drag delay in client ticks (20ms)", + position = 3, + hidden = true, + unhide = "keybind" + ) + default int dragDelay() + { + return Constants.GAME_TICK_LENGTH / Constants.CLIENT_TICK_LENGTH; // one game tick + } + @ConfigItem( keyName = "reqfocus", name = "Reset on focus loss", description = "Disable antidrag when losing focus (like alt tabbing)", - position = 3 + position = 4, + hidden = true, + unhide = "keybind" ) default boolean reqfocus() { @@ -74,7 +107,9 @@ public interface AntiDragConfig extends Config keyName = "overlay", name = "Enable overlay", description = "Do you really need a description?", - position = 4 + position = 5, + hidden = true, + unhide = "keybind" ) default boolean overlay() { @@ -87,8 +122,8 @@ public interface AntiDragConfig extends Config name = "Overlay color", description = "Change the overlay color, duh", hidden = true, - unhide = "overlay", - position = 5 + unhide = "keybind", + position = 6 ) default Color color() { @@ -99,7 +134,9 @@ public interface AntiDragConfig extends Config keyName = "changeCursor", name = "Change Cursor", description = "Change cursor when you have anti-drag enabled.", - position = 6 + position = 7, + hidden = true, + unhide = "keybind" ) default boolean changeCursor() { @@ -111,8 +148,8 @@ public interface AntiDragConfig extends Config name = "Cursor", description = "Select which cursor you wish to use", hidden = true, - unhide = "changeCursor", - position = 7 + unhide = "keybind", + position = 8 ) default CustomCursor selectedCursor() { diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/antidrag/AntiDragPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/antidrag/AntiDragPlugin.java index 76db48c55e..687ee9bc20 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/antidrag/AntiDragPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/antidrag/AntiDragPlugin.java @@ -28,6 +28,7 @@ package net.runelite.client.plugins.antidrag; import com.google.inject.Provides; import javax.inject.Inject; import net.runelite.api.Client; +import net.runelite.api.events.ConfigChanged; import net.runelite.api.events.FocusChanged; import net.runelite.client.config.ConfigManager; import net.runelite.client.eventbus.Subscribe; @@ -51,6 +52,7 @@ import net.runelite.client.util.HotkeyListener; public class AntiDragPlugin extends Plugin { private static final int DEFAULT_DELAY = 5; + private boolean toggleDrag; @Inject @@ -83,9 +85,11 @@ public class AntiDragPlugin extends Plugin @Override protected void startUp() throws Exception { - keyManager.registerKeyListener(hotkeyListener); - toggleDrag = false; - + if (config.keybind()) + { + keyManager.registerKeyListener(hotkeyListener); + } + client.setInventoryDragDelay(config.alwaysOn() ? config.dragDelay() : DEFAULT_DELAY); } @Override @@ -97,46 +101,75 @@ public class AntiDragPlugin extends Plugin overlayManager.remove(overlay); } + @Subscribe + public void onConfigChanged(ConfigChanged event) + { + if (event.getGroup().equals("antiDrag")) + { + if (event.getKey().equals("keybind")) + { + if (config.keybind()) + { + keyManager.registerKeyListener(hotkeyListener); + } + else + { + keyManager.unregisterKeyListener(hotkeyListener); + } + } + if (event.getKey().equals("alwaysOn")) + { + client.setInventoryDragDelay(config.alwaysOn() ? config.dragDelay() : DEFAULT_DELAY); + } + } + } + + @Subscribe + public void onFocusChanged(FocusChanged focusChanged) + { + if (!config.alwaysOn()) + { + if (!focusChanged.isFocused() && config.reqfocus()) + { + client.setInventoryDragDelay(DEFAULT_DELAY); + overlayManager.remove(overlay); + } + } + } + private final HotkeyListener hotkeyListener = new HotkeyListener(() -> config.key()) { @Override public void hotkeyPressed() { - toggleDrag = !toggleDrag; - if (toggleDrag) + if (!config.alwaysOn()) { - if (config.overlay()) + toggleDrag = !toggleDrag; + if (toggleDrag) { - overlayManager.add(overlay); - } - if (config.changeCursor()) - { - CustomCursor selectedCursor = config.selectedCursor(); - clientUI.setCursor(selectedCursor.getCursorImage(), selectedCursor.toString()); - } + if (config.overlay()) + { + overlayManager.add(overlay); + } + if (config.changeCursor()) + { + CustomCursor selectedCursor = config.selectedCursor(); + clientUI.setCursor(selectedCursor.getCursorImage(), selectedCursor.toString()); + } - client.setInventoryDragDelay(config.dragDelay()); - } - else - { - overlayManager.remove(overlay); - client.setInventoryDragDelay(DEFAULT_DELAY); - if (config.changeCursor()) + client.setInventoryDragDelay(config.dragDelay()); + } + else { - net.runelite.client.plugins.customcursor.CustomCursor selectedCursor = configManager.getConfig(CustomCursorConfig.class).selectedCursor(); - clientUI.setCursor(selectedCursor.getCursorImage(), selectedCursor.toString()); + overlayManager.remove(overlay); + client.setInventoryDragDelay(DEFAULT_DELAY); + if (config.changeCursor()) + { + net.runelite.client.plugins.customcursor.CustomCursor selectedCursor = configManager.getConfig(CustomCursorConfig.class).selectedCursor(); + clientUI.setCursor(selectedCursor.getCursorImage(), selectedCursor.toString()); + } } } } }; - - @Subscribe - public void onFocusChanged(FocusChanged focusChanged) - { - if (!focusChanged.isFocused() && config.reqfocus()) - { - client.setInventoryDragDelay(DEFAULT_DELAY); - overlayManager.remove(overlay); - } - } } 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 179c9b8c02..48491da688 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 @@ -27,10 +27,8 @@ */ package net.runelite.client.plugins.aoewarnings; -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 java.awt.Rectangle; @@ -38,13 +36,11 @@ import java.time.Duration; 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.Perspective; import net.runelite.api.Point; import net.runelite.api.Projectile; -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; @@ -62,7 +58,7 @@ public class AoeWarningOverlay extends Overlay private final AoeWarningConfig config; @Inject - public AoeWarningOverlay(@Nullable Client client, AoeWarningPlugin plugin, AoeWarningConfig config) + public AoeWarningOverlay(Client client, AoeWarningPlugin plugin, AoeWarningConfig config) { setPosition(OverlayPosition.DYNAMIC); setLayer(OverlayLayer.UNDER_WIDGETS); @@ -74,24 +70,25 @@ public class AoeWarningOverlay extends Overlay @Override public Dimension render(Graphics2D graphics) { + WorldPoint lp = client.getLocalPlayer().getWorldLocation(); for (WorldPoint point : plugin.getLightningTrail()) { - drawTile(graphics, point, new Color(0, 150, 200), 2, 150, 50); + OverlayUtil.drawTile(graphics, client, point, lp, new Color(0, 150, 200), 2, 150, 50); } for (WorldPoint point : plugin.getAcidTrail()) { - drawTile(graphics, point, new Color(69, 241, 44), 2, 150, 50); + OverlayUtil.drawTile(graphics, client, point, lp, new Color(69, 241, 44), 2, 150, 50); } for (WorldPoint point : plugin.getCrystalSpike()) { - drawTile(graphics, point, new Color(255, 0, 84), 2, 150, 50); + OverlayUtil.drawTile(graphics, client, point, lp, new Color(255, 0, 84), 2, 150, 50); } for (WorldPoint point : plugin.getWintertodtSnowFall()) { - drawTile(graphics, point, new Color(255, 0, 84), 2, 150, 50); + OverlayUtil.drawTile(graphics, client, point, lp, new Color(255, 0, 84), 2, 150, 50); } Instant now = Instant.now(); @@ -164,7 +161,8 @@ public class AoeWarningOverlay extends Overlay { if (tickProgress >= 0) { - renderTextLocation(graphics, Integer.toString(tickProgress), config.textSize(), config.fontStyle().getFont(), color, centerPoint(tilePoly.getBounds())); + OverlayUtil.renderTextLocation(graphics, Integer.toString(tickProgress), plugin.getTextSize(), + plugin.getFontStyle(), color, centerPoint(tilePoly.getBounds()), plugin.isShadows(), 0); } } graphics.setColor(new Color(setAlphaComponent(config.overlayColor().getRGB(), fillAlpha), true)); @@ -173,50 +171,6 @@ public class AoeWarningOverlay extends Overlay 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; - } - 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, 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); - if (config.shadows()) - { - OverlayUtil.renderTextLocation(graphics, canvasCenterPoint_shadow, txtString, Color.BLACK); - } - OverlayUtil.renderTextLocation(graphics, canvasCenterPoint, txtString, fontColor); - } - } - private Point centerPoint(Rectangle rect) { int x = (int) (rect.getX() + rect.getWidth() / 2); 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 37375941d6..00ed024a44 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 @@ -41,6 +41,7 @@ import lombok.extern.slf4j.Slf4j; import net.runelite.api.Client; import net.runelite.api.GameObject; import net.runelite.api.GameState; +import net.runelite.api.GraphicID; import net.runelite.api.GraphicsObject; import net.runelite.api.NullObjectID; import net.runelite.api.ObjectID; @@ -48,6 +49,7 @@ import net.runelite.api.Projectile; import net.runelite.api.Tile; import net.runelite.api.coords.LocalPoint; import net.runelite.api.coords.WorldPoint; +import net.runelite.api.events.ConfigChanged; import net.runelite.api.events.GameObjectDespawned; import net.runelite.api.events.GameObjectSpawned; import net.runelite.api.events.GameStateChanged; @@ -72,40 +74,35 @@ import net.runelite.client.ui.overlay.OverlayManager; @Slf4j public class AoeWarningPlugin extends Plugin { - @Getter private final Map bombs = new HashMap<>(); private final Map projectiles = new HashMap<>(); - @Inject public AoeWarningConfig config; - @Inject private Notifier notifier; - @Inject private OverlayManager overlayManager; - @Inject private AoeWarningOverlay coreOverlay; - @Inject private BombOverlay bombOverlay; - @Inject private Client client; - @Getter(AccessLevel.PACKAGE) private List LightningTrail = new ArrayList<>(); - @Getter(AccessLevel.PACKAGE) private List AcidTrail = new ArrayList<>(); - @Getter(AccessLevel.PACKAGE) private List CrystalSpike = new ArrayList<>(); - @Getter(AccessLevel.PACKAGE) private List WintertodtSnowFall = new ArrayList<>(); + @Getter(AccessLevel.PACKAGE) + private boolean shadows; + @Getter(AccessLevel.PACKAGE) + private int textSize; + @Getter(AccessLevel.PACKAGE) + private int fontStyle; @Provides AoeWarningConfig getConfig(ConfigManager configManager) @@ -123,10 +120,7 @@ public class AoeWarningPlugin extends Plugin { overlayManager.add(coreOverlay); overlayManager.add(bombOverlay); - LightningTrail.clear(); - AcidTrail.clear(); - CrystalSpike.clear(); - WintertodtSnowFall.clear(); + reset(true); } @Override @@ -134,10 +128,29 @@ public class AoeWarningPlugin extends Plugin { overlayManager.remove(coreOverlay); overlayManager.remove(bombOverlay); - LightningTrail.clear(); - AcidTrail.clear(); - CrystalSpike.clear(); - WintertodtSnowFall.clear(); + reset(false); + } + + @Subscribe + public void onConfigChanged(ConfigChanged event) + { + if (!event.getGroup().equals("aoe")) + { + return; + } + + switch (event.getKey()) + { + case "fontStyle": + fontStyle = config.fontStyle().getFont(); + break; + case "textSize": + textSize = config.textSize(); + break; + case "shadows": + shadows = config.shadows(); + break; + } } @Subscribe @@ -172,12 +185,12 @@ public class AoeWarningPlugin extends Plugin public void onGameObjectSpawned(GameObjectSpawned event) { final GameObject gameObject = event.getGameObject(); - final WorldPoint bombLocation = gameObject.getWorldLocation(); + final WorldPoint wp = gameObject.getWorldLocation(); switch (gameObject.getId()) { case ObjectID.CRYSTAL_BOMB: - bombs.put(bombLocation, new CrystalBomb(gameObject, client.getTickCount())); + bombs.put(wp, new CrystalBomb(gameObject, client.getTickCount())); if (config.aoeNotifyAll() || config.bombDisplayNotifyEnabled()) { @@ -185,17 +198,16 @@ public class AoeWarningPlugin extends Plugin } break; case ObjectID.ACID_POOL: - AcidTrail.add(bombLocation); + AcidTrail.add(wp); break; case ObjectID.SMALL_CRYSTALS: - //todo - CrystalSpike.add(bombLocation); + CrystalSpike.add(wp); break; case NullObjectID.NULL_26690: //Wintertodt Snowfall if (config.isWintertodtEnabled()) { - WintertodtSnowFall.add(bombLocation); + WintertodtSnowFall.add(wp); if (config.aoeNotifyAll() || config.isWintertodtNotifyEnabled()) { @@ -210,25 +222,23 @@ public class AoeWarningPlugin extends Plugin public void onGameObjectDespawned(GameObjectDespawned event) { GameObject gameObject = event.getGameObject(); - WorldPoint bombLocation = gameObject.getWorldLocation(); + WorldPoint wp = gameObject.getWorldLocation(); switch (gameObject.getId()) { case ObjectID.CRYSTAL_BOMB: - //might as well check the ObjectID to save some time. purgeBombs(bombs); break; case ObjectID.ACID_POOL: - AcidTrail.remove(bombLocation); + AcidTrail.remove(wp); break; case ObjectID.SMALL_CRYSTALS: - //todo - CrystalSpike.remove(bombLocation); + CrystalSpike.remove(wp); break; case NullObjectID.NULL_26690: //Wintertodt Snowfall if (config.isWintertodtEnabled()) { - WintertodtSnowFall.remove(bombLocation); + WintertodtSnowFall.remove(wp); } break; } @@ -251,7 +261,7 @@ public class AoeWarningPlugin extends Plugin LightningTrail.clear(); for (GraphicsObject o : client.getGraphicsObjects()) { - if (o.getId() == 1356) + if (o.getId() == GraphicID.OLM_LIGHTNING) { LightningTrail.add(WorldPoint.fromLocal(client, o.getLocation())); @@ -281,6 +291,12 @@ public class AoeWarningPlugin extends Plugin Map.Entry entry = it.next(); WorldPoint world = entry.getKey(); LocalPoint local = LocalPoint.fromWorld(client, world); + + if (local == null) + { + return; + } + Tile tile = tiles[world.getPlane()][local.getSceneX()][local.getSceneY()]; GameObject[] objects = tile.getGameObjects(); boolean containsObjects = false; @@ -391,4 +407,20 @@ public class AoeWarningPlugin extends Plugin return false; } -} + + private void reset(boolean setConfig) + { + LightningTrail.clear(); + AcidTrail.clear(); + CrystalSpike.clear(); + WintertodtSnowFall.clear(); + bombs.clear(); + projectiles.clear(); + if (setConfig) + { + fontStyle = config.fontStyle().getFont(); + textSize = config.textSize(); + shadows = config.shadows(); + } + } +} \ No newline at end of file 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 b538b3df25..317f5ad04b 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 @@ -121,6 +121,10 @@ public class BombOverlay extends Overlay { final Player localPlayer = client.getLocalPlayer(); LocalPoint localLoc = LocalPoint.fromWorld(client, bomb.getWorldLocation()); + if (localLoc == null) + { + return; + } double distance_x = Math.abs(bomb.getWorldLocation().getX() - localPlayer.getWorldLocation().getX()); double distance_y = Math.abs(bomb.getWorldLocation().getY() - localPlayer.getWorldLocation().getY()); Color color_code = Color.decode(SAFE); @@ -142,7 +146,7 @@ public class BombOverlay extends Overlay { color_code = Color.decode(CAUTION); } - LocalPoint CenterPoint = new LocalPoint(localLoc.getX() + 0, localLoc.getY() + 0); + LocalPoint CenterPoint = new LocalPoint(localLoc.getX(), localLoc.getY()); Polygon poly = Perspective.getCanvasTileAreaPoly(client, CenterPoint, BOMB_AOE); if (poly != null) diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/barbarianassault/BarbarianAssaultMenu.java b/runelite-client/src/main/java/net/runelite/client/plugins/barbarianassault/BarbarianAssaultMenu.java index 8f852846e4..0f8f843fd8 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/barbarianassault/BarbarianAssaultMenu.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/barbarianassault/BarbarianAssaultMenu.java @@ -174,7 +174,7 @@ class BarbarianAssaultMenu return config.removeIncorrectCalls() && !hornUpdated; default: - return config.removeUnusedMenus(); + return role != null && config.removeUnusedMenus(); } }); diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/barbarianassault/Menus.java b/runelite-client/src/main/java/net/runelite/client/plugins/barbarianassault/Menus.java index 4f18e25578..5ec0dfb8de 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/barbarianassault/Menus.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/barbarianassault/Menus.java @@ -79,11 +79,11 @@ public enum Menus ATTACK_PENANCE_QUEEN(null, new ComparableEntry("attack", "penance queen", -1, -1, true, false)), ATTACK_QUEEN_SPAWN(null, new ComparableEntry("attack", "queen spawn", -1, -1, true, false)), - DROP_HORN(null, new ComparableEntry("drop", "horn", -1, -1, true, false)), - EXAMINE_HORN(null, new ComparableEntry("examine", "horn", -1, -1, true, false)), + DROP_HORN(null, new ComparableEntry("drop", "r horn", -1, -1, true, false)), + EXAMINE_HORN(null, new ComparableEntry("examine", "r horn", -1, -1, true, false)), LIGHT_LOGS(null, new ComparableEntry("light", "logs", -1, -1, true, true)), - MEDIC_HORN(null, new ComparableEntry("medic", "horn", -1, -1, true, false)), - USE_HORN(null, new ComparableEntry("use", "horn", -1, -1, true, false)); + MEDIC_HORN(null, new ComparableEntry("medic", "r horn", -1, -1, true, false)), + USE_HORN(null, new ComparableEntry("use", "r horn", -1, -1, true, false)); @Getter private final Role role; diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/boosts/BoostsConfig.java b/runelite-client/src/main/java/net/runelite/client/plugins/boosts/BoostsConfig.java index d5d7cadba8..8443994243 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/boosts/BoostsConfig.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/boosts/BoostsConfig.java @@ -82,11 +82,22 @@ public interface BoostsConfig extends Config return false; } + @ConfigItem( + keyName = "boldIconFont", + name = "Bold Font for Icons", + description = "", + position = 5 + ) + default boolean boldIconFont() + { + return false; + } + @ConfigItem( keyName = "displayNextBuffChange", name = "Display next buff change", description = "Configures whether or not to display when the next buffed stat change will be", - position = 5 + position = 6 ) default DisplayChangeMode displayNextBuffChange() { @@ -97,7 +108,7 @@ public interface BoostsConfig extends Config keyName = "displayNextDebuffChange", name = "Display next debuff change", description = "Configures whether or not to display when the next debuffed stat change will be", - position = 6 + position = 7 ) default DisplayChangeMode displayNextDebuffChange() { @@ -108,7 +119,7 @@ public interface BoostsConfig extends Config keyName = "boostThreshold", name = "Boost Amount Threshold", description = "The amount of levels boosted to send a notification at. A value of 0 will disable notification.", - position = 7 + position = 8 ) default int boostThreshold() { @@ -119,7 +130,7 @@ public interface BoostsConfig extends Config keyName = "groupNotifications", name = "Group Notifications", description = "Configures whether or not to group notifications for multiple skills into a single notification", - position = 8 + position = 9 ) default boolean groupNotifications() { diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/boosts/CombatIconsOverlay.java b/runelite-client/src/main/java/net/runelite/client/plugins/boosts/CombatIconsOverlay.java index 0609c4f1c8..2e4c9c5ab9 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/boosts/CombatIconsOverlay.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/boosts/CombatIconsOverlay.java @@ -19,6 +19,7 @@ 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.FontManager; import net.runelite.client.util.ColorUtil; import net.runelite.client.util.ImageUtil; @@ -50,7 +51,12 @@ class CombatIconsOverlay extends Overlay { return null; } - + + if (config.boldIconFont()) + { + graphics.setFont(FontManager.getRunescapeBoldFont()); + } + panelComponent.getChildren().clear(); panelComponent.setPreferredSize(new Dimension(28, 0)); panelComponent.setWrapping(2); diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/chatcommands/ChatCommandsConfig.java b/runelite-client/src/main/java/net/runelite/client/plugins/chatcommands/ChatCommandsConfig.java index 92987467d0..835ccec71e 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/chatcommands/ChatCommandsConfig.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/chatcommands/ChatCommandsConfig.java @@ -110,6 +110,17 @@ public interface ChatCommandsConfig extends Config @ConfigItem( position = 7, + keyName = "duels", + name = "Duels Command", + description = "Configures whether the duel arena command is enabled
!duels" + ) + default boolean duels() + { + return true; + } + + @ConfigItem( + position = 8, keyName = "clearShortcuts", name = "Clear shortcuts", description = "Enable shortcuts (ctrl+w and backspace) for clearing the chatbox" @@ -118,4 +129,4 @@ public interface ChatCommandsConfig extends Config { return true; } -} +} \ No newline at end of file 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 269c116c76..079f1cdba6 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 @@ -64,6 +64,7 @@ import net.runelite.client.plugins.PluginDescriptor; import net.runelite.client.util.StackFormatter; import static net.runelite.client.util.Text.sanitize; import net.runelite.http.api.chat.ChatClient; +import net.runelite.http.api.chat.Duels; import net.runelite.http.api.hiscore.HiscoreClient; import net.runelite.http.api.hiscore.HiscoreEndpoint; import net.runelite.http.api.hiscore.HiscoreResult; @@ -89,6 +90,8 @@ public class ChatCommandsPlugin extends Plugin private static final Pattern BARROWS_PATTERN = Pattern.compile("Your Barrows chest count is: (\\d+)"); private static final Pattern KILL_DURATION_PATTERN = Pattern.compile("Fight duration: [0-9:]+. Personal best: ([0-9:]+)"); private static final Pattern NEW_PB_PATTERN = Pattern.compile("Fight duration: ([0-9:]+) \\(new personal best\\)"); + private static final Pattern DUEL_ARENA_WINS_PATTERN = Pattern.compile("You (were defeated|won)! You have(?: now)? won (\\d+) duels?"); + private static final Pattern DUEL_ARENA_LOSSES_PATTERN = Pattern.compile("You have(?: now)? lost (\\d+) duels?"); private static final String TOTAL_LEVEL_COMMAND_STRING = "!total"; private static final String PRICE_COMMAND_STRING = "!price"; private static final String LEVEL_COMMAND_STRING = "!lvl"; @@ -98,6 +101,7 @@ public class ChatCommandsPlugin extends Plugin private static final String QP_COMMAND_STRING = "!qp"; private static final String GC_COMMAND_STRING = "!gc"; private static final String PB_COMMAND = "!pb"; + private static final String DUEL_ARENA_COMMAND = "!duels"; private final HiscoreClient hiscoreClient = new HiscoreClient(); private final ChatClient chatClient = new ChatClient(); @@ -148,6 +152,7 @@ public class ChatCommandsPlugin extends Plugin chatCommandManager.registerCommandAsync(QP_COMMAND_STRING, this::questPointsLookup, this::questPointsSubmit); chatCommandManager.registerCommandAsync(GC_COMMAND_STRING, this::gambleCountLookup, this::gambleCountSubmit); chatCommandManager.registerCommandAsync(PB_COMMAND, this::personalBestLookup, this::personalBestSubmit); + chatCommandManager.registerCommandAsync(DUEL_ARENA_COMMAND, this::duelArenaLookup, this::duelArenaSubmit); } @Override @@ -166,6 +171,7 @@ public class ChatCommandsPlugin extends Plugin chatCommandManager.unregisterCommand(QP_COMMAND_STRING); chatCommandManager.unregisterCommand(PB_COMMAND); chatCommandManager.unregisterCommand(GC_COMMAND_STRING); + chatCommandManager.unregisterCommand(DUEL_ARENA_COMMAND); } @Provides @@ -203,7 +209,9 @@ public class ChatCommandsPlugin extends Plugin @Subscribe public void onChatMessage(ChatMessage chatMessage) { - if (chatMessage.getType() != ChatMessageType.GAMEMESSAGE && chatMessage.getType() != ChatMessageType.SPAM) + if (chatMessage.getType() != ChatMessageType.TRADE + && chatMessage.getType() != ChatMessageType.GAMEMESSAGE + && chatMessage.getType() != ChatMessageType.SPAM) { return; } @@ -239,6 +247,43 @@ public class ChatCommandsPlugin extends Plugin return; } + matcher = DUEL_ARENA_WINS_PATTERN.matcher(message); + if (matcher.find()) + { + final int oldWins = getKc("Duel Arena Wins"); + final int wins = Integer.parseInt(matcher.group(2)); + final String result = matcher.group(1); + int winningStreak = getKc("Duel Arena Win Streak"); + int losingStreak = getKc("Duel Arena Lose Streak"); + + if (result.equals("won") && wins > oldWins) + { + losingStreak = 0; + winningStreak += 1; + } + else if (result.equals("were defeated")) + { + losingStreak += 1; + winningStreak = 0; + } + else + { + log.warn("unrecognized duel streak chat message: {}", message); + } + + setKc("Duel Arena Wins", wins); + setKc("Duel Arena Win Streak", winningStreak); + setKc("Duel Arena Lose Streak", losingStreak); + } + + matcher = DUEL_ARENA_LOSSES_PATTERN.matcher(message); + if (matcher.find()) + { + int losses = Integer.parseInt(matcher.group(1)); + + setKc("Duel Arena Losses", losses); + } + matcher = BARROWS_PATTERN.matcher(message); if (matcher.find()) { @@ -419,6 +464,96 @@ public class ChatCommandsPlugin extends Plugin client.refreshChat(); } + private boolean duelArenaSubmit(ChatInput chatInput, String value) + { + final int wins = getKc("Duel Arena Wins"); + final int losses = getKc("Duel Arena Losses"); + final int winningStreak = getKc("Duel Arena Win Streak"); + final int losingStreak = getKc("Duel Arena Lose Streak"); + + if (wins <= 0 && losses <= 0 && winningStreak <= 0 && losingStreak <= 0) + { + return false; + } + + final String playerName = client.getLocalPlayer().getName(); + + executor.execute(() -> + { + try + { + chatClient.submitDuels(playerName, wins, losses, winningStreak, losingStreak); + } + catch (Exception ex) + { + log.warn("unable to submit duels", ex); + } + finally + { + chatInput.resume(); + } + }); + + return true; + } + + private void duelArenaLookup(ChatMessage chatMessage, String message) + { + if (!config.duels()) + { + return; + } + + ChatMessageType type = chatMessage.getType(); + + final String player; + if (type == ChatMessageType.PRIVATECHATOUT) + { + player = client.getLocalPlayer().getName(); + } + else + { + player = sanitize(chatMessage.getName()); + } + + Duels duels; + try + { + duels = chatClient.getDuels(player); + } + catch (IOException ex) + { + log.debug("unable to lookup duels", ex); + return; + } + + final int wins = duels.getWins(); + final int losses = duels.getLosses(); + final int winningStreak = duels.getWinningStreak(); + final int losingStreak = duels.getLosingStreak(); + + String response = new ChatMessageBuilder() + .append(ChatColorType.NORMAL) + .append("Duel Arena wins: ") + .append(ChatColorType.HIGHLIGHT) + .append(Integer.toString(wins)) + .append(ChatColorType.NORMAL) + .append(" losses: ") + .append(ChatColorType.HIGHLIGHT) + .append(Integer.toString(losses)) + .append(ChatColorType.NORMAL) + .append(" streak: ") + .append(ChatColorType.HIGHLIGHT) + .append(Integer.toString((winningStreak != 0 ? winningStreak : -losingStreak))) + .build(); + + log.debug("Setting response {}", response); + final MessageNode messageNode = chatMessage.getMessageNode(); + messageNode.setRuneLiteFormatMessage(response); + chatMessageManager.update(messageNode); + client.refreshChat(); + } + private void questPointsLookup(ChatMessage chatMessage, String message) { if (!config.qp()) @@ -1231,4 +1366,4 @@ public class ChatCommandsPlugin extends Plugin return WordUtils.capitalize(boss); } } -} +} \ No newline at end of file diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/chattranslation/ChatTranslationConfig.java b/runelite-client/src/main/java/net/runelite/client/plugins/chattranslation/ChatTranslationConfig.java new file mode 100644 index 0000000000..32e8481c7c --- /dev/null +++ b/runelite-client/src/main/java/net/runelite/client/plugins/chattranslation/ChatTranslationConfig.java @@ -0,0 +1,91 @@ +package net.runelite.client.plugins.chattranslation; + +import net.runelite.client.config.Config; +import net.runelite.client.config.ConfigGroup; +import net.runelite.client.config.ConfigItem; + +@ConfigGroup("chattranslation") +public interface ChatTranslationConfig extends Config +{ + + @ConfigItem( + keyName = "translateOptionVisable", + name = "Show 'Translate' menu option", + description = "Adds 'Translate' to the right-click menu in the Chatbox.", + position = 0, + group = "Public Chat Translation" + ) + default boolean translateOptionVisable() + { + return true; + } + + @ConfigItem( + keyName = "publicChat", + name = "Translate incoming Messages", + description = "Would you like to Translate Public Chat?", + position = 1, + group = "Public Chat Translation", + hidden = true, + unhide = "translateOptionVisable" + ) + default boolean publicChat() + { + return false; + } + + @ConfigItem( + keyName = "playerNames", + name = "Translated Player list:", + description = "Players you add to this list will be Translated in Public chat.", + position = 2, + group = "Public Chat Translation", + hidden = true, + unhide = "translateOptionVisable" + ) + default String getPlayerNames() + { + return ""; + } + + @ConfigItem( + keyName = "publicTargetLanguage", + name = "Target Language", + description = "Language to translate messages too.", + position = 2, + group = "Public Chat Translation", + hidden = true, + unhide = "publicChat" + ) + default Languages publicTargetLanguage() + { + return Languages.ENGLISH; + } + + @ConfigItem( + keyName = "playerChat", + name = "Translate outgoing Messages", + description = "Would you like to Translate your Messages?", + position = 3, + group = "Player Message Translation" + ) + default boolean playerChat() + { + return false; + } + + @ConfigItem( + keyName = "playerTargetLanguage", + name = "Target Language", + description = "Language to translate messages too.", + position = 4, + group = "Player Message Translation", + hidden = true, + unhide = "playerChat" + ) + default Languages playerTargetLanguage() + { + return Languages.SPANISH; + } + +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/chattranslation/ChatTranslationPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/chattranslation/ChatTranslationPlugin.java new file mode 100644 index 0000000000..65668483e2 --- /dev/null +++ b/runelite-client/src/main/java/net/runelite/client/plugins/chattranslation/ChatTranslationPlugin.java @@ -0,0 +1,280 @@ +package net.runelite.client.plugins.chattranslation; + +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ObjectArrays; +import com.google.inject.Provides; +import net.runelite.api.*; +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.Widget; +import net.runelite.api.widgets.WidgetInfo; +import net.runelite.client.callback.ClientThread; +import net.runelite.client.chat.ChatMessageManager; +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.menus.MenuManager; +import net.runelite.client.plugins.Plugin; +import net.runelite.client.plugins.PluginDescriptor; +import net.runelite.client.plugins.PluginType; +import net.runelite.client.util.Text; +import org.apache.commons.lang3.ArrayUtils; + +import javax.inject.Inject; +import javax.inject.Provider; +import java.awt.event.KeyEvent; +import java.util.ArrayList; + +@PluginDescriptor( + name = "Chat Translator", + description = "Translates messages from one Language to another.", + tags = {"translate", "language", "english", "spanish", "dutch", "french"}, + type = PluginType.UTILITY +) +public class ChatTranslationPlugin extends Plugin implements KeyListener +{ + + private static final String TRANSLATE = "Translate"; + + private static final ImmutableList AFTER_OPTIONS = ImmutableList.of("Message", "Add ignore", "Remove friend", "Kick"); + + private ArrayList playerNames = new ArrayList<>(); + + @Inject + private Client client; + + @Inject + private ClientThread clientThread; + + @Inject + private ConfigManager configManager; + + @Inject + private Provider menuManager; + + @Inject + private ChatMessageManager chatMessageManager; + + @Inject + private KeyManager keyManager; + + @Inject + private ChatTranslationConfig config; + + @Provides + ChatTranslationConfig provideConfig(ConfigManager configManager) + { + return configManager.getConfig(ChatTranslationConfig.class); + } + + @Override + protected void startUp() throws Exception + { + if (client != null) + { + if (config.translateOptionVisable()) + { + menuManager.get().addPlayerMenuItem(TRANSLATE); + } + } + keyManager.registerKeyListener(this); + + playerNames.addAll(Text.fromCSV(config.getPlayerNames())); + } + + @Override + protected void shutDown() throws Exception + { + if (client != null) + { + if (config.translateOptionVisable()) + { + menuManager.get().removePlayerMenuItem(TRANSLATE); + } + } + keyManager.unregisterKeyListener(this); + + playerNames.clear(); + } + + @Subscribe + public void onConfigChanged(ConfigChanged event) + { + if (event.getGroup().equals("chattranslation")) + { + if (event.getKey().equals("playerNames")) + { + for (String names : Text.fromCSV(config.getPlayerNames())) + { + if (!playerNames.contains(Text.toJagexName(names))) + { + playerNames.add(Text.toJagexName(names)); + } + } + } + } + } + + @Subscribe + public void onMenuEntryAdded(MenuEntryAdded event) + { + if (!config.translateOptionVisable()) + { + return; + } + + int groupId = WidgetInfo.TO_GROUP(event.getActionParam1()); + String option = event.getOption(); + + if (groupId == WidgetInfo.CHATBOX.getGroupId()) + { + boolean after; + + if (!AFTER_OPTIONS.contains(option)) + { + return; + } + + final MenuEntry menuEntry = new MenuEntry(); + menuEntry.setOption(TRANSLATE); + menuEntry.setTarget(event.getTarget()); + menuEntry.setType(MenuAction.RUNELITE.getId()); + menuEntry.setParam0(event.getActionParam0()); + menuEntry.setParam1(event.getActionParam1()); + menuEntry.setIdentifier(event.getIdentifier()); + + MenuEntry[] newMenu = ObjectArrays.concat(menuEntry, client.getMenuEntries()); + int menuEntryCount = newMenu.length; + ArrayUtils.swap(newMenu, menuEntryCount - 1, menuEntryCount - 2); + client.setMenuEntries(newMenu); + } + } + + @Subscribe + public void onPlayerMenuOptionClicked(PlayerMenuOptionClicked event) + { + if (event.getMenuOption().equals(TRANSLATE)) + { + String name = Text.toJagexName(event.getMenuTarget()); + if (!playerNames.contains(name)) + { + playerNames.add(name); + } + + configManager.setConfiguration("chattranslation", "playerNames", Text.toCSV(playerNames)); + configManager.sendConfig(); + } + } + + @Subscribe + public void onChatMessage(ChatMessage chatMessage) + { + if (client.getGameState() != GameState.LOADING && client.getGameState() != GameState.LOGGED_IN) + { + return; + } + switch (chatMessage.getType()) + { + case PUBLICCHAT: + case MODCHAT: + if (!config.publicChat()) + { + return; + } + break; + default: + return; + } + + for (String nameList : playerNames) + { + if (nameList.contains(Text.toJagexName(chatMessage.getName()))) + { + String message = chatMessage.getMessage(); + + Translator translator = new Translator(); + + try + { + //Automatically check language of message and translate to selected language. + String translation = translator.translate("auto", config.publicTargetLanguage().toString(), message); + if (translation != null) + { + final MessageNode messageNode = chatMessage.getMessageNode(); + messageNode.setRuneLiteFormatMessage(translation); + chatMessageManager.update(messageNode); + } + } + catch (Exception e) + { + e.printStackTrace(); + } + + client.refreshChat(); + } + } + } + + @Override + public void keyPressed(KeyEvent event) + { + if (client.getGameState() != GameState.LOADING && client.getGameState() != GameState.LOGGED_IN) + { + return; + } + + if (!config.playerChat()) + { + return; + } + + Widget chatboxParent = client.getWidget(WidgetInfo.CHATBOX_PARENT); + + if (chatboxParent != null && chatboxParent.getOnKeyListener() != null) + { + if (event.getKeyCode() == 0xA) + { + event.consume(); + + Translator translator = new Translator(); + String message = client.getVar(VarClientStr.CHATBOX_TYPED_TEXT); + + try + { + //Automatically check language of message and translate to selected language. + String translation = translator.translate("auto", config.playerTargetLanguage().toString(), message); + if (translation != null) + { + client.setVar(VarClientStr.CHATBOX_TYPED_TEXT, translation); + + clientThread.invoke(() -> + { + client.runScript(96, 0, translation); + }); + } + client.setVar(VarClientStr.CHATBOX_TYPED_TEXT, ""); + } + catch (Exception e) + { + e.printStackTrace(); + } + } + } + } + + @Override + public void keyReleased(KeyEvent e) + { + // Nothing. + } + + @Override + public void keyTyped(KeyEvent e) + { + // Nothing. + } + +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/chattranslation/Languages.java b/runelite-client/src/main/java/net/runelite/client/plugins/chattranslation/Languages.java new file mode 100644 index 0000000000..3ec7b3ad81 --- /dev/null +++ b/runelite-client/src/main/java/net/runelite/client/plugins/chattranslation/Languages.java @@ -0,0 +1,24 @@ +package net.runelite.client.plugins.chattranslation; + +public enum Languages +{ + + ENGLISH("en"), + DUTCH("nl"), + SPANISH("es"), + FRENCH("fr"); + + private final String shortName; + + Languages(String shortName) + { + this.shortName = shortName; + } + + @Override + public String toString() + { + return shortName; + } + +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/chattranslation/Translator.java b/runelite-client/src/main/java/net/runelite/client/plugins/chattranslation/Translator.java new file mode 100644 index 0000000000..df8f26ea29 --- /dev/null +++ b/runelite-client/src/main/java/net/runelite/client/plugins/chattranslation/Translator.java @@ -0,0 +1,46 @@ +package net.runelite.client.plugins.chattranslation; + +import org.json.JSONArray; + +import java.io.BufferedReader; +import java.io.InputStreamReader; +import java.net.HttpURLConnection; +import java.net.URL; +import java.net.URLEncoder; + +public class Translator +{ + + public String translate(String source, String target, String message) throws Exception + { + + String url = "https://translate.googleapis.com/translate_a/single?client=gtx&sl=" + source + "&tl=" + target + "&dt=t&q=" + URLEncoder.encode(message, "UTF-8"); + + URL obj = new URL(url); + HttpURLConnection con = (HttpURLConnection) obj.openConnection(); + con.setRequestProperty("User-Agent", "Mozilla/5.0"); + + BufferedReader in = new BufferedReader(new InputStreamReader(con.getInputStream())); + String inputLine; + StringBuffer response = new StringBuffer(); + + while ((inputLine = in.readLine()) != null) + { + response.append(inputLine); + } + in.close(); + + return parseResult(response.toString()); + } + + private String parseResult(String inputJson) throws Exception + { + //TODO: find a way to do this using google.gson + JSONArray jsonArray = new JSONArray(inputJson); + JSONArray jsonArray2 = (JSONArray) jsonArray.get(0); + JSONArray jsonArray3 = (JSONArray) jsonArray2.get(0); + + return jsonArray3.get(0).toString(); + } + +} 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 725d17622c..3d71281cd7 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 @@ -80,7 +80,7 @@ public class CrypticClue extends ClueScroll implements TextClueScroll, NpcClueSc new CrypticClue("Speak to the bartender of the Blue Moon Inn in Varrock.", "Bartender", new WorldPoint(3226, 3399, 0), "Talk to the bartender in Blue Moon Inn in Varrock."), new CrypticClue("This aviator is at the peak of his profession.", "Captain Bleemadge", new WorldPoint(2846, 1749, 0), "Captain Bleemadge, the gnome glider pilot, is found at the top of White Wolf Mountain."), new CrypticClue("Search the crates in the shed just north of East Ardougne.", CRATE_355, new WorldPoint(2617, 3347, 0), "The crates in the shed north of the northern Ardougne bank."), - new CrypticClue("I wouldn't wear this jean on my legs.", "Father Jean", new WorldPoint(1697, 3574, 0), "Talk to father Jean in the Hosidius church"), + new CrypticClue("I wouldn't wear this jean on my legs.", "Father Jean", new WorldPoint(1734, 3576, 0), "Talk to father Jean in the Hosidius church"), new CrypticClue("Search the crate in the Toad and Chicken pub.", CRATE_354, new WorldPoint(2913, 3536, 0), "The Toad and Chicken pub is located in Burthorpe."), new CrypticClue("Search chests found in the upstairs of shops in Port Sarim.", CLOSED_CHEST_375, new WorldPoint(3016, 3205, 1), "Search the chest in the upstairs of Wydin's Food Store, on the east wall."), new CrypticClue("Right on the blessed border, cursed by the evil ones. On the spot inaccessible by both; I will be waiting. The bugs' imminent possession holds the answer.", new WorldPoint(3410, 3324, 0), "B I P. Dig right under the fairy ring."), 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 762bda9ad9..8136d00117 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,5 +1,6 @@ /* * Copyright (c) 2018, Eadgars Ruse + * Copyright (c) 2019, Jordan Atwood * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -24,21 +25,19 @@ */ 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.Collection; +import java.util.EnumMap; import java.util.Map; -import java.util.regex.Matcher; -import java.util.regex.Pattern; +import java.util.Set; +import java.util.stream.Collectors; +import javax.annotation.Nullable; +import lombok.EqualsAndHashCode; import lombok.Getter; +import lombok.extern.slf4j.Slf4j; import net.runelite.api.NPC; import net.runelite.api.coords.LocalPoint; import net.runelite.api.coords.WorldPoint; @@ -47,35 +46,45 @@ 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.plugins.cluescrolls.clues.hotcold.HotColdSolver; +import net.runelite.client.plugins.cluescrolls.clues.hotcold.HotColdTemperature; +import net.runelite.client.plugins.cluescrolls.clues.hotcold.HotColdTemperatureChange; 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; +@EqualsAndHashCode(callSuper = false, exclude = { "hotColdSolver", "location" }) @Getter +@Slf4j 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."); + private static final int HOT_COLD_PANEL_WIDTH = 200; + private static final HotColdClue BEGINNER_CLUE = new HotColdClue("Buried beneath the ground, who knows where it's found. Lucky for you, A man called Reldo may have a clue.", + "Reldo", + "Speak to Reldo to receive a strange device."); + private static final HotColdClue MASTER_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; + @Nullable + private HotColdSolver hotColdSolver; private WorldPoint location; - private WorldPoint lastWorldPoint; public static HotColdClue forText(String text) { - if (CLUE.text.equalsIgnoreCase(text)) + if (BEGINNER_CLUE.text.equalsIgnoreCase(text)) { - return CLUE; + BEGINNER_CLUE.reset(); + return BEGINNER_CLUE; + } + else if (MASTER_CLUE.text.equalsIgnoreCase(text)) + { + MASTER_CLUE.reset(); + return MASTER_CLUE; } return null; @@ -87,24 +96,35 @@ public class HotColdClue extends ClueScroll implements LocationClueScroll, Locat this.npc = npc; this.solution = solution; setRequiresSpade(true); + initializeSolver(); } @Override public WorldPoint[] getLocations() { - return Lists.transform(digLocations, HotColdLocation::getWorldPoint).toArray(new WorldPoint[0]); + if (hotColdSolver == null) + { + return new WorldPoint[0]; + } + + return hotColdSolver.getPossibleLocations().stream().map(HotColdLocation::getWorldPoint).toArray(WorldPoint[]::new); } @Override public void makeOverlayHint(PanelComponent panelComponent, ClueScrollPlugin plugin) { + if (hotColdSolver == null) + { + return; + } + panelComponent.getChildren().add(TitleComponent.builder() .text("Hot/Cold Clue") .build()); - panelComponent.setPreferredSize(new Dimension(200, 0)); + panelComponent.setPreferredSize(new Dimension(HOT_COLD_PANEL_WIDTH, 0)); // strange device has not been tested yet, show how to get it - if (lastWorldPoint == null && location == null) + if (hotColdSolver.getLastWorldPoint() == null && location == null) { if (getNpc() != null) { @@ -131,7 +151,9 @@ public class HotColdClue extends ClueScroll implements LocationClueScroll, Locat panelComponent.getChildren().add(LineComponent.builder() .left("Possible areas:") .build()); - Map locationCounts = new HashMap<>(); + + final Map locationCounts = new EnumMap<>(HotColdArea.class); + final Collection digLocations = hotColdSolver.getPossibleLocations(); for (HotColdLocation hotColdLocation : digLocations) { @@ -159,17 +181,16 @@ public class HotColdClue extends ClueScroll implements LocationClueScroll, Locat } else { - for (HotColdArea s : locationCounts.keySet()) + for (HotColdArea area : locationCounts.keySet()) { panelComponent.getChildren().add(LineComponent.builder() - .left(s.getName() + ":") + .left(area.getName() + ':') .build()); for (HotColdLocation hotColdLocation : digLocations) { - if (hotColdLocation.getHotColdArea() == s) + if (hotColdLocation.getHotColdArea() == area) { - Rectangle2D r = hotColdLocation.getRect(); panelComponent.getChildren().add(LineComponent.builder() .left("- " + hotColdLocation.getArea()) .leftColor(Color.LIGHT_GRAY) @@ -184,8 +205,13 @@ public class HotColdClue extends ClueScroll implements LocationClueScroll, Locat @Override public void makeWorldOverlayHint(Graphics2D graphics, ClueScrollPlugin plugin) { + if (hotColdSolver == null) + { + return; + } + // when final location has been found - if (this.location != null) + if (location != null) { LocalPoint localLocation = LocalPoint.fromWorld(plugin.getClient(), getLocation()); @@ -197,20 +223,17 @@ public class HotColdClue extends ClueScroll implements LocationClueScroll, Locat return; } - // when strange device hasn't been activated yet, show Jorral - if (lastWorldPoint == null) + // when strange device hasn't been activated yet, show npc who gives you the strange device + if (hotColdSolver.getLastWorldPoint() == null && plugin.getNpcsToMark() != null) { - // Mark NPC - if (plugin.getNpcsToMark() != null) + for (NPC npcToMark : plugin.getNpcsToMark()) { - for (NPC npc : plugin.getNpcsToMark()) - { - OverlayUtil.renderActorOverlayImage(graphics, npc, plugin.getClueScrollImage(), Color.ORANGE, IMAGE_Z_OFFSET); - } + OverlayUtil.renderActorOverlayImage(graphics, npcToMark, plugin.getClueScrollImage(), Color.ORANGE, IMAGE_Z_OFFSET); } } // once the number of possible dig locations is below 10, show the dig spots + final Collection digLocations = hotColdSolver.getPossibleLocations(); if (digLocations.size() < 10) { // Mark potential dig locations @@ -231,171 +254,87 @@ public class HotColdClue extends ClueScroll implements LocationClueScroll, Locat public boolean update(final String message, final ClueScrollPlugin plugin) { - if (!message.startsWith("The device is")) + if (hotColdSolver == null) { 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); + final Set temperatureSet; - // the order that these pattern matchers are checked is important - if (m1.find()) + if (this.equals(BEGINNER_CLUE)) { - // final location for hot cold clue has been found - WorldPoint localWorld = plugin.getClient().getLocalPlayer().getWorldLocation(); - - if (localWorld != null) - { - markFinalSpot(localWorld); - return true; - } + temperatureSet = HotColdTemperature.BEGINNER_HOT_COLD_TEMPERATURES; } - else if (m2.find()) + else if (this.equals(MASTER_CLUE)) { - 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; - } + temperatureSet = HotColdTemperature.MASTER_HOT_COLD_TEMPERATURES; } - else if (m3.find()) + else { - String temperature = m3.group(1); - WorldPoint localWorld = plugin.getClient().getLocalPlayer().getWorldLocation(); - - if (localWorld != null) - { - updatePossibleArea(localWorld, temperature, ""); - return true; - } + temperatureSet = null; } - return false; + final HotColdTemperature temperature = HotColdTemperature.getFromTemperatureSet(temperatureSet, message); + + if (temperature == null) + { + return false; + } + + final WorldPoint localWorld = plugin.getClient().getLocalPlayer().getWorldLocation(); + + if (localWorld == null) + { + return false; + } + + if ((this.equals(BEGINNER_CLUE) && temperature == HotColdTemperature.BEGINNER_VISIBLY_SHAKING) + || (this.equals(MASTER_CLUE) && temperature == HotColdTemperature.MASTER_VISIBLY_SHAKING)) + { + markFinalSpot(localWorld); + } + else + { + location = null; + + final HotColdTemperatureChange temperatureChange = HotColdTemperatureChange.of(message); + hotColdSolver.signal(localWorld, temperature, temperatureChange); + } + + return true; } @Override public void reset() { - this.lastWorldPoint = null; - digLocations.clear(); + initializeSolver(); } - private void updatePossibleArea(WorldPoint currentWp, String temperature, String difference) + private void initializeSolver() { - this.location = null; + final boolean isBeginner; - if (digLocations.isEmpty()) + if (this.equals(BEGINNER_CLUE)) { - digLocations.addAll(Arrays.asList(HotColdLocation.values())); + isBeginner = true; + } + else if (this.equals(MASTER_CLUE)) + { + isBeginner = false; } - int maxSquaresAway = 5000; - int minSquaresAway = 0; - - switch (temperature) + else { - // 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; + log.warn("Hot cold solver could not be initialized, clue type is unknown; text: {}, npc: {}, solution: {}", + text, npc, solution); + hotColdSolver = null; + return; } - // 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); + final Set locations = Arrays.stream(HotColdLocation.values()) + .filter(l -> l.isBeginnerClue() == isBeginner) + .collect(Collectors.toSet()); + hotColdSolver = new HotColdSolver(locations); } private void markFinalSpot(WorldPoint wp) @@ -408,4 +347,4 @@ public class HotColdClue extends ClueScroll implements LocationClueScroll, Locat { return new String[]{npc}; } -} \ No newline at end of file +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/clues/hotcold/HotColdLocation.java b/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/clues/hotcold/HotColdLocation.java index e41fd5357e..b3bd0c91db 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/clues/hotcold/HotColdLocation.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/clues/hotcold/HotColdLocation.java @@ -1,6 +1,7 @@ /* * Copyright (c) 2018, Eadgars Ruse * Copyright (c) 2018, Adam + * Copyright (c) 2019, Jordan Atwood * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -26,7 +27,6 @@ package net.runelite.client.plugins.cluescrolls.clues.hotcold; import java.awt.Rectangle; -import java.awt.geom.Rectangle2D; import lombok.AllArgsConstructor; import lombok.Getter; import net.runelite.api.coords.WorldPoint; @@ -69,6 +69,8 @@ public enum HotColdLocation DESERT_POLLNIVNEACH(new WorldPoint(3287, 2975, 0), DESERT, "West of Pollnivneach."), DESERT_MTA(new WorldPoint(3350, 3293, 0), DESERT, "Next to Mage Training Arena."), DESERT_SHANTY(new WorldPoint(3294, 3106, 0), DESERT, "South-west of Shantay Pass."), + DRAYNOR_MANOR_MUSHROOMS(true, new WorldPoint(3096, 3379, 0), MISTHALIN, "Patch of mushrooms just northwest of Draynor Manor"), + DRAYNOR_WHEAT_FIELD(true, new WorldPoint(3120, 3282, 0), MISTHALIN, "Inside the wheat field next to Draynor Village"), FELDIP_HILLS_JIGGIG(new WorldPoint(2413, 3055, 0), FELDIP_HILLS, "West of Jiggig, east of the fairy ring bkp."), FELDIP_HILLS_SW(new WorldPoint(2582, 2895, 0), FELDIP_HILLS, "West of the southeasternmost lake in Feldip Hills."), FELDIP_HILLS_GNOME_GLITER(new WorldPoint(2553, 2972, 0), FELDIP_HILLS, "East of the gnome glider (Lemantolly Undri)."), @@ -91,6 +93,7 @@ public enum HotColdLocation FREMENNIK_PROVINCE_ASTRAL_ALTER(new WorldPoint(2147, 3862, 0), FREMENNIK_PROVINCE, "Astral altar"), FREMENNIK_PROVINCE_LUNAR_VILLAGE(new WorldPoint(2087, 3915, 0), FREMENNIK_PROVINCE, "Lunar Isle, inside the village."), FREMENNIK_PROVINCE_LUNAR_NORTH(new WorldPoint(2106, 3949, 0), FREMENNIK_PROVINCE, "Lunar Isle, north of the village."), + ICE_MOUNTAIN(true, new WorldPoint(3007, 3475, 0), MISTHALIN, "Atop Ice Mountain"), KANDARIN_SINCLAR_MANSION(new WorldPoint(2726, 3588, 0), KANDARIN, "North-west of the Sinclair Mansion, near the log balance shortcut."), KANDARIN_CATHERBY(new WorldPoint(2774, 3433, 0), KANDARIN, "Catherby, between the bank and the beehives, near small rock formation."), KANDARIN_GRAND_TREE(new WorldPoint(2444, 3503, 0), KANDARIN, "Grand Tree, just east of the terrorchick gnome enclosure."), @@ -115,6 +118,7 @@ public enum HotColdLocation KARAMJA_KHARAZI_NE(new WorldPoint(2904, 2925, 0), KARAMJA, "North-eastern part of Kharazi Jungle."), KARAMJA_KHARAZI_SW(new WorldPoint(2783, 2898, 0), KARAMJA, "South-western part of Kharazi Jungle."), KARAMJA_CRASH_ISLAND(new WorldPoint(2910, 2737, 0), KARAMJA, "Northern part of Crash Island."), + LUMBRIDGE_COW_FIELD(true, new WorldPoint(3174, 3336, 0), MISTHALIN, "Cow field north of Lumbridge"), MISTHALIN_VARROCK_STONE_CIRCLE(new WorldPoint(3225, 3355, 0), MISTHALIN, "South of the stone circle near Varrock's entrance."), MISTHALIN_LUMBRIDGE(new WorldPoint(3238, 3169, 0), MISTHALIN, "Just north-west of the Lumbridge Fishing tutor."), MISTHALIN_LUMBRIDGE_2(new WorldPoint(3170, 3278, 0), MISTHALIN, "North of the pond between Lumbridge and Draynor Village."), @@ -131,6 +135,7 @@ public enum HotColdLocation MORYTANIA_MOS_LES_HARMLESS_BAR(new WorldPoint(3670, 2974, 0), MORYTANIA, "Near Mos Le'Harmless southern bar."), MORYTANIA_DRAGONTOOTH_NORTH(new WorldPoint(3813, 3567, 0), MORYTANIA, "Northern part of Dragontooth Island."), MORYTANIA_DRAGONTOOTH_SOUTH(new WorldPoint(3803, 3532, 0), MORYTANIA, "Southern part of Dragontooth Island."), + NORTHEAST_OF_AL_KHARID_MINE(true, new WorldPoint(3332, 3313, 0), MISTHALIN, "Northeast of Al Kharid Mine"), WESTERN_PROVINCE_EAGLES_PEAK(new WorldPoint(2297, 3530, 0), WESTERN_PROVINCE, "North-west of Eagles' Peak."), WESTERN_PROVINCE_PISCATORIS(new WorldPoint(2337, 3689, 0), WESTERN_PROVINCE, "Piscatoris Fishing Colony"), WESTERN_PROVINCE_PISCATORIS_HUNTER_AREA(new WorldPoint(2361, 3566, 0), WESTERN_PROVINCE, "Eastern part of Piscatoris Hunter area, south-west of the Falconry."), @@ -176,12 +181,20 @@ public enum HotColdLocation ZEAH_DAIRY_COW(new WorldPoint(1320, 3718, 0), ZEAH, "North-east of the Kebos Lowlands, east of the dairy cow."), ZEAH_CRIMSON_SWIFTS(new WorldPoint(1186, 3583, 0), ZEAH, "South-west of the Kebos Swamp, below the crimson swifts."); + private final boolean beginnerClue; private final WorldPoint worldPoint; private final HotColdArea hotColdArea; private final String area; - public Rectangle2D getRect() + HotColdLocation(WorldPoint worldPoint, HotColdArea hotColdArea, String areaDescription) { - return new Rectangle(worldPoint.getX() - 4, worldPoint.getY() - 4, 9, 9); + this(false, worldPoint, hotColdArea, areaDescription); + } + + public Rectangle getRect() + { + final int digRadius = beginnerClue ? HotColdTemperature.BEGINNER_VISIBLY_SHAKING.getMaxDistance() : + HotColdTemperature.MASTER_VISIBLY_SHAKING.getMaxDistance(); + return new Rectangle(worldPoint.getX() - digRadius, worldPoint.getY() - digRadius, digRadius * 2 + 1, digRadius * 2 + 1); } } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/clues/hotcold/HotColdSolver.java b/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/clues/hotcold/HotColdSolver.java new file mode 100644 index 0000000000..87414f0387 --- /dev/null +++ b/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/clues/hotcold/HotColdSolver.java @@ -0,0 +1,167 @@ +/* + * Copyright (c) 2018, Eadgars Ruse + * 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.cluescrolls.clues.hotcold; + +import com.google.common.annotations.VisibleForTesting; +import java.awt.Rectangle; +import java.util.Set; +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +import lombok.Getter; +import net.runelite.api.coords.WorldPoint; + +/** + * Solution finder for hot-cold style puzzles. + *

+ * These puzzles are established by having some way to test the distance from the solution via "warmth", where being + * colder means one is farther away from the target, and being warmer means one is closer to it, with the goal being to + * reach the most warm value to discover the solution point. Hot-cold puzzles in Old School Runescape are implemented + * with specific set of solution points, so this solver will filter from a provided set of possible solutions as new + * signals of temperatures and temperature changes are provided. + */ +@Getter +public class HotColdSolver +{ + private final Set possibleLocations; + @Nullable + private WorldPoint lastWorldPoint; + + public HotColdSolver(Set possibleLocations) + { + this.possibleLocations = possibleLocations; + } + + /** + * Process a hot-cold update given a {@link WorldPoint} where a check occurred and the resulting temperature and + * temperature change discovered at that point. This will filter the set of possible locations which can be the + * solution. + * + * @param worldPoint The point where a hot-cold check occurred + * @param temperature The temperature of the checked point + * @param temperatureChange The change of temperature of the checked point compared to the previously-checked point + * @return A set of {@link HotColdLocation}s which are still possible after the filtering occurs. This return value + * is the same as would be returned by {@code getPossibleLocations()}. + */ + public Set signal(@Nonnull final WorldPoint worldPoint, @Nonnull final HotColdTemperature temperature, @Nullable final HotColdTemperatureChange temperatureChange) + { + // 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) + int maxSquaresAway = temperature.getMaxDistance(); + int minSquaresAway = temperature.getMinDistance(); + + // maxDistanceArea encompasses all of the points that are within the max possible distance from the player + final Rectangle maxDistanceArea = new Rectangle( + worldPoint.getX() - maxSquaresAway, + worldPoint.getY() - maxSquaresAway, + 2 * maxSquaresAway + 1, + 2 * maxSquaresAway + 1); + // minDistanceArea encompasses all of the points that are within the min possible distance from the player + final Rectangle minDistanceArea = new Rectangle( + worldPoint.getX() - minSquaresAway, + worldPoint.getY() - minSquaresAway, + 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 + possibleLocations.removeIf(entry -> minDistanceArea.contains(entry.getRect()) || !maxDistanceArea.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 && temperatureChange != null) + { + switch (temperatureChange) + { + case COLDER: + // eliminate spots that are absolutely warmer + possibleLocations.removeIf(entry -> isFirstPointCloserRect(worldPoint, lastWorldPoint, entry.getRect())); + break; + case WARMER: + // eliminate spots that are absolutely colder + possibleLocations.removeIf(entry -> isFirstPointCloserRect(lastWorldPoint, worldPoint, entry.getRect())); + break; + case SAME: + // I couldn't figure out a clean implementation for this case + // not necessary for quickly determining final location + } + } + + lastWorldPoint = worldPoint; + return getPossibleLocations(); + } + + /** + * Determines whether the first point passed is closer to each corner of the given rectangle than the second point. + * + * @param firstPoint First point to test. Return result will be relating to this point's location. + * @param secondPoint Second point to test + * @param rect Rectangle, whose corner points will be compared to the first and second points passed + * @return {@code true} if {@code firstPoint} is closer to each of {@code rect}'s four corner points than + * {@code secondPoint}, {@code false} otherwise. + * @see WorldPoint#distanceTo2D + */ + @VisibleForTesting + static boolean isFirstPointCloserRect(final WorldPoint firstPoint, final WorldPoint secondPoint, final Rectangle rect) + { + final WorldPoint nePoint = new WorldPoint((rect.x + rect.width), (rect.y + rect.height), 0); + + if (!isFirstPointCloser(firstPoint, secondPoint, nePoint)) + { + return false; + } + + final WorldPoint sePoint = new WorldPoint((rect.x + rect.width), rect.y, 0); + + if (!isFirstPointCloser(firstPoint, secondPoint, sePoint)) + { + return false; + } + + final WorldPoint nwPoint = new WorldPoint(rect.x, (rect.y + rect.height), 0); + + if (!isFirstPointCloser(firstPoint, secondPoint, nwPoint)) + { + return false; + } + + final WorldPoint swPoint = new WorldPoint(rect.x, rect.y, 0); + return (isFirstPointCloser(firstPoint, secondPoint, swPoint)); + } + + /** + * Determines whether the first point passed is closer to the given point of comparison than the second point. + * + * @param firstPoint First point to test. Return result will be relating to this point's location. + * @param secondPoint Second point to test + * @param worldPoint Point to compare to the first and second points passed + * @return {@code true} if {@code firstPoint} is closer to {@code worldPoint} than {@code secondPoint}, + * {@code false} otherwise. + * @see WorldPoint#distanceTo2D + */ + @VisibleForTesting + static boolean isFirstPointCloser(final WorldPoint firstPoint, final WorldPoint secondPoint, final WorldPoint worldPoint) + { + return firstPoint.distanceTo2D(worldPoint) < secondPoint.distanceTo2D(worldPoint); + } +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/clues/hotcold/HotColdTemperature.java b/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/clues/hotcold/HotColdTemperature.java new file mode 100644 index 0000000000..2dc5909000 --- /dev/null +++ b/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/clues/hotcold/HotColdTemperature.java @@ -0,0 +1,112 @@ +/* + * 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.cluescrolls.clues.hotcold; + +import com.google.common.collect.Sets; +import java.util.ArrayList; +import java.util.Comparator; +import java.util.List; +import java.util.Set; +import javax.annotation.Nullable; +import lombok.AllArgsConstructor; +import lombok.Getter; + +@AllArgsConstructor +@Getter +public enum HotColdTemperature +{ + ICE_COLD("ice cold", 500, 5000), + VERY_COLD("very cold", 200, 499), + COLD("cold", 150, 199), + WARM("warm", 100, 149), + HOT("hot", 70, 99), + VERY_HOT("very hot", 30, 69), + BEGINNER_INCREDIBLY_HOT("incredibly hot", 4, 29), + BEGINNER_VISIBLY_SHAKING("visibly shaking", 0, 3), + MASTER_INCREDIBLY_HOT("incredibly hot", 5, 29), + MASTER_VISIBLY_SHAKING("visibly shaking", 0, 4); + + public static final Set BEGINNER_HOT_COLD_TEMPERATURES = Sets.immutableEnumSet( + ICE_COLD, + VERY_COLD, + COLD, + WARM, + HOT, + VERY_HOT, + BEGINNER_INCREDIBLY_HOT, + BEGINNER_VISIBLY_SHAKING + ); + public static final Set MASTER_HOT_COLD_TEMPERATURES = Sets.immutableEnumSet( + ICE_COLD, + VERY_COLD, + COLD, + WARM, + HOT, + VERY_HOT, + MASTER_INCREDIBLY_HOT, + MASTER_VISIBLY_SHAKING + ); + + private final String text; + private final int minDistance; + private final int maxDistance; + + private static final String DEVICE_USED_START_TEXT = "The device is "; + + /** + * Gets the temperature from a set of temperatures corresponding to the passed string. + * + * @param temperatureSet A set of temperature values to select from + * @param message A string containing a temperature value + * @return The corresponding enum from the given temperature set. + *

+ * Note that in cases where two temperature values in the given set are equally likely to be the given + * temperature (say, two temperatures with identical text values), the behavior is undefined. + */ + @Nullable + public static HotColdTemperature getFromTemperatureSet(final Set temperatureSet, final String message) + { + if (!message.startsWith(DEVICE_USED_START_TEXT) || temperatureSet == null) + { + return null; + } + + final List possibleTemperatures = new ArrayList<>(); + + for (final HotColdTemperature temperature : temperatureSet) + { + if (message.contains(temperature.getText())) + { + possibleTemperatures.add(temperature); + } + } + + return possibleTemperatures.stream() + // For messages such as "The device is very cold", this will choose the Enum with text of greatest length so + // that VERY_COLD would be selected over COLD, though both Enums have matching text for this message. + .max(Comparator.comparingInt(x -> (x.getText()).length())) + .orElse(null); + } +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/clues/hotcold/HotColdTemperatureChange.java b/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/clues/hotcold/HotColdTemperatureChange.java new file mode 100644 index 0000000000..e9077bc9e1 --- /dev/null +++ b/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/clues/hotcold/HotColdTemperatureChange.java @@ -0,0 +1,55 @@ +/* + * 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.cluescrolls.clues.hotcold; + +import lombok.AllArgsConstructor; + +@AllArgsConstructor +public enum HotColdTemperatureChange +{ + WARMER("and warmer than"), + SAME("and the same temperature as"), + COLDER("but colder than"); + + private final String text; + + public static HotColdTemperatureChange of(final String message) + { + if (!message.endsWith(" last time.")) + { + return null; + } + + for (final HotColdTemperatureChange change : values()) + { + if (message.contains(change.text)) + { + return change; + } + } + + return null; + } +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/devtools/DevToolsButton.java b/runelite-client/src/main/java/net/runelite/client/plugins/devtools/DevToolsButton.java index 52de0309a9..e21af75f5a 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/devtools/DevToolsButton.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/devtools/DevToolsButton.java @@ -37,6 +37,7 @@ class DevToolsButton extends JButton { super(title); addActionListener((ev) -> setActive(!active)); + this.setToolTipText(title); } void setActive(boolean active) diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/fightcave/FightCaveConfig.java b/runelite-client/src/main/java/net/runelite/client/plugins/fightcave/FightCaveConfig.java index f1e5457f7a..72c21243c5 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/fightcave/FightCaveConfig.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/fightcave/FightCaveConfig.java @@ -24,20 +24,119 @@ */ package net.runelite.client.plugins.fightcave; +import java.awt.Font; +import lombok.AllArgsConstructor; +import lombok.Getter; 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 net.runelite.client.config.Stub; @ConfigGroup("fightcave") public interface FightCaveConfig extends Config { @ConfigItem( + position = 0, + keyName = "mainConfig", + name = "Main Config", + description = "" + ) + default Stub mainConfig() + { + return new Stub(); + } + + @ConfigItem( + position = 1, keyName = "waveDisplay", name = "Wave display", - description = "Shows monsters that will spawn on the selected wave(s)." + description = "Shows monsters that will spawn on the selected wave(s).", + parent = "mainConfig" ) default WaveDisplayMode waveDisplay() { return WaveDisplayMode.BOTH; } + + @ConfigItem( + position = 2, + keyName = "tickTimersWidget", + name = "Tick Timers in Prayer", + description = "Adds an overlay to the Praayer Interface with the ticks until next attack for that prayer.", + parent = "mainConfig" + ) + default boolean tickTimersWidget() + { + return true; + } + + @ConfigItem( + position = 3, + keyName = "text", + name = "Text", + description = "" + ) + default Stub text() + { + return new Stub(); + } + + @ConfigItem( + position = 4, + keyName = "fontStyle", + name = "Font Style", + description = "Plain | Bold | Italics", + parent = "text" + ) + default FontStyle fontStyle() + { + return FontStyle.BOLD; + } + + @Range( + min = 14, + max = 40 + ) + @ConfigItem( + position = 5, + keyName = "textSize", + name = "Text Size", + description = "Text Size for Timers.", + parent = "text" + ) + default int textSize() + { + return 32; + } + + @ConfigItem( + position = 6, + keyName = "shadows", + name = "Shadows", + description = "Adds Shadows to text.", + parent = "text" + ) + default boolean shadows() + { + return false; + } + + @Getter + @AllArgsConstructor + enum FontStyle + { + BOLD("Bold", Font.BOLD), + ITALIC("Italic", Font.ITALIC), + PLAIN("Plain", Font.PLAIN); + + private String name; + private int font; + + @Override + public String toString() + { + return getName(); + } + } } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/fightcave/FightCaveContainer.java b/runelite-client/src/main/java/net/runelite/client/plugins/fightcave/FightCaveContainer.java new file mode 100644 index 0000000000..cc0f1a523c --- /dev/null +++ b/runelite-client/src/main/java/net/runelite/client/plugins/fightcave/FightCaveContainer.java @@ -0,0 +1,138 @@ +/* + * Copyright (c) 2019, Ganom + * 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.fightcave; + +import com.google.common.collect.ImmutableMap; +import com.google.common.collect.ImmutableSet; +import java.awt.Color; +import lombok.AccessLevel; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.RequiredArgsConstructor; +import lombok.Setter; +import net.runelite.api.Actor; +import net.runelite.api.AnimationID; +import net.runelite.api.NPC; +import net.runelite.api.NPCDefinition; +import net.runelite.api.NpcID; +import net.runelite.api.Prayer; + +@Getter +class FightCaveContainer +{ + private NPC npc; + private String npcName; + private int npcIndex; + private int npcSize; + private int attackSpeed; + private int priority; + private ImmutableSet animations; + @Setter + private int ticksUntilAttack; + @Setter + private Actor npcInteracting; + @Setter + private AttackStyle attackStyle; + + FightCaveContainer(NPC npc, int attackSpeed) + { + this.npc = npc; + this.npcName = npc.getName(); + this.npcIndex = npc.getIndex(); + this.npcInteracting = npc.getInteracting(); + this.attackStyle = AttackStyle.UNKNOWN; + this.attackSpeed = attackSpeed; + this.ticksUntilAttack = -1; + final NPCDefinition composition = npc.getTransformedDefinition(); + + BossMonsters monster = BossMonsters.of(npc.getId()); + + if (monster == null) + { + throw new IllegalStateException(); + } + + this.animations = monster.animations; + this.attackStyle = monster.attackStyle; + this.priority = monster.priority; + + if (composition != null) + { + this.npcSize = composition.getSize(); + } + } + + @RequiredArgsConstructor + enum BossMonsters + { + TOK_XIL1(NpcID.TOKXIL_3121, AttackStyle.RANGE, ImmutableSet.of(AnimationID.TOK_XIL_RANGE_ATTACK, AnimationID.TOK_XIL_MELEE_ATTACK), 1), + TOK_XIL2(NpcID.TOKXIL_3122, AttackStyle.RANGE, ImmutableSet.of(AnimationID.TOK_XIL_RANGE_ATTACK, AnimationID.TOK_XIL_MELEE_ATTACK), 1), + KETZEK1(NpcID.KETZEK, AttackStyle.MAGE, ImmutableSet.of(AnimationID.KET_ZEK_MAGE_ATTACK, AnimationID.KET_ZEK_MELEE_ATTACK), 0), + KETZEK2(NpcID.KETZEK_3126, AttackStyle.MAGE, ImmutableSet.of(AnimationID.KET_ZEK_MAGE_ATTACK, AnimationID.KET_ZEK_MELEE_ATTACK), 0), + YTMEJKOT1(NpcID.YTMEJKOT, AttackStyle.MELEE, ImmutableSet.of(AnimationID.MEJ_KOT_HEAL_ATTACK, AnimationID.MEJ_KOT_MELEE_ATTACK), 2), + YTMEJKOT2(NpcID.YTMEJKOT_3124, AttackStyle.MELEE, ImmutableSet.of(AnimationID.MEJ_KOT_HEAL_ATTACK, AnimationID.MEJ_KOT_MELEE_ATTACK), 2), + TZTOKJAD1(NpcID.TZTOKJAD, AttackStyle.UNKNOWN, ImmutableSet.of(AnimationID.TZTOK_JAD_MAGIC_ATTACK, AnimationID.TZTOK_JAD_RANGE_ATTACK, AnimationID.TZTOK_JAD_MELEE_ATTACK), 0), + TZTOKJAD2(NpcID.TZTOKJAD_6506, AttackStyle.UNKNOWN, ImmutableSet.of(AnimationID.TZTOK_JAD_MAGIC_ATTACK, AnimationID.TZTOK_JAD_RANGE_ATTACK, AnimationID.TZTOK_JAD_MELEE_ATTACK), 0); + + private static ImmutableMap idMap; + + static + { + ImmutableMap.Builder builder = ImmutableMap.builder(); + + for (BossMonsters monster : values()) + { + builder.put(monster.npcID, monster); + } + + idMap = builder.build(); + } + + private final int npcID; + private final AttackStyle attackStyle; + private final ImmutableSet animations; + private final int priority; + + static BossMonsters of(int npcID) + { + return idMap.get(npcID); + } + } + + @Getter(AccessLevel.PACKAGE) + @AllArgsConstructor + enum AttackStyle + { + MAGE("Mage", Color.CYAN, Prayer.PROTECT_FROM_MAGIC), + RANGE("Range", Color.GREEN, Prayer.PROTECT_FROM_MISSILES), + MELEE("Melee", Color.RED, Prayer.PROTECT_FROM_MELEE), + UNKNOWN("Unknown", Color.WHITE, null); + + private String name; + private Color color; + private Prayer prayer; + } +} \ No newline at end of file diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/fightcave/FightCaveOverlay.java b/runelite-client/src/main/java/net/runelite/client/plugins/fightcave/FightCaveOverlay.java new file mode 100644 index 0000000000..68569157d5 --- /dev/null +++ b/runelite-client/src/main/java/net/runelite/client/plugins/fightcave/FightCaveOverlay.java @@ -0,0 +1,201 @@ +/* + * Copyright (c) 2019, Ganom + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 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.Font; +import java.awt.Graphics2D; +import java.awt.Rectangle; +import java.awt.image.BufferedImage; +import javax.inject.Inject; +import net.runelite.api.Client; +import net.runelite.api.Point; +import net.runelite.api.Prayer; +import net.runelite.api.SpriteID; +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.OverlayUtil; +import net.runelite.client.util.ImageUtil; + +public class FightCaveOverlay extends Overlay +{ + private FightCavePlugin plugin; + private FightCaveConfig config; + private Client client; + private SpriteManager spriteManager; + + @Inject + FightCaveOverlay(Client client, FightCavePlugin plugin, FightCaveConfig config, SpriteManager spriteManager) + { + this.client = client; + this.plugin = plugin; + this.config = config; + this.spriteManager = spriteManager; + setPosition(OverlayPosition.DYNAMIC); + setPriority(OverlayPriority.HIGHEST); + setLayer(OverlayLayer.ALWAYS_ON_TOP); + } + + @Override + public Dimension render(Graphics2D graphics) + { + for (FightCaveContainer npc : plugin.getFightCaveContainer()) + { + if (npc.getNpc() == null) + { + continue; + } + + final int ticksLeft = npc.getTicksUntilAttack(); + final FightCaveContainer.AttackStyle attackStyle = npc.getAttackStyle(); + + if (ticksLeft <= 0) + { + continue; + } + + final String ticksLeftStr = String.valueOf(ticksLeft); + final int font = config.fontStyle().getFont(); + final boolean shadows = config.shadows(); + Color color = (ticksLeft <= 1 ? Color.WHITE : attackStyle.getColor()); + final Point canvasPoint = npc.getNpc().getCanvasTextLocation(graphics, Integer.toString(ticksLeft), 0); + + if (npc.getNpcName().equals("TzTok-Jad")) + { + color = (ticksLeft <= 1 || ticksLeft == 8 ? attackStyle.getColor() : Color.WHITE); + + BufferedImage pray = getPrayerImage(npc.getAttackStyle()); + + if (pray == null) + { + continue; + } + + renderImageLocation(graphics, npc.getNpc().getCanvasImageLocation(ImageUtil.resizeImage(pray, 36, 36), 0), pray, 12, 30); + } + + OverlayUtil.renderTextLocation(graphics, ticksLeftStr, config.textSize(), font, color, canvasPoint, shadows, 0); + } + + if (config.tickTimersWidget()) + { + + if (!plugin.getMageTicks().isEmpty()) + { + widgetHandler(graphics, + Prayer.PROTECT_FROM_MAGIC, + plugin.getMageTicks().get(0) == 1 ? Color.WHITE : Color.CYAN, + Integer.toString(plugin.getMageTicks().get(0)), + config.shadows() + ); + } + if (!plugin.getRangedTicks().isEmpty()) + { + widgetHandler(graphics, + Prayer.PROTECT_FROM_MISSILES, + plugin.getRangedTicks().get(0) == 1 ? Color.WHITE : Color.GREEN, + Integer.toString(plugin.getRangedTicks().get(0)), + config.shadows() + ); + } + if (!plugin.getMeleeTicks().isEmpty()) + { + widgetHandler(graphics, + Prayer.PROTECT_FROM_MELEE, + plugin.getMeleeTicks().get(0) == 1 ? Color.WHITE : Color.RED, + Integer.toString(plugin.getMeleeTicks().get(0)), + config.shadows() + ); + } + } + return null; + } + + private void widgetHandler(Graphics2D graphics, Prayer prayer, Color color, String ticks, boolean shadows) + { + if (prayer != null) + { + Rectangle bounds = OverlayUtil.renderPrayerOverlay(graphics, client, prayer, color); + + if (bounds != null) + { + renderTextLocation(graphics, ticks, 16, config.fontStyle().getFont(), color, centerPoint(bounds), shadows); + } + } + } + + private BufferedImage getPrayerImage(FightCaveContainer.AttackStyle attackStyle) + { + switch (attackStyle) + { + case MAGE: + return spriteManager.getSprite(SpriteID.PRAYER_PROTECT_FROM_MAGIC, 0); + case MELEE: + return spriteManager.getSprite(SpriteID.PRAYER_PROTECT_FROM_MELEE, 0); + case RANGE: + return spriteManager.getSprite(SpriteID.PRAYER_PROTECT_FROM_MISSILES, 0); + } + return null; + } + + private void renderImageLocation(Graphics2D graphics, Point imgLoc, BufferedImage image, int xOffset, int yOffset) + { + int x = imgLoc.getX() + xOffset; + int y = imgLoc.getY() - yOffset; + + graphics.drawImage(image, x, y, null); + } + + private void renderTextLocation(Graphics2D graphics, String txtString, int fontSize, int fontStyle, Color fontColor, Point canvasPoint, boolean shadows) + { + graphics.setFont(new Font("Arial", fontStyle, fontSize)); + if (canvasPoint != null) + { + final Point canvasCenterPoint = new Point( + canvasPoint.getX() - 3, + canvasPoint.getY() + 6); + final Point canvasCenterPoint_shadow = new Point( + canvasPoint.getX() - 2, + canvasPoint.getY() + 7); + if (shadows) + { + OverlayUtil.renderTextLocation(graphics, canvasCenterPoint_shadow, txtString, Color.BLACK); + } + OverlayUtil.renderTextLocation(graphics, canvasCenterPoint, txtString, fontColor); + } + } + + private Point centerPoint(Rectangle rect) + { + int x = (int) (rect.getX() + rect.getWidth() / 2); + int y = (int) (rect.getY() + rect.getHeight() / 2); + return new Point(x, y); + } +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/fightcave/FightCavePlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/fightcave/FightCavePlugin.java index 7b8281becf..c694aae2f2 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/fightcave/FightCavePlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/fightcave/FightCavePlugin.java @@ -27,22 +27,23 @@ package net.runelite.client.plugins.fightcave; import com.google.inject.Provides; import java.util.ArrayList; +import java.util.Collections; import java.util.EnumMap; -import java.util.HashMap; +import java.util.HashSet; import java.util.List; -import java.util.Map; +import java.util.Set; import java.util.regex.Matcher; import java.util.regex.Pattern; -import javax.annotation.Nullable; import javax.inject.Inject; import lombok.AccessLevel; import lombok.Getter; +import lombok.extern.slf4j.Slf4j; +import net.runelite.api.AnimationID; 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.events.AnimationChanged; import net.runelite.api.events.ChatMessage; import net.runelite.api.events.GameStateChanged; import net.runelite.api.events.GameTick; @@ -50,6 +51,7 @@ 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.NPCManager; import net.runelite.client.plugins.Plugin; import net.runelite.client.plugins.PluginDescriptor; import net.runelite.client.plugins.PluginType; @@ -64,59 +66,16 @@ import org.apache.commons.lang3.ArrayUtils; enabledByDefault = false ) +@Slf4j public class FightCavePlugin extends Plugin { + static final int MAX_WAVE = 63; + @Getter(AccessLevel.PACKAGE) + static final List> WAVES = new ArrayList<>(); private static final Pattern WAVE_PATTERN = Pattern.compile(".*Wave: (\\d+).*"); private static final int FIGHT_CAVE_REGION = 9551; private static final int MAX_MONSTERS_OF_TYPE_PER_WAVE = 2; - static final int MAX_WAVE = 63; - - @Getter - static final List> WAVES = new ArrayList<>(); - - @Getter - private int currentWave = -1; - - @Inject - private Client client; - - @Inject - private OverlayManager overlayManager; - - @Inject - private WaveOverlay waveOverlay; - - @Inject - private JadOverlay jadOverlay; - - @Inject - private TimersOverlay timersOverlay; - - @Inject - private ConfigManager externalConfig; - - @Getter(AccessLevel.PACKAGE) - private Map Rangers = new HashMap<>(); - - @Getter(AccessLevel.PACKAGE) - private Map Magers = new HashMap<>(); - - @Getter(AccessLevel.PACKAGE) - private Map Meleers = new HashMap<>(); - - @Getter(AccessLevel.PACKAGE) - private Map Drainers = new HashMap<>(); - - @Getter(AccessLevel.PACKAGE) - private Map Ignore = new HashMap<>(); - - @Getter(AccessLevel.PACKAGE) - @Nullable - private JadAttack attack; - - private NPC jad; - static { final WaveMonster[] waveMonsters = WaveMonster.values(); @@ -157,6 +116,36 @@ public class FightCavePlugin extends Plugin } } + @Inject + private Client client; + @Inject + private NPCManager npcManager; + @Inject + private OverlayManager overlayManager; + @Inject + private WaveOverlay waveOverlay; + @Inject + private FightCaveOverlay fightCaveOverlay; + @Inject + private FightCaveConfig config; + @Getter(AccessLevel.PACKAGE) + private Set fightCaveContainer = new HashSet<>(); + @Getter(AccessLevel.PACKAGE) + private int currentWave = -1; + @Getter(AccessLevel.PACKAGE) + private boolean validRegion; + @Getter(AccessLevel.PACKAGE) + private List mageTicks = new ArrayList<>(); + @Getter(AccessLevel.PACKAGE) + private List rangedTicks = new ArrayList<>(); + @Getter(AccessLevel.PACKAGE) + private List meleeTicks = new ArrayList<>(); + + static String formatMonsterQuantity(final WaveMonster monster, final int quantity) + { + return String.format("%dx %s", quantity, monster); + } + @Provides FightCaveConfig provideConfig(ConfigManager configManager) { @@ -166,21 +155,41 @@ public class FightCavePlugin extends Plugin @Override public void startUp() { - overlayManager.add(waveOverlay); - overlayManager.add(jadOverlay); - overlayManager.add(timersOverlay); + if (client.getGameState() == GameState.LOGGED_IN) + { + if (regionCheck()) + { + validRegion = true; + overlayManager.add(waveOverlay); + overlayManager.add(fightCaveOverlay); + } + } } @Override public void shutDown() { overlayManager.remove(waveOverlay); + overlayManager.remove(fightCaveOverlay); currentWave = -1; - overlayManager.remove(timersOverlay); - overlayManager.remove(jadOverlay); - jad = null; - attack = null; + } + @Subscribe + public void onChatMessage(ChatMessage event) + { + if (!validRegion) + { + return; + } + + final Matcher waveMatcher = WAVE_PATTERN.matcher(event.getMessage()); + + if (event.getType() != ChatMessageType.GAMEMESSAGE || !waveMatcher.matches()) + { + return; + } + + currentWave = Integer.parseInt(waveMatcher.group(1)); } @Subscribe @@ -191,98 +200,43 @@ public class FightCavePlugin extends Plugin return; } - if (!inFightCave()) + if (regionCheck()) { - currentWave = -1; + validRegion = true; + overlayManager.add(waveOverlay); + overlayManager.add(fightCaveOverlay); } + else + { + validRegion = false; + overlayManager.remove(fightCaveOverlay); + overlayManager.remove(fightCaveOverlay); + } + + fightCaveContainer.clear(); } - @Subscribe - public void onGameTick(GameTick Event) - { - for (NPCContainer ranger : getRangers().values()) - { - ranger.setTicksUntilAttack(ranger.getTicksUntilAttack() - 1); - if (ranger.getNpc().getAnimation() == 2633) - { - if (ranger.getTicksUntilAttack() < 1) - { - ranger.setTicksUntilAttack(4); - } - } - } - - for (NPCContainer meleer : getMeleers().values()) - { - meleer.setTicksUntilAttack(meleer.getTicksUntilAttack() - 1); - if (meleer.getNpc().getAnimation() == 2637 || meleer.getNpc().getAnimation() == 2639) - { - if (meleer.getTicksUntilAttack() < 1) - { - meleer.setTicksUntilAttack(4); - } - } - } - - for (NPCContainer mager : getMagers().values()) - { - mager.setTicksUntilAttack(mager.getTicksUntilAttack() - 1); - if (mager.getNpc().getAnimation() == 2647) - { - if (mager.getTicksUntilAttack() < 1) - { - mager.setTicksUntilAttack(4); - } - } - } - } - - @Subscribe - public void onChatMessage(ChatMessage event) - { - final Matcher waveMatcher = WAVE_PATTERN.matcher(event.getMessage()); - - if (event.getType() != ChatMessageType.GAMEMESSAGE - || !inFightCave() - || !waveMatcher.matches()) - { - return; - } - - currentWave = Integer.parseInt(waveMatcher.group(1)); - } - - @Subscribe public void onNpcSpawned(NpcSpawned event) { + if (!validRegion) + { + return; + } + NPC npc = event.getNpc(); + switch (npc.getId()) { - case NpcID.TZKIH_3116: - case NpcID.TZKIH_3117: - Drainers.put(npc, new NPCContainer(npc)); - break; - case NpcID.TZKEK_3118: - case NpcID.TZKEK_3119: - case NpcID.TZKEK_3120: - Ignore.put(npc, new NPCContainer(npc)); - break; case NpcID.TOKXIL_3121: case NpcID.TOKXIL_3122: - Rangers.put(npc, new NPCContainer(npc)); - break; case NpcID.YTMEJKOT: case NpcID.YTMEJKOT_3124: - Meleers.put(npc, new NPCContainer(npc)); - break; case NpcID.KETZEK: case NpcID.KETZEK_3126: - Magers.put(npc, new NPCContainer(npc)); - break; case NpcID.TZTOKJAD: case NpcID.TZTOKJAD_6506: - jad = npc; + fightCaveContainer.add(new FightCaveContainer(npc, npcManager.getAttackSpeed(npc.getId()))); break; } } @@ -290,55 +244,106 @@ public class FightCavePlugin extends Plugin @Subscribe public void onNpcDespawned(NpcDespawned event) { - if (Rangers.remove(event.getNpc()) != null && Rangers.isEmpty()) - { - Rangers.clear(); - } - if (Meleers.remove(event.getNpc()) != null && Meleers.isEmpty()) - { - Meleers.clear(); - } - if (Magers.remove(event.getNpc()) != null && Magers.isEmpty()) - { - Magers.clear(); - } - if (Drainers.remove(event.getNpc()) != null && Drainers.isEmpty()) - { - Drainers.clear(); - } - if (Ignore.remove(event.getNpc()) != null && Ignore.isEmpty()) - { - Ignore.clear(); - } - - } - - @Subscribe - public void onAnimationChanged(AnimationChanged event) - { - if (event.getActor() != jad) + if (!validRegion) { return; } - if (jad.getAnimation() == JadAttack.MAGIC.getAnimation()) - { - attack = JadAttack.MAGIC; - } + NPC npc = event.getNpc(); - else if (jad.getAnimation() == JadAttack.RANGE.getAnimation()) + switch (npc.getId()) { - attack = JadAttack.RANGE; + case NpcID.TOKXIL_3121: + case NpcID.TOKXIL_3122: + case NpcID.YTMEJKOT: + case NpcID.YTMEJKOT_3124: + case NpcID.KETZEK: + case NpcID.KETZEK_3126: + case NpcID.TZTOKJAD: + case NpcID.TZTOKJAD_6506: + fightCaveContainer.removeIf(c -> c.getNpc() == npc); + break; } } - boolean inFightCave() + @Subscribe + public void onGameTick(GameTick Event) + { + if (!validRegion) + { + return; + } + + mageTicks.clear(); + rangedTicks.clear(); + meleeTicks.clear(); + + for (FightCaveContainer npc : fightCaveContainer) + { + if (npc.getTicksUntilAttack() >= 0) + { + npc.setTicksUntilAttack(npc.getTicksUntilAttack() - 1); + } + + for (int anims : npc.getAnimations()) + { + if (anims == npc.getNpc().getAnimation()) + { + if (npc.getTicksUntilAttack() < 1) + { + npc.setTicksUntilAttack(npc.getAttackSpeed()); + } + + switch (anims) + { + case AnimationID.TZTOK_JAD_RANGE_ATTACK: + npc.setAttackStyle(FightCaveContainer.AttackStyle.RANGE); + break; + case AnimationID.TZTOK_JAD_MAGIC_ATTACK: + npc.setAttackStyle(FightCaveContainer.AttackStyle.MAGE); + break; + case AnimationID.TZTOK_JAD_MELEE_ATTACK: + npc.setAttackStyle(FightCaveContainer.AttackStyle.MELEE); + break; + } + } + } + + if (npc.getNpcName().equals("TzTok-Jad")) + { + continue; + } + + switch (npc.getAttackStyle()) + { + case RANGE: + if (npc.getTicksUntilAttack() > 0) + { + rangedTicks.add(npc.getTicksUntilAttack()); + } + break; + case MELEE: + if (npc.getTicksUntilAttack() > 0) + { + meleeTicks.add(npc.getTicksUntilAttack()); + } + break; + case MAGE: + if (npc.getTicksUntilAttack() > 0) + { + mageTicks.add(npc.getTicksUntilAttack()); + } + break; + } + } + + Collections.sort(mageTicks); + Collections.sort(rangedTicks); + Collections.sort(meleeTicks); + } + + private boolean regionCheck() { return ArrayUtils.contains(client.getMapRegions(), FIGHT_CAVE_REGION); } - - static String formatMonsterQuantity(final WaveMonster monster, final int quantity) - { - return String.format("%dx %s", quantity, monster); - } } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/fightcave/TimersOverlay.java b/runelite-client/src/main/java/net/runelite/client/plugins/fightcave/TimersOverlay.java deleted file mode 100644 index 88998a3841..0000000000 --- a/runelite-client/src/main/java/net/runelite/client/plugins/fightcave/TimersOverlay.java +++ /dev/null @@ -1,184 +0,0 @@ -/* - * Copyright (c) 2019, Ganom - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 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.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.NPC; -import net.runelite.api.NPCDefinition; -import net.runelite.api.Perspective; -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; -import net.runelite.client.ui.overlay.OverlayPriority; -import net.runelite.client.ui.overlay.OverlayUtil; - -public class TimersOverlay extends Overlay -{ - private FightCavePlugin plugin; - private Client client; - - @Inject - TimersOverlay(FightCavePlugin plugin, Client client) - { - this.plugin = plugin; - this.client = client; - setPosition(OverlayPosition.DYNAMIC); - setPriority(OverlayPriority.HIGHEST); - setLayer(OverlayLayer.ALWAYS_ON_TOP); - } - - @Override - public Dimension render(Graphics2D graphics) - { - for (NPCContainer npc : plugin.getDrainers().values()) - { - renderNpcOverlay(graphics, npc.getNpc(), Color.RED, 255, 20); - String str = "drainer"; - Point canvasPoint = npc.getNpc().getCanvasTextLocation(graphics, str, 0); - renderTextLocation(graphics, str, 12, Color.WHITE, canvasPoint); - } - - for (NPCContainer npc : plugin.getIgnore().values()) - { - renderNpcOverlay(graphics, npc.getNpc(), Color.BLACK, 50, 5); - String str = "ignore"; - Point canvasPoint = npc.getNpc().getCanvasTextLocation(graphics, str, 0); - renderTextLocation(graphics, str, 10, Color.WHITE, canvasPoint); - } - - Color tickcolor; - - for (NPCContainer npc : plugin.getRangers().values()) - { - renderNpcOverlay(graphics, npc.getNpc(), Color.GREEN, 100, 10); - final int ticksLeft = npc.getTicksUntilAttack(); - if (ticksLeft > 0) - { - if (ticksLeft == 1) - { - tickcolor = Color.GREEN; - } - else - { - tickcolor = Color.WHITE; - } - final String ticksLeftStr = String.valueOf(ticksLeft); - Point canvasPoint = npc.getNpc().getCanvasTextLocation(graphics, ticksLeftStr, 0); - renderTextLocation(graphics, ticksLeftStr, 32, tickcolor, canvasPoint); - } - } - - for (NPCContainer npc : plugin.getMagers().values()) - { - renderNpcOverlay(graphics, npc.getNpc(), Color.CYAN, 100, 10); - final int ticksLeft = npc.getTicksUntilAttack(); - if (ticksLeft > 0) - { - if (ticksLeft == 1) - { - tickcolor = Color.CYAN; - } - else - { - - tickcolor = Color.WHITE; - } - final String ticksLeftStr = String.valueOf(ticksLeft); - Point canvasPoint = npc.getNpc().getCanvasTextLocation(graphics, ticksLeftStr, 0); - renderTextLocation(graphics, ticksLeftStr, 32, tickcolor, canvasPoint); - } - } - - for (NPCContainer npc : plugin.getMeleers().values()) - { - renderNpcOverlay(graphics, npc.getNpc(), Color.RED, 100, 10); - final int ticksLeft = npc.getTicksUntilAttack(); - if (ticksLeft > 0) - { - if (ticksLeft == 1) - { - tickcolor = Color.RED; - } - else - { - - tickcolor = Color.WHITE; - } - final String ticksLeftStr = String.valueOf(ticksLeft); - Point canvasPoint = npc.getNpc().getCanvasTextLocation(graphics, ticksLeftStr, 0); - renderTextLocation(graphics, ticksLeftStr, 32, tickcolor, canvasPoint); - } - } - - return null; - } - - private void renderNpcOverlay(Graphics2D graphics, NPC actor, Color color, int outlineAlpha, int fillAlpha) - { - int size = 1; - NPCDefinition composition = actor.getTransformedDefinition(); - if (composition != null) - { - 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(2)); - 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, Color fontColor, Point canvasPoint) - { - graphics.setFont(new Font("Arial", Font.BOLD, 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); - } - } -} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/fightcave/WaveMonster.java b/runelite-client/src/main/java/net/runelite/client/plugins/fightcave/WaveMonster.java index 9919623124..399cd1947b 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/fightcave/WaveMonster.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/fightcave/WaveMonster.java @@ -29,12 +29,12 @@ import lombok.AllArgsConstructor; @AllArgsConstructor enum WaveMonster { - TZ_KIH("Tz-Kih", 22), - TZ_KEK("Tz-Kek", 45), - TOK_XIL("Tok-Xil", 90), - YT_MEJKOT("Yt-MejKot", 180), - KET_ZEK("Ket-Zek", 360), - TZKOK_JAD("TzTok-Jad", 702); + TZ_KIH("Drainer", 22), + TZ_KEK("Blob", 45), + TOK_XIL("Range", 90), + YT_MEJKOT("Melee", 180), + KET_ZEK("Mage", 360), + TZKOK_JAD("Jad", 702); private final String name; private final int level; 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 2b5fdf370b..f1d81816f6 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 @@ -37,8 +37,8 @@ import net.runelite.client.ui.overlay.Overlay; import net.runelite.client.ui.overlay.OverlayPosition; import net.runelite.client.ui.overlay.components.PanelComponent; import net.runelite.client.ui.overlay.components.TitleComponent; -import net.runelite.client.ui.overlay.components.table.TableComponent; import net.runelite.client.ui.overlay.components.table.TableAlignment; +import net.runelite.client.ui.overlay.components.table.TableComponent; class WaveOverlay extends Overlay { @@ -46,22 +46,38 @@ class WaveOverlay extends Overlay 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; + setPosition(OverlayPosition.TOP_RIGHT); + } + + 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 String line = FightCavePlugin.formatMonsterQuantity(monster, quantity); + + outputLines.add(line); + } + + return outputLines; } @Override public Dimension render(Graphics2D graphics) { - if (!plugin.inFightCave() - || plugin.getCurrentWave() < 0) + if (!plugin.isValidRegion() || plugin.getCurrentWave() < 0) { return null; } @@ -108,26 +124,8 @@ class WaveOverlay extends Overlay } if (!tableComponent.isEmpty()) - { - panelComponent.getChildren().add(tableComponent); - } - } - - 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 String line = FightCavePlugin.formatMonsterQuantity(monster, quantity); - - outputLines.add(line); + panelComponent.getChildren().add(tableComponent); } - - return outputLines; } } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/freezetimers/FreezeTimersOverlay.java b/runelite-client/src/main/java/net/runelite/client/plugins/freezetimers/FreezeTimersOverlay.java index 87e3a0ee98..6842cd111d 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/freezetimers/FreezeTimersOverlay.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/freezetimers/FreezeTimersOverlay.java @@ -54,17 +54,17 @@ public class FreezeTimersOverlay extends Overlay private final BufferedImage FREEZE_IMAGE = ImageUtil.getResourceStreamFromClass(getClass(), "freeze.png"); private final BufferedImage TB_IMAGE = ImageUtil.getResourceStreamFromClass(getClass(), "teleblock.png"); private final BufferedImage VENG_IMAGE = ImageUtil.getResourceStreamFromClass(getClass(), "veng.png"); - @Inject private Timers timers; private boolean lock; private long finishedAtTest; @Inject - public FreezeTimersOverlay(FreezeTimersConfig config, Client client) + public FreezeTimersOverlay(FreezeTimersConfig config, Client client, Timers timers) { this.config = config; this.client = client; + this.timers = timers; setPriority(OverlayPriority.HIGHEST); setPosition(OverlayPosition.DYNAMIC); setLayer(OverlayLayer.UNDER_WIDGETS); @@ -119,24 +119,23 @@ public class FreezeTimersOverlay extends Overlay String text = processTickCounter(finishedAt); int test = Integer.parseInt(text); Point poi = actor.getCanvasTextLocation(g, text, 0); + if (poi == null) { return false; } - int xpoi = poi.getX(); - int ypoi = poi.getY(); - Point FixedPoint = new Point(xpoi, ypoi); + Point FixedPoint = new Point(poi.getX(), poi.getY()); if (config.noImage()) { if (test > 3) { - renderTextLocation(g, text, config.textSize(), config.fontStyle().getFont(), Color.WHITE, FixedPoint); + OverlayUtil.renderTextLocation(g, text, config.textSize(), config.fontStyle().getFont(), Color.WHITE, FixedPoint, false, 0); } else { - renderTextLocation(g, text, config.textSize(), config.fontStyle().getFont(), Color.YELLOW, FixedPoint); + OverlayUtil.renderTextLocation(g, text, config.textSize(), config.fontStyle().getFont(), Color.YELLOW, FixedPoint, false, 0); } } else @@ -161,23 +160,26 @@ public class FreezeTimersOverlay extends Overlay String text = processTickCounter(finishedAt); Point poi = actor.getCanvasTextLocation(g, text, 0); - int xpoi = poi.getX() + 20; - int ypoi = poi.getY(); - Point FixedPoint = new Point(xpoi, ypoi); + if (poi == null) + { + return false; + } + + Point FixedPoint = new Point(poi.getX() + 20, poi.getY()); if (config.noImage()) { if (timers.getTimerEnd(actor, TimerType.FREEZE) <= currentTick) { - renderTextLocation(g, text, config.textSize(), config.fontStyle().getFont(), Color.CYAN, poi); + OverlayUtil.renderTextLocation(g, text, config.textSize(), config.fontStyle().getFont(), Color.CYAN, poi, false, 0); } if (timers.getTimerEnd(actor, TimerType.FREEZE) >= currentTick) { - renderTextLocation(g, " | " + text, config.textSize(), config.fontStyle().getFont(), Color.CYAN, FixedPoint); + OverlayUtil.renderTextLocation(g, " | " + text, config.textSize(), config.fontStyle().getFont(), Color.CYAN, FixedPoint, false, 0); } if (timers.getTimerEnd(actor, TimerType.VENG) >= currentTick) { - renderTextLocation(g, " | " + text, config.textSize(), config.fontStyle().getFont(), Color.CYAN, FixedPoint); + OverlayUtil.renderTextLocation(g, " | " + text, config.textSize(), config.fontStyle().getFont(), Color.CYAN, FixedPoint, false, 0); } } else @@ -202,22 +204,26 @@ public class FreezeTimersOverlay extends Overlay String text = processTickCounter(finishedAt); Point poi = actor.getCanvasTextLocation(g, text, 0); - int xpoi = poi.getX() - 20; - int ypoi = poi.getY(); - Point FixedPoint = new Point(xpoi, ypoi); + + if (poi == null) + { + return false; + } + + Point FixedPoint = new Point(poi.getX() - 20, poi.getY()); if (config.noImage()) { if (timers.getTimerEnd(actor, TimerType.FREEZE) <= currentTick) { - renderTextLocation(g, text, config.textSize(), config.fontStyle().getFont(), Color.RED, poi); + OverlayUtil.renderTextLocation(g, text, config.textSize(), config.fontStyle().getFont(), Color.RED, poi, false, 0); } if (timers.getTimerEnd(actor, TimerType.FREEZE) >= currentTick) { - renderTextLocation(g, text + " | ", config.textSize(), config.fontStyle().getFont(), Color.RED, FixedPoint); + OverlayUtil.renderTextLocation(g, text + " | ", config.textSize(), config.fontStyle().getFont(), Color.RED, FixedPoint, false, 0); } if (timers.getTimerEnd(actor, TimerType.TELEBLOCK) >= currentTick) { - renderTextLocation(g, text + " | ", config.textSize(), config.fontStyle().getFont(), Color.RED, FixedPoint); + OverlayUtil.renderTextLocation(g, text + " | ", config.textSize(), config.fontStyle().getFont(), Color.RED, FixedPoint, false, 0); } } else @@ -229,10 +235,13 @@ public class FreezeTimersOverlay extends Overlay g.setColor(RED); Polygon poly = actor.getCanvasTilePoly(); - if (poly != null) + + if (poly == null) { - OverlayUtil.renderPolygon(g, poly, RED); + return false; } + + OverlayUtil.renderPolygon(g, poly, RED); OverlayUtil.renderTextLocation(g, new Point((int) poly.getBounds2D().getCenterX(), (int) poly.getBounds2D().getCenterY()), actor.getName(), RED); } @@ -249,22 +258,6 @@ public class FreezeTimersOverlay extends Overlay xOffset); } - 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); - } - } - public void renderImageLocation(Graphics2D graphics, Point imgLoc, BufferedImage image) { int x = imgLoc.getX(); @@ -273,12 +266,9 @@ public class FreezeTimersOverlay extends Overlay graphics.drawImage(image, x, y, null); } - public void renderActorTextAndImage(Graphics2D graphics, Actor actor, String text, Color color, - BufferedImage image, int yOffset, int xOffset) + private void renderActorTextAndImage(Graphics2D graphics, Actor actor, String text, Color color, BufferedImage image, int yOffset, int xOffset) { - Point textLocation = new Point(actor.getCanvasImageLocation(image, 0).getX() + xOffset, - actor.getCanvasImageLocation(image, 0).getY() + yOffset); - + Point textLocation = new Point(actor.getCanvasImageLocation(image, 0).getX() + xOffset, actor.getCanvasImageLocation(image, 0).getY() + yOffset); renderImageLocation(graphics, textLocation, image); xOffset = image.getWidth() + 1; yOffset = (image.getHeight() - (int) graphics.getFontMetrics().getStringBounds(text, graphics).getHeight()); diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/implings/ImplingsPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/implings/ImplingsPlugin.java index f0709535f4..5ec61041da 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/implings/ImplingsPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/implings/ImplingsPlugin.java @@ -30,14 +30,13 @@ import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; -import java.util.HashMap; import javax.inject.Inject; import lombok.AccessLevel; import lombok.Getter; import net.runelite.api.GameState; import net.runelite.api.NPC; -import net.runelite.api.events.GameTick; import net.runelite.api.events.GameStateChanged; +import net.runelite.api.events.GameTick; import net.runelite.api.events.NpcDespawned; import net.runelite.api.events.NpcSpawned; import net.runelite.client.config.ConfigManager; @@ -119,6 +118,11 @@ public class ImplingsPlugin extends Plugin { Impling impling = Impling.findImpling(npc.getId()); + if (impling == null || impling.getImplingType() == null) + { + continue; + } + ImplingType type = impling.getImplingType(); if (implingCounterMap.containsKey(type)) { diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/interfacestyles/InterfaceStylesConfig.java b/runelite-client/src/main/java/net/runelite/client/plugins/interfacestyles/InterfaceStylesConfig.java index 540186558c..3f64778e52 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/interfacestyles/InterfaceStylesConfig.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/interfacestyles/InterfaceStylesConfig.java @@ -62,4 +62,14 @@ public interface InterfaceStylesConfig extends Config { return false; } + + @ConfigItem( + keyName = "rsCrossSprites", + name = "RuneScape cross sprites", + description = "Replaces left-click cross sprites with the ones in RuneScape" + ) + default boolean rsCrossSprites() + { + return false; + } } \ No newline at end of file diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/interfacestyles/InterfaceStylesPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/interfacestyles/InterfaceStylesPlugin.java index fa70dff0fc..6944a982d7 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/interfacestyles/InterfaceStylesPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/interfacestyles/InterfaceStylesPlugin.java @@ -31,11 +31,13 @@ import java.awt.image.BufferedImage; import javax.inject.Inject; import lombok.extern.slf4j.Slf4j; import net.runelite.api.Client; +import net.runelite.api.GameState; import net.runelite.api.HealthBar; import net.runelite.api.SpriteID; import net.runelite.api.Sprite; import net.runelite.api.events.BeforeMenuRender; import net.runelite.api.events.ConfigChanged; +import net.runelite.api.events.GameStateChanged; import net.runelite.api.events.PostHealthBar; import net.runelite.api.events.WidgetPositioned; import net.runelite.api.widgets.Widget; @@ -69,6 +71,8 @@ public class InterfaceStylesPlugin extends Plugin @Inject private SpriteManager spriteManager; + private Sprite[] defaultCrossSprites; + @Provides InterfaceStylesConfig provideConfig(ConfigManager configManager) { @@ -89,6 +93,7 @@ public class InterfaceStylesPlugin extends Plugin restoreWidgetDimensions(); removeGameframe(); restoreHealthBars(); + restoreCrossSprites(); }); } @@ -126,6 +131,22 @@ public class InterfaceStylesPlugin extends Plugin } } + @Subscribe + public void onGameStateChanged(GameStateChanged gameStateChanged) + { + if (gameStateChanged.getGameState() != GameState.LOGIN_SCREEN) + { + return; + } + + /* + * The cross sprites aren't loaded yet when the initial config change event is received. + * So run the overriding for cross sprites when we reach the login screen, + * at which point the cross sprites will have been loaded. + */ + overrideCrossSprites(); + } + private void updateAllOverrides() { removeGameframe(); @@ -134,6 +155,7 @@ public class InterfaceStylesPlugin extends Plugin restoreWidgetDimensions(); adjustWidgetDimensions(); overrideHealthBars(); + overrideCrossSprites(); } @Subscribe @@ -283,6 +305,62 @@ public class InterfaceStylesPlugin extends Plugin clientThread.invokeLater(client::resetHealthBarCaches); } + private void overrideCrossSprites() + { + if (config.rsCrossSprites()) + { + // If we've already replaced them, + // we don't need to replace them again + if (defaultCrossSprites != null) + { + return; + } + + Sprite[] crossSprites = client.getCrossSprites(); + + if (crossSprites == null) + { + return; + } + + defaultCrossSprites = new Sprite[crossSprites.length]; + System.arraycopy(crossSprites, 0, defaultCrossSprites, 0, defaultCrossSprites.length); + + for (int i = 0; i < crossSprites.length; i++) + { + Sprite newSprite = getFileSpritePixels("rs3/cross_sprites/" + i + ".png"); + + if (newSprite == null) + { + continue; + } + + crossSprites[i] = newSprite; + } + } + else + { + restoreCrossSprites(); + } + } + + private void restoreCrossSprites() + { + if (defaultCrossSprites == null) + { + return; + } + + Sprite[] crossSprites = client.getCrossSprites(); + + if (crossSprites != null && defaultCrossSprites.length == crossSprites.length) + { + System.arraycopy(defaultCrossSprites, 0, crossSprites, 0, defaultCrossSprites.length); + } + + defaultCrossSprites = null; + } + private void restoreWidgetDimensions() { for (WidgetOffset widgetOffset : WidgetOffset.values()) diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/interfacestyles/WidgetOffset.java b/runelite-client/src/main/java/net/runelite/client/plugins/interfacestyles/WidgetOffset.java index fe61af1af7..9edf17165e 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/interfacestyles/WidgetOffset.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/interfacestyles/WidgetOffset.java @@ -118,33 +118,33 @@ enum WidgetOffset FIXED_2005_INTERFACE_CONTAINER(Skin.AROUND_2005, WidgetInfo.FIXED_VIEWPORT_INTERFACE_CONTAINER, 7, null, null, null), FIXED_2005_BANK_CONTAINER(Skin.AROUND_2005, WidgetInfo.FIXED_VIEWPORT_BANK_CONTAINER, 7, null, null, null), FIXED_2005_COMBAT_HIGHLIGHT(Skin.AROUND_2005, WidgetInfo.FIXED_VIEWPORT_COMBAT_TAB, 19, 2, null, null), - FIXED_2005_COMBAT_ICON(Skin.AROUND_2005, WidgetInfo.FIXED_VIEWPORT_COMBAT_ICON, 26, null, null, null), + FIXED_2005_COMBAT_ICON(Skin.AROUND_2005, WidgetInfo.FIXED_VIEWPORT_COMBAT_ICON, 28, 1, null, null), FIXED_2005_STATS_HIGHLIGHT(Skin.AROUND_2005, WidgetInfo.FIXED_VIEWPORT_STATS_TAB, 55, null, 30, null), - FIXED_2005_STATS_ICON(Skin.AROUND_2005, WidgetInfo.FIXED_VIEWPORT_STATS_ICON, 53, null, null, null), + FIXED_2005_STATS_ICON(Skin.AROUND_2005, WidgetInfo.FIXED_VIEWPORT_STATS_ICON, 51, null, null, null), FIXED_2005_QUESTS_HIGHLIGHT(Skin.AROUND_2005, WidgetInfo.FIXED_VIEWPORT_QUESTS_TAB, 82, 1, 30, null), - FIXED_2005_QUESTS_ICON(Skin.AROUND_2005, WidgetInfo.FIXED_VIEWPORT_QUESTS_ICON, 81, null, null, null), + FIXED_2005_QUESTS_ICON(Skin.AROUND_2005, WidgetInfo.FIXED_VIEWPORT_QUESTS_ICON, 80, null, null, null), FIXED_2005_INVENTORY_HIGHLIGHT(Skin.AROUND_2005, WidgetInfo.FIXED_VIEWPORT_INVENTORY_TAB, null, null, 45, null), - FIXED_2005_INVENTORY_ICON(Skin.AROUND_2005, WidgetInfo.FIXED_VIEWPORT_INVENTORY_ICON, 115, null, null, null), + FIXED_2005_INVENTORY_ICON(Skin.AROUND_2005, WidgetInfo.FIXED_VIEWPORT_INVENTORY_ICON, 113, 1, null, null), FIXED_2005_EQUIPMENT_HIGHLIGHT(Skin.AROUND_2005, WidgetInfo.FIXED_VIEWPORT_EQUIPMENT_TAB, 153, 1, 30, null), - FIXED_2005_EQUIPMENT_ICON(Skin.AROUND_2005, WidgetInfo.FIXED_VIEWPORT_EQUIPMENT_ICON, 152, 4, null, null), + FIXED_2005_EQUIPMENT_ICON(Skin.AROUND_2005, WidgetInfo.FIXED_VIEWPORT_EQUIPMENT_ICON, 151, 4, null, null), FIXED_2005_PRAYER_HIGHLIGHT(Skin.AROUND_2005, WidgetInfo.FIXED_VIEWPORT_PRAYER_TAB, 180, null, 32, null), - FIXED_2005_PRAYER_ICON(Skin.AROUND_2005, WidgetInfo.FIXED_VIEWPORT_PRAYER_ICON, 180, null, null, null), + FIXED_2005_PRAYER_ICON(Skin.AROUND_2005, WidgetInfo.FIXED_VIEWPORT_PRAYER_ICON, 178, null, null, null), FIXED_2005_MAGIC_HIGHLIGHT(Skin.AROUND_2005, WidgetInfo.FIXED_VIEWPORT_MAGIC_TAB, 209, 1, 30, null), - FIXED_2005_MAGIC_ICON(Skin.AROUND_2005, WidgetInfo.FIXED_VIEWPORT_MAGIC_ICON, 206, 3, null, null), + FIXED_2005_MAGIC_ICON(Skin.AROUND_2005, WidgetInfo.FIXED_VIEWPORT_MAGIC_ICON, 206, 2, null, null), FIXED_2005_CLAN_CHAT_HIGHLIGHT(Skin.AROUND_2005, WidgetInfo.FIXED_VIEWPORT_CLAN_CHAT_TAB, 15, null, null, null), FIXED_2005_CLAN_CHAT_ICON(Skin.AROUND_2005, WidgetInfo.FIXED_VIEWPORT_CLAN_CHAT_ICON, 22, 0, null, null), FIXED_2005_FRIENDS_HIGHLIGHT(Skin.AROUND_2005, WidgetInfo.FIXED_VIEWPORT_FRIENDS_TAB, 51, null, 30, null), - FIXED_2005_FRIENDS_ICON(Skin.AROUND_2005, WidgetInfo.FIXED_VIEWPORT_FRIENDS_ICON, 50, null, null, null), + FIXED_2005_FRIENDS_ICON(Skin.AROUND_2005, WidgetInfo.FIXED_VIEWPORT_FRIENDS_ICON, 49, -1, null, null), FIXED_2005_IGNORES_HIGHLIGHT(Skin.AROUND_2005, WidgetInfo.FIXED_VIEWPORT_IGNORES_TAB, 79, null, 30, null), FIXED_2005_IGNORES_ICON(Skin.AROUND_2005, WidgetInfo.FIXED_VIEWPORT_IGNORES_ICON, 78, null, null, null), FIXED_2005_LOGOUT_HIGHLIGHT(Skin.AROUND_2005, WidgetInfo.FIXED_VIEWPORT_LOGOUT_TAB, 107, 1, 45, null), - FIXED_2005_LOGOUT_ICON(Skin.AROUND_2005, WidgetInfo.FIXED_VIEWPORT_LOGOUT_ICON, 114, 1, null, null), + FIXED_2005_LOGOUT_ICON(Skin.AROUND_2005, WidgetInfo.FIXED_VIEWPORT_LOGOUT_ICON, 112, null, null, null), FIXED_2005_OPTIONS_HIGHLIGHT(Skin.AROUND_2005, WidgetInfo.FIXED_VIEWPORT_OPTIONS_TAB, 150, null, 30, null), - FIXED_2005_OPTIONS_ICON(Skin.AROUND_2005, WidgetInfo.FIXED_VIEWPORT_OPTIONS_ICON, 149, null, null, null), + FIXED_2005_OPTIONS_ICON(Skin.AROUND_2005, WidgetInfo.FIXED_VIEWPORT_OPTIONS_ICON, 148, -1, null, null), FIXED_2005_EMOTES_HIGHLIGHT(Skin.AROUND_2005, WidgetInfo.FIXED_VIEWPORT_EMOTES_TAB, 178, null, 30, null), - FIXED_2005_EMOTES_ICON(Skin.AROUND_2005, WidgetInfo.FIXED_VIEWPORT_EMOTES_ICON, 179, null, null, null), + FIXED_2005_EMOTES_ICON(Skin.AROUND_2005, WidgetInfo.FIXED_VIEWPORT_EMOTES_ICON, 178, 1, null, null), FIXED_2005_MUSIC_HIGHLIGHT(Skin.AROUND_2005, WidgetInfo.FIXED_VIEWPORT_MUSIC_TAB, 206, null, 30, null), - FIXED_2005_MUSIC_ICON(Skin.AROUND_2005, WidgetInfo.FIXED_VIEWPORT_MUSIC_ICON, 202, 5, null, null); + FIXED_2005_MUSIC_ICON(Skin.AROUND_2005, WidgetInfo.FIXED_VIEWPORT_MUSIC_ICON, 202, 2, null, null); private Skin skin; private WidgetInfo widgetInfo; diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/itemcharges/ItemChargeConfig.java b/runelite-client/src/main/java/net/runelite/client/plugins/itemcharges/ItemChargeConfig.java index 18b9d6386b..a822cf74a8 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/itemcharges/ItemChargeConfig.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/itemcharges/ItemChargeConfig.java @@ -173,10 +173,10 @@ public interface ItemChargeConfig extends Config } @ConfigItem( - keyName = "showBellowCharges", - name = "Show Bellow Charges", - description = "Configures if ogre bellow item charge is shown", - position = 12 + keyName = "showBellowCharges", + name = "Show Bellow Charges", + description = "Configures if ogre bellow item charge is shown", + position = 12 ) default boolean showBellowCharges() { @@ -184,10 +184,32 @@ public interface ItemChargeConfig extends Config } @ConfigItem( - keyName = "showAbyssalBraceletCharges", - name = "Show Abyssal Bracelet Charges", - description = "Configures if abyssal bracelet item charge is shown", - position = 13 + keyName = "showBasketCharges", + name = "Show Basket Charges", + description = "Configures if fruit basket item charge is shown", + position = 13 + ) + default boolean showBasketCharges() + { + return true; + } + + @ConfigItem( + keyName = "showSackCharges", + name = "Show Sack Charges", + description = "Configures if sack item charge is shown", + position = 14 + ) + default boolean showSackCharges() + { + return true; + } + + @ConfigItem( + keyName = "showAbyssalBraceletCharges", + name = "Show Abyssal Bracelet Charges", + description = "Configures if abyssal bracelet item charge is shown", + position = 15 ) default boolean showAbyssalBraceletCharges() { @@ -198,7 +220,7 @@ public interface ItemChargeConfig extends Config keyName = "recoilNotification", name = "Ring of Recoil Notification", description = "Configures if the ring of recoil breaking notification is shown", - position = 14 + position = 16 ) default boolean recoilNotification() { @@ -209,7 +231,7 @@ public interface ItemChargeConfig extends Config keyName = "showBindingNecklaceCharges", name = "Show Binding Necklace Charges", description = "Configures if binding necklace item charge is shown", - position = 15 + position = 17 ) default boolean showBindingNecklaceCharges() { @@ -238,7 +260,7 @@ public interface ItemChargeConfig extends Config keyName = "bindingNotification", name = "Binding Necklace Notification", description = "Configures if the binding necklace breaking notification is shown", - position = 16 + position = 18 ) default boolean bindingNotification() { @@ -249,7 +271,7 @@ public interface ItemChargeConfig extends Config keyName = "showExplorerRingCharges", name = "Show Explorer's Ring Alch Charges", description = "Configures if explorer's ring alchemy charges are shown", - position = 17 + position = 19 ) default boolean showExplorerRingCharges() { @@ -278,7 +300,7 @@ public interface ItemChargeConfig extends Config keyName = "showInfoboxes", name = "Show Infoboxes", description = "Configures whether to show an infobox equipped charge items", - position = 18 + position = 20 ) default boolean showInfoboxes() { diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/itemcharges/ItemChargeOverlay.java b/runelite-client/src/main/java/net/runelite/client/plugins/itemcharges/ItemChargeOverlay.java index 32f92da25e..ec140e2749 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/itemcharges/ItemChargeOverlay.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/itemcharges/ItemChargeOverlay.java @@ -38,6 +38,8 @@ import static net.runelite.client.plugins.itemcharges.ItemChargeType.IMPBOX; import static net.runelite.client.plugins.itemcharges.ItemChargeType.TELEPORT; import static net.runelite.client.plugins.itemcharges.ItemChargeType.WATERCAN; import static net.runelite.client.plugins.itemcharges.ItemChargeType.WATERSKIN; +import static net.runelite.client.plugins.itemcharges.ItemChargeType.FRUIT_BASKET; +import static net.runelite.client.plugins.itemcharges.ItemChargeType.SACK; import net.runelite.client.ui.FontManager; import net.runelite.client.ui.overlay.WidgetItemOverlay; import net.runelite.client.ui.overlay.components.TextComponent; @@ -152,6 +154,8 @@ class ItemChargeOverlay extends WidgetItemOverlay || (type == WATERCAN && !config.showWateringCanCharges()) || (type == WATERSKIN && !config.showWaterskinCharges()) || (type == BELLOWS && !config.showBellowCharges()) + || (type == FRUIT_BASKET && !config.showBasketCharges()) + || (type == SACK && !config.showSackCharges()) || (type == ABYSSAL_BRACELET && !config.showAbyssalBraceletCharges())) { return; @@ -172,6 +176,7 @@ class ItemChargeOverlay extends WidgetItemOverlay { return config.showTeleportCharges() || config.showDodgyCount() || config.showFungicideCharges() || config.showImpCharges() || config.showWateringCanCharges() || config.showWaterskinCharges() - || config.showBellowCharges() || config.showAbyssalBraceletCharges() || config.showExplorerRingCharges(); + || config.showBellowCharges() || config.showBasketCharges() || config.showSackCharges() + || config.showAbyssalBraceletCharges() || config.showExplorerRingCharges(); } } \ No newline at end of file diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/itemcharges/ItemChargeType.java b/runelite-client/src/main/java/net/runelite/client/plugins/itemcharges/ItemChargeType.java index 3d131aec20..e219bae493 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/itemcharges/ItemChargeType.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/itemcharges/ItemChargeType.java @@ -37,5 +37,7 @@ enum ItemChargeType BRACELET_OF_SLAUGHTER, EXPEDITIOUS_BRACELET, BINDING_NECKLACE, - EXPLORER_RING + EXPLORER_RING, + FRUIT_BASKET, + SACK } 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 2f2fe76469..9e3113b85c 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,133 +29,8 @@ import java.util.Map; import javax.annotation.Nullable; import lombok.AllArgsConstructor; import lombok.Getter; -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.api.ItemID.*; 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; @@ -163,6 +38,8 @@ import static net.runelite.client.plugins.itemcharges.ItemChargeType.IMPBOX; import static net.runelite.client.plugins.itemcharges.ItemChargeType.TELEPORT; import static net.runelite.client.plugins.itemcharges.ItemChargeType.WATERCAN; import static net.runelite.client.plugins.itemcharges.ItemChargeType.WATERSKIN; +import static net.runelite.client.plugins.itemcharges.ItemChargeType.FRUIT_BASKET; +import static net.runelite.client.plugins.itemcharges.ItemChargeType.SACK; @AllArgsConstructor @Getter @@ -173,6 +50,31 @@ enum ItemWithCharge ABRACE3(ABYSSAL_BRACELET, ABYSSAL_BRACELET3, 3), ABRACE4(ABYSSAL_BRACELET, ABYSSAL_BRACELET4, 4), ABRACE5(ABYSSAL_BRACELET, ABYSSAL_BRACELET5, 5), + BASKET_APPLES1(FRUIT_BASKET, APPLES1, 1), + BASKET_APPLES2(FRUIT_BASKET, APPLES2, 2), + BASKET_APPLES3(FRUIT_BASKET, APPLES3, 3), + BASKET_APPLES4(FRUIT_BASKET, APPLES4, 4), + BASKET_APPLES5(FRUIT_BASKET, APPLES5, 5), + BASKET_BANANAS1(FRUIT_BASKET, BANANAS1, 1), + BASKET_BANANAS2(FRUIT_BASKET, BANANAS2, 2), + BASKET_BANANAS3(FRUIT_BASKET, BANANAS3, 3), + BASKET_BANANAS4(FRUIT_BASKET, BANANAS4, 4), + BASKET_BANANAS5(FRUIT_BASKET, BANANAS5, 5), + BASKET_ORANGES1(FRUIT_BASKET, ORANGES1, 1), + BASKET_ORANGES2(FRUIT_BASKET, ORANGES2, 2), + BASKET_ORANGES3(FRUIT_BASKET, ORANGES3, 3), + BASKET_ORANGES4(FRUIT_BASKET, ORANGES4, 4), + BASKET_ORANGES5(FRUIT_BASKET, ORANGES5, 5), + BASKET_STRAWBERRIES1(FRUIT_BASKET, STRAWBERRIES1, 1), + BASKET_STRAWBERRIES2(FRUIT_BASKET, STRAWBERRIES2, 2), + BASKET_STRAWBERRIES3(FRUIT_BASKET, STRAWBERRIES3, 3), + BASKET_STRAWBERRIES4(FRUIT_BASKET, STRAWBERRIES4, 4), + BASKET_STRAWBERRIES5(FRUIT_BASKET, STRAWBERRIES5, 5), + BASKET_TOMATOES1(FRUIT_BASKET, TOMATOES1, 1), + BASKET_TOMATOES2(FRUIT_BASKET, TOMATOES2, 2), + BASKET_TOMATOES3(FRUIT_BASKET, TOMATOES3, 3), + BASKET_TOMATOES4(FRUIT_BASKET, TOMATOES4, 4), + BASKET_TOMATOES5(FRUIT_BASKET, TOMATOES5, 5), BELLOWS0(BELLOWS, OGRE_BELLOWS, 0), BELLOWS1(BELLOWS, OGRE_BELLOWS_1, 1), BELLOWS2(BELLOWS, OGRE_BELLOWS_2, 2), @@ -270,6 +172,36 @@ enum ItemWithCharge ROW3(TELEPORT, RING_OF_WEALTH_3, 3), ROW4(TELEPORT, RING_OF_WEALTH_4, 4), ROW5(TELEPORT, RING_OF_WEALTH_5, 5), + SACK_CABBAGES1(SACK, CABBAGES1, 1), + SACK_CABBAGES2(SACK, CABBAGES2, 2), + SACK_CABBAGES3(SACK, CABBAGES3, 3), + SACK_CABBAGES4(SACK, CABBAGES4, 4), + SACK_CABBAGES5(SACK, CABBAGES5, 5), + SACK_CABBAGES6(SACK, CABBAGES6, 6), + SACK_CABBAGES7(SACK, CABBAGES7, 7), + SACK_CABBAGES8(SACK, CABBAGES8, 8), + SACK_CABBAGES9(SACK, CABBAGES9, 9), + SACK_CABBAGES10(SACK, CABBAGES10, 10), + SACK_ONIONS1(SACK, ONIONS1, 1), + SACK_ONIONS2(SACK, ONIONS2, 2), + SACK_ONIONS3(SACK, ONIONS3, 3), + SACK_ONIONS4(SACK, ONIONS4, 4), + SACK_ONIONS5(SACK, ONIONS5, 5), + SACK_ONIONS6(SACK, ONIONS6, 6), + SACK_ONIONS7(SACK, ONIONS7, 7), + SACK_ONIONS8(SACK, ONIONS8, 8), + SACK_ONIONS9(SACK, ONIONS9, 9), + SACK_ONIONS10(SACK, ONIONS10, 10), + SACK_POTATOES1(SACK, POTATOES1, 1), + SACK_POTATOES2(SACK, POTATOES2, 2), + SACK_POTATOES3(SACK, POTATOES3, 3), + SACK_POTATOES4(SACK, POTATOES4, 4), + SACK_POTATOES5(SACK, POTATOES5, 5), + SACK_POTATOES6(SACK, POTATOES6, 6), + SACK_POTATOES7(SACK, POTATOES7, 7), + SACK_POTATOES8(SACK, POTATOES8, 8), + SACK_POTATOES9(SACK, POTATOES9, 9), + SACK_POTATOES10(SACK, POTATOES10, 10), SKILLS1(TELEPORT, SKILLS_NECKLACE1, 1), SKILLS2(TELEPORT, SKILLS_NECKLACE2, 2), SKILLS3(TELEPORT, SKILLS_NECKLACE3, 3), 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 d503b41968..0ac8e4b979 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 @@ -129,9 +129,12 @@ public class LootTrackerPlugin extends Plugin // Chest loot handling private static final String CHEST_LOOTED_MESSAGE = "You find some treasure in the chest!"; + private static final Pattern LARRAN_LOOTED_PATTERN = Pattern.compile("You have opened Larran's (big|small) chest .*"); private static final Map CHEST_EVENT_TYPES = ImmutableMap.of( 5179, "Brimstone Chest", - 11573, "Crystal Chest" + 11573, "Crystal Chest", + 12093, "Larran's big chest", + 13113, "Larran's small chest" ); private static final File LOOT_RECORDS_FILE = new File(RuneLite.RUNELITE_DIR, "lootRecords.json"); private static final Set RESPAWN_REGIONS = ImmutableSet.of( @@ -545,7 +548,7 @@ public class LootTrackerPlugin extends Plugin final String message = event.getMessage(); - if (message.equals(CHEST_LOOTED_MESSAGE)) + if (message.equals(CHEST_LOOTED_MESSAGE) || LARRAN_LOOTED_PATTERN.matcher(message).matches()) { final int regionID = client.getLocalPlayer().getWorldLocation().getRegionID(); if (!CHEST_EVENT_TYPES.containsKey(regionID)) 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 e6497432aa..e90c97acdc 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 @@ -1690,4 +1690,4 @@ default CharterOption charterOption() { return true; } -} +} \ No newline at end of file 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 c6eb0a7947..f7f04ddef9 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 @@ -906,34 +906,28 @@ public class MenuEntrySwapperPlugin extends Plugin } } } - - Player[] players = client.getCachedPlayers(); - Player player = null; - int identifier = event.getIdentifier(); - - if (identifier >= 0 && identifier < players.length) - { - player = players[identifier]; - } - - if (player == null) - { - return; - } //If the option is already to walk there, or cancel we don't need to swap it with anything - if (pOptionToReplace.equals(CANCEL) || pOptionToReplace.equals(WALK_HERE)) - { - return; - } + if (!pOptionToReplace.equals(CANCEL) && !pOptionToReplace.equals(WALK_HERE)) + { + Player[] players = client.getCachedPlayers(); + int identifier = event.getIdentifier(); - if (((config.getRemoveFreezePlayerCoX() && client.getVar(Varbits.IN_RAID) == 1) - || (config.getRemoveFreezePlayerToB() && client.getVar(Varbits.THEATRE_OF_BLOOD) == 2)) - && (player.isFriend() || player.isClanMember()) - && CAST_OPTIONS_KEYWORDS.contains(pOptionToReplace)) + if (identifier >= 0 && identifier < players.length) { - addswap(pOptionToReplace); + Player player = players[identifier]; + if (player != null) + { + if (((config.getRemoveFreezePlayerCoX() && client.getVar(Varbits.IN_RAID) == 1) + || (config.getRemoveFreezePlayerToB() && client.getVar(Varbits.THEATRE_OF_BLOOD) == 2)) + && (player.isFriend() || player.isClanMember()) + && CAST_OPTIONS_KEYWORDS.contains(pOptionToReplace)) + { + addswap(pOptionToReplace); + } + } } + } if (option.equals("talk-to")) { diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/menuentryswapper/util/DigsitePendantMode.java b/runelite-client/src/main/java/net/runelite/client/plugins/menuentryswapper/util/DigsitePendantMode.java index 95e84a3188..dd9b58eea5 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/menuentryswapper/util/DigsitePendantMode.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/menuentryswapper/util/DigsitePendantMode.java @@ -29,7 +29,7 @@ public enum DigsitePendantMode { DIGSITE("Digsite"), FOSSIL_ISLAND("Fossil Island"), - LITHKREN("Lithkren"); + LITHKREN("Lithkren Dungeon"); private final String name; diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/npchighlight/MemorizedNpc.java b/runelite-client/src/main/java/net/runelite/client/plugins/npchighlight/MemorizedNpc.java index 09531c4cfc..404748db74 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/npchighlight/MemorizedNpc.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/npchighlight/MemorizedNpc.java @@ -25,7 +25,9 @@ package net.runelite.client.plugins.npchighlight; import java.util.ArrayList; +import java.util.HashSet; import java.util.List; +import java.util.Set; import lombok.Getter; import lombok.Setter; import net.runelite.api.NPC; @@ -38,7 +40,7 @@ class MemorizedNpc private int npcIndex; @Getter - private String npcName; + private Set npcNames; @Getter private int npcSize; @@ -63,7 +65,8 @@ class MemorizedNpc MemorizedNpc(NPC npc) { - this.npcName = npc.getName(); + this.npcNames = new HashSet<>(); + this.npcNames.add(npc.getName()); this.npcIndex = npc.getIndex(); this.possibleRespawnLocations = new ArrayList<>(); this.respawnTime = -1; 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 34d89e1944..63ec966f6d 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 @@ -34,6 +34,7 @@ import java.util.Arrays; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; +import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; @@ -58,6 +59,7 @@ import net.runelite.api.events.GameTick; import net.runelite.api.events.GraphicsObjectCreated; import net.runelite.api.events.MenuEntryAdded; import net.runelite.api.events.MenuOptionClicked; +import net.runelite.api.events.NpcDefinitionChanged; import net.runelite.api.events.NpcDespawned; import net.runelite.api.events.NpcSpawned; import net.runelite.client.callback.ClientThread; @@ -304,14 +306,15 @@ public class NpcIndicatorsPlugin extends Plugin if (removed) { - highlightedNpcs.remove(npc); - memorizedNpcs.remove(npc.getIndex()); + MemorizedNpc mn = memorizedNpcs.get(npc.getIndex()); + if (mn != null && isNpcMemorizationUnnecessary(mn)) + { + memorizedNpcs.remove(npc.getIndex()); + } } else { - memorizeNpc(npc); npcTags.add(id); - highlightedNpcs.add(npc); } click.consume(); @@ -320,30 +323,28 @@ public class NpcIndicatorsPlugin extends Plugin @Subscribe public void onNpcSpawned(NpcSpawned npcSpawned) { - final NPC npc = npcSpawned.getNpc(); - final String npcName = npc.getName(); + NPC npc = npcSpawned.getNpc(); + highlightNpcIfMatch(npc); - if (npcName == null) + if (memorizedNpcs.containsKey(npc.getIndex())) { - return; - } - - if (npcTags.contains(npc.getIndex())) - { - memorizeNpc(npc); - highlightedNpcs.add(npc); spawnedNpcsThisTick.add(npc); - return; } + } - for (String highlight : highlights) + @Subscribe + public void onNpcDefinitionChanged(NpcDefinitionChanged event) + { + NPC npc = event.getNpc(); + highlightNpcIfMatch(npc); + + MemorizedNpc mn = memorizedNpcs.get(npc.getIndex()); + if (mn != null) { - if (WildcardMatcher.matches(highlight, npcName)) + String npcName = npc.getName(); + if (npcName != null) { - memorizeNpc(npc); - highlightedNpcs.add(npc); - spawnedNpcsThisTick.add(npc); - break; + mn.getNpcNames().add(npcName); } } } @@ -428,12 +429,59 @@ public class NpcIndicatorsPlugin extends Plugin return new WorldPoint(currWP.getX() - dx, currWP.getY() - dy, currWP.getPlane()); } + private void highlightNpcIfMatch(final NPC npc) + { + if (npcTags.contains(npc.getIndex())) + { + memorizeNpc(npc); + highlightedNpcs.add(npc); + return; + } + + final String npcName = npc.getName(); + if (npcName != null) + { + for (String highlight : highlights) + { + if (WildcardMatcher.matches(highlight, npcName)) + { + memorizeNpc(npc); + highlightedNpcs.add(npc); + return; + } + } + } + + highlightedNpcs.remove(npc); + } + private void memorizeNpc(NPC npc) { final int npcIndex = npc.getIndex(); memorizedNpcs.putIfAbsent(npcIndex, new MemorizedNpc(npc)); } + private boolean isNpcMemorizationUnnecessary(final MemorizedNpc mn) + { + if (npcTags.contains(mn.getNpcIndex())) + { + return false; + } + + for (String npcName : mn.getNpcNames()) + { + for (String highlight : highlights) + { + if (WildcardMatcher.matches(highlight, npcName)) + { + return false; + } + } + } + + return true; + } + private void removeOldHighlightedRespawns() { deadNpcsToDisplay.values().removeIf(x -> x.getDiedOnTick() + x.getRespawnTime() <= client.getTickCount() + 1); @@ -464,34 +512,21 @@ public class NpcIndicatorsPlugin extends Plugin return; } - outer: + Iterator> it = memorizedNpcs.entrySet().iterator(); + while (it.hasNext()) + { + MemorizedNpc mn = it.next().getValue(); + + if (isNpcMemorizationUnnecessary(mn)) + { + deadNpcsToDisplay.remove(mn.getNpcIndex()); + it.remove(); + } + } + for (NPC npc : client.getNpcs()) { - final String npcName = npc.getName(); - - if (npcName == null) - { - continue; - } - - if (npcTags.contains(npc.getIndex())) - { - highlightedNpcs.add(npc); - continue; - } - - for (String highlight : highlights) - { - if (WildcardMatcher.matches(highlight, npcName)) - { - memorizeNpc(npc); - highlightedNpcs.add(npc); - continue outer; - } - } - - // NPC is not highlighted - memorizedNpcs.remove(npc.getIndex()); + highlightNpcIfMatch(npc); } } @@ -524,7 +559,7 @@ public class NpcIndicatorsPlugin extends Plugin if (!mn.getPossibleRespawnLocations().isEmpty()) { - log.debug("Starting {} tick countdown for {}", mn.getRespawnTime(), mn.getNpcName()); + log.debug("Starting {} tick countdown for {}", mn.getRespawnTime(), mn.getNpcNames().iterator().next()); deadNpcsToDisplay.put(mn.getNpcIndex(), mn); } } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/npcstatus/MemorizedNPC.java b/runelite-client/src/main/java/net/runelite/client/plugins/npcstatus/MemorizedNPC.java new file mode 100644 index 0000000000..4a746e63db --- /dev/null +++ b/runelite-client/src/main/java/net/runelite/client/plugins/npcstatus/MemorizedNPC.java @@ -0,0 +1,84 @@ +/* + * Copyright (c) 2019, GeChallengeM + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package net.runelite.client.plugins.npcstatus; + +import java.awt.Color; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.Setter; +import net.runelite.api.NPC; +import net.runelite.api.coords.WorldArea; +import net.runelite.api.Actor; + +@Getter +class MemorizedNPC +{ + private NPC npc; + private int npcIndex; + private String npcName; + private int attackSpeed; + @Setter + private int combatTimerEnd; + @Setter + private int timeLeft; + @Setter + private int flinchTimerEnd; + @Setter + private Status status; + @Setter + private WorldArea lastnpcarea; + @Setter + private Actor lastinteracted; + @Setter + private int lastspotanimation; + + MemorizedNPC(NPC npc, int attackSpeed, WorldArea worldArea) + { + this.npc = npc; + this.npcIndex = npc.getIndex(); + this.npcName = npc.getName(); + this.attackSpeed = attackSpeed; + this.combatTimerEnd = -1; + this.flinchTimerEnd = -1; + this.timeLeft = 0; + this.status = Status.OUT_OF_COMBAT; + this.lastnpcarea = worldArea; + this.lastinteracted = null; + this.lastspotanimation = -1; + } + + @Getter + @AllArgsConstructor + enum Status + { + FLINCHING("Flinching", Color.GREEN), + IN_COMBAT_DELAY("In Combat Delay", Color.ORANGE), + IN_COMBAT("In Combat", Color.RED), + OUT_OF_COMBAT("Out of Combat", Color.BLUE); + + private String name; + private Color color; + } +} \ No newline at end of file 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/npcstatus/NpcStatusConfig.java similarity index 68% rename from runelite-client/src/main/java/net/runelite/client/plugins/fightcave/JadAttack.java rename to runelite-client/src/main/java/net/runelite/client/plugins/npcstatus/NpcStatusConfig.java index ae752e015a..bf0495fae5 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/fightcave/JadAttack.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/npcstatus/NpcStatusConfig.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, Devin French + * Copyright (c) 2019, GeChallengeM * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -22,32 +22,22 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package net.runelite.client.plugins.fightcave; +package net.runelite.client.plugins.npcstatus; -import net.runelite.api.AnimationID; -import net.runelite.api.Prayer; +import net.runelite.client.config.Config; +import net.runelite.client.config.ConfigGroup; +import net.runelite.client.config.ConfigItem; -public enum JadAttack +@ConfigGroup("npcstatus") +public interface NpcStatusConfig extends Config { - 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) + @ConfigItem( + keyName = "AttackRange", + name = "NPC Attack range", + description = "The attack range of the NPC" + ) + default int getRange() { - this.animation = animation; - this.prayer = prayer; + return 1; } - - 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/npcstatus/NpcStatusOverlay.java b/runelite-client/src/main/java/net/runelite/client/plugins/npcstatus/NpcStatusOverlay.java new file mode 100644 index 0000000000..7b948f24c0 --- /dev/null +++ b/runelite-client/src/main/java/net/runelite/client/plugins/npcstatus/NpcStatusOverlay.java @@ -0,0 +1,89 @@ +/* + * Copyright (c) 2018, GeChallengeM + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package net.runelite.client.plugins.npcstatus; + +import java.awt.Dimension; +import java.awt.Graphics2D; +import javax.inject.Inject; +import net.runelite.api.Client; +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.OverlayUtil; + +public class NpcStatusOverlay extends Overlay +{ + private final Client client; + private final NpcStatusPlugin plugin; + + @Inject + NpcStatusOverlay(Client client, NpcStatusPlugin plugin) + { + this.client = client; + this.plugin = plugin; + setPosition(OverlayPosition.DYNAMIC); + setLayer(OverlayLayer.ABOVE_SCENE); + } + + @Override + public Dimension render(Graphics2D graphics) + { + for (MemorizedNPC npc : plugin.getMemorizedNPCs()) + { + if (npc.getNpc().getInteracting() == null) + { + continue; + } + if (npc.getNpc().getInteracting() == client.getLocalPlayer() || client.getLocalPlayer().getInteracting() == npc.getNpc()) + { + switch (npc.getStatus()) + { + case FLINCHING: + npc.setTimeLeft(Math.max(0, npc.getFlinchTimerEnd() - client.getTickCount())); + break; + case IN_COMBAT_DELAY: + npc.setTimeLeft(Math.max(0, npc.getCombatTimerEnd() - client.getTickCount() - 7)); + break; + case IN_COMBAT: + npc.setTimeLeft(Math.max(0, npc.getCombatTimerEnd() - client.getTickCount())); + break; + case OUT_OF_COMBAT: + default: + npc.setTimeLeft(0); + break; + } + + Point textLocation = npc.getNpc().getCanvasTextLocation(graphics, Integer.toString(npc.getTimeLeft()), npc.getNpc().getLogicalHeight() + 40); + + if (textLocation != null) + { + OverlayUtil.renderTextLocation(graphics, textLocation, Integer.toString(npc.getTimeLeft()), npc.getStatus().getColor()); + } + } + } + return null; + } +} \ No newline at end of file diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/npcstatus/NpcStatusPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/npcstatus/NpcStatusPlugin.java new file mode 100644 index 0000000000..0f1a59a17a --- /dev/null +++ b/runelite-client/src/main/java/net/runelite/client/plugins/npcstatus/NpcStatusPlugin.java @@ -0,0 +1,231 @@ +/* + * Copyright (c) 2019, GeChallengeM + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package net.runelite.client.plugins.npcstatus; + +import com.google.inject.Provides; +import java.time.Instant; +import java.util.Arrays; +import java.util.HashSet; +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 net.runelite.api.GameState; +import net.runelite.api.GraphicID; +import net.runelite.api.Hitsplat; +import net.runelite.api.NPC; +import net.runelite.api.coords.WorldArea; +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.client.config.ConfigManager; +import net.runelite.client.eventbus.Subscribe; +import net.runelite.client.game.ItemManager; +import net.runelite.client.game.NPCManager; +import net.runelite.client.plugins.Plugin; +import net.runelite.client.plugins.PluginDescriptor; +import net.runelite.client.ui.overlay.OverlayManager; + +@Slf4j +@PluginDescriptor( + name = "NPC Status Timer", + description = "Adds a timer on NPC's for their attacks and flinching.", + tags = {"flinch", "npc"}, + enabledByDefault = false +) +public class NpcStatusPlugin extends Plugin +{ + @Getter(AccessLevel.PACKAGE) + private final Set memorizedNPCs = new HashSet<>(); + @Inject + private Client client; + @Inject + private OverlayManager overlayManager; + @Inject + private ItemManager itemManager; + @Inject + private NPCManager npcManager; + @Inject + private NpcStatusConfig config; + @Inject + private NpcStatusOverlay npcStatusOverlay; + @Getter(AccessLevel.PACKAGE) + private Instant lastTickUpdate; + private WorldArea lastPlayerLocation; + + @Provides + NpcStatusConfig provideConfig(ConfigManager configManager) + { + return configManager.getConfig(NpcStatusConfig.class); + } + + @Override + protected void startUp() throws Exception + { + overlayManager.add(npcStatusOverlay); + } + + @Override + protected void shutDown() throws Exception + { + overlayManager.remove(npcStatusOverlay); + memorizedNPCs.clear(); + } + + @Subscribe + public void onNpcSpawned(NpcSpawned npcSpawned) + { + final NPC npc = npcSpawned.getNpc(); + final String npcName = npc.getName(); + + if (npcName == null || !Arrays.asList(npc.getDefinition().getActions()).contains("Attack")) + { + return; + } + memorizedNPCs.add(new MemorizedNPC(npc, npcManager.getAttackSpeed(npc.getId()), npc.getWorldArea())); + } + + @Subscribe + public void onNpcDespawned(NpcDespawned npcDespawned) + { + final NPC npc = npcDespawned.getNpc(); + memorizedNPCs.removeIf(c -> c.getNpc() == npc); + } + + @Subscribe + public void onGameStateChanged(GameStateChanged event) + { + if (event.getGameState() == GameState.LOGIN_SCREEN || + event.getGameState() == GameState.HOPPING) + { + memorizedNPCs.clear(); + } + } + + @Subscribe + public void onHitsplatApplied(HitsplatApplied event) + { + if (event.getActor().getInteracting() != client.getLocalPlayer()) + { + return; + } + final Hitsplat hitsplat = event.getHitsplat(); + if (hitsplat.getHitsplatType() == Hitsplat.HitsplatType.DAMAGE || hitsplat.getHitsplatType() == Hitsplat.HitsplatType.BLOCK) + { + if (event.getActor() instanceof NPC) + { + for (MemorizedNPC mn : memorizedNPCs) + { + if (mn.getStatus() == MemorizedNPC.Status.OUT_OF_COMBAT || (mn.getStatus() == MemorizedNPC.Status.IN_COMBAT && mn.getCombatTimerEnd() - client.getTickCount() < 1) || mn.getLastinteracted() == null) + { + mn.setStatus(MemorizedNPC.Status.FLINCHING); + mn.setCombatTimerEnd(-1); + mn.setFlinchTimerEnd(client.getTickCount() + mn.getAttackSpeed() / 2 + 1); + } + } + } + } + } + + private void checkStatus() + { + for (MemorizedNPC npc : memorizedNPCs) + { + final int ATTACK_SPEED = npc.getAttackSpeed(); + final double CombatTime = npc.getCombatTimerEnd() - client.getTickCount(); + final double FlinchTime = npc.getFlinchTimerEnd() - client.getTickCount(); + if (npc.getNpc().getWorldArea() == null) + { + continue; + } + if (npc.getNpc().getInteracting() == client.getLocalPlayer()) + { + if (npc.getLastspotanimation() == GraphicID.SPLASH && npc.getNpc().getSpotAnimation() == GraphicID.SPLASH) //For splash flinching + { + npc.setLastspotanimation(-1); + if ((npc.getStatus() == MemorizedNPC.Status.OUT_OF_COMBAT ) || npc.getLastinteracted() == null) + { + npc.setStatus(MemorizedNPC.Status.FLINCHING); + npc.setCombatTimerEnd(-1); + npc.setFlinchTimerEnd(client.getTickCount() + ATTACK_SPEED / 2 + 1); + npc.setLastnpcarea(npc.getNpc().getWorldArea()); + npc.setLastinteracted(npc.getNpc().getInteracting()); + continue; + } + } + //Checks: will the NPC attack this tick? + if (((npc.getNpc().getWorldArea().canMelee(client, lastPlayerLocation) && config.getRange() == 1) //Separate mechanics for meleerange-only NPC's because they have extra collisiondata checks (fences etc.) and can't attack diagonally + || (lastPlayerLocation.hasLineOfSightTo(client, npc.getNpc().getWorldArea()) && npc.getNpc().getWorldArea().distanceTo(lastPlayerLocation) <= config.getRange() && config.getRange() > 1)) + && ((npc.getStatus() != MemorizedNPC.Status.FLINCHING && CombatTime < 9) || (npc.getStatus() == MemorizedNPC.Status.FLINCHING && FlinchTime < 2)) + && npc.getNpc().getAnimation() != -1 //Failsafe, attacking NPC's always have an animation. + && !(npc.getLastnpcarea().distanceTo(lastPlayerLocation) == 0 && npc.getLastnpcarea() != npc.getNpc().getWorldArea())) //Weird mechanic: NPC's can't attack on the tick they do a random move + { + npc.setCombatTimerEnd(client.getTickCount() + ATTACK_SPEED + 8); + npc.setStatus(MemorizedNPC.Status.IN_COMBAT_DELAY); + npc.setLastnpcarea(npc.getNpc().getWorldArea()); + npc.setLastspotanimation(npc.getNpc().getSpotAnimation()); + npc.setLastinteracted(npc.getNpc().getInteracting()); + continue; + } + } + switch (npc.getStatus()) + { + case IN_COMBAT: + if (CombatTime < 2) + { + npc.setStatus(MemorizedNPC.Status.OUT_OF_COMBAT); + } + break; + case IN_COMBAT_DELAY: + if (CombatTime < 9) + { + npc.setStatus(MemorizedNPC.Status.IN_COMBAT); + } + break; + case FLINCHING: + if (FlinchTime < 2) + { + npc.setStatus(MemorizedNPC.Status.IN_COMBAT); + npc.setCombatTimerEnd(client.getTickCount() + 8); + } + } + npc.setLastnpcarea(npc.getNpc().getWorldArea()); + npc.setLastspotanimation(npc.getNpc().getSpotAnimation()); + npc.setLastinteracted(npc.getNpc().getInteracting()); + } + } + + @Subscribe + public void onGameTick(GameTick event) + { + lastTickUpdate = Instant.now(); + checkStatus(); + lastPlayerLocation = client.getLocalPlayer().getWorldArea(); + } +} 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 a2b9f1bb01..e937633dc8 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 @@ -106,7 +106,7 @@ public class BatSolver } - public void calculateChanceOfPoison() + private void calculateChanceOfPoison() { if (getType() == null) { 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 11bda048e5..82c36163e4 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 @@ -35,9 +35,9 @@ import lombok.Getter; // 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 +class SolutionSet { - public static final SolutionSet[] SOLUTION_SETS = + static final SolutionSet[] SOLUTION_SETS = { new SolutionSet(ThievingRoomType.LEFT_TURN, 1, 16, 17, 55), new SolutionSet(ThievingRoomType.LEFT_TURN, 1, 17, 38, 54), @@ -147,12 +147,12 @@ public class SolutionSet this.emptyChests = new HashSet<>(Arrays.asList(emptyChests)); } - public void addEmptyChest(int chestId) + void addEmptyChest(int chestId) { emptyChests.add(chestId); } - public boolean containsChest(int chestId) + boolean containsChest(int chestId) { return emptyChests.contains(chestId); } 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 490c5d40b1..b1ba3e0102 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 @@ -15,7 +15,7 @@ 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) + private InstancePoint(int x, int y, int rot) { this.x = x; this.y = y; @@ -29,7 +29,7 @@ public class InstancePoint this.rot = 0; } - public static InstancePoint buildFromPoint(WorldPoint worldPoint, Client client) + static InstancePoint buildFromPoint(WorldPoint worldPoint, Client client) { Point point = new Point(worldPoint.getX(), worldPoint.getY()); Point base = new Point(client.getBaseX(), client.getBaseY()); @@ -48,7 +48,7 @@ public class InstancePoint return buildFromTile(base, point, rotation, new Point(x, y)); } - public static InstancePoint buildFromTile(Point base, Point tile, int rot, Point chunkOrigin) + private static InstancePoint buildFromTile(Point base, Point tile, int rot, Point chunkOrigin) { int deltaX = tile.getX() - base.getX(); int deltaY = tile.getY() - base.getY(); diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/raidsthieving/RaidsThievingConstants.java b/runelite-client/src/main/java/net/runelite/client/plugins/raidsthieving/RaidsThievingConstants.java index 965934a01b..8ab527ebe8 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/raidsthieving/RaidsThievingConstants.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/raidsthieving/RaidsThievingConstants.java @@ -26,10 +26,10 @@ package net.runelite.client.plugins.raidsthieving; public class RaidsThievingConstants { - public static final int CLOSED_CHEST_ID = 29742; - public static final int OPEN_EMPTY_CHEST = 29743; - public static final int OPEN_FULL_CHEST_1 = 29744; - public static final int OPEN_FULL_CHEST_2 = 29745; - public static final int EMPTY_TROUGH = 29746; + static final int CLOSED_CHEST_ID = 29742; + static final int OPEN_EMPTY_CHEST = 29743; + static final int OPEN_FULL_CHEST_1 = 29744; + static final int OPEN_FULL_CHEST_2 = 29745; + static final int EMPTY_TROUGH = 29746; public static final int[] STORAGE = {29769, 29770, 29771, 29772}; } 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 1569ab79fe..a7679b985a 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 @@ -201,6 +201,12 @@ public class RaidsThievingPlugin extends Plugin { log.debug("Found poison splat"); WorldPoint loc = WorldPoint.fromLocal(client, obj.getLocation()); + + if (chests.get(loc) == null) + { + return; + } + chests.get(loc).setPoison(true); } } @@ -235,7 +241,7 @@ public class RaidsThievingPlugin extends Plugin mapper = null; } - public int numberOfEmptyChestsFound() + int numberOfEmptyChestsFound() { int total = 0; for (ThievingChest chest : chests.values()) @@ -248,7 +254,6 @@ public class RaidsThievingPlugin extends Plugin return total; } - private boolean checkForBats() { for (ThievingChest chest : chests.values()) @@ -266,7 +271,7 @@ public class RaidsThievingPlugin extends Plugin return false; } - public int getChestId(WorldPoint worldPoint) + int getChestId(WorldPoint worldPoint) { return chests.get(worldPoint).getChestId(); } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/screenmarkers/ui/ScreenMarkerPanel.java b/runelite-client/src/main/java/net/runelite/client/plugins/screenmarkers/ui/ScreenMarkerPanel.java index d225410209..23b6cad174 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/screenmarkers/ui/ScreenMarkerPanel.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/screenmarkers/ui/ScreenMarkerPanel.java @@ -29,6 +29,8 @@ import java.awt.BorderLayout; import java.awt.Color; import java.awt.Dimension; import java.awt.FlowLayout; +import java.awt.event.KeyAdapter; +import java.awt.event.KeyEvent; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.awt.event.WindowAdapter; @@ -169,12 +171,7 @@ class ScreenMarkerPanel extends JPanel @Override public void mousePressed(MouseEvent mouseEvent) { - marker.getMarker().setName(nameInput.getText()); - plugin.updateConfig(); - - nameInput.setEditable(false); - updateNameActions(false); - requestFocusInWindow(); + save(); } @Override @@ -198,10 +195,7 @@ class ScreenMarkerPanel extends JPanel @Override public void mousePressed(MouseEvent mouseEvent) { - nameInput.setEditable(false); - nameInput.setText(marker.getMarker().getName()); - updateNameActions(false); - requestFocusInWindow(); + cancel(); } @Override @@ -252,6 +246,35 @@ class ScreenMarkerPanel extends JPanel nameInput.setPreferredSize(new Dimension(0, 24)); nameInput.getTextField().setForeground(Color.WHITE); nameInput.getTextField().setBorder(new EmptyBorder(0, 8, 0, 0)); + nameInput.addKeyListener(new KeyAdapter() + { + @Override + public void keyPressed(KeyEvent e) + { + if (e.getKeyCode() == KeyEvent.VK_ENTER) + { + save(); + } + else if (e.getKeyCode() == KeyEvent.VK_ESCAPE) + { + cancel(); + } + } + }); + nameInput.getTextField().addMouseListener(new MouseAdapter() + { + @Override + public void mouseEntered(MouseEvent mouseEvent) + { + preview(true); + } + + @Override + public void mouseExited(MouseEvent mouseEvent) + { + preview(false); + } + }); nameWrapper.add(nameInput, BorderLayout.CENTER); nameWrapper.add(nameActions, BorderLayout.EAST); @@ -359,10 +382,7 @@ class ScreenMarkerPanel extends JPanel @Override public void mousePressed(MouseEvent mouseEvent) { - visible = !visible; - marker.getMarker().setVisible(visible); - plugin.updateConfig(); - updateVisibility(); + toggle(!visible); } @Override @@ -424,6 +444,42 @@ class ScreenMarkerPanel extends JPanel } + private void preview(boolean on) + { + if (visible) + { + return; + } + + marker.getMarker().setVisible(on); + } + + private void toggle(boolean on) + { + visible = on; + marker.getMarker().setVisible(visible); + plugin.updateConfig(); + updateVisibility(); + } + + private void save() + { + marker.getMarker().setName(nameInput.getText()); + plugin.updateConfig(); + + nameInput.setEditable(false); + updateNameActions(false); + requestFocusInWindow(); + } + + private void cancel() + { + nameInput.setEditable(false); + nameInput.setText(marker.getMarker().getName()); + updateNameActions(false); + requestFocusInWindow(); + } + private void updateNameActions(boolean saveAndCancel) { save.setVisible(saveAndCancel); 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 36ad3f492a..a4e2b92543 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 @@ -26,11 +26,30 @@ package net.runelite.client.plugins.shiftwalker; import net.runelite.client.config.Config; import net.runelite.client.config.ConfigGroup; -// import net.runelite.client.config.ConfigItem; +import net.runelite.client.config.ConfigItem; @ConfigGroup("shiftwalkhere") public interface ShiftWalkerConfig extends Config { + @ConfigItem( + keyName = "shiftWalk", + name = "Shift to Walk", + description = "For when you want Walk here as a priority" + ) + default boolean shiftWalk() + { + return false; + } + + @ConfigItem( + keyName = "shiftLoot", + name = "Shift to Loot", + description = "For when people stand on your loot" + ) + default boolean shiftLoot() + { + return false; + } /* @ConfigItem( 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 e9378e6f99..7197de9eaa 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 @@ -50,7 +50,7 @@ public class ShiftWalkerPlugin extends Plugin { private static final String WALK_HERE = "Walk here"; - + private static final String TAKE = "Take"; @Inject private ShiftWalkerConfig config; @@ -92,11 +92,20 @@ public class ShiftWalkerPlugin extends Plugin void startPrioritizing() { - menuManager.addPriorityEntry(WALK_HERE); + if (config.shiftLoot()) + { + menuManager.addPriorityEntry(TAKE); + } + + if (config.shiftWalk()) + { + menuManager.addPriorityEntry(WALK_HERE); + } } void stopPrioritizing() { + menuManager.removePriorityEntry(TAKE); menuManager.removePriorityEntry(WALK_HERE); } } 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 b97e2aa21f..dc2afab56c 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 @@ -27,7 +27,7 @@ package net.runelite.client.plugins.slayer; import java.util.ArrayList; import java.util.List; -public class KnapsackSolver +class KnapsackSolver { private List reconstructItemsInSack(int[][] sackMatrix, List items, int i, int w) @@ -49,7 +49,7 @@ public class KnapsackSolver } } - public int howMuchFitsInSack(List items, int maxWeight) + int howMuchFitsInSack(List items, int maxWeight) { int itemCount = items.size(); diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/slayer/NPCPresence.java b/runelite-client/src/main/java/net/runelite/client/plugins/slayer/NPCPresence.java index 0924660d6c..cc28df5393 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/slayer/NPCPresence.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/slayer/NPCPresence.java @@ -29,17 +29,17 @@ public class NPCPresence return name + "[" + combatLevel + "]"; } - public boolean shouldExist() + boolean shouldExist() { return fadeTimer > 0; } - public void tickExistence() + void tickExistence() { fadeTimer--; } - public static NPCPresence buildPresence(NPC npc) + static NPCPresence buildPresence(NPC npc) { return new NPCPresence(npc.getName(), npc.getCombatLevel()); } 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 e15e641d33..b805edd030 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 @@ -36,6 +36,7 @@ import java.time.Instant; import java.time.temporal.ChronoUnit; import java.util.ArrayList; import java.util.Arrays; +import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Set; @@ -66,6 +67,7 @@ import net.runelite.api.events.ExperienceChanged; import net.runelite.api.events.GameStateChanged; import net.runelite.api.events.GameTick; import net.runelite.api.events.InteractingChanged; +import net.runelite.api.events.NpcDefinitionChanged; import net.runelite.api.events.NpcDespawned; import net.runelite.api.events.NpcSpawned; import net.runelite.api.events.VarbitChanged; @@ -79,7 +81,6 @@ import net.runelite.client.chat.ChatCommandManager; import net.runelite.client.chat.ChatMessageBuilder; import net.runelite.client.chat.ChatMessageManager; import net.runelite.client.config.ConfigManager; -import net.runelite.client.eventbus.EventBus; import net.runelite.client.eventbus.Subscribe; import net.runelite.client.events.ChatInput; import net.runelite.client.game.AsyncBufferedImage; @@ -215,11 +216,8 @@ public class SlayerPlugin extends Plugin @Inject private ChatClient chatClient; - @Inject - private EventBus eventBus; - @Getter(AccessLevel.PACKAGE) - private List highlightedTargets = new ArrayList<>(); + private final Set highlightedTargets = new HashSet<>(); @Getter(AccessLevel.PACKAGE) @Setter(AccessLevel.PACKAGE) @@ -349,8 +347,17 @@ public class SlayerPlugin extends Plugin if (isTarget(npc, targetNames)) { highlightedTargets.add(npc); - NPCPresence newPresence = NPCPresence.buildPresence(npc); - // log.debug("New presence of " + newPresence.toString()); + } + } + + @Subscribe + public void onNpcDefinitionChanged(NpcDefinitionChanged event) + { + NPC npc = event.getNpc(); + + if (isTarget(npc, targetNames)) + { + highlightedTargets.add(npc); } } @@ -363,7 +370,6 @@ public class SlayerPlugin extends Plugin { NPCPresence lingeringPresence = NPCPresence.buildPresence(npc); lingeringPresences.add(lingeringPresence); - // log.debug("Presence of " + lingeringPresence.toString() + " now lingering"); } } @@ -390,7 +396,7 @@ public class SlayerPlugin extends Plugin } } - int estimateKillCount(List potentialKills, int gains) + private int estimateKillCount(List potentialKills, int gains) { // failsafe to avoid calculating kill count if there were no slayer monsters around that could be killed on task // this failsafe *WILL FAIL* if someone decides to lamp their slayer in the middle of a task next to on task creatures @@ -583,8 +589,6 @@ public class SlayerPlugin extends Plugin streak = 1; break; case 1: - streak = Integer.parseInt(matches.get(0)); - break; case 3: streak = Integer.parseInt(matches.get(0)); break; @@ -665,29 +669,13 @@ public class SlayerPlugin extends Plugin // this is not the initial xp sent on login so these are new xp gains int gains = slayerExp - cachedXp; - //log.debug("Slayer xp drop received"); - - //StringBuilder debugString = new StringBuilder(); - // potential npcs to give xp drop are current highlighted npcs and the lingering presences - List potentialNPCs = new ArrayList<>(); - //debugString.append("Lingering presences {"); - for (NPCPresence presence : lingeringPresences) - { - potentialNPCs.add(presence); - // debugString.append(presence.toString()); - // debugString.append(", "); - } - //debugString.append("}\nCurrent presences {"); + List potentialNPCs = new ArrayList<>(lingeringPresences); for (NPC npc : highlightedTargets) { NPCPresence currentPresence = NPCPresence.buildPresence(npc); potentialNPCs.add(currentPresence); - // debugString.append(currentPresence.toString()); - // debugString.append(", "); } - //debugString.append("}"); - //log.debug(debugString.toString()); int killCount = estimateKillCount(potentialNPCs, gains); for (int i = 0; i < killCount; i++) @@ -751,7 +739,7 @@ public class SlayerPlugin extends Plugin } @VisibleForTesting - void killedOne() + private void killedOne() { if (currentTask.getAmount() == 0) { @@ -788,7 +776,7 @@ public class SlayerPlugin extends Plugin } // checks if any contiguous subsequence of seq0 exactly matches the String toMatch - boolean contiguousSubsequenceMatches(String[] seq0, String toMatch) + private boolean contiguousSubsequenceMatches(String[] seq0, String toMatch) { for (int i = 0; i < seq0.length; i++) { @@ -906,8 +894,7 @@ public class SlayerPlugin extends Plugin if (task != null) { - task.getNpcIds().stream() - .forEach(targetIds::add); + targetIds.addAll(task.getNpcIds()); } } @@ -962,7 +949,7 @@ public class SlayerPlugin extends Plugin rebuildTargetList(); } - public AsyncBufferedImage getImageForTask(Task task) + AsyncBufferedImage getImageForTask(Task task) { int itemSpriteId = ItemID.ENCHANTED_GEM; if (task != null) @@ -1048,6 +1035,11 @@ public class SlayerPlugin extends Plugin return; } + if (task == null) + { + return; + } + if (TASK_STRING_VALIDATION.matcher(task.getTask()).find() || task.getTask().length() > TASK_STRING_MAX_LENGTH || TASK_STRING_VALIDATION.matcher(task.getLocation()).find() || task.getLocation().length() > TASK_STRING_MAX_LENGTH) { 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 ea3fbf0712..0cd238a6d3 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 @@ -343,7 +343,7 @@ public class SlayerTaskPanel extends PluginPanel changePauseState(paused); } - static String htmlLabel(String key, long timeMillis) + private static String htmlLabel(String key, long timeMillis) { if (timeMillis == Long.MAX_VALUE) { @@ -363,7 +363,7 @@ public class SlayerTaskPanel extends PluginPanel } } - static String htmlLabel(String key, int value) + private static String htmlLabel(String key, int value) { String valueStr = StackFormatter.quantityToRSDecimalStack(value); return String.format(HTML_LABEL_TEMPLATE, ColorUtil.toHexColor(ColorScheme.LIGHT_GRAY_COLOR), 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 a3e3898390..458c9421c2 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 @@ -31,14 +31,14 @@ import java.io.InputStreamReader; import java.util.List; import java.util.Map; -public class SlayerXpDropLookup +class SlayerXpDropLookup { private Map> xpMap; // floating point math equality private static final double EPSILON = 1e-6; - void loadXpJson() + private void loadXpJson() { final InputStream xpFile = getClass().getResourceAsStream("/slayer_xp.json"); Gson gson = new Gson(); @@ -76,7 +76,7 @@ public class SlayerXpDropLookup * @param npc the npc we are estimating slayer xp for * @return our best guess for the slayer xp for this npc */ - public double findXpForNpc(NPCPresence npc) + double findXpForNpc(NPCPresence npc) { List xpCombatLevel = xpMap.get(npc.getName()); if (xpCombatLevel == null) @@ -127,7 +127,7 @@ public class SlayerXpDropLookup return -1; } - public SlayerXpDropLookup() + SlayerXpDropLookup() { loadXpJson(); } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/slayer/TargetClickboxOverlay.java b/runelite-client/src/main/java/net/runelite/client/plugins/slayer/TargetClickboxOverlay.java index e9f6866770..12eeac7ead 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/slayer/TargetClickboxOverlay.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/slayer/TargetClickboxOverlay.java @@ -26,12 +26,11 @@ */ package net.runelite.client.plugins.slayer; -import java.awt.BasicStroke; import java.awt.Color; import java.awt.Dimension; import java.awt.Graphics2D; import java.awt.Polygon; -import java.util.List; +import java.util.Set; import javax.inject.Inject; import net.runelite.api.Client; import net.runelite.api.NPC; @@ -57,8 +56,7 @@ public class TargetClickboxOverlay extends Overlay private final ModelOutlineRenderer modelOutliner; @Inject - TargetClickboxOverlay(Client client, SlayerConfig config, SlayerPlugin plugin, - ModelOutlineRenderer modelOutlineRenderer) + TargetClickboxOverlay(Client client, SlayerConfig config, SlayerPlugin plugin, ModelOutlineRenderer modelOutlineRenderer) { this.client = client; this.config = config; @@ -73,10 +71,16 @@ public class TargetClickboxOverlay extends Overlay { if (config.highlightTargets()) { - List targets = plugin.getHighlightedTargets(); + Set targets = plugin.getHighlightedTargets(); for (NPC target : targets) { + if (target == null || target.getName() == null) + { + continue; + } + Color coloration = config.getTargetColor(); + if (plugin.isSuperior(target.getName())) { coloration = config.getSuperiorColor(); @@ -95,28 +99,36 @@ public class TargetClickboxOverlay extends Overlay { case SOUTH_WEST_TILE: LocalPoint lp1 = LocalPoint.fromWorld(client, actor.getWorldLocation()); + + if (lp1 == null) + { + return; + } + Polygon tilePoly1 = Perspective.getCanvasTilePoly(client, lp1); - renderPoly(graphics, color, tilePoly1); + OverlayUtil.renderPolygon(graphics, tilePoly1, color); break; case TILE: int size = 1; NPCDefinition composition = actor.getTransformedDefinition(); + if (composition != null) { size = composition.getSize(); } + LocalPoint lp = actor.getLocalLocation(); Polygon tilePoly = Perspective.getCanvasTileAreaPoly(client, lp, size); - renderPoly(graphics, color, tilePoly); + OverlayUtil.renderPolygon(graphics, tilePoly, color); break; case HULL: Polygon objectClickbox = actor.getConvexHull(); - renderPoly(graphics, color, objectClickbox); + OverlayUtil.renderPolygon(graphics, objectClickbox, color); break; case THIN_OUTLINE: modelOutliner.drawOutline(actor, 1, color); @@ -136,15 +148,23 @@ public class TargetClickboxOverlay extends Overlay case TRUE_LOCATIONS: size = 1; composition = actor.getTransformedDefinition(); + if (composition != null) { size = composition.getSize(); } + WorldPoint wp = actor.getWorldLocation(); lp = LocalPoint.fromWorld(client, wp); + + if (lp == null) + { + return; + } + tilePoly = Perspective.getCanvasTileAreaPoly(client, lp, size); - renderPoly(graphics, color, tilePoly); + OverlayUtil.renderPolygon(graphics, tilePoly, color); break; } @@ -159,16 +179,4 @@ public class TargetClickboxOverlay extends Overlay } } } - - private static void renderPoly(Graphics2D graphics, Color color, Polygon polygon) - { - if (polygon != null) - { - graphics.setColor(color); - graphics.setStroke(new BasicStroke(2)); - graphics.draw(polygon); - graphics.setColor(new Color(color.getRed(), color.getGreen(), color.getBlue(), 20)); - graphics.fill(polygon); - } - } } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/slayer/TargetMinimapOverlay.java b/runelite-client/src/main/java/net/runelite/client/plugins/slayer/TargetMinimapOverlay.java index 8100ff70c7..ceb81e6cd2 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/slayer/TargetMinimapOverlay.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/slayer/TargetMinimapOverlay.java @@ -29,9 +29,8 @@ package net.runelite.client.plugins.slayer; import java.awt.Color; import java.awt.Dimension; import java.awt.Graphics2D; -import java.util.List; +import java.util.Set; 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; @@ -41,15 +40,12 @@ import net.runelite.client.ui.overlay.OverlayUtil; public class TargetMinimapOverlay extends Overlay { - - private final Client client; private final SlayerConfig config; private final SlayerPlugin plugin; @Inject - TargetMinimapOverlay(Client client, SlayerConfig config, SlayerPlugin plugin) + TargetMinimapOverlay(SlayerConfig config, SlayerPlugin plugin) { - this.client = client; this.config = config; this.plugin = plugin; setPosition(OverlayPosition.DYNAMIC); @@ -64,10 +60,16 @@ public class TargetMinimapOverlay extends Overlay return null; } - List targets = plugin.getHighlightedTargets(); + Set targets = plugin.getHighlightedTargets(); for (NPC target : targets) { + if (target == null || target.getName() == null) + { + continue; + } + Color coloration = config.getTargetColor(); + if (plugin.isSuperior(target.getName())) { coloration = config.getSuperiorColor(); 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/tearsofguthix/TearsOfGuthixExperienceOverlay.java similarity index 52% rename from runelite-client/src/main/java/net/runelite/client/plugins/fightcave/JadOverlay.java rename to runelite-client/src/main/java/net/runelite/client/plugins/tearsofguthix/TearsOfGuthixExperienceOverlay.java index 25ca70820d..b702556f5f 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/fightcave/JadOverlay.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/tearsofguthix/TearsOfGuthixExperienceOverlay.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, Devin French + * Copyright (c) 2018, Aquivers * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -22,66 +22,56 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 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; +package net.runelite.client.plugins.tearsofguthix; + 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; +import javax.inject.Inject; +import java.awt.Dimension; +import java.awt.Graphics2D; +import net.runelite.client.ui.overlay.components.table.TableAlignment; +import net.runelite.client.ui.overlay.components.table.TableComponent; -public class JadOverlay extends Overlay +class TearsOfGuthixExperienceOverlay 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(); + private final TearsOfGuthixPlugin plugin; + private final PanelComponent panelComponent = new PanelComponent(); @Inject - private JadOverlay(Client client, FightCavePlugin plugin, SpriteManager spriteManager) + private Client client; + + @Inject + private TearsOfGuthixExperienceOverlay(final TearsOfGuthixPlugin plugin) { - setPosition(OverlayPosition.BOTTOM_RIGHT); - setPriority(OverlayPriority.HIGH); - this.client = client; + setPosition(OverlayPosition.ABOVE_CHATBOX_RIGHT); + setPriority(OverlayPriority.LOW); this.plugin = plugin; - this.spriteManager = spriteManager; } @Override public Dimension render(Graphics2D graphics) { - final JadAttack attack = plugin.getAttack(); - - if (attack == null) + if (plugin.getPlayerLowestSkill() == null) { return null; } - final BufferedImage prayerImage = getPrayerImage(attack); + panelComponent.getChildren().clear(); - imagePanelComponent.getChildren().clear(); - imagePanelComponent.getChildren().add(new ImageComponent(prayerImage)); - imagePanelComponent.setBackgroundColor(client.isPrayerActive(attack.getPrayer()) - ? ComponentConstants.STANDARD_BACKGROUND_COLOR - : NOT_ACTIVATED_BACKGROUND_COLOR); + TableComponent tableComponent = new TableComponent(); + tableComponent.setColumnAlignments(TableAlignment.LEFT, TableAlignment.RIGHT); - return imagePanelComponent.render(graphics); - } + tableComponent.addRow(plugin.getPlayerLowestSkill().getName(), "Lvl - " + client.getRealSkillLevel(plugin.getPlayerLowestSkill()) + ""); - 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); + if (!tableComponent.isEmpty()) + { + panelComponent.getChildren().add(tableComponent); + } + + return panelComponent.render(graphics); } } \ No newline at end of file diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/tearsofguthix/TearsOfGuthixPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/tearsofguthix/TearsOfGuthixPlugin.java index 6567c15e24..9d2f1100aa 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/tearsofguthix/TearsOfGuthixPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/tearsofguthix/TearsOfGuthixPlugin.java @@ -28,10 +28,13 @@ import java.time.Instant; import java.util.HashMap; import java.util.Map; import javax.inject.Inject; +import lombok.AccessLevel; import lombok.Getter; import net.runelite.api.Client; import net.runelite.api.DecorativeObject; +import net.runelite.api.GameState; import net.runelite.api.ObjectID; +import net.runelite.api.Skill; import net.runelite.api.events.DecorativeObjectDespawned; import net.runelite.api.events.DecorativeObjectSpawned; import net.runelite.api.events.GameStateChanged; @@ -58,20 +61,29 @@ public class TearsOfGuthixPlugin extends Plugin @Inject private TearsOfGuthixOverlay overlay; - @Getter + @Inject + private TearsOfGuthixExperienceOverlay experienceOverlay; + + @Getter(AccessLevel.PACKAGE) private final Map streams = new HashMap<>(); + @Getter(AccessLevel.PACKAGE) + private Skill playerLowestSkill = null; + @Override protected void startUp() { overlayManager.add(overlay); + overlayManager.add(experienceOverlay); } @Override protected void shutDown() { overlayManager.remove(overlay); + overlayManager.remove(experienceOverlay); streams.clear(); + playerLowestSkill = null; } @Subscribe @@ -84,6 +96,26 @@ public class TearsOfGuthixPlugin extends Plugin case HOPPING: streams.clear(); } + + if (event.getGameState() == GameState.LOGGED_IN) + { + if (client.getLocalPlayer().getWorldLocation().getRegionID() == TOG_REGION) + { + if (playerLowestSkill != null) + { + return; + } + + if (client.getSkillExperience(Skill.HITPOINTS) > 0) + { + playerLowestSkill = getLowestPlayerSkill(); + } + } + else + { + playerLowestSkill = null; + } + } } @Subscribe @@ -112,4 +144,24 @@ public class TearsOfGuthixPlugin extends Plugin DecorativeObject object = event.getDecorativeObject(); streams.remove(object); } + + private Skill getLowestPlayerSkill() + { + final Skill[] playerSkills = Skill.values(); + Skill lowestExperienceSkill = null; + int lowestExperienceAmount = Integer.MAX_VALUE; + + for (Skill skill : playerSkills) + { + int currentSkillExp = client.getSkillExperience(skill); + + if (currentSkillExp < lowestExperienceAmount) + { + lowestExperienceAmount = currentSkillExp; + lowestExperienceSkill = skill; + } + } + + return lowestExperienceSkill; + } } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/theatre/RoomHandler.java b/runelite-client/src/main/java/net/runelite/client/plugins/theatre/RoomHandler.java index e67560663f..3615d58f6d 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/theatre/RoomHandler.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/theatre/RoomHandler.java @@ -1,17 +1,23 @@ package net.runelite.client.plugins.theatre; -import net.runelite.api.*; +import java.awt.BasicStroke; +import java.awt.Color; +import java.awt.Font; +import java.awt.Graphics2D; +import java.awt.Polygon; +import java.util.Iterator; +import java.util.Map; +import net.runelite.api.Client; +import net.runelite.api.NPC; +import net.runelite.api.NPCDefinition; +import net.runelite.api.Perspective; import net.runelite.api.Point; +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.OverlayUtil; -import java.awt.*; -import java.util.Iterator; -import java.util.List; -import java.util.Map; -public abstract class RoomHandler +public abstract class RoomHandler { protected final Client client; @@ -29,7 +35,7 @@ public abstract class RoomHandler public abstract void onStop(); - protected void drawTile2(Graphics2D graphics, WorldPoint point, Color color, int strokeWidth, int outlineAlpha, int fillAlpha) + protected void drawTile2(Graphics2D graphics, WorldPoint point, Color color, int strokeWidth, int outlineAlpha, int fillAlpha) { WorldPoint playerLocation = client.getLocalPlayer().getWorldLocation(); if (point.distanceTo(playerLocation) >= 32) @@ -71,14 +77,14 @@ public abstract class RoomHandler Point textLocation = Perspective.getCanvasTextLocation(client, graphics, projectilePoint, text, 0); if (textLocation != null) { - if (projectileId == 1607) + if (projectileId == 1607) { // range renderTextLocation(graphics, text, 17, Font.BOLD, new Color(57, 255, 20, 255), textLocation); - } + } else if (projectileId == 1606) { //mage renderTextLocation(graphics, text, 17, Font.BOLD, new Color(64, 224, 208, 255), textLocation); - } + } else { //Orb of death? i hope renderTextLocation(graphics, text, 20, Font.BOLD, Color.WHITE, textLocation); @@ -87,20 +93,26 @@ public abstract class RoomHandler } } - protected void drawTile(Graphics2D graphics, WorldPoint point, Color color, int strokeWidth, int outlineAlpha, int fillAlpha) + protected 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; + } graphics.setColor(new Color(color.getRed(), color.getGreen(), color.getBlue(), outlineAlpha)); graphics.setStroke(new BasicStroke(strokeWidth)); @@ -109,13 +121,15 @@ public abstract class RoomHandler graphics.fill(poly); } - protected void renderNpcOverlay(Graphics2D graphics, NPC actor, Color color, int outlineWidth, int outlineAlpha, int fillAlpha) + protected void renderNpcOverlay(Graphics2D graphics, NPC actor, Color color, int outlineWidth, int outlineAlpha, int fillAlpha) { int size = 1; NPCDefinition composition = actor.getTransformedDefinition(); if (composition != null) + { size = composition.getSize(); + } LocalPoint lp = actor.getLocalLocation(); Polygon tilePoly = Perspective.getCanvasTileAreaPoly(client, lp, size); @@ -143,26 +157,6 @@ public abstract class RoomHandler } } - protected List getHitSquares(WorldPoint npcLoc, int npcSize, int thickness, boolean includeUnder) - { - 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(); - if (little.contains(p)) - { - it.remove(); - } - } - } - - return big; - } - protected String twoDigitString(long number) { diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/theatre/TheatreConfig.java b/runelite-client/src/main/java/net/runelite/client/plugins/theatre/TheatreConfig.java index 39a5cc7e41..bf9a5e5963 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/theatre/TheatreConfig.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/theatre/TheatreConfig.java @@ -8,30 +8,15 @@ package net.runelite.client.plugins.theatre; +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("Theatre") public interface TheatreConfig extends Config { - enum NYLOCAS - { - NONE, - MAGE, - MELEE, - RANGER - } - - enum NYLOOPTION - { - NONE, - TILE, - TIMER - } - @ConfigItem( position = 0, keyName = "showMaidenBloodToss", @@ -39,7 +24,7 @@ public interface TheatreConfig extends Config description = "Displays the tile location where tossed blood will land.", group = "Maiden" ) - default boolean showMaidenBloodToss() + default boolean showMaidenBloodToss() { return true; } @@ -51,7 +36,19 @@ public interface TheatreConfig extends Config description = "Show the tiles that blood spawns will travel to.", group = "Maiden" ) - default boolean showMaidenBloodSpawns() + default boolean showMaidenBloodSpawns() + { + return true; + } + + @ConfigItem( + position = 2, + keyName = "showNyloFreezeHighlights", + name = "Show Nylo Freeze Highlights", + description = "Show when to freeze Nylos at maiden. Say n1,n2,s1,s2 in chat for it to register.", + group = "Maiden" + ) + default boolean showNyloFreezeHighlights() { return true; } @@ -63,7 +60,7 @@ public interface TheatreConfig extends Config description = "Displays Bloat's status (asleep, wake, and enrage) using color code.", group = "Bloat" ) - default boolean showBloatIndicator() + default boolean showBloatIndicator() { return true; } @@ -75,7 +72,7 @@ public interface TheatreConfig extends Config description = "Highlights the falling hands inside Bloat.", group = "Bloat" ) - default boolean showBloatHands() + default boolean showBloatHands() { return true; } @@ -87,8 +84,8 @@ public interface TheatreConfig extends Config description = "", group = "Bloat" ) - default boolean BloatFeetIndicatorRaveEdition() - { + default boolean BloatFeetIndicatorRaveEdition() + { return false; } @@ -135,45 +132,40 @@ public interface TheatreConfig extends Config description = "An overlay will appear that counts the amount of Nylocas in the room.", group = "Nylocas" ) - default boolean showNylocasAmount() + default boolean showNylocasAmount() { return true; } /** - @ConfigItem( - position = 8, - keyName = "showNylocasSpawns", - name = "Show Nylocas Pre-spawns", - description = "Know the contents of the next upcoming wave." - ) - default boolean showNylocasSpawns() - { - return true; - } - - @ConfigItem( - position = 9, - keyName = "highlightNyloRoles", - name = "Highlight Nylo Prespawns", - description = "Highlights the next upcoming wave based on role. FOR BEGINNERS" - ) - default NYLOCAS highlightNyloRoles() - { - return NYLOCAS.NONE; - } - - @ConfigItem( - position = 10, - keyName = "highlightNyloParents", - name = "Show Nylo Parents (Un-used)", - description = "Highlight the Nylocas that spawn outside the center." - ) - default boolean highlightNyloParents() - { - return true; - } - **/ + * @ConfigItem( position = 8, + * keyName = "showNylocasSpawns", + * name = "Show Nylocas Pre-spawns", + * description = "Know the contents of the next upcoming wave." + * ) + * default boolean showNylocasSpawns() + * { + * return true; + * } + * @ConfigItem( position = 9, + * keyName = "highlightNyloRoles", + * name = "Highlight Nylo Prespawns", + * description = "Highlights the next upcoming wave based on role. FOR BEGINNERS" + * ) + * default NYLOCAS highlightNyloRoles() + * { + * return NYLOCAS.NONE; + * } + * @ConfigItem( position = 10, + * keyName = "highlightNyloParents", + * name = "Show Nylo Parents (Un-used)", + * description = "Highlight the Nylocas that spawn outside the center." + * ) + * default boolean highlightNyloParents() + * { + * return true; + * } + **/ @ConfigItem( position = 11, @@ -218,7 +210,7 @@ public interface TheatreConfig extends Config description = "Marks the tiles of Sotetseg's maze while in the underworld.", group = "Sotetseg" ) - default boolean showSotetsegSolo() + default boolean showSotetsegSolo() { return true; } @@ -234,6 +226,7 @@ public interface TheatreConfig extends Config { return Color.WHITE; } + @ConfigItem( position = 15, keyName = "showXarpusHeals", @@ -302,10 +295,10 @@ public interface TheatreConfig extends Config group = "Verzik" ) default boolean VerzikTankTile() - { + { return false; } - + @ConfigItem( position = 22, keyName = "verzikrangeattacks", @@ -314,10 +307,10 @@ public interface TheatreConfig extends Config group = "Verzik" ) default boolean verzikRangeAttacks() - { - return true; + { + return true; } - + @ConfigItem( position = 23, keyName = "extratimers", @@ -329,7 +322,7 @@ public interface TheatreConfig extends Config { return false; } - + @ConfigItem( position = 24, keyName = "p1attacks", @@ -341,7 +334,7 @@ public interface TheatreConfig extends Config { return true; } - + @ConfigItem( position = 25, keyName = "p2attacks", @@ -353,7 +346,7 @@ public interface TheatreConfig extends Config { return true; } - + @ConfigItem( position = 26, keyName = "p3attacks", @@ -365,4 +358,19 @@ public interface TheatreConfig extends Config { return true; } + + enum NYLOCAS + { + NONE, + MAGE, + MELEE, + RANGER + } + + enum NYLOOPTION + { + NONE, + TILE, + TIMER + } } \ No newline at end of file diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/theatre/TheatreConstant.java b/runelite-client/src/main/java/net/runelite/client/plugins/theatre/TheatreConstant.java index 90e47bd242..0724fb099e 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/theatre/TheatreConstant.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/theatre/TheatreConstant.java @@ -1,6 +1,6 @@ package net.runelite.client.plugins.theatre; -public class TheatreConstant +public class TheatreConstant { public static final int MAIDEN_BLOOD_THROW = 1579; diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/theatre/TheatreOverlay.java b/runelite-client/src/main/java/net/runelite/client/plugins/theatre/TheatreOverlay.java index 492e9a25c4..e4dc6c2683 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/theatre/TheatreOverlay.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/theatre/TheatreOverlay.java @@ -8,28 +8,30 @@ package net.runelite.client.plugins.theatre; -import java.awt.*; -import java.util.*; +import java.awt.Dimension; +import java.awt.Graphics2D; import javax.inject.Inject; -import net.runelite.api.*; +import net.runelite.api.Client; +import net.runelite.client.graphics.ModelOutlineRenderer; 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 TheatreOverlay extends Overlay +public class TheatreOverlay extends Overlay { - private final Client client; private final TheatrePlugin plugin; private final TheatreConfig config; + private final ModelOutlineRenderer modelOutline; @Inject - private TheatreOverlay(Client client, TheatrePlugin plugin, TheatreConfig config) + private TheatreOverlay(Client client, TheatrePlugin plugin, TheatreConfig config, ModelOutlineRenderer modelOutline) { this.client = client; this.plugin = plugin; this.config = config; + this.modelOutline = modelOutline; setPosition(OverlayPosition.DYNAMIC); setPriority(OverlayPriority.HIGH); diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/theatre/TheatrePlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/theatre/TheatrePlugin.java index 0fe357d9e3..2a08416e84 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/theatre/TheatrePlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/theatre/TheatrePlugin.java @@ -9,32 +9,44 @@ package net.runelite.client.plugins.theatre; import com.google.inject.Provides; +import java.awt.Color; +import java.util.LinkedList; +import java.util.List; +import javax.inject.Inject; import lombok.AccessLevel; import lombok.Getter; import lombok.Setter; +import lombok.extern.slf4j.Slf4j; import net.runelite.api.Client; -import java.util.LinkedList; -import java.util.List; -import net.runelite.api.events.*; -import net.runelite.client.config.ConfigManager; -import net.runelite.client.eventbus.Subscribe; -import net.runelite.client.plugins.Plugin; +import net.runelite.api.events.AnimationChanged; +import net.runelite.api.events.ChatMessage; +import net.runelite.api.events.ConfigChanged; +import net.runelite.api.events.GameTick; +import net.runelite.api.events.GroundObjectSpawned; +import net.runelite.api.events.NpcDefinitionChanged; +import net.runelite.api.events.NpcDespawned; +import net.runelite.api.events.NpcSpawned; +import net.runelite.api.events.ProjectileMoved; +import net.runelite.api.events.SpotAnimationChanged; +import net.runelite.api.events.VarbitChanged; +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.config.ConfigManager; +import net.runelite.client.eventbus.Subscribe; +import net.runelite.client.graphics.ModelOutlineRenderer; +import net.runelite.client.plugins.Plugin; import net.runelite.client.plugins.PluginDescriptor; import net.runelite.client.plugins.PluginType; import net.runelite.client.plugins.theatre.rooms.BloatHandler; import net.runelite.client.plugins.theatre.rooms.MaidenHandler; import net.runelite.client.plugins.theatre.rooms.SotetsegHandler; import net.runelite.client.plugins.theatre.rooms.VerzikHandler; -import net.runelite.client.plugins.theatre.rooms.xarpus.XarpusHandler; import net.runelite.client.plugins.theatre.rooms.nylocas.NyloHandler; +import net.runelite.client.plugins.theatre.rooms.xarpus.XarpusHandler; import net.runelite.client.ui.overlay.OverlayManager; -import javax.inject.Inject; -import java.awt.*; - @PluginDescriptor( name = "Theatre of Blood", description = "All-in-one plugin for Theatre of Blood.", @@ -43,9 +55,9 @@ import java.awt.*; enabledByDefault = false ) -public class TheatrePlugin extends Plugin +@Slf4j +public class TheatrePlugin extends Plugin { - @Getter(AccessLevel.PUBLIC) @Setter(AccessLevel.PUBLIC) private TheatreRoom room; @@ -83,6 +95,9 @@ public class TheatrePlugin extends Plugin @Inject private TheatreConfig config; + @Inject + private ModelOutlineRenderer modelOutline; + @Provides TheatreConfig getConfig(ConfigManager configManager) { @@ -94,7 +109,7 @@ public class TheatrePlugin extends Plugin { room = TheatreRoom.UNKNOWN; - maidenHandler = new MaidenHandler(client, this, config); + maidenHandler = new MaidenHandler(client, this, config, modelOutline); bloatHandler = new BloatHandler(client, this, config); nyloHandler = new NyloHandler(client, this, config); sotetsegHandler = new SotetsegHandler(client, this, config); @@ -131,26 +146,56 @@ public class TheatrePlugin extends Plugin overlayManager.remove(overlay); } + @Subscribe + public void onSpotAnimationChanged(SpotAnimationChanged event) + { + if (maidenHandler != null) + { + maidenHandler.onSpotAnimationChanged(event); + } + } + + @Subscribe + public void onNpcDefinitionChanged(NpcDefinitionChanged event) + { + if (maidenHandler != null) + { + maidenHandler.onNpcDefinitionChanged(event); + } + } + @Subscribe public void onNpcSpawned(NpcSpawned event) { if (maidenHandler != null) + { maidenHandler.onNpcSpawned(event); + } if (bloatHandler != null) + { bloatHandler.onNpcSpawned(event); + } if (nyloHandler != null) + { nyloHandler.onNpcSpawned(event); + } if (sotetsegHandler != null) + { sotetsegHandler.onNpcSpawned(event); + } if (xarpusHandler != null) + { xarpusHandler.onNpcSpawned(event); + } if (verzikHandler != null) + { verzikHandler.onNpcSpawned(event); + } } @@ -158,19 +203,29 @@ public class TheatrePlugin extends Plugin public void onNpcDespawned(NpcDespawned event) { if (maidenHandler != null) + { maidenHandler.onNpcDespawned(event); + } if (bloatHandler != null) + { bloatHandler.onNpcDespawned(event); + } if (nyloHandler != null) + { nyloHandler.onNpcDespawned(event); + } if (sotetsegHandler != null) + { sotetsegHandler.onNpcDespawned(event); + } if (xarpusHandler != null) + { xarpusHandler.onNpcDespawned(event); + } } @@ -178,7 +233,18 @@ public class TheatrePlugin extends Plugin public void onAnimationChanged(AnimationChanged event) { if (verzikHandler != null) + { verzikHandler.onAnimationChanged(event); + } + } + + @Subscribe + public void onChatMessage(ChatMessage event) + { + if (maidenHandler != null) + { + maidenHandler.onChatMessage(event); + } } @Subscribe @@ -204,22 +270,34 @@ public class TheatrePlugin extends Plugin public void onGameTick(GameTick event) { if (maidenHandler != null) + { maidenHandler.onGameTick(); + } if (bloatHandler != null) + { bloatHandler.onGameTick(); + } if (nyloHandler != null) + { nyloHandler.onGameTick(); + } if (sotetsegHandler != null) + { sotetsegHandler.onGameTick(); + } if (xarpusHandler != null) + { xarpusHandler.onGameTick(); + } if (verzikHandler != null) + { verzikHandler.onGameTick(); + } if (widget == null) { @@ -315,27 +393,37 @@ public class TheatrePlugin extends Plugin public void onGroundObjectSpawned(GroundObjectSpawned event) { if (sotetsegHandler != null) + { sotetsegHandler.onGroundObjectSpawned(event); + } if (xarpusHandler != null) + { xarpusHandler.onGroundObjectSpawned(event); + } } @Subscribe public void onConfigChanged(ConfigChanged event) { if (nyloHandler != null) + { nyloHandler.onConfigChanged(); + } } @Subscribe public void onVarbitChanged(VarbitChanged event) { if (bloatHandler != null) + { bloatHandler.onVarbitChanged(event); + } if (xarpusHandler != null) + { xarpusHandler.onVarbitChanged(event); + } } @Subscribe diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/theatre/TheatreRoom.java b/runelite-client/src/main/java/net/runelite/client/plugins/theatre/TheatreRoom.java index e13635b13f..4da8512503 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/theatre/TheatreRoom.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/theatre/TheatreRoom.java @@ -1,6 +1,6 @@ package net.runelite.client.plugins.theatre; -public enum TheatreRoom +public enum TheatreRoom { MAIDEN, BLOAT, @@ -8,5 +8,5 @@ public enum TheatreRoom SOTETSEG, XARPUS, VERSIK, - UNKNOWN; + UNKNOWN } \ No newline at end of file diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/theatre/rooms/BloatHandler.java b/runelite-client/src/main/java/net/runelite/client/plugins/theatre/rooms/BloatHandler.java index 98e229a58b..b62b979012 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/theatre/rooms/BloatHandler.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/theatre/rooms/BloatHandler.java @@ -1,42 +1,36 @@ package net.runelite.client.plugins.theatre.rooms; +import java.awt.Color; +import java.awt.Font; +import java.awt.Graphics2D; +import java.util.Random; import lombok.AccessLevel; import lombok.Getter; -import net.runelite.api.*; +import net.runelite.api.Client; +import net.runelite.api.GraphicsObject; +import net.runelite.api.NPC; +import net.runelite.api.NpcID; import net.runelite.api.Point; +import net.runelite.api.Varbits; import net.runelite.api.coords.WorldPoint; import net.runelite.api.events.NpcDespawned; import net.runelite.api.events.NpcSpawned; import net.runelite.api.events.VarbitChanged; import net.runelite.client.eventbus.Subscribe; +import net.runelite.client.plugins.theatre.RoomHandler; import net.runelite.client.plugins.theatre.TheatreConfig; import net.runelite.client.plugins.theatre.TheatrePlugin; import net.runelite.client.plugins.theatre.TheatreRoom; -import net.runelite.client.plugins.theatre.RoomHandler; - -import java.awt.*; -import java.util.Random; public class BloatHandler extends RoomHandler { - public static enum BloatState - { - DOWN, - UP, - WARN; - } - + private int bloatTimer; @Getter(AccessLevel.PUBLIC) private NPC bloat; - private int counter; - - //My variables private boolean bloatFlag; - int bloatTimer; private Color color; - @Getter(AccessLevel.PUBLIC) private BloatState bloatState; @@ -49,7 +43,9 @@ public class BloatHandler extends RoomHandler public void onStart() { if (this.plugin.getRoom() == TheatreRoom.BLOAT) + { return; + } this.reset(); this.plugin.setRoom(TheatreRoom.BLOAT); @@ -106,8 +102,8 @@ public class BloatHandler extends RoomHandler WorldPoint point = WorldPoint.fromLocal(client, object.getLocation()); if (!config.BloatFeetIndicatorRaveEdition()) { - drawTile(graphics, point, new Color(36, 248, 229), 2, 255, 10); - } + drawTile(graphics, point, new Color(36, 248, 229), 2, 255, 10); + } else { drawTile(graphics, point, color, 2, 255, 10); @@ -120,15 +116,15 @@ public class BloatHandler extends RoomHandler if (config.showBloatTimer()) { final String tickCounter = String.valueOf(bloatTimer); - int secondConversion = (int)(bloatTimer * .6); + int secondConversion = (int) (bloatTimer * .6); if (bloat != null) { Point canvasPoint = bloat.getCanvasTextLocation(graphics, tickCounter, 60); - if (bloatTimer <= 37) + if (bloatTimer <= 37) { renderTextLocation(graphics, tickCounter + "( " + secondConversion + " )", 15, Font.BOLD, Color.WHITE, canvasPoint); - } - else + } + else { renderTextLocation(graphics, tickCounter + "( " + secondConversion + " )", 15, Font.BOLD, Color.RED, canvasPoint); } @@ -139,9 +135,9 @@ public class BloatHandler extends RoomHandler @Subscribe public void onVarbitChanged(VarbitChanged event) { - if (client.getVar(Varbits.BLOAT_DOOR) == 1) + if (client.getVar(Varbits.BLOAT_DOOR) == 1) { - if (!bloatFlag) + if (!bloatFlag) { bloatTimer = 0; bloatFlag = true; @@ -149,12 +145,12 @@ public class BloatHandler extends RoomHandler } } - public void onNpcSpawned(NpcSpawned event) + public void onNpcSpawned(NpcSpawned event) { NPC npc = event.getNpc(); int id = npc.getId(); - if (id == NpcID.PESTILENT_BLOAT) + if (id == NpcID.PESTILENT_BLOAT) { this.onStart(); bloatTimer = 0; @@ -162,12 +158,12 @@ public class BloatHandler extends RoomHandler } } - public void onNpcDespawned(NpcDespawned event) + public void onNpcDespawned(NpcDespawned event) { NPC npc = event.getNpc(); int id = npc.getId(); - if (id == NpcID.PESTILENT_BLOAT) + if (id == NpcID.PESTILENT_BLOAT) { this.onStop(); bloatTimer = 0; @@ -175,9 +171,9 @@ public class BloatHandler extends RoomHandler } } - public void onGameTick() + public void onGameTick() { - if (plugin.getRoom() != TheatreRoom.BLOAT) + if (plugin.getRoom() != TheatreRoom.BLOAT) { return; } @@ -196,39 +192,46 @@ public class BloatHandler extends RoomHandler counter++; - if (bloat.getAnimation() == -1) + if (bloat.getAnimation() == -1) { bloatTimer++; counter = 0; if (bloat.getHealth() == 0) { bloatState = BloatState.DOWN; - } - else + } + else { bloatState = BloatState.UP; } - } - else + } + else { - if (25 < counter && counter < 35) + if (25 < counter && counter < 35) { bloatState = BloatState.WARN; - } - else if (counter < 26) + } + else if (counter < 26) { bloatTimer = 0; bloatState = BloatState.DOWN; - } - else if (bloat.getModelHeight() == 568) + } + else if (bloat.getModelHeight() == 568) { bloatTimer = 0; bloatState = BloatState.DOWN; - } - else + } + else { bloatState = BloatState.UP; } } } + + public enum BloatState + { + DOWN, + UP, + WARN + } } \ No newline at end of file diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/theatre/rooms/MaidenHandler.java b/runelite-client/src/main/java/net/runelite/client/plugins/theatre/rooms/MaidenHandler.java index 5c926e127b..68115623fa 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/theatre/rooms/MaidenHandler.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/theatre/rooms/MaidenHandler.java @@ -1,162 +1,308 @@ package net.runelite.client.plugins.theatre.rooms; -import lombok.AccessLevel; -import lombok.Getter; +import com.google.common.collect.ImmutableSet; +import java.awt.Color; +import java.awt.Graphics2D; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import lombok.extern.slf4j.Slf4j; import net.runelite.api.ChatMessageType; import net.runelite.api.Client; import net.runelite.api.GraphicsObject; import net.runelite.api.NPC; -import net.runelite.api.NpcID; import net.runelite.api.coords.WorldPoint; +import net.runelite.api.events.ChatMessage; +import net.runelite.api.events.NpcDefinitionChanged; import net.runelite.api.events.NpcDespawned; import net.runelite.api.events.NpcSpawned; +import net.runelite.api.events.SpotAnimationChanged; +import net.runelite.client.graphics.ModelOutlineRenderer; import net.runelite.client.plugins.theatre.RoomHandler; import net.runelite.client.plugins.theatre.TheatreConfig; import net.runelite.client.plugins.theatre.TheatreConstant; import net.runelite.client.plugins.theatre.TheatrePlugin; import net.runelite.client.plugins.theatre.TheatreRoom; +import net.runelite.client.util.Text; -import java.awt.*; -import java.util.ArrayList; -import java.util.List; - -public class MaidenHandler extends RoomHandler +@Slf4j +public class MaidenHandler extends RoomHandler { - - @Getter(AccessLevel.PACKAGE) + private static final ImmutableSet N1 = ImmutableSet.of( + new WorldPoint(3182, 4457, 0), + new WorldPoint(3174, 4457, 0) + ); + private static final ImmutableSet N2 = ImmutableSet.of( + new WorldPoint(3178, 4457, 0), + new WorldPoint(3186, 4455, 0), + new WorldPoint(3186, 4457, 0) + ); + private static final ImmutableSet S1 = ImmutableSet.of( + new WorldPoint(3174, 4437, 0), + new WorldPoint(3182, 4437, 0) + ); + private static final ImmutableSet S2 = ImmutableSet.of( + new WorldPoint(3186, 4439, 0), + new WorldPoint(3186, 4437, 0), + new WorldPoint(3178, 4437, 0) + ); + private static final ImmutableSet FREEZEANIMS = ImmutableSet.of( + 361, + 363, + 367, + 369 + ); + private static final Color TRANSPARENT = new Color(0, 0, 0, 0); + private static final Color FREEZE = new Color(0, 226, 255, 255); private List bloodThrows = new ArrayList<>(); - - @Getter(AccessLevel.PACKAGE) private List bloodSpawns = new ArrayList<>(); - - @Getter(AccessLevel.PACKAGE) private List bloodSpawnLocation = new ArrayList<>(); - - @Getter(AccessLevel.PACKAGE) private List bloodSpawnTarget = new ArrayList<>(); - + private NPC maiden; + private String nyloCall; + private Set nylos = new HashSet<>(); private List healers = new ArrayList<>(); private int healerCount = 0; private int wave = 1; private long startTime = 0; + private ModelOutlineRenderer modelOutline; - public MaidenHandler(Client client, TheatrePlugin plugin, TheatreConfig config) + public MaidenHandler(Client client, TheatrePlugin plugin, TheatreConfig config, ModelOutlineRenderer modelOutline) { super(client, plugin, config); + this.modelOutline = modelOutline; } @Override - public void onStart() + public void onStart() { if (this.plugin.getRoom() == TheatreRoom.MAIDEN) + { return; - + } this.reset(); - this.plugin.setRoom(TheatreRoom.MAIDEN); this.startTime = System.currentTimeMillis(); - System.out.println("Starting Maiden Room"); + log.debug("Starting Maiden Room"); } @Override - public void onStop() + public void onStop() { this.reset(); this.plugin.setRoom(TheatreRoom.UNKNOWN); - System.out.println("Stopping Maiden Room"); + log.debug("Stopping Maiden Room"); } - public void reset() + public void reset() { this.bloodThrows.clear(); this.bloodSpawns.clear(); this.bloodSpawnLocation.clear(); this.bloodSpawnTarget.clear(); - this.healers.clear(); + this.nylos.clear(); this.healerCount = 0; this.startTime = -1; this.wave = 1; } - public void render(Graphics2D graphics) + public void render(Graphics2D graphics) { - if (config.showMaidenBloodToss()) + for (Nylos nylo : nylos) { - for (WorldPoint point : bloodThrows) + if (nylo.getNpc() == null || nylo.getNpc().getId() == -1) + { + continue; + } + + final String location = nylo.getSpawnLocation().getName(); + + if (nyloCall == null || nyloCall.equals("")) + { + nyloCall = "n1"; + } + + if (location.equals(nyloCall)) + { + Color color = Color.WHITE; + int width = 4; + + if (nylo.getNpc().getWorldArea().distanceTo(maiden.getWorldArea()) <= 3) + { + color = FREEZE; + width = 8; + } + + modelOutline.drawOutline(nylo.getNpc(), width, color, TRANSPARENT); + } + } + + if (config.showMaidenBloodToss()) + { + for (WorldPoint point : bloodThrows) { drawTile(graphics, point, new Color(36, 248, 229), 2, 150, 10); } } - if (config.showMaidenBloodSpawns()) + if (config.showMaidenBloodSpawns()) { - for (WorldPoint point : bloodSpawnLocation) + for (WorldPoint point : bloodSpawnLocation) { drawTile(graphics, point, new Color(36, 248, 229), 2, 180, 20); } - for (WorldPoint point : bloodSpawnTarget) + for (WorldPoint point : bloodSpawnTarget) { drawTile(graphics, point, new Color(36, 248, 229), 1, 120, 10); } } } - public void onNpcSpawned(NpcSpawned event) + public void onSpotAnimationChanged(SpotAnimationChanged event) + { + if (event.getActor() instanceof NPC) + { + NPC npc = (NPC) event.getActor(); + + if (npc.getId() != 8366) + { + return; + } + + int anim = npc.getSpotAnimation(); + + if (FREEZEANIMS.contains(anim)) + { + nylos.removeIf(c -> c.getNpc() == npc); + } + } + } + + public void onNpcSpawned(NpcSpawned event) { NPC npc = event.getNpc(); - String name = npc.getName(); - int id = npc.getId(); - if (npc.getName() != null && name.equals("The Maiden of Sugadinti")) + if (npc.getName() == null) { - this.onStart(); - } - else if (plugin.getRoom() == TheatreRoom.MAIDEN) + return; + } + + switch (npc.getName()) { - if (id == NpcID.BLOOD_SPAWN) - { - if (!bloodSpawns.contains(npc)) - bloodSpawns.add(npc); - } - else if (name != null && name.equalsIgnoreCase("Nylocas Matomenos")) - { + case "The Maiden of Sugadinti": + this.onStart(); + maiden = npc; + break; + case "Nylocas Matomenos": + if (!config.showNyloFreezeHighlights()) + { + return; + } + this.healers.add(npc); - } + + WorldPoint wp = WorldPoint.fromLocalInstance(client, npc.getLocalLocation()); + + if (N1.contains(wp)) + { + addNylo(npc, Nylos.SpawnLocation.N1); + } + if (N2.contains(wp)) + { + addNylo(npc, Nylos.SpawnLocation.N2); + } + if (S1.contains(wp)) + { + addNylo(npc, Nylos.SpawnLocation.S1); + } + if (S2.contains(wp)) + { + addNylo(npc, Nylos.SpawnLocation.S2); + } + if (!N1.contains(wp) && !N2.contains(wp) && !S1.contains(wp) && !S2.contains(wp)) + { + log.info("No World Points Matched"); + log.info("Instance Loc: " + wp); + } + break; + case "Blood spawn": + if (!bloodSpawns.contains(npc)) + { + bloodSpawns.add(npc); + } + break; } } - public void onNpcDespawned(NpcDespawned event) + public void onNpcDefinitionChanged(NpcDefinitionChanged event) { NPC npc = event.getNpc(); - String name = npc.getName(); - int id = npc.getId(); - if (npc.getName() != null && name.equals("The Maiden of Sugadinti")) + if (npc.getName() != null && npc.getName().equals("Nylocas Matomenos")) { - this.onStop(); - } - else if (plugin.getRoom() == TheatreRoom.MAIDEN) - { - if (id == NpcID.BLOOD_SPAWN) + if (npc.getId() == -1) { - bloodSpawns.remove(npc); + nylos.removeIf(c -> c.getNpc() == npc); } } } - public void onGameTick() + public void onChatMessage(ChatMessage event) { - if (plugin.getRoom() != TheatreRoom.MAIDEN) + if (event.getSender() != null && !event.getSender().equals(client.getLocalPlayer().getName())) + { + return; + } + + String msg = Text.standardize(event.getMessageNode().getValue()); + + switch (msg) + { + case "n1": + case "n2": + case "s1": + case "s2": + nyloCall = msg; + log.debug("Nylo Call Assigned: " + msg); + break; + } + } + + public void onNpcDespawned(NpcDespawned event) + { + NPC npc = event.getNpc(); + + if (npc.getName() == null) + { + return; + } + + switch (npc.getName()) + { + case "The Maiden of Sugadinti": + this.onStop(); + break; + case "Blood Spawn": + bloodSpawns.remove(npc); + break; + } + } + + public void onGameTick() + { + if (plugin.getRoom() != TheatreRoom.MAIDEN) { return; } bloodThrows.clear(); - for (GraphicsObject o : client.getGraphicsObjects()) + + for (GraphicsObject o : client.getGraphicsObjects()) { - if (o.getId() == TheatreConstant.MAIDEN_BLOOD_THROW) + if (o.getId() == TheatreConstant.MAIDEN_BLOOD_THROW) { bloodThrows.add(WorldPoint.fromLocal(client, o.getLocation())); } @@ -164,12 +310,13 @@ public class MaidenHandler extends RoomHandler bloodSpawnLocation = new ArrayList<>(bloodSpawnTarget); bloodSpawnTarget.clear(); - for (NPC spawn : bloodSpawns) + + for (NPC spawn : bloodSpawns) { bloodSpawnTarget.add(spawn.getWorldLocation()); } - if (this.healerCount != this.healers.size()) + if (this.healerCount != this.healers.size()) { this.healerCount = this.healers.size(); @@ -181,7 +328,15 @@ public class MaidenHandler extends RoomHandler int percentage = 70 - (20 * ((wave++) - 1)); if (config.extraTimers()) - this.client.addChatMessage(ChatMessageType.GAMEMESSAGE, "", "Wave 'The Maiden of Sugadinti - " + percentage + "%' completed! Duration: " + minutes + ":" + twoDigitString(seconds), null); + { + this.client.addChatMessage(ChatMessageType.GAMEMESSAGE, "", "Wave 'The Maiden of Sugadinti - " + percentage + "%' completed! Duration: " + minutes + ":" + twoDigitString(seconds), null); + } } } + + + private void addNylo(NPC npc, Nylos.SpawnLocation spawnLocation) + { + nylos.add(new Nylos(npc, spawnLocation)); + } } \ No newline at end of file diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/theatre/rooms/Nylos.java b/runelite-client/src/main/java/net/runelite/client/plugins/theatre/rooms/Nylos.java new file mode 100644 index 0000000000..53469f3fe4 --- /dev/null +++ b/runelite-client/src/main/java/net/runelite/client/plugins/theatre/rooms/Nylos.java @@ -0,0 +1,36 @@ +package net.runelite.client.plugins.theatre.rooms; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.Setter; +import net.runelite.api.NPC; + +class Nylos +{ + @Getter + private NPC npc; + @Getter + private int npcIndex; + @Getter + @Setter + private SpawnLocation spawnLocation; + + Nylos(NPC npc, SpawnLocation spawnLocation) + { + this.npc = npc; + this.npcIndex = npc.getIndex(); + this.spawnLocation = spawnLocation; + } + + @Getter + @AllArgsConstructor + enum SpawnLocation + { + N1("n1"), + N2("n2"), + S1("s1"), + S2("s2"); + + private String name; + } +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/theatre/rooms/SotetsegHandler.java b/runelite-client/src/main/java/net/runelite/client/plugins/theatre/rooms/SotetsegHandler.java index 03c706c154..13551b9ec4 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/theatre/rooms/SotetsegHandler.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/theatre/rooms/SotetsegHandler.java @@ -1,9 +1,23 @@ package net.runelite.client.plugins.theatre.rooms; +import java.awt.BasicStroke; +import java.awt.Color; +import java.awt.Graphics2D; +import java.awt.Polygon; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; import lombok.AccessLevel; import lombok.Getter; -import net.runelite.api.*; +import net.runelite.api.Client; +import net.runelite.api.GroundObject; +import net.runelite.api.NPC; +import net.runelite.api.NpcID; import net.runelite.api.Point; +import net.runelite.api.Projectile; +import net.runelite.api.Tile; import net.runelite.api.coords.WorldPoint; import net.runelite.api.events.GroundObjectSpawned; import net.runelite.api.events.NpcDespawned; @@ -16,33 +30,24 @@ import net.runelite.client.plugins.theatre.TheatrePlugin; import net.runelite.client.plugins.theatre.TheatreRoom; import net.runelite.client.ui.overlay.OverlayUtil; -import java.awt.*; -import java.util.*; -import java.util.List; - public class SotetsegHandler extends RoomHandler { @Getter(AccessLevel.PUBLIC) private final Map redTiles = new LinkedHashMap<>(); - + //My variables + private int playerX; + private int playerY; @Getter(AccessLevel.PUBLIC) private List redOverworld = new ArrayList<>(); - private List blackOverworld = new ArrayList<>(); - private List blackUnderworld = new ArrayList<>(); - private List redUnderworld = new ArrayList<>(); - private List gridPath = new ArrayList<>(); - - //My variables - int playerX; - int playerY; private Map soteyProjectiles = new HashMap<>(); private NPC npc; private long startTime = 0; + public SotetsegHandler(Client client, TheatrePlugin plugin, TheatreConfig config) { super(client, plugin, config); @@ -52,7 +57,9 @@ public class SotetsegHandler extends RoomHandler public void onStart() { if (this.plugin.getRoom() == TheatreRoom.SOTETSEG) + { return; + } this.reset(); this.plugin.setRoom(TheatreRoom.SOTETSEG); @@ -125,68 +132,16 @@ public class SotetsegHandler extends RoomHandler String countdownStr; if (id == 1607) { - countdownStr = "R " + String.valueOf(ticksRemaining); + countdownStr = "R " + ticksRemaining; } else { - countdownStr = "M " + String.valueOf(ticksRemaining); + countdownStr = "M " + ticksRemaining; } projectileMap.put(p, countdownStr); } renderProjectiles(graphics, projectileMap); - //Legacy code from yuri, works great but shows all projectiles not just ones targetting local player - /** - for (Projectile projectile : client.getProjectiles()) - { - int id = projectile.getId(); - - String name = null; - Color color = null; - - double millis = projectile.getRemainingCycles(); - double ticks = millis / 60; // 10 millis per cycle, 0.6 ticks per second, 10/0.6 = 60 - double round = Math.round(ticks * 10d) / 10d; - if (id == TheatreConstant.SOTETSEG_BOMB) - { - name = "" + round; - color = Color.WHITE; - } - else if (id == TheatreConstant.SOTETSEG_MAGE) - { - - name = "" + round; - color = new Color(64, 224, 208, 255); - } - else if (id == TheatreConstant.SOTETSEG_RANGE) - { - name = "" + round; - color = new Color(57, 255, 20, 255); - } - - if (name != null) - { - int x = (int) projectile.getX(); - int y = (int) projectile.getY(); - - LocalPoint point = new LocalPoint(x, y); - Point loc = Perspective.getCanvasTextLocation(client, graphics, point, name, 0); - - if (loc != null) - { - if (id == TheatreConstant.SOTETSEG_BOMB) - { - graphics.setFont(new Font("Arial", Font.BOLD, 20)); - } - else - { - graphics.setFont(new Font("Arial", Font.BOLD, 17)); - } - - OverlayUtil.renderTextLocation(graphics, loc, name, color); - } - } - }**/ } } @@ -242,12 +197,16 @@ public class SotetsegHandler extends RoomHandler if (t.getPlane() == 0) { if (!blackOverworld.contains(p)) + { blackOverworld.add(p); + } } else { if (!blackUnderworld.contains(p)) + { blackUnderworld.add(p); + } } } @@ -265,7 +224,9 @@ public class SotetsegHandler extends RoomHandler else { if (!redUnderworld.contains(p)) + { redUnderworld.add(p); + } } } } @@ -282,19 +243,10 @@ public class SotetsegHandler extends RoomHandler playerY = client.getLocalPlayer().getLocalLocation().getY(); - - //Remove projectiles that are about to die if (!soteyProjectiles.isEmpty()) { - for (Iterator it = soteyProjectiles.keySet().iterator(); it.hasNext(); ) - { - Projectile projectile = it.next(); - if (projectile.getRemainingCycles() < 1) - { - it.remove(); - } - } + soteyProjectiles.keySet().removeIf(p -> p.getRemainingCycles() < 1); } boolean sotetsegFighting = false; @@ -338,7 +290,7 @@ public class SotetsegHandler extends RoomHandler WorldPoint pW = new WorldPoint(p.getX() - 1, p.getY(), p.getPlane()); if (!((redUnderworld.contains(pN) && redUnderworld.contains(pS)) || - (redUnderworld.contains(pE) && redUnderworld.contains(pW)))) + (redUnderworld.contains(pE) && redUnderworld.contains(pW)))) { gridPath.add(new Point(p.getX() - minX, p.getY() - minY)); if (!messageSent) diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/theatre/rooms/VerzikHandler.java b/runelite-client/src/main/java/net/runelite/client/plugins/theatre/rooms/VerzikHandler.java index 7b02a32106..0f92345fa4 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/theatre/rooms/VerzikHandler.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/theatre/rooms/VerzikHandler.java @@ -1,5 +1,12 @@ package net.runelite.client.plugins.theatre.rooms; +import java.awt.Color; +import java.awt.Font; +import java.awt.Graphics2D; +import java.util.HashMap; +import java.util.Map; +import java.util.regex.Matcher; +import java.util.regex.Pattern; import lombok.AccessLevel; import lombok.Getter; import net.runelite.api.Actor; @@ -22,38 +29,26 @@ import net.runelite.client.plugins.theatre.TheatreConfig; import net.runelite.client.plugins.theatre.TheatreConstant; import net.runelite.client.plugins.theatre.TheatrePlugin; import net.runelite.client.plugins.theatre.TheatreRoom; -import java.awt.*; -import java.util.*; -import java.util.regex.Matcher; -import java.util.regex.Pattern; public class VerzikHandler extends RoomHandler { @Getter(AccessLevel.PACKAGE) private final Map Verzik_RangeProjectiles = new HashMap<>(); - + //My variables + private int redCrabsTimer; @Getter(AccessLevel.PUBLIC) private int versikCounter = 0; private int attacksLeft = 0; - @Getter(AccessLevel.PUBLIC) private NPC npc; - private int lastId = -1; - private int autosSinceYellows; private int yellows; - private boolean tornados; - private int attackTick = -1; - private long startTime = 0; - //My variables - int redCrabsTimer; - public VerzikHandler(Client client, TheatrePlugin plugin, TheatreConfig config) { super(client, plugin, config); @@ -63,7 +58,9 @@ public class VerzikHandler extends RoomHandler public void onStart() { if (this.plugin.getRoom() == TheatreRoom.VERSIK) + { return; + } this.reset(); this.plugin.setRoom(TheatreRoom.VERSIK); @@ -117,10 +114,10 @@ public class VerzikHandler extends RoomHandler if (this.versikCounter >= 0) { String str = Integer.toString(versikCounter); - + LocalPoint lp = npc.getLocalLocation(); Point point = Perspective.getCanvasTextLocation(client, graphics, lp, str, 0); - + renderTextLocation(graphics, str, 20, Font.BOLD, Color.CYAN, point); } } @@ -141,19 +138,6 @@ public class VerzikHandler extends RoomHandler } } -/* - if (npc.getAnimation() == 8117){ - if (this.redCrabsTimer > 0){ - String str = Integer.toString(redCrabsTimer); - - LocalPoint lp = npc.getLocalLocation(); - Point point = Perspective.getCanvasTextLocation(client, graphics, lp, str, 60); - renderTextLocation(graphics, str, 15, Font.BOLD, Color.WHITE, point); - } - - - }*/ - else if (id == TheatreConstant.VERZIK_ID_P3) { if (config.p3attacks()) @@ -162,10 +146,10 @@ public class VerzikHandler extends RoomHandler if (versikCounter > 0 && versikCounter < 8) { String str = Math.max(versikCounter, 0) + "";// + " | " + model.getModelHeight();// + " | " + model.getRadius(); - + LocalPoint lp = npc.getLocalLocation(); Point point = Perspective.getCanvasTextLocation(client, graphics, lp, str, 0); - + renderTextLocation(graphics, str, 15, Font.BOLD, Color.WHITE, point); } } @@ -210,16 +194,22 @@ public class VerzikHandler extends RoomHandler for (NPC npc : client.getNpcs()) { if (npc.getName() == null) + { continue; + } Pattern p = Pattern.compile("Nylocas (Hagios|Toxobolos|Ischyros)"); Matcher m = p.matcher(npc.getName()); if (!m.matches()) + { continue; + } Actor target = npc.getInteracting(); if (target == null || target.getName() == null) + { continue; + } LocalPoint lp = npc.getLocalLocation(); Color color = local.getName().equals(target.getName()) ? Color.RED : Color.GREEN; @@ -231,15 +221,17 @@ public class VerzikHandler extends RoomHandler } } -public void onProjectileMoved(ProjectileMoved event) -{ - Projectile projectile = event.getProjectile(); - if (projectile.getId() == 1583) + + public void onProjectileMoved(ProjectileMoved event) { - WorldPoint p = WorldPoint.fromLocal(client, event.getPosition()); - Verzik_RangeProjectiles.put(projectile, p); + Projectile projectile = event.getProjectile(); + if (projectile.getId() == 1583) + { + WorldPoint p = WorldPoint.fromLocal(client, event.getPosition()); + Verzik_RangeProjectiles.put(projectile, p); + } } -} + public void onNpcSpawned(NpcSpawned event) { NPC npc = event.getNpc(); @@ -282,7 +274,9 @@ public void onProjectileMoved(ProjectileMoved event) Actor actor = event.getActor(); if (!(actor instanceof NPC)) + { return; + } NPC npc = (NPC) actor; int id = npc.getId(); @@ -325,29 +319,22 @@ public void onProjectileMoved(ProjectileMoved event) } if (!Verzik_RangeProjectiles.isEmpty()) { - for (Iterator it = Verzik_RangeProjectiles.keySet().iterator(); it.hasNext();) - { - Projectile projectile = it.next(); - if (projectile.getRemainingCycles() < 1) - { - it.remove(); - } - } + Verzik_RangeProjectiles.keySet().removeIf(p -> p.getRemainingCycles() < 1); } if (this.yellows == 0) { //if (this.autosSinceYellows > 0){ - for (GraphicsObject object : client.getGraphicsObjects()) + for (GraphicsObject object : client.getGraphicsObjects()) + { + if (object.getId() == TheatreConstant.GRAPHIC_ID_YELLOWS) { - if (object.getId() == TheatreConstant.GRAPHIC_ID_YELLOWS) - { - this.yellows = 14; + this.yellows = 14; // this.versikCounter = 22; - this.autosSinceYellows = 0; - System.out.println("Yellows have spawned."); - break; - } + this.autosSinceYellows = 0; + System.out.println("Yellows have spawned."); + break; } + } //} } else @@ -380,7 +367,9 @@ public void onProjectileMoved(ProjectileMoved event) } if (foundTornado && foundVerzik) + { break; + } } if (!foundVerzik) @@ -390,7 +379,9 @@ public void onProjectileMoved(ProjectileMoved event) } if (npc == null) + { return; + } int id = npc.getId(); @@ -410,7 +401,9 @@ public void onProjectileMoved(ProjectileMoved event) long minutes = seconds / 60L; seconds = seconds % 60; if (config.extraTimers()) - this.client.addChatMessage(ChatMessageType.GAMEMESSAGE, "", "Wave 'The Final Challenge - Part 1' completed! Duration: " + minutes + ":" + twoDigitString(seconds), null); + { + this.client.addChatMessage(ChatMessageType.GAMEMESSAGE, "", "Wave 'The Final Challenge - Part 1' completed! Duration: " + minutes + ":" + twoDigitString(seconds), null); + } } else if (id == TheatreConstant.VERZIK_ID_P2_TRANSFORM && this.startTime != 0) { @@ -424,7 +417,9 @@ public void onProjectileMoved(ProjectileMoved event) this.versikCounter = -1; this.attacksLeft = 9; if (config.extraTimers()) - this.client.addChatMessage(ChatMessageType.GAMEMESSAGE, "", "Wave 'The Final Challenge - Part 2' completed! Duration: " + minutes + ":" + twoDigitString(seconds), null); + { + this.client.addChatMessage(ChatMessageType.GAMEMESSAGE, "", "Wave 'The Final Challenge - Part 2' completed! Duration: " + minutes + ":" + twoDigitString(seconds), null); + } } } @@ -443,7 +438,9 @@ public void onProjectileMoved(ProjectileMoved event) { versikCounter--; if (versikCounter < 0) + { versikCounter = 0; + } } else if (id == TheatreConstant.VERZIK_ID_P3) { diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/theatre/rooms/nylocas/NyloHandler.java b/runelite-client/src/main/java/net/runelite/client/plugins/theatre/rooms/nylocas/NyloHandler.java index 1e84e21eb6..4ff3c17ae7 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/theatre/rooms/nylocas/NyloHandler.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/theatre/rooms/nylocas/NyloHandler.java @@ -1,5 +1,17 @@ package net.runelite.client.plugins.theatre.rooms.nylocas; +import java.awt.BasicStroke; +import java.awt.Color; +import java.awt.Font; +import java.awt.Graphics2D; +import java.awt.Polygon; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; +import java.util.regex.Matcher; +import java.util.regex.Pattern; import lombok.AccessLevel; import lombok.Getter; import lombok.Setter; @@ -18,41 +30,26 @@ import net.runelite.client.plugins.theatre.TheatreConstant; import net.runelite.client.plugins.theatre.TheatrePlugin; import net.runelite.client.plugins.theatre.TheatreRoom; -import java.awt.*; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Map; -import java.util.Set; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -public class NyloHandler extends RoomHandler +public class NyloHandler extends RoomHandler { + public long startTime = 0L; + int startTick = 0; + ArrayList waveSpawns = new ArrayList(); + ArrayList waveAgros = new ArrayList(); @Getter(AccessLevel.PUBLIC) private Map pillars = new HashMap<>(); - @Getter(AccessLevel.PUBLIC) private Map spiders = new HashMap<>(); - @Getter @Setter private int wave = 0; - private NyloOverlay overlay = null; private NyloPredictor predictor = null; - private Point south = new Point(64, 41); private Point west = new Point(49, 56); private Point east = new Point(78, 56); - public long startTime = 0L; - public int startTick = 0; - - public ArrayList waveSpawns = new ArrayList(); - public ArrayList waveAgros = new ArrayList(); - public NyloHandler(Client client, TheatrePlugin plugin, TheatreConfig config) { super(client, plugin, config); @@ -62,7 +59,9 @@ public class NyloHandler extends RoomHandler public void onStart() { if (this.plugin.getRoom() == TheatreRoom.NYLOCAS) + { return; + } this.reset(); @@ -102,7 +101,9 @@ public class NyloHandler extends RoomHandler if (this.startTime != 0) { if (config.extraTimers()) - this.client.addChatMessage(ChatMessageType.GAMEMESSAGE, "", "Wave 'The Nylocas - Waves' completed! Duration: " + minutes + ":" + twoDigitString(seconds), null); + { + this.client.addChatMessage(ChatMessageType.GAMEMESSAGE, "", "Wave 'The Nylocas - Waves' completed! Duration: " + minutes + ":" + twoDigitString(seconds), null); + } } System.out.println("Stopping Nylocas Room"); } @@ -159,7 +160,7 @@ public class NyloHandler extends RoomHandler for (NPC npc : pillars.keySet()) { final int health = pillars.get(npc); - final String healthStr = String.valueOf(health) + "%"; + final String healthStr = health + "%"; WorldPoint p = npc.getWorldLocation(); LocalPoint lp = LocalPoint.fromWorld(client, p.getX() + 1, p.getY() + 1); @@ -203,45 +204,21 @@ public class NyloHandler extends RoomHandler Set toHighlight = new HashSet(); - /** - if (config.highlightNyloParents()) - { - for (NPC npc : new ArrayList(this.waveSpawns)) - { - try - { - if (npc.getHealthRatio() == 0 || npc.isDead()) - { - this.waveSpawns.remove(npc); - continue; - } - - if (!toHighlight.contains(npc)) - toHighlight.add(npc); - } - catch (Exception ex) - { - - } - } - }**/ - - if (config.highlightNyloAgros()) + if (config.highlightNyloAgros()) { for (NPC npc : new ArrayList(this.waveAgros)) { try { - if (npc.getHealthRatio() == 0 || npc.isDead()) + if (npc.getHealthRatio() == 0 || npc.isDead()) { this.waveAgros.remove(npc); continue; } - if (!toHighlight.contains(npc)) - toHighlight.add(npc); - } - catch (Exception ex) + toHighlight.add(npc); + } + catch (Exception ex) { } @@ -258,58 +235,25 @@ public class NyloHandler extends RoomHandler String name = npc.getName() != null ? npc.getName() : ""; if (name.contains("Hagios")) + { color = Color.CYAN; + } else if (name.contains("Toxobolos")) + { color = Color.GREEN; + } else + { color = Color.LIGHT_GRAY; + } renderPoly(graphics, color, objectClickbox); - } + } catch (Exception ex) { } } -/** - if (config.showNylocasSpawns() && predictor != null) - { - NyloPredictor.Wave nextWave = predictor.getNextWave(); - if (nextWave != null) - { - TheatreConfig.NYLOCAS mark = config.highlightNyloRoles(); - - String southStr = predictor.getSpawnStr(NyloPredictor.Spawn.SOUTH, nextWave); - if (southStr != null && south != null) - { - LocalPoint lp = LocalPoint.fromScene(south.getX(), south.getY()); - Point point = Perspective.getCanvasTextLocation(client, graphics, lp, southStr, 1); - Color color = mark != TheatreConfig.NYLOCAS.NONE ? (((southStr.contains("Mage") && mark == TheatreConfig.NYLOCAS.MAGE) || (southStr.contains("Range") && mark == TheatreConfig.NYLOCAS.RANGER) || (southStr.contains("Melee") && mark == TheatreConfig.NYLOCAS.MELEE)) ? Color.MAGENTA : Color.RED) : Color.RED; - renderTextLocation(graphics, southStr, 18, Font.BOLD, color, point); -// drawTile(graphics, WorldPoint.fromLocal(client, lp), new Color(0, 150, 200), 2, 150, 10); - } - - String westStr = predictor.getSpawnStr(NyloPredictor.Spawn.WEST, nextWave); - if (westStr != null && west != null) - { - LocalPoint lp = LocalPoint.fromScene(west.getX(), west.getY()); - Point point = Perspective.getCanvasTextLocation(client, graphics, lp, westStr, 1); - Color color = mark != TheatreConfig.NYLOCAS.NONE ? (((westStr.contains("Mage") && mark == TheatreConfig.NYLOCAS.MAGE) || (westStr.contains("Range") && mark == TheatreConfig.NYLOCAS.RANGER) || (westStr.contains("Melee") && mark == TheatreConfig.NYLOCAS.MELEE)) ? Color.MAGENTA : Color.RED) : Color.RED; - renderTextLocation(graphics, westStr, 18, Font.BOLD, color, point); -// drawTile(graphics, WorldPoint.fromLocal(client, lp), new Color(0, 150, 200), 2, 150, 10); - } - - String eastStr = predictor.getSpawnStr(NyloPredictor.Spawn.EAST, nextWave); - if (eastStr != null && east != null) - { - LocalPoint lp = LocalPoint.fromScene(east.getX(), east.getY()); - Point point = Perspective.getCanvasTextLocation(client, graphics, lp, eastStr, 1); - Color color = mark != TheatreConfig.NYLOCAS.NONE ? (((eastStr.contains("Mage") && mark == TheatreConfig.NYLOCAS.MAGE) || (eastStr.contains("Range") && mark == TheatreConfig.NYLOCAS.RANGER) || (eastStr.contains("Melee") && mark == TheatreConfig.NYLOCAS.MELEE)) ? Color.MAGENTA : Color.RED) : Color.RED; - renderTextLocation(graphics, eastStr, 18, Font.BOLD, color, point); -// drawTile(graphics, WorldPoint.fromLocal(client, lp), new Color(0, 150, 200), 2, 150, 10); - } - } - }**/ } public void onNpcSpawned(NpcSpawned event) @@ -351,15 +295,9 @@ public class NyloHandler extends RoomHandler NPC npc = event.getNpc(); int id = npc.getId(); - if (this.waveSpawns.contains(npc)) - { - this.waveSpawns.remove(npc); - } + this.waveSpawns.remove(npc); - if (this.waveAgros.contains(npc)) - { - this.waveAgros.remove(npc); - } + this.waveAgros.remove(npc); if (id == TheatreConstant.NPC_ID_NYLOCAS_PILLAR) { @@ -393,7 +331,7 @@ public class NyloHandler extends RoomHandler if (plugin.getRoom() != TheatreRoom.NYLOCAS) { return; - } + } else { boolean findPillar = false; diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/theatre/rooms/nylocas/NyloOverlay.java b/runelite-client/src/main/java/net/runelite/client/plugins/theatre/rooms/nylocas/NyloOverlay.java index 54e568cb7e..9c57485f26 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/theatre/rooms/nylocas/NyloOverlay.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/theatre/rooms/nylocas/NyloOverlay.java @@ -39,21 +39,21 @@ 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.PanelComponent; +import net.runelite.client.ui.overlay.components.table.TableAlignment; import net.runelite.client.ui.overlay.components.table.TableComponent; import net.runelite.client.util.ColorUtil; -class NyloOverlay extends Overlay +class NyloOverlay extends Overlay { private final Client client; private final TheatrePlugin plugin; - private final TheatreConfig config; private final PanelComponent panelComponent = new PanelComponent(); private NyloHandler nylohandler; - public NyloOverlay(Client client, TheatrePlugin plugin, TheatreConfig config, NyloHandler nylohandler) + NyloOverlay(Client client, TheatrePlugin plugin, TheatreConfig config, NyloHandler nylohandler) { super(plugin); @@ -62,7 +62,6 @@ class NyloOverlay extends Overlay this.client = client; this.plugin = plugin; - this.config = config; this.nylohandler = nylohandler; getMenuEntries().add(new OverlayMenuEntry(RUNELITE_OVERLAY_CONFIG, OPTION_CONFIGURE, "Nylocas Overlay")); @@ -102,6 +101,7 @@ class NyloOverlay extends Overlay panelComponent.getChildren().clear(); TableComponent tableComponent = new TableComponent(); + tableComponent.setColumnAlignments(TableAlignment.LEFT, TableAlignment.RIGHT); int nyloCount = (hagios + toxobolos + ischyros); if (nylohandler.getWave() < 21) @@ -109,14 +109,14 @@ class NyloOverlay extends Overlay if (nyloCount > 12) { tableComponent.addRow("Total Nylocas:", ColorUtil.prependColorTag(nyloCount + " / 12", Color.RED)); - } + } else { tableComponent.addRow("Total Nylocas:", ColorUtil.prependColorTag(nyloCount + " / 12", Color.GREEN)); } - } - else + } + else { if (nyloCount > 24) { @@ -130,23 +130,6 @@ class NyloOverlay extends Overlay panelComponent.getChildren().add(tableComponent); - - /** - panelComponent.getChildren().add(LineComponent.builder() - .left("Ischyros:") - .right(Integer.toString(ischyros)) - .build()); - - panelComponent.getChildren().add(LineComponent.builder() - .left("Toxobolos:") - .right(Integer.toString(toxobolos)) - .build()); - - panelComponent.getChildren().add(LineComponent.builder() - .left("Hagios:") - .right(Integer.toString(hagios)) - .build()); - **/ return panelComponent.render(graphics); } } \ No newline at end of file diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/theatre/rooms/nylocas/NyloPredictor.java b/runelite-client/src/main/java/net/runelite/client/plugins/theatre/rooms/nylocas/NyloPredictor.java index 75042fa328..b9d3e19b44 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/theatre/rooms/nylocas/NyloPredictor.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/theatre/rooms/nylocas/NyloPredictor.java @@ -1,91 +1,19 @@ package net.runelite.client.plugins.theatre.rooms.nylocas; -import net.runelite.api.Client; -import net.runelite.api.NPC; -import net.runelite.api.coords.LocalPoint; -import net.runelite.api.events.NpcSpawned; - import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; +import net.runelite.api.Client; +import net.runelite.api.NPC; +import net.runelite.api.coords.LocalPoint; +import net.runelite.api.events.NpcSpawned; public class NyloPredictor { - public enum NylocasType - { - MELEE_162, - RANGE_162, - MAGE_162, - MELEE_260, - RANGE_260, - MAGE_260; - } - - public enum Spawn - { - WEST, - SOUTH, - EAST; - } - - public static class Nylocas - { - - private NylocasType type; - private Spawn spawn; - - public Nylocas(NylocasType type, Spawn spawn) + private static final Wave[] NYLOCAS_WAVES = new Wave[] { - this.type = type; - this.spawn = spawn; - } - - public NylocasType getType() - { - return this.type; - } - - public Spawn getSpawn() - { - return this.spawn; - } - - @Override - public boolean equals(Object object) - { - if (object != null && (object instanceof Nylocas)) - { - Nylocas nylo = (Nylocas) object; - if (nylo.getType() == this.type && nylo.getSpawn() == this.spawn) - { - return true; - } - } - - return false; - } - } - - public static class Wave - { - - private Nylocas[] spawns; - - public Wave(Nylocas... nylocas) - { - this.spawns = nylocas; - } - - public Nylocas[] getSpawns() - { - return this.spawns; - } - } - - public static final Wave[] NYLOCAS_WAVES = new Wave[] - { new Wave(new Nylocas(NylocasType.RANGE_162, Spawn.WEST), new Nylocas(NylocasType.MAGE_162, Spawn.SOUTH), new Nylocas(NylocasType.MELEE_162, Spawn.EAST)), new Wave(new Nylocas(NylocasType.MAGE_162, Spawn.WEST), new Nylocas(NylocasType.MELEE_162, Spawn.SOUTH), new Nylocas(NylocasType.RANGE_162, Spawn.EAST)), new Wave(new Nylocas(NylocasType.MELEE_162, Spawn.WEST), new Nylocas(NylocasType.RANGE_162, Spawn.SOUTH), new Nylocas(NylocasType.MAGE_162, Spawn.EAST)), @@ -117,15 +45,16 @@ public class NyloPredictor new Wave(new Nylocas(NylocasType.MELEE_162, Spawn.WEST), new Nylocas(NylocasType.RANGE_162, Spawn.WEST), new Nylocas(NylocasType.MELEE_260, Spawn.SOUTH), new Nylocas(NylocasType.RANGE_162, Spawn.EAST), new Nylocas(NylocasType.MAGE_162, Spawn.EAST)), new Wave(new Nylocas(NylocasType.RANGE_260, Spawn.WEST), new Nylocas(NylocasType.MAGE_162, Spawn.SOUTH), new Nylocas(NylocasType.MELEE_162, Spawn.SOUTH), new Nylocas(NylocasType.MAGE_260, Spawn.EAST)), new Wave(new Nylocas(NylocasType.MELEE_162, Spawn.WEST), new Nylocas(NylocasType.RANGE_162, Spawn.WEST), new Nylocas(NylocasType.MAGE_162, Spawn.SOUTH), new Nylocas(NylocasType.MELEE_162, Spawn.SOUTH), new Nylocas(NylocasType.RANGE_162, Spawn.EAST), new Nylocas(NylocasType.MAGE_162, Spawn.EAST)) - }; - + }; public Client client; - public NyloHandler handler; + int westBound = 50; + int eastBound = 77; + int southBound = 42; + private NyloHandler handler; + private Map currentSpawns = new HashMap(); + private int currentIndex = -1; - public Map currentSpawns = new HashMap(); - public int currentIndex = -1; - - public NyloPredictor(Client client, NyloHandler handler) + NyloPredictor(Client client, NyloHandler handler) { this.client = client; this.handler = handler; @@ -138,12 +67,6 @@ public class NyloPredictor this.currentIndex = -1; } - public int westBound = 50; - - public int eastBound = 77; - - public int southBound = 42; - public void onNpcSpawned(NpcSpawned event) { NPC npc = event.getNpc(); @@ -157,11 +80,11 @@ public class NyloPredictor if (x <= westBound) { spawn = Spawn.WEST; - } + } else if (x >= eastBound) { spawn = Spawn.EAST; - } + } else if (y <= southBound) { spawn = Spawn.SOUTH; @@ -175,11 +98,11 @@ public class NyloPredictor if (name.contains("Hagios")) { type = NylocasType.valueOf("MAGE_" + level); - } + } else if (name.contains("Toxobolos")) { type = NylocasType.valueOf("RANGE_" + level); - } + } else if (name.contains("Ischyros")) { type = NylocasType.valueOf("MELEE_" + level); @@ -213,7 +136,7 @@ public class NyloPredictor int index = queue.indexOf(nylocas); Nylocas hashed = queue.remove(index); npcs.put(currentSpawns.get(hashed), hashed); - } + } else { found = false; @@ -257,12 +180,14 @@ public class NyloPredictor for (NPC npc : client.getNpcs()) { if (npc.getHealthRatio() == 0) + { continue; + } if (npc.getName().equalsIgnoreCase("Nylocas Hagios")) { mage_level += npc.getCombatLevel(); mage_count += 1; - } + } else if (npc.getName().equalsIgnoreCase("Nylocas Toxobolos")) { range_level += npc.getCombatLevel(); @@ -300,7 +225,7 @@ public class NyloPredictor } } - public boolean isAgressive(NylocasType type, Spawn spawn, int wave) + private boolean isAgressive(NylocasType type, Spawn spawn, int wave) { if (wave == 0 && spawn == Spawn.WEST) { @@ -329,9 +254,13 @@ public class NyloPredictor else if (wave == 9) { if (spawn == Spawn.EAST && type == NylocasType.RANGE_162) + { return true; - else if (spawn == Spawn.WEST) - return true; + } + else + { + return spawn == Spawn.WEST; + } } else if (wave == 10 && (spawn == Spawn.EAST || spawn == Spawn.WEST)) { @@ -344,23 +273,35 @@ public class NyloPredictor else if (wave == 12) { if (spawn == Spawn.WEST && type == NylocasType.MAGE_162) + { return true; - else if (spawn == Spawn.EAST) - return true; + } + else + { + return spawn == Spawn.EAST; + } } else if (wave == 13) { if (spawn == Spawn.WEST && type == NylocasType.MELEE_162) + { return true; - else if (spawn == Spawn.EAST) - return true; + } + else + { + return spawn == Spawn.EAST; + } } else if (wave == 14) { if (spawn == Spawn.WEST && type == NylocasType.RANGE_162) + { return true; - else if (spawn == Spawn.EAST && type == NylocasType.MAGE_162) - return true; + } + else + { + return spawn == Spawn.EAST && type == NylocasType.MAGE_162; + } } else if (wave == 17 && spawn == Spawn.WEST) { @@ -405,17 +346,20 @@ public class NyloPredictor else if (wave == 28) { if (spawn == Spawn.EAST && type == NylocasType.RANGE_162) + { return true; - else if (spawn == Spawn.WEST && type == NylocasType.MELEE_162) - return true; + } + else + { + return spawn == Spawn.WEST && type == NylocasType.MELEE_162; + } } - else if (wave == 29 && spawn == Spawn.EAST) + else { - return true; + return wave == 29 && spawn == Spawn.EAST; } - return false; } public int getCurrentWave() @@ -487,4 +431,72 @@ public class NyloPredictor return types.length() > 0 ? types : null; } } + + public enum NylocasType + { + MELEE_162, + RANGE_162, + MAGE_162, + MELEE_260, + RANGE_260, + MAGE_260 + } + + public enum Spawn + { + WEST, + SOUTH, + EAST + } + + public static class Nylocas + { + + private NylocasType type; + private Spawn spawn; + + public Nylocas(NylocasType type, Spawn spawn) + { + this.type = type; + this.spawn = spawn; + } + + public NylocasType getType() + { + return this.type; + } + + public Spawn getSpawn() + { + return this.spawn; + } + + @Override + public boolean equals(Object object) + { + if (object != null && (object instanceof Nylocas)) + { + Nylocas nylo = (Nylocas) object; + return nylo.getType() == this.type && nylo.getSpawn() == this.spawn; + } + + return false; + } + } + + public static class Wave + { + + private Nylocas[] spawns; + + public Wave(Nylocas... nylocas) + { + this.spawns = nylocas; + } + + public Nylocas[] getSpawns() + { + return this.spawns; + } + } } \ No newline at end of file diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/theatre/rooms/xarpus/XarpusCounter.java b/runelite-client/src/main/java/net/runelite/client/plugins/theatre/rooms/xarpus/XarpusCounter.java index 840902c186..2be0d90109 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/theatre/rooms/xarpus/XarpusCounter.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/theatre/rooms/xarpus/XarpusCounter.java @@ -13,6 +13,7 @@ import net.runelite.client.ui.overlay.OverlayMenuEntry; import net.runelite.client.ui.overlay.OverlayPosition; import net.runelite.client.ui.overlay.components.PanelComponent; import net.runelite.client.ui.overlay.components.TitleComponent; +import net.runelite.client.ui.overlay.components.table.TableAlignment; import net.runelite.client.ui.overlay.components.table.TableComponent; public class XarpusCounter extends Overlay @@ -21,10 +22,8 @@ public class XarpusCounter extends Overlay private final Client client; private final TheatrePlugin plugin; private final TheatreConfig config; - - private XarpusHandler xarpusHandler; - PanelComponent panelComponent = new PanelComponent(); + private XarpusHandler xarpusHandler; public XarpusCounter(Client client, TheatrePlugin plugin, TheatreConfig config, XarpusHandler xarpushandler) { @@ -50,16 +49,17 @@ public class XarpusCounter extends Overlay // Build overlay title panelComponent.getChildren().add(TitleComponent.builder() - .text(overlayTitle) - .color(Color.GREEN) - .build()); + .text(overlayTitle) + .color(Color.GREEN) + .build()); //Set the size of overlay panelComponent.setPreferredSize(new Dimension( - graphics.getFontMetrics().stringWidth(overlayTitle) + 30, 0 + graphics.getFontMetrics().stringWidth(overlayTitle) + 30, 0 )); TableComponent tableComponent = new TableComponent(); + tableComponent.setColumnAlignments(TableAlignment.LEFT, TableAlignment.RIGHT); tableComponent.addRow("Exhumes", String.valueOf(xarpusHandler.getExhumesCount())); panelComponent.getChildren().add(tableComponent); diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/theatre/rooms/xarpus/XarpusHandler.java b/runelite-client/src/main/java/net/runelite/client/plugins/theatre/rooms/xarpus/XarpusHandler.java index f8395e14b4..d2c278806e 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/theatre/rooms/xarpus/XarpusHandler.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/theatre/rooms/xarpus/XarpusHandler.java @@ -1,5 +1,13 @@ package net.runelite.client.plugins.theatre.rooms.xarpus; +import java.awt.BasicStroke; +import java.awt.Color; +import java.awt.Font; +import java.awt.Graphics2D; +import java.awt.Polygon; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Map; import lombok.Getter; import net.runelite.api.ChatMessageType; import net.runelite.api.Client; @@ -19,20 +27,13 @@ import net.runelite.client.plugins.theatre.TheatreConfig; import net.runelite.client.plugins.theatre.TheatreConstant; import net.runelite.client.plugins.theatre.TheatrePlugin; import net.runelite.client.plugins.theatre.TheatreRoom; -import java.awt.*; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.Map; public class XarpusHandler extends RoomHandler { - private int previousTurn; - - private boolean staring; - private final Map exhumes = new HashMap<>(); - + private int previousTurn; + private boolean staring; private int ticksUntilShoot = 8; @Getter @@ -56,7 +57,9 @@ public class XarpusHandler extends RoomHandler public void onStart() { if (this.plugin.getRoom() == TheatreRoom.XARPUS) + { return; + } this.reset(); this.plugin.setRoom(TheatreRoom.XARPUS); @@ -102,7 +105,9 @@ public class XarpusHandler extends RoomHandler public void render(Graphics2D graphics) { if (npc == null) + { return; + } if (npc.getId() == NpcID.XARPUS_8340) //&& !staring&& config.showXarpusTick()) { @@ -111,13 +116,15 @@ public class XarpusHandler extends RoomHandler this.up = true; long elapsedTime = System.currentTimeMillis() - this.startTime; long seconds = elapsedTime / 1000L; - + long minutes = seconds / 60L; seconds = seconds % 60; - + this.ticksUntilShoot = 8; if (config.extraTimers()) - this.client.addChatMessage(ChatMessageType.GAMEMESSAGE, "", "Wave 'Xarpus - Recovery' completed! Duration: " + minutes + ":" + twoDigitString(seconds), null); + { + this.client.addChatMessage(ChatMessageType.GAMEMESSAGE, "", "Wave 'Xarpus - Recovery' completed! Duration: " + minutes + ":" + twoDigitString(seconds), null); + } } final String ticksLeftStr = String.valueOf(ticksUntilShoot); @@ -257,7 +264,9 @@ public class XarpusHandler extends RoomHandler long minutes = seconds / 60L; seconds = seconds % 60; if (config.extraTimers()) - this.client.addChatMessage(ChatMessageType.GAMEMESSAGE, "", "Wave 'Xarpus - Acid' completed! Duration: " + minutes + ":" + twoDigitString(seconds), null); + { + this.client.addChatMessage(ChatMessageType.GAMEMESSAGE, "", "Wave 'Xarpus - Acid' completed! Duration: " + minutes + ":" + twoDigitString(seconds), null); + } } ticksUntilShoot = 6; @@ -275,7 +284,7 @@ public class XarpusHandler extends RoomHandler if (staring) { ticksUntilShoot = 8; - } + } else { ticksUntilShoot = 4; diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/theatre/timers/RoomTimer.java b/runelite-client/src/main/java/net/runelite/client/plugins/theatre/timers/RoomTimer.java index 9fb911a542..3a9c13252f 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/theatre/timers/RoomTimer.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/theatre/timers/RoomTimer.java @@ -1,18 +1,20 @@ package net.runelite.client.plugins.theatre.timers; +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.Player; import net.runelite.client.plugins.theatre.TheatrePlugin; 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.PanelComponent; import net.runelite.client.ui.overlay.components.TitleComponent; -import javax.inject.Inject; -import java.awt.*; -import static net.runelite.api.MenuAction.RUNELITE_OVERLAY_CONFIG; -import static net.runelite.client.ui.overlay.OverlayManager.OPTION_CONFIGURE; public class RoomTimer extends Overlay { @@ -25,9 +27,9 @@ public class RoomTimer extends Overlay @Inject - public RoomTimer (Client client, TheatrePlugin plugin) + public RoomTimer(Client client, TheatrePlugin plugin) { - super (plugin); + super(plugin); setPosition(OverlayPosition.ABOVE_CHATBOX_RIGHT); setPriority(OverlayPriority.HIGH); @@ -40,15 +42,17 @@ public class RoomTimer extends Overlay @Override - public Dimension render(Graphics2D graphics) + public Dimension render(Graphics2D graphics) { panelComponent.getChildren().clear(); Player local = client.getLocalPlayer(); if (local == null || local.getName() == null) + { return null; + } - switch (plugin.getRoom()) + switch (plugin.getRoom()) { case MAIDEN: plugin.getMaidenHandler().render(graphics); diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/theatre/timers/Timeable.java b/runelite-client/src/main/java/net/runelite/client/plugins/theatre/timers/Timeable.java index e19452b435..04c5a1a6c5 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/theatre/timers/Timeable.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/theatre/timers/Timeable.java @@ -4,5 +4,5 @@ import java.util.HashMap; public interface Timeable { - public abstract HashMap getTimes(); + HashMap getTimes(); } \ No newline at end of file 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 84abfcf9f5..0dce1c78b5 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 @@ -97,7 +97,7 @@ public class WorldHopperPlugin extends Plugin { private static final int WORLD_FETCH_TIMER = 10; private static final int WORLD_PING_TIMER = 10; - private static final int REFRESH_THROTTLE = 60_000; // ms + private static final int REFRESH_THROTTLE = 60_000; // ms private static final int TICK_THROTTLE = (int) Duration.ofMinutes(10).toMillis(); private static final int DISPLAY_SWITCHER_MAX_ATTEMPTS = 3; diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/worldmap/RareTreeLocation.java b/runelite-client/src/main/java/net/runelite/client/plugins/worldmap/RareTreeLocation.java index d32dee4c32..843d6eb645 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/worldmap/RareTreeLocation.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/worldmap/RareTreeLocation.java @@ -67,6 +67,7 @@ enum RareTreeLocation new WorldPoint(1640, 3496, 0), new WorldPoint(1613, 3494, 0), new WorldPoint(1560, 3636, 0), + new WorldPoint(1646, 3590, 0), // Miscellania new WorldPoint(2550, 3869, 0), @@ -109,9 +110,8 @@ enum RareTreeLocation new WorldPoint(1353, 3731, 0), new WorldPoint(1529, 3452, 0), new WorldPoint(1591, 3421, 0), - new WorldPoint(1647, 3510, 0), - new WorldPoint(1632, 3509, 0), - new WorldPoint(1623, 3512, 0), + new WorldPoint(1647, 3508, 0), + new WorldPoint(1621, 3512, 0), new WorldPoint(1593, 3491, 0), new WorldPoint(1583, 3499, 0), new WorldPoint(1696, 3554, 0), @@ -119,6 +119,9 @@ enum RareTreeLocation new WorldPoint(1625, 3669, 0), new WorldPoint(1642, 3683, 0), new WorldPoint(1642, 3663, 0), + new WorldPoint(1642, 3533, 0), + new WorldPoint(1671, 3657, 0), + new WorldPoint(1680, 3657, 0), // Tirannwn new WorldPoint(2217, 3141, 0), @@ -187,8 +190,10 @@ enum RareTreeLocation new WorldPoint(1389, 3821, 0), new WorldPoint(1610, 3443, 0), new WorldPoint(1578, 3488, 0), - new WorldPoint(1772, 3510, 0), new WorldPoint(1685, 3740, 0), + new WorldPoint(1681, 3689, 0), + new WorldPoint(1751, 3564, 0), + new WorldPoint(1796, 3600, 0), // Misthalin new WorldPoint(3355, 3312, 0), diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/xptracker/XpInfoBox.java b/runelite-client/src/main/java/net/runelite/client/plugins/xptracker/XpInfoBox.java index d6fff3c47b..c2e2284797 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/xptracker/XpInfoBox.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/xptracker/XpInfoBox.java @@ -28,6 +28,9 @@ package net.runelite.client.plugins.xptracker; import java.awt.BorderLayout; import java.awt.Color; import java.awt.Dimension; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import java.awt.event.MouseListener; import java.text.DecimalFormat; import java.util.ArrayList; import java.util.Collections; @@ -79,12 +82,13 @@ class XpInfoBox extends JPanel /* The tracker's wrapping container */ private final JPanel container = new JPanel(); - /* Contains the skill icon and the stats panel */ - private final JPanel headerPanel = new JPanel(); + /* Contains the skill icon */ + private final JPanel skillWrapper = new JPanel(); /* Contains all the skill information (exp gained, per hour, etc) */ private final JPanel statsPanel = new JPanel(); + private final JPanel progressWrapper = new JPanel(); private final ProgressBar progressBar = new ProgressBar(); private final JLabel expGained = new JLabel(); @@ -98,6 +102,14 @@ class XpInfoBox extends JPanel private boolean paused = false; + private Style style = Style.FULL; + + private enum Style + { + FULL, + SIMPLE + } + XpInfoBox(XpTrackerPlugin xpTrackerPlugin, XpTrackerConfig xpTrackerConfig, Client client, JPanel panel, Skill skill, SkillIconManager iconManager) { this.xpTrackerConfig = xpTrackerConfig; @@ -134,6 +146,10 @@ class XpInfoBox extends JPanel popupMenu.add(pauseSkill); popupMenu.add(canvasItem); + skillWrapper.setBackground(ColorScheme.DARKER_GRAY_COLOR); + skillWrapper.setLayout(new BorderLayout()); + skillWrapper.setBorder(new EmptyBorder(0, 5, 0, 0)); + canvasItem.addActionListener(e -> { if (canvasItem.getText().equals(REMOVE_STATE)) @@ -151,14 +167,13 @@ class XpInfoBox extends JPanel JLabel skillIcon = new JLabel(new ImageIcon(iconManager.getSkillImage(skill))); skillIcon.setHorizontalAlignment(SwingConstants.CENTER); skillIcon.setVerticalAlignment(SwingConstants.CENTER); - skillIcon.setPreferredSize(new Dimension(35, 35)); + skillIcon.setPreferredSize(new Dimension(30, 30)); - headerPanel.setBackground(ColorScheme.DARKER_GRAY_COLOR); - headerPanel.setLayout(new BorderLayout()); + skillWrapper.add(skillIcon, BorderLayout.NORTH); statsPanel.setLayout(new DynamicGridLayout(2, 2)); statsPanel.setBackground(ColorScheme.DARKER_GRAY_COLOR); - statsPanel.setBorder(new EmptyBorder(9, 2, 9, 2)); + statsPanel.setBorder(new EmptyBorder(6, 5, 0, 2)); expGained.setFont(FontManager.getRunescapeSmallFont()); expHour.setFont(FontManager.getRunescapeSmallFont()); @@ -170,13 +185,8 @@ class XpInfoBox extends JPanel statsPanel.add(expHour); statsPanel.add(actionsLeft); - headerPanel.add(skillIcon, BorderLayout.WEST); - headerPanel.add(statsPanel, BorderLayout.CENTER); - - JPanel progressWrapper = new JPanel(); progressWrapper.setBackground(ColorScheme.DARKER_GRAY_COLOR); progressWrapper.setLayout(new BorderLayout()); - progressWrapper.setBorder(new EmptyBorder(0, 7, 7, 7)); progressBar.setMaximumValue(100); progressBar.setBackground(new Color(61, 56, 49)); @@ -185,15 +195,48 @@ class XpInfoBox extends JPanel progressWrapper.add(progressBar, BorderLayout.NORTH); - container.add(headerPanel, BorderLayout.NORTH); - container.add(progressWrapper, BorderLayout.SOUTH); - container.setComponentPopupMenu(popupMenu); progressBar.setComponentPopupMenu(popupMenu); + MouseListener mouseListener = new MouseAdapter() + { + @Override + public void mouseClicked(MouseEvent e) + { + if (SwingUtilities.isLeftMouseButton(e)) + { + toggleStyle(); + } + } + }; + container.addMouseListener(mouseListener); + progressBar.addMouseListener(mouseListener); + add(container, BorderLayout.NORTH); } + void setStyle(Style style) + { + container.removeAll(); + + if (style == Style.SIMPLE) + { + progressWrapper.setBorder(new EmptyBorder(7, 7, 7, 7)); + container.add(skillWrapper, BorderLayout.WEST); + container.add(progressWrapper, BorderLayout.CENTER); + } + else + { + progressWrapper.setBorder(new EmptyBorder(4, 7, 7, 7)); + container.add(skillWrapper, BorderLayout.WEST); + container.add(statsPanel, BorderLayout.CENTER); + container.add(progressWrapper, BorderLayout.SOUTH); + } + + panel.revalidate(); + this.style = style; + } + void reset() { canvasItem.setText(ADD_STATE); @@ -214,7 +257,7 @@ class XpInfoBox extends JPanel if (getParent() != panel) { panel.add(this); - panel.revalidate(); + setStyle(style); } paused = skillPaused; @@ -284,6 +327,18 @@ class XpInfoBox extends JPanel expHour.setText(htmlLabel("XP/Hour: ", xpSnapshotSingle.getXpPerHour())); } + private void toggleStyle() + { + if (style == Style.FULL) + { + setStyle(Style.SIMPLE); + } + else + { + setStyle(Style.FULL); + } + } + static String htmlLabel(String key, int value) { String valueStr = StackFormatter.quantityToRSDecimalStack(value, true); diff --git a/runelite-client/src/main/resources/net/runelite/client/plugins/interfacestyles/2005/900.png b/runelite-client/src/main/resources/net/runelite/client/plugins/interfacestyles/2005/900.png index 407e476c54..80c3b83fc8 100644 Binary files a/runelite-client/src/main/resources/net/runelite/client/plugins/interfacestyles/2005/900.png and b/runelite-client/src/main/resources/net/runelite/client/plugins/interfacestyles/2005/900.png differ diff --git a/runelite-client/src/main/resources/net/runelite/client/plugins/interfacestyles/rs3/cross_sprites/0.png b/runelite-client/src/main/resources/net/runelite/client/plugins/interfacestyles/rs3/cross_sprites/0.png new file mode 100644 index 0000000000..b817c474c0 Binary files /dev/null and b/runelite-client/src/main/resources/net/runelite/client/plugins/interfacestyles/rs3/cross_sprites/0.png differ diff --git a/runelite-client/src/main/resources/net/runelite/client/plugins/interfacestyles/rs3/cross_sprites/1.png b/runelite-client/src/main/resources/net/runelite/client/plugins/interfacestyles/rs3/cross_sprites/1.png new file mode 100644 index 0000000000..a6add2616d Binary files /dev/null and b/runelite-client/src/main/resources/net/runelite/client/plugins/interfacestyles/rs3/cross_sprites/1.png differ diff --git a/runelite-client/src/main/resources/net/runelite/client/plugins/interfacestyles/rs3/cross_sprites/2.png b/runelite-client/src/main/resources/net/runelite/client/plugins/interfacestyles/rs3/cross_sprites/2.png new file mode 100644 index 0000000000..015b85e5a0 Binary files /dev/null and b/runelite-client/src/main/resources/net/runelite/client/plugins/interfacestyles/rs3/cross_sprites/2.png differ diff --git a/runelite-client/src/main/resources/net/runelite/client/plugins/interfacestyles/rs3/cross_sprites/3.png b/runelite-client/src/main/resources/net/runelite/client/plugins/interfacestyles/rs3/cross_sprites/3.png new file mode 100644 index 0000000000..e62c91b16c Binary files /dev/null and b/runelite-client/src/main/resources/net/runelite/client/plugins/interfacestyles/rs3/cross_sprites/3.png differ diff --git a/runelite-client/src/main/resources/net/runelite/client/plugins/interfacestyles/rs3/cross_sprites/4.png b/runelite-client/src/main/resources/net/runelite/client/plugins/interfacestyles/rs3/cross_sprites/4.png new file mode 100644 index 0000000000..695cc03088 Binary files /dev/null and b/runelite-client/src/main/resources/net/runelite/client/plugins/interfacestyles/rs3/cross_sprites/4.png differ diff --git a/runelite-client/src/main/resources/net/runelite/client/plugins/interfacestyles/rs3/cross_sprites/5.png b/runelite-client/src/main/resources/net/runelite/client/plugins/interfacestyles/rs3/cross_sprites/5.png new file mode 100644 index 0000000000..f69f4eb430 Binary files /dev/null and b/runelite-client/src/main/resources/net/runelite/client/plugins/interfacestyles/rs3/cross_sprites/5.png differ diff --git a/runelite-client/src/main/resources/net/runelite/client/plugins/interfacestyles/rs3/cross_sprites/6.png b/runelite-client/src/main/resources/net/runelite/client/plugins/interfacestyles/rs3/cross_sprites/6.png new file mode 100644 index 0000000000..0d156b6a17 Binary files /dev/null and b/runelite-client/src/main/resources/net/runelite/client/plugins/interfacestyles/rs3/cross_sprites/6.png differ diff --git a/runelite-client/src/main/resources/net/runelite/client/plugins/interfacestyles/rs3/cross_sprites/7.png b/runelite-client/src/main/resources/net/runelite/client/plugins/interfacestyles/rs3/cross_sprites/7.png new file mode 100644 index 0000000000..c17114ae82 Binary files /dev/null and b/runelite-client/src/main/resources/net/runelite/client/plugins/interfacestyles/rs3/cross_sprites/7.png differ diff --git a/runelite-client/src/test/java/net/runelite/client/plugins/chatcommands/ChatCommandsPluginTest.java b/runelite-client/src/test/java/net/runelite/client/plugins/chatcommands/ChatCommandsPluginTest.java index b6af13221d..de4e89299c 100644 --- a/runelite-client/src/test/java/net/runelite/client/plugins/chatcommands/ChatCommandsPluginTest.java +++ b/runelite-client/src/test/java/net/runelite/client/plugins/chatcommands/ChatCommandsPluginTest.java @@ -30,6 +30,7 @@ import com.google.inject.testing.fieldbinder.BoundFieldModule; import java.util.concurrent.ScheduledExecutorService; import javax.inject.Inject; import static net.runelite.api.ChatMessageType.GAMEMESSAGE; +import static net.runelite.api.ChatMessageType.TRADE; import net.runelite.api.Client; import net.runelite.api.events.ChatMessage; import net.runelite.client.config.ChatColorConfig; @@ -191,4 +192,38 @@ public class ChatCommandsPluginTest verify(configManager).setConfiguration(eq("personalbest.adam"), eq("kree'arra"), eq(181)); } -} \ No newline at end of file + + @Test + public void testDuelArenaWin() + { + when(client.getUsername()).thenReturn("Adam"); + + ChatMessage chatMessageEvent = new ChatMessage(null, TRADE, "", "You won! You have now won 27 duels.", null, 0); + chatCommandsPlugin.onChatMessage(chatMessageEvent); + + verify(configManager).setConfiguration("killcount.adam", "duel arena wins", 27); + verify(configManager).setConfiguration("killcount.adam", "duel arena win streak", 1); + } + + @Test + public void testDuelArenaWin2() + { + when(client.getUsername()).thenReturn("Adam"); + + ChatMessage chatMessageEvent = new ChatMessage(null, TRADE, "", "You were defeated! You have won 22 duels.", null, 0); + chatCommandsPlugin.onChatMessage(chatMessageEvent); + + verify(configManager).setConfiguration("killcount.adam", "duel arena wins", 22); + } + + @Test + public void testDuelArenaLose() + { + when(client.getUsername()).thenReturn("Adam"); + + ChatMessage chatMessageEvent = new ChatMessage(null, TRADE, "", "You have now lost 999 duels.", null, 0); + chatCommandsPlugin.onChatMessage(chatMessageEvent); + + verify(configManager).setConfiguration("killcount.adam", "duel arena losses", 999); + } +} diff --git a/runelite-client/src/test/java/net/runelite/client/plugins/cluescrolls/clues/hotcold/BeginnerHotColdLocationTest.java b/runelite-client/src/test/java/net/runelite/client/plugins/cluescrolls/clues/hotcold/BeginnerHotColdLocationTest.java new file mode 100644 index 0000000000..d67a00b989 --- /dev/null +++ b/runelite-client/src/test/java/net/runelite/client/plugins/cluescrolls/clues/hotcold/BeginnerHotColdLocationTest.java @@ -0,0 +1,50 @@ +/* + * 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.cluescrolls.clues.hotcold; + +import java.util.Arrays; +import java.util.Set; +import java.util.stream.Collectors; +import static org.junit.Assert.assertEquals; +import org.junit.Test; + +public class BeginnerHotColdLocationTest +{ + private static final Set BEGINNER_HOT_COLD_LOCATIONS = Arrays.stream(HotColdLocation.values()) + .filter(HotColdLocation::isBeginnerClue) + .collect(Collectors.toSet()); + private static final int EXPECTED_DIMENSION_SIZE = 7; + + @Test + public void beginnerHotColdLocationAreaTest() + { + + for (final HotColdLocation location : BEGINNER_HOT_COLD_LOCATIONS) + { + assertEquals(EXPECTED_DIMENSION_SIZE, location.getRect().height); + assertEquals(EXPECTED_DIMENSION_SIZE, location.getRect().width); + } + } +} diff --git a/runelite-client/src/test/java/net/runelite/client/plugins/cluescrolls/clues/hotcold/HotColdSolverTest.java b/runelite-client/src/test/java/net/runelite/client/plugins/cluescrolls/clues/hotcold/HotColdSolverTest.java new file mode 100644 index 0000000000..a5c4cc4e31 --- /dev/null +++ b/runelite-client/src/test/java/net/runelite/client/plugins/cluescrolls/clues/hotcold/HotColdSolverTest.java @@ -0,0 +1,259 @@ +/* + * 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.cluescrolls.clues.hotcold; + +import com.google.common.collect.Sets; +import java.awt.Rectangle; +import java.util.EnumSet; +import java.util.Set; +import java.util.stream.Collectors; +import static junit.framework.TestCase.assertTrue; +import net.runelite.api.coords.WorldPoint; +import static net.runelite.client.plugins.cluescrolls.clues.hotcold.HotColdSolver.isFirstPointCloser; +import static net.runelite.client.plugins.cluescrolls.clues.hotcold.HotColdSolver.isFirstPointCloserRect; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import org.junit.Test; + +public class HotColdSolverTest +{ + private static final String RESPONSE_TEXT_ICE_COLD_COLDER = "The device is ice cold, but colder than last time."; + private static final String RESPONSE_TEXT_VERY_COLD_WARMER = "The device is very cold, and warmer than last time."; + private static final String RESPONSE_TEXT_COLD = "The device is cold."; + private static final String RESPONSE_TEXT_COLD_COLDER = "The device is cold, but colder than last time."; + private static final String RESPONSE_TEXT_COLD_WARMER = "The device is cold, and warmer than last time."; + private static final String RESPONSE_TEXT_COLD_SAME_TEMP = "The device is cold, and the same temperature as last time."; + private static final String RESPONSE_TEXT_VERY_HOT = "The device is very hot."; + private static final String RESPONSE_TEXT_VERY_HOT_COLDER = "The device is very hot, but colder than last time."; + private static final String RESPONSE_TEXT_VERY_HOT_WARMER = "The device is very hot, and warmer than last time."; + private static final String RESPONSE_TEXT_VERY_HOT_SAME_TEMP = "The device is very hot, and the same temperature as last time."; + + @Test + public void testOneStepSolution() + { + final Set foundLocation = Sets.immutableEnumSet(HotColdLocation.KARAMJA_KHARAZI_NE); + + testSolver(createHotColdSolver(), new WorldPoint(2852, 2992, 0), RESPONSE_TEXT_VERY_HOT, foundLocation); + } + + @Test + public void testIgnoreStartingTemperatureDifference() + { + final WorldPoint testedPoint = new WorldPoint(2852, 2992, 0); + final Set foundLocations = Sets.immutableEnumSet(HotColdLocation.KARAMJA_KHARAZI_NE); + + testSolver(createHotColdSolver(), testedPoint, RESPONSE_TEXT_VERY_HOT, foundLocations); + testSolver(createHotColdSolver(), testedPoint, RESPONSE_TEXT_VERY_HOT_COLDER, foundLocations); + testSolver(createHotColdSolver(), testedPoint, RESPONSE_TEXT_VERY_HOT_WARMER, foundLocations); + testSolver(createHotColdSolver(), testedPoint, RESPONSE_TEXT_VERY_HOT_SAME_TEMP, foundLocations); + } + + @Test + public void testSameTempNoChanges() + { + final HotColdSolver solver = createHotColdSolver(); + final WorldPoint testedPoint = new WorldPoint(2851, 2955, 0); + final Set foundLocations = Sets.immutableEnumSet( + HotColdLocation.KARAMJA_KHARAZI_NE, + HotColdLocation.KARAMJA_KHARAZI_SW); + + testSolver(solver, testedPoint, RESPONSE_TEXT_VERY_HOT, foundLocations); + testSolver(solver, testedPoint, RESPONSE_TEXT_VERY_HOT_SAME_TEMP, foundLocations); + } + + @Test + public void testNoChangesAfterSolutionFound() + { + final HotColdSolver solver = createHotColdSolver(); + final Set intermediateFoundLocations = Sets.immutableEnumSet( + HotColdLocation.KARAMJA_KHARAZI_NE, + HotColdLocation.KARAMJA_KHARAZI_SW); + final Set finalLocation = Sets.immutableEnumSet(HotColdLocation.KARAMJA_KHARAZI_NE); + + testSolver(solver, new WorldPoint(2851, 2955, 0), RESPONSE_TEXT_VERY_HOT, intermediateFoundLocations); + testSolver(solver, new WorldPoint(2852, 2955, 0), RESPONSE_TEXT_VERY_HOT_WARMER, finalLocation); + testSolver(solver, new WorldPoint(2851, 2955, 0), RESPONSE_TEXT_VERY_HOT_COLDER, finalLocation); + testSolver(solver, new WorldPoint(2465, 3495, 0), RESPONSE_TEXT_ICE_COLD_COLDER, finalLocation); + testSolver(solver, new WorldPoint(3056, 3291, 0), RESPONSE_TEXT_VERY_COLD_WARMER, finalLocation); + testSolver(solver, new WorldPoint(2571, 2956, 0), RESPONSE_TEXT_VERY_COLD_WARMER, finalLocation); + } + + @Test + public void testNarrowToFindSolutions() + { + final HotColdSolver solver = createHotColdSolver(); + final Set firstLocationsSet = Sets.immutableEnumSet( + HotColdLocation.FELDIP_HILLS_GNOME_GLITER, + HotColdLocation.FELDIP_HILLS_RED_CHIN, + HotColdLocation.KARAMJA_KHARAZI_NE, + HotColdLocation.KARAMJA_CRASH_ISLAND); + final Set secondLocationsSet = firstLocationsSet.stream() + .filter(location -> location != HotColdLocation.FELDIP_HILLS_RED_CHIN) + .collect(Collectors.toSet()); + final Set thirdLocationSet = secondLocationsSet.stream() + .filter(location -> location != HotColdLocation.FELDIP_HILLS_GNOME_GLITER) + .collect(Collectors.toSet()); + final Set finalLocation = thirdLocationSet.stream() + .filter(location -> location != HotColdLocation.KARAMJA_CRASH_ISLAND) + .collect(Collectors.toSet()); + + testSolver(solver, new WorldPoint(2711, 2803, 0), RESPONSE_TEXT_COLD, firstLocationsSet); + testSolver(solver, new WorldPoint(2711, 2802, 0), RESPONSE_TEXT_COLD_SAME_TEMP, firstLocationsSet); + testSolver(solver, new WorldPoint(2716, 2802, 0), RESPONSE_TEXT_COLD_WARMER, secondLocationsSet); + testSolver(solver, new WorldPoint(2739, 2808, 0), RESPONSE_TEXT_COLD_WARMER, thirdLocationSet); + testSolver(solver, new WorldPoint(2810, 2757, 0), RESPONSE_TEXT_COLD_COLDER, finalLocation); + } + + @Test + public void testSomewhatDistantLocations() + { + // Activate device on Ape Atoll when solution point is HotColdLocation.KARAMJA_KHARAZI_NE + testSolver(createHotColdSolver(), new WorldPoint(2723, 2743, 0), RESPONSE_TEXT_COLD, + Sets.immutableEnumSet( + HotColdLocation.KARAMJA_KHARAZI_NE, + HotColdLocation.KARAMJA_KHARAZI_SW, + HotColdLocation.KARAMJA_CRASH_ISLAND, + HotColdLocation.FELDIP_HILLS_SW, + HotColdLocation.FELDIP_HILLS_RANTZ, + HotColdLocation.FELDIP_HILLS_RED_CHIN, + HotColdLocation.FELDIP_HILLS_SE)); + + // Activate device near fairy ring DKP when solution point is HotColdLocation.KARAMJA_KHARAZI_NE + testSolver(createHotColdSolver(), new WorldPoint(2900, 3111, 0), RESPONSE_TEXT_COLD, + Sets.immutableEnumSet( + HotColdLocation.KARAMJA_WEST_BRIMHAVEN, + HotColdLocation.KARAMJA_KHARAZI_NE, + HotColdLocation.ASGARNIA_COW, + HotColdLocation.ASGARNIA_CRAFT_GUILD, + HotColdLocation.KANDARIN_WITCHHAVEN, + HotColdLocation.MISTHALIN_DRAYNOR_BANK)); + + // Activate device on Mudskipper Point when solution point is HotColdLocation.KARAMJA_KHARAZI_NE + testSolver(createHotColdSolver(), new WorldPoint(2985, 3106, 0), RESPONSE_TEXT_COLD, + Sets.immutableEnumSet( + HotColdLocation.KARAMJA_BRIMHAVEN_FRUIT_TREE, + HotColdLocation.KARAMJA_KHARAZI_NE, + HotColdLocation.ASGARNIA_COW, + HotColdLocation.ASGARNIA_CRAFT_GUILD, + HotColdLocation.MISTHALIN_LUMBRIDGE_2, + HotColdLocation.DESERT_BEDABIN_CAMP)); + } + + @Test + public void testIsFirstPointCloserRect() + { + assertFalse(isFirstPointCloserRect(new WorldPoint(0, 0, 0), new WorldPoint(0, 0, 0), new Rectangle(0, 0, 1, 1))); + assertFalse(isFirstPointCloserRect(new WorldPoint(1, 0, 0), new WorldPoint(5, 0, 0), new Rectangle(2, 1, 5, 5))); + assertFalse(isFirstPointCloserRect(new WorldPoint(1, 0, 0), new WorldPoint(0, 0, 0), new Rectangle(2, 0, 1, 2))); + assertFalse(isFirstPointCloserRect(new WorldPoint(0, 0, 0), new WorldPoint(1, 1, 1), new Rectangle(2, 2, 2, 2))); + assertFalse(isFirstPointCloserRect(new WorldPoint(0, 0, 0), new WorldPoint(4, 4, 4), new Rectangle(1, 1, 2, 2))); + assertFalse(isFirstPointCloserRect(new WorldPoint(3, 2, 0), new WorldPoint(1, 5, 0), new Rectangle(0, 0, 4, 4))); + + assertTrue(isFirstPointCloserRect(new WorldPoint(1, 1, 0), new WorldPoint(0, 1, 0), new Rectangle(2, 0, 3, 2))); + assertTrue(isFirstPointCloserRect(new WorldPoint(4, 4, 0), new WorldPoint(1, 1, 0), new Rectangle(3, 3, 2, 2))); + assertTrue(isFirstPointCloserRect(new WorldPoint(3, 2, 0), new WorldPoint(7, 0, 0), new Rectangle(1, 3, 4, 2))); + + } + + @Test + public void testIsFirstPointCloser() + { + assertFalse(isFirstPointCloser(new WorldPoint(0, 0, 0), new WorldPoint(0, 0, 0), new WorldPoint(0, 0, 0))); + assertFalse(isFirstPointCloser(new WorldPoint(0, 0, 0), new WorldPoint(0, 0, 1), new WorldPoint(0, 0, 0))); + assertFalse(isFirstPointCloser(new WorldPoint(1, 0, 0), new WorldPoint(0, 0, 0), new WorldPoint(1, 1, 0))); + assertFalse(isFirstPointCloser(new WorldPoint(2, 2, 0), new WorldPoint(0, 0, 0), new WorldPoint(1, 1, 0))); + + assertTrue(isFirstPointCloser(new WorldPoint(1, 0, 0), new WorldPoint(0, 0, 0), new WorldPoint(2, 0, 0))); + assertTrue(isFirstPointCloser(new WorldPoint(1, 1, 0), new WorldPoint(1, 0, 0), new WorldPoint(2, 2, 0))); + assertTrue(isFirstPointCloser(new WorldPoint(1, 1, 1), new WorldPoint(0, 1, 0), new WorldPoint(1, 1, 0))); + } + + /** + * Tests a hot-cold solver by signalling a test point, temperature, and temperature change to it and asserting the + * resulting possible location set is equal to that of a given set of expected locations. + * + * @param solver The hot-cold solver to signal to. + *
+ * Note: This will mutate the passed solver, which is helpful for testing + * multiple sequential steps. + * @param testPoint The {@link WorldPoint} where the signal occurs. + * @param deviceResponse The string containing the temperature and temperature change which is + * given when the hot-cold checking device is activated. + * @param expectedRemainingPossibleLocations A {@link Set} of {@link HotColdLocation}s which is expected to be + * given by {@link HotColdSolver#getPossibleLocations()} after it receives + * the signal formed by the other given arguments. + */ + private static void testSolver(final HotColdSolver solver, final WorldPoint testPoint, final String deviceResponse, final Set expectedRemainingPossibleLocations) + { + final HotColdTemperature temperature = HotColdTemperature.getFromTemperatureSet(HotColdTemperature.MASTER_HOT_COLD_TEMPERATURES, deviceResponse); + final HotColdTemperatureChange temperatureChange = HotColdTemperatureChange.of(deviceResponse); + + assertNotNull(temperature); + assertEquals(expectedRemainingPossibleLocations, solver.signal(testPoint, temperature, temperatureChange)); + } + + /** + * @return A hot-cold solver with a starting set of master hot-cold locations nearby the KARAMJA_KHARAZI_NE + * location. {@link HotColdLocation#values()} is not used as it may change with future game updates, and + * such changes would break this test suite. + */ + private static HotColdSolver createHotColdSolver() + { + final Set hotColdLocations = EnumSet.of( + HotColdLocation.KARAMJA_KHARAZI_NE, + HotColdLocation.KARAMJA_KHARAZI_SW, + HotColdLocation.KARAMJA_GLIDER, + HotColdLocation.KARAMJA_MUSA_POINT, + HotColdLocation.KARAMJA_BRIMHAVEN_FRUIT_TREE, + HotColdLocation.KARAMJA_WEST_BRIMHAVEN, + HotColdLocation.KARAMJA_CRASH_ISLAND, + HotColdLocation.DESERT_BEDABIN_CAMP, + HotColdLocation.DESERT_MENAPHOS_GATE, + HotColdLocation.DESERT_POLLNIVNEACH, + HotColdLocation.DESERT_SHANTY, + HotColdLocation.MISTHALIN_LUMBRIDGE, + HotColdLocation.MISTHALIN_LUMBRIDGE_2, + HotColdLocation.MISTHALIN_DRAYNOR_BANK, + HotColdLocation.ASGARNIA_COW, + HotColdLocation.ASGARNIA_PARTY_ROOM, + HotColdLocation.ASGARNIA_CRAFT_GUILD, + HotColdLocation.ASGARNIA_RIMMINGTON, + HotColdLocation.ASGARNIA_MUDSKIPPER, + HotColdLocation.KANDARIN_WITCHHAVEN, + HotColdLocation.KANDARIN_NECRO_TOWER, + HotColdLocation.KANDARIN_FIGHT_ARENA, + HotColdLocation.KANDARIN_TREE_GNOME_VILLAGE, + HotColdLocation.FELDIP_HILLS_GNOME_GLITER, + HotColdLocation.FELDIP_HILLS_JIGGIG, + HotColdLocation.FELDIP_HILLS_RANTZ, + HotColdLocation.FELDIP_HILLS_RED_CHIN, + HotColdLocation.FELDIP_HILLS_SE, + HotColdLocation.FELDIP_HILLS_SOUTH, + HotColdLocation.FELDIP_HILLS_SW + ); + return new HotColdSolver(hotColdLocations); + } +} diff --git a/runelite-client/src/test/java/net/runelite/client/plugins/cluescrolls/clues/hotcold/HotColdTemperatureChangeTest.java b/runelite-client/src/test/java/net/runelite/client/plugins/cluescrolls/clues/hotcold/HotColdTemperatureChangeTest.java new file mode 100644 index 0000000000..9b7cdcaf3c --- /dev/null +++ b/runelite-client/src/test/java/net/runelite/client/plugins/cluescrolls/clues/hotcold/HotColdTemperatureChangeTest.java @@ -0,0 +1,68 @@ +/* + * 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.cluescrolls.clues.hotcold; + +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import org.junit.Test; + +public class HotColdTemperatureChangeTest +{ + private static final String[] VALID_MESSAGES = { + "The device is warm, and warmer than last time.", + "The device is cold, but colder than last time.", + "The device is very hot, and the same temperature as last time.", + }; + private static final String[] INVALID_MESSAGES = { + "The device is cold.", + "The device is ice cold.", + "The device is very cold.", + "The device is hot.", + "The device is incredibly hot.", + "The device is an octopus, and is wetter than last time", + "foobar", + "a q p w", + "My feet are cold, I should put them in some lukewarm water, or run hot water over them.", + "and warmer than and colder than and the same temperature", + }; + + @Test + public void testValidTemperatureChangeMessages() + { + for (final String message : VALID_MESSAGES) + { + assertNotNull(message, HotColdTemperatureChange.of(message)); + } + } + + @Test + public void testInvalidTemperatureChangeMessages() + { + for (final String message : INVALID_MESSAGES) + { + assertNull(message, HotColdTemperatureChange.of(message)); + } + } +} diff --git a/runelite-client/src/test/java/net/runelite/client/plugins/cluescrolls/clues/hotcold/HotColdTemperatureTest.java b/runelite-client/src/test/java/net/runelite/client/plugins/cluescrolls/clues/hotcold/HotColdTemperatureTest.java new file mode 100644 index 0000000000..e9711dc433 --- /dev/null +++ b/runelite-client/src/test/java/net/runelite/client/plugins/cluescrolls/clues/hotcold/HotColdTemperatureTest.java @@ -0,0 +1,77 @@ +/* + * 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.cluescrolls.clues.hotcold; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import org.junit.Test; + +public class HotColdTemperatureTest +{ + private static final String[] VALID_MESSAGES = { + "The device is warm, and warmer than last time.", + "The device is visibly shaking and burns to the touch. This must be the spot.", + "The device is cold.", + "The device is ice cold.", + "The device is very cold.", + "The device is hot.", + "The device is incredibly hot.", + }; + private static final String[] INVALID_MESSAGES = { + "The device is an octopus, and is wetter than last time.", + "foobar", + "a q p w", + "My feet are cold, I should put them in some lukewarm water, or run hot water over them.", + }; + + @Test + public void testValidTemperatureMessages() + { + for (final String message : VALID_MESSAGES) + { + assertNotNull(message, HotColdTemperature.getFromTemperatureSet(HotColdTemperature.BEGINNER_HOT_COLD_TEMPERATURES, message)); + assertNotNull(message, HotColdTemperature.getFromTemperatureSet(HotColdTemperature.MASTER_HOT_COLD_TEMPERATURES, message)); + } + } + + @Test + public void testInvalidTemperatureMessages() + { + for (final String message : INVALID_MESSAGES) + { + assertNull(message, HotColdTemperature.getFromTemperatureSet(HotColdTemperature.BEGINNER_HOT_COLD_TEMPERATURES, message)); + assertNull(message, HotColdTemperature.getFromTemperatureSet(HotColdTemperature.MASTER_HOT_COLD_TEMPERATURES, message)); + } + } + + @Test + public void testAmbiguousTemperatureMessages() + { + assertEquals(HotColdTemperature.ICE_COLD, HotColdTemperature.getFromTemperatureSet(HotColdTemperature.MASTER_HOT_COLD_TEMPERATURES, "The device is ice cold.")); + assertEquals(HotColdTemperature.VERY_COLD, HotColdTemperature.getFromTemperatureSet(HotColdTemperature.MASTER_HOT_COLD_TEMPERATURES, "The device is very cold.")); + assertEquals(HotColdTemperature.VERY_HOT, HotColdTemperature.getFromTemperatureSet(HotColdTemperature.MASTER_HOT_COLD_TEMPERATURES, "The device is very hot.")); + } +} diff --git a/runelite-client/src/test/java/net/runelite/client/plugins/cluescrolls/clues/hotcold/MasterHotColdLocationTest.java b/runelite-client/src/test/java/net/runelite/client/plugins/cluescrolls/clues/hotcold/MasterHotColdLocationTest.java new file mode 100644 index 0000000000..abda26549d --- /dev/null +++ b/runelite-client/src/test/java/net/runelite/client/plugins/cluescrolls/clues/hotcold/MasterHotColdLocationTest.java @@ -0,0 +1,49 @@ +/* + * 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.cluescrolls.clues.hotcold; + +import java.util.Arrays; +import java.util.Set; +import java.util.stream.Collectors; +import static org.junit.Assert.assertEquals; +import org.junit.Test; + +public class MasterHotColdLocationTest +{ + private static final Set MASTER_HOT_COLD_LOCATIONS = Arrays.stream(HotColdLocation.values()) + .filter(l -> !l.isBeginnerClue()) + .collect(Collectors.toSet()); + private static final int EXPECTED_DIMENSION_SIZE = 9; + + @Test + public void beginnerHotColdLocationAreaTest() + { + for (final HotColdLocation location : MASTER_HOT_COLD_LOCATIONS) + { + assertEquals(EXPECTED_DIMENSION_SIZE, location.getRect().height); + assertEquals(EXPECTED_DIMENSION_SIZE, location.getRect().width); + } + } +} diff --git a/runelite-mixins/src/main/java/net/runelite/mixins/RSNPCMixin.java b/runelite-mixins/src/main/java/net/runelite/mixins/RSNPCMixin.java index ea0f74f93c..e33afa700b 100644 --- a/runelite-mixins/src/main/java/net/runelite/mixins/RSNPCMixin.java +++ b/runelite-mixins/src/main/java/net/runelite/mixins/RSNPCMixin.java @@ -24,12 +24,13 @@ */ package net.runelite.mixins; +import java.awt.Polygon; import net.runelite.api.AnimationID; import net.runelite.api.NPCDefinition; import net.runelite.api.Perspective; import net.runelite.api.coords.LocalPoint; +import net.runelite.api.events.NpcDefinitionChanged; import net.runelite.api.events.NpcDespawned; -import java.awt.Polygon; import net.runelite.api.mixins.Copy; import net.runelite.api.mixins.FieldHook; import net.runelite.api.mixins.Inject; @@ -111,6 +112,10 @@ public abstract class RSNPCMixin implements RSNPC { client.getCallbacks().post(new NpcDespawned(this)); } + else if (this.getId() != -1) + { + client.getCallbacks().post(new NpcDefinitionChanged(this)); + } } @Copy("getModel") diff --git a/runescape-api/src/main/java/net/runelite/rs/api/RSClient.java b/runescape-api/src/main/java/net/runelite/rs/api/RSClient.java index d33785c9e7..17f88f3eb3 100644 --- a/runescape-api/src/main/java/net/runelite/rs/api/RSClient.java +++ b/runescape-api/src/main/java/net/runelite/rs/api/RSClient.java @@ -1034,4 +1034,8 @@ public interface RSClient extends RSGameShell, Client @Import("viewportWalking") void setViewportWalking(boolean viewportWalking); + + @Import("crossSprites") + @Override + RSSprite[] getCrossSprites(); }