Merge branch 'master' into loot-tracker-reset

This commit is contained in:
PKLite
2019-07-02 02:00:39 -04:00
133 changed files with 4715 additions and 2067 deletions

View File

@@ -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; x += this.offsetX;
y += this.offsetY; y += this.offsetY;

View File

@@ -64,7 +64,7 @@ public class AreaDumper
for (AreaDefinition area : areaManager.getAreas()) 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; ++count;
} }
} }

View File

@@ -80,7 +80,7 @@ public class EnumDumperTest
if (def != null) 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; ++count;
} }
} }

View File

@@ -101,7 +101,7 @@ public class FrameDumper
frames.add(frame); 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; ++count;
} }
} }

View File

@@ -74,7 +74,7 @@ public class FramemapDumper
FramemapLoader loader = new FramemapLoader(); FramemapLoader loader = new FramemapLoader();
FramemapDefinition framemap = loader.load(0, contents); 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; ++count;
} }
} }

View File

@@ -77,7 +77,7 @@ public class InventoryDumper
InventoryLoader loader = new InventoryLoader(); InventoryLoader loader = new InventoryLoader();
InventoryDefinition inv = loader.load(file.getFileId(), file.getContents()); 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; ++count;
} }
} }

View File

@@ -78,7 +78,7 @@ public class KitDumperTest
KitDefinition def = loader.load(file.getFileId(), b); 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; ++count;
} }
} }

View File

@@ -77,7 +77,7 @@ public class OverlayDumper
OverlayLoader loader = new OverlayLoader(); OverlayLoader loader = new OverlayLoader();
OverlayDefinition overlay = loader.load(file.getFileId(), file.getContents()); 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; ++count;
} }
} }

View File

@@ -77,7 +77,7 @@ public class SequenceDumper
SequenceLoader loader = new SequenceLoader(); SequenceLoader loader = new SequenceLoader();
SequenceDefinition seq = loader.load(file.getFileId(), file.getContents()); 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; ++count;
} }
} }

View File

@@ -71,7 +71,7 @@ public class SoundEffectsDumperTest
SoundEffectLoader soundEffectLoader = new SoundEffectLoader(); SoundEffectLoader soundEffectLoader = new SoundEffectLoader();
SoundEffectDefinition soundEffect = soundEffectLoader.load(contents); 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; ++count;
} }
} }

View File

@@ -64,7 +64,7 @@ public class StructManagerTest
{ {
StructDefinition def = struct.getValue(); 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; ++count;
} }
} }

View File

@@ -64,7 +64,7 @@ public class TextureDumper
for (TextureDefinition texture : tm.getTextures()) 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; ++count;
} }
} }

View File

@@ -77,7 +77,7 @@ public class UnderlayDumper
UnderlayLoader loader = new UnderlayLoader(); UnderlayLoader loader = new UnderlayLoader();
UnderlayDefinition underlay = loader.load(file.getFileId(), file.getContents()); 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; ++count;
} }
} }

View File

@@ -77,7 +77,7 @@ public class VarbitDumper
VarbitLoader loader = new VarbitLoader(); VarbitLoader loader = new VarbitLoader();
VarbitDefinition varbit = loader.load(file.getFileId(), file.getContents()); 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; ++count;
} }
} }

View File

@@ -77,7 +77,7 @@ public class WorldMapDumperTest
WorldMapLoader loader = new WorldMapLoader(); WorldMapLoader loader = new WorldMapLoader();
WorldMapDefinition def = loader.load(file.getContents(), file.getFileId()); 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; ++count;
} }
} }

View File

@@ -39,8 +39,8 @@ import okhttp3.Response;
public class ChatClient public class ChatClient
{ {
private static final Predicate<String> LAYOUT_VALIDATOR = Pattern private static final Predicate<String> LAYOUT_VALIDATOR = Pattern
.compile("\\[[A-Z]+]:(\\s*\\w+\\s*(\\([A-Za-z]+\\))?,?)+") .compile("\\[[A-Z]+]:(\\s*\\w+\\s*(\\([A-Za-z]+\\))?,?)+")
.asPredicate(); .asPredicate();
public boolean submitKc(String username, String boss, int kc) throws IOException public boolean submitKc(String username, String boss, int kc) throws IOException
{ {
@@ -237,7 +237,7 @@ public class ChatClient
.url(url) .url(url)
.build(); .build();
try (Response response = RuneLiteAPI.RLP_CLIENT.newCall(request).execute()) try (Response response = RuneLiteAPI.CLIENT.newCall(request).execute())
{ {
return response.isSuccessful(); return response.isSuccessful();
} }
@@ -273,16 +273,16 @@ public class ChatClient
} }
HttpUrl url = RuneLiteAPI.getPlusApiBase().newBuilder() HttpUrl url = RuneLiteAPI.getPlusApiBase().newBuilder()
.addPathSegment("chat") .addPathSegment("chat")
.addPathSegment("layout") .addPathSegment("layout")
.addQueryParameter("name", username) .addQueryParameter("name", username)
.addQueryParameter("layout", layout) .addQueryParameter("layout", layout)
.build(); .build();
Request request = new Request.Builder() Request request = new Request.Builder()
.post(RequestBody.create(null, new byte[0])) .post(RequestBody.create(null, new byte[0]))
.url(url) .url(url)
.build(); .build();
try (Response response = RuneLiteAPI.RLP_CLIENT.newCall(request).execute()) 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 public String getLayout(String username) throws IOException
{ {
HttpUrl url = RuneLiteAPI.getPlusApiBase().newBuilder() HttpUrl url = RuneLiteAPI.getPlusApiBase().newBuilder()
.addPathSegment("chat") .addPathSegment("chat")
.addPathSegment("layout") .addPathSegment("layout")
.addQueryParameter("name", username) .addQueryParameter("name", username)
.build(); .build();
Request request = new Request.Builder() Request request = new Request.Builder()
.url(url) .url(url)
.build(); .build();
try (Response response = RuneLiteAPI.RLP_CLIENT.newCall(request).execute()) 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 public House[] getHosts(int world, String location) throws IOException
{ {
HttpUrl url = RuneLiteAPI.getPlusApiBase().newBuilder() HttpUrl url = RuneLiteAPI.getPlusApiBase().newBuilder()
.addPathSegment("chat") .addPathSegment("chat")
.addPathSegment("hosts") .addPathSegment("hosts")
.addQueryParameter("world", Integer.toString(world)) .addQueryParameter("world", Integer.toString(world))
.addQueryParameter("location", location) .addQueryParameter("location", location)
.build(); .build();
Request request = new Request.Builder() Request request = new Request.Builder()
.url(url) .url(url)
.build(); .build();
try (Response response = RuneLiteAPI.RLP_CLIENT.newCall(request).execute()) try (Response response = RuneLiteAPI.RLP_CLIENT.newCall(request).execute())
{ {
@@ -347,6 +370,35 @@ public class ChatClient
InputStream in = response.body().byteStream(); InputStream in = response.body().byteStream();
return RuneLiteAPI.GSON.fromJson(new InputStreamReader(in), House[].class); 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) catch (JsonParseException ex)
{ {
@@ -357,24 +409,24 @@ public class ChatClient
public boolean submitHost(int world, String location, House house) throws IOException public boolean submitHost(int world, String location, House house) throws IOException
{ {
HttpUrl url = RuneLiteAPI.getPlusApiBase().newBuilder() HttpUrl url = RuneLiteAPI.getPlusApiBase().newBuilder()
.addPathSegment("chat") .addPathSegment("chat")
.addPathSegment("hosts") .addPathSegment("hosts")
.addQueryParameter("world", Integer.toString(world)) .addQueryParameter("world", Integer.toString(world))
.addQueryParameter("location", location) .addQueryParameter("location", location)
.addQueryParameter("owner", house.getOwner()) .addQueryParameter("owner", house.getOwner())
.addQueryParameter("guildedAltar", Boolean.toString(house.isGuildedAltarPresent())) .addQueryParameter("guildedAltar", Boolean.toString(house.isGuildedAltarPresent()))
.addQueryParameter("occultAltar", Boolean.toString(house.isOccultAltarPresent())) .addQueryParameter("occultAltar", Boolean.toString(house.isOccultAltarPresent()))
.addQueryParameter("spiritTree", Boolean.toString(house.isSpiritTreePresent())) .addQueryParameter("spiritTree", Boolean.toString(house.isSpiritTreePresent()))
.addQueryParameter("fairyRing", Boolean.toString(house.isFairyRingPresent())) .addQueryParameter("fairyRing", Boolean.toString(house.isFairyRingPresent()))
.addQueryParameter("wildernessObelisk", Boolean.toString(house.isWildernessObeliskPresent())) .addQueryParameter("wildernessObelisk", Boolean.toString(house.isWildernessObeliskPresent()))
.addQueryParameter("repairStand", Boolean.toString(house.isRepairStandPresent())) .addQueryParameter("repairStand", Boolean.toString(house.isRepairStandPresent()))
.addQueryParameter("combatDummy", Boolean.toString(house.isCombatDummyPresent())) .addQueryParameter("combatDummy", Boolean.toString(house.isCombatDummyPresent()))
.build(); .build();
Request request = new Request.Builder() Request request = new Request.Builder()
.post(RequestBody.create(null, new byte[0])) .post(RequestBody.create(null, new byte[0]))
.url(url) .url(url)
.build(); .build();
try (Response response = RuneLiteAPI.RLP_CLIENT.newCall(request).execute()) 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 public boolean removeHost(int world, String location, House house) throws IOException
{ {
HttpUrl url = RuneLiteAPI.getPlusApiBase().newBuilder() HttpUrl url = RuneLiteAPI.getPlusApiBase().newBuilder()
.addPathSegment("chat") .addPathSegment("chat")
.addPathSegment("hosts") .addPathSegment("hosts")
.addQueryParameter("world", Integer.toString(world)) .addQueryParameter("world", Integer.toString(world))
.addQueryParameter("location", location) .addQueryParameter("location", location)
.addQueryParameter("owner", house.getOwner()) .addQueryParameter("owner", house.getOwner())
.addQueryParameter("guildedAltar", Boolean.toString(house.isGuildedAltarPresent())) .addQueryParameter("guildedAltar", Boolean.toString(house.isGuildedAltarPresent()))
.addQueryParameter("occultAltar", Boolean.toString(house.isOccultAltarPresent())) .addQueryParameter("occultAltar", Boolean.toString(house.isOccultAltarPresent()))
.addQueryParameter("spiritTree", Boolean.toString(house.isSpiritTreePresent())) .addQueryParameter("spiritTree", Boolean.toString(house.isSpiritTreePresent()))
.addQueryParameter("fairyRing", Boolean.toString(house.isFairyRingPresent())) .addQueryParameter("fairyRing", Boolean.toString(house.isFairyRingPresent()))
.addQueryParameter("wildernessObelisk", Boolean.toString(house.isWildernessObeliskPresent())) .addQueryParameter("wildernessObelisk", Boolean.toString(house.isWildernessObeliskPresent()))
.addQueryParameter("repairStand", Boolean.toString(house.isRepairStandPresent())) .addQueryParameter("repairStand", Boolean.toString(house.isRepairStandPresent()))
.addQueryParameter("combatDummy", Boolean.toString(house.isCombatDummyPresent())) .addQueryParameter("combatDummy", Boolean.toString(house.isCombatDummyPresent()))
.addQueryParameter("remove", Boolean.toString(true)) .addQueryParameter("remove", Boolean.toString(true))
.build(); .build();
Request request = new Request.Builder() Request request = new Request.Builder()
.post(RequestBody.create(null, new byte[0])) .post(RequestBody.create(null, new byte[0]))
.url(url) .url(url)
.build(); .build();
try (Response response = RuneLiteAPI.RLP_CLIENT.newCall(request).execute()) try (Response response = RuneLiteAPI.RLP_CLIENT.newCall(request).execute())
{ {
return response.isSuccessful(); return response.isSuccessful();
} }
} }
} }

View File

@@ -0,0 +1,36 @@
/*
* Copyright (c) 2019, Adam <Adam@sigterm.info>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package net.runelite.http.api.chat;
import lombok.Data;
@Data
public class Duels
{
private int wins;
private int losses;
private int winningStreak;
private int losingStreak;
}

View File

@@ -1,92 +0,0 @@
/*
* Copyright (c) 2018, Adam <Adam@sigterm.info>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package net.runelite.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<AnimationKey> 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;
}
}

View File

@@ -100,4 +100,4 @@ public class ChatController
{ {
return chatService.getHosts(world, location); return chatService.getHosts(world, location);
} }
} }

View File

@@ -117,4 +117,4 @@ public class ChatService
jedis.lrem(key, 0, json); jedis.lrem(key, 0, json);
} }
} }
} }

View File

@@ -22,7 +22,7 @@
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * 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. * 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 public static final int BLOCK_UNARMED = 424; // Same Animation as failed pickpocked
// NPC animations // 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_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 HELLHOUND_DEFENCE = 6566;
public static final int VORKATH_WAKE_UP = 7950; public static final int VORKATH_WAKE_UP = 7950;
public static final int VORKATH_DEATH = 7949; public static final int VORKATH_DEATH = 7949;

View File

@@ -1627,6 +1627,11 @@ public interface Client extends GameShell
*/ */
NodeCache getItemDefinitionCache(); NodeCache getItemDefinitionCache();
/**
* Returns the array of cross sprites that appear and animate when left-clicking
*/
Sprite[] getCrossSprites();
EnumDefinition getEnum(int id); EnumDefinition getEnum(int id);
void draw2010Menu(); void draw2010Menu();

View File

@@ -51,9 +51,10 @@ public class GraphicID
public static final int IMBUED_HEART = 1316; public static final int IMBUED_HEART = 1316;
public static final int FLYING_FISH = 1387; public static final int FLYING_FISH = 1387;
public static final int OLM_BURN = 1351; 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_TELEPORT = 1359;
public static final int OLM_HEAL = 1363; public static final int OLM_HEAL = 1363;
public static final int OLM_CRYSTAL = 1447; public static final int OLM_CRYSTAL = 1447;
public static final int XERIC_TELEPORT = 1612; public static final int XERIC_TELEPORT = 1612;
public static final int HYDRA_LIGHTNING = 1666; public static final int HYDRA_LIGHTNING = 1666;
} }

View File

@@ -184,6 +184,25 @@ public class WorldArea
return isInMeleeDistance(new WorldArea(other, 1, 1)); 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. * Checks whether this area intersects with another.
* *

View File

@@ -1,6 +1,5 @@
/* /*
* Copyright (c) 2018, Woox <https://github.com/wooxsolo> * Copyright (c) 2018, Woox <https://github.com/wooxsolo>
* Copyright (c) 2019, Ganom <https://github.com/Ganom>
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * 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 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * 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.Value;
import lombok.Setter;
import net.runelite.api.Actor;
import net.runelite.api.NPC; 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 * The NPC of which the composition changed.
private NPC npc; */
private final 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();
}
}
} }

View File

@@ -284,6 +284,11 @@
<artifactId>asm-all</artifactId> <artifactId>asm-all</artifactId>
<version>6.0_BETA</version> <version>6.0_BETA</version>
</dependency> </dependency>
<dependency>
<groupId>org.json</groupId>
<artifactId>json</artifactId>
<version>20180813</version>
</dependency>
</dependencies> </dependencies>
<build> <build>

View File

@@ -451,7 +451,7 @@ public interface ChatColorConfig extends Config
) )
default Color transparentExamineHighlight() default Color transparentExamineHighlight()
{ {
return Color.decode("#0000FF"); return Color.GREEN;
} }
@ConfigItem( @ConfigItem(

View File

@@ -28,6 +28,8 @@ import java.lang.invoke.MethodHandles;
import java.lang.reflect.Constructor; import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationHandler; import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects; import java.util.Objects;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
@@ -36,26 +38,49 @@ class ConfigInvocationHandler implements InvocationHandler
{ {
private final ConfigManager manager; private final ConfigManager manager;
// Caches for annotation values
private static final Map<Class<?>, String> groupValueCache = new HashMap<>();
private static final Map<Method, String> methodKeyNameCache = new HashMap<>();
public ConfigInvocationHandler(ConfigManager manager) public ConfigInvocationHandler(ConfigManager manager)
{ {
this.manager = 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 @Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable public Object invoke(Object proxy, Method method, Object[] args) throws Throwable
{ {
Class<?> iface = proxy.getClass().getInterfaces()[0]; String itemKeyName, groupValue;
try
ConfigGroup group = iface.getAnnotation(ConfigGroup.class); {
ConfigItem item = method.getAnnotation(ConfigItem.class); groupValue = groupValueCache.computeIfAbsent(proxy.getClass(), ConfigInvocationHandler::groupValueFromProxy);
}
if (group == null) catch (NullPointerException e)
{ {
log.warn("Configuration proxy class {} has no @ConfigGroup!", proxy.getClass()); log.warn("Configuration proxy class {} has no @ConfigGroup!", proxy.getClass());
return null; return null;
} }
if (item == null) try
{
itemKeyName = methodKeyNameCache.computeIfAbsent(method, ConfigInvocationHandler::keyNameFromMethod);
}
catch (NullPointerException e)
{ {
log.warn("Configuration method {} has no @ConfigItem!", method); log.warn("Configuration method {} has no @ConfigItem!", method);
return null; return null;
@@ -64,38 +89,43 @@ class ConfigInvocationHandler implements InvocationHandler
if (args == null) if (args == null)
{ {
// Getting configuration item // Getting configuration item
String value = manager.getConfiguration(group.value(), item.keyName()); return manager.getConfigObjectFromCacheOrElse(groupValue, itemKeyName, (value) ->
if (value == null)
{ {
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;
}
} }
catch (Throwable throwable)
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())
{ {
Object defaultValue = callDefaultMethod(proxy, method, null); log.error("Unable to resolve configuration value {}.{}", groupValue, itemKeyName, throwable);
return null;
manager.setConfiguration(group.value(), item.keyName(), defaultValue);
return defaultValue;
} }
return null; });
}
} }
else else
{ {
@@ -103,13 +133,13 @@ class ConfigInvocationHandler implements InvocationHandler
if (args.length != 1) 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]; Object newValue = args[0];
Class<?> type = method.getParameterTypes()[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)) if (Objects.equals(oldValue, newValue))
{ {
@@ -124,19 +154,19 @@ class ConfigInvocationHandler implements InvocationHandler
if (Objects.equals(newValue, defaultValue)) if (Objects.equals(newValue, defaultValue))
{ {
// Just unset if it goes back to the default // Just unset if it goes back to the default
manager.unsetConfiguration(group.value(), item.keyName()); manager.unsetConfiguration(groupValue, itemKeyName);
return null; return null;
} }
} }
if (newValue == null) if (newValue == null)
{ {
manager.unsetConfiguration(group.value(), item.keyName()); manager.unsetConfiguration(groupValue, itemKeyName);
} }
else else
{ {
String newValueStr = ConfigManager.objectToString(newValue); String newValueStr = ConfigManager.objectToString(newValue);
manager.setConfiguration(group.value(), item.keyName(), newValueStr); manager.setConfiguration(groupValue, itemKeyName, newValueStr);
} }
return null; return null;
} }

View File

@@ -55,6 +55,7 @@ import java.util.Objects;
import java.util.Properties; import java.util.Properties;
import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import java.util.function.Function;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import javax.inject.Inject; import javax.inject.Inject;
import javax.inject.Singleton; import javax.inject.Singleton;
@@ -81,6 +82,7 @@ public class ConfigManager
private final ScheduledExecutorService executor; private final ScheduledExecutorService executor;
private final ConfigInvocationHandler handler = new ConfigInvocationHandler(this); private final ConfigInvocationHandler handler = new ConfigInvocationHandler(this);
private final Properties properties = new Properties(); private final Properties properties = new Properties();
private final Map<String, Object> configObjectCache = new HashMap<>();
private final Map<String, String> pendingChanges = new HashMap<>(); private final Map<String, String> pendingChanges = new HashMap<>();
@Inject @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<String, Object> 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> T getConfig(Class<T> clazz) public <T> T getConfig(Class<T> clazz)
{ {
if (!Modifier.isPublic(clazz.getModifiers())) if (!Modifier.isPublic(clazz.getModifiers()))
@@ -245,6 +261,11 @@ public class ConfigManager
return properties.getProperty(groupName + "." + key); return properties.getProperty(groupName + "." + key);
} }
public String getConfiguration(String propertyKey)
{
return properties.getProperty(propertyKey);
}
public <T> T getConfiguration(String groupName, String key, Class<T> clazz) public <T> T getConfiguration(String groupName, String key, Class<T> clazz)
{ {
String value = getConfiguration(groupName, key); String value = getConfiguration(groupName, key);
@@ -284,7 +305,7 @@ public class ConfigManager
configChanged.setOldValue(oldValue); configChanged.setOldValue(oldValue);
configChanged.setNewValue(value); configChanged.setNewValue(value);
eventBus.post(configChanged); postConfigChanged(configChanged);
} }
public void setConfiguration(String groupName, String key, Object value) public void setConfiguration(String groupName, String key, Object value)

View File

@@ -288,7 +288,7 @@ public enum AgilityShortcut
GOBLIN_VILLAGE_WALL(14, "Wall", new WorldPoint(2925, 3523, 0), TIGHTGAP), 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), CORSAIR_COVE_DUNGEON_PILLAR(15, "Pillar Jump", new WorldPoint(1980, 8996, 0), PILLAR_31809),
EDGEVILLE_DUNGEON_MONKEYBARS(15, "Monkey Bars", null, MONKEYBARS_23566), 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_UNDERWALL_TUNNEL(16, "Underwall Tunnel", new WorldPoint(2574, 3109, 0), HOLE_16520, CASTLE_WALL),
YANILLE_WATCHTOWER_TRELLIS(18, "Trellis", null, TRELLIS_20056), YANILLE_WATCHTOWER_TRELLIS(18, "Trellis", null, TRELLIS_20056),
COAL_TRUCKS_LOG_BALANCE(20, "Log Balance", new WorldPoint(2598, 3475, 0), LOG_BALANCE_23274), COAL_TRUCKS_LOG_BALANCE(20, "Log Balance", new WorldPoint(2598, 3475, 0), LOG_BALANCE_23274),

View File

@@ -37,33 +37,66 @@ import net.runelite.client.config.ModifierlessKeybind;
@ConfigGroup("antiDrag") @ConfigGroup("antiDrag")
public interface AntiDragConfig extends Config public interface AntiDragConfig extends Config
{ {
@ConfigItem( @ConfigItem(
keyName = "dragDelay", position = 0,
name = "Drag Delay", keyName = "alwaysOn",
description = "Configures the inventory drag delay in client ticks (20ms)", name = "Always On",
position = 1 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( @ConfigItem(
position = 1,
keyName = "keybind", 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", description = "The keybind you want to use for antidrag",
position = 2 position = 2,
hidden = true,
unhide = "keybind"
) )
default Keybind key() default Keybind key()
{ {
return new ModifierlessKeybind(KeyEvent.VK_SHIFT, 0); 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( @ConfigItem(
keyName = "reqfocus", keyName = "reqfocus",
name = "Reset on focus loss", name = "Reset on focus loss",
description = "Disable antidrag when losing focus (like alt tabbing)", description = "Disable antidrag when losing focus (like alt tabbing)",
position = 3 position = 4,
hidden = true,
unhide = "keybind"
) )
default boolean reqfocus() default boolean reqfocus()
{ {
@@ -74,7 +107,9 @@ public interface AntiDragConfig extends Config
keyName = "overlay", keyName = "overlay",
name = "Enable overlay", name = "Enable overlay",
description = "Do you really need a description?", description = "Do you really need a description?",
position = 4 position = 5,
hidden = true,
unhide = "keybind"
) )
default boolean overlay() default boolean overlay()
{ {
@@ -87,8 +122,8 @@ public interface AntiDragConfig extends Config
name = "Overlay color", name = "Overlay color",
description = "Change the overlay color, duh", description = "Change the overlay color, duh",
hidden = true, hidden = true,
unhide = "overlay", unhide = "keybind",
position = 5 position = 6
) )
default Color color() default Color color()
{ {
@@ -99,7 +134,9 @@ public interface AntiDragConfig extends Config
keyName = "changeCursor", keyName = "changeCursor",
name = "Change Cursor", name = "Change Cursor",
description = "Change cursor when you have anti-drag enabled.", description = "Change cursor when you have anti-drag enabled.",
position = 6 position = 7,
hidden = true,
unhide = "keybind"
) )
default boolean changeCursor() default boolean changeCursor()
{ {
@@ -111,8 +148,8 @@ public interface AntiDragConfig extends Config
name = "Cursor", name = "Cursor",
description = "Select which cursor you wish to use", description = "Select which cursor you wish to use",
hidden = true, hidden = true,
unhide = "changeCursor", unhide = "keybind",
position = 7 position = 8
) )
default CustomCursor selectedCursor() default CustomCursor selectedCursor()
{ {

View File

@@ -28,6 +28,7 @@ package net.runelite.client.plugins.antidrag;
import com.google.inject.Provides; import com.google.inject.Provides;
import javax.inject.Inject; import javax.inject.Inject;
import net.runelite.api.Client; import net.runelite.api.Client;
import net.runelite.api.events.ConfigChanged;
import net.runelite.api.events.FocusChanged; import net.runelite.api.events.FocusChanged;
import net.runelite.client.config.ConfigManager; import net.runelite.client.config.ConfigManager;
import net.runelite.client.eventbus.Subscribe; import net.runelite.client.eventbus.Subscribe;
@@ -51,6 +52,7 @@ import net.runelite.client.util.HotkeyListener;
public class AntiDragPlugin extends Plugin public class AntiDragPlugin extends Plugin
{ {
private static final int DEFAULT_DELAY = 5; private static final int DEFAULT_DELAY = 5;
private boolean toggleDrag; private boolean toggleDrag;
@Inject @Inject
@@ -83,9 +85,11 @@ public class AntiDragPlugin extends Plugin
@Override @Override
protected void startUp() throws Exception protected void startUp() throws Exception
{ {
keyManager.registerKeyListener(hotkeyListener); if (config.keybind())
toggleDrag = false; {
keyManager.registerKeyListener(hotkeyListener);
}
client.setInventoryDragDelay(config.alwaysOn() ? config.dragDelay() : DEFAULT_DELAY);
} }
@Override @Override
@@ -97,46 +101,75 @@ public class AntiDragPlugin extends Plugin
overlayManager.remove(overlay); 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()) private final HotkeyListener hotkeyListener = new HotkeyListener(() -> config.key())
{ {
@Override @Override
public void hotkeyPressed() public void hotkeyPressed()
{ {
toggleDrag = !toggleDrag; if (!config.alwaysOn())
if (toggleDrag)
{ {
if (config.overlay()) toggleDrag = !toggleDrag;
if (toggleDrag)
{ {
overlayManager.add(overlay); if (config.overlay())
} {
if (config.changeCursor()) overlayManager.add(overlay);
{ }
CustomCursor selectedCursor = config.selectedCursor(); if (config.changeCursor())
clientUI.setCursor(selectedCursor.getCursorImage(), selectedCursor.toString()); {
} CustomCursor selectedCursor = config.selectedCursor();
clientUI.setCursor(selectedCursor.getCursorImage(), selectedCursor.toString());
}
client.setInventoryDragDelay(config.dragDelay()); client.setInventoryDragDelay(config.dragDelay());
} }
else else
{
overlayManager.remove(overlay);
client.setInventoryDragDelay(DEFAULT_DELAY);
if (config.changeCursor())
{ {
net.runelite.client.plugins.customcursor.CustomCursor selectedCursor = configManager.getConfig(CustomCursorConfig.class).selectedCursor(); overlayManager.remove(overlay);
clientUI.setCursor(selectedCursor.getCursorImage(), selectedCursor.toString()); 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);
}
}
} }

View File

@@ -27,10 +27,8 @@
*/ */
package net.runelite.client.plugins.aoewarnings; package net.runelite.client.plugins.aoewarnings;
import java.awt.BasicStroke;
import java.awt.Color; import java.awt.Color;
import java.awt.Dimension; import java.awt.Dimension;
import java.awt.Font;
import java.awt.Graphics2D; import java.awt.Graphics2D;
import java.awt.Polygon; import java.awt.Polygon;
import java.awt.Rectangle; import java.awt.Rectangle;
@@ -38,13 +36,11 @@ import java.time.Duration;
import java.time.Instant; import java.time.Instant;
import java.util.Iterator; import java.util.Iterator;
import java.util.Map; import java.util.Map;
import javax.annotation.Nullable;
import javax.inject.Inject; import javax.inject.Inject;
import net.runelite.api.Client; import net.runelite.api.Client;
import net.runelite.api.Perspective; import net.runelite.api.Perspective;
import net.runelite.api.Point; import net.runelite.api.Point;
import net.runelite.api.Projectile; import net.runelite.api.Projectile;
import net.runelite.api.coords.LocalPoint;
import net.runelite.api.coords.WorldPoint; import net.runelite.api.coords.WorldPoint;
import net.runelite.client.ui.overlay.Overlay; import net.runelite.client.ui.overlay.Overlay;
import net.runelite.client.ui.overlay.OverlayLayer; import net.runelite.client.ui.overlay.OverlayLayer;
@@ -62,7 +58,7 @@ public class AoeWarningOverlay extends Overlay
private final AoeWarningConfig config; private final AoeWarningConfig config;
@Inject @Inject
public AoeWarningOverlay(@Nullable Client client, AoeWarningPlugin plugin, AoeWarningConfig config) public AoeWarningOverlay(Client client, AoeWarningPlugin plugin, AoeWarningConfig config)
{ {
setPosition(OverlayPosition.DYNAMIC); setPosition(OverlayPosition.DYNAMIC);
setLayer(OverlayLayer.UNDER_WIDGETS); setLayer(OverlayLayer.UNDER_WIDGETS);
@@ -74,24 +70,25 @@ public class AoeWarningOverlay extends Overlay
@Override @Override
public Dimension render(Graphics2D graphics) public Dimension render(Graphics2D graphics)
{ {
WorldPoint lp = client.getLocalPlayer().getWorldLocation();
for (WorldPoint point : plugin.getLightningTrail()) 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()) 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()) 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()) 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(); Instant now = Instant.now();
@@ -164,7 +161,8 @@ public class AoeWarningOverlay extends Overlay
{ {
if (tickProgress >= 0) 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)); graphics.setColor(new Color(setAlphaComponent(config.overlayColor().getRGB(), fillAlpha), true));
@@ -173,50 +171,6 @@ public class AoeWarningOverlay extends Overlay
return null; return null;
} }
private void drawTile(Graphics2D graphics, WorldPoint point, Color color, int strokeWidth, int outlineAlpha, int fillAlpha)
{
WorldPoint playerLocation = client.getLocalPlayer().getWorldLocation();
if (point.distanceTo(playerLocation) >= 32)
{
return;
}
LocalPoint lp = LocalPoint.fromWorld(client, point);
if (lp == null)
{
return;
}
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) private Point centerPoint(Rectangle rect)
{ {
int x = (int) (rect.getX() + rect.getWidth() / 2); int x = (int) (rect.getX() + rect.getWidth() / 2);

View File

@@ -41,6 +41,7 @@ import lombok.extern.slf4j.Slf4j;
import net.runelite.api.Client; import net.runelite.api.Client;
import net.runelite.api.GameObject; import net.runelite.api.GameObject;
import net.runelite.api.GameState; import net.runelite.api.GameState;
import net.runelite.api.GraphicID;
import net.runelite.api.GraphicsObject; import net.runelite.api.GraphicsObject;
import net.runelite.api.NullObjectID; import net.runelite.api.NullObjectID;
import net.runelite.api.ObjectID; import net.runelite.api.ObjectID;
@@ -48,6 +49,7 @@ import net.runelite.api.Projectile;
import net.runelite.api.Tile; import net.runelite.api.Tile;
import net.runelite.api.coords.LocalPoint; import net.runelite.api.coords.LocalPoint;
import net.runelite.api.coords.WorldPoint; import net.runelite.api.coords.WorldPoint;
import net.runelite.api.events.ConfigChanged;
import net.runelite.api.events.GameObjectDespawned; import net.runelite.api.events.GameObjectDespawned;
import net.runelite.api.events.GameObjectSpawned; import net.runelite.api.events.GameObjectSpawned;
import net.runelite.api.events.GameStateChanged; import net.runelite.api.events.GameStateChanged;
@@ -72,40 +74,35 @@ import net.runelite.client.ui.overlay.OverlayManager;
@Slf4j @Slf4j
public class AoeWarningPlugin extends Plugin public class AoeWarningPlugin extends Plugin
{ {
@Getter @Getter
private final Map<WorldPoint, CrystalBomb> bombs = new HashMap<>(); private final Map<WorldPoint, CrystalBomb> bombs = new HashMap<>();
private final Map<Projectile, AoeProjectile> projectiles = new HashMap<>(); private final Map<Projectile, AoeProjectile> projectiles = new HashMap<>();
@Inject @Inject
public AoeWarningConfig config; public AoeWarningConfig config;
@Inject @Inject
private Notifier notifier; private Notifier notifier;
@Inject @Inject
private OverlayManager overlayManager; private OverlayManager overlayManager;
@Inject @Inject
private AoeWarningOverlay coreOverlay; private AoeWarningOverlay coreOverlay;
@Inject @Inject
private BombOverlay bombOverlay; private BombOverlay bombOverlay;
@Inject @Inject
private Client client; private Client client;
@Getter(AccessLevel.PACKAGE) @Getter(AccessLevel.PACKAGE)
private List<WorldPoint> LightningTrail = new ArrayList<>(); private List<WorldPoint> LightningTrail = new ArrayList<>();
@Getter(AccessLevel.PACKAGE) @Getter(AccessLevel.PACKAGE)
private List<WorldPoint> AcidTrail = new ArrayList<>(); private List<WorldPoint> AcidTrail = new ArrayList<>();
@Getter(AccessLevel.PACKAGE) @Getter(AccessLevel.PACKAGE)
private List<WorldPoint> CrystalSpike = new ArrayList<>(); private List<WorldPoint> CrystalSpike = new ArrayList<>();
@Getter(AccessLevel.PACKAGE) @Getter(AccessLevel.PACKAGE)
private List<WorldPoint> WintertodtSnowFall = new ArrayList<>(); private List<WorldPoint> WintertodtSnowFall = new ArrayList<>();
@Getter(AccessLevel.PACKAGE)
private boolean shadows;
@Getter(AccessLevel.PACKAGE)
private int textSize;
@Getter(AccessLevel.PACKAGE)
private int fontStyle;
@Provides @Provides
AoeWarningConfig getConfig(ConfigManager configManager) AoeWarningConfig getConfig(ConfigManager configManager)
@@ -123,10 +120,7 @@ public class AoeWarningPlugin extends Plugin
{ {
overlayManager.add(coreOverlay); overlayManager.add(coreOverlay);
overlayManager.add(bombOverlay); overlayManager.add(bombOverlay);
LightningTrail.clear(); reset(true);
AcidTrail.clear();
CrystalSpike.clear();
WintertodtSnowFall.clear();
} }
@Override @Override
@@ -134,10 +128,29 @@ public class AoeWarningPlugin extends Plugin
{ {
overlayManager.remove(coreOverlay); overlayManager.remove(coreOverlay);
overlayManager.remove(bombOverlay); overlayManager.remove(bombOverlay);
LightningTrail.clear(); reset(false);
AcidTrail.clear(); }
CrystalSpike.clear();
WintertodtSnowFall.clear(); @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 @Subscribe
@@ -172,12 +185,12 @@ public class AoeWarningPlugin extends Plugin
public void onGameObjectSpawned(GameObjectSpawned event) public void onGameObjectSpawned(GameObjectSpawned event)
{ {
final GameObject gameObject = event.getGameObject(); final GameObject gameObject = event.getGameObject();
final WorldPoint bombLocation = gameObject.getWorldLocation(); final WorldPoint wp = gameObject.getWorldLocation();
switch (gameObject.getId()) switch (gameObject.getId())
{ {
case ObjectID.CRYSTAL_BOMB: 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()) if (config.aoeNotifyAll() || config.bombDisplayNotifyEnabled())
{ {
@@ -185,17 +198,16 @@ public class AoeWarningPlugin extends Plugin
} }
break; break;
case ObjectID.ACID_POOL: case ObjectID.ACID_POOL:
AcidTrail.add(bombLocation); AcidTrail.add(wp);
break; break;
case ObjectID.SMALL_CRYSTALS: case ObjectID.SMALL_CRYSTALS:
//todo CrystalSpike.add(wp);
CrystalSpike.add(bombLocation);
break; break;
case NullObjectID.NULL_26690: case NullObjectID.NULL_26690:
//Wintertodt Snowfall //Wintertodt Snowfall
if (config.isWintertodtEnabled()) if (config.isWintertodtEnabled())
{ {
WintertodtSnowFall.add(bombLocation); WintertodtSnowFall.add(wp);
if (config.aoeNotifyAll() || config.isWintertodtNotifyEnabled()) if (config.aoeNotifyAll() || config.isWintertodtNotifyEnabled())
{ {
@@ -210,25 +222,23 @@ public class AoeWarningPlugin extends Plugin
public void onGameObjectDespawned(GameObjectDespawned event) public void onGameObjectDespawned(GameObjectDespawned event)
{ {
GameObject gameObject = event.getGameObject(); GameObject gameObject = event.getGameObject();
WorldPoint bombLocation = gameObject.getWorldLocation(); WorldPoint wp = gameObject.getWorldLocation();
switch (gameObject.getId()) switch (gameObject.getId())
{ {
case ObjectID.CRYSTAL_BOMB: case ObjectID.CRYSTAL_BOMB:
//might as well check the ObjectID to save some time.
purgeBombs(bombs); purgeBombs(bombs);
break; break;
case ObjectID.ACID_POOL: case ObjectID.ACID_POOL:
AcidTrail.remove(bombLocation); AcidTrail.remove(wp);
break; break;
case ObjectID.SMALL_CRYSTALS: case ObjectID.SMALL_CRYSTALS:
//todo CrystalSpike.remove(wp);
CrystalSpike.remove(bombLocation);
break; break;
case NullObjectID.NULL_26690: case NullObjectID.NULL_26690:
//Wintertodt Snowfall //Wintertodt Snowfall
if (config.isWintertodtEnabled()) if (config.isWintertodtEnabled())
{ {
WintertodtSnowFall.remove(bombLocation); WintertodtSnowFall.remove(wp);
} }
break; break;
} }
@@ -251,7 +261,7 @@ public class AoeWarningPlugin extends Plugin
LightningTrail.clear(); LightningTrail.clear();
for (GraphicsObject o : client.getGraphicsObjects()) for (GraphicsObject o : client.getGraphicsObjects())
{ {
if (o.getId() == 1356) if (o.getId() == GraphicID.OLM_LIGHTNING)
{ {
LightningTrail.add(WorldPoint.fromLocal(client, o.getLocation())); LightningTrail.add(WorldPoint.fromLocal(client, o.getLocation()));
@@ -281,6 +291,12 @@ public class AoeWarningPlugin extends Plugin
Map.Entry<WorldPoint, CrystalBomb> entry = it.next(); Map.Entry<WorldPoint, CrystalBomb> entry = it.next();
WorldPoint world = entry.getKey(); WorldPoint world = entry.getKey();
LocalPoint local = LocalPoint.fromWorld(client, world); LocalPoint local = LocalPoint.fromWorld(client, world);
if (local == null)
{
return;
}
Tile tile = tiles[world.getPlane()][local.getSceneX()][local.getSceneY()]; Tile tile = tiles[world.getPlane()][local.getSceneX()][local.getSceneY()];
GameObject[] objects = tile.getGameObjects(); GameObject[] objects = tile.getGameObjects();
boolean containsObjects = false; boolean containsObjects = false;
@@ -391,4 +407,20 @@ public class AoeWarningPlugin extends Plugin
return false; 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();
}
}
}

View File

@@ -121,6 +121,10 @@ public class BombOverlay extends Overlay
{ {
final Player localPlayer = client.getLocalPlayer(); final Player localPlayer = client.getLocalPlayer();
LocalPoint localLoc = LocalPoint.fromWorld(client, bomb.getWorldLocation()); LocalPoint localLoc = LocalPoint.fromWorld(client, bomb.getWorldLocation());
if (localLoc == null)
{
return;
}
double distance_x = Math.abs(bomb.getWorldLocation().getX() - localPlayer.getWorldLocation().getX()); double distance_x = Math.abs(bomb.getWorldLocation().getX() - localPlayer.getWorldLocation().getX());
double distance_y = Math.abs(bomb.getWorldLocation().getY() - localPlayer.getWorldLocation().getY()); double distance_y = Math.abs(bomb.getWorldLocation().getY() - localPlayer.getWorldLocation().getY());
Color color_code = Color.decode(SAFE); Color color_code = Color.decode(SAFE);
@@ -142,7 +146,7 @@ public class BombOverlay extends Overlay
{ {
color_code = Color.decode(CAUTION); 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); Polygon poly = Perspective.getCanvasTileAreaPoly(client, CenterPoint, BOMB_AOE);
if (poly != null) if (poly != null)

View File

@@ -174,7 +174,7 @@ class BarbarianAssaultMenu
return config.removeIncorrectCalls() && !hornUpdated; return config.removeIncorrectCalls() && !hornUpdated;
default: default:
return config.removeUnusedMenus(); return role != null && config.removeUnusedMenus();
} }
}); });

View File

@@ -79,11 +79,11 @@ public enum Menus
ATTACK_PENANCE_QUEEN(null, new ComparableEntry("attack", "penance queen", -1, -1, true, false)), 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)), ATTACK_QUEEN_SPAWN(null, new ComparableEntry("attack", "queen spawn", -1, -1, true, false)),
DROP_HORN(null, new ComparableEntry("drop", "horn", -1, -1, true, false)), DROP_HORN(null, new ComparableEntry("drop", "r horn", -1, -1, true, false)),
EXAMINE_HORN(null, new ComparableEntry("examine", "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)), LIGHT_LOGS(null, new ComparableEntry("light", "logs", -1, -1, true, true)),
MEDIC_HORN(null, new ComparableEntry("medic", "horn", -1, -1, true, false)), MEDIC_HORN(null, new ComparableEntry("medic", "r horn", -1, -1, true, false)),
USE_HORN(null, new ComparableEntry("use", "horn", -1, -1, true, false)); USE_HORN(null, new ComparableEntry("use", "r horn", -1, -1, true, false));
@Getter @Getter
private final Role role; private final Role role;

View File

@@ -82,11 +82,22 @@ public interface BoostsConfig extends Config
return false; return false;
} }
@ConfigItem(
keyName = "boldIconFont",
name = "Bold Font for Icons",
description = "",
position = 5
)
default boolean boldIconFont()
{
return false;
}
@ConfigItem( @ConfigItem(
keyName = "displayNextBuffChange", keyName = "displayNextBuffChange",
name = "Display next buff change", name = "Display next buff change",
description = "Configures whether or not to display when the next buffed stat change will be", description = "Configures whether or not to display when the next buffed stat change will be",
position = 5 position = 6
) )
default DisplayChangeMode displayNextBuffChange() default DisplayChangeMode displayNextBuffChange()
{ {
@@ -97,7 +108,7 @@ public interface BoostsConfig extends Config
keyName = "displayNextDebuffChange", keyName = "displayNextDebuffChange",
name = "Display next debuff change", name = "Display next debuff change",
description = "Configures whether or not to display when the next debuffed stat change will be", description = "Configures whether or not to display when the next debuffed stat change will be",
position = 6 position = 7
) )
default DisplayChangeMode displayNextDebuffChange() default DisplayChangeMode displayNextDebuffChange()
{ {
@@ -108,7 +119,7 @@ public interface BoostsConfig extends Config
keyName = "boostThreshold", keyName = "boostThreshold",
name = "Boost Amount Threshold", name = "Boost Amount Threshold",
description = "The amount of levels boosted to send a notification at. A value of 0 will disable notification.", 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() default int boostThreshold()
{ {
@@ -119,7 +130,7 @@ public interface BoostsConfig extends Config
keyName = "groupNotifications", keyName = "groupNotifications",
name = "Group Notifications", name = "Group Notifications",
description = "Configures whether or not to group notifications for multiple skills into a single notification", description = "Configures whether or not to group notifications for multiple skills into a single notification",
position = 8 position = 9
) )
default boolean groupNotifications() default boolean groupNotifications()
{ {

View File

@@ -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.ImageComponent;
import net.runelite.client.ui.overlay.components.LineComponent; import net.runelite.client.ui.overlay.components.LineComponent;
import net.runelite.client.ui.overlay.components.PanelComponent; 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.ColorUtil;
import net.runelite.client.util.ImageUtil; import net.runelite.client.util.ImageUtil;
@@ -50,7 +51,12 @@ class CombatIconsOverlay extends Overlay
{ {
return null; return null;
} }
if (config.boldIconFont())
{
graphics.setFont(FontManager.getRunescapeBoldFont());
}
panelComponent.getChildren().clear(); panelComponent.getChildren().clear();
panelComponent.setPreferredSize(new Dimension(28, 0)); panelComponent.setPreferredSize(new Dimension(28, 0));
panelComponent.setWrapping(2); panelComponent.setWrapping(2);

View File

@@ -110,6 +110,17 @@ public interface ChatCommandsConfig extends Config
@ConfigItem( @ConfigItem(
position = 7, position = 7,
keyName = "duels",
name = "Duels Command",
description = "Configures whether the duel arena command is enabled<br> !duels"
)
default boolean duels()
{
return true;
}
@ConfigItem(
position = 8,
keyName = "clearShortcuts", keyName = "clearShortcuts",
name = "Clear shortcuts", name = "Clear shortcuts",
description = "Enable shortcuts (ctrl+w and backspace) for clearing the chatbox" description = "Enable shortcuts (ctrl+w and backspace) for clearing the chatbox"
@@ -118,4 +129,4 @@ public interface ChatCommandsConfig extends Config
{ {
return true; return true;
} }
} }

View File

@@ -64,6 +64,7 @@ import net.runelite.client.plugins.PluginDescriptor;
import net.runelite.client.util.StackFormatter; import net.runelite.client.util.StackFormatter;
import static net.runelite.client.util.Text.sanitize; import static net.runelite.client.util.Text.sanitize;
import net.runelite.http.api.chat.ChatClient; 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.HiscoreClient;
import net.runelite.http.api.hiscore.HiscoreEndpoint; import net.runelite.http.api.hiscore.HiscoreEndpoint;
import net.runelite.http.api.hiscore.HiscoreResult; 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: <col=ff0000>(\\d+)</col>"); private static final Pattern BARROWS_PATTERN = Pattern.compile("Your Barrows chest count is: <col=ff0000>(\\d+)</col>");
private static final Pattern KILL_DURATION_PATTERN = Pattern.compile("Fight duration: <col=ff0000>[0-9:]+</col>. Personal best: ([0-9:]+)"); private static final Pattern KILL_DURATION_PATTERN = Pattern.compile("Fight duration: <col=ff0000>[0-9:]+</col>. Personal best: ([0-9:]+)");
private static final Pattern NEW_PB_PATTERN = Pattern.compile("Fight duration: <col=ff0000>([0-9:]+)</col> \\(new personal best\\)"); private static final Pattern NEW_PB_PATTERN = Pattern.compile("Fight duration: <col=ff0000>([0-9:]+)</col> \\(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 TOTAL_LEVEL_COMMAND_STRING = "!total";
private static final String PRICE_COMMAND_STRING = "!price"; private static final String PRICE_COMMAND_STRING = "!price";
private static final String LEVEL_COMMAND_STRING = "!lvl"; 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 QP_COMMAND_STRING = "!qp";
private static final String GC_COMMAND_STRING = "!gc"; private static final String GC_COMMAND_STRING = "!gc";
private static final String PB_COMMAND = "!pb"; private static final String PB_COMMAND = "!pb";
private static final String DUEL_ARENA_COMMAND = "!duels";
private final HiscoreClient hiscoreClient = new HiscoreClient(); private final HiscoreClient hiscoreClient = new HiscoreClient();
private final ChatClient chatClient = new ChatClient(); 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(QP_COMMAND_STRING, this::questPointsLookup, this::questPointsSubmit);
chatCommandManager.registerCommandAsync(GC_COMMAND_STRING, this::gambleCountLookup, this::gambleCountSubmit); chatCommandManager.registerCommandAsync(GC_COMMAND_STRING, this::gambleCountLookup, this::gambleCountSubmit);
chatCommandManager.registerCommandAsync(PB_COMMAND, this::personalBestLookup, this::personalBestSubmit); chatCommandManager.registerCommandAsync(PB_COMMAND, this::personalBestLookup, this::personalBestSubmit);
chatCommandManager.registerCommandAsync(DUEL_ARENA_COMMAND, this::duelArenaLookup, this::duelArenaSubmit);
} }
@Override @Override
@@ -166,6 +171,7 @@ public class ChatCommandsPlugin extends Plugin
chatCommandManager.unregisterCommand(QP_COMMAND_STRING); chatCommandManager.unregisterCommand(QP_COMMAND_STRING);
chatCommandManager.unregisterCommand(PB_COMMAND); chatCommandManager.unregisterCommand(PB_COMMAND);
chatCommandManager.unregisterCommand(GC_COMMAND_STRING); chatCommandManager.unregisterCommand(GC_COMMAND_STRING);
chatCommandManager.unregisterCommand(DUEL_ARENA_COMMAND);
} }
@Provides @Provides
@@ -203,7 +209,9 @@ public class ChatCommandsPlugin extends Plugin
@Subscribe @Subscribe
public void onChatMessage(ChatMessage chatMessage) 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; return;
} }
@@ -239,6 +247,43 @@ public class ChatCommandsPlugin extends Plugin
return; 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); matcher = BARROWS_PATTERN.matcher(message);
if (matcher.find()) if (matcher.find())
{ {
@@ -419,6 +464,96 @@ public class ChatCommandsPlugin extends Plugin
client.refreshChat(); 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) private void questPointsLookup(ChatMessage chatMessage, String message)
{ {
if (!config.qp()) if (!config.qp())
@@ -1231,4 +1366,4 @@ public class ChatCommandsPlugin extends Plugin
return WordUtils.capitalize(boss); return WordUtils.capitalize(boss);
} }
} }
} }

View File

@@ -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;
}
}

View File

@@ -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<String> AFTER_OPTIONS = ImmutableList.of("Message", "Add ignore", "Remove friend", "Kick");
private ArrayList<String> playerNames = new ArrayList<>();
@Inject
private Client client;
@Inject
private ClientThread clientThread;
@Inject
private ConfigManager configManager;
@Inject
private Provider<MenuManager> 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.
}
}

View File

@@ -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;
}
}

View File

@@ -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();
}
}

View File

@@ -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("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("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("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 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("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."), 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."),

View File

@@ -1,5 +1,6 @@
/* /*
* Copyright (c) 2018, Eadgars Ruse <https://github.com/Eadgars-Ruse> * Copyright (c) 2018, Eadgars Ruse <https://github.com/Eadgars-Ruse>
* Copyright (c) 2019, Jordan Atwood <nightfirecat@protonmail.com>
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
@@ -24,21 +25,19 @@
*/ */
package net.runelite.client.plugins.cluescrolls.clues; package net.runelite.client.plugins.cluescrolls.clues;
import com.google.common.collect.Lists;
import java.awt.Color; import java.awt.Color;
import java.awt.Dimension; import java.awt.Dimension;
import java.awt.Graphics2D; 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.Arrays;
import java.util.HashMap; import java.util.Collection;
import java.util.List; import java.util.EnumMap;
import java.util.Map; import java.util.Map;
import java.util.regex.Matcher; import java.util.Set;
import java.util.regex.Pattern; import java.util.stream.Collectors;
import javax.annotation.Nullable;
import lombok.EqualsAndHashCode;
import lombok.Getter; import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import net.runelite.api.NPC; import net.runelite.api.NPC;
import net.runelite.api.coords.LocalPoint; import net.runelite.api.coords.LocalPoint;
import net.runelite.api.coords.WorldPoint; 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 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.HotColdArea;
import net.runelite.client.plugins.cluescrolls.clues.hotcold.HotColdLocation; 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.OverlayUtil;
import net.runelite.client.ui.overlay.components.LineComponent; import net.runelite.client.ui.overlay.components.LineComponent;
import net.runelite.client.ui.overlay.components.PanelComponent; import net.runelite.client.ui.overlay.components.PanelComponent;
import net.runelite.client.ui.overlay.components.TitleComponent; import net.runelite.client.ui.overlay.components.TitleComponent;
@EqualsAndHashCode(callSuper = false, exclude = { "hotColdSolver", "location" })
@Getter @Getter
@Slf4j
public class HotColdClue extends ClueScroll implements LocationClueScroll, LocationsClueScroll, TextClueScroll, NpcClueScroll 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 int HOT_COLD_PANEL_WIDTH = 200;
private static final Pattern STRANGE_DEVICE_MESSAGE = Pattern.compile("The device is (.*), (.*) last time\\."); 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.",
private static final Pattern FINAL_STRANGE_DEVICE_MESSAGE = Pattern.compile("The device is visibly shaking.*"); "Reldo",
private static final HotColdClue CLUE = "Speak to Reldo to receive a strange device.");
new HotColdClue("Buried beneath the ground, who knows where it's found. Lucky for you, A man called Jorral may have a clue.", 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", "Jorral",
"Speak to Jorral to receive a strange device."); "Speak to Jorral to receive a strange device.");
// list of potential places to dig
private List<HotColdLocation> digLocations = new ArrayList<>();
private final String text; private final String text;
private final String npc; private final String npc;
private final String solution; private final String solution;
@Nullable
private HotColdSolver hotColdSolver;
private WorldPoint location; private WorldPoint location;
private WorldPoint lastWorldPoint;
public static HotColdClue forText(String text) 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; return null;
@@ -87,24 +96,35 @@ public class HotColdClue extends ClueScroll implements LocationClueScroll, Locat
this.npc = npc; this.npc = npc;
this.solution = solution; this.solution = solution;
setRequiresSpade(true); setRequiresSpade(true);
initializeSolver();
} }
@Override @Override
public WorldPoint[] getLocations() 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 @Override
public void makeOverlayHint(PanelComponent panelComponent, ClueScrollPlugin plugin) public void makeOverlayHint(PanelComponent panelComponent, ClueScrollPlugin plugin)
{ {
if (hotColdSolver == null)
{
return;
}
panelComponent.getChildren().add(TitleComponent.builder() panelComponent.getChildren().add(TitleComponent.builder()
.text("Hot/Cold Clue") .text("Hot/Cold Clue")
.build()); .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 // 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) if (getNpc() != null)
{ {
@@ -131,7 +151,9 @@ public class HotColdClue extends ClueScroll implements LocationClueScroll, Locat
panelComponent.getChildren().add(LineComponent.builder() panelComponent.getChildren().add(LineComponent.builder()
.left("Possible areas:") .left("Possible areas:")
.build()); .build());
Map<HotColdArea, Integer> locationCounts = new HashMap<>();
final Map<HotColdArea, Integer> locationCounts = new EnumMap<>(HotColdArea.class);
final Collection<HotColdLocation> digLocations = hotColdSolver.getPossibleLocations();
for (HotColdLocation hotColdLocation : digLocations) for (HotColdLocation hotColdLocation : digLocations)
{ {
@@ -159,17 +181,16 @@ public class HotColdClue extends ClueScroll implements LocationClueScroll, Locat
} }
else else
{ {
for (HotColdArea s : locationCounts.keySet()) for (HotColdArea area : locationCounts.keySet())
{ {
panelComponent.getChildren().add(LineComponent.builder() panelComponent.getChildren().add(LineComponent.builder()
.left(s.getName() + ":") .left(area.getName() + ':')
.build()); .build());
for (HotColdLocation hotColdLocation : digLocations) for (HotColdLocation hotColdLocation : digLocations)
{ {
if (hotColdLocation.getHotColdArea() == s) if (hotColdLocation.getHotColdArea() == area)
{ {
Rectangle2D r = hotColdLocation.getRect();
panelComponent.getChildren().add(LineComponent.builder() panelComponent.getChildren().add(LineComponent.builder()
.left("- " + hotColdLocation.getArea()) .left("- " + hotColdLocation.getArea())
.leftColor(Color.LIGHT_GRAY) .leftColor(Color.LIGHT_GRAY)
@@ -184,8 +205,13 @@ public class HotColdClue extends ClueScroll implements LocationClueScroll, Locat
@Override @Override
public void makeWorldOverlayHint(Graphics2D graphics, ClueScrollPlugin plugin) public void makeWorldOverlayHint(Graphics2D graphics, ClueScrollPlugin plugin)
{ {
if (hotColdSolver == null)
{
return;
}
// when final location has been found // when final location has been found
if (this.location != null) if (location != null)
{ {
LocalPoint localLocation = LocalPoint.fromWorld(plugin.getClient(), getLocation()); LocalPoint localLocation = LocalPoint.fromWorld(plugin.getClient(), getLocation());
@@ -197,20 +223,17 @@ public class HotColdClue extends ClueScroll implements LocationClueScroll, Locat
return; return;
} }
// when strange device hasn't been activated yet, show Jorral // when strange device hasn't been activated yet, show npc who gives you the strange device
if (lastWorldPoint == null) if (hotColdSolver.getLastWorldPoint() == null && plugin.getNpcsToMark() != null)
{ {
// Mark NPC for (NPC npcToMark : plugin.getNpcsToMark())
if (plugin.getNpcsToMark() != null)
{ {
for (NPC npc : plugin.getNpcsToMark()) OverlayUtil.renderActorOverlayImage(graphics, npcToMark, plugin.getClueScrollImage(), Color.ORANGE, IMAGE_Z_OFFSET);
{
OverlayUtil.renderActorOverlayImage(graphics, npc, plugin.getClueScrollImage(), Color.ORANGE, IMAGE_Z_OFFSET);
}
} }
} }
// once the number of possible dig locations is below 10, show the dig spots // once the number of possible dig locations is below 10, show the dig spots
final Collection<HotColdLocation> digLocations = hotColdSolver.getPossibleLocations();
if (digLocations.size() < 10) if (digLocations.size() < 10)
{ {
// Mark potential dig locations // 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) public boolean update(final String message, final ClueScrollPlugin plugin)
{ {
if (!message.startsWith("The device is")) if (hotColdSolver == null)
{ {
return false; return false;
} }
Matcher m1 = FINAL_STRANGE_DEVICE_MESSAGE.matcher(message); final Set<HotColdTemperature> temperatureSet;
Matcher m2 = STRANGE_DEVICE_MESSAGE.matcher(message);
Matcher m3 = INITIAL_STRANGE_DEVICE_MESSAGE.matcher(message);
// the order that these pattern matchers are checked is important if (this.equals(BEGINNER_CLUE))
if (m1.find())
{ {
// final location for hot cold clue has been found temperatureSet = HotColdTemperature.BEGINNER_HOT_COLD_TEMPERATURES;
WorldPoint localWorld = plugin.getClient().getLocalPlayer().getWorldLocation();
if (localWorld != null)
{
markFinalSpot(localWorld);
return true;
}
} }
else if (m2.find()) else if (this.equals(MASTER_CLUE))
{ {
String temperature = m2.group(1); temperatureSet = HotColdTemperature.MASTER_HOT_COLD_TEMPERATURES;
String difference = m2.group(2);
WorldPoint localWorld = plugin.getClient().getLocalPlayer().getWorldLocation();
if (localWorld != null)
{
updatePossibleArea(localWorld, temperature, difference);
return true;
}
} }
else if (m3.find()) else
{ {
String temperature = m3.group(1); temperatureSet = null;
WorldPoint localWorld = plugin.getClient().getLocalPlayer().getWorldLocation();
if (localWorld != null)
{
updatePossibleArea(localWorld, temperature, "");
return true;
}
} }
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 @Override
public void reset() public void reset()
{ {
this.lastWorldPoint = null; initializeSolver();
digLocations.clear();
} }
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; else
int minSquaresAway = 0;
switch (temperature)
{ {
// when the strange device reads a temperature, that means that the center of the final dig location log.warn("Hot cold solver could not be initialized, clue type is unknown; text: {}, npc: {}, solution: {}",
// is a range of squares away from the player's current location (Chebyshev AKA Chess-board distance) text, npc, solution);
case "ice cold": hotColdSolver = null;
maxSquaresAway = 5000; return;
minSquaresAway = 500;
break;
case "very cold":
maxSquaresAway = 499;
minSquaresAway = 200;
break;
case "cold":
maxSquaresAway = 199;
minSquaresAway = 150;
break;
case "warm":
maxSquaresAway = 149;
minSquaresAway = 100;
break;
case "hot":
maxSquaresAway = 99;
minSquaresAway = 70;
break;
case "very hot":
maxSquaresAway = 69;
minSquaresAway = 30;
break;
case "incredibly hot":
maxSquaresAway = 29;
minSquaresAway = 5;
break;
} }
// rectangle r1 encompasses all of the points that are within the max possible distance from the player final Set<HotColdLocation> locations = Arrays.stream(HotColdLocation.values())
Point p1 = new Point(currentWp.getX() - maxSquaresAway, currentWp.getY() - maxSquaresAway); .filter(l -> l.isBeginnerClue() == isBeginner)
Rectangle r1 = new Rectangle((int) p1.getX(), (int) p1.getY(), 2 * maxSquaresAway + 1, 2 * maxSquaresAway + 1); .collect(Collectors.toSet());
// rectangle r2 encompasses all of the points that are within the min possible distance from the player hotColdSolver = new HotColdSolver(locations);
Point p2 = new Point(currentWp.getX() - minSquaresAway, currentWp.getY() - minSquaresAway);
Rectangle r2 = new Rectangle((int) p2.getX(), (int) p2.getY(), 2 * minSquaresAway + 1, 2 * minSquaresAway + 1);
// eliminate from consideration dig spots that lie entirely within the min range or entirely outside of the max range
digLocations.removeIf(entry -> r2.contains(entry.getRect()) || !r1.intersects(entry.getRect()));
// if a previous world point has been recorded, we can consider the warmer/colder result from the strange device
if (lastWorldPoint != null)
{
switch (difference)
{
case "but colder than":
// eliminate spots that are absolutely warmer
digLocations.removeIf(entry -> isFirstPointCloserRect(currentWp, lastWorldPoint, entry.getRect()));
break;
case "and warmer than":
// eliminate spots that are absolutely colder
digLocations.removeIf(entry -> isFirstPointCloserRect(lastWorldPoint, currentWp, entry.getRect()));
break;
case "and the same temperature as":
// I couldn't figure out a clean implementation for this case
// not necessary for quickly determining final location
}
}
lastWorldPoint = currentWp;
}
private boolean isFirstPointCloserRect(WorldPoint firstWp, WorldPoint secondWp, Rectangle2D r)
{
WorldPoint p1 = new WorldPoint((int) r.getMaxX(), (int) r.getMaxY(), 0);
if (!isFirstPointCloser(firstWp, secondWp, p1))
{
return false;
}
WorldPoint p2 = new WorldPoint((int) r.getMaxX(), (int) r.getMinY(), 0);
if (!isFirstPointCloser(firstWp, secondWp, p2))
{
return false;
}
WorldPoint p3 = new WorldPoint((int) r.getMinX(), (int) r.getMaxY(), 0);
if (!isFirstPointCloser(firstWp, secondWp, p3))
{
return false;
}
WorldPoint p4 = new WorldPoint((int) r.getMinX(), (int) r.getMinY(), 0);
return (isFirstPointCloser(firstWp, secondWp, p4));
}
private boolean isFirstPointCloser(WorldPoint firstWp, WorldPoint secondWp, WorldPoint wp)
{
int firstDistance = firstWp.distanceTo2D(wp);
int secondDistance = secondWp.distanceTo2D(wp);
return (firstDistance < secondDistance);
} }
private void markFinalSpot(WorldPoint wp) private void markFinalSpot(WorldPoint wp)
@@ -408,4 +347,4 @@ public class HotColdClue extends ClueScroll implements LocationClueScroll, Locat
{ {
return new String[]{npc}; return new String[]{npc};
} }
} }

View File

@@ -1,6 +1,7 @@
/* /*
* Copyright (c) 2018, Eadgars Ruse <https://github.com/Eadgars-Ruse> * Copyright (c) 2018, Eadgars Ruse <https://github.com/Eadgars-Ruse>
* Copyright (c) 2018, Adam <Adam@sigterm.info> * Copyright (c) 2018, Adam <Adam@sigterm.info>
* Copyright (c) 2019, Jordan Atwood <nightfirecat@protonmail.com>
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
@@ -26,7 +27,6 @@
package net.runelite.client.plugins.cluescrolls.clues.hotcold; package net.runelite.client.plugins.cluescrolls.clues.hotcold;
import java.awt.Rectangle; import java.awt.Rectangle;
import java.awt.geom.Rectangle2D;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import lombok.Getter; import lombok.Getter;
import net.runelite.api.coords.WorldPoint; 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_POLLNIVNEACH(new WorldPoint(3287, 2975, 0), DESERT, "West of Pollnivneach."),
DESERT_MTA(new WorldPoint(3350, 3293, 0), DESERT, "Next to Mage Training Arena."), 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."), 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_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_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)."), 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_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_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."), 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_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_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."), 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_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_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."), 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_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(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."), 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_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_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."), 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_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(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."), 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_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."); 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 WorldPoint worldPoint;
private final HotColdArea hotColdArea; private final HotColdArea hotColdArea;
private final String area; 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);
} }
} }

View File

@@ -0,0 +1,167 @@
/*
* Copyright (c) 2018, Eadgars Ruse <https://github.com/Eadgars-Ruse>
* Copyright (c) 2019, Jordan Atwood <nightfirecat@protonmail.com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package net.runelite.client.plugins.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.
* <p>
* 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<HotColdLocation> possibleLocations;
@Nullable
private WorldPoint lastWorldPoint;
public HotColdSolver(Set<HotColdLocation> 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<HotColdLocation> 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);
}
}

View File

@@ -0,0 +1,112 @@
/*
* Copyright (c) 2019, Jordan Atwood <nightfirecat@protonmail.com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package net.runelite.client.plugins.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<HotColdTemperature> 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<HotColdTemperature> 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.
* <p>
* 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<HotColdTemperature> temperatureSet, final String message)
{
if (!message.startsWith(DEVICE_USED_START_TEXT) || temperatureSet == null)
{
return null;
}
final List<HotColdTemperature> 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);
}
}

View File

@@ -0,0 +1,55 @@
/*
* Copyright (c) 2019, Jordan Atwood <nightfirecat@protonmail.com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package net.runelite.client.plugins.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;
}
}

View File

@@ -37,6 +37,7 @@ class DevToolsButton extends JButton
{ {
super(title); super(title);
addActionListener((ev) -> setActive(!active)); addActionListener((ev) -> setActive(!active));
this.setToolTipText(title);
} }
void setActive(boolean active) void setActive(boolean active)

View File

@@ -24,20 +24,119 @@
*/ */
package net.runelite.client.plugins.fightcave; 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.Config;
import net.runelite.client.config.ConfigGroup; import net.runelite.client.config.ConfigGroup;
import net.runelite.client.config.ConfigItem; import net.runelite.client.config.ConfigItem;
import net.runelite.client.config.Range;
import net.runelite.client.config.Stub;
@ConfigGroup("fightcave") @ConfigGroup("fightcave")
public interface FightCaveConfig extends Config public interface FightCaveConfig extends Config
{ {
@ConfigItem( @ConfigItem(
position = 0,
keyName = "mainConfig",
name = "Main Config",
description = ""
)
default Stub mainConfig()
{
return new Stub();
}
@ConfigItem(
position = 1,
keyName = "waveDisplay", keyName = "waveDisplay",
name = "Wave display", 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() default WaveDisplayMode waveDisplay()
{ {
return WaveDisplayMode.BOTH; 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();
}
}
} }

View File

@@ -0,0 +1,138 @@
/*
* Copyright (c) 2019, Ganom <https://github.com/Ganom>
* Copyright (c) 2019, Lucas <https://github.com/lucwousin>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 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<Integer> 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<Integer, BossMonsters> idMap;
static
{
ImmutableMap.Builder<Integer, BossMonsters> 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<Integer> 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;
}
}

View File

@@ -0,0 +1,201 @@
/*
* Copyright (c) 2019, Ganom <https://github.com/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);
}
}

View File

@@ -27,22 +27,23 @@ package net.runelite.client.plugins.fightcave;
import com.google.inject.Provides; import com.google.inject.Provides;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections;
import java.util.EnumMap; import java.util.EnumMap;
import java.util.HashMap; import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Set;
import java.util.regex.Matcher; import java.util.regex.Matcher;
import java.util.regex.Pattern; import java.util.regex.Pattern;
import javax.annotation.Nullable;
import javax.inject.Inject; import javax.inject.Inject;
import lombok.AccessLevel; import lombok.AccessLevel;
import lombok.Getter; import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import net.runelite.api.AnimationID;
import net.runelite.api.ChatMessageType; import net.runelite.api.ChatMessageType;
import net.runelite.api.Client; import net.runelite.api.Client;
import net.runelite.api.GameState; import net.runelite.api.GameState;
import net.runelite.api.NPC; import net.runelite.api.NPC;
import net.runelite.api.NpcID; import net.runelite.api.NpcID;
import net.runelite.api.events.AnimationChanged;
import net.runelite.api.events.ChatMessage; import net.runelite.api.events.ChatMessage;
import net.runelite.api.events.GameStateChanged; import net.runelite.api.events.GameStateChanged;
import net.runelite.api.events.GameTick; 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.api.events.NpcSpawned;
import net.runelite.client.config.ConfigManager; import net.runelite.client.config.ConfigManager;
import net.runelite.client.eventbus.Subscribe; import net.runelite.client.eventbus.Subscribe;
import net.runelite.client.game.NPCManager;
import net.runelite.client.plugins.Plugin; import net.runelite.client.plugins.Plugin;
import net.runelite.client.plugins.PluginDescriptor; import net.runelite.client.plugins.PluginDescriptor;
import net.runelite.client.plugins.PluginType; import net.runelite.client.plugins.PluginType;
@@ -64,59 +66,16 @@ import org.apache.commons.lang3.ArrayUtils;
enabledByDefault = false enabledByDefault = false
) )
@Slf4j
public class FightCavePlugin extends Plugin public class FightCavePlugin extends Plugin
{ {
static final int MAX_WAVE = 63;
@Getter(AccessLevel.PACKAGE)
static final List<EnumMap<WaveMonster, Integer>> WAVES = new ArrayList<>();
private static final Pattern WAVE_PATTERN = Pattern.compile(".*Wave: (\\d+).*"); private static final Pattern WAVE_PATTERN = Pattern.compile(".*Wave: (\\d+).*");
private static final int FIGHT_CAVE_REGION = 9551; private static final int FIGHT_CAVE_REGION = 9551;
private static final int MAX_MONSTERS_OF_TYPE_PER_WAVE = 2; private static final int MAX_MONSTERS_OF_TYPE_PER_WAVE = 2;
static final int MAX_WAVE = 63;
@Getter
static final List<EnumMap<WaveMonster, Integer>> 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<NPC, NPCContainer> Rangers = new HashMap<>();
@Getter(AccessLevel.PACKAGE)
private Map<NPC, NPCContainer> Magers = new HashMap<>();
@Getter(AccessLevel.PACKAGE)
private Map<NPC, NPCContainer> Meleers = new HashMap<>();
@Getter(AccessLevel.PACKAGE)
private Map<NPC, NPCContainer> Drainers = new HashMap<>();
@Getter(AccessLevel.PACKAGE)
private Map<NPC, NPCContainer> Ignore = new HashMap<>();
@Getter(AccessLevel.PACKAGE)
@Nullable
private JadAttack attack;
private NPC jad;
static static
{ {
final WaveMonster[] waveMonsters = WaveMonster.values(); 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> fightCaveContainer = new HashSet<>();
@Getter(AccessLevel.PACKAGE)
private int currentWave = -1;
@Getter(AccessLevel.PACKAGE)
private boolean validRegion;
@Getter(AccessLevel.PACKAGE)
private List<Integer> mageTicks = new ArrayList<>();
@Getter(AccessLevel.PACKAGE)
private List<Integer> rangedTicks = new ArrayList<>();
@Getter(AccessLevel.PACKAGE)
private List<Integer> meleeTicks = new ArrayList<>();
static String formatMonsterQuantity(final WaveMonster monster, final int quantity)
{
return String.format("%dx %s", quantity, monster);
}
@Provides @Provides
FightCaveConfig provideConfig(ConfigManager configManager) FightCaveConfig provideConfig(ConfigManager configManager)
{ {
@@ -166,21 +155,41 @@ public class FightCavePlugin extends Plugin
@Override @Override
public void startUp() public void startUp()
{ {
overlayManager.add(waveOverlay); if (client.getGameState() == GameState.LOGGED_IN)
overlayManager.add(jadOverlay); {
overlayManager.add(timersOverlay); if (regionCheck())
{
validRegion = true;
overlayManager.add(waveOverlay);
overlayManager.add(fightCaveOverlay);
}
}
} }
@Override @Override
public void shutDown() public void shutDown()
{ {
overlayManager.remove(waveOverlay); overlayManager.remove(waveOverlay);
overlayManager.remove(fightCaveOverlay);
currentWave = -1; 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 @Subscribe
@@ -191,98 +200,43 @@ public class FightCavePlugin extends Plugin
return; 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 @Subscribe
public void onNpcSpawned(NpcSpawned event) public void onNpcSpawned(NpcSpawned event)
{ {
if (!validRegion)
{
return;
}
NPC npc = event.getNpc(); NPC npc = event.getNpc();
switch (npc.getId()) 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_3121:
case NpcID.TOKXIL_3122: case NpcID.TOKXIL_3122:
Rangers.put(npc, new NPCContainer(npc));
break;
case NpcID.YTMEJKOT: case NpcID.YTMEJKOT:
case NpcID.YTMEJKOT_3124: case NpcID.YTMEJKOT_3124:
Meleers.put(npc, new NPCContainer(npc));
break;
case NpcID.KETZEK: case NpcID.KETZEK:
case NpcID.KETZEK_3126: case NpcID.KETZEK_3126:
Magers.put(npc, new NPCContainer(npc));
break;
case NpcID.TZTOKJAD: case NpcID.TZTOKJAD:
case NpcID.TZTOKJAD_6506: case NpcID.TZTOKJAD_6506:
jad = npc; fightCaveContainer.add(new FightCaveContainer(npc, npcManager.getAttackSpeed(npc.getId())));
break; break;
} }
} }
@@ -290,55 +244,106 @@ public class FightCavePlugin extends Plugin
@Subscribe @Subscribe
public void onNpcDespawned(NpcDespawned event) public void onNpcDespawned(NpcDespawned event)
{ {
if (Rangers.remove(event.getNpc()) != null && Rangers.isEmpty()) if (!validRegion)
{
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)
{ {
return; return;
} }
if (jad.getAnimation() == JadAttack.MAGIC.getAnimation()) NPC npc = event.getNpc();
{
attack = JadAttack.MAGIC;
}
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); return ArrayUtils.contains(client.getMapRegions(), FIGHT_CAVE_REGION);
} }
static String formatMonsterQuantity(final WaveMonster monster, final int quantity)
{
return String.format("%dx %s", quantity, monster);
}
} }

View File

@@ -1,184 +0,0 @@
/*
* Copyright (c) 2019, Ganom <https://github.com/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);
}
}
}

View File

@@ -29,12 +29,12 @@ import lombok.AllArgsConstructor;
@AllArgsConstructor @AllArgsConstructor
enum WaveMonster enum WaveMonster
{ {
TZ_KIH("Tz-Kih", 22), TZ_KIH("Drainer", 22),
TZ_KEK("Tz-Kek", 45), TZ_KEK("Blob", 45),
TOK_XIL("Tok-Xil", 90), TOK_XIL("Range", 90),
YT_MEJKOT("Yt-MejKot", 180), YT_MEJKOT("Melee", 180),
KET_ZEK("Ket-Zek", 360), KET_ZEK("Mage", 360),
TZKOK_JAD("TzTok-Jad", 702); TZKOK_JAD("Jad", 702);
private final String name; private final String name;
private final int level; private final int level;

View File

@@ -37,8 +37,8 @@ import net.runelite.client.ui.overlay.Overlay;
import net.runelite.client.ui.overlay.OverlayPosition; import net.runelite.client.ui.overlay.OverlayPosition;
import net.runelite.client.ui.overlay.components.PanelComponent; import net.runelite.client.ui.overlay.components.PanelComponent;
import net.runelite.client.ui.overlay.components.TitleComponent; 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.TableAlignment;
import net.runelite.client.ui.overlay.components.table.TableComponent;
class WaveOverlay extends Overlay class WaveOverlay extends Overlay
{ {
@@ -46,22 +46,38 @@ class WaveOverlay extends Overlay
private final FightCaveConfig config; private final FightCaveConfig config;
private final FightCavePlugin plugin; private final FightCavePlugin plugin;
private final PanelComponent panelComponent = new PanelComponent(); private final PanelComponent panelComponent = new PanelComponent();
@Inject @Inject
private WaveOverlay(FightCaveConfig config, FightCavePlugin plugin) private WaveOverlay(FightCaveConfig config, FightCavePlugin plugin)
{ {
setPosition(OverlayPosition.TOP_RIGHT);
this.config = config; this.config = config;
this.plugin = plugin; this.plugin = plugin;
setPosition(OverlayPosition.TOP_RIGHT);
}
private static Collection<String> buildWaveLines(final Map<WaveMonster, Integer> wave)
{
final List<Map.Entry<WaveMonster, Integer>> monsters = new ArrayList<>(wave.entrySet());
monsters.sort(Map.Entry.comparingByKey());
final List<String> outputLines = new ArrayList<>();
for (Map.Entry<WaveMonster, Integer> 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 @Override
public Dimension render(Graphics2D graphics) public Dimension render(Graphics2D graphics)
{ {
if (!plugin.inFightCave() if (!plugin.isValidRegion() || plugin.getCurrentWave() < 0)
|| plugin.getCurrentWave() < 0)
{ {
return null; return null;
} }
@@ -108,26 +124,8 @@ class WaveOverlay extends Overlay
} }
if (!tableComponent.isEmpty()) if (!tableComponent.isEmpty())
{
panelComponent.getChildren().add(tableComponent);
}
}
private static Collection<String> buildWaveLines(final Map<WaveMonster, Integer> wave)
{
final List<Map.Entry<WaveMonster, Integer>> monsters = new ArrayList<>(wave.entrySet());
monsters.sort(Map.Entry.comparingByKey());
final List<String> outputLines = new ArrayList<>();
for (Map.Entry<WaveMonster, Integer> monsterEntry : monsters)
{ {
final WaveMonster monster = monsterEntry.getKey(); panelComponent.getChildren().add(tableComponent);
final int quantity = monsterEntry.getValue();
final String line = FightCavePlugin.formatMonsterQuantity(monster, quantity);
outputLines.add(line);
} }
return outputLines;
} }
} }

View File

@@ -54,17 +54,17 @@ public class FreezeTimersOverlay extends Overlay
private final BufferedImage FREEZE_IMAGE = ImageUtil.getResourceStreamFromClass(getClass(), "freeze.png"); private final BufferedImage FREEZE_IMAGE = ImageUtil.getResourceStreamFromClass(getClass(), "freeze.png");
private final BufferedImage TB_IMAGE = ImageUtil.getResourceStreamFromClass(getClass(), "teleblock.png"); private final BufferedImage TB_IMAGE = ImageUtil.getResourceStreamFromClass(getClass(), "teleblock.png");
private final BufferedImage VENG_IMAGE = ImageUtil.getResourceStreamFromClass(getClass(), "veng.png"); private final BufferedImage VENG_IMAGE = ImageUtil.getResourceStreamFromClass(getClass(), "veng.png");
@Inject
private Timers timers; private Timers timers;
private boolean lock; private boolean lock;
private long finishedAtTest; private long finishedAtTest;
@Inject @Inject
public FreezeTimersOverlay(FreezeTimersConfig config, Client client) public FreezeTimersOverlay(FreezeTimersConfig config, Client client, Timers timers)
{ {
this.config = config; this.config = config;
this.client = client; this.client = client;
this.timers = timers;
setPriority(OverlayPriority.HIGHEST); setPriority(OverlayPriority.HIGHEST);
setPosition(OverlayPosition.DYNAMIC); setPosition(OverlayPosition.DYNAMIC);
setLayer(OverlayLayer.UNDER_WIDGETS); setLayer(OverlayLayer.UNDER_WIDGETS);
@@ -119,24 +119,23 @@ public class FreezeTimersOverlay extends Overlay
String text = processTickCounter(finishedAt); String text = processTickCounter(finishedAt);
int test = Integer.parseInt(text); int test = Integer.parseInt(text);
Point poi = actor.getCanvasTextLocation(g, text, 0); Point poi = actor.getCanvasTextLocation(g, text, 0);
if (poi == null) if (poi == null)
{ {
return false; return false;
} }
int xpoi = poi.getX(); Point FixedPoint = new Point(poi.getX(), poi.getY());
int ypoi = poi.getY();
Point FixedPoint = new Point(xpoi, ypoi);
if (config.noImage()) if (config.noImage())
{ {
if (test > 3) 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 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 else
@@ -161,23 +160,26 @@ public class FreezeTimersOverlay extends Overlay
String text = processTickCounter(finishedAt); String text = processTickCounter(finishedAt);
Point poi = actor.getCanvasTextLocation(g, text, 0); 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 (config.noImage())
{ {
if (timers.getTimerEnd(actor, TimerType.FREEZE) <= currentTick) 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) 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) 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 else
@@ -202,22 +204,26 @@ public class FreezeTimersOverlay extends Overlay
String text = processTickCounter(finishedAt); String text = processTickCounter(finishedAt);
Point poi = actor.getCanvasTextLocation(g, text, 0); Point poi = actor.getCanvasTextLocation(g, text, 0);
int xpoi = poi.getX() - 20;
int ypoi = poi.getY(); if (poi == null)
Point FixedPoint = new Point(xpoi, ypoi); {
return false;
}
Point FixedPoint = new Point(poi.getX() - 20, poi.getY());
if (config.noImage()) if (config.noImage())
{ {
if (timers.getTimerEnd(actor, TimerType.FREEZE) <= currentTick) 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) 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) 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 else
@@ -229,10 +235,13 @@ public class FreezeTimersOverlay extends Overlay
g.setColor(RED); g.setColor(RED);
Polygon poly = actor.getCanvasTilePoly(); 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(), OverlayUtil.renderTextLocation(g, new Point((int) poly.getBounds2D().getCenterX(),
(int) poly.getBounds2D().getCenterY()), actor.getName(), RED); (int) poly.getBounds2D().getCenterY()), actor.getName(), RED);
} }
@@ -249,22 +258,6 @@ public class FreezeTimersOverlay extends Overlay
xOffset); 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) public void renderImageLocation(Graphics2D graphics, Point imgLoc, BufferedImage image)
{ {
int x = imgLoc.getX(); int x = imgLoc.getX();
@@ -273,12 +266,9 @@ public class FreezeTimersOverlay extends Overlay
graphics.drawImage(image, x, y, null); graphics.drawImage(image, x, y, null);
} }
public void renderActorTextAndImage(Graphics2D graphics, Actor actor, String text, Color color, private void renderActorTextAndImage(Graphics2D graphics, Actor actor, String text, Color color, BufferedImage image, int yOffset, int xOffset)
BufferedImage image, int yOffset, int xOffset)
{ {
Point textLocation = new Point(actor.getCanvasImageLocation(image, 0).getX() + xOffset, Point textLocation = new Point(actor.getCanvasImageLocation(image, 0).getX() + xOffset, actor.getCanvasImageLocation(image, 0).getY() + yOffset);
actor.getCanvasImageLocation(image, 0).getY() + yOffset);
renderImageLocation(graphics, textLocation, image); renderImageLocation(graphics, textLocation, image);
xOffset = image.getWidth() + 1; xOffset = image.getWidth() + 1;
yOffset = (image.getHeight() - (int) graphics.getFontMetrics().getStringBounds(text, graphics).getHeight()); yOffset = (image.getHeight() - (int) graphics.getFontMetrics().getStringBounds(text, graphics).getHeight());

View File

@@ -30,14 +30,13 @@ import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.HashMap;
import javax.inject.Inject; import javax.inject.Inject;
import lombok.AccessLevel; import lombok.AccessLevel;
import lombok.Getter; import lombok.Getter;
import net.runelite.api.GameState; import net.runelite.api.GameState;
import net.runelite.api.NPC; import net.runelite.api.NPC;
import net.runelite.api.events.GameTick;
import net.runelite.api.events.GameStateChanged; import net.runelite.api.events.GameStateChanged;
import net.runelite.api.events.GameTick;
import net.runelite.api.events.NpcDespawned; import net.runelite.api.events.NpcDespawned;
import net.runelite.api.events.NpcSpawned; import net.runelite.api.events.NpcSpawned;
import net.runelite.client.config.ConfigManager; import net.runelite.client.config.ConfigManager;
@@ -119,6 +118,11 @@ public class ImplingsPlugin extends Plugin
{ {
Impling impling = Impling.findImpling(npc.getId()); Impling impling = Impling.findImpling(npc.getId());
if (impling == null || impling.getImplingType() == null)
{
continue;
}
ImplingType type = impling.getImplingType(); ImplingType type = impling.getImplingType();
if (implingCounterMap.containsKey(type)) if (implingCounterMap.containsKey(type))
{ {

View File

@@ -62,4 +62,14 @@ public interface InterfaceStylesConfig extends Config
{ {
return false; 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;
}
} }

View File

@@ -31,11 +31,13 @@ import java.awt.image.BufferedImage;
import javax.inject.Inject; import javax.inject.Inject;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import net.runelite.api.Client; import net.runelite.api.Client;
import net.runelite.api.GameState;
import net.runelite.api.HealthBar; import net.runelite.api.HealthBar;
import net.runelite.api.SpriteID; import net.runelite.api.SpriteID;
import net.runelite.api.Sprite; import net.runelite.api.Sprite;
import net.runelite.api.events.BeforeMenuRender; import net.runelite.api.events.BeforeMenuRender;
import net.runelite.api.events.ConfigChanged; import net.runelite.api.events.ConfigChanged;
import net.runelite.api.events.GameStateChanged;
import net.runelite.api.events.PostHealthBar; import net.runelite.api.events.PostHealthBar;
import net.runelite.api.events.WidgetPositioned; import net.runelite.api.events.WidgetPositioned;
import net.runelite.api.widgets.Widget; import net.runelite.api.widgets.Widget;
@@ -69,6 +71,8 @@ public class InterfaceStylesPlugin extends Plugin
@Inject @Inject
private SpriteManager spriteManager; private SpriteManager spriteManager;
private Sprite[] defaultCrossSprites;
@Provides @Provides
InterfaceStylesConfig provideConfig(ConfigManager configManager) InterfaceStylesConfig provideConfig(ConfigManager configManager)
{ {
@@ -89,6 +93,7 @@ public class InterfaceStylesPlugin extends Plugin
restoreWidgetDimensions(); restoreWidgetDimensions();
removeGameframe(); removeGameframe();
restoreHealthBars(); 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() private void updateAllOverrides()
{ {
removeGameframe(); removeGameframe();
@@ -134,6 +155,7 @@ public class InterfaceStylesPlugin extends Plugin
restoreWidgetDimensions(); restoreWidgetDimensions();
adjustWidgetDimensions(); adjustWidgetDimensions();
overrideHealthBars(); overrideHealthBars();
overrideCrossSprites();
} }
@Subscribe @Subscribe
@@ -283,6 +305,62 @@ public class InterfaceStylesPlugin extends Plugin
clientThread.invokeLater(client::resetHealthBarCaches); 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() private void restoreWidgetDimensions()
{ {
for (WidgetOffset widgetOffset : WidgetOffset.values()) for (WidgetOffset widgetOffset : WidgetOffset.values())

View File

@@ -118,33 +118,33 @@ enum WidgetOffset
FIXED_2005_INTERFACE_CONTAINER(Skin.AROUND_2005, WidgetInfo.FIXED_VIEWPORT_INTERFACE_CONTAINER, 7, null, null, null), 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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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_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 Skin skin;
private WidgetInfo widgetInfo; private WidgetInfo widgetInfo;

View File

@@ -173,10 +173,10 @@ public interface ItemChargeConfig extends Config
} }
@ConfigItem( @ConfigItem(
keyName = "showBellowCharges", keyName = "showBellowCharges",
name = "Show Bellow Charges", name = "Show Bellow Charges",
description = "Configures if ogre bellow item charge is shown", description = "Configures if ogre bellow item charge is shown",
position = 12 position = 12
) )
default boolean showBellowCharges() default boolean showBellowCharges()
{ {
@@ -184,10 +184,32 @@ public interface ItemChargeConfig extends Config
} }
@ConfigItem( @ConfigItem(
keyName = "showAbyssalBraceletCharges", keyName = "showBasketCharges",
name = "Show Abyssal Bracelet Charges", name = "Show Basket Charges",
description = "Configures if abyssal bracelet item charge is shown", description = "Configures if fruit basket item charge is shown",
position = 13 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() default boolean showAbyssalBraceletCharges()
{ {
@@ -198,7 +220,7 @@ public interface ItemChargeConfig extends Config
keyName = "recoilNotification", keyName = "recoilNotification",
name = "Ring of Recoil Notification", name = "Ring of Recoil Notification",
description = "Configures if the ring of recoil breaking notification is shown", description = "Configures if the ring of recoil breaking notification is shown",
position = 14 position = 16
) )
default boolean recoilNotification() default boolean recoilNotification()
{ {
@@ -209,7 +231,7 @@ public interface ItemChargeConfig extends Config
keyName = "showBindingNecklaceCharges", keyName = "showBindingNecklaceCharges",
name = "Show Binding Necklace Charges", name = "Show Binding Necklace Charges",
description = "Configures if binding necklace item charge is shown", description = "Configures if binding necklace item charge is shown",
position = 15 position = 17
) )
default boolean showBindingNecklaceCharges() default boolean showBindingNecklaceCharges()
{ {
@@ -238,7 +260,7 @@ public interface ItemChargeConfig extends Config
keyName = "bindingNotification", keyName = "bindingNotification",
name = "Binding Necklace Notification", name = "Binding Necklace Notification",
description = "Configures if the binding necklace breaking notification is shown", description = "Configures if the binding necklace breaking notification is shown",
position = 16 position = 18
) )
default boolean bindingNotification() default boolean bindingNotification()
{ {
@@ -249,7 +271,7 @@ public interface ItemChargeConfig extends Config
keyName = "showExplorerRingCharges", keyName = "showExplorerRingCharges",
name = "Show Explorer's Ring Alch Charges", name = "Show Explorer's Ring Alch Charges",
description = "Configures if explorer's ring alchemy charges are shown", description = "Configures if explorer's ring alchemy charges are shown",
position = 17 position = 19
) )
default boolean showExplorerRingCharges() default boolean showExplorerRingCharges()
{ {
@@ -278,7 +300,7 @@ public interface ItemChargeConfig extends Config
keyName = "showInfoboxes", keyName = "showInfoboxes",
name = "Show Infoboxes", name = "Show Infoboxes",
description = "Configures whether to show an infobox equipped charge items", description = "Configures whether to show an infobox equipped charge items",
position = 18 position = 20
) )
default boolean showInfoboxes() default boolean showInfoboxes()
{ {

View File

@@ -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.TELEPORT;
import static net.runelite.client.plugins.itemcharges.ItemChargeType.WATERCAN; 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.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.FontManager;
import net.runelite.client.ui.overlay.WidgetItemOverlay; import net.runelite.client.ui.overlay.WidgetItemOverlay;
import net.runelite.client.ui.overlay.components.TextComponent; import net.runelite.client.ui.overlay.components.TextComponent;
@@ -152,6 +154,8 @@ class ItemChargeOverlay extends WidgetItemOverlay
|| (type == WATERCAN && !config.showWateringCanCharges()) || (type == WATERCAN && !config.showWateringCanCharges())
|| (type == WATERSKIN && !config.showWaterskinCharges()) || (type == WATERSKIN && !config.showWaterskinCharges())
|| (type == BELLOWS && !config.showBellowCharges()) || (type == BELLOWS && !config.showBellowCharges())
|| (type == FRUIT_BASKET && !config.showBasketCharges())
|| (type == SACK && !config.showSackCharges())
|| (type == ABYSSAL_BRACELET && !config.showAbyssalBraceletCharges())) || (type == ABYSSAL_BRACELET && !config.showAbyssalBraceletCharges()))
{ {
return; return;
@@ -172,6 +176,7 @@ class ItemChargeOverlay extends WidgetItemOverlay
{ {
return config.showTeleportCharges() || config.showDodgyCount() || config.showFungicideCharges() return config.showTeleportCharges() || config.showDodgyCount() || config.showFungicideCharges()
|| config.showImpCharges() || config.showWateringCanCharges() || config.showWaterskinCharges() || config.showImpCharges() || config.showWateringCanCharges() || config.showWaterskinCharges()
|| config.showBellowCharges() || config.showAbyssalBraceletCharges() || config.showExplorerRingCharges(); || config.showBellowCharges() || config.showBasketCharges() || config.showSackCharges()
|| config.showAbyssalBraceletCharges() || config.showExplorerRingCharges();
} }
} }

View File

@@ -37,5 +37,7 @@ enum ItemChargeType
BRACELET_OF_SLAUGHTER, BRACELET_OF_SLAUGHTER,
EXPEDITIOUS_BRACELET, EXPEDITIOUS_BRACELET,
BINDING_NECKLACE, BINDING_NECKLACE,
EXPLORER_RING EXPLORER_RING,
FRUIT_BASKET,
SACK
} }

View File

@@ -29,133 +29,8 @@ import java.util.Map;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import lombok.Getter; 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.*;
import static net.runelite.api.ItemID.ABYSSAL_BRACELET3;
import static net.runelite.api.ItemID.ABYSSAL_BRACELET4;
import static net.runelite.api.ItemID.ABYSSAL_BRACELET5;
import static net.runelite.api.ItemID.AMULET_OF_GLORY1;
import static net.runelite.api.ItemID.AMULET_OF_GLORY2;
import static net.runelite.api.ItemID.AMULET_OF_GLORY3;
import static net.runelite.api.ItemID.AMULET_OF_GLORY4;
import static net.runelite.api.ItemID.AMULET_OF_GLORY5;
import static net.runelite.api.ItemID.AMULET_OF_GLORY6;
import static net.runelite.api.ItemID.AMULET_OF_GLORY_T1;
import static net.runelite.api.ItemID.AMULET_OF_GLORY_T2;
import static net.runelite.api.ItemID.AMULET_OF_GLORY_T3;
import static net.runelite.api.ItemID.AMULET_OF_GLORY_T4;
import static net.runelite.api.ItemID.AMULET_OF_GLORY_T5;
import static net.runelite.api.ItemID.AMULET_OF_GLORY_T6;
import static net.runelite.api.ItemID.BURNING_AMULET1;
import static net.runelite.api.ItemID.BURNING_AMULET2;
import static net.runelite.api.ItemID.BURNING_AMULET3;
import static net.runelite.api.ItemID.BURNING_AMULET4;
import static net.runelite.api.ItemID.BURNING_AMULET5;
import static net.runelite.api.ItemID.COMBAT_BRACELET1;
import static net.runelite.api.ItemID.COMBAT_BRACELET2;
import static net.runelite.api.ItemID.COMBAT_BRACELET3;
import static net.runelite.api.ItemID.COMBAT_BRACELET4;
import static net.runelite.api.ItemID.COMBAT_BRACELET5;
import static net.runelite.api.ItemID.COMBAT_BRACELET6;
import static net.runelite.api.ItemID.DIGSITE_PENDANT_1;
import static net.runelite.api.ItemID.DIGSITE_PENDANT_2;
import static net.runelite.api.ItemID.DIGSITE_PENDANT_3;
import static net.runelite.api.ItemID.DIGSITE_PENDANT_4;
import static net.runelite.api.ItemID.DIGSITE_PENDANT_5;
import static net.runelite.api.ItemID.ENCHANTED_LYRE1;
import static net.runelite.api.ItemID.ENCHANTED_LYRE2;
import static net.runelite.api.ItemID.ENCHANTED_LYRE3;
import static net.runelite.api.ItemID.ENCHANTED_LYRE4;
import static net.runelite.api.ItemID.ENCHANTED_LYRE5;
import static net.runelite.api.ItemID.FUNGICIDE_SPRAY_0;
import static net.runelite.api.ItemID.FUNGICIDE_SPRAY_1;
import static net.runelite.api.ItemID.FUNGICIDE_SPRAY_10;
import static net.runelite.api.ItemID.FUNGICIDE_SPRAY_2;
import static net.runelite.api.ItemID.FUNGICIDE_SPRAY_3;
import static net.runelite.api.ItemID.FUNGICIDE_SPRAY_4;
import static net.runelite.api.ItemID.FUNGICIDE_SPRAY_5;
import static net.runelite.api.ItemID.FUNGICIDE_SPRAY_6;
import static net.runelite.api.ItemID.FUNGICIDE_SPRAY_7;
import static net.runelite.api.ItemID.FUNGICIDE_SPRAY_8;
import static net.runelite.api.ItemID.FUNGICIDE_SPRAY_9;
import static net.runelite.api.ItemID.GAMES_NECKLACE1;
import static net.runelite.api.ItemID.GAMES_NECKLACE2;
import static net.runelite.api.ItemID.GAMES_NECKLACE3;
import static net.runelite.api.ItemID.GAMES_NECKLACE4;
import static net.runelite.api.ItemID.GAMES_NECKLACE5;
import static net.runelite.api.ItemID.GAMES_NECKLACE6;
import static net.runelite.api.ItemID.GAMES_NECKLACE7;
import static net.runelite.api.ItemID.GAMES_NECKLACE8;
import static net.runelite.api.ItemID.IMPINABOX1;
import static net.runelite.api.ItemID.IMPINABOX2;
import static net.runelite.api.ItemID.NECKLACE_OF_PASSAGE1;
import static net.runelite.api.ItemID.NECKLACE_OF_PASSAGE2;
import static net.runelite.api.ItemID.NECKLACE_OF_PASSAGE3;
import static net.runelite.api.ItemID.NECKLACE_OF_PASSAGE4;
import static net.runelite.api.ItemID.NECKLACE_OF_PASSAGE5;
import static net.runelite.api.ItemID.OGRE_BELLOWS;
import static net.runelite.api.ItemID.OGRE_BELLOWS_1;
import static net.runelite.api.ItemID.OGRE_BELLOWS_2;
import static net.runelite.api.ItemID.OGRE_BELLOWS_3;
import static net.runelite.api.ItemID.PHARAOHS_SCEPTRE_1;
import static net.runelite.api.ItemID.PHARAOHS_SCEPTRE_2;
import static net.runelite.api.ItemID.PHARAOHS_SCEPTRE_3;
import static net.runelite.api.ItemID.PHARAOHS_SCEPTRE_4;
import static net.runelite.api.ItemID.PHARAOHS_SCEPTRE_5;
import static net.runelite.api.ItemID.PHARAOHS_SCEPTRE_6;
import static net.runelite.api.ItemID.PHARAOHS_SCEPTRE_7;
import static net.runelite.api.ItemID.PHARAOHS_SCEPTRE_8;
import static net.runelite.api.ItemID.RING_OF_DUELING1;
import static net.runelite.api.ItemID.RING_OF_DUELING2;
import static net.runelite.api.ItemID.RING_OF_DUELING3;
import static net.runelite.api.ItemID.RING_OF_DUELING4;
import static net.runelite.api.ItemID.RING_OF_DUELING5;
import static net.runelite.api.ItemID.RING_OF_DUELING6;
import static net.runelite.api.ItemID.RING_OF_DUELING7;
import static net.runelite.api.ItemID.RING_OF_DUELING8;
import static net.runelite.api.ItemID.RING_OF_RETURNING1;
import static net.runelite.api.ItemID.RING_OF_RETURNING2;
import static net.runelite.api.ItemID.RING_OF_RETURNING3;
import static net.runelite.api.ItemID.RING_OF_RETURNING4;
import static net.runelite.api.ItemID.RING_OF_RETURNING5;
import static net.runelite.api.ItemID.RING_OF_WEALTH_1;
import static net.runelite.api.ItemID.RING_OF_WEALTH_2;
import static net.runelite.api.ItemID.RING_OF_WEALTH_3;
import static net.runelite.api.ItemID.RING_OF_WEALTH_4;
import static net.runelite.api.ItemID.RING_OF_WEALTH_5;
import static net.runelite.api.ItemID.SKILLS_NECKLACE1;
import static net.runelite.api.ItemID.SKILLS_NECKLACE2;
import static net.runelite.api.ItemID.SKILLS_NECKLACE3;
import static net.runelite.api.ItemID.SKILLS_NECKLACE4;
import static net.runelite.api.ItemID.SKILLS_NECKLACE5;
import static net.runelite.api.ItemID.SKILLS_NECKLACE6;
import static net.runelite.api.ItemID.SLAYER_RING_1;
import static net.runelite.api.ItemID.SLAYER_RING_2;
import static net.runelite.api.ItemID.SLAYER_RING_3;
import static net.runelite.api.ItemID.SLAYER_RING_4;
import static net.runelite.api.ItemID.SLAYER_RING_5;
import static net.runelite.api.ItemID.SLAYER_RING_6;
import static net.runelite.api.ItemID.SLAYER_RING_7;
import static net.runelite.api.ItemID.SLAYER_RING_8;
import static net.runelite.api.ItemID.TELEPORT_CRYSTAL_1;
import static net.runelite.api.ItemID.TELEPORT_CRYSTAL_2;
import static net.runelite.api.ItemID.TELEPORT_CRYSTAL_3;
import static net.runelite.api.ItemID.TELEPORT_CRYSTAL_4;
import static net.runelite.api.ItemID.TELEPORT_CRYSTAL_5;
import static net.runelite.api.ItemID.WATERING_CAN;
import static net.runelite.api.ItemID.WATERING_CAN1;
import static net.runelite.api.ItemID.WATERING_CAN2;
import static net.runelite.api.ItemID.WATERING_CAN3;
import static net.runelite.api.ItemID.WATERING_CAN4;
import static net.runelite.api.ItemID.WATERING_CAN5;
import static net.runelite.api.ItemID.WATERING_CAN6;
import static net.runelite.api.ItemID.WATERING_CAN7;
import static net.runelite.api.ItemID.WATERING_CAN8;
import static net.runelite.api.ItemID.WATERSKIN0;
import static net.runelite.api.ItemID.WATERSKIN1;
import static net.runelite.api.ItemID.WATERSKIN2;
import static net.runelite.api.ItemID.WATERSKIN3;
import static net.runelite.api.ItemID.WATERSKIN4;
import static net.runelite.client.plugins.itemcharges.ItemChargeType.ABYSSAL_BRACELET; import static net.runelite.client.plugins.itemcharges.ItemChargeType.ABYSSAL_BRACELET;
import static net.runelite.client.plugins.itemcharges.ItemChargeType.BELLOWS; import static net.runelite.client.plugins.itemcharges.ItemChargeType.BELLOWS;
import static net.runelite.client.plugins.itemcharges.ItemChargeType.FUNGICIDE_SPRAY; 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.TELEPORT;
import static net.runelite.client.plugins.itemcharges.ItemChargeType.WATERCAN; 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.WATERSKIN;
import static net.runelite.client.plugins.itemcharges.ItemChargeType.FRUIT_BASKET;
import static net.runelite.client.plugins.itemcharges.ItemChargeType.SACK;
@AllArgsConstructor @AllArgsConstructor
@Getter @Getter
@@ -173,6 +50,31 @@ enum ItemWithCharge
ABRACE3(ABYSSAL_BRACELET, ABYSSAL_BRACELET3, 3), ABRACE3(ABYSSAL_BRACELET, ABYSSAL_BRACELET3, 3),
ABRACE4(ABYSSAL_BRACELET, ABYSSAL_BRACELET4, 4), ABRACE4(ABYSSAL_BRACELET, ABYSSAL_BRACELET4, 4),
ABRACE5(ABYSSAL_BRACELET, ABYSSAL_BRACELET5, 5), 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), BELLOWS0(BELLOWS, OGRE_BELLOWS, 0),
BELLOWS1(BELLOWS, OGRE_BELLOWS_1, 1), BELLOWS1(BELLOWS, OGRE_BELLOWS_1, 1),
BELLOWS2(BELLOWS, OGRE_BELLOWS_2, 2), BELLOWS2(BELLOWS, OGRE_BELLOWS_2, 2),
@@ -270,6 +172,36 @@ enum ItemWithCharge
ROW3(TELEPORT, RING_OF_WEALTH_3, 3), ROW3(TELEPORT, RING_OF_WEALTH_3, 3),
ROW4(TELEPORT, RING_OF_WEALTH_4, 4), ROW4(TELEPORT, RING_OF_WEALTH_4, 4),
ROW5(TELEPORT, RING_OF_WEALTH_5, 5), 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), SKILLS1(TELEPORT, SKILLS_NECKLACE1, 1),
SKILLS2(TELEPORT, SKILLS_NECKLACE2, 2), SKILLS2(TELEPORT, SKILLS_NECKLACE2, 2),
SKILLS3(TELEPORT, SKILLS_NECKLACE3, 3), SKILLS3(TELEPORT, SKILLS_NECKLACE3, 3),

View File

@@ -129,9 +129,12 @@ public class LootTrackerPlugin extends Plugin
// Chest loot handling // Chest loot handling
private static final String CHEST_LOOTED_MESSAGE = "You find some treasure in the chest!"; 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<Integer, String> CHEST_EVENT_TYPES = ImmutableMap.of( private static final Map<Integer, String> CHEST_EVENT_TYPES = ImmutableMap.of(
5179, "Brimstone Chest", 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 File LOOT_RECORDS_FILE = new File(RuneLite.RUNELITE_DIR, "lootRecords.json");
private static final Set<Integer> RESPAWN_REGIONS = ImmutableSet.of( private static final Set<Integer> RESPAWN_REGIONS = ImmutableSet.of(
@@ -545,7 +548,7 @@ public class LootTrackerPlugin extends Plugin
final String message = event.getMessage(); 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(); final int regionID = client.getLocalPlayer().getWorldLocation().getRegionID();
if (!CHEST_EVENT_TYPES.containsKey(regionID)) if (!CHEST_EVENT_TYPES.containsKey(regionID))

View File

@@ -1690,4 +1690,4 @@ default CharterOption charterOption()
{ {
return true; return true;
} }
} }

View File

@@ -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 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)) if (!pOptionToReplace.equals(CANCEL) && !pOptionToReplace.equals(WALK_HERE))
{ {
return; Player[] players = client.getCachedPlayers();
} int identifier = event.getIdentifier();
if (((config.getRemoveFreezePlayerCoX() && client.getVar(Varbits.IN_RAID) == 1) if (identifier >= 0 && identifier < players.length)
|| (config.getRemoveFreezePlayerToB() && client.getVar(Varbits.THEATRE_OF_BLOOD) == 2))
&& (player.isFriend() || player.isClanMember())
&& CAST_OPTIONS_KEYWORDS.contains(pOptionToReplace))
{ {
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")) if (option.equals("talk-to"))
{ {

View File

@@ -29,7 +29,7 @@ public enum DigsitePendantMode
{ {
DIGSITE("Digsite"), DIGSITE("Digsite"),
FOSSIL_ISLAND("Fossil Island"), FOSSIL_ISLAND("Fossil Island"),
LITHKREN("Lithkren"); LITHKREN("Lithkren Dungeon");
private final String name; private final String name;

View File

@@ -25,7 +25,9 @@
package net.runelite.client.plugins.npchighlight; package net.runelite.client.plugins.npchighlight;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Set;
import lombok.Getter; import lombok.Getter;
import lombok.Setter; import lombok.Setter;
import net.runelite.api.NPC; import net.runelite.api.NPC;
@@ -38,7 +40,7 @@ class MemorizedNpc
private int npcIndex; private int npcIndex;
@Getter @Getter
private String npcName; private Set<String> npcNames;
@Getter @Getter
private int npcSize; private int npcSize;
@@ -63,7 +65,8 @@ class MemorizedNpc
MemorizedNpc(NPC npc) MemorizedNpc(NPC npc)
{ {
this.npcName = npc.getName(); this.npcNames = new HashSet<>();
this.npcNames.add(npc.getName());
this.npcIndex = npc.getIndex(); this.npcIndex = npc.getIndex();
this.possibleRespawnLocations = new ArrayList<>(); this.possibleRespawnLocations = new ArrayList<>();
this.respawnTime = -1; this.respawnTime = -1;

View File

@@ -34,6 +34,7 @@ import java.util.Arrays;
import java.util.Collections; import java.util.Collections;
import java.util.HashMap; import java.util.HashMap;
import java.util.HashSet; import java.util.HashSet;
import java.util.Iterator;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set; 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.GraphicsObjectCreated;
import net.runelite.api.events.MenuEntryAdded; import net.runelite.api.events.MenuEntryAdded;
import net.runelite.api.events.MenuOptionClicked; import net.runelite.api.events.MenuOptionClicked;
import net.runelite.api.events.NpcDefinitionChanged;
import net.runelite.api.events.NpcDespawned; import net.runelite.api.events.NpcDespawned;
import net.runelite.api.events.NpcSpawned; import net.runelite.api.events.NpcSpawned;
import net.runelite.client.callback.ClientThread; import net.runelite.client.callback.ClientThread;
@@ -304,14 +306,15 @@ public class NpcIndicatorsPlugin extends Plugin
if (removed) if (removed)
{ {
highlightedNpcs.remove(npc); MemorizedNpc mn = memorizedNpcs.get(npc.getIndex());
memorizedNpcs.remove(npc.getIndex()); if (mn != null && isNpcMemorizationUnnecessary(mn))
{
memorizedNpcs.remove(npc.getIndex());
}
} }
else else
{ {
memorizeNpc(npc);
npcTags.add(id); npcTags.add(id);
highlightedNpcs.add(npc);
} }
click.consume(); click.consume();
@@ -320,30 +323,28 @@ public class NpcIndicatorsPlugin extends Plugin
@Subscribe @Subscribe
public void onNpcSpawned(NpcSpawned npcSpawned) public void onNpcSpawned(NpcSpawned npcSpawned)
{ {
final NPC npc = npcSpawned.getNpc(); NPC npc = npcSpawned.getNpc();
final String npcName = npc.getName(); highlightNpcIfMatch(npc);
if (npcName == null) if (memorizedNpcs.containsKey(npc.getIndex()))
{ {
return;
}
if (npcTags.contains(npc.getIndex()))
{
memorizeNpc(npc);
highlightedNpcs.add(npc);
spawnedNpcsThisTick.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); mn.getNpcNames().add(npcName);
highlightedNpcs.add(npc);
spawnedNpcsThisTick.add(npc);
break;
} }
} }
} }
@@ -428,12 +429,59 @@ public class NpcIndicatorsPlugin extends Plugin
return new WorldPoint(currWP.getX() - dx, currWP.getY() - dy, currWP.getPlane()); 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) private void memorizeNpc(NPC npc)
{ {
final int npcIndex = npc.getIndex(); final int npcIndex = npc.getIndex();
memorizedNpcs.putIfAbsent(npcIndex, new MemorizedNpc(npc)); 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() private void removeOldHighlightedRespawns()
{ {
deadNpcsToDisplay.values().removeIf(x -> x.getDiedOnTick() + x.getRespawnTime() <= client.getTickCount() + 1); deadNpcsToDisplay.values().removeIf(x -> x.getDiedOnTick() + x.getRespawnTime() <= client.getTickCount() + 1);
@@ -464,34 +512,21 @@ public class NpcIndicatorsPlugin extends Plugin
return; return;
} }
outer: Iterator<Map.Entry<Integer, MemorizedNpc>> 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()) for (NPC npc : client.getNpcs())
{ {
final String npcName = npc.getName(); highlightNpcIfMatch(npc);
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());
} }
} }
@@ -524,7 +559,7 @@ public class NpcIndicatorsPlugin extends Plugin
if (!mn.getPossibleRespawnLocations().isEmpty()) 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); deadNpcsToDisplay.put(mn.getNpcIndex(), mn);
} }
} }

View File

@@ -0,0 +1,84 @@
/*
* Copyright (c) 2019, GeChallengeM <https://github.com/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;
}
}

View File

@@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2017, Devin French <https://github.com/devinfrench> * Copyright (c) 2019, GeChallengeM <https://github.com/GeChallengeM>
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * 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 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * 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.client.config.Config;
import net.runelite.api.Prayer; 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), @ConfigItem(
RANGE(AnimationID.TZTOK_JAD_RANGE_ATTACK, Prayer.PROTECT_FROM_MISSILES); keyName = "AttackRange",
name = "NPC Attack range",
private final int animation; description = "The attack range of the NPC"
private final Prayer prayer; )
default int getRange()
JadAttack(int animation, Prayer prayer)
{ {
this.animation = animation; return 1;
this.prayer = prayer;
} }
}
public int getAnimation()
{
return animation;
}
public Prayer getPrayer()
{
return prayer;
}
}

View File

@@ -0,0 +1,89 @@
/*
* Copyright (c) 2018, GeChallengeM <https://github.com/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;
}
}

View File

@@ -0,0 +1,231 @@
/*
* Copyright (c) 2019, GeChallengeM <https://github.com/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<MemorizedNPC> 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();
}
}

View File

@@ -106,7 +106,7 @@ public class BatSolver
} }
public void calculateChanceOfPoison() private void calculateChanceOfPoison()
{ {
if (getType() == null) if (getType() == null)
{ {

View File

@@ -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 // 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 // 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, 16, 17, 55),
new SolutionSet(ThievingRoomType.LEFT_TURN, 1, 17, 38, 54), new SolutionSet(ThievingRoomType.LEFT_TURN, 1, 17, 38, 54),
@@ -147,12 +147,12 @@ public class SolutionSet
this.emptyChests = new HashSet<>(Arrays.asList(emptyChests)); this.emptyChests = new HashSet<>(Arrays.asList(emptyChests));
} }
public void addEmptyChest(int chestId) void addEmptyChest(int chestId)
{ {
emptyChests.add(chestId); emptyChests.add(chestId);
} }
public boolean containsChest(int chestId) boolean containsChest(int chestId)
{ {
return emptyChests.contains(chestId); return emptyChests.contains(chestId);
} }

View File

@@ -15,7 +15,7 @@ public class InstancePoint
private static final int CHUNK_SIZE = 8; private static final int CHUNK_SIZE = 8;
private static final double CHUNK_OFFSET = 3.5; 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.x = x;
this.y = y; this.y = y;
@@ -29,7 +29,7 @@ public class InstancePoint
this.rot = 0; 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 point = new Point(worldPoint.getX(), worldPoint.getY());
Point base = new Point(client.getBaseX(), client.getBaseY()); Point base = new Point(client.getBaseX(), client.getBaseY());
@@ -48,7 +48,7 @@ public class InstancePoint
return buildFromTile(base, point, rotation, new Point(x, y)); 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 deltaX = tile.getX() - base.getX();
int deltaY = tile.getY() - base.getY(); int deltaY = tile.getY() - base.getY();

View File

@@ -26,10 +26,10 @@ package net.runelite.client.plugins.raidsthieving;
public class RaidsThievingConstants public class RaidsThievingConstants
{ {
public static final int CLOSED_CHEST_ID = 29742; static final int CLOSED_CHEST_ID = 29742;
public static final int OPEN_EMPTY_CHEST = 29743; static final int OPEN_EMPTY_CHEST = 29743;
public static final int OPEN_FULL_CHEST_1 = 29744; static final int OPEN_FULL_CHEST_1 = 29744;
public static final int OPEN_FULL_CHEST_2 = 29745; static final int OPEN_FULL_CHEST_2 = 29745;
public static final int EMPTY_TROUGH = 29746; static final int EMPTY_TROUGH = 29746;
public static final int[] STORAGE = {29769, 29770, 29771, 29772}; public static final int[] STORAGE = {29769, 29770, 29771, 29772};
} }

View File

@@ -201,6 +201,12 @@ public class RaidsThievingPlugin extends Plugin
{ {
log.debug("Found poison splat"); log.debug("Found poison splat");
WorldPoint loc = WorldPoint.fromLocal(client, obj.getLocation()); WorldPoint loc = WorldPoint.fromLocal(client, obj.getLocation());
if (chests.get(loc) == null)
{
return;
}
chests.get(loc).setPoison(true); chests.get(loc).setPoison(true);
} }
} }
@@ -235,7 +241,7 @@ public class RaidsThievingPlugin extends Plugin
mapper = null; mapper = null;
} }
public int numberOfEmptyChestsFound() int numberOfEmptyChestsFound()
{ {
int total = 0; int total = 0;
for (ThievingChest chest : chests.values()) for (ThievingChest chest : chests.values())
@@ -248,7 +254,6 @@ public class RaidsThievingPlugin extends Plugin
return total; return total;
} }
private boolean checkForBats() private boolean checkForBats()
{ {
for (ThievingChest chest : chests.values()) for (ThievingChest chest : chests.values())
@@ -266,7 +271,7 @@ public class RaidsThievingPlugin extends Plugin
return false; return false;
} }
public int getChestId(WorldPoint worldPoint) int getChestId(WorldPoint worldPoint)
{ {
return chests.get(worldPoint).getChestId(); return chests.get(worldPoint).getChestId();
} }

View File

@@ -29,6 +29,8 @@ import java.awt.BorderLayout;
import java.awt.Color; import java.awt.Color;
import java.awt.Dimension; import java.awt.Dimension;
import java.awt.FlowLayout; import java.awt.FlowLayout;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.event.MouseAdapter; import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent; import java.awt.event.MouseEvent;
import java.awt.event.WindowAdapter; import java.awt.event.WindowAdapter;
@@ -169,12 +171,7 @@ class ScreenMarkerPanel extends JPanel
@Override @Override
public void mousePressed(MouseEvent mouseEvent) public void mousePressed(MouseEvent mouseEvent)
{ {
marker.getMarker().setName(nameInput.getText()); save();
plugin.updateConfig();
nameInput.setEditable(false);
updateNameActions(false);
requestFocusInWindow();
} }
@Override @Override
@@ -198,10 +195,7 @@ class ScreenMarkerPanel extends JPanel
@Override @Override
public void mousePressed(MouseEvent mouseEvent) public void mousePressed(MouseEvent mouseEvent)
{ {
nameInput.setEditable(false); cancel();
nameInput.setText(marker.getMarker().getName());
updateNameActions(false);
requestFocusInWindow();
} }
@Override @Override
@@ -252,6 +246,35 @@ class ScreenMarkerPanel extends JPanel
nameInput.setPreferredSize(new Dimension(0, 24)); nameInput.setPreferredSize(new Dimension(0, 24));
nameInput.getTextField().setForeground(Color.WHITE); nameInput.getTextField().setForeground(Color.WHITE);
nameInput.getTextField().setBorder(new EmptyBorder(0, 8, 0, 0)); 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(nameInput, BorderLayout.CENTER);
nameWrapper.add(nameActions, BorderLayout.EAST); nameWrapper.add(nameActions, BorderLayout.EAST);
@@ -359,10 +382,7 @@ class ScreenMarkerPanel extends JPanel
@Override @Override
public void mousePressed(MouseEvent mouseEvent) public void mousePressed(MouseEvent mouseEvent)
{ {
visible = !visible; toggle(!visible);
marker.getMarker().setVisible(visible);
plugin.updateConfig();
updateVisibility();
} }
@Override @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) private void updateNameActions(boolean saveAndCancel)
{ {
save.setVisible(saveAndCancel); save.setVisible(saveAndCancel);

View File

@@ -26,11 +26,30 @@ package net.runelite.client.plugins.shiftwalker;
import net.runelite.client.config.Config; import net.runelite.client.config.Config;
import net.runelite.client.config.ConfigGroup; import net.runelite.client.config.ConfigGroup;
// import net.runelite.client.config.ConfigItem; import net.runelite.client.config.ConfigItem;
@ConfigGroup("shiftwalkhere") @ConfigGroup("shiftwalkhere")
public interface ShiftWalkerConfig extends Config 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( @ConfigItem(

View File

@@ -50,7 +50,7 @@ public class ShiftWalkerPlugin extends Plugin
{ {
private static final String WALK_HERE = "Walk here"; private static final String WALK_HERE = "Walk here";
private static final String TAKE = "Take";
@Inject @Inject
private ShiftWalkerConfig config; private ShiftWalkerConfig config;
@@ -92,11 +92,20 @@ public class ShiftWalkerPlugin extends Plugin
void startPrioritizing() void startPrioritizing()
{ {
menuManager.addPriorityEntry(WALK_HERE); if (config.shiftLoot())
{
menuManager.addPriorityEntry(TAKE);
}
if (config.shiftWalk())
{
menuManager.addPriorityEntry(WALK_HERE);
}
} }
void stopPrioritizing() void stopPrioritizing()
{ {
menuManager.removePriorityEntry(TAKE);
menuManager.removePriorityEntry(WALK_HERE); menuManager.removePriorityEntry(WALK_HERE);
} }
} }

View File

@@ -27,7 +27,7 @@ package net.runelite.client.plugins.slayer;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
public class KnapsackSolver class KnapsackSolver
{ {
private List<Integer> reconstructItemsInSack(int[][] sackMatrix, List<Integer> items, int i, int w) private List<Integer> reconstructItemsInSack(int[][] sackMatrix, List<Integer> items, int i, int w)
@@ -49,7 +49,7 @@ public class KnapsackSolver
} }
} }
public int howMuchFitsInSack(List<Integer> items, int maxWeight) int howMuchFitsInSack(List<Integer> items, int maxWeight)
{ {
int itemCount = items.size(); int itemCount = items.size();

View File

@@ -29,17 +29,17 @@ public class NPCPresence
return name + "[" + combatLevel + "]"; return name + "[" + combatLevel + "]";
} }
public boolean shouldExist() boolean shouldExist()
{ {
return fadeTimer > 0; return fadeTimer > 0;
} }
public void tickExistence() void tickExistence()
{ {
fadeTimer--; fadeTimer--;
} }
public static NPCPresence buildPresence(NPC npc) static NPCPresence buildPresence(NPC npc)
{ {
return new NPCPresence(npc.getName(), npc.getCombatLevel()); return new NPCPresence(npc.getName(), npc.getCombatLevel());
} }

View File

@@ -36,6 +36,7 @@ import java.time.Instant;
import java.time.temporal.ChronoUnit; import java.time.temporal.ChronoUnit;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.HashSet;
import java.util.Iterator; import java.util.Iterator;
import java.util.List; import java.util.List;
import java.util.Set; 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.GameStateChanged;
import net.runelite.api.events.GameTick; import net.runelite.api.events.GameTick;
import net.runelite.api.events.InteractingChanged; import net.runelite.api.events.InteractingChanged;
import net.runelite.api.events.NpcDefinitionChanged;
import net.runelite.api.events.NpcDespawned; import net.runelite.api.events.NpcDespawned;
import net.runelite.api.events.NpcSpawned; import net.runelite.api.events.NpcSpawned;
import net.runelite.api.events.VarbitChanged; 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.ChatMessageBuilder;
import net.runelite.client.chat.ChatMessageManager; import net.runelite.client.chat.ChatMessageManager;
import net.runelite.client.config.ConfigManager; import net.runelite.client.config.ConfigManager;
import net.runelite.client.eventbus.EventBus;
import net.runelite.client.eventbus.Subscribe; import net.runelite.client.eventbus.Subscribe;
import net.runelite.client.events.ChatInput; import net.runelite.client.events.ChatInput;
import net.runelite.client.game.AsyncBufferedImage; import net.runelite.client.game.AsyncBufferedImage;
@@ -215,11 +216,8 @@ public class SlayerPlugin extends Plugin
@Inject @Inject
private ChatClient chatClient; private ChatClient chatClient;
@Inject
private EventBus eventBus;
@Getter(AccessLevel.PACKAGE) @Getter(AccessLevel.PACKAGE)
private List<NPC> highlightedTargets = new ArrayList<>(); private final Set<NPC> highlightedTargets = new HashSet<>();
@Getter(AccessLevel.PACKAGE) @Getter(AccessLevel.PACKAGE)
@Setter(AccessLevel.PACKAGE) @Setter(AccessLevel.PACKAGE)
@@ -349,8 +347,17 @@ public class SlayerPlugin extends Plugin
if (isTarget(npc, targetNames)) if (isTarget(npc, targetNames))
{ {
highlightedTargets.add(npc); 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); NPCPresence lingeringPresence = NPCPresence.buildPresence(npc);
lingeringPresences.add(lingeringPresence); lingeringPresences.add(lingeringPresence);
// log.debug("Presence of " + lingeringPresence.toString() + " now lingering");
} }
} }
@@ -390,7 +396,7 @@ public class SlayerPlugin extends Plugin
} }
} }
int estimateKillCount(List<NPCPresence> potentialKills, int gains) private int estimateKillCount(List<NPCPresence> potentialKills, int gains)
{ {
// failsafe to avoid calculating kill count if there were no slayer monsters around that could be killed on task // 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 // 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; streak = 1;
break; break;
case 1: case 1:
streak = Integer.parseInt(matches.get(0));
break;
case 3: case 3:
streak = Integer.parseInt(matches.get(0)); streak = Integer.parseInt(matches.get(0));
break; 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 // this is not the initial xp sent on login so these are new xp gains
int gains = slayerExp - cachedXp; 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 // potential npcs to give xp drop are current highlighted npcs and the lingering presences
List<NPCPresence> potentialNPCs = new ArrayList<>(); List<NPCPresence> potentialNPCs = new ArrayList<>(lingeringPresences);
//debugString.append("Lingering presences {");
for (NPCPresence presence : lingeringPresences)
{
potentialNPCs.add(presence);
// debugString.append(presence.toString());
// debugString.append(", ");
}
//debugString.append("}\nCurrent presences {");
for (NPC npc : highlightedTargets) for (NPC npc : highlightedTargets)
{ {
NPCPresence currentPresence = NPCPresence.buildPresence(npc); NPCPresence currentPresence = NPCPresence.buildPresence(npc);
potentialNPCs.add(currentPresence); potentialNPCs.add(currentPresence);
// debugString.append(currentPresence.toString());
// debugString.append(", ");
} }
//debugString.append("}");
//log.debug(debugString.toString());
int killCount = estimateKillCount(potentialNPCs, gains); int killCount = estimateKillCount(potentialNPCs, gains);
for (int i = 0; i < killCount; i++) for (int i = 0; i < killCount; i++)
@@ -751,7 +739,7 @@ public class SlayerPlugin extends Plugin
} }
@VisibleForTesting @VisibleForTesting
void killedOne() private void killedOne()
{ {
if (currentTask.getAmount() == 0) 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 // 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++) for (int i = 0; i < seq0.length; i++)
{ {
@@ -906,8 +894,7 @@ public class SlayerPlugin extends Plugin
if (task != null) if (task != null)
{ {
task.getNpcIds().stream() targetIds.addAll(task.getNpcIds());
.forEach(targetIds::add);
} }
} }
@@ -962,7 +949,7 @@ public class SlayerPlugin extends Plugin
rebuildTargetList(); rebuildTargetList();
} }
public AsyncBufferedImage getImageForTask(Task task) AsyncBufferedImage getImageForTask(Task task)
{ {
int itemSpriteId = ItemID.ENCHANTED_GEM; int itemSpriteId = ItemID.ENCHANTED_GEM;
if (task != null) if (task != null)
@@ -1048,6 +1035,11 @@ public class SlayerPlugin extends Plugin
return; return;
} }
if (task == null)
{
return;
}
if (TASK_STRING_VALIDATION.matcher(task.getTask()).find() || task.getTask().length() > TASK_STRING_MAX_LENGTH || 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) TASK_STRING_VALIDATION.matcher(task.getLocation()).find() || task.getLocation().length() > TASK_STRING_MAX_LENGTH)
{ {

View File

@@ -343,7 +343,7 @@ public class SlayerTaskPanel extends PluginPanel
changePauseState(paused); changePauseState(paused);
} }
static String htmlLabel(String key, long timeMillis) private static String htmlLabel(String key, long timeMillis)
{ {
if (timeMillis == Long.MAX_VALUE) 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); String valueStr = StackFormatter.quantityToRSDecimalStack(value);
return String.format(HTML_LABEL_TEMPLATE, ColorUtil.toHexColor(ColorScheme.LIGHT_GRAY_COLOR), return String.format(HTML_LABEL_TEMPLATE, ColorUtil.toHexColor(ColorScheme.LIGHT_GRAY_COLOR),

View File

@@ -31,14 +31,14 @@ import java.io.InputStreamReader;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
public class SlayerXpDropLookup class SlayerXpDropLookup
{ {
private Map<String, List<Double>> xpMap; private Map<String, List<Double>> xpMap;
// floating point math equality // floating point math equality
private static final double EPSILON = 1e-6; private static final double EPSILON = 1e-6;
void loadXpJson() private void loadXpJson()
{ {
final InputStream xpFile = getClass().getResourceAsStream("/slayer_xp.json"); final InputStream xpFile = getClass().getResourceAsStream("/slayer_xp.json");
Gson gson = new Gson(); Gson gson = new Gson();
@@ -76,7 +76,7 @@ public class SlayerXpDropLookup
* @param npc the npc we are estimating slayer xp for * @param npc the npc we are estimating slayer xp for
* @return our best guess for the slayer xp for this npc * @return our best guess for the slayer xp for this npc
*/ */
public double findXpForNpc(NPCPresence npc) double findXpForNpc(NPCPresence npc)
{ {
List<Double> xpCombatLevel = xpMap.get(npc.getName()); List<Double> xpCombatLevel = xpMap.get(npc.getName());
if (xpCombatLevel == null) if (xpCombatLevel == null)
@@ -127,7 +127,7 @@ public class SlayerXpDropLookup
return -1; return -1;
} }
public SlayerXpDropLookup() SlayerXpDropLookup()
{ {
loadXpJson(); loadXpJson();
} }

View File

@@ -26,12 +26,11 @@
*/ */
package net.runelite.client.plugins.slayer; package net.runelite.client.plugins.slayer;
import java.awt.BasicStroke;
import java.awt.Color; import java.awt.Color;
import java.awt.Dimension; import java.awt.Dimension;
import java.awt.Graphics2D; import java.awt.Graphics2D;
import java.awt.Polygon; import java.awt.Polygon;
import java.util.List; import java.util.Set;
import javax.inject.Inject; import javax.inject.Inject;
import net.runelite.api.Client; import net.runelite.api.Client;
import net.runelite.api.NPC; import net.runelite.api.NPC;
@@ -57,8 +56,7 @@ public class TargetClickboxOverlay extends Overlay
private final ModelOutlineRenderer modelOutliner; private final ModelOutlineRenderer modelOutliner;
@Inject @Inject
TargetClickboxOverlay(Client client, SlayerConfig config, SlayerPlugin plugin, TargetClickboxOverlay(Client client, SlayerConfig config, SlayerPlugin plugin, ModelOutlineRenderer modelOutlineRenderer)
ModelOutlineRenderer modelOutlineRenderer)
{ {
this.client = client; this.client = client;
this.config = config; this.config = config;
@@ -73,10 +71,16 @@ public class TargetClickboxOverlay extends Overlay
{ {
if (config.highlightTargets()) if (config.highlightTargets())
{ {
List<NPC> targets = plugin.getHighlightedTargets(); Set<NPC> targets = plugin.getHighlightedTargets();
for (NPC target : targets) for (NPC target : targets)
{ {
if (target == null || target.getName() == null)
{
continue;
}
Color coloration = config.getTargetColor(); Color coloration = config.getTargetColor();
if (plugin.isSuperior(target.getName())) if (plugin.isSuperior(target.getName()))
{ {
coloration = config.getSuperiorColor(); coloration = config.getSuperiorColor();
@@ -95,28 +99,36 @@ public class TargetClickboxOverlay extends Overlay
{ {
case SOUTH_WEST_TILE: case SOUTH_WEST_TILE:
LocalPoint lp1 = LocalPoint.fromWorld(client, actor.getWorldLocation()); LocalPoint lp1 = LocalPoint.fromWorld(client, actor.getWorldLocation());
if (lp1 == null)
{
return;
}
Polygon tilePoly1 = Perspective.getCanvasTilePoly(client, lp1); Polygon tilePoly1 = Perspective.getCanvasTilePoly(client, lp1);
renderPoly(graphics, color, tilePoly1); OverlayUtil.renderPolygon(graphics, tilePoly1, color);
break; break;
case TILE: case TILE:
int size = 1; int size = 1;
NPCDefinition composition = actor.getTransformedDefinition(); NPCDefinition composition = actor.getTransformedDefinition();
if (composition != null) if (composition != null)
{ {
size = composition.getSize(); size = composition.getSize();
} }
LocalPoint lp = actor.getLocalLocation(); LocalPoint lp = actor.getLocalLocation();
Polygon tilePoly = Perspective.getCanvasTileAreaPoly(client, lp, size); Polygon tilePoly = Perspective.getCanvasTileAreaPoly(client, lp, size);
renderPoly(graphics, color, tilePoly); OverlayUtil.renderPolygon(graphics, tilePoly, color);
break; break;
case HULL: case HULL:
Polygon objectClickbox = actor.getConvexHull(); Polygon objectClickbox = actor.getConvexHull();
renderPoly(graphics, color, objectClickbox); OverlayUtil.renderPolygon(graphics, objectClickbox, color);
break; break;
case THIN_OUTLINE: case THIN_OUTLINE:
modelOutliner.drawOutline(actor, 1, color); modelOutliner.drawOutline(actor, 1, color);
@@ -136,15 +148,23 @@ public class TargetClickboxOverlay extends Overlay
case TRUE_LOCATIONS: case TRUE_LOCATIONS:
size = 1; size = 1;
composition = actor.getTransformedDefinition(); composition = actor.getTransformedDefinition();
if (composition != null) if (composition != null)
{ {
size = composition.getSize(); size = composition.getSize();
} }
WorldPoint wp = actor.getWorldLocation(); WorldPoint wp = actor.getWorldLocation();
lp = LocalPoint.fromWorld(client, wp); lp = LocalPoint.fromWorld(client, wp);
if (lp == null)
{
return;
}
tilePoly = Perspective.getCanvasTileAreaPoly(client, lp, size); tilePoly = Perspective.getCanvasTileAreaPoly(client, lp, size);
renderPoly(graphics, color, tilePoly); OverlayUtil.renderPolygon(graphics, tilePoly, color);
break; 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);
}
}
} }

View File

@@ -29,9 +29,8 @@ package net.runelite.client.plugins.slayer;
import java.awt.Color; import java.awt.Color;
import java.awt.Dimension; import java.awt.Dimension;
import java.awt.Graphics2D; import java.awt.Graphics2D;
import java.util.List; import java.util.Set;
import javax.inject.Inject; import javax.inject.Inject;
import net.runelite.api.Client;
import net.runelite.api.NPC; import net.runelite.api.NPC;
import net.runelite.api.Point; import net.runelite.api.Point;
import net.runelite.client.ui.overlay.Overlay; import net.runelite.client.ui.overlay.Overlay;
@@ -41,15 +40,12 @@ import net.runelite.client.ui.overlay.OverlayUtil;
public class TargetMinimapOverlay extends Overlay public class TargetMinimapOverlay extends Overlay
{ {
private final Client client;
private final SlayerConfig config; private final SlayerConfig config;
private final SlayerPlugin plugin; private final SlayerPlugin plugin;
@Inject @Inject
TargetMinimapOverlay(Client client, SlayerConfig config, SlayerPlugin plugin) TargetMinimapOverlay(SlayerConfig config, SlayerPlugin plugin)
{ {
this.client = client;
this.config = config; this.config = config;
this.plugin = plugin; this.plugin = plugin;
setPosition(OverlayPosition.DYNAMIC); setPosition(OverlayPosition.DYNAMIC);
@@ -64,10 +60,16 @@ public class TargetMinimapOverlay extends Overlay
return null; return null;
} }
List<NPC> targets = plugin.getHighlightedTargets(); Set<NPC> targets = plugin.getHighlightedTargets();
for (NPC target : targets) for (NPC target : targets)
{ {
if (target == null || target.getName() == null)
{
continue;
}
Color coloration = config.getTargetColor(); Color coloration = config.getTargetColor();
if (plugin.isSuperior(target.getName())) if (plugin.isSuperior(target.getName()))
{ {
coloration = config.getSuperiorColor(); coloration = config.getSuperiorColor();

View File

@@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2017, Devin French <https://github.com/devinfrench> * Copyright (c) 2018, Aquivers <https://github.com/aquivers>
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * 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 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/ */
package net.runelite.client.plugins.fightcave;
import java.awt.Color; package net.runelite.client.plugins.tearsofguthix;
import java.awt.Dimension;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import javax.inject.Inject;
import net.runelite.api.Client; import net.runelite.api.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.Overlay;
import net.runelite.client.ui.overlay.OverlayPosition; import net.runelite.client.ui.overlay.OverlayPosition;
import net.runelite.client.ui.overlay.OverlayPriority; 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 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 TearsOfGuthixPlugin plugin;
private final PanelComponent panelComponent = new PanelComponent();
private final Client client;
private final FightCavePlugin plugin;
private final SpriteManager spriteManager;
private final PanelComponent imagePanelComponent = new PanelComponent();
@Inject @Inject
private JadOverlay(Client client, FightCavePlugin plugin, SpriteManager spriteManager) private Client client;
@Inject
private TearsOfGuthixExperienceOverlay(final TearsOfGuthixPlugin plugin)
{ {
setPosition(OverlayPosition.BOTTOM_RIGHT); setPosition(OverlayPosition.ABOVE_CHATBOX_RIGHT);
setPriority(OverlayPriority.HIGH); setPriority(OverlayPriority.LOW);
this.client = client;
this.plugin = plugin; this.plugin = plugin;
this.spriteManager = spriteManager;
} }
@Override @Override
public Dimension render(Graphics2D graphics) public Dimension render(Graphics2D graphics)
{ {
final JadAttack attack = plugin.getAttack(); if (plugin.getPlayerLowestSkill() == null)
if (attack == null)
{ {
return null; return null;
} }
final BufferedImage prayerImage = getPrayerImage(attack); panelComponent.getChildren().clear();
imagePanelComponent.getChildren().clear(); TableComponent tableComponent = new TableComponent();
imagePanelComponent.getChildren().add(new ImageComponent(prayerImage)); tableComponent.setColumnAlignments(TableAlignment.LEFT, TableAlignment.RIGHT);
imagePanelComponent.setBackgroundColor(client.isPrayerActive(attack.getPrayer())
? ComponentConstants.STANDARD_BACKGROUND_COLOR
: NOT_ACTIVATED_BACKGROUND_COLOR);
return imagePanelComponent.render(graphics); tableComponent.addRow(plugin.getPlayerLowestSkill().getName(), "Lvl - " + client.getRealSkillLevel(plugin.getPlayerLowestSkill()) + "");
}
private BufferedImage getPrayerImage(JadAttack attack) if (!tableComponent.isEmpty())
{ {
final int prayerSpriteID = attack == JadAttack.MAGIC ? SpriteID.PRAYER_PROTECT_FROM_MAGIC : SpriteID.PRAYER_PROTECT_FROM_MISSILES; panelComponent.getChildren().add(tableComponent);
return spriteManager.getSprite(prayerSpriteID, 0); }
return panelComponent.render(graphics);
} }
} }

View File

@@ -28,10 +28,13 @@ import java.time.Instant;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import javax.inject.Inject; import javax.inject.Inject;
import lombok.AccessLevel;
import lombok.Getter; import lombok.Getter;
import net.runelite.api.Client; import net.runelite.api.Client;
import net.runelite.api.DecorativeObject; import net.runelite.api.DecorativeObject;
import net.runelite.api.GameState;
import net.runelite.api.ObjectID; import net.runelite.api.ObjectID;
import net.runelite.api.Skill;
import net.runelite.api.events.DecorativeObjectDespawned; import net.runelite.api.events.DecorativeObjectDespawned;
import net.runelite.api.events.DecorativeObjectSpawned; import net.runelite.api.events.DecorativeObjectSpawned;
import net.runelite.api.events.GameStateChanged; import net.runelite.api.events.GameStateChanged;
@@ -58,20 +61,29 @@ public class TearsOfGuthixPlugin extends Plugin
@Inject @Inject
private TearsOfGuthixOverlay overlay; private TearsOfGuthixOverlay overlay;
@Getter @Inject
private TearsOfGuthixExperienceOverlay experienceOverlay;
@Getter(AccessLevel.PACKAGE)
private final Map<DecorativeObject, Instant> streams = new HashMap<>(); private final Map<DecorativeObject, Instant> streams = new HashMap<>();
@Getter(AccessLevel.PACKAGE)
private Skill playerLowestSkill = null;
@Override @Override
protected void startUp() protected void startUp()
{ {
overlayManager.add(overlay); overlayManager.add(overlay);
overlayManager.add(experienceOverlay);
} }
@Override @Override
protected void shutDown() protected void shutDown()
{ {
overlayManager.remove(overlay); overlayManager.remove(overlay);
overlayManager.remove(experienceOverlay);
streams.clear(); streams.clear();
playerLowestSkill = null;
} }
@Subscribe @Subscribe
@@ -84,6 +96,26 @@ public class TearsOfGuthixPlugin extends Plugin
case HOPPING: case HOPPING:
streams.clear(); 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 @Subscribe
@@ -112,4 +144,24 @@ public class TearsOfGuthixPlugin extends Plugin
DecorativeObject object = event.getDecorativeObject(); DecorativeObject object = event.getDecorativeObject();
streams.remove(object); 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;
}
} }

View File

@@ -1,17 +1,23 @@
package net.runelite.client.plugins.theatre; 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.Point;
import net.runelite.api.Projectile;
import net.runelite.api.coords.LocalPoint; import net.runelite.api.coords.LocalPoint;
import net.runelite.api.coords.WorldArea;
import net.runelite.api.coords.WorldPoint; import net.runelite.api.coords.WorldPoint;
import net.runelite.client.ui.overlay.OverlayUtil; 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; protected final Client client;
@@ -29,7 +35,7 @@ public abstract class RoomHandler
public abstract void onStop(); 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(); WorldPoint playerLocation = client.getLocalPlayer().getWorldLocation();
if (point.distanceTo(playerLocation) >= 32) if (point.distanceTo(playerLocation) >= 32)
@@ -71,14 +77,14 @@ public abstract class RoomHandler
Point textLocation = Perspective.getCanvasTextLocation(client, graphics, projectilePoint, text, 0); Point textLocation = Perspective.getCanvasTextLocation(client, graphics, projectilePoint, text, 0);
if (textLocation != null) if (textLocation != null)
{ {
if (projectileId == 1607) if (projectileId == 1607)
{ // range { // range
renderTextLocation(graphics, text, 17, Font.BOLD, new Color(57, 255, 20, 255), textLocation); renderTextLocation(graphics, text, 17, Font.BOLD, new Color(57, 255, 20, 255), textLocation);
} }
else if (projectileId == 1606) else if (projectileId == 1606)
{ //mage { //mage
renderTextLocation(graphics, text, 17, Font.BOLD, new Color(64, 224, 208, 255), textLocation); renderTextLocation(graphics, text, 17, Font.BOLD, new Color(64, 224, 208, 255), textLocation);
} }
else else
{ //Orb of death? i hope { //Orb of death? i hope
renderTextLocation(graphics, text, 20, Font.BOLD, Color.WHITE, textLocation); 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(); WorldPoint playerLocation = client.getLocalPlayer().getWorldLocation();
if (point.distanceTo(playerLocation) >= 32) if (point.distanceTo(playerLocation) >= 32)
{
return; return;
}
LocalPoint lp = LocalPoint.fromWorld(client, point); LocalPoint lp = LocalPoint.fromWorld(client, point);
if (lp == null) if (lp == null)
{
return; return;
}
Polygon poly = Perspective.getCanvasTilePoly(client, lp); Polygon poly = Perspective.getCanvasTilePoly(client, lp);
if (poly == null) if (poly == null)
{
return; return;
}
graphics.setColor(new Color(color.getRed(), color.getGreen(), color.getBlue(), outlineAlpha)); graphics.setColor(new Color(color.getRed(), color.getGreen(), color.getBlue(), outlineAlpha));
graphics.setStroke(new BasicStroke(strokeWidth)); graphics.setStroke(new BasicStroke(strokeWidth));
@@ -109,13 +121,15 @@ public abstract class RoomHandler
graphics.fill(poly); 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; int size = 1;
NPCDefinition composition = actor.getTransformedDefinition(); NPCDefinition composition = actor.getTransformedDefinition();
if (composition != null) if (composition != null)
{
size = composition.getSize(); size = composition.getSize();
}
LocalPoint lp = actor.getLocalLocation(); LocalPoint lp = actor.getLocalLocation();
Polygon tilePoly = Perspective.getCanvasTileAreaPoly(client, lp, size); Polygon tilePoly = Perspective.getCanvasTileAreaPoly(client, lp, size);
@@ -143,26 +157,6 @@ public abstract class RoomHandler
} }
} }
protected List<WorldPoint> getHitSquares(WorldPoint npcLoc, int npcSize, int thickness, boolean includeUnder)
{
List<WorldPoint> little = new WorldArea(npcLoc, npcSize, npcSize).toWorldPointList();
List<WorldPoint> big = new WorldArea(npcLoc.getX() - thickness, npcLoc.getY() - thickness, npcSize + (thickness * 2), npcSize + (thickness * 2), npcLoc.getPlane()).toWorldPointList();
if (!includeUnder)
{
for (Iterator<WorldPoint> it = big.iterator(); it.hasNext(); )
{
WorldPoint p = it.next();
if (little.contains(p))
{
it.remove();
}
}
}
return big;
}
protected String twoDigitString(long number) protected String twoDigitString(long number)
{ {

View File

@@ -8,30 +8,15 @@
package net.runelite.client.plugins.theatre; package net.runelite.client.plugins.theatre;
import java.awt.Color;
import net.runelite.client.config.Config; import net.runelite.client.config.Config;
import net.runelite.client.config.ConfigGroup; import net.runelite.client.config.ConfigGroup;
import net.runelite.client.config.ConfigItem; import net.runelite.client.config.ConfigItem;
import java.awt.*;
@ConfigGroup("Theatre") @ConfigGroup("Theatre")
public interface TheatreConfig extends Config public interface TheatreConfig extends Config
{ {
enum NYLOCAS
{
NONE,
MAGE,
MELEE,
RANGER
}
enum NYLOOPTION
{
NONE,
TILE,
TIMER
}
@ConfigItem( @ConfigItem(
position = 0, position = 0,
keyName = "showMaidenBloodToss", keyName = "showMaidenBloodToss",
@@ -39,7 +24,7 @@ public interface TheatreConfig extends Config
description = "Displays the tile location where tossed blood will land.", description = "Displays the tile location where tossed blood will land.",
group = "Maiden" group = "Maiden"
) )
default boolean showMaidenBloodToss() default boolean showMaidenBloodToss()
{ {
return true; return true;
} }
@@ -51,7 +36,19 @@ public interface TheatreConfig extends Config
description = "Show the tiles that blood spawns will travel to.", description = "Show the tiles that blood spawns will travel to.",
group = "Maiden" 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; return true;
} }
@@ -63,7 +60,7 @@ public interface TheatreConfig extends Config
description = "Displays Bloat's status (asleep, wake, and enrage) using color code.", description = "Displays Bloat's status (asleep, wake, and enrage) using color code.",
group = "Bloat" group = "Bloat"
) )
default boolean showBloatIndicator() default boolean showBloatIndicator()
{ {
return true; return true;
} }
@@ -75,7 +72,7 @@ public interface TheatreConfig extends Config
description = "Highlights the falling hands inside Bloat.", description = "Highlights the falling hands inside Bloat.",
group = "Bloat" group = "Bloat"
) )
default boolean showBloatHands() default boolean showBloatHands()
{ {
return true; return true;
} }
@@ -87,8 +84,8 @@ public interface TheatreConfig extends Config
description = "", description = "",
group = "Bloat" group = "Bloat"
) )
default boolean BloatFeetIndicatorRaveEdition() default boolean BloatFeetIndicatorRaveEdition()
{ {
return false; 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.", description = "An overlay will appear that counts the amount of Nylocas in the room.",
group = "Nylocas" group = "Nylocas"
) )
default boolean showNylocasAmount() default boolean showNylocasAmount()
{ {
return true; return true;
} }
/** /**
@ConfigItem( * @ConfigItem( position = 8,
position = 8, * keyName = "showNylocasSpawns",
keyName = "showNylocasSpawns", * name = "Show Nylocas Pre-spawns",
name = "Show Nylocas Pre-spawns", * description = "Know the contents of the next upcoming wave."
description = "Know the contents of the next upcoming wave." * )
) * default boolean showNylocasSpawns()
default boolean showNylocasSpawns() * {
{ * return true;
return true; * }
} * @ConfigItem( position = 9,
* keyName = "highlightNyloRoles",
@ConfigItem( * name = "Highlight Nylo Prespawns",
position = 9, * description = "Highlights the next upcoming wave based on role. FOR BEGINNERS"
keyName = "highlightNyloRoles", * )
name = "Highlight Nylo Prespawns", * default NYLOCAS highlightNyloRoles()
description = "Highlights the next upcoming wave based on role. FOR BEGINNERS" * {
) * return NYLOCAS.NONE;
default NYLOCAS highlightNyloRoles() * }
{ * @ConfigItem( position = 10,
return NYLOCAS.NONE; * keyName = "highlightNyloParents",
} * name = "Show Nylo Parents (Un-used)",
* description = "Highlight the Nylocas that spawn outside the center."
@ConfigItem( * )
position = 10, * default boolean highlightNyloParents()
keyName = "highlightNyloParents", * {
name = "Show Nylo Parents (Un-used)", * return true;
description = "Highlight the Nylocas that spawn outside the center." * }
) **/
default boolean highlightNyloParents()
{
return true;
}
**/
@ConfigItem( @ConfigItem(
position = 11, position = 11,
@@ -218,7 +210,7 @@ public interface TheatreConfig extends Config
description = "Marks the tiles of Sotetseg's maze while in the underworld.", description = "Marks the tiles of Sotetseg's maze while in the underworld.",
group = "Sotetseg" group = "Sotetseg"
) )
default boolean showSotetsegSolo() default boolean showSotetsegSolo()
{ {
return true; return true;
} }
@@ -234,6 +226,7 @@ public interface TheatreConfig extends Config
{ {
return Color.WHITE; return Color.WHITE;
} }
@ConfigItem( @ConfigItem(
position = 15, position = 15,
keyName = "showXarpusHeals", keyName = "showXarpusHeals",
@@ -302,10 +295,10 @@ public interface TheatreConfig extends Config
group = "Verzik" group = "Verzik"
) )
default boolean VerzikTankTile() default boolean VerzikTankTile()
{ {
return false; return false;
} }
@ConfigItem( @ConfigItem(
position = 22, position = 22,
keyName = "verzikrangeattacks", keyName = "verzikrangeattacks",
@@ -314,10 +307,10 @@ public interface TheatreConfig extends Config
group = "Verzik" group = "Verzik"
) )
default boolean verzikRangeAttacks() default boolean verzikRangeAttacks()
{ {
return true; return true;
} }
@ConfigItem( @ConfigItem(
position = 23, position = 23,
keyName = "extratimers", keyName = "extratimers",
@@ -329,7 +322,7 @@ public interface TheatreConfig extends Config
{ {
return false; return false;
} }
@ConfigItem( @ConfigItem(
position = 24, position = 24,
keyName = "p1attacks", keyName = "p1attacks",
@@ -341,7 +334,7 @@ public interface TheatreConfig extends Config
{ {
return true; return true;
} }
@ConfigItem( @ConfigItem(
position = 25, position = 25,
keyName = "p2attacks", keyName = "p2attacks",
@@ -353,7 +346,7 @@ public interface TheatreConfig extends Config
{ {
return true; return true;
} }
@ConfigItem( @ConfigItem(
position = 26, position = 26,
keyName = "p3attacks", keyName = "p3attacks",
@@ -365,4 +358,19 @@ public interface TheatreConfig extends Config
{ {
return true; return true;
} }
enum NYLOCAS
{
NONE,
MAGE,
MELEE,
RANGER
}
enum NYLOOPTION
{
NONE,
TILE,
TIMER
}
} }

View File

@@ -1,6 +1,6 @@
package net.runelite.client.plugins.theatre; package net.runelite.client.plugins.theatre;
public class TheatreConstant public class TheatreConstant
{ {
public static final int MAIDEN_BLOOD_THROW = 1579; public static final int MAIDEN_BLOOD_THROW = 1579;

View File

@@ -8,28 +8,30 @@
package net.runelite.client.plugins.theatre; package net.runelite.client.plugins.theatre;
import java.awt.*; import java.awt.Dimension;
import java.util.*; import java.awt.Graphics2D;
import javax.inject.Inject; 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.Overlay;
import net.runelite.client.ui.overlay.OverlayLayer; import net.runelite.client.ui.overlay.OverlayLayer;
import net.runelite.client.ui.overlay.OverlayPosition; import net.runelite.client.ui.overlay.OverlayPosition;
import net.runelite.client.ui.overlay.OverlayPriority; import net.runelite.client.ui.overlay.OverlayPriority;
public class TheatreOverlay extends Overlay public class TheatreOverlay extends Overlay
{ {
private final Client client; private final Client client;
private final TheatrePlugin plugin; private final TheatrePlugin plugin;
private final TheatreConfig config; private final TheatreConfig config;
private final ModelOutlineRenderer modelOutline;
@Inject @Inject
private TheatreOverlay(Client client, TheatrePlugin plugin, TheatreConfig config) private TheatreOverlay(Client client, TheatrePlugin plugin, TheatreConfig config, ModelOutlineRenderer modelOutline)
{ {
this.client = client; this.client = client;
this.plugin = plugin; this.plugin = plugin;
this.config = config; this.config = config;
this.modelOutline = modelOutline;
setPosition(OverlayPosition.DYNAMIC); setPosition(OverlayPosition.DYNAMIC);
setPriority(OverlayPriority.HIGH); setPriority(OverlayPriority.HIGH);

View File

@@ -9,32 +9,44 @@
package net.runelite.client.plugins.theatre; package net.runelite.client.plugins.theatre;
import com.google.inject.Provides; 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.AccessLevel;
import lombok.Getter; import lombok.Getter;
import lombok.Setter; import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import net.runelite.api.Client; import net.runelite.api.Client;
import java.util.LinkedList; import net.runelite.api.events.AnimationChanged;
import java.util.List; import net.runelite.api.events.ChatMessage;
import net.runelite.api.events.*; import net.runelite.api.events.ConfigChanged;
import net.runelite.client.config.ConfigManager; import net.runelite.api.events.GameTick;
import net.runelite.client.eventbus.Subscribe; import net.runelite.api.events.GroundObjectSpawned;
import net.runelite.client.plugins.Plugin; 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.Widget;
import net.runelite.api.widgets.WidgetID; import net.runelite.api.widgets.WidgetID;
import net.runelite.api.widgets.WidgetInfo; 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.PluginDescriptor;
import net.runelite.client.plugins.PluginType; import net.runelite.client.plugins.PluginType;
import net.runelite.client.plugins.theatre.rooms.BloatHandler; import net.runelite.client.plugins.theatre.rooms.BloatHandler;
import net.runelite.client.plugins.theatre.rooms.MaidenHandler; import net.runelite.client.plugins.theatre.rooms.MaidenHandler;
import net.runelite.client.plugins.theatre.rooms.SotetsegHandler; import net.runelite.client.plugins.theatre.rooms.SotetsegHandler;
import net.runelite.client.plugins.theatre.rooms.VerzikHandler; 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.nylocas.NyloHandler;
import net.runelite.client.plugins.theatre.rooms.xarpus.XarpusHandler;
import net.runelite.client.ui.overlay.OverlayManager; import net.runelite.client.ui.overlay.OverlayManager;
import javax.inject.Inject;
import java.awt.*;
@PluginDescriptor( @PluginDescriptor(
name = "Theatre of Blood", name = "Theatre of Blood",
description = "All-in-one plugin for Theatre of Blood.", description = "All-in-one plugin for Theatre of Blood.",
@@ -43,9 +55,9 @@ import java.awt.*;
enabledByDefault = false enabledByDefault = false
) )
public class TheatrePlugin extends Plugin @Slf4j
public class TheatrePlugin extends Plugin
{ {
@Getter(AccessLevel.PUBLIC) @Getter(AccessLevel.PUBLIC)
@Setter(AccessLevel.PUBLIC) @Setter(AccessLevel.PUBLIC)
private TheatreRoom room; private TheatreRoom room;
@@ -83,6 +95,9 @@ public class TheatrePlugin extends Plugin
@Inject @Inject
private TheatreConfig config; private TheatreConfig config;
@Inject
private ModelOutlineRenderer modelOutline;
@Provides @Provides
TheatreConfig getConfig(ConfigManager configManager) TheatreConfig getConfig(ConfigManager configManager)
{ {
@@ -94,7 +109,7 @@ public class TheatrePlugin extends Plugin
{ {
room = TheatreRoom.UNKNOWN; room = TheatreRoom.UNKNOWN;
maidenHandler = new MaidenHandler(client, this, config); maidenHandler = new MaidenHandler(client, this, config, modelOutline);
bloatHandler = new BloatHandler(client, this, config); bloatHandler = new BloatHandler(client, this, config);
nyloHandler = new NyloHandler(client, this, config); nyloHandler = new NyloHandler(client, this, config);
sotetsegHandler = new SotetsegHandler(client, this, config); sotetsegHandler = new SotetsegHandler(client, this, config);
@@ -131,26 +146,56 @@ public class TheatrePlugin extends Plugin
overlayManager.remove(overlay); 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 @Subscribe
public void onNpcSpawned(NpcSpawned event) public void onNpcSpawned(NpcSpawned event)
{ {
if (maidenHandler != null) if (maidenHandler != null)
{
maidenHandler.onNpcSpawned(event); maidenHandler.onNpcSpawned(event);
}
if (bloatHandler != null) if (bloatHandler != null)
{
bloatHandler.onNpcSpawned(event); bloatHandler.onNpcSpawned(event);
}
if (nyloHandler != null) if (nyloHandler != null)
{
nyloHandler.onNpcSpawned(event); nyloHandler.onNpcSpawned(event);
}
if (sotetsegHandler != null) if (sotetsegHandler != null)
{
sotetsegHandler.onNpcSpawned(event); sotetsegHandler.onNpcSpawned(event);
}
if (xarpusHandler != null) if (xarpusHandler != null)
{
xarpusHandler.onNpcSpawned(event); xarpusHandler.onNpcSpawned(event);
}
if (verzikHandler != null) if (verzikHandler != null)
{
verzikHandler.onNpcSpawned(event); verzikHandler.onNpcSpawned(event);
}
} }
@@ -158,19 +203,29 @@ public class TheatrePlugin extends Plugin
public void onNpcDespawned(NpcDespawned event) public void onNpcDespawned(NpcDespawned event)
{ {
if (maidenHandler != null) if (maidenHandler != null)
{
maidenHandler.onNpcDespawned(event); maidenHandler.onNpcDespawned(event);
}
if (bloatHandler != null) if (bloatHandler != null)
{
bloatHandler.onNpcDespawned(event); bloatHandler.onNpcDespawned(event);
}
if (nyloHandler != null) if (nyloHandler != null)
{
nyloHandler.onNpcDespawned(event); nyloHandler.onNpcDespawned(event);
}
if (sotetsegHandler != null) if (sotetsegHandler != null)
{
sotetsegHandler.onNpcDespawned(event); sotetsegHandler.onNpcDespawned(event);
}
if (xarpusHandler != null) if (xarpusHandler != null)
{
xarpusHandler.onNpcDespawned(event); xarpusHandler.onNpcDespawned(event);
}
} }
@@ -178,7 +233,18 @@ public class TheatrePlugin extends Plugin
public void onAnimationChanged(AnimationChanged event) public void onAnimationChanged(AnimationChanged event)
{ {
if (verzikHandler != null) if (verzikHandler != null)
{
verzikHandler.onAnimationChanged(event); verzikHandler.onAnimationChanged(event);
}
}
@Subscribe
public void onChatMessage(ChatMessage event)
{
if (maidenHandler != null)
{
maidenHandler.onChatMessage(event);
}
} }
@Subscribe @Subscribe
@@ -204,22 +270,34 @@ public class TheatrePlugin extends Plugin
public void onGameTick(GameTick event) public void onGameTick(GameTick event)
{ {
if (maidenHandler != null) if (maidenHandler != null)
{
maidenHandler.onGameTick(); maidenHandler.onGameTick();
}
if (bloatHandler != null) if (bloatHandler != null)
{
bloatHandler.onGameTick(); bloatHandler.onGameTick();
}
if (nyloHandler != null) if (nyloHandler != null)
{
nyloHandler.onGameTick(); nyloHandler.onGameTick();
}
if (sotetsegHandler != null) if (sotetsegHandler != null)
{
sotetsegHandler.onGameTick(); sotetsegHandler.onGameTick();
}
if (xarpusHandler != null) if (xarpusHandler != null)
{
xarpusHandler.onGameTick(); xarpusHandler.onGameTick();
}
if (verzikHandler != null) if (verzikHandler != null)
{
verzikHandler.onGameTick(); verzikHandler.onGameTick();
}
if (widget == null) if (widget == null)
{ {
@@ -315,27 +393,37 @@ public class TheatrePlugin extends Plugin
public void onGroundObjectSpawned(GroundObjectSpawned event) public void onGroundObjectSpawned(GroundObjectSpawned event)
{ {
if (sotetsegHandler != null) if (sotetsegHandler != null)
{
sotetsegHandler.onGroundObjectSpawned(event); sotetsegHandler.onGroundObjectSpawned(event);
}
if (xarpusHandler != null) if (xarpusHandler != null)
{
xarpusHandler.onGroundObjectSpawned(event); xarpusHandler.onGroundObjectSpawned(event);
}
} }
@Subscribe @Subscribe
public void onConfigChanged(ConfigChanged event) public void onConfigChanged(ConfigChanged event)
{ {
if (nyloHandler != null) if (nyloHandler != null)
{
nyloHandler.onConfigChanged(); nyloHandler.onConfigChanged();
}
} }
@Subscribe @Subscribe
public void onVarbitChanged(VarbitChanged event) public void onVarbitChanged(VarbitChanged event)
{ {
if (bloatHandler != null) if (bloatHandler != null)
{
bloatHandler.onVarbitChanged(event); bloatHandler.onVarbitChanged(event);
}
if (xarpusHandler != null) if (xarpusHandler != null)
{
xarpusHandler.onVarbitChanged(event); xarpusHandler.onVarbitChanged(event);
}
} }
@Subscribe @Subscribe

Some files were not shown because too many files have changed in this diff Show More