diff --git a/cache/pom.xml b/cache/pom.xml
index c9828136d1..077d2174cf 100644
--- a/cache/pom.xml
+++ b/cache/pom.xml
@@ -29,7 +29,7 @@
net.runelite
runelite-parent
- 1.10.26.4
+ 1.10.27
cache
diff --git a/cache/src/main/java/net/runelite/cache/FontManager.java b/cache/src/main/java/net/runelite/cache/FontManager.java
new file mode 100644
index 0000000000..6af2da4c06
--- /dev/null
+++ b/cache/src/main/java/net/runelite/cache/FontManager.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 2024, Christopher Brown
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package net.runelite.cache;
+
+import net.runelite.cache.definitions.FontDefinition;
+import net.runelite.cache.definitions.loaders.FontLoader;
+import net.runelite.cache.fs.Archive;
+import net.runelite.cache.fs.FSFile;
+import net.runelite.cache.fs.Index;
+import net.runelite.cache.fs.Storage;
+import net.runelite.cache.fs.Store;
+import net.runelite.cache.util.Djb2;
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
+
+public class FontManager
+{
+ private final Store store;
+ private final Map fonts = new HashMap<>();
+
+ public FontManager(Store store)
+ {
+ this.store = store;
+ }
+
+ public void load() throws IOException
+ {
+ Storage storage = store.getStorage();
+ Index index = store.getIndex(IndexType.FONTS);
+ FontLoader fontLoader = new FontLoader();
+
+ for (Archive archive : index.getArchives())
+ {
+ byte[] data = storage.loadArchive(archive);
+ FSFile file = archive.getFiles(data).getFiles().get(0);
+ FontDefinition fontDefinition = fontLoader.load(file.getContents());
+
+ fonts.put(archive.getNameHash(), fontDefinition);
+ }
+ }
+
+ public FontDefinition getFont(int nameHash)
+ {
+ return fonts.get(nameHash);
+ }
+
+ public FontDefinition findFontByName(String name)
+ {
+ int nameHash = Djb2.hash(name);
+ return this.getFont(nameHash);
+ }
+}
diff --git a/cache/src/main/java/net/runelite/cache/FontName.java b/cache/src/main/java/net/runelite/cache/FontName.java
new file mode 100644
index 0000000000..202d0b1d63
--- /dev/null
+++ b/cache/src/main/java/net/runelite/cache/FontName.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2024, Christopher Brown
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package net.runelite.cache;
+
+public enum FontName
+{
+ PLAIN_11("p11_full"),
+ PLAIN_12("p12_full"),
+ BOLD_12("b12_full"),
+ VERDANA_11("verdana_11pt_regular"),
+ VERDANA_13("verdana_13pt_regular"),
+ VERDANA_15("verdana_15pt_regular");
+
+ private String name;
+
+ FontName(String name)
+ {
+ this.name = name;
+ }
+
+ public String getName()
+ {
+ return this.name;
+ }
+}
diff --git a/cache/src/main/java/net/runelite/cache/MapImageDumper.java b/cache/src/main/java/net/runelite/cache/MapImageDumper.java
index 83b7d5a426..eea52a5495 100644
--- a/cache/src/main/java/net/runelite/cache/MapImageDumper.java
+++ b/cache/src/main/java/net/runelite/cache/MapImageDumper.java
@@ -41,10 +41,12 @@
import lombok.experimental.Accessors;
import lombok.extern.slf4j.Slf4j;
import net.runelite.cache.definitions.AreaDefinition;
+import net.runelite.cache.definitions.FontDefinition;
import net.runelite.cache.definitions.ObjectDefinition;
import net.runelite.cache.definitions.OverlayDefinition;
import net.runelite.cache.definitions.SpriteDefinition;
import net.runelite.cache.definitions.UnderlayDefinition;
+import net.runelite.cache.definitions.WorldMapElementDefinition;
import net.runelite.cache.definitions.loaders.OverlayLoader;
import net.runelite.cache.definitions.loaders.SpriteLoader;
import net.runelite.cache.definitions.loaders.UnderlayLoader;
@@ -94,6 +96,8 @@ public class MapImageDumper
private final RegionLoader regionLoader;
private final AreaManager areas;
private final SpriteManager sprites;
+ private final FontManager fonts;
+ private final WorldMapManager worldMapManager;
private RSTextureProvider rsTextureProvider;
private final ObjectManager objectManager;
@@ -117,6 +121,10 @@ public class MapImageDumper
@Setter
private boolean renderIcons = true;
+ @Getter
+ @Setter
+ private boolean renderLabels = true;
+
@Getter
@Setter
private boolean transparency = false;
@@ -136,6 +144,8 @@ public MapImageDumper(Store store, RegionLoader regionLoader)
this.regionLoader = regionLoader;
this.areas = new AreaManager(store);
this.sprites = new SpriteManager(store);
+ this.fonts = new FontManager(store);
+ this.worldMapManager = new WorldMapManager(store);
this.objectManager = new ObjectManager(store);
}
@@ -218,6 +228,8 @@ public MapImageDumper load() throws IOException
areas.load();
sprites.load();
loadSprites();
+ fonts.load();
+ worldMapManager.load();
return this;
}
@@ -253,6 +265,7 @@ public BufferedImage drawMap(int z)
drawMap(image, z);
drawObjects(image, z);
drawMapIcons(image, z);
+ drawMapLabels(image, z);
return image;
}
@@ -919,6 +932,57 @@ private void drawMapIcons(BufferedImage image, int z)
}
}
+ private void drawMapLabels(BufferedImage image, int z)
+ {
+ if (!renderLabels)
+ {
+ return;
+ }
+
+ FontName[] fontSizes = new FontName[] { FontName.VERDANA_11, FontName.VERDANA_13, FontName.VERDANA_15 };
+ List elements = worldMapManager.getElements();
+ for (WorldMapElementDefinition element : elements)
+ {
+ AreaDefinition area = areas.getArea(element.getAreaDefinitionId());
+ Position worldPosition = element.getWorldPosition();
+ if (area == null || area.getName() == null || worldPosition.getZ() != z)
+ {
+ continue;
+ }
+
+ FontName fontSize = fontSizes[area.getTextScale()];
+ FontDefinition font = fonts.findFontByName(fontSize.getName());
+ String areaLabel = area.getName();
+ String[] lines = areaLabel.split("
");
+ int ascent = 0;
+
+ for (String line : lines)
+ {
+ int advance = 0;
+ int stringWidth = font.stringWidth(line);
+ for (int i = 0; i < line.length(); ++i)
+ {
+ char c = line.charAt(i);
+ SpriteDefinition sprite = sprites.findSpriteByArchiveName(fontSize.getName(), c);
+ if (sprite.getWidth() != 0 && sprite.getHeight() != 0)
+ {
+ int drawX = worldPosition.getX() - regionLoader.getLowestX().getBaseX();
+ int drawY = regionLoader.getHighestY().getBaseY() - worldPosition.getY() + Region.Y - 2;
+ blitGlyph(image,
+ (drawX * MAP_SCALE) + advance - (stringWidth / 2),
+ (drawY * MAP_SCALE) + ascent - (font.getAscent() / 2),
+ area.getTextColor(),
+ sprite
+ );
+ }
+
+ advance += font.getAdvances()[c];
+ }
+ ascent += font.getAscent() / 2;
+ }
+ }
+ }
+
private ObjectDefinition findObject(int id)
{
return objectManager.getObject(id);
@@ -1032,13 +1096,9 @@ private void drawMapIcons(BufferedImage img, Region region, int z, int drawBaseX
{
int localX = location.getPosition().getX() - region.getBaseX();
int localY = location.getPosition().getY() - region.getBaseY();
- boolean isBridge = (region.getTileSetting(1, localX, localY) & 2) != 0;
- int tileZ = z + (isBridge ? 1 : 0);
- int localZ = location.getPosition().getZ();
- if (z != 0 && localZ != tileZ)
+ if (z != location.getPosition().getZ())
{
- // draw all icons on z=0
continue;
}
@@ -1058,11 +1118,36 @@ private void drawMapIcons(BufferedImage img, Region region, int z, int drawBaseX
assert sprite != null;
blitIcon(img,
- 2 + (drawX * MAP_SCALE) - (sprite.getMaxWidth() / 2),
- 2 + (drawY * MAP_SCALE) - (sprite.getMaxHeight() / 2),
+ (drawX * MAP_SCALE) - (sprite.getMaxWidth() / 2),
+ (drawY * MAP_SCALE) - (sprite.getMaxHeight() / 2),
sprite);
}
}
+
+ // Draw the intermap link icons which are not stored with the map locations
+ List elements = worldMapManager.getElements();
+ for (WorldMapElementDefinition element : elements)
+ {
+ AreaDefinition area = areas.getArea(element.getAreaDefinitionId());
+ Position worldPosition = element.getWorldPosition();
+ int regionX = worldPosition.getX() / Region.X;
+ int regionY = worldPosition.getY() / Region.Y;
+
+ if (area == null || area.getName() != null || worldPosition.getZ() != z || regionX != region.getRegionX() || regionY != region.getRegionY())
+ {
+ continue;
+ }
+
+ int localX = worldPosition.getX() - region.getBaseX();
+ int localY = worldPosition.getY() - region.getBaseY();
+ int drawX = drawBaseX + localX;
+ int drawY = drawBaseY + (Region.Y - 1 - localY);
+ SpriteDefinition sprite = sprites.findSprite(area.spriteId, 0);
+ blitIcon(img,
+ (drawX * MAP_SCALE) - (sprite.getMaxWidth() / 2),
+ (drawY * MAP_SCALE) - (sprite.getMaxHeight() / 2),
+ sprite);
+ }
}
private void loadRegions() throws IOException
@@ -1164,4 +1249,27 @@ private void blitIcon(BufferedImage dst, int x, int y, SpriteDefinition sprite)
}
}
}
+
+ private void blitGlyph(BufferedImage dst, int x, int y, int color, SpriteDefinition glyph)
+ {
+ int[] pixels = glyph.getPixels();
+ int[] shadowPixels = new int[pixels.length];
+ for (int i = 0; i < pixels.length; ++i)
+ {
+ if (pixels[i] != 0)
+ {
+ pixels[i] = color;
+ shadowPixels[i] = 0xFF000000;
+ }
+ }
+ SpriteDefinition shadow = new SpriteDefinition();
+ shadow.setPixels(shadowPixels);
+ shadow.setOffsetX(glyph.getOffsetX());
+ shadow.setOffsetY(glyph.getOffsetY());
+ shadow.setWidth(glyph.getWidth());
+ shadow.setHeight(glyph.getHeight());
+
+ blitIcon(dst, x + 1, y + 1, shadow);
+ blitIcon(dst, x, y, glyph);
+ }
}
diff --git a/cache/src/main/java/net/runelite/cache/SpriteManager.java b/cache/src/main/java/net/runelite/cache/SpriteManager.java
index a18dd4f6ba..7c49040a87 100644
--- a/cache/src/main/java/net/runelite/cache/SpriteManager.java
+++ b/cache/src/main/java/net/runelite/cache/SpriteManager.java
@@ -31,6 +31,8 @@
import java.io.IOException;
import java.util.Collection;
import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
import net.runelite.cache.definitions.SpriteDefinition;
import net.runelite.cache.definitions.exporters.SpriteExporter;
import net.runelite.cache.definitions.loaders.SpriteLoader;
@@ -39,11 +41,13 @@
import net.runelite.cache.fs.Index;
import net.runelite.cache.fs.Storage;
import net.runelite.cache.fs.Store;
+import net.runelite.cache.util.Djb2;
public class SpriteManager implements SpriteProvider
{
private final Store store;
private final Multimap sprites = LinkedListMultimap.create();
+ private final Map spriteIdsByArchiveNameHash = new HashMap<>();
public SpriteManager(Store store)
{
@@ -65,6 +69,7 @@ public void load() throws IOException
for (SpriteDefinition sprite : defs)
{
sprites.put(sprite.getId(), sprite);
+ spriteIdsByArchiveNameHash.put(a.getNameHash(), sprite.getId());
}
}
}
@@ -93,11 +98,23 @@ public BufferedImage getSpriteImage(SpriteDefinition sprite)
return image;
}
+ public SpriteDefinition findSpriteByArchiveName(String name, int frameId)
+ {
+ int nameHash = Djb2.hash(name);
+ Integer spriteId = spriteIdsByArchiveNameHash.get(nameHash);
+ if (spriteId != null)
+ {
+ return this.findSprite(spriteId, frameId);
+ }
+
+ return null;
+ }
+
public void export(File outDir) throws IOException
{
for (SpriteDefinition sprite : sprites.values())
{
- // I don't know why this happens
+ // Some sprites like ones for non-printable font characters do not have sizes
if (sprite.getHeight() <= 0 || sprite.getWidth() <= 0)
{
continue;
diff --git a/cache/src/main/java/net/runelite/cache/WorldMapManager.java b/cache/src/main/java/net/runelite/cache/WorldMapManager.java
new file mode 100644
index 0000000000..d40d0cfd0d
--- /dev/null
+++ b/cache/src/main/java/net/runelite/cache/WorldMapManager.java
@@ -0,0 +1,124 @@
+/*
+ * Copyright (c) 2024, Christopher Brown
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package net.runelite.cache;
+
+import net.runelite.cache.definitions.ScriptDefinition;
+import net.runelite.cache.definitions.WorldMapCompositeDefinition;
+import net.runelite.cache.definitions.WorldMapElementDefinition;
+import net.runelite.cache.definitions.loaders.ScriptLoader;
+import net.runelite.cache.definitions.loaders.WorldMapCompositeLoader;
+import net.runelite.cache.fs.Archive;
+import net.runelite.cache.fs.ArchiveFiles;
+import net.runelite.cache.fs.FSFile;
+import net.runelite.cache.fs.Storage;
+import net.runelite.cache.fs.Store;
+import net.runelite.cache.fs.Index;
+import net.runelite.cache.region.Position;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+public class WorldMapManager
+{
+ private final Store store;
+ private final List worldMapCompositeDefinitions = new ArrayList<>();
+ private final List elements = new ArrayList<>();
+ private final Map intermapLinks = new HashMap<>();
+
+ public WorldMapManager(Store store)
+ {
+ this.store = store;
+ }
+
+ public void load() throws IOException
+ {
+ Storage storage = store.getStorage();
+ Index index = store.getIndex(IndexType.WORLDMAP);
+ Archive compositeMapArchive = index.findArchiveByName("compositemap");
+ WorldMapCompositeLoader worldMapCompositeLoader = new WorldMapCompositeLoader();
+
+ ArchiveFiles compositeMapFiles = compositeMapArchive.getFiles(storage.loadArchive(compositeMapArchive));
+ for (FSFile compositeFile : compositeMapFiles.getFiles())
+ {
+ WorldMapCompositeDefinition composite = worldMapCompositeLoader.load(compositeFile.getContents());
+ worldMapCompositeDefinitions.add(composite);
+ }
+
+ for (WorldMapCompositeDefinition compositeDefinition : worldMapCompositeDefinitions)
+ {
+ elements.addAll(compositeDefinition.getWorldMapElementDefinitions());
+ }
+
+ // Intermap links. These are stored in a client script, so we have to parse it from there.
+ final int intermapLinkScriptId = 1705;
+ Index scriptIndex = store.getIndex(IndexType.CLIENTSCRIPT);
+ Archive intermapLinkScript = scriptIndex.getArchive(intermapLinkScriptId);
+ byte[] data = storage.loadArchive(intermapLinkScript);
+ FSFile file = intermapLinkScript.getFiles(data).findFile(0);
+
+ ScriptLoader scriptLoader = new ScriptLoader();
+ ScriptDefinition scriptDefinition = scriptLoader.load(intermapLinkScriptId, file.getContents());
+
+ List linkEnds = new ArrayList<>();
+ for (int i = 1; i < scriptDefinition.getIntOperands().length; ++i)
+ {
+ // 1706 is the script that gets called to jump to a location and the position is the int just before it
+ if (scriptDefinition.getIntOperands()[i] == 1706)
+ {
+ linkEnds.add(Position.fromPacked(scriptDefinition.getIntOperands()[i - 1]));
+ }
+ }
+
+ // The starting positions are in switch cases. We need to sort the cases by their jump positions
+ // so that they correspond to the end position in the int operands.
+ Map linkSwitch = scriptDefinition.getSwitches()[0];
+ int[] linkStarts = Arrays.stream(linkSwitch.keySet().toArray())
+ .sorted(Comparator.comparingInt(linkSwitch::get))
+ .mapToInt(i -> (int)i)
+ .toArray();
+ assert (linkStarts.length - 1) == linkEnds.size(); // The last case in the switch statement is the default case
+
+ for (int i = 0; i < linkStarts.length; ++i)
+ {
+ Position linkStartPosition = Position.fromPacked(linkStarts[i]);
+ Position linkEndPosition = linkEnds.get(i);
+ intermapLinks.put(linkStartPosition, linkEndPosition);
+ }
+ }
+
+ public List getElements()
+ {
+ return elements;
+ }
+
+ public Map getIntermapLinks()
+ {
+ return intermapLinks;
+ }
+}
diff --git a/cache/src/main/java/net/runelite/cache/definitions/AbstractWorldMapDataDefinition.java b/cache/src/main/java/net/runelite/cache/definitions/AbstractWorldMapDataDefinition.java
new file mode 100644
index 0000000000..d56b2f5d51
--- /dev/null
+++ b/cache/src/main/java/net/runelite/cache/definitions/AbstractWorldMapDataDefinition.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2024, Christopher Brown
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package net.runelite.cache.definitions;
+
+import lombok.Data;
+
+@Data
+public abstract class AbstractWorldMapDataDefinition
+{
+ public int minLevel;
+ public int levels;
+ public int displaySquareX;
+ public int displaySquareZ;
+ public int sourceSquareX;
+ public int sourceSquareZ;
+ public int groupId;
+ public int fileId;
+}
diff --git a/cache/src/main/java/net/runelite/cache/definitions/AreaDefinition.java b/cache/src/main/java/net/runelite/cache/definitions/AreaDefinition.java
index 7abdbdfddd..ca76b3c880 100644
--- a/cache/src/main/java/net/runelite/cache/definitions/AreaDefinition.java
+++ b/cache/src/main/java/net/runelite/cache/definitions/AreaDefinition.java
@@ -34,12 +34,12 @@ public class AreaDefinition
public int spriteId = -1;
public int field3294 = -1;
public String name;
- public int field3296;
- public int field3297 = -1;
+ public int textColor;
+ public int category = -1;
public String[] field3298 = new String[5];
public int[] field3300;
public String field3308;
public byte[] field3309;
- public int field3310;
+ public int textScale;
}
diff --git a/cache/src/main/java/net/runelite/cache/definitions/FontDefinition.java b/cache/src/main/java/net/runelite/cache/definitions/FontDefinition.java
new file mode 100644
index 0000000000..a7b8a727b6
--- /dev/null
+++ b/cache/src/main/java/net/runelite/cache/definitions/FontDefinition.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2024, Christopher Brown
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package net.runelite.cache.definitions;
+
+import lombok.Data;
+
+@Data
+public class FontDefinition
+{
+ public int[] advances = new int[256];
+ public int ascent;
+
+ public int stringWidth(String s)
+ {
+ int width = 0;
+ for (int i = 0; i < s.length(); ++i)
+ {
+ char c = s.charAt(i);
+ width += this.advances[c];
+ }
+
+ return width;
+ }
+}
diff --git a/cache/src/main/java/net/runelite/cache/definitions/MapSquareDefinition.java b/cache/src/main/java/net/runelite/cache/definitions/MapSquareDefinition.java
new file mode 100644
index 0000000000..57df517717
--- /dev/null
+++ b/cache/src/main/java/net/runelite/cache/definitions/MapSquareDefinition.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2024, Christopher Brown
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package net.runelite.cache.definitions;
+
+import lombok.Data;
+import lombok.ToString;
+
+@Data
+@ToString(callSuper = true)
+public class MapSquareDefinition extends AbstractWorldMapDataDefinition
+{
+ public boolean equals(Object obj)
+ {
+ if (!(obj instanceof MapSquareDefinition))
+ {
+ return false;
+ }
+ else
+ {
+ MapSquareDefinition other = (MapSquareDefinition) obj;
+ return other.sourceSquareX == this.sourceSquareX && other.sourceSquareZ == this.sourceSquareZ;
+ }
+ }
+
+ public int hashCode()
+ {
+ return this.sourceSquareX | this.sourceSquareZ << 8;
+ }
+}
diff --git a/cache/src/main/java/net/runelite/cache/definitions/WorldMapCompositeDefinition.java b/cache/src/main/java/net/runelite/cache/definitions/WorldMapCompositeDefinition.java
new file mode 100644
index 0000000000..9f508db32a
--- /dev/null
+++ b/cache/src/main/java/net/runelite/cache/definitions/WorldMapCompositeDefinition.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2024, Christopher Brown
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package net.runelite.cache.definitions;
+
+import lombok.Data;
+import net.runelite.cache.region.Position;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+@Data
+public class WorldMapCompositeDefinition
+{
+ public final Set mapSquareDefinitions = new HashSet<>();
+ public final Set zoneDefinitions = new HashSet<>();
+ public final List worldMapElementDefinitions = new ArrayList<>();
+
+ public Position calculateWorldOffset(Position position)
+ {
+ int squareX = position.getX() / 64;
+ int squareZ = position.getY() / 64;
+ int zoneX = (position.getX() & 63) / 8;
+ int zoneZ = (position.getY() & 63) / 8;
+ Position offset = null;
+
+ for (MapSquareDefinition mapSquare : mapSquareDefinitions)
+ {
+ if (squareX == mapSquare.sourceSquareX && squareZ == mapSquare.sourceSquareZ)
+ {
+ int shiftX = ((mapSquare.displaySquareX - mapSquare.sourceSquareX) * 64);
+ int shiftZ = ((mapSquare.displaySquareZ - mapSquare.sourceSquareZ) * 64);
+ offset = new Position(shiftX, shiftZ, mapSquare.getMinLevel());
+ }
+ }
+
+ for (ZoneDefinition zone : zoneDefinitions)
+ {
+ if (squareX == zone.sourceSquareX && squareZ == zone.sourceSquareZ && zoneX == zone.sourceZoneX && zoneZ == zone.sourceZoneZ)
+ {
+ int shiftX = ((zone.displaySquareX - zone.sourceSquareX) * 64) + ((zone.displayZoneX - zone.sourceZoneX) * 8);
+ int shiftZ = ((zone.displaySquareZ - zone.sourceSquareZ) * 64) + ((zone.displayZoneY - zone.sourceZoneZ) * 8);
+ offset = new Position(shiftX, shiftZ, zone.getMinLevel());
+ }
+ }
+
+ return offset;
+ }
+}
diff --git a/cache/src/main/java/net/runelite/cache/definitions/WorldMapElementDefinition.java b/cache/src/main/java/net/runelite/cache/definitions/WorldMapElementDefinition.java
new file mode 100644
index 0000000000..569ad819b4
--- /dev/null
+++ b/cache/src/main/java/net/runelite/cache/definitions/WorldMapElementDefinition.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2024, Christopher Brown
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package net.runelite.cache.definitions;
+
+import lombok.Data;
+import net.runelite.cache.region.Position;
+
+@Data
+public class WorldMapElementDefinition
+{
+ public Position position;
+ public Position offset;
+ public int areaDefinitionId;
+ public boolean membersOnly;
+
+ public Position getWorldPosition()
+ {
+ if (offset == null)
+ {
+ return new Position(position.getX(), position.getY(), 0);
+ }
+
+ return new Position(position.getX() + offset.getX(), position.getY() + offset.getY(), offset.getZ());
+ }
+}
diff --git a/cache/src/main/java/net/runelite/cache/definitions/ZoneDefinition.java b/cache/src/main/java/net/runelite/cache/definitions/ZoneDefinition.java
new file mode 100644
index 0000000000..b487d546ba
--- /dev/null
+++ b/cache/src/main/java/net/runelite/cache/definitions/ZoneDefinition.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2024, Christopher Brown
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package net.runelite.cache.definitions;
+
+import lombok.Data;
+import lombok.ToString;
+
+@Data
+@ToString(callSuper = true)
+public class ZoneDefinition extends AbstractWorldMapDataDefinition
+{
+ public int displayZoneX;
+ public int displayZoneY;
+ public int sourceZoneX;
+ public int sourceZoneZ;
+
+ public boolean equals(Object obj)
+ {
+ if (!(obj instanceof ZoneDefinition))
+ {
+ return false;
+ }
+ else
+ {
+ ZoneDefinition other = (ZoneDefinition) obj;
+ return other.sourceSquareX == this.sourceSquareX && other.sourceSquareZ == this.sourceSquareZ
+ && other.sourceZoneX == this.sourceZoneX && other.sourceZoneZ == this.sourceZoneZ;
+ }
+ }
+
+ public int hashCode()
+ {
+ return this.sourceSquareX | this.sourceSquareZ << 8 | this.sourceZoneX << 16 | this.sourceZoneZ << 24;
+ }
+}
diff --git a/cache/src/main/java/net/runelite/cache/definitions/loaders/AreaLoader.java b/cache/src/main/java/net/runelite/cache/definitions/loaders/AreaLoader.java
index 7b47358678..077f8f27d3 100644
--- a/cache/src/main/java/net/runelite/cache/definitions/loaders/AreaLoader.java
+++ b/cache/src/main/java/net/runelite/cache/definitions/loaders/AreaLoader.java
@@ -65,7 +65,7 @@ else if (opcode == 3)
}
else if (opcode == 4)
{
- def.field3296 = in.read24BitInt();
+ def.textColor = in.read24BitInt();
}
else if (opcode == 5)
{
@@ -73,7 +73,7 @@ else if (opcode == 5)
}
else if (opcode == 6)
{
- def.field3310 = in.readUnsignedByte();
+ def.textScale = in.readUnsignedByte();
}
else if (opcode == 7)
{
@@ -138,7 +138,7 @@ else if (opcode == 18)
}
else if (opcode == 19)
{
- def.field3297 = in.readUnsignedShort();
+ def.category = in.readUnsignedShort();
}
else if (opcode == 21)
{
diff --git a/cache/src/main/java/net/runelite/cache/definitions/loaders/FontLoader.java b/cache/src/main/java/net/runelite/cache/definitions/loaders/FontLoader.java
new file mode 100644
index 0000000000..5a6d5ce242
--- /dev/null
+++ b/cache/src/main/java/net/runelite/cache/definitions/loaders/FontLoader.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2024, Christopher Brown
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package net.runelite.cache.definitions.loaders;
+
+import net.runelite.cache.definitions.FontDefinition;
+
+public class FontLoader
+{
+ public FontDefinition load(byte[] buffer)
+ {
+ FontDefinition fontDefinition = new FontDefinition();
+
+ if (buffer.length == 257)
+ {
+ for (int i = 0; i < fontDefinition.advances.length; ++i)
+ {
+ fontDefinition.advances[i] = buffer[i] & 255;
+ }
+
+ fontDefinition.ascent = buffer[256] & 255;
+ }
+ else
+ {
+ // buffer length 256 may exist in some version of the cache?
+ throw new RuntimeException("Font data buffer is the wrong size");
+ }
+
+ return fontDefinition;
+ }
+}
diff --git a/cache/src/main/java/net/runelite/cache/definitions/loaders/WorldMapCompositeLoader.java b/cache/src/main/java/net/runelite/cache/definitions/loaders/WorldMapCompositeLoader.java
new file mode 100644
index 0000000000..eb503322eb
--- /dev/null
+++ b/cache/src/main/java/net/runelite/cache/definitions/loaders/WorldMapCompositeLoader.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2024, Christopher Brown
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package net.runelite.cache.definitions.loaders;
+
+import net.runelite.cache.definitions.WorldMapCompositeDefinition;
+import net.runelite.cache.definitions.WorldMapElementDefinition;
+import net.runelite.cache.io.InputStream;
+import net.runelite.cache.region.Position;
+
+public class WorldMapCompositeLoader
+{
+ public WorldMapCompositeDefinition load(byte[] buffer)
+ {
+ WorldMapDataLoader worldMapDataLoader = new WorldMapDataLoader();
+ WorldMapElementLoader worldMapElementLoader = new WorldMapElementLoader();
+
+ WorldMapCompositeDefinition worldMapCompositeDefinition = new WorldMapCompositeDefinition();
+ InputStream in = new InputStream(buffer);
+
+ int worldData0Count = in.readUnsignedShort();
+ for (int i = 0; i < worldData0Count; ++i)
+ {
+ worldMapCompositeDefinition.mapSquareDefinitions.add(worldMapDataLoader.loadMapSquare(in));
+ }
+
+ int worldData1Amount = in.readUnsignedShort();
+ for (int i = 0; i < worldData1Amount; ++i)
+ {
+ worldMapCompositeDefinition.zoneDefinitions.add(worldMapDataLoader.loadZone(in));
+ }
+
+ int iconAmount = in.readUnsignedShort();
+ for (int i = 0; i < iconAmount; ++i)
+ {
+ worldMapCompositeDefinition.worldMapElementDefinitions.add(worldMapElementLoader.load(in));
+ }
+
+ // The graphics in the world map are patched together from parts of the map and the position of
+ // the map elements are based on the result of that. This calculates the offset needed to place the element back
+ // into world coordinates.
+ for (WorldMapElementDefinition element : worldMapCompositeDefinition.worldMapElementDefinitions)
+ {
+ Position position = element.getPosition();
+ element.setOffset(worldMapCompositeDefinition.calculateWorldOffset(position));
+ }
+
+ return worldMapCompositeDefinition;
+ }
+}
diff --git a/cache/src/main/java/net/runelite/cache/definitions/loaders/WorldMapDataLoader.java b/cache/src/main/java/net/runelite/cache/definitions/loaders/WorldMapDataLoader.java
new file mode 100644
index 0000000000..54691e9a16
--- /dev/null
+++ b/cache/src/main/java/net/runelite/cache/definitions/loaders/WorldMapDataLoader.java
@@ -0,0 +1,80 @@
+/*
+ * Copyright (c) 2024, Christopher Brown
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package net.runelite.cache.definitions.loaders;
+
+import net.runelite.cache.definitions.MapSquareDefinition;
+import net.runelite.cache.definitions.ZoneDefinition;
+import net.runelite.cache.io.InputStream;
+
+public class WorldMapDataLoader
+{
+ public MapSquareDefinition loadMapSquare(InputStream in)
+ {
+ int worldMapDataType = in.readUnsignedByte();
+
+ if (worldMapDataType != 0)
+ {
+ throw new RuntimeException("Expected worldMapDataType 0 got " + worldMapDataType);
+ }
+
+ MapSquareDefinition mapSquareDefinition = new MapSquareDefinition();
+ mapSquareDefinition.minLevel = in.readUnsignedByte();
+ mapSquareDefinition.levels = in.readUnsignedByte();
+ mapSquareDefinition.displaySquareX = in.readUnsignedShort();
+ mapSquareDefinition.displaySquareZ = in.readUnsignedShort();
+ mapSquareDefinition.sourceSquareX = in.readUnsignedShort();
+ mapSquareDefinition.sourceSquareZ = in.readUnsignedShort();
+ mapSquareDefinition.groupId = in.readBigSmart2();
+ mapSquareDefinition.fileId = in.readBigSmart2();
+
+ return mapSquareDefinition;
+ }
+
+ public ZoneDefinition loadZone(InputStream in)
+ {
+ int worldMapDataType = in.readUnsignedByte();
+
+ if (worldMapDataType != 1)
+ {
+ throw new RuntimeException("Expected worldMapDataType 1 got " + worldMapDataType);
+ }
+
+ ZoneDefinition zoneDefinition = new ZoneDefinition();
+ zoneDefinition.minLevel = in.readUnsignedByte();
+ zoneDefinition.levels = in.readUnsignedByte();
+ zoneDefinition.displaySquareX = in.readUnsignedShort();
+ zoneDefinition.displaySquareZ = in.readUnsignedShort();
+ zoneDefinition.displayZoneX = in.readUnsignedByte();
+ zoneDefinition.displayZoneY = in.readUnsignedByte();
+ zoneDefinition.sourceSquareX = in.readUnsignedShort();
+ zoneDefinition.sourceSquareZ = in.readUnsignedShort();
+ zoneDefinition.sourceZoneX = in.readUnsignedByte();
+ zoneDefinition.sourceZoneZ = in.readUnsignedByte();
+ zoneDefinition.groupId = in.readBigSmart2();
+ zoneDefinition.fileId = in.readBigSmart2();
+
+ return zoneDefinition;
+ }
+}
diff --git a/cache/src/main/java/net/runelite/cache/definitions/loaders/WorldMapElementLoader.java b/cache/src/main/java/net/runelite/cache/definitions/loaders/WorldMapElementLoader.java
new file mode 100644
index 0000000000..297d8b3749
--- /dev/null
+++ b/cache/src/main/java/net/runelite/cache/definitions/loaders/WorldMapElementLoader.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2024, Christopher Brown
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package net.runelite.cache.definitions.loaders;
+
+import net.runelite.cache.definitions.WorldMapElementDefinition;
+import net.runelite.cache.io.InputStream;
+import net.runelite.cache.region.Position;
+
+public class WorldMapElementLoader
+{
+ public WorldMapElementDefinition load(InputStream in)
+ {
+ WorldMapElementDefinition worldMapElementDefinition = new WorldMapElementDefinition();
+
+ worldMapElementDefinition.areaDefinitionId = in.readBigSmart2();
+ worldMapElementDefinition.position = Position.fromPacked(in.readInt());
+ worldMapElementDefinition.membersOnly = in.readUnsignedByte() == 1;
+
+ return worldMapElementDefinition;
+ }
+}
diff --git a/cache/src/main/java/net/runelite/cache/region/Position.java b/cache/src/main/java/net/runelite/cache/region/Position.java
index d80144c80a..2509497135 100644
--- a/cache/src/main/java/net/runelite/cache/region/Position.java
+++ b/cache/src/main/java/net/runelite/cache/region/Position.java
@@ -38,6 +38,19 @@ public Position(int x, int y, int z)
this.z = z;
}
+ public static Position fromPacked(int packedPosition)
+ {
+ if (packedPosition == -1)
+ {
+ return new Position(-1, -1, -1);
+ }
+
+ int z = packedPosition >> 28 & 3;
+ int x = packedPosition >> 14 & 16383;
+ int y = packedPosition & 16383;
+ return new Position(x, y, z);
+ }
+
@Override
public String toString()
{
diff --git a/pom.xml b/pom.xml
index 463df6460a..3d95e39110 100644
--- a/pom.xml
+++ b/pom.xml
@@ -28,7 +28,7 @@
net.runelite
runelite-parent
- 1.10.26.4
+ 1.10.27
pom
RuneLite
@@ -66,7 +66,7 @@
https://github.com/runelite/runelite
scm:git:git://github.com/runelite/runelite
scm:git:git@github.com:runelite/runelite
- runelite-parent-1.10.26.4
+ runelite-parent-1.10.27
diff --git a/runelite-api/pom.xml b/runelite-api/pom.xml
index e43f7b4e64..0a66388bf7 100644
--- a/runelite-api/pom.xml
+++ b/runelite-api/pom.xml
@@ -29,7 +29,7 @@
net.runelite
runelite-parent
- 1.10.26.4
+ 1.10.27
runelite-api
diff --git a/runelite-api/src/main/interfaces/interfaces.toml b/runelite-api/src/main/interfaces/interfaces.toml
index 74c6d4c615..9857d04926 100644
--- a/runelite-api/src/main/interfaces/interfaces.toml
+++ b/runelite-api/src/main/interfaces/interfaces.toml
@@ -7,9 +7,11 @@ id=741
title=2
text=3
+# this is actually just a generic menu
[adventure_log]
id=187
container=0
+options=3
[agility_arena]
id=5
@@ -295,6 +297,7 @@ emote_scrollbar=4
[equipment]
id=387
inventory_item_container=0
+cape=16
[equipment_bonuses]
id=84
@@ -723,6 +726,7 @@ emote_icon=48
music_icon=49
inventory_tab=55
prayer_tab=57
+magic_tab=58
cmb_icon=59
skills_icon=60
quests_icon=61
@@ -800,6 +804,7 @@ inventory_item_container=0
[spellbook]
id=218
+parent=0
kourend_home_teleport=4
catherby_home_teleport=5
lumbridge_home_teleport=7
diff --git a/runelite-api/src/main/java/net/runelite/api/AnimationID.java b/runelite-api/src/main/java/net/runelite/api/AnimationID.java
index c5512b5142..d09ffdd2e2 100644
--- a/runelite-api/src/main/java/net/runelite/api/AnimationID.java
+++ b/runelite-api/src/main/java/net/runelite/api/AnimationID.java
@@ -59,6 +59,33 @@ public final class AnimationID
public static final int WOODCUTTING_2H_CRYSTAL = 10072;
public static final int WOODCUTTING_2H_CRYSTAL_INACTIVE = 10073;
public static final int WOODCUTTING_2H_3A = 10074;
+ public static final int WOODCUTTING_ENT_BRONZE = 3291;
+ public static final int WOODCUTTING_ENT_IRON = 3290;
+ public static final int WOODCUTTING_ENT_STEEL = 3289;
+ public static final int WOODCUTTING_ENT_BLACK = 3288;
+ public static final int WOODCUTTING_ENT_MITHRIL = 3287;
+ public static final int WOODCUTTING_ENT_ADAMANT = 3286;
+ public static final int WOODCUTTING_ENT_RUNE = 3285;
+ public static final int WOODCUTTING_ENT_GILDED = 8305;
+ public static final int WOODCUTTING_ENT_DRAGON = 3292;
+ public static final int WOODCUTTING_ENT_DRAGON_OR = 23;
+ public static final int WOODCUTTING_ENT_INFERNAL = 2116;
+ public static final int WOODCUTTING_ENT_INFERNAL_OR = 8777;
+ public static final int WOODCUTTING_ENT_3A = 7266;
+ public static final int WOODCUTTING_ENT_CRYSTAL = 8323;
+ public static final int WOODCUTTING_ENT_CRYSTAL_INACTIVE = 8327;
+ public static final int WOODCUTTING_ENT_TRAILBLAZER = 8780;
+ public static final int WOODCUTTING_ENT_2H_BRONZE = 10517;
+ public static final int WOODCUTTING_ENT_2H_IRON = 10518;
+ public static final int WOODCUTTING_ENT_2H_STEEL = 10519;
+ public static final int WOODCUTTING_ENT_2H_BLACK = 10520;
+ public static final int WOODCUTTING_ENT_2H_MITHRIL = 10521;
+ public static final int WOODCUTTING_ENT_2H_ADAMANT = 10522;
+ public static final int WOODCUTTING_ENT_2H_RUNE = 10523;
+ public static final int WOODCUTTING_ENT_2H_DRAGON = 10524;
+ public static final int WOODCUTTING_ENT_2H_CRYSTAL = 10525;
+ public static final int WOODCUTTING_ENT_2H_CRYSTAL_INACTIVE = 10526;
+ public static final int WOODCUTTING_ENT_2H_3A = 10527;
public static final int CONSUMING = 829; // consuming consumables
public static final int FIREMAKING = 733;
public static final int FIREMAKING_FORESTERS_CAMPFIRE_ARCTIC_PINE = 10563;
diff --git a/runelite-api/src/main/java/net/runelite/api/Client.java b/runelite-api/src/main/java/net/runelite/api/Client.java
index d94aa3382f..6aef7976c8 100644
--- a/runelite-api/src/main/java/net/runelite/api/Client.java
+++ b/runelite-api/src/main/java/net/runelite/api/Client.java
@@ -1415,6 +1415,21 @@ Projectile createProjectile(int id, int plane, int startX, int startY, int start
*/
String[] getStringStack();
+ /**
+ * Get the size of one of the cs2 vm's arrays.
+ * @param arrayId the array id
+ * @return
+ */
+ int getArraySizes(int arrayId);
+
+ /**
+ * Get one of the cs2 vm's arrays. Use {@link #getArraySizes(int)} to get
+ * the array length.
+ * @param arrayId the array id
+ * @return
+ */
+ int[] getArray(int arrayId);
+
/**
* Gets the cs2 vm's active widget
*
@@ -2147,4 +2162,6 @@ Projectile createProjectile(int id, int plane, int startX, int startY, int start
void setMinimapTileDrawer(TileFunction drawTile);
Rasterizer getRasterizer();
+
+ void menuAction(int p0, int p1, MenuAction action, int id, int itemId, String option, String target);
}
diff --git a/runelite-api/src/main/java/net/runelite/api/EnumID.java b/runelite-api/src/main/java/net/runelite/api/EnumID.java
index 478aeffccf..c8618f6d1e 100644
--- a/runelite-api/src/main/java/net/runelite/api/EnumID.java
+++ b/runelite-api/src/main/java/net/runelite/api/EnumID.java
@@ -90,4 +90,7 @@ public final class EnumID
* val: enum
*/
public static final int WEAPON_STYLES = 3908;
+
+ public static final int SPELLBOOKS = 1981;
+ public static final int SPELLBOOKS_SUB = 5280;
}
diff --git a/runelite-api/src/main/java/net/runelite/api/ItemID.java b/runelite-api/src/main/java/net/runelite/api/ItemID.java
index 7caef70dc7..bb5462df6a 100644
--- a/runelite-api/src/main/java/net/runelite/api/ItemID.java
+++ b/runelite-api/src/main/java/net/runelite/api/ItemID.java
@@ -13920,7 +13920,7 @@ public final class ItemID
public static final int BLESSED_BONE_STATUETTE_29340 = 29340;
public static final int BLESSED_BONE_STATUETTE_29342 = 29342;
public static final int BLESSED_BONES = 29344;
- public static final int BLESSD_BAT_BONES = 29346;
+ public static final int BLESSED_BAT_BONES = 29346;
public static final int BLESSED_BIG_BONES = 29348;
public static final int BLESSED_ZOGRE_BONES = 29350;
public static final int BLESSED_BABYDRAGON_BONES = 29352;
@@ -13979,5 +13979,10 @@ public final class ItemID
public static final int EGG_PRIEST_MITRE = 29443;
public static final int EASTER_EGG_MINED = 29445;
public static final int EGGNAPPIN_SACK = 29446;
+ public static final int IMBUED_MAGE_ARENA_CAPE = 29448;
+ public static final int ZOMBIE_PIRATE_KEY = 29449;
+ public static final int TELEPORT_ANCHORING_SCROLL = 29455;
+ public static final int ADAMANT_SEEDS = 29458;
+ public static final int WILDERNESS_AGILITY_TICKET = 29460;
/* This file is automatically generated. Do not edit. */
}
diff --git a/runelite-api/src/main/java/net/runelite/api/MenuAction.java b/runelite-api/src/main/java/net/runelite/api/MenuAction.java
index 1a590c0d9b..41bb1af3f2 100644
--- a/runelite-api/src/main/java/net/runelite/api/MenuAction.java
+++ b/runelite-api/src/main/java/net/runelite/api/MenuAction.java
@@ -244,6 +244,12 @@ public enum MenuAction
*/
WIDGET_TARGET_ON_WIDGET(58),
+ /**
+ * Submenu parent that is also a widget.
+ * see {@link #RUNELITE_SUBMENU}
+ */
+ RUNELITE_SUBMENU_WIDGET(998),
+
/**
* Menu action for high priority runelite options
*/
diff --git a/runelite-api/src/main/java/net/runelite/api/NpcID.java b/runelite-api/src/main/java/net/runelite/api/NpcID.java
index cb6a8503ff..e53832fcca 100644
--- a/runelite-api/src/main/java/net/runelite/api/NpcID.java
+++ b/runelite-api/src/main/java/net/runelite/api/NpcID.java
@@ -10946,11 +10946,10 @@ public final class NpcID
public static final int ORYX = 13006;
public static final int FLIES_13007 = 13007;
public static final int FLIES_13008 = 13008;
- public static final int BLOOD_MOON = 13010;
- public static final int BLOOD_MOON_13011 = 13011;
+ public static final int GREEN_DRAGON_13010 = 13010;
+ public static final int BLOOD_MOON = 13011;
public static final int ECLIPSE_MOON = 13012;
public static final int BLUE_MOON = 13013;
- public static final int ECLIPSE_MOON_13019 = 13019;
public static final int MOON_SHIELD = 13020;
public static final int BLOOD_JAGUAR = 13021;
public static final int FROZEN_WEAPONS = 13025;
@@ -11330,5 +11329,25 @@ public final class NpcID
public static final int RABBIT_13469 = 13469;
public static final int RABBIT_13470 = 13470;
public static final int CHICKEN_13471 = 13471;
+ public static final int ENRAGED_BLOOD_MOON = 13485;
+ public static final int ENRAGED_BLUE_MOON = 13486;
+ public static final int ENRAGED_ECLIPSE_MOON = 13487;
+ public static final int GREEN_DRAGON_13488 = 13488;
+ public static final int ZOMBIE_PIRATE_13489 = 13489;
+ public static final int ZOMBIE_PIRATE_13490 = 13490;
+ public static final int ZOMBIE_PIRATE_13491 = 13491;
+ public static final int ZOMBIE_PIRATE_13492 = 13492;
+ public static final int ZOMBIE_PIRATE_13493 = 13493;
+ public static final int ZOMBIE_PIRATE_13494 = 13494;
+ public static final int SKELETON_13495 = 13495;
+ public static final int SKELETON_13496 = 13496;
+ public static final int SKELETON_13497 = 13497;
+ public static final int SKELETON_13498 = 13498;
+ public static final int SKELETON_13499 = 13499;
+ public static final int SKELETON_13500 = 13500;
+ public static final int SKELETON_13501 = 13501;
+ public static final int HILL_GIANT_13502 = 13502;
+ public static final int HILL_GIANT_13503 = 13503;
+ public static final int HILL_GIANT_13504 = 13504;
/* This file is automatically generated. Do not edit. */
}
diff --git a/runelite-api/src/main/java/net/runelite/api/NullItemID.java b/runelite-api/src/main/java/net/runelite/api/NullItemID.java
index f5e98629f5..b97374b48a 100644
--- a/runelite-api/src/main/java/net/runelite/api/NullItemID.java
+++ b/runelite-api/src/main/java/net/runelite/api/NullItemID.java
@@ -15258,5 +15258,14 @@ public final class NullItemID
public static final int NULL_29442 = 29442;
public static final int NULL_29444 = 29444;
public static final int NULL_29447 = 29447;
+ public static final int NULL_29450 = 29450;
+ public static final int NULL_29451 = 29451;
+ public static final int NULL_29452 = 29452;
+ public static final int NULL_29453 = 29453;
+ public static final int NULL_29454 = 29454;
+ public static final int NULL_29456 = 29456;
+ public static final int NULL_29457 = 29457;
+ public static final int NULL_29459 = 29459;
+ public static final int NULL_29461 = 29461;
/* This file is automatically generated. Do not edit. */
}
diff --git a/runelite-api/src/main/java/net/runelite/api/NullNpcID.java b/runelite-api/src/main/java/net/runelite/api/NullNpcID.java
index 8e75e987b1..2f623a39a0 100644
--- a/runelite-api/src/main/java/net/runelite/api/NullNpcID.java
+++ b/runelite-api/src/main/java/net/runelite/api/NullNpcID.java
@@ -2050,6 +2050,7 @@ public final class NullNpcID
public static final int NULL_13016 = 13016;
public static final int NULL_13017 = 13017;
public static final int NULL_13018 = 13018;
+ public static final int NULL_13019 = 13019;
public static final int NULL_13022 = 13022;
public static final int NULL_13023 = 13023;
public static final int NULL_13024 = 13024;
diff --git a/runelite-api/src/main/java/net/runelite/api/NullObjectID.java b/runelite-api/src/main/java/net/runelite/api/NullObjectID.java
index 043d3168c4..ab4a330ee9 100644
--- a/runelite-api/src/main/java/net/runelite/api/NullObjectID.java
+++ b/runelite-api/src/main/java/net/runelite/api/NullObjectID.java
@@ -27564,11 +27564,6 @@ public final class NullObjectID
public static final int NULL_53183 = 53183;
public static final int NULL_53184 = 53184;
public static final int NULL_53185 = 53185;
- public static final int NULL_53188 = 53188;
- public static final int NULL_53189 = 53189;
- public static final int NULL_53190 = 53190;
- public static final int NULL_53191 = 53191;
- public static final int NULL_53192 = 53192;
public static final int NULL_53193 = 53193;
public static final int NULL_53194 = 53194;
public static final int NULL_53195 = 53195;
@@ -27589,6 +27584,15 @@ public final class NullObjectID
public static final int NULL_53210 = 53210;
public static final int NULL_53211 = 53211;
public static final int NULL_53212 = 53212;
+ public static final int NULL_53213 = 53213;
+ public static final int NULL_53214 = 53214;
+ public static final int NULL_53215 = 53215;
+ public static final int NULL_53216 = 53216;
+ public static final int NULL_53217 = 53217;
public static final int NULL_53218 = 53218;
+ public static final int NULL_53219 = 53219;
+ public static final int NULL_53220 = 53220;
+ public static final int NULL_53221 = 53221;
+ public static final int NULL_53223 = 53223;
/* This file is automatically generated. Do not edit. */
}
diff --git a/runelite-api/src/main/java/net/runelite/api/ObjectID.java b/runelite-api/src/main/java/net/runelite/api/ObjectID.java
index c413ef5248..551b195c60 100644
--- a/runelite-api/src/main/java/net/runelite/api/ObjectID.java
+++ b/runelite-api/src/main/java/net/runelite/api/ObjectID.java
@@ -25607,10 +25607,12 @@ public final class ObjectID
public static final int BUFFERS_53170 = 53170;
public static final int COLUMN_53186 = 53186;
public static final int DOOR_53187 = 53187;
- public static final int SKELETON_53213 = 53213;
- public static final int SKELETON_53214 = 53214;
- public static final int SKELETON_53215 = 53215;
- public static final int TREE_53216 = 53216;
- public static final int TREE_STUMP_53217 = 53217;
+ public static final int TREE_53188 = 53188;
+ public static final int TREE_STUMP_53189 = 53189;
+ public static final int SKELETON_53190 = 53190;
+ public static final int SKELETON_53191 = 53191;
+ public static final int SKELETON_53192 = 53192;
+ public static final int ZOMBIE_PIRATES_LOCKER = 53222;
+ public static final int AGILITY_DISPENSER = 53224;
/* This file is automatically generated. Do not edit. */
}
diff --git a/runelite-api/src/main/java/net/runelite/api/ParamID.java b/runelite-api/src/main/java/net/runelite/api/ParamID.java
index 00babf8053..cebb1e63e8 100644
--- a/runelite-api/src/main/java/net/runelite/api/ParamID.java
+++ b/runelite-api/src/main/java/net/runelite/api/ParamID.java
@@ -67,4 +67,8 @@ public final class ParamID
public static final int SLAYER_TASK_NAME = 1801;
public static final int ATTACK_STYLE_NAME = 1407;
+
+ public static final int SPELL_BUTTON = 596;
+ public static final int SPELL_NAME = 601;
+ public static final int SPELL_LEVELREQ = 604;
}
diff --git a/runelite-api/src/main/java/net/runelite/api/ScriptID.java b/runelite-api/src/main/java/net/runelite/api/ScriptID.java
index ec9691a639..062ae1a9c4 100644
--- a/runelite-api/src/main/java/net/runelite/api/ScriptID.java
+++ b/runelite-api/src/main/java/net/runelite/api/ScriptID.java
@@ -452,4 +452,7 @@ public final class ScriptID
@ScriptArguments(integer = 6)
public static final int EQUIPMENT_SET_STAT_BONUS_SETUP = 3517;
+
+ @ScriptArguments(integer = 12, string = 2)
+ public static final int MAGIC_SPELLBOOK_INITIALISESPELLS = 2616;
}
diff --git a/runelite-api/src/main/java/net/runelite/api/SpriteID.java b/runelite-api/src/main/java/net/runelite/api/SpriteID.java
index 3300aad143..bd3ac22ae1 100644
--- a/runelite-api/src/main/java/net/runelite/api/SpriteID.java
+++ b/runelite-api/src/main/java/net/runelite/api/SpriteID.java
@@ -380,7 +380,9 @@ public final class SpriteID
public static final int SPELL_WATER_SURGE = 363;
public static final int SPELL_EARTH_SURGE = 364;
public static final int SPELL_FIRE_SURGE = 365;
- /* Unmapped: 366, 367, 368 */
+ /* Unmapped: 366 */
+ public static final int SPELL_CIVITAS_ILLA_FORTIS_TELEPORT = 367;
+ /* Unmapped: 368 */
public static final int SPELL_BIND_DISABLED = 369;
public static final int SPELL_SNARE_DISABLED = 370;
public static final int SPELL_ENTANGLE_DISABLED = 371;
diff --git a/runelite-api/src/main/java/net/runelite/api/TileItem.java b/runelite-api/src/main/java/net/runelite/api/TileItem.java
index 8c1b08541e..0a92f982a3 100644
--- a/runelite-api/src/main/java/net/runelite/api/TileItem.java
+++ b/runelite-api/src/main/java/net/runelite/api/TileItem.java
@@ -36,4 +36,17 @@ public interface TileItem extends Renderable
int getId();
int getQuantity();
+
+ /**
+ * Get the time, in server ticks, when the item despawns, relative to the spawn time.
+ * @return
+ */
+ int getDespawnTime();
+
+ /**
+ * Get the time, in server ticks, when the item becomes visible to other players, relative
+ * to the spawn time.
+ * @return
+ */
+ int getVisibleTime();
}
diff --git a/runelite-api/src/main/java/net/runelite/api/Varbits.java b/runelite-api/src/main/java/net/runelite/api/Varbits.java
index 07c1657b1c..7b395640e1 100644
--- a/runelite-api/src/main/java/net/runelite/api/Varbits.java
+++ b/runelite-api/src/main/java/net/runelite/api/Varbits.java
@@ -879,4 +879,7 @@ public final class Varbits
* 1 = active
*/
public static final int SPELLBOOK_SWAP = 3617;
+
+ public static final int SPELLBOOK = 4070;
+ public static final int SPELLBOOK_SUBMENU = 9730;
}
diff --git a/runelite-client/pom.xml b/runelite-client/pom.xml
index 2544b802af..abf15a8164 100644
--- a/runelite-client/pom.xml
+++ b/runelite-client/pom.xml
@@ -29,7 +29,7 @@
net.runelite
runelite-parent
- 1.10.26.4
+ 1.10.27
client
@@ -140,7 +140,7 @@
net.runelite
rlawt
- 1.4
+ 1.5
diff --git a/runelite-client/src/main/java/net/runelite/client/Notifier.java b/runelite-client/src/main/java/net/runelite/client/Notifier.java
index 1772a443ad..9d76c72778 100644
--- a/runelite-client/src/main/java/net/runelite/client/Notifier.java
+++ b/runelite-client/src/main/java/net/runelite/client/Notifier.java
@@ -67,6 +67,7 @@
import net.runelite.client.chat.ChatMessageManager;
import net.runelite.client.chat.QueuedMessage;
import net.runelite.client.config.FlashNotification;
+import net.runelite.client.config.Notification;
import net.runelite.client.config.RuneLiteConfig;
import net.runelite.client.eventbus.EventBus;
import net.runelite.client.events.NotificationFired;
@@ -117,6 +118,8 @@ public String toString()
private final Path notifyIconPath;
private boolean terminalNotifierAvailable;
private Instant flashStart;
+ private FlashNotification flashNotification;
+ private Color flashColor;
private long mouseLastPressedMillis;
private long lastClipMTime = CLIP_MTIME_UNLOADED;
private Clip clip = null;
@@ -151,21 +154,53 @@ private Notifier(
storeIcon();
}
+ private Notification defaultNotification(TrayIcon.MessageType trayMessageType)
+ {
+ // Create a new notification just using the RuneLite notification settings
+ return new Notification(true, true,
+ true, // Not really overriden, but this it to avoid recreating the notification due to !override
+ runeLiteConfig.enableTrayNotifications(), trayMessageType, runeLiteConfig.notificationRequestFocus(),
+ runeLiteConfig.notificationSound(), runeLiteConfig.notificationVolume(), runeLiteConfig.notificationTimeout(),
+ runeLiteConfig.enableGameMessageNotification(), runeLiteConfig.flashNotification(), runeLiteConfig.notificationFlashColor(),
+ runeLiteConfig.sendNotificationsWhenFocused());
+ }
+
public void notify(String message)
{
- notify(message, TrayIcon.MessageType.NONE);
+ var notif = defaultNotification(TrayIcon.MessageType.NONE);
+ notify(notif, message);
}
public void notify(String message, TrayIcon.MessageType type)
{
- eventBus.post(new NotificationFired(message, type));
+ var notif = defaultNotification(type);
+ notify(notif, message);
+ }
- if (!runeLiteConfig.sendNotificationsWhenFocused() && clientUI.isFocused())
+ public void notify(Notification notification, String message)
+ {
+ if (!notification.isEnabled())
{
return;
}
- switch (runeLiteConfig.notificationRequestFocus())
+ // Non-overriden notifications use the default notification settings.
+ if (!notification.isOverride() || !notification.isInitialized())
+ {
+ notification = defaultNotification(notification.getTrayIconType());
+ }
+
+ assert notification.isInitialized();
+
+ log.debug("{}", message);
+ eventBus.post(new NotificationFired(notification, message, notification.getTrayIconType()));
+
+ if (!notification.isSendWhenFocused() && clientUI.isFocused())
+ {
+ return;
+ }
+
+ switch (notification.getRequestFocus())
{
case REQUEST:
clientUI.requestFocus();
@@ -178,21 +213,22 @@ public void notify(String message, TrayIcon.MessageType type)
break;
}
- if (runeLiteConfig.enableTrayNotifications())
+ if (notification.isTray())
{
- sendNotification(buildTitle(), message, type);
+ sendNotification(notification, buildTitle(), message);
}
- switch (runeLiteConfig.notificationSound())
+ switch (notification.getSound())
{
case NATIVE:
Toolkit.getDefaultToolkit().beep();
break;
case CUSTOM:
- executorService.submit(this::playCustomSound);
+ var n = notification;
+ executorService.submit(() -> playCustomSound(n));
}
- if (runeLiteConfig.enableGameMessageNotification() && client.getGameState() == GameState.LOGGED_IN)
+ if (notification.isGameMessage() && client.getGameState() == GameState.LOGGED_IN)
{
final String formattedMessage = new ChatMessageBuilder()
.append(ChatColorType.HIGHLIGHT)
@@ -206,13 +242,13 @@ public void notify(String message, TrayIcon.MessageType type)
.build());
}
- if (runeLiteConfig.flashNotification() != FlashNotification.DISABLED)
+ if (notification.getFlash() != FlashNotification.DISABLED)
{
+ flashNotification = notification.getFlash();
+ flashColor = notification.getFlashColor();
flashStart = Instant.now();
mouseLastPressedMillis = client.getMouseLastPressedMillis();
}
-
- log.debug(message);
}
private String buildTitle()
@@ -234,12 +270,13 @@ private String buildTitle()
public void processFlash(final Graphics2D graphics)
{
- FlashNotification flashNotification = runeLiteConfig.flashNotification();
-
- if (flashStart == null || client.getGameState() != GameState.LOGGED_IN
+ if (flashStart == null || flashNotification == null || flashColor == null
+ || client.getGameState() != GameState.LOGGED_IN
|| flashNotification == FlashNotification.DISABLED)
{
flashStart = null;
+ flashNotification = null;
+ flashColor = null;
return;
}
@@ -250,6 +287,8 @@ public void processFlash(final Graphics2D graphics)
case FLASH_TWO_SECONDS:
case SOLID_TWO_SECONDS:
flashStart = null;
+ flashNotification = null;
+ flashColor = null;
return;
case SOLID_UNTIL_CANCELLED:
case FLASH_UNTIL_CANCELLED:
@@ -259,6 +298,8 @@ public void processFlash(final Graphics2D graphics)
|| client.getMouseLastPressedMillis() > mouseLastPressedMillis) && clientUI.isFocused())
{
flashStart = null;
+ flashNotification = null;
+ flashColor = null;
return;
}
break;
@@ -274,47 +315,44 @@ public void processFlash(final Graphics2D graphics)
}
final Color color = graphics.getColor();
- graphics.setColor(runeLiteConfig.notificationFlashColor());
+ graphics.setColor(flashColor);
graphics.fill(new Rectangle(client.getCanvas().getSize()));
graphics.setColor(color);
}
private void sendNotification(
+ final Notification notification,
final String title,
- final String message,
- final TrayIcon.MessageType type)
+ final String message)
{
- final String escapedTitle = SHELL_ESCAPE.escape(title);
- final String escapedMessage = SHELL_ESCAPE.escape(message);
-
switch (OSType.getOSType())
{
case Linux:
- sendLinuxNotification(escapedTitle, escapedMessage, type);
+ sendLinuxNotification(notification, title, message);
break;
case MacOS:
- sendMacNotification(escapedTitle, escapedMessage);
+ sendMacNotification(title, message);
break;
default:
- sendTrayNotification(title, message, type);
+ sendTrayNotification(notification, title, message);
}
}
private void sendTrayNotification(
+ final Notification notification,
final String title,
- final String message,
- final TrayIcon.MessageType type)
+ final String message)
{
if (clientUI.getTrayIcon() != null)
{
- clientUI.getTrayIcon().displayMessage(title, message, type);
+ clientUI.getTrayIcon().displayMessage(title, message, notification.getTrayIconType());
}
}
private void sendLinuxNotification(
+ final Notification notification,
final String title,
- final String message,
- final TrayIcon.MessageType type)
+ final String message)
{
final List commands = new ArrayList<>();
commands.add("notify-send");
@@ -325,11 +363,11 @@ private void sendLinuxNotification(
commands.add("-i");
commands.add(SHELL_ESCAPE.escape(notifyIconPath.toAbsolutePath().toString()));
commands.add("-u");
- commands.add(toUrgency(type));
- if (runeLiteConfig.notificationTimeout() > 0)
+ commands.add(toUrgency(notification.getTrayIconType()));
+ if (notification.getTimeout() > 0)
{
commands.add("-t");
- commands.add(String.valueOf(runeLiteConfig.notificationTimeout()));
+ commands.add(String.valueOf(notification.getTimeout()));
}
executorService.submit(() ->
@@ -350,7 +388,7 @@ private void sendLinuxNotification(
}
// fall back to tray notification
- sendTrayNotification(title, message, type);
+ sendTrayNotification(notification, title, message);
});
}
@@ -375,11 +413,11 @@ private void sendMacNotification(final String title, final String message)
commands.add("-e");
final String script = "display notification " + DOUBLE_QUOTE +
- message +
+ SHELL_ESCAPE.escape(message) +
DOUBLE_QUOTE +
" with title " +
DOUBLE_QUOTE +
- title +
+ SHELL_ESCAPE.escape(title) +
DOUBLE_QUOTE;
commands.add(script);
@@ -447,7 +485,7 @@ private static String toUrgency(TrayIcon.MessageType type)
}
}
- private synchronized void playCustomSound()
+ private synchronized void playCustomSound(Notification notification)
{
long currentMTime = NOTIFICATION_FILE.exists() ? NOTIFICATION_FILE.lastModified() : CLIP_MTIME_BUILTIN;
if (clip == null || currentMTime != lastClipMTime || !clip.isOpen())
@@ -479,7 +517,7 @@ private synchronized void playCustomSound()
}
// converts user controlled linear volume ranging 1-100 to exponential decibel gains
- float volume = runeLiteConfig.notificationVolume() / 100f;
+ float volume = notification.getVolume() / 100f;
float gainDB = (float) Math.log10(volume) * 20;
FloatControl gainControl = (FloatControl) clip.getControl(FloatControl.Type.MASTER_GAIN);
gainControl.setValue(gainDB);
diff --git a/runelite-client/src/main/java/net/runelite/client/callback/Hooks.java b/runelite-client/src/main/java/net/runelite/client/callback/Hooks.java
index 502848ea74..4b91e20840 100644
--- a/runelite-client/src/main/java/net/runelite/client/callback/Hooks.java
+++ b/runelite-client/src/main/java/net/runelite/client/callback/Hooks.java
@@ -79,7 +79,6 @@
import net.runelite.client.ui.overlay.infobox.InfoBoxManager;
import net.runelite.client.util.DeferredEventBus;
import net.runelite.client.util.LinkBrowser;
-import net.runelite.client.util.OSType;
import net.runelite.client.util.RSTimeUnit;
/**
@@ -472,8 +471,7 @@ public void draw(MainBufferProvider mainBufferProvider, Graphics graphics, int x
private Image screenshot(Image src)
{
// scale source image to the size of the client ui
- final AffineTransform transform = OSType.getOSType() == OSType.MacOS ? new AffineTransform() :
- clientUi.getGraphicsConfiguration().getDefaultTransform();
+ final AffineTransform transform = clientUi.getGraphicsConfiguration().getDefaultTransform();
int swidth = src.getWidth(null);
int sheight = src.getHeight(null);
int twidth = (int) (swidth * transform.getScaleX() + .5);
diff --git a/runelite-client/src/main/java/net/runelite/client/config/ConfigManager.java b/runelite-client/src/main/java/net/runelite/client/config/ConfigManager.java
index bec12ce70a..9a832af122 100644
--- a/runelite-client/src/main/java/net/runelite/client/config/ConfigManager.java
+++ b/runelite-client/src/main/java/net/runelite/client/config/ConfigManager.java
@@ -53,6 +53,7 @@
import java.util.Map;
import java.util.Objects;
import java.util.Set;
+import java.util.WeakHashMap;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
@@ -130,6 +131,8 @@ public class ConfigManager
@Nullable
private String rsProfileKey;
+ private final Map> serializers = Collections.synchronizedMap(new WeakHashMap<>());
+
@Inject
private ConfigManager(
@Nullable @Named("profile") String profile,
@@ -1192,6 +1195,27 @@ Object stringToObject(String str, Type type)
return gson.fromJson(str, parameterizedType);
}
}
+ if (type instanceof Class)
+ {
+ Class> clazz = (Class>) type;
+ ConfigSerializer configSerializer = clazz.getAnnotation(ConfigSerializer.class);
+ if (configSerializer != null)
+ {
+ Class extends Serializer>> serializerClass = configSerializer.value();
+ Serializer> serializer = serializers.get(type);
+ if (serializer == null)
+ {
+ // Guice holds references to all jitted types.
+ // To allow class unloading, use a temporary child injector
+ // and use it to get the instance, and cache it a weak map.
+ serializer = RuneLite.getInjector()
+ .createChildInjector()
+ .getInstance(serializerClass);
+ serializers.put(type, serializer);
+ }
+ return serializer.deserialize(str);
+ }
+ }
return str;
}
@@ -1247,6 +1271,23 @@ String objectToString(Object object)
{
return gson.toJson(object, Set.class);
}
+ if (object != null)
+ {
+ ConfigSerializer configSerializer = object.getClass().getAnnotation(ConfigSerializer.class);
+ if (configSerializer != null)
+ {
+ Class extends Serializer>> serializerClass = configSerializer.value();
+ Serializer serializer = serializers.get(serializerClass);
+ if (serializer == null)
+ {
+ serializer = RuneLite.getInjector()
+ .createChildInjector()
+ .getInstance(serializerClass);
+ serializers.put(serializerClass, serializer);
+ }
+ return serializer.serialize(object);
+ }
+ }
return object == null ? null : object.toString();
}
diff --git a/runelite-client/src/main/java/net/runelite/client/config/ConfigSerializer.java b/runelite-client/src/main/java/net/runelite/client/config/ConfigSerializer.java
new file mode 100644
index 0000000000..a7e2385d3d
--- /dev/null
+++ b/runelite-client/src/main/java/net/runelite/client/config/ConfigSerializer.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2024, Adam
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package net.runelite.client.config;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target(ElementType.TYPE)
+public @interface ConfigSerializer
+{
+ Class extends Serializer>> value();
+}
diff --git a/runelite-client/src/main/java/net/runelite/client/config/Notification.java b/runelite-client/src/main/java/net/runelite/client/config/Notification.java
new file mode 100644
index 0000000000..54b4d4cd57
--- /dev/null
+++ b/runelite-client/src/main/java/net/runelite/client/config/Notification.java
@@ -0,0 +1,91 @@
+/*
+ * Copyright (c) 2024, Adam
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package net.runelite.client.config;
+
+import com.google.gson.Gson;
+import com.google.inject.Inject;
+import java.awt.Color;
+import java.awt.TrayIcon;
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import lombok.With;
+import net.runelite.client.Notifier;
+
+@ConfigSerializer(NotificationSerializer.class)
+@AllArgsConstructor
+@NoArgsConstructor(force = true)
+@Getter
+@With
+public class Notification
+{
+ public static final Notification OFF = new Notification();
+ public static final Notification ON = new Notification().withEnabled(true);
+
+ boolean enabled;
+ // Whether this has been initialized with the RuneLite config notification settings.
+ // It is used to determine if the settings should be applied to it when first enabled.
+ boolean initialized;
+ boolean override;
+ boolean tray;
+ transient TrayIcon.MessageType trayIconType = TrayIcon.MessageType.NONE;
+ RequestFocusType requestFocus;
+ Notifier.NativeCustomOff sound;
+ int volume;
+ int timeout;
+ boolean gameMessage;
+ FlashNotification flash;
+ Color flashColor;
+ boolean sendWhenFocused;
+}
+
+class NotificationSerializer implements Serializer
+{
+ private final Gson gson;
+
+ @Inject
+ private NotificationSerializer(Gson gson)
+ {
+ this.gson = gson;
+ }
+
+ @Override
+ public String serialize(Notification value)
+ {
+ return gson.toJson(value);
+ }
+
+ @Override
+ public Notification deserialize(String s)
+ {
+ if ("true".equals(s) || "false".equals(s))
+ {
+ return new Notification()
+ .withEnabled(Boolean.parseBoolean(s));
+ }
+
+ return gson.fromJson(s, Notification.class);
+ }
+}
\ No newline at end of file
diff --git a/runelite-client/src/main/java/net/runelite/client/config/Serializer.java b/runelite-client/src/main/java/net/runelite/client/config/Serializer.java
new file mode 100644
index 0000000000..ef296df8d3
--- /dev/null
+++ b/runelite-client/src/main/java/net/runelite/client/config/Serializer.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2024, Adam
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package net.runelite.client.config;
+
+public interface Serializer
+{
+ String serialize(T value);
+
+ T deserialize(String s);
+}
diff --git a/runelite-client/src/main/java/net/runelite/client/events/NotificationFired.java b/runelite-client/src/main/java/net/runelite/client/events/NotificationFired.java
index ecf1ffaf2d..79dd5499bb 100644
--- a/runelite-client/src/main/java/net/runelite/client/events/NotificationFired.java
+++ b/runelite-client/src/main/java/net/runelite/client/events/NotificationFired.java
@@ -26,10 +26,12 @@
import java.awt.TrayIcon;
import lombok.Value;
+import net.runelite.client.config.Notification;
@Value
public class NotificationFired
{
+ final Notification notification;
final String message;
final TrayIcon.MessageType type;
}
diff --git a/runelite-client/src/main/java/net/runelite/client/game/NpcUtil.java b/runelite-client/src/main/java/net/runelite/client/game/NpcUtil.java
index 9b3abb0045..c459829992 100644
--- a/runelite-client/src/main/java/net/runelite/client/game/NpcUtil.java
+++ b/runelite-client/src/main/java/net/runelite/client/game/NpcUtil.java
@@ -132,6 +132,8 @@ public boolean isDying(final NPC npc)
case NpcID.RUNITE_ROCKS:
case NpcID.STRANGE_CREATURE_12076: // Secrets of the North transitioning to Jhallan
case NpcID.BOUNCER_3509:
+ // Tutorial island giant rats respawn instantly.
+ case NpcID.GIANT_RAT_3313:
// Agrith Naar restores health upon reaching 0hp if the player does not have Silverlight
// equipped, or moved away immediately after applying the killing blow.
case NpcID.AGRITH_NAAR:
diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/agility/AgilityConfig.java b/runelite-client/src/main/java/net/runelite/client/plugins/agility/AgilityConfig.java
index 0e2af795d1..6df20b3015 100644
--- a/runelite-client/src/main/java/net/runelite/client/plugins/agility/AgilityConfig.java
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/agility/AgilityConfig.java
@@ -30,6 +30,7 @@
import net.runelite.client.config.ConfigGroup;
import net.runelite.client.config.ConfigItem;
import net.runelite.client.config.ConfigSection;
+import net.runelite.client.config.Notification;
import net.runelite.client.config.Units;
@ConfigGroup("agility")
@@ -196,9 +197,9 @@ default Color getTrapColor()
description = "Notify on ticket location change in Agility Arena",
position = 13
)
- default boolean notifyAgilityArena()
+ default Notification notifyAgilityArena()
{
- return true;
+ return Notification.ON;
}
@ConfigItem(
diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/agility/AgilityPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/agility/AgilityPlugin.java
index 96d11d2b43..c8a6ea1ba5 100644
--- a/runelite-client/src/main/java/net/runelite/client/plugins/agility/AgilityPlugin.java
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/agility/AgilityPlugin.java
@@ -290,10 +290,7 @@ public void onGameTick(GameTick tick)
{
log.debug("Ticked position moved from {} to {}", oldTickPosition, newTicketPosition);
- if (config.notifyAgilityArena())
- {
- notifier.notify("Ticket location changed");
- }
+ notifier.notify(config.notifyAgilityArena(), "Ticket location changed");
if (config.showAgilityArenaTimer())
{
diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/boosts/BoostsConfig.java b/runelite-client/src/main/java/net/runelite/client/plugins/boosts/BoostsConfig.java
index 86b9629081..cf48c7dd92 100644
--- a/runelite-client/src/main/java/net/runelite/client/plugins/boosts/BoostsConfig.java
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/boosts/BoostsConfig.java
@@ -27,6 +27,7 @@
import net.runelite.client.config.Config;
import net.runelite.client.config.ConfigGroup;
import net.runelite.client.config.ConfigItem;
+import net.runelite.client.config.Notification;
@ConfigGroup("boosts")
public interface BoostsConfig extends Config
@@ -140,8 +141,8 @@ default int boostThreshold()
description = "Configures whether or not a notification will be sent for boosted stats.",
position = 13
)
- default boolean notifyOnBoost()
+ default Notification notifyOnBoost()
{
- return true;
+ return Notification.ON;
}
}
diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/boosts/BoostsPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/boosts/BoostsPlugin.java
index 05baee07e6..2f235cd16b 100644
--- a/runelite-client/src/main/java/net/runelite/client/plugins/boosts/BoostsPlugin.java
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/boosts/BoostsPlugin.java
@@ -221,14 +221,14 @@ public void onStatChanged(StatChanged statChanged)
int boostThreshold = config.boostThreshold();
- if (boostThreshold != 0 && config.notifyOnBoost())
+ if (boostThreshold != 0)
{
int real = client.getRealSkillLevel(skill);
int lastBoost = last - real;
int boost = cur - real;
if (boost <= boostThreshold && boostThreshold < lastBoost)
{
- notifier.notify(skill.getName() + " level is getting low!");
+ notifier.notify(config.notifyOnBoost(), skill.getName() + " level is getting low!");
}
}
}
diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/cannon/CannonConfig.java b/runelite-client/src/main/java/net/runelite/client/plugins/cannon/CannonConfig.java
index 3b7a5a3a1a..4dc87d8599 100644
--- a/runelite-client/src/main/java/net/runelite/client/plugins/cannon/CannonConfig.java
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/cannon/CannonConfig.java
@@ -29,6 +29,7 @@
import net.runelite.client.config.Config;
import net.runelite.client.config.ConfigGroup;
import net.runelite.client.config.ConfigItem;
+import net.runelite.client.config.Notification;
import net.runelite.client.config.Range;
@ConfigGroup("cannon")
@@ -40,9 +41,9 @@ public interface CannonConfig extends Config
description = "Configures whether to notify you when your cannon is low on cannonballs",
position = 1
)
- default boolean showCannonNotifications()
+ default Notification showCannonNotifications()
{
- return true;
+ return Notification.ON;
}
@Range(
diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/cannon/CannonPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/cannon/CannonPlugin.java
index 11d2dac240..bb602c7350 100644
--- a/runelite-client/src/main/java/net/runelite/client/plugins/cannon/CannonPlugin.java
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/cannon/CannonPlugin.java
@@ -302,9 +302,9 @@ public void onVarbitChanged(VarbitChanged varbitChanged)
{
cballsLeft = varbitChanged.getValue();
- if (config.showCannonNotifications() && !cannonBallNotificationSent && cballsLeft > 0 && config.lowWarningThreshold() >= cballsLeft)
+ if (!cannonBallNotificationSent && cballsLeft > 0 && config.lowWarningThreshold() >= cballsLeft)
{
- notifier.notify(String.format("Your cannon has %d cannon balls remaining!", cballsLeft));
+ notifier.notify(config.showCannonNotifications(), String.format("Your cannon has %d cannon balls remaining!", cballsLeft));
cannonBallNotificationSent = true;
}
}
@@ -366,10 +366,7 @@ else if (event.getMessage().startsWith("You load the cannon with"))
}
else if (event.getMessage().contains("Your cannon is out of ammo!"))
{
- if (config.showCannonNotifications())
- {
- notifier.notify("Your cannon is out of ammo!");
- }
+ notifier.notify(config.showCannonNotifications(), "Your cannon is out of ammo!");
}
else if (event.getMessage().equals("This isn't your cannon!") || event.getMessage().equals("This is not your cannon."))
{
diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/chatcommands/ChatCommandsPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/chatcommands/ChatCommandsPlugin.java
index 4343e43705..84225fca8d 100644
--- a/runelite-client/src/main/java/net/runelite/client/plugins/chatcommands/ChatCommandsPlugin.java
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/chatcommands/ChatCommandsPlugin.java
@@ -2190,6 +2190,11 @@ private static String longBossName(String boss)
// Tombs of Amascut
case "toa":
+ case "tombs":
+ case "amascut":
+ case "warden":
+ case "wardens":
+ case "raids 3":
return "Tombs of Amascut";
case "toa 1":
case "toa solo":
@@ -2497,6 +2502,13 @@ private static String longBossName(String boss)
case "vard awakened":
return "Vardorvis (awakened)";
+ // lunar chest variants
+ case "lunar chests":
+ case "perilous moons":
+ case "perilous moon":
+ case "moons of peril":
+ return "Lunar Chest";
+
default:
return WordUtils.capitalize(boss);
}
diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/chatnotifications/ChatNotificationsConfig.java b/runelite-client/src/main/java/net/runelite/client/plugins/chatnotifications/ChatNotificationsConfig.java
index c2bc53909f..0bd5b44bac 100644
--- a/runelite-client/src/main/java/net/runelite/client/plugins/chatnotifications/ChatNotificationsConfig.java
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/chatnotifications/ChatNotificationsConfig.java
@@ -29,6 +29,7 @@
import net.runelite.client.config.ConfigGroup;
import net.runelite.client.config.ConfigItem;
import net.runelite.client.config.ConfigSection;
+import net.runelite.client.config.Notification;
@ConfigGroup("chatnotification")
public interface ChatNotificationsConfig extends Config
@@ -81,9 +82,9 @@ default boolean highlightOwnName()
name = "Notify on own name",
description = "Notifies you whenever someone mentions you by name"
)
- default boolean notifyOnOwnName()
+ default Notification notifyOnOwnName()
{
- return false;
+ return Notification.OFF;
}
@ConfigItem(
@@ -92,9 +93,9 @@ default boolean notifyOnOwnName()
name = "Notify on highlight",
description = "Notifies you whenever a highlighted word is matched"
)
- default boolean notifyOnHighlight()
+ default Notification notifyOnHighlight()
{
- return false;
+ return Notification.OFF;
}
@ConfigItem(
@@ -103,9 +104,9 @@ default boolean notifyOnHighlight()
name = "Notify on trade",
description = "Notifies you whenever you are traded"
)
- default boolean notifyOnTrade()
+ default Notification notifyOnTrade()
{
- return false;
+ return Notification.OFF;
}
@ConfigItem(
@@ -114,9 +115,9 @@ default boolean notifyOnTrade()
name = "Notify on duel",
description = "Notifies you whenever you are challenged to a duel"
)
- default boolean notifyOnDuel()
+ default Notification notifyOnDuel()
{
- return false;
+ return Notification.OFF;
}
@ConfigItem(
@@ -125,9 +126,9 @@ default boolean notifyOnDuel()
name = "Notify on broadcast",
description = "Notifies you whenever you receive a broadcast message"
)
- default boolean notifyOnBroadcast()
+ default Notification notifyOnBroadcast()
{
- return false;
+ return Notification.OFF;
}
@ConfigItem(
@@ -136,8 +137,8 @@ default boolean notifyOnBroadcast()
name = "Notify on private message",
description = "Notifies you whenever you receive a private message"
)
- default boolean notifyOnPM()
+ default Notification notifyOnPM()
{
- return false;
+ return Notification.OFF;
}
}
diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/chatnotifications/ChatNotificationsPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/chatnotifications/ChatNotificationsPlugin.java
index e26275a2eb..6648e7c188 100644
--- a/runelite-client/src/main/java/net/runelite/client/plugins/chatnotifications/ChatNotificationsPlugin.java
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/chatnotifications/ChatNotificationsPlugin.java
@@ -48,6 +48,7 @@
import net.runelite.client.Notifier;
import net.runelite.client.chat.ChatColorType;
import net.runelite.client.config.ConfigManager;
+import net.runelite.client.config.Notification;
import net.runelite.client.eventbus.Subscribe;
import net.runelite.client.events.ConfigChanged;
import net.runelite.client.plugins.Plugin;
@@ -166,39 +167,33 @@ public void onChatMessage(ChatMessage chatMessage)
switch (chatMessage.getType())
{
case TRADEREQ:
- if (chatMessage.getMessage().contains("wishes to trade with you.") && config.notifyOnTrade())
+ if (chatMessage.getMessage().contains("wishes to trade with you."))
{
- notifier.notify(chatMessage.getMessage());
+ notifier.notify(config.notifyOnTrade(), chatMessage.getMessage());
}
break;
case CHALREQ_TRADE:
- if (chatMessage.getMessage().contains("wishes to duel with you.") && config.notifyOnDuel())
+ if (chatMessage.getMessage().contains("wishes to duel with you."))
{
- notifier.notify(chatMessage.getMessage());
+ notifier.notify(config.notifyOnDuel(), chatMessage.getMessage());
}
break;
case BROADCAST:
- if (config.notifyOnBroadcast())
- {
- // Some broadcasts have links attached, notated by `|` followed by a number, while others contain color tags.
- // We don't want to see either in the printed notification.
- String broadcast = chatMessage.getMessage();
-
- int urlTokenIndex = broadcast.lastIndexOf('|');
- if (urlTokenIndex != -1)
- {
- broadcast = broadcast.substring(0, urlTokenIndex);
- }
+ // Some broadcasts have links attached, notated by `|` followed by a number, while others contain color tags.
+ // We don't want to see either in the printed notification.
+ String broadcast = chatMessage.getMessage();
- notifier.notify(Text.removeFormattingTags(broadcast));
+ int urlTokenIndex = broadcast.lastIndexOf('|');
+ if (urlTokenIndex != -1)
+ {
+ broadcast = broadcast.substring(0, urlTokenIndex);
}
+
+ notifier.notify(config.notifyOnBroadcast(), Text.removeFormattingTags(broadcast));
break;
case PRIVATECHAT:
case MODPRIVATECHAT:
- if (config.notifyOnPM())
- {
- notifier.notify(Text.removeTags(chatMessage.getName()) + ": " + chatMessage.getMessage());
- }
+ notifier.notify(config.notifyOnPM(), Text.removeTags(chatMessage.getName()) + ": " + chatMessage.getMessage());
break;
case PRIVATECHATOUT:
case DIALOG:
@@ -259,15 +254,15 @@ public void onChatMessage(ChatMessage chatMessage)
messageNode.setValue(stringBuffer.toString());
update = true;
- if (config.notifyOnOwnName() && (chatMessage.getType() == ChatMessageType.PUBLICCHAT
+ if (chatMessage.getType() == ChatMessageType.PUBLICCHAT
|| chatMessage.getType() == ChatMessageType.PRIVATECHAT
|| chatMessage.getType() == ChatMessageType.FRIENDSCHAT
|| chatMessage.getType() == ChatMessageType.MODCHAT
|| chatMessage.getType() == ChatMessageType.MODPRIVATECHAT
|| chatMessage.getType() == ChatMessageType.CLAN_CHAT
- || chatMessage.getType() == ChatMessageType.CLAN_GUEST_CHAT))
+ || chatMessage.getType() == ChatMessageType.CLAN_GUEST_CHAT)
{
- sendNotification(chatMessage);
+ sendNotification(config.notifyOnOwnName(), chatMessage);
}
}
}
@@ -313,10 +308,7 @@ public void onChatMessage(ChatMessage chatMessage)
if (matchesHighlight)
{
messageNode.setValue(nodeValue);
- if (config.notifyOnHighlight())
- {
- sendNotification(chatMessage);
- }
+ sendNotification(config.notifyOnHighlight(), chatMessage);
}
if (update)
@@ -325,7 +317,7 @@ public void onChatMessage(ChatMessage chatMessage)
}
}
- private void sendNotification(ChatMessage message)
+ private void sendNotification(Notification notification, ChatMessage message)
{
String name = Text.removeTags(message.getName());
String sender = message.getSender();
@@ -342,8 +334,8 @@ private void sendNotification(ChatMessage message)
}
stringBuilder.append(Text.removeTags(message.getMessage()));
- String notification = stringBuilder.toString();
- notifier.notify(notification);
+ String m = stringBuilder.toString();
+ notifier.notify(notification, m);
}
private String quoteAndIgnoreColor(String str)
diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/clues/CoordinateClue.java b/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/clues/CoordinateClue.java
index ac49013e2b..d50e114cca 100644
--- a/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/clues/CoordinateClue.java
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/clues/CoordinateClue.java
@@ -179,7 +179,7 @@ private CoordinateClueInfo(@Nonnull String directions, Enemy enemy, boolean ligh
.put(new WorldPoint(3189, 3963, 0), new CoordinateClueInfo("Wilderness. North of Resource Area, near magic axe hut.", ZAMORAK_WIZARD))
.put(new WorldPoint(2341, 3697, 0), new CoordinateClueInfo("North-east of the Piscatoris Fishing Colony bank.", SARADOMIN_WIZARD))
.put(new WorldPoint(3143, 3774, 0), new CoordinateClueInfo("In level 32 Wilderness, by the black chinchompa hunting area.", ZAMORAK_WIZARD))
- .put(new WorldPoint(2992, 3941, 0), new CoordinateClueInfo("Wilderness Agility Course, past the log balance.", ZAMORAK_WIZARD))
+ .put(new WorldPoint(2970, 3913, 0), new CoordinateClueInfo("Frozen Waste Plateau, south-west of Wilderness Agility Course.", ZAMORAK_WIZARD))
.put(new WorldPoint(1410, 3611, 0), new CoordinateClueInfo("Lake Molch dock west of Shayzien Encampment.", SARADOMIN_WIZARD))
.put(new WorldPoint(1409, 3483, 0), new CoordinateClueInfo("South of Shayziens' Wall.", SARADOMIN_WIZARD))
// Elite
@@ -248,7 +248,7 @@ private CoordinateClueInfo(@Nonnull String directions, Enemy enemy, boolean ligh
.put(new WorldPoint(3380, 3929, 0), new CoordinateClueInfo("Wilderness. Near Volcano.", ANCIENT_WIZARDS))
.put(new WorldPoint(3188, 3939, 0), new CoordinateClueInfo("Wilderness. Resource Area.", BRASSICAN_MAGE))
.put(new WorldPoint(3304, 3941, 0), new CoordinateClueInfo("Wilderness. East of Rogues' Castle.", ANCIENT_WIZARDS))
- .put(new WorldPoint(2994, 3961, 0), new CoordinateClueInfo("Wilderness. Inside Agility Training Area.", BRASSICAN_MAGE))
+ .put(new WorldPoint(3028, 3928, 0), new CoordinateClueInfo("Wilderness. South-east of Agility Training Area.", BRASSICAN_MAGE))
.put(new WorldPoint(1769, 3418, 0), new CoordinateClueInfo("Crabclaw Isle", ANCIENT_WIZARDS))
.build();
diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/clues/EmoteClue.java b/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/clues/EmoteClue.java
index f433edc615..41439b4214 100644
--- a/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/clues/EmoteClue.java
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/clues/EmoteClue.java
@@ -202,7 +202,7 @@ public class EmoteClue extends ClueScroll implements LocationClueScroll
new EmoteClue("Salute outside the gates of Cam Torum. Beware of double agents! Equip a full set of blue moon equipment.", "Cam Torum", CAM_TORUM_ENTRANCE, new WorldPoint(1436, 3115, 0), DOUBLE_AGENT_141, SALUTE, any("Blue moon helm", item(BLUE_MOON_HELM), item(BLUE_MOON_HELM_29041)), any("Blue moon chestplate", item(BLUE_MOON_CHESTPLATE), item(BLUE_MOON_CHESTPLATE_29037)), any("Blue moon tassets", item(BLUE_MOON_TASSETS), item(BLUE_MOON_TASSETS_29039)), item(BLUE_MOON_SPEAR)),
new EmoteClue("Shrug in the mine near Rimmington. Equip a gold necklace, a gold ring and a bronze spear.", "Rimmington mine", RIMMINGTON_MINE, new WorldPoint(2976, 3238, 0), SHRUG, item(GOLD_NECKLACE), item(GOLD_RING), item(BRONZE_SPEAR)),
new EmoteClue("Shrug in Catherby bank. Yawn before you talk to me. Equip a maple longbow, green d'hide chaps and an iron med helm.", "Catherby", OUTSIDE_CATHERBY_BANK, new WorldPoint(2808, 3440, 0), SHRUG, YAWN, item(MAPLE_LONGBOW), item(GREEN_DHIDE_CHAPS), item(IRON_MED_HELM)),
- new EmoteClue("Shrug in the Zamorak temple found in the Eastern Wilderness. Beware of double agents! Equip rune platelegs, an iron platebody and blue dragonhide vambraces.", "Chaos Temple (east of Ferox Enclave)", CHAOS_TEMPLE_IN_THE_SOUTHEASTERN_WILDERNESS, new WorldPoint(3239, 3611, 0), DOUBLE_AGENT_65, SHRUG, item(RUNE_PLATELEGS), item(IRON_PLATEBODY), item(BLUE_DHIDE_VAMBRACES)),
+ new EmoteClue("Shrug in the woods east of the Level 19 Wilderness Obelisk. Beware of double agents! Equip rune platelegs, an iron platebody and blue dragonhide vambraces.", "East of the Level 19 Wilderness Obelisk", EAST_OF_THE_LEVEL_19_WILDERNESS_OBELISK, new WorldPoint(3241, 3672, 0), DOUBLE_AGENT_65, SHRUG, item(RUNE_PLATELEGS), item(IRON_PLATEBODY), item(BLUE_DHIDE_VAMBRACES)),
new EmoteClue("Shrug in the Shayzien war tent. Equip a blue mystic robe bottom, a rune kiteshield and any bob shirt.", "Shayzien war tent", SHAYZIEN_WAR_TENT, new WorldPoint(1487, 3635, 0), SHRUG, item(MYSTIC_ROBE_BOTTOM), item(RUNE_KITESHIELD), range("Any bob shirt", BOBS_RED_SHIRT, BOBS_PURPLE_SHIRT)),
new EmoteClue("Slap your head in the centre of the Kourend catacombs. Beware of double agents! Equip the arclight and the amulet of the damned.", "Kourend catacombs", CENTRE_OF_THE_CATACOMBS_OF_KOUREND, new WorldPoint(1663, 10045, 0), DOUBLE_AGENT_141, SLAP_HEAD, item(ARCLIGHT), any("Amulet of the damned", item(AMULET_OF_THE_DAMNED), item(AMULET_OF_THE_DAMNED_FULL))),
new EmoteClue("Spin at the crossroads north of Rimmington. Equip a green gnome hat, cream gnome top and leather chaps.", "Rimmington", ROAD_JUNCTION_NORTH_OF_RIMMINGTON, new WorldPoint(2981, 3276, 0), SPIN, item(GREEN_HAT), item(CREAM_ROBE_TOP), item(LEATHER_CHAPS)),
diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/clues/HotColdClue.java b/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/clues/HotColdClue.java
index ef742c847c..88ef383d28 100644
--- a/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/clues/HotColdClue.java
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/clues/HotColdClue.java
@@ -36,7 +36,6 @@
import lombok.AccessLevel;
import lombok.EqualsAndHashCode;
import lombok.Getter;
-import lombok.extern.slf4j.Slf4j;
import net.runelite.api.NPC;
import net.runelite.api.coords.LocalPoint;
import net.runelite.api.coords.WorldPoint;
@@ -55,7 +54,6 @@
@EqualsAndHashCode(callSuper = false, exclude = { "hotColdSolver", "location" })
@Getter
-@Slf4j
public class HotColdClue extends ClueScroll implements LocationClueScroll, LocationsClueScroll, NpcClueScroll
{
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.",
diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/clues/SkillChallengeClue.java b/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/clues/SkillChallengeClue.java
index 8e7878c271..ab08b6f68d 100644
--- a/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/clues/SkillChallengeClue.java
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/clues/SkillChallengeClue.java
@@ -196,7 +196,7 @@ enum ChallengeType
.orElseGet(Stream::empty)
.map(ItemRequirements::item)
.toArray(SingleItemRequirement[]::new))),
- new SkillChallengeClue("Catch a black warlock.", item(ItemID.BUTTERFLY_JAR), any("Butterfly Net", item(ItemID.BUTTERFLY_NET), item(ItemID.MAGIC_BUTTERFLY_NET))),
+ new SkillChallengeClue("Catch a black warlock.", any("Butterfly Net", item(ItemID.BUTTERFLY_NET), item(ItemID.MAGIC_BUTTERFLY_NET))),
new SkillChallengeClue("Catch a red chinchompa.", item(ItemID.BOX_TRAP)),
new SkillChallengeClue("Mine a mithril ore.", ANY_PICKAXE),
new SkillChallengeClue("Smith a mithril 2h sword.", ANY_HAMMER, xOfItem(ItemID.MITHRIL_BAR, 3)),
diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/clues/emote/STASHUnit.java b/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/clues/emote/STASHUnit.java
index e3481e2406..7eba0112b3 100644
--- a/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/clues/emote/STASHUnit.java
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/clues/emote/STASHUnit.java
@@ -82,7 +82,7 @@ public enum STASHUnit
WEST_OF_THE_SHAYZIEN_COMBAT_RING(NullObjectID.NULL_29006, new WorldPoint(1541, 3631, 0)),
ENTRANCE_OF_THE_ARCEUUS_LIBRARY(NullObjectID.NULL_29007, new WorldPoint(1642, 3809, 0)),
OUTSIDE_DRAYNOR_VILLAGE_JAIL(NullObjectID.NULL_29008, new WorldPoint(3130, 3250, 0)),
- CHAOS_TEMPLE_IN_THE_SOUTHEASTERN_WILDERNESS(NullObjectID.NULL_29009, new WorldPoint(3245, 3609, 0)),
+ EAST_OF_THE_LEVEL_19_WILDERNESS_OBELISK(NullObjectID.NULL_29009, new WorldPoint(3243, 3662, 0)),
FISHING_GUILD_BANK(NullObjectID.NULL_29010, new WorldPoint(2593, 3409, 0)),
TOP_FLOOR_OF_THE_LIGHTHOUSE(NullObjectID.NULL_29011, new WorldPoint(2512, 3640, 2)),
OUTSIDE_THE_GREAT_PYRAMID_OF_SOPHANEM(NullObjectID.NULL_29012, new WorldPoint(3291, 2780, 0)),
diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/config/ConfigPanel.java b/runelite-client/src/main/java/net/runelite/client/plugins/config/ConfigPanel.java
index 88e683a089..3071d3d7cb 100644
--- a/runelite-client/src/main/java/net/runelite/client/plugins/config/ConfigPanel.java
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/config/ConfigPanel.java
@@ -47,6 +47,7 @@
import java.util.Set;
import java.util.TreeMap;
import javax.inject.Inject;
+import javax.inject.Provider;
import javax.swing.BorderFactory;
import javax.swing.BoxLayout;
import javax.swing.ImageIcon;
@@ -84,6 +85,7 @@
import net.runelite.client.config.ConfigSectionDescriptor;
import net.runelite.client.config.Keybind;
import net.runelite.client.config.ModifierlessKeybind;
+import net.runelite.client.config.Notification;
import net.runelite.client.config.Range;
import net.runelite.client.config.Units;
import net.runelite.client.eventbus.Subscribe;
@@ -113,6 +115,7 @@ class ConfigPanel extends PluginPanel
private static final int SPINNER_FIELD_WIDTH = 6;
private static final ImageIcon SECTION_EXPAND_ICON;
private static final ImageIcon SECTION_RETRACT_ICON;
+ static final ImageIcon CONFIG_ICON;
static final ImageIcon BACK_ICON;
private static final Map sectionExpandStates = new HashMap<>();
@@ -127,6 +130,8 @@ class ConfigPanel extends PluginPanel
SECTION_EXPAND_ICON = new ImageIcon(sectionRetractIcon);
final BufferedImage sectionExpandIcon = ImageUtil.rotateImage(sectionRetractIcon, Math.PI / 2);
SECTION_RETRACT_ICON = new ImageIcon(sectionExpandIcon);
+ BufferedImage configIcon = ImageUtil.loadImageResource(ConfigPanel.class, "config_edit_icon.png");
+ CONFIG_ICON = new ImageIcon(configIcon);
}
private final PluginListPanel pluginList;
@@ -134,6 +139,7 @@ class ConfigPanel extends PluginPanel
private final PluginManager pluginManager;
private final ExternalPluginManager externalPluginManager;
private final ColorPickerManager colorPickerManager;
+ private final Provider notificationPanelProvider;
private final TitleCaseListCellRenderer listCellRenderer = new TitleCaseListCellRenderer();
@@ -144,8 +150,14 @@ class ConfigPanel extends PluginPanel
private PluginConfigurationDescriptor pluginConfig = null;
@Inject
- private ConfigPanel(PluginListPanel pluginList, ConfigManager configManager, PluginManager pluginManager,
- ExternalPluginManager externalPluginManager, ColorPickerManager colorPickerManager)
+ private ConfigPanel(
+ PluginListPanel pluginList,
+ ConfigManager configManager,
+ PluginManager pluginManager,
+ ExternalPluginManager externalPluginManager,
+ ColorPickerManager colorPickerManager,
+ Provider notificationPanelProvider
+ )
{
super(false);
@@ -154,6 +166,7 @@ private ConfigPanel(PluginListPanel pluginList, ConfigManager configManager, Plu
this.pluginManager = pluginManager;
this.externalPluginManager = externalPluginManager;
this.colorPickerManager = colorPickerManager;
+ this.notificationPanelProvider = notificationPanelProvider;
setLayout(new BorderLayout());
setBackground(ColorScheme.DARK_GRAY_COLOR);
@@ -372,6 +385,10 @@ else if (cid.getType() == Keybind.class || cid.getType() == ModifierlessKeybind.
{
item.add(createKeybind(cd, cid), BorderLayout.EAST);
}
+ else if (cid.getType() == Notification.class)
+ {
+ item.add(createNotification(cd, cid), BorderLayout.EAST);
+ }
else if (cid.getType() instanceof ParameterizedType)
{
ParameterizedType parameterizedType = (ParameterizedType) cid.getType();
@@ -457,7 +474,7 @@ private JSpinner createIntSpinner(ConfigDescriptor cd, ConfigItemDescriptor cid)
Units units = cid.getUnits();
if (units != null)
{
- spinnerTextField.setFormatterFactory(new UnitFormatterFactory(units));
+ spinnerTextField.setFormatterFactory(new UnitFormatterFactory(units.value()));
}
return spinner;
@@ -483,7 +500,6 @@ private JTextComponent createTextField(ConfigDescriptor cd, ConfigItemDescriptor
if (cid.getItem().secret())
{
textField = new JPasswordField();
- textField.setFont(FontManager.getDefaultFont());
}
else
{
@@ -638,6 +654,43 @@ public void focusLost(FocusEvent e)
return button;
}
+ private JPanel createNotification(ConfigDescriptor cd, ConfigItemDescriptor cid)
+ {
+ JPanel panel = new JPanel();
+ panel.setLayout(new BorderLayout());
+
+ JButton button = new JButton(ConfigPanel.CONFIG_ICON);
+ SwingUtil.removeButtonDecorations(button);
+ button.setPreferredSize(new Dimension(25, 0));
+ button.addActionListener(l ->
+ {
+ var muxer = pluginList.getMuxer();
+ var notifPanel = notificationPanelProvider.get();
+ notifPanel.init(cd, cid);
+ muxer.pushState(notifPanel);
+ });
+ panel.add(button, BorderLayout.WEST);
+
+ JCheckBox checkbox = new JCheckBox();
+ {
+ Notification notif = configManager.getConfiguration(cd.getGroup().value(), cid.getItem().keyName(), Notification.class);
+ checkbox.setSelected(notif.isEnabled());
+ }
+ checkbox.addActionListener(ae ->
+ {
+ button.setVisible(checkbox.isSelected());
+
+ Notification notif = configManager.getConfiguration(cd.getGroup().value(), cid.getItem().keyName(), Notification.class);
+ configManager.setConfiguration(cd.getGroup().value(), cid.getItem().keyName(), notif.withEnabled(checkbox.isSelected()));
+ });
+ checkbox.setBackground(ColorScheme.LIGHT_GRAY_COLOR);
+ panel.add(checkbox, BorderLayout.EAST);
+
+ // button visibility is tied to the checkbox
+ button.setVisible(checkbox.isSelected());
+ return panel;
+ }
+
private JList> createList(ConfigDescriptor cd, ConfigItemDescriptor cid)
{
ParameterizedType parameterizedType = (ParameterizedType) cid.getType();
diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/config/NotificationPanel.java b/runelite-client/src/main/java/net/runelite/client/plugins/config/NotificationPanel.java
new file mode 100644
index 0000000000..23a559cf2b
--- /dev/null
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/config/NotificationPanel.java
@@ -0,0 +1,402 @@
+/*
+ * Copyright (c) 2024, Adam
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package net.runelite.client.plugins.config;
+
+import com.google.common.primitives.Ints;
+import java.awt.BorderLayout;
+import java.awt.Color;
+import java.awt.Component;
+import java.awt.Dimension;
+import java.awt.TrayIcon;
+import java.awt.event.ItemEvent;
+import java.awt.event.MouseAdapter;
+import java.awt.event.MouseEvent;
+import java.util.function.Consumer;
+import javax.inject.Inject;
+import javax.swing.JButton;
+import javax.swing.JCheckBox;
+import javax.swing.JComboBox;
+import javax.swing.JFormattedTextField;
+import javax.swing.JLabel;
+import javax.swing.JOptionPane;
+import javax.swing.JPanel;
+import javax.swing.JScrollPane;
+import javax.swing.JSpinner;
+import javax.swing.ScrollPaneConstants;
+import javax.swing.SpinnerModel;
+import javax.swing.SpinnerNumberModel;
+import javax.swing.SwingUtilities;
+import javax.swing.border.EmptyBorder;
+import lombok.extern.slf4j.Slf4j;
+import net.runelite.client.Notifier;
+import net.runelite.client.config.ConfigDescriptor;
+import net.runelite.client.config.ConfigItemDescriptor;
+import net.runelite.client.config.ConfigManager;
+import net.runelite.client.config.FlashNotification;
+import net.runelite.client.config.Notification;
+import net.runelite.client.config.RequestFocusType;
+import net.runelite.client.config.RuneLiteConfig;
+import net.runelite.client.ui.ColorScheme;
+import net.runelite.client.ui.DynamicGridLayout;
+import net.runelite.client.ui.PluginPanel;
+import net.runelite.client.ui.components.ColorJButton;
+import net.runelite.client.ui.components.TitleCaseListCellRenderer;
+import net.runelite.client.ui.components.colorpicker.ColorPickerManager;
+import net.runelite.client.ui.components.colorpicker.RuneliteColorPicker;
+import net.runelite.client.util.ColorUtil;
+import net.runelite.client.util.SwingUtil;
+import net.runelite.client.util.Text;
+
+@Slf4j
+class NotificationPanel extends PluginPanel
+{
+ private final ConfigManager configManager;
+ private final ColorPickerManager colorPickerManager;
+
+ private final JLabel title;
+ private final FixedWidthPanel mainPanel;
+ private final JCheckBox enabled;
+
+ private ConfigDescriptor configDescriptor;
+ private ConfigItemDescriptor configItemDescriptor;
+
+ @Inject
+ private NotificationPanel(
+ ConfigManager configManager,
+ ColorPickerManager colorPickerManager,
+ RuneLiteConfig runeLiteConfig,
+ PluginListPanel pluginList
+ )
+ {
+ super(false);
+
+ this.configManager = configManager;
+ this.colorPickerManager = colorPickerManager;
+
+ setLayout(new BorderLayout());
+ setBackground(ColorScheme.DARK_GRAY_COLOR);
+
+ JPanel topPanel = new JPanel();
+ topPanel.setBorder(new EmptyBorder(10, 10, 10, 10));
+ topPanel.setLayout(new BorderLayout(0, BORDER_OFFSET));
+ add(topPanel, BorderLayout.NORTH);
+
+ mainPanel = new FixedWidthPanel();
+ mainPanel.setBorder(new EmptyBorder(8, 10, 10, 10));
+ mainPanel.setLayout(new DynamicGridLayout(0, 1, 0, 5));
+ mainPanel.setAlignmentX(Component.LEFT_ALIGNMENT);
+
+ JPanel contentsPanel = new FixedWidthPanel();
+ contentsPanel.setLayout(new BorderLayout());
+ contentsPanel.add(mainPanel, BorderLayout.NORTH);
+
+ JScrollPane scrollPane = new JScrollPane(contentsPanel);
+ scrollPane.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
+ add(scrollPane, BorderLayout.CENTER);
+
+ JButton topPanelBackButton = new JButton(ConfigPanel.BACK_ICON);
+ SwingUtil.removeButtonDecorations(topPanelBackButton);
+ topPanelBackButton.setPreferredSize(new Dimension(22, 0));
+ topPanelBackButton.setBorder(new EmptyBorder(0, 0, 0, 5));
+ topPanelBackButton.addActionListener(e -> pluginList.getMuxer().popState());
+ topPanelBackButton.setToolTipText("Back");
+ topPanel.add(topPanelBackButton, BorderLayout.WEST);
+
+ title = new JLabel();
+ title.setForeground(Color.WHITE);
+ topPanel.add(title, BorderLayout.CENTER);
+
+ enabled = new JCheckBox();
+ enabled.addActionListener(l ->
+ {
+ Notification notif = loadNotification();
+ // If the notification has not been initialized yet, apply default config from the RuneLite settings
+ if (enabled.isSelected() && !notif.isInitialized())
+ {
+ log.debug("Initializing notification {}.{}", configDescriptor.getGroup().value(), configItemDescriptor.getItem().name());
+ notif = new Notification(true, true, true,
+ runeLiteConfig.enableTrayNotifications(), TrayIcon.MessageType.NONE, runeLiteConfig.notificationRequestFocus(),
+ runeLiteConfig.notificationSound(), runeLiteConfig.notificationVolume(), runeLiteConfig.notificationTimeout(),
+ runeLiteConfig.enableGameMessageNotification(), runeLiteConfig.flashNotification(), runeLiteConfig.notificationFlashColor(),
+ runeLiteConfig.sendNotificationsWhenFocused());
+ }
+ else
+ {
+ notif = notif.withOverride(enabled.isSelected());
+ }
+ saveNotification(notif);
+ rebuild(notif);
+ });
+ }
+
+ private void item(String name, String description, Component component)
+ {
+ JPanel item = new JPanel();
+ item.setLayout(new BorderLayout());
+ item.setMinimumSize(new Dimension(PANEL_WIDTH, 0));
+ JLabel configEntryName = new JLabel(name);
+ configEntryName.setForeground(Color.WHITE);
+ if (!"".equals(description))
+ {
+ configEntryName.setToolTipText("" + name + ":
" + description + "");
+ }
+ item.add(configEntryName, BorderLayout.CENTER);
+ item.add(component, BorderLayout.EAST);
+ mainPanel.add(item);
+ }
+
+ private JCheckBox checkbox(boolean selected)
+ {
+ JCheckBox checkbox = new JCheckBox();
+ checkbox.setSelected(selected);
+ return checkbox;
+ }
+
+ private > JComboBox> combobox(Class clazz, T value)
+ {
+ JComboBox> box = new JComboBox<>(clazz.getEnumConstants());
+ // set renderer prior to calling box.getPreferredSize(), since it will invoke the renderer
+ // to build components for each combobox element in order to compute the display size of the
+ // combobox
+ box.setRenderer(new TitleCaseListCellRenderer());
+ box.setPreferredSize(new Dimension(box.getPreferredSize().width, 22));
+
+ try
+ {
+ Enum> selectedItem = Enum.valueOf(clazz, value.name());
+ box.setSelectedItem(selectedItem);
+ box.setToolTipText(Text.titleCase(selectedItem));
+ }
+ catch (IllegalArgumentException ex)
+ {
+ log.debug("invalid selected item", ex);
+ }
+ box.addItemListener(e ->
+ {
+ if (e.getStateChange() == ItemEvent.SELECTED)
+ {
+ box.setToolTipText(Text.titleCase((Enum>) box.getSelectedItem()));
+ }
+ });
+
+ return box;
+ }
+
+ private JSpinner createIntSpinner(int min, int max, int value, String unit)
+ {
+ // Config may previously have been out of range
+ value = Ints.constrainToRange(value, min, max);
+
+ SpinnerModel model = new SpinnerNumberModel(value, min, max, 1);
+ JSpinner spinner = new JSpinner(model);
+ Component editor = spinner.getEditor();
+ JFormattedTextField spinnerTextField = ((JSpinner.DefaultEditor) editor).getTextField();
+ spinnerTextField.setColumns(6);
+ spinnerTextField.setFormatterFactory(new UnitFormatterFactory(unit));
+ return spinner;
+ }
+
+ private ColorJButton createColorPicker(String name, Color existing, Consumer onClose)
+ {
+ ColorJButton colorPickerBtn;
+
+ if (existing == null)
+ {
+ colorPickerBtn = new ColorJButton("Pick a color", Color.BLACK);
+ }
+ else
+ {
+ String colorHex = "#" + ColorUtil.colorToAlphaHexCode(existing).toUpperCase();
+ colorPickerBtn = new ColorJButton(colorHex, existing);
+ }
+
+ colorPickerBtn.setFocusable(false);
+ colorPickerBtn.addMouseListener(new MouseAdapter()
+ {
+ @Override
+ public void mouseClicked(MouseEvent e)
+ {
+ RuneliteColorPicker colorPicker = colorPickerManager.create(
+ SwingUtilities.windowForComponent(NotificationPanel.this),
+ colorPickerBtn.getColor(),
+ name,
+ false);
+ colorPicker.setLocationRelativeTo(colorPickerBtn);
+ colorPicker.setOnColorChange(c ->
+ {
+ colorPickerBtn.setColor(c);
+ colorPickerBtn.setText("#" + ColorUtil.colorToAlphaHexCode(c).toUpperCase());
+ });
+ colorPicker.setOnClose(onClose);
+ colorPicker.setVisible(true);
+ }
+ });
+
+ return colorPickerBtn;
+ }
+
+ void init(ConfigDescriptor cd, ConfigItemDescriptor cid)
+ {
+ title.setText(cid.name());
+
+ configDescriptor = cd;
+ configItemDescriptor = cid;
+
+ var notif = loadNotification();
+ enabled.setSelected(notif.isOverride());
+
+ rebuild(notif);
+ }
+
+ private void rebuild(Notification notif)
+ {
+ mainPanel.removeAll();
+
+ mainPanel.add(enabled);
+
+ item("Customize notification", "", enabled);
+
+ if (notif.isOverride())
+ {
+ var checkboxTray = checkbox(notif.isTray());
+ checkboxTray.addActionListener(ae ->
+ {
+ var n = loadNotification();
+ saveNotification(n.withTray(checkboxTray.isSelected()));
+ });
+ item("Tray notification", "Enables tray notifications", checkboxTray);
+
+ var comboboxRequestFocus = combobox(RequestFocusType.class, notif.getRequestFocus());
+ comboboxRequestFocus.addItemListener(e ->
+ {
+ if (e.getStateChange() == ItemEvent.SELECTED)
+ {
+ var n = loadNotification();
+ saveNotification(n.withRequestFocus((RequestFocusType) comboboxRequestFocus.getSelectedItem()));
+ }
+ });
+ item("Request focus", "Configures the window focus request type on notification", comboboxRequestFocus);
+
+ var comboboxSound = combobox(Notifier.NativeCustomOff.class, notif.getSound());
+ comboboxSound.addItemListener(e ->
+ {
+ if (e.getStateChange() == ItemEvent.SELECTED)
+ {
+ var n = loadNotification();
+ saveNotification(n.withSound((Notifier.NativeCustomOff) comboboxSound.getSelectedItem()));
+ }
+ });
+ item("Notification sound", "Enables the playing of a beep sound when notifications are displayed", comboboxSound);
+
+ var spinnerVolume = createIntSpinner(0, 100, notif.getVolume(), "%");
+ spinnerVolume.addChangeListener(ce ->
+ {
+ var n = loadNotification();
+ saveNotification(n.withVolume((int) spinnerVolume.getValue()));
+ });
+ item("Notification volume", "Configures the volume of custom notifications (does not control native volume).", spinnerVolume);
+
+ var spinnerTimeout = createIntSpinner(0, Integer.MAX_VALUE, notif.getTimeout(), "ms");
+ spinnerVolume.addChangeListener(ce ->
+ {
+ var n = loadNotification();
+ saveNotification(n.withTimeout((int) spinnerTimeout.getValue()));
+ });
+ item("Notification timeout", "How long notification will be shown in milliseconds. A value of 0 will make it use the system configuration. (Linux only)", spinnerTimeout);
+
+ var checkboxGameMessage = checkbox(notif.isGameMessage());
+ checkboxGameMessage.addActionListener(ae ->
+ {
+ var n = loadNotification();
+ saveNotification(n.withGameMessage(checkboxGameMessage.isSelected()));
+ });
+ item("Game message notification", "Adds a notification message to the chatbox", checkboxGameMessage);
+
+ var comboboxFlash = combobox(FlashNotification.class, notif.getFlash());
+ comboboxFlash.addItemListener(e ->
+ {
+ if (e.getStateChange() == ItemEvent.SELECTED)
+ {
+ var n = loadNotification();
+ saveNotification(n.withFlash((FlashNotification) comboboxFlash.getSelectedItem()));
+ }
+ });
+ item("Flash", "Flashes the game frame as a notification", combobox(FlashNotification.class, notif.getFlash()));
+
+ var colorpickerFlashColor = createColorPicker("Flash color", notif.getFlashColor(), c ->
+ {
+ var n = loadNotification();
+ saveNotification(n.withFlashColor(c));
+ });
+ item("Flash color", "Sets the color of the notification flashes.", colorpickerFlashColor);
+
+ var checkboxSendWhenFocused = checkbox(notif.isSendWhenFocused());
+ checkboxSendWhenFocused.addActionListener(ae ->
+ {
+ var n = loadNotification();
+ saveNotification(n.withSendWhenFocused(checkboxSendWhenFocused.isSelected()));
+ });
+ item("Send notifications when focused", "Sends the notification even when the client is focused", checkboxSendWhenFocused);
+
+ JButton resetButton = new JButton("Reset");
+ resetButton.addActionListener((e) ->
+ {
+ final int result = JOptionPane.showOptionDialog(resetButton, "Are you sure you want to reset this notification configuration?",
+ "Are you sure?", JOptionPane.YES_NO_OPTION, JOptionPane.WARNING_MESSAGE,
+ null, new String[]{"Yes", "No"}, "No");
+
+ if (result == JOptionPane.YES_OPTION)
+ {
+ enabled.setSelected(false);
+
+ // Reset every setting
+ var n = new Notification().withEnabled(true);
+ saveNotification(n);
+ rebuild(n);
+ }
+ });
+ mainPanel.add(resetButton);
+ }
+ else
+ {
+ JPanel infoPanel = new JPanel();
+ infoPanel.setLayout(new BorderLayout());
+ mainPanel.add(infoPanel);
+
+ infoPanel.setBorder(new EmptyBorder(10, 0, 0, 0));
+ infoPanel.add(new JLabel("Notification settings can be customized for each type of notification. Notifications without custom settings use the default settings found in the 'RuneLite' configuration under 'Notification Settings'."));
+ }
+ }
+
+ private Notification loadNotification()
+ {
+ return configManager.getConfiguration(configDescriptor.getGroup().value(), configItemDescriptor.getItem().keyName(), Notification.class);
+ }
+
+ private void saveNotification(Notification notification)
+ {
+ configManager.setConfiguration(configDescriptor.getGroup().value(), configItemDescriptor.getItem().keyName(), notification);
+ }
+}
diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/config/PluginConfigurationDescriptor.java b/runelite-client/src/main/java/net/runelite/client/plugins/config/PluginConfigurationDescriptor.java
index 5a753baba7..05408ee192 100644
--- a/runelite-client/src/main/java/net/runelite/client/plugins/config/PluginConfigurationDescriptor.java
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/config/PluginConfigurationDescriptor.java
@@ -57,11 +57,6 @@ class PluginConfigurationDescriptor
@Nullable
private final List conflicts;
- boolean hasConfigurables()
- {
- return configDescriptor != null && !configDescriptor.getItems().stream().allMatch(item -> item.getItem().hidden());
- }
-
PluginConfigurationDescriptor(String name, String description, String[] tags, Config config, ConfigDescriptor configDescriptor)
{
this(name, description, tags, null, config, configDescriptor, null);
diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/config/PluginListItem.java b/runelite-client/src/main/java/net/runelite/client/plugins/config/PluginListItem.java
index 09220a0176..91436e2b57 100644
--- a/runelite-client/src/main/java/net/runelite/client/plugins/config/PluginListItem.java
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/config/PluginListItem.java
@@ -54,7 +54,6 @@
class PluginListItem extends JPanel implements SearchablePlugin
{
- private static final ImageIcon CONFIG_ICON;
private static final ImageIcon ON_STAR;
private static final ImageIcon OFF_STAR;
@@ -71,9 +70,7 @@ class PluginListItem extends JPanel implements SearchablePlugin
static
{
- BufferedImage configIcon = ImageUtil.loadImageResource(ConfigPanel.class, "config_edit_icon.png");
BufferedImage onStar = ImageUtil.loadImageResource(ConfigPanel.class, "star_on.png");
- CONFIG_ICON = new ImageIcon(configIcon);
ON_STAR = new ImageIcon(onStar);
BufferedImage offStar = ImageUtil.luminanceScale(
@@ -131,9 +128,9 @@ class PluginListItem extends JPanel implements SearchablePlugin
add(buttonPanel, BorderLayout.LINE_END);
JMenuItem configMenuItem = null;
- if (pluginConfig.hasConfigurables())
+ if (pluginConfig.getConfigDescriptor() != null)
{
- JButton configButton = new JButton(CONFIG_ICON);
+ JButton configButton = new JButton(ConfigPanel.CONFIG_ICON);
SwingUtil.removeButtonDecorations(configButton);
configButton.setPreferredSize(new Dimension(25, 0));
configButton.setVisible(false);
@@ -141,7 +138,7 @@ class PluginListItem extends JPanel implements SearchablePlugin
configButton.addActionListener(e ->
{
- configButton.setIcon(CONFIG_ICON);
+ configButton.setIcon(ConfigPanel.CONFIG_ICON);
openGroupConfigPanel();
});
diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/config/UnitFormatter.java b/runelite-client/src/main/java/net/runelite/client/plugins/config/UnitFormatter.java
index efe2181d9b..0f7f477314 100644
--- a/runelite-client/src/main/java/net/runelite/client/plugins/config/UnitFormatter.java
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/config/UnitFormatter.java
@@ -29,15 +29,14 @@
import java.util.Map;
import javax.swing.JFormattedTextField;
import lombok.RequiredArgsConstructor;
-import net.runelite.client.config.Units;
final class UnitFormatter extends JFormattedTextField.AbstractFormatter
{
private final String units;
- UnitFormatter(Units units)
+ UnitFormatter(String units)
{
- this.units = units.value();
+ this.units = units;
}
@Override
@@ -75,7 +74,7 @@ public String valueToString(final Object value)
@RequiredArgsConstructor
final class UnitFormatterFactory extends JFormattedTextField.AbstractFormatterFactory
{
- private final Units units;
+ private final String units;
private final Map formatters = new HashMap<>();
@Override
diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/devtools/DevToolsPanel.java b/runelite-client/src/main/java/net/runelite/client/plugins/devtools/DevToolsPanel.java
index b0f6d0df59..c751b25aaa 100644
--- a/runelite-client/src/main/java/net/runelite/client/plugins/devtools/DevToolsPanel.java
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/devtools/DevToolsPanel.java
@@ -41,6 +41,7 @@
import net.runelite.api.MenuAction;
import net.runelite.client.Notifier;
import net.runelite.client.callback.ClientThread;
+import net.runelite.client.config.Notification;
import net.runelite.client.ui.ColorScheme;
import net.runelite.client.ui.PluginPanel;
import net.runelite.client.ui.overlay.OverlayMenuEntry;
@@ -144,9 +145,13 @@ private JPanel createOptionsPanel()
final JButton notificationBtn = new JButton("Notification");
notificationBtn.addActionListener(e ->
- {
- scheduledExecutorService.schedule(() -> notifier.notify("Wow!", TrayIcon.MessageType.ERROR), 3, TimeUnit.SECONDS);
- });
+ scheduledExecutorService.schedule(() ->
+ {
+ var notif = new Notification()
+ .withEnabled(true)
+ .withTrayIconType(TrayIcon.MessageType.ERROR);
+ notifier.notify(notif, "Wow!");
+ }, 3, TimeUnit.SECONDS));
container.add(notificationBtn);
container.add(plugin.getScriptInspector());
diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/discord/DiscordGameEventType.java b/runelite-client/src/main/java/net/runelite/client/plugins/discord/DiscordGameEventType.java
index 10184a56f7..dc215ecfb7 100644
--- a/runelite-client/src/main/java/net/runelite/client/plugins/discord/DiscordGameEventType.java
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/discord/DiscordGameEventType.java
@@ -108,8 +108,10 @@ enum DiscordGameEventType
CITY_BRIMHAVEN("Brimhaven" , DiscordAreaType.CITIES, 11057, 11058),
CITY_BURGH_DE_ROTT("Burgh de Rott" , DiscordAreaType.CITIES, 13874, 13873, 14130, 14129),
CITY_BURTHORPE("Burthorpe" , DiscordAreaType.CITIES, 11319, 11575),
+ CITY_CAM_TORUM("Cam Torum" , DiscordAreaType.CITIES, 5525, 5780, 5781, 6037),
CITY_CANIFIS("Canifis" , DiscordAreaType.CITIES, 13878),
CITY_CATHERBY("Catherby" , DiscordAreaType.CITIES, 11317, 11318, 11061),
+ CITY_CIVITAS_ILLA_FORTIS("Civitas Illa Fortis" , DiscordAreaType.CITIES, 6448, 6449, 6704, 6705, 6960, 6961),
CITY_CORSAIR_COVE("Corsair Cove" , DiscordAreaType.CITIES, 10028, 10284),
CITY_DARKMEYER("Darkmeyer", DiscordAreaType.CITIES, 14388, 14644),
CITY_DORGESH_KAAN("Dorgesh-Kaan" , DiscordAreaType.CITIES, 10835, 10834),
@@ -189,6 +191,7 @@ enum DiscordGameEventType
DUNGEON_CHASM_OF_FIRE("Chasm of Fire", DiscordAreaType.DUNGEONS, 5789),
DUNGEON_CHASM_OF_TEARS("Chasm of Tears", DiscordAreaType.DUNGEONS, 12948),
DUNGEON_CHINCHOMPA("Chinchompa Hunting Ground", DiscordAreaType.DUNGEONS, 10129),
+ DUNGEON_CIVITAS_ILLA_FORTIS("Civitas illa Fortis Underground", DiscordAreaType.DUNGEONS, 6549, 6804, 6805),
DUNGEON_CLOCK_TOWER("Clock Tower Basement", DiscordAreaType.DUNGEONS, 10390),
DUNGEON_CORSAIR_COVE("Corsair Cove Dungeon", DiscordAreaType.DUNGEONS, 8076, 8332),
DUNGEON_CRABCLAW_CAVES("Crabclaw Caves", DiscordAreaType.DUNGEONS, 6553, 6809),
@@ -266,6 +269,7 @@ enum DiscordGameEventType
DUNGEON_TEMPLE_OF_IKOV("Temple of Ikov", DiscordAreaType.DUNGEONS, 10649, 10905, 10650),
DUNGEON_TEMPLE_OF_LIGHT("Temple of Light", DiscordAreaType.DUNGEONS, 7496),
DUNGEON_TEMPLE_OF_MARIMBO("Temple of Marimbo", DiscordAreaType.DUNGEONS, 11151),
+ DUNGEON_THE_BURROW("The Burrow", DiscordAreaType.DUNGEONS, 6291),
DUNGEON_THE_WARRENS("The Warrens", DiscordAreaType.DUNGEONS, 7070, 7326),
DUNGEON_TOLNA("Dungeon of Tolna", DiscordAreaType.DUNGEONS, 13209),
DUNGEON_TOWER_OF_LIFE("Tower of Life Basement", DiscordAreaType.DUNGEONS, 12100),
@@ -297,6 +301,8 @@ enum DiscordGameEventType
MG_CLAN_WARS("Clan Wars", DiscordAreaType.MINIGAMES, 12621, 12622, 12623, 13130, 13131, 13133, 13134, 13135, 13386, 13387, 13390, 13641, 13642, 13643, 13644, 13645, 13646, 13647, 13899, 13900, 14155, 14156),
MG_PVP_ARENA("PvP Arena", DiscordAreaType.MINIGAMES, 13362, 13363),
MG_FISHING_TRAWLER("Fishing Trawler", DiscordAreaType.MINIGAMES, 7499),
+ MG_FORTIS_COLOSSEUM("Fortis Colosseum", DiscordAreaType.MINIGAMES, 7216),
+ MG_FORTIS_COLOSSEUM_LOBBY("Fortis Colosseum Lobby", DiscordAreaType.MINIGAMES, 7316),
MG_GAUNTLET("The Gauntlet", DiscordAreaType.MINIGAMES, 12127, 7512),
MG_CORRUPTED_GAUNTLET("Corrupted Gauntlet", DiscordAreaType.MINIGAMES, 7768),
MG_GIANTS_FOUNDRY("Giants' Foundry", DiscordAreaType.MINIGAMES, 13491),
@@ -339,6 +345,7 @@ enum DiscordGameEventType
REGION_APE_ATOLL("Ape Atoll" , DiscordAreaType.REGIONS, 10794, 10795, 10974, 11050),
REGION_ARANDAR("Arandar", DiscordAreaType.REGIONS, 9266, 9267, 9523),
REGION_ASGARNIA("Asgarnia", DiscordAreaType.REGIONS, 11825, 11829, 11830, 12085, 12086),
+ REGION_AVIUM_SAVANNAH("Avium Savannah", DiscordAreaType.REGIONS, 5935, 5936, 5937, 6189, 6445, 6446, 6447, 6701, 6702, 6703, 6957, 6958, 6959, 7215),
REGION_BATTLEFIELD("Battlefield", DiscordAreaType.REGIONS, 10034),
REGION_BATTLEFRONT("Battlefront", DiscordAreaType.REGIONS, 5433, 5434),
REGION_BLAST_MINE("Blast Mine", DiscordAreaType.REGIONS, 5948),
@@ -386,6 +393,7 @@ enum DiscordGameEventType
REGION_GWD("God Wars Dungeon", DiscordAreaType.REGIONS, 11578),
REGION_HARMONY("Harmony Island", DiscordAreaType.REGIONS, 15148),
REGION_HAZELMERE("Hazelmere's Island", DiscordAreaType.REGIONS, 10544),
+ REGION_HUNTER_GUILD("Hunter Guild", DiscordAreaType.REGIONS, 6191),
REGION_ICE_PATH("Ice Path", DiscordAreaType.REGIONS, 11322, 11323),
REGION_ICEBERG("Iceberg", DiscordAreaType.REGIONS, 10558, 10559),
REGION_ICYENE_GRAVEYARD("Icyene Graveyard", DiscordAreaType.REGIONS, 14641, 14897, 14898),
@@ -425,6 +433,7 @@ enum DiscordGameEventType
REGION_NORTHERN_TUNDRAS("Northern Tundras", DiscordAreaType.REGIONS, 6204, 6205, 6717),
REGION_OBSERVATORY("Observatory", DiscordAreaType.REGIONS, 9777),
REGION_ODD_ONE_OUT("Odd One Out", DiscordAreaType.REGIONS, 7754),
+ REGION_ORTUS_FARM("Ortus Farm", DiscordAreaType.REGIONS, 6192, 6193),
REGION_OTTOS_GROTTO("Otto's Grotto", DiscordAreaType.REGIONS, 10038),
REGION_OURANIA_HUNTER("Ourania Hunter Area", DiscordAreaType.REGIONS, 9778),
REGION_PIRATES_COVE("Pirates' Cove", DiscordAreaType.REGIONS, 8763),
@@ -434,6 +443,7 @@ enum DiscordGameEventType
REGION_PORT_TYRAS("Port Tyras", DiscordAreaType.REGIONS, 8496),
REGION_PURO_PURO("Puro Puro", DiscordAreaType.REGIONS, 10307),
REGION_QUARRY("Quarry", DiscordAreaType.REGIONS, 12589),
+ REGION_RALOS_RISE("Ralos' Rise", DiscordAreaType.REGIONS, 5424, 5425, 5679, 5680, 5681, 5682),
REGION_RANGING_GUILD("Ranging Guild", DiscordAreaType.REGIONS, 10549),
REGION_RATCATCHERS_MANSION("Ratcatchers Mansion", DiscordAreaType.REGIONS, 11343),
REGION_RUINS_OF_UNKAH("Ruins of Unkah", DiscordAreaType.REGIONS, 12588),
@@ -449,6 +459,7 @@ enum DiscordGameEventType
REGION_SLAYER_TOWER("Slayer Tower", DiscordAreaType.REGIONS, 13623, 13723),
REGION_SOUL_ALTAR("Soul Altar", DiscordAreaType.REGIONS, 7228),
REGION_STRANGLEWOOD_TEMPLE("Stranglewood Temple", DiscordAreaType.REGIONS, 4761),
+ REGION_SUNSET_COAST("Sunset Coast", DiscordAreaType.REGIONS, 5934, 6190),
REGION_THE_SCAR("The Scar", DiscordAreaType.REGIONS, 8036, 8292),
REGION_THE_STRANGLEWOOD("The Stranglewood", DiscordAreaType.REGIONS, 4403, 4404, 4659, 4660, 4661, 4916, 4917),
REGION_TROLL_ARENA("Troll Arena", DiscordAreaType.REGIONS, 11576),
diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/emojis/EmojiPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/emojis/EmojiPlugin.java
index c439916b72..48b526f782 100644
--- a/runelite-client/src/main/java/net/runelite/client/plugins/emojis/EmojiPlugin.java
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/emojis/EmojiPlugin.java
@@ -29,7 +29,6 @@
import javax.annotation.Nullable;
import javax.inject.Inject;
import joptsimple.internal.Strings;
-import lombok.extern.slf4j.Slf4j;
import net.runelite.api.MessageNode;
import net.runelite.api.Player;
import net.runelite.api.events.ChatMessage;
@@ -45,7 +44,6 @@
description = "Replaces common emoticons such as :) with their corresponding emoji in the chat",
enabledByDefault = false
)
-@Slf4j
public class EmojiPlugin extends Plugin
{
private static final Pattern WHITESPACE_REGEXP = Pattern.compile("[\\s\\u00A0]");
diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/fishing/FishingConfig.java b/runelite-client/src/main/java/net/runelite/client/plugins/fishing/FishingConfig.java
index f0f37fdbc5..bc327f7bef 100644
--- a/runelite-client/src/main/java/net/runelite/client/plugins/fishing/FishingConfig.java
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/fishing/FishingConfig.java
@@ -29,6 +29,7 @@
import net.runelite.client.config.Config;
import net.runelite.client.config.ConfigGroup;
import net.runelite.client.config.ConfigItem;
+import net.runelite.client.config.Notification;
import net.runelite.client.config.Units;
@ConfigGroup("fishing")
@@ -166,9 +167,9 @@ default boolean showMinnowOverlay()
name = "Flying fish notification",
description = "Send a notification when a flying fish spawns on your fishing spot."
)
- default boolean flyingFishNotification()
+ default Notification flyingFishNotification()
{
- return true;
+ return Notification.ON;
}
@ConfigItem(
diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/fishing/FishingPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/fishing/FishingPlugin.java
index d821ca5c05..2c60502b76 100644
--- a/runelite-client/src/main/java/net/runelite/client/plugins/fishing/FishingPlugin.java
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/fishing/FishingPlugin.java
@@ -205,9 +205,9 @@ public void onChatMessage(ChatMessage event)
fishingSpotMinimapOverlay.setHidden(false);
}
- if (message.equals("A flying fish jumps up and eats some of your minnows!") && config.flyingFishNotification())
+ if (message.equals("A flying fish jumps up and eats some of your minnows!"))
{
- notifier.notify("A flying fish is eating your minnows!");
+ notifier.notify(config.flyingFishNotification(), "A flying fish is eating your minnows!");
}
}
diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/gpu/GpuPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/gpu/GpuPlugin.java
index 0470bdf528..4e7f7afdb0 100644
--- a/runelite-client/src/main/java/net/runelite/client/plugins/gpu/GpuPlugin.java
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/gpu/GpuPlugin.java
@@ -815,14 +815,11 @@ private void initUniformBuffer()
private void initAAFbo(int width, int height, int aaSamples)
{
- if (OSType.getOSType() != OSType.MacOS)
- {
- final GraphicsConfiguration graphicsConfiguration = clientUI.getGraphicsConfiguration();
- final AffineTransform transform = graphicsConfiguration.getDefaultTransform();
+ final GraphicsConfiguration graphicsConfiguration = clientUI.getGraphicsConfiguration();
+ final AffineTransform transform = graphicsConfiguration.getDefaultTransform();
- width = getScaledValue(transform.getScaleX(), width);
- height = getScaledValue(transform.getScaleY(), height);
- }
+ width = getScaledValue(transform.getScaleX(), width);
+ height = getScaledValue(transform.getScaleY(), height);
// Create and bind the FBO
fboSceneHandle = GL43C.glGenFramebuffers();
@@ -1273,7 +1270,7 @@ public void draw(int overlayColor)
if (gameState == GameState.LOGGED_IN)
{
// avoid textures animating during loading
- GL43C.glUniform1i(uniTick, client.getGameCycle());
+ GL43C.glUniform1i(uniTick, client.getGameCycle() & 127);
}
// Calculate projection matrix
@@ -1332,14 +1329,11 @@ public void draw(int overlayColor)
int width = lastStretchedCanvasWidth;
int height = lastStretchedCanvasHeight;
- if (OSType.getOSType() != OSType.MacOS)
- {
- final GraphicsConfiguration graphicsConfiguration = clientUI.getGraphicsConfiguration();
- final AffineTransform transform = graphicsConfiguration.getDefaultTransform();
+ final GraphicsConfiguration graphicsConfiguration = clientUI.getGraphicsConfiguration();
+ final AffineTransform transform = graphicsConfiguration.getDefaultTransform();
- width = getScaledValue(transform.getScaleX(), width);
- height = getScaledValue(transform.getScaleY(), height);
- }
+ width = getScaledValue(transform.getScaleX(), width);
+ height = getScaledValue(transform.getScaleY(), height);
GL43C.glBindFramebuffer(GL43C.GL_READ_FRAMEBUFFER, fboSceneHandle);
GL43C.glBindFramebuffer(GL43C.GL_DRAW_FRAMEBUFFER, awtContext.getFramebuffer(false));
@@ -1421,13 +1415,10 @@ private void drawUi(final int overlayColor, final int canvasHeight, final int ca
// Set the sampling function used when stretching the UI.
// This is probably better done with sampler objects instead of texture parameters, but this is easier and likely more portable.
// See https://www.khronos.org/opengl/wiki/Sampler_Object for details.
- if (client.isStretchedEnabled())
- {
- // GL_NEAREST makes sampling for bicubic/xBR simpler, so it should be used whenever linear isn't
- final int function = uiScalingMode == UIScalingMode.LINEAR ? GL43C.GL_LINEAR : GL43C.GL_NEAREST;
- GL43C.glTexParameteri(GL43C.GL_TEXTURE_2D, GL43C.GL_TEXTURE_MIN_FILTER, function);
- GL43C.glTexParameteri(GL43C.GL_TEXTURE_2D, GL43C.GL_TEXTURE_MAG_FILTER, function);
- }
+ // GL_NEAREST makes sampling for bicubic/xBR simpler, so it should be used whenever linear isn't
+ final int function = uiScalingMode == UIScalingMode.LINEAR ? GL43C.GL_LINEAR : GL43C.GL_NEAREST;
+ GL43C.glTexParameteri(GL43C.GL_TEXTURE_2D, GL43C.GL_TEXTURE_MIN_FILTER, function);
+ GL43C.glTexParameteri(GL43C.GL_TEXTURE_2D, GL43C.GL_TEXTURE_MAG_FILTER, function);
// Texture on UI
GL43C.glBindVertexArray(vaoUiHandle);
@@ -1458,13 +1449,10 @@ private Image screenshot()
height = dim.height;
}
- if (OSType.getOSType() != OSType.MacOS)
- {
- final GraphicsConfiguration graphicsConfiguration = clientUI.getGraphicsConfiguration();
- final AffineTransform t = graphicsConfiguration.getDefaultTransform();
- width = getScaledValue(t.getScaleX(), width);
- height = getScaledValue(t.getScaleY(), height);
- }
+ final GraphicsConfiguration graphicsConfiguration = clientUI.getGraphicsConfiguration();
+ final AffineTransform t = graphicsConfiguration.getDefaultTransform();
+ width = getScaledValue(t.getScaleX(), width);
+ height = getScaledValue(t.getScaleY(), height);
ByteBuffer buffer = ByteBuffer.allocateDirect(width * height * 4)
.order(ByteOrder.nativeOrder());
@@ -1852,21 +1840,13 @@ private int getScaledValue(final double scale, final int value)
private void glDpiAwareViewport(final int x, final int y, final int width, final int height)
{
- if (OSType.getOSType() == OSType.MacOS)
- {
- // macos handles DPI scaling for us already
- GL43C.glViewport(x, y, width, height);
- }
- else
- {
- final GraphicsConfiguration graphicsConfiguration = clientUI.getGraphicsConfiguration();
- final AffineTransform t = graphicsConfiguration.getDefaultTransform();
- GL43C.glViewport(
- getScaledValue(t.getScaleX(), x),
- getScaledValue(t.getScaleY(), y),
- getScaledValue(t.getScaleX(), width),
- getScaledValue(t.getScaleY(), height));
- }
+ final GraphicsConfiguration graphicsConfiguration = clientUI.getGraphicsConfiguration();
+ final AffineTransform t = graphicsConfiguration.getDefaultTransform();
+ GL43C.glViewport(
+ getScaledValue(t.getScaleX(), x),
+ getScaledValue(t.getScaleY(), y),
+ getScaledValue(t.getScaleX(), width),
+ getScaledValue(t.getScaleY(), height));
}
private int getDrawDistance()
diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/gpu/regions/Regions.java b/runelite-client/src/main/java/net/runelite/client/plugins/gpu/regions/Regions.java
index 0b6bd81769..99dce1a6cf 100644
--- a/runelite-client/src/main/java/net/runelite/client/plugins/gpu/regions/Regions.java
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/gpu/regions/Regions.java
@@ -36,9 +36,7 @@
import java.util.regex.Pattern;
import lombok.AccessLevel;
import lombok.Getter;
-import lombok.extern.slf4j.Slf4j;
-@Slf4j
public class Regions
{
private static final Pattern PATTERN = Pattern.compile("^[ \\t]*(?" +
diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/grandexchange/GrandExchangeConfig.java b/runelite-client/src/main/java/net/runelite/client/plugins/grandexchange/GrandExchangeConfig.java
index b57d92a566..20f32b3812 100644
--- a/runelite-client/src/main/java/net/runelite/client/plugins/grandexchange/GrandExchangeConfig.java
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/grandexchange/GrandExchangeConfig.java
@@ -27,6 +27,7 @@
import net.runelite.client.config.Config;
import net.runelite.client.config.ConfigGroup;
import net.runelite.client.config.ConfigItem;
+import net.runelite.client.config.Notification;
@ConfigGroup(GrandExchangeConfig.CONFIG_GROUP)
public interface GrandExchangeConfig extends Config
@@ -50,9 +51,9 @@ default boolean quickLookup()
name = "Notify on offer update",
description = "Configures whether to enable notifications when an offer updates"
)
- default boolean enableNotifications()
+ default Notification enableNotifications()
{
- return true;
+ return Notification.ON;
}
@ConfigItem(
@@ -61,9 +62,9 @@ default boolean enableNotifications()
name = "Notify on offer complete",
description = "Configures whether to enable notifications when an offer completes"
)
- default boolean notifyOnOfferComplete()
+ default Notification notifyOnOfferComplete()
{
- return false;
+ return Notification.OFF;
}
@ConfigItem(
diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/grandexchange/GrandExchangePlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/grandexchange/GrandExchangePlugin.java
index 4a4755de5c..82f24b20f0 100644
--- a/runelite-client/src/main/java/net/runelite/client/plugins/grandexchange/GrandExchangePlugin.java
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/grandexchange/GrandExchangePlugin.java
@@ -606,13 +606,13 @@ public void onChatMessage(ChatMessage event)
String message = Text.removeTags(event.getMessage());
- if (message.startsWith("Grand Exchange:") && config.enableNotifications())
+ if (message.startsWith("Grand Exchange: Finished"))
{
- notifier.notify(message);
+ notifier.notify(config.notifyOnOfferComplete(), message);
}
- else if (message.startsWith("Grand Exchange: Finished") && config.notifyOnOfferComplete())
+ else if (message.startsWith("Grand Exchange:"))
{
- notifier.notify(message);
+ notifier.notify(config.enableNotifications(), message);
}
}
diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/grounditems/GroundItem.java b/runelite-client/src/main/java/net/runelite/client/plugins/grounditems/GroundItem.java
index 89eae64fcc..ea51c350b2 100644
--- a/runelite-client/src/main/java/net/runelite/client/plugins/grounditems/GroundItem.java
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/grounditems/GroundItem.java
@@ -25,6 +25,7 @@
package net.runelite.client.plugins.grounditems;
import java.awt.Color;
+import java.time.Duration;
import java.time.Instant;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
@@ -51,6 +52,8 @@ class GroundItem
@Nullable
private Instant spawnTime;
private boolean stackable;
+ private Duration despawnTime;
+ private Duration visibleTime;
// cached values derived from config
boolean highlighted;
diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/grounditems/GroundItemsOverlay.java b/runelite-client/src/main/java/net/runelite/client/plugins/grounditems/GroundItemsOverlay.java
index 7fe3a555c2..eb6da70f0e 100644
--- a/runelite-client/src/main/java/net/runelite/client/plugins/grounditems/GroundItemsOverlay.java
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/grounditems/GroundItemsOverlay.java
@@ -31,9 +31,7 @@
import java.awt.Graphics2D;
import java.awt.Polygon;
import java.awt.Rectangle;
-import java.time.Duration;
import java.time.Instant;
-import java.time.temporal.ChronoUnit;
import java.util.AbstractMap.SimpleEntry;
import java.util.ArrayList;
import java.util.Collection;
@@ -72,23 +70,6 @@ public class GroundItemsOverlay extends Overlay
private static final Color PUBLIC_TIMER_COLOR = Color.YELLOW;
private static final Color PRIVATE_TIMER_COLOR = Color.GREEN;
private static final int TIMER_OVERLAY_DIAMETER = 10;
- private static final Duration DESPAWN_TIME_INFERNO = Duration.ofMinutes(180);
- private static final Duration DESPAWN_TIME_INSTANCE = Duration.ofMinutes(30);
- private static final Duration DESPAWN_TIME_LOOT = Duration.ofMinutes(2);
- private static final Duration DESPAWN_TIME_DROP = Duration.ofMinutes(3);
- private static final Duration DESPAWN_TIME_TABLE = Duration.ofMinutes(10);
- private static final int KRAKEN_REGION = 9116;
- private static final int CLAN_HALL_REGION = 6997;
- private static final int KBD_NMZ_REGION = 9033;
- private static final int ZILYANA_REGION = 11602;
- private static final int GRAARDOR_REGION = 11347;
- private static final int KRIL_TSUTSAROTH_REGION = 11603;
- private static final int KREEARRA_REGION = 11346;
- private static final int NEX_REGION = 11601;
- private static final int NIGHTMARE_REGION = 15515;
- private static final int TEMPOROSS_REGION = 12078;
- private static final int KALPHITE_QUEEN_REGION = 13972;
- private static final int INFERNO_REGION = 9043;
private final Client client;
private final GroundItemsPlugin plugin;
@@ -398,92 +379,14 @@ else if (groundItemTimers == DespawnTimerMode.SECONDS || groundItemTimers == Des
private Instant calculateDespawnTime(GroundItem groundItem)
{
- // We can only accurately guess despawn times for our own pvm loot, dropped items,
- // and items we placed on tables
- if (groundItem.getLootType() != LootType.PVM
- && groundItem.getLootType() != LootType.DROPPED
- && groundItem.getLootType() != LootType.TABLE)
- {
- return null;
- }
-
- // Loot appears to others after 1 minute, and despawns after 2 minutes
- // Dropped items appear to others after 1 minute, and despawns after 3 minutes
- // Items in instances never appear to anyone and despawn after 30 minutes
-
Instant spawnTime = groundItem.getSpawnTime();
if (spawnTime == null)
{
return null;
}
- final Instant despawnTime;
- Instant now = Instant.now();
- if (client.isInInstancedRegion())
- {
- final int playerRegionID = WorldPoint.fromLocalInstance(client, client.getLocalPlayer().getLocalLocation()).getRegionID();
- if (playerRegionID == KRAKEN_REGION)
- {
- // Items in the Kraken instance never despawn
- return null;
- }
- else if (playerRegionID == KBD_NMZ_REGION)
- {
- // NMZ and the KBD lair uses the same region ID but NMZ uses planes 1-3 and KBD uses plane 0
- if (client.getLocalPlayer().getWorldLocation().getPlane() == 0)
- {
- despawnTime = spawnTime.plus(DESPAWN_TIME_INSTANCE);
- }
- else
- {
- if (groundItem.getLootType() == LootType.DROPPED)
- {
- // Dropped items in the NMZ instance never despawn
- return null;
- }
- else
- {
- despawnTime = spawnTime.plus(DESPAWN_TIME_LOOT);
- }
- }
- }
- else if (playerRegionID == INFERNO_REGION)
- {
- despawnTime = spawnTime.plus(DESPAWN_TIME_INFERNO);
- }
- else if (playerRegionID == ZILYANA_REGION || playerRegionID == GRAARDOR_REGION ||
- playerRegionID == KRIL_TSUTSAROTH_REGION || playerRegionID == KREEARRA_REGION ||
- playerRegionID == NEX_REGION || playerRegionID == KALPHITE_QUEEN_REGION ||
- playerRegionID == NIGHTMARE_REGION || playerRegionID == TEMPOROSS_REGION ||
- playerRegionID == CLAN_HALL_REGION)
- {
- // GWD, Kalphite Queen, Nightmare, and Tempoross instances use the normal despawn timers
- despawnTime = spawnTime.plus(groundItem.getLootType() == LootType.DROPPED
- ? DESPAWN_TIME_DROP
- : DESPAWN_TIME_LOOT);
- }
- else
- {
- despawnTime = spawnTime.plus(DESPAWN_TIME_INSTANCE);
- }
- }
- else
- {
- switch (groundItem.getLootType())
- {
- case DROPPED:
- despawnTime = spawnTime.plus(DESPAWN_TIME_DROP);
- break;
- case TABLE:
- despawnTime = spawnTime.plus(DESPAWN_TIME_TABLE);
- break;
- default:
- despawnTime = spawnTime.plus(DESPAWN_TIME_LOOT);
- break;
- }
- }
-
- if (now.isBefore(spawnTime) || now.isAfter(despawnTime))
+ Instant despawnTime = spawnTime.plus(groundItem.getDespawnTime());
+ if (Instant.now().isAfter(despawnTime))
{
// that's weird
return null;
@@ -494,15 +397,6 @@ else if (playerRegionID == ZILYANA_REGION || playerRegionID == GRAARDOR_REGION |
private Color getItemTimerColor(GroundItem groundItem)
{
- // We can only accurately guess despawn times for our own pvm loot, dropped items,
- // and items we placed on tables
- if (groundItem.getLootType() != LootType.PVM
- && groundItem.getLootType() != LootType.DROPPED
- && groundItem.getLootType() != LootType.TABLE)
- {
- return null;
- }
-
final Instant spawnTime = groundItem.getSpawnTime();
if (spawnTime == null)
{
@@ -510,16 +404,19 @@ private Color getItemTimerColor(GroundItem groundItem)
}
final Instant now = Instant.now();
+ final Instant despawnTime = spawnTime.plus(groundItem.getDespawnTime());
+ final Instant visibleTime = spawnTime.plus(groundItem.getVisibleTime());
- // If it has not yet been a minute, the item is private
- if (client.isInInstancedRegion() || spawnTime.plus(1, ChronoUnit.MINUTES).isAfter(now))
+ if (visibleTime != null && visibleTime.isAfter(now))
{
return PRIVATE_TIMER_COLOR;
}
- else
+ if (despawnTime != null && despawnTime.isAfter(now))
{
return PUBLIC_TIMER_COLOR;
}
+
+ return null;
}
private void drawTimerPieOverlay(Graphics2D graphics, int textX, int textY, GroundItem groundItem)
diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/grounditems/GroundItemsPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/grounditems/GroundItemsPlugin.java
index 404027fe54..02326f7036 100644
--- a/runelite-client/src/main/java/net/runelite/client/plugins/grounditems/GroundItemsPlugin.java
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/grounditems/GroundItemsPlugin.java
@@ -38,6 +38,7 @@
import java.awt.Rectangle;
import static java.lang.Boolean.FALSE;
import static java.lang.Boolean.TRUE;
+import java.time.Duration;
import java.time.Instant;
import java.util.ArrayList;
import java.util.Collection;
@@ -101,6 +102,7 @@
import net.runelite.client.ui.overlay.OverlayManager;
import net.runelite.client.util.ColorUtil;
import net.runelite.client.util.QuantityFormatter;
+import net.runelite.client.util.RSTimeUnit;
import net.runelite.client.util.Text;
@PluginDescriptor(
@@ -447,6 +449,8 @@ private GroundItem buildGroundItem(final Tile tile, final TileItem item)
.lootType(dropped ? LootType.DROPPED : (table ? LootType.TABLE : LootType.UNKNOWN))
.spawnTime(Instant.now())
.stackable(itemComposition.isStackable())
+ .despawnTime(Duration.of(item.getDespawnTime(), RSTimeUnit.GAME_TICKS))
+ .visibleTime(Duration.of(item.getVisibleTime(), RSTimeUnit.GAME_TICKS))
.build();
// Update item price in case it is coins
diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/hunter/HunterConfig.java b/runelite-client/src/main/java/net/runelite/client/plugins/hunter/HunterConfig.java
index 66bf54660c..019dd6707c 100644
--- a/runelite-client/src/main/java/net/runelite/client/plugins/hunter/HunterConfig.java
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/hunter/HunterConfig.java
@@ -29,6 +29,7 @@
import net.runelite.client.config.Config;
import net.runelite.client.config.ConfigGroup;
import net.runelite.client.config.ConfigItem;
+import net.runelite.client.config.Notification;
@ConfigGroup("hunterplugin")
public interface HunterConfig extends Config
@@ -87,8 +88,8 @@ default Color getTransTrapColor()
name = "Maniacal monkey notification",
description = "Send notification when maniacal monkey is caught or you fail to catch."
)
- default boolean maniacalMonkeyNotify()
+ default Notification maniacalMonkeyNotify()
{
- return false;
+ return Notification.OFF;
}
}
diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/hunter/HunterPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/hunter/HunterPlugin.java
index 0322819ca3..a44a9eaf4c 100644
--- a/runelite-client/src/main/java/net/runelite/client/plugins/hunter/HunterPlugin.java
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/hunter/HunterPlugin.java
@@ -200,9 +200,9 @@ public void onGameObjectSpawned(GameObjectSpawned event)
myTrap.setState(HunterTrap.State.FULL);
myTrap.resetTimer();
- if (config.maniacalMonkeyNotify() && myTrap.getObjectId() == ObjectID.MONKEY_TRAP)
+ if (myTrap.getObjectId() == ObjectID.MONKEY_TRAP)
{
- notifier.notify("You've caught part of a monkey's tail.");
+ notifier.notify(config.maniacalMonkeyNotify(), "You've caught part of a monkey's tail.");
}
}
@@ -375,10 +375,10 @@ else if (containsBoulder) // For traps like deadfalls. This is different because
log.debug("Special trap removed from personal trap collection, {} left", traps.size());
// Case we have notifications enabled and the action was not manual, throw notification
- if (config.maniacalMonkeyNotify() && trap.getObjectId() == ObjectID.MONKEY_TRAP &&
+ if (trap.getObjectId() == ObjectID.MONKEY_TRAP &&
!trap.getState().equals(HunterTrap.State.FULL) && !trap.getState().equals(HunterTrap.State.OPEN))
{
- notifier.notify("The monkey escaped.");
+ notifier.notify(config.maniacalMonkeyNotify(), "The monkey escaped.");
}
}
}
diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/idlenotifier/IdleNotifierConfig.java b/runelite-client/src/main/java/net/runelite/client/plugins/idlenotifier/IdleNotifierConfig.java
index 99f0a5b55f..4b2a893ffe 100644
--- a/runelite-client/src/main/java/net/runelite/client/plugins/idlenotifier/IdleNotifierConfig.java
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/idlenotifier/IdleNotifierConfig.java
@@ -27,6 +27,7 @@
import net.runelite.client.config.Config;
import net.runelite.client.config.ConfigGroup;
import net.runelite.client.config.ConfigItem;
+import net.runelite.client.config.Notification;
import net.runelite.client.config.Range;
import net.runelite.client.config.Units;
@@ -39,9 +40,9 @@ public interface IdleNotifierConfig extends Config
description = "Configures if idle animation notifications are enabled",
position = 1
)
- default boolean animationIdle()
+ default Notification animationIdle()
{
- return true;
+ return Notification.ON;
}
@ConfigItem(
@@ -50,9 +51,9 @@ default boolean animationIdle()
description = "Configures if idle interaction notifications are enabled e.g. combat, fishing",
position = 2
)
- default boolean interactionIdle()
+ default Notification interactionIdle()
{
- return true;
+ return Notification.ON;
}
@ConfigItem(
@@ -61,9 +62,9 @@ default boolean interactionIdle()
description = "Configures if idle movement notifications are enabled e.g. running, walking",
position = 3
)
- default boolean movementIdle()
+ default Notification movementIdle()
{
- return false;
+ return Notification.OFF;
}
@ConfigItem(
@@ -72,9 +73,9 @@ default boolean movementIdle()
description = "Configures if the idle logout notifications are enabled",
position = 4
)
- default boolean logoutIdle()
+ default Notification logoutIdle()
{
- return true;
+ return Notification.ON;
}
@ConfigItem(
diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/idlenotifier/IdleNotifierPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/idlenotifier/IdleNotifierPlugin.java
index 1626357731..5e711f4ea1 100644
--- a/runelite-client/src/main/java/net/runelite/client/plugins/idlenotifier/IdleNotifierPlugin.java
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/idlenotifier/IdleNotifierPlugin.java
@@ -161,6 +161,34 @@ public void onAnimationChanged(AnimationChanged event)
case WOODCUTTING_2H_CRYSTAL:
case WOODCUTTING_2H_CRYSTAL_INACTIVE:
case WOODCUTTING_2H_3A:
+ /* Woodcutting: Ents & Canoes */
+ case WOODCUTTING_ENT_BRONZE:
+ case WOODCUTTING_ENT_IRON:
+ case WOODCUTTING_ENT_STEEL:
+ case WOODCUTTING_ENT_BLACK:
+ case WOODCUTTING_ENT_MITHRIL:
+ case WOODCUTTING_ENT_ADAMANT:
+ case WOODCUTTING_ENT_RUNE:
+ case WOODCUTTING_ENT_GILDED:
+ case WOODCUTTING_ENT_DRAGON:
+ case WOODCUTTING_ENT_DRAGON_OR:
+ case WOODCUTTING_ENT_INFERNAL:
+ case WOODCUTTING_ENT_INFERNAL_OR:
+ case WOODCUTTING_ENT_3A:
+ case WOODCUTTING_ENT_CRYSTAL:
+ case WOODCUTTING_ENT_CRYSTAL_INACTIVE:
+ case WOODCUTTING_ENT_TRAILBLAZER:
+ case WOODCUTTING_ENT_2H_BRONZE:
+ case WOODCUTTING_ENT_2H_IRON:
+ case WOODCUTTING_ENT_2H_STEEL:
+ case WOODCUTTING_ENT_2H_BLACK:
+ case WOODCUTTING_ENT_2H_MITHRIL:
+ case WOODCUTTING_ENT_2H_ADAMANT:
+ case WOODCUTTING_ENT_2H_RUNE:
+ case WOODCUTTING_ENT_2H_DRAGON:
+ case WOODCUTTING_ENT_2H_CRYSTAL:
+ case WOODCUTTING_ENT_2H_CRYSTAL_INACTIVE:
+ case WOODCUTTING_ENT_2H_3A:
case BLISTERWOOD_JUMP_SCARE:
/* Firemaking */
case FIREMAKING_FORESTERS_CAMPFIRE_ARCTIC_PINE:
@@ -484,9 +512,9 @@ public void onGameTick(GameTick event)
return;
}
- if (config.logoutIdle() && checkIdleLogout())
+ if (checkIdleLogout())
{
- notifier.notify("You are about to log out from idling too long!");
+ notifier.notify(config.logoutIdle(), "You are about to log out from idling too long!");
}
if (check6hrLogout())
@@ -494,25 +522,25 @@ public void onGameTick(GameTick event)
notifier.notify("You are about to log out from being online for 6 hours!");
}
- if (config.animationIdle() && checkAnimationIdle(waitDuration, local))
+ if (checkAnimationIdle(waitDuration, local))
{
- notifier.notify("You are now idle!");
+ notifier.notify(config.animationIdle(), "You are now idle!");
}
- if (config.movementIdle() && checkMovementIdle(waitDuration, local))
+ if (checkMovementIdle(waitDuration, local))
{
- notifier.notify("You have stopped moving!");
+ notifier.notify(config.movementIdle(), "You have stopped moving!");
}
- if (config.interactionIdle() && checkInteractionIdle(waitDuration, local))
+ if (checkInteractionIdle(waitDuration, local))
{
if (lastInteractWasCombat)
{
- notifier.notify("You are now out of combat!");
+ notifier.notify(config.interactionIdle(), "You are now out of combat!");
}
else
{
- notifier.notify("You are now idle!");
+ notifier.notify(config.interactionIdle(), "You are now idle!");
}
}
diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/itemcharges/ItemChargeConfig.java b/runelite-client/src/main/java/net/runelite/client/plugins/itemcharges/ItemChargeConfig.java
index 876606ec71..6472c641c7 100644
--- a/runelite-client/src/main/java/net/runelite/client/plugins/itemcharges/ItemChargeConfig.java
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/itemcharges/ItemChargeConfig.java
@@ -31,6 +31,7 @@
import net.runelite.client.config.ConfigGroup;
import net.runelite.client.config.ConfigItem;
import net.runelite.client.config.ConfigSection;
+import net.runelite.client.config.Notification;
@ConfigGroup(ItemChargeConfig.GROUP)
public interface ItemChargeConfig extends Config
@@ -138,9 +139,9 @@ default boolean showDodgyCount()
position = 7,
section = notificationSection
)
- default boolean dodgyNotification()
+ default Notification dodgyNotification()
{
- return true;
+ return Notification.ON;
}
@ConfigItem(
@@ -270,9 +271,9 @@ default boolean showAmuletOfBountyCharges()
position = 18,
section = notificationSection
)
- default boolean recoilNotification()
+ default Notification recoilNotification()
{
- return false;
+ return Notification.OFF;
}
@ConfigItem(
@@ -294,9 +295,9 @@ default boolean showBindingNecklaceCharges()
position = 20,
section = notificationSection
)
- default boolean bindingNotification()
+ default Notification bindingNotification()
{
- return true;
+ return Notification.ON;
}
@ConfigItem(
@@ -330,9 +331,9 @@ default boolean showRingOfForgingCount()
position = 23,
section = notificationSection
)
- default boolean ringOfForgingNotification()
+ default Notification ringOfForgingNotification()
{
- return true;
+ return Notification.ON;
}
@ConfigItem(
@@ -377,9 +378,9 @@ default boolean showBraceletOfSlaughterCharges()
position = 27,
section = notificationSection
)
- default boolean slaughterNotification()
+ default Notification slaughterNotification()
{
- return true;
+ return Notification.ON;
}
@ConfigItem(
@@ -401,9 +402,9 @@ default boolean showExpeditiousBraceletCharges()
position = 29,
section = notificationSection
)
- default boolean expeditiousNotification()
+ default Notification expeditiousNotification()
{
- return true;
+ return Notification.ON;
}
@ConfigItem(
@@ -449,9 +450,9 @@ default boolean showBraceletOfClayCharges()
position = 32,
section = notificationSection
)
- default boolean braceletOfClayNotification()
+ default Notification braceletOfClayNotification()
{
- return true;
+ return Notification.ON;
}
@ConfigItem(
@@ -461,8 +462,8 @@ default boolean braceletOfClayNotification()
position = 33,
section = notificationSection
)
- default boolean amuletOfChemistryNotification()
+ default Notification amuletOfChemistryNotification()
{
- return true;
+ return Notification.ON;
}
}
diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/itemcharges/ItemChargePlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/itemcharges/ItemChargePlugin.java
index dbf5059903..733ec51629 100644
--- a/runelite-client/src/main/java/net/runelite/client/plugins/itemcharges/ItemChargePlugin.java
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/itemcharges/ItemChargePlugin.java
@@ -271,16 +271,13 @@ public void onChatMessage(ChatMessage event)
Matcher bloodEssenceExtractMatcher = BLOOD_ESSENCE_EXTRACT_PATTERN.matcher(message);
Matcher braceletOfClayCheckMatcher = BRACELET_OF_CLAY_CHECK_PATTERN.matcher(message);
- if (config.recoilNotification() && message.contains(RING_OF_RECOIL_BREAK_MESSAGE))
+ if (message.contains(RING_OF_RECOIL_BREAK_MESSAGE))
{
- notifier.notify("Your Ring of Recoil has shattered");
+ notifier.notify(config.recoilNotification(), "Your Ring of Recoil has shattered");
}
else if (dodgyBreakMatcher.find())
{
- if (config.dodgyNotification())
- {
- notifier.notify("Your dodgy necklace has crumbled to dust.");
- }
+ notifier.notify(config.dodgyNotification(), "Your dodgy necklace has crumbled to dust.");
updateDodgyNecklaceCharges(MAX_DODGY_CHARGES);
}
@@ -310,10 +307,7 @@ else if (amuletOfChemistryUsedMatcher.find())
}
else if (amuletOfChemistryBreakMatcher.find())
{
- if (config.amuletOfChemistryNotification())
- {
- notifier.notify("Your Amulet of Chemistry has crumbled to dust.");
- }
+ notifier.notify(config.amuletOfChemistryNotification(), "Your Amulet of Chemistry has crumbled to dust.");
updateAmuletOfChemistryCharges(MAX_AMULET_OF_CHEMISTRY_CHARGES);
}
@@ -331,10 +325,7 @@ else if (message.equals(AMULET_OF_BOUNTY_BREAK_TEXT))
}
else if (message.contains(BINDING_BREAK_TEXT))
{
- if (config.bindingNotification())
- {
- notifier.notify(BINDING_BREAK_TEXT);
- }
+ notifier.notify(config.bindingNotification(), BINDING_BREAK_TEXT);
// This chat message triggers before the used message so add 1 to the max charges to ensure proper sync
updateBindingNecklaceCharges(MAX_BINDING_CHARGES + 1);
@@ -389,10 +380,7 @@ else if (message.equals(RING_OF_FORGING_USED_TEXT) || message.equals(RING_OF_FOR
}
else if (message.equals(RING_OF_FORGING_BREAK_TEXT))
{
- if (config.ringOfForgingNotification())
- {
- notifier.notify("Your ring of forging has melted.");
- }
+ notifier.notify(config.ringOfForgingNotification(), "Your ring of forging has melted.");
// This chat message triggers before the used message so add 1 to the max charges to ensure proper sync
updateRingOfForgingCharges(MAX_RING_OF_FORGING_CHARGES + 1);
@@ -432,10 +420,7 @@ else if (slaughterActivateMatcher.find())
if (found == null)
{
updateBraceletOfSlaughterCharges(MAX_SLAYER_BRACELET_CHARGES);
- if (config.slaughterNotification())
- {
- notifier.notify(BRACELET_OF_SLAUGHTER_BREAK_TEXT);
- }
+ notifier.notify(config.slaughterNotification(), BRACELET_OF_SLAUGHTER_BREAK_TEXT);
}
else
{
@@ -452,10 +437,7 @@ else if (expeditiousActivateMatcher.find())
if (found == null)
{
updateExpeditiousBraceletCharges(MAX_SLAYER_BRACELET_CHARGES);
- if (config.expeditiousNotification())
- {
- notifier.notify(EXPEDITIOUS_BRACELET_BREAK_TEXT);
- }
+ notifier.notify(config.expeditiousNotification(), EXPEDITIOUS_BRACELET_BREAK_TEXT);
}
else
{
@@ -505,10 +487,7 @@ else if (message.equals(BRACELET_OF_CLAY_USE_TEXT) || message.equals(BRACELET_OF
}
else if (message.equals(BRACELET_OF_CLAY_BREAK_TEXT))
{
- if (config.braceletOfClayNotification())
- {
- notifier.notify("Your bracelet of clay has crumbled to dust");
- }
+ notifier.notify(config.braceletOfClayNotification(), "Your bracelet of clay has crumbled to dust");
updateBraceletOfClayCharges(MAX_BRACELET_OF_CLAY_CHARGES);
}
}
diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/loginscreen/LoginScreenOverride.java b/runelite-client/src/main/java/net/runelite/client/plugins/loginscreen/LoginScreenOverride.java
index 7f1f250232..69f378ccb7 100644
--- a/runelite-client/src/main/java/net/runelite/client/plugins/loginscreen/LoginScreenOverride.java
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/loginscreen/LoginScreenOverride.java
@@ -46,6 +46,7 @@ public enum LoginScreenOverride
A_KINGDOM_DIVIDED("akd.jpg"),
NEX("nex.jpg"),
TOMBS_OF_AMASCUT("toa.jpg"),
+ VARLAMORE("varlamore.jpg"),
CUSTOM,
RANDOM;
diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/menuentryswapper/MenuEntrySwapperConfig.java b/runelite-client/src/main/java/net/runelite/client/plugins/menuentryswapper/MenuEntrySwapperConfig.java
index 7069265d76..a41428b61e 100644
--- a/runelite-client/src/main/java/net/runelite/client/plugins/menuentryswapper/MenuEntrySwapperConfig.java
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/menuentryswapper/MenuEntrySwapperConfig.java
@@ -424,6 +424,17 @@ default boolean swapTeleportItem()
return false;
}
+ @ConfigItem(
+ keyName = "teleportSubmenus",
+ name = "Teleport submenus",
+ description = "Use submenus for max, construction, and diary cape teleports",
+ section = itemSection
+ )
+ default boolean teleportSubmenus()
+ {
+ return false;
+ }
+
@ConfigItem(
keyName = "swapTeleToPoh",
name = "Tele to POH",
diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/menuentryswapper/MenuEntrySwapperPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/menuentryswapper/MenuEntrySwapperPlugin.java
index 6e45d2b405..0cb4bc19c8 100644
--- a/runelite-client/src/main/java/net/runelite/client/plugins/menuentryswapper/MenuEntrySwapperPlugin.java
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/menuentryswapper/MenuEntrySwapperPlugin.java
@@ -27,10 +27,12 @@
package net.runelite.client.plugins.menuentryswapper;
import com.google.common.annotations.VisibleForTesting;
+import com.google.common.base.Preconditions;
import static com.google.common.base.Predicates.alwaysTrue;
import static com.google.common.base.Predicates.equalTo;
import com.google.common.base.Strings;
import com.google.common.collect.ArrayListMultimap;
+import com.google.common.collect.HashMultimap;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.LinkedHashMultimap;
@@ -45,11 +47,13 @@
import java.util.function.Consumer;
import java.util.function.Predicate;
import java.util.function.Supplier;
+import java.util.stream.Collectors;
import javax.inject.Inject;
import lombok.extern.slf4j.Slf4j;
import net.runelite.api.ChatMessageType;
import net.runelite.api.Client;
import net.runelite.api.ItemComposition;
+import net.runelite.api.ItemID;
import net.runelite.api.KeyCode;
import net.runelite.api.MenuAction;
import net.runelite.api.MenuEntry;
@@ -57,10 +61,13 @@
import net.runelite.api.NPCComposition;
import net.runelite.api.ObjectComposition;
import net.runelite.api.ParamID;
+import net.runelite.api.annotations.Component;
import net.runelite.api.events.ClientTick;
+import net.runelite.api.events.MenuEntryAdded;
import net.runelite.api.events.MenuOpened;
import net.runelite.api.events.PostItemComposition;
import net.runelite.api.events.PostMenuSort;
+import net.runelite.api.widgets.ComponentID;
import net.runelite.api.widgets.InterfaceID;
import net.runelite.api.widgets.Widget;
import net.runelite.api.widgets.WidgetConfig;
@@ -158,6 +165,7 @@ public class MenuEntrySwapperPlugin extends Plugin
private final Multimap swaps = LinkedHashMultimap.create();
private final ArrayListMultimap optionIndexes = ArrayListMultimap.create();
+ private final Multimap teleportSwaps = HashMultimap.create();
@Provides
MenuEntrySwapperConfig provideConfig(ConfigManager configManager)
@@ -169,6 +177,7 @@ MenuEntrySwapperConfig provideConfig(ConfigManager configManager)
public void startUp()
{
setupSwaps();
+ setupTeleportSwaps();
removeOldSwaps();
}
@@ -176,6 +185,7 @@ public void startUp()
public void shutDown()
{
swaps.clear();
+ teleportSwaps.clear();
}
@VisibleForTesting
@@ -266,6 +276,7 @@ void setupSwaps()
swap("teleport menu", "pvp arena", config::swapJewelleryBox);
swap("teleport menu", "castle wars", config::swapJewelleryBox);
swap("teleport menu", "ferox enclave", config::swapJewelleryBox);
+ swap("teleport menu", "fortis colosseum", config::swapJewelleryBox);
swap("teleport menu", "burthorpe", config::swapJewelleryBox);
swap("teleport menu", "barbarian outpost", config::swapJewelleryBox);
swap("teleport menu", "corporeal beast", config::swapJewelleryBox);
@@ -524,13 +535,6 @@ private void configureObjectClick(MenuOpened event)
continue;
}
- if ("Build".equals(actions[actionIdx])
- || "Remove".equals(actions[actionIdx]))
- {
- // https://secure.runescape.com/m=news/third-party-client-guidelines?oldschool=1
- continue;
- }
-
final MenuAction menuAction = OBJECT_MENU_TYPES.get(actionIdx);
if (menuAction != currentAction)
{
@@ -894,6 +898,31 @@ private void configureWornItems(MenuOpened event)
}
}
+ var subSwaps = teleportSwaps.get(itemComposition.getId())
+ .stream()
+ .filter(ts -> ts.worn)
+ .collect(Collectors.toList());
+ for (TeleportSwap top : subSwaps)
+ {
+ for (TeleportSub sub : top.subs)
+ {
+ if (leftClickOp == null || leftClickOp != sub.option.hashCode())
+ {
+ leftClickMenus.add(client.createMenuEntry(idx)
+ .setOption(sub.option)
+ .setType(MenuAction.RUNELITE)
+ .onClick(wornItemConsumer(itemComposition, sub.option, sub.option.hashCode(), false)));
+ }
+ if (shiftClickOp == null || shiftClickOp != sub.option.hashCode())
+ {
+ shiftClickMenus.add(client.createMenuEntry(idx)
+ .setOption(sub.option)
+ .setType(MenuAction.RUNELITE)
+ .onClick(wornItemConsumer(itemComposition, sub.option, sub.option.hashCode(), true)));
+ }
+ }
+ }
+
if (leftClickOp != null)
{
leftClickMenus.add(client.createMenuEntry(idx)
@@ -1052,6 +1081,31 @@ private void configureItems(MenuOpened event)
}
}
+ var subSwaps = teleportSwaps.get(itemComposition.getId())
+ .stream()
+ .filter(ts -> ts.held)
+ .collect(Collectors.toList());
+ for (TeleportSwap top : subSwaps)
+ {
+ for (TeleportSub sub : top.subs)
+ {
+ if (leftClickOp == null || leftClickOp != sub.option.hashCode())
+ {
+ leftClickMenus.add(client.createMenuEntry(idx)
+ .setOption(sub.option)
+ .setType(MenuAction.RUNELITE)
+ .onClick(heldItemConsumer(itemComposition, sub.option, sub.option.hashCode(), false)));
+ }
+ if (shiftClickOp == null || shiftClickOp != sub.option.hashCode())
+ {
+ shiftClickMenus.add(client.createMenuEntry(idx)
+ .setOption(sub.option)
+ .setType(MenuAction.RUNELITE)
+ .onClick(heldItemConsumer(itemComposition, sub.option, sub.option.hashCode(), true)));
+ }
+ }
+ }
+
if (leftClickOp != null && config.leftClickCustomization())
{
leftClickMenus.add(client.createMenuEntry(idx)
@@ -1419,20 +1473,25 @@ private void swapMenuEntry(MenuEntry[] menuEntries, int index, MenuEntry menuEnt
final String option = Text.removeTags(menuEntry.getOption()).toLowerCase();
final String target = Text.removeTags(menuEntry.getTarget()).toLowerCase();
- final boolean itemOp = menuEntry.isItemOp();
+ final Widget w = menuEntry.getParent() != null ? menuEntry.getParent().getWidget() : menuEntry.getWidget();
// Custom shift-click item swap
- if (shiftModifier() && itemOp)
+ if (shiftModifier() && w != null && WidgetUtil.componentToInterface(w.getId()) == InterfaceID.INVENTORY)
{
- // Special case use shift click due to items not actually containing a "Use" option, making
- // the client unable to perform the swap itself.
if (config.shiftClickCustomization() && !option.equals("use"))
{
- Integer customOption = getItemSwapConfig(true, menuEntry.getItemId());
+ Integer customOption = getItemSwapConfig(true, w.getItemId());
+ // Special case use shift click due to items not actually containing a "Use" option, making
+ // the client unable to perform the swap itself.
if (customOption != null && customOption == -1)
{
swap(menuEntries, "use", target, index, true);
}
+ else if (customOption != null && menuEntry.getParent() != null && menuEntry.getOption().hashCode() == customOption)
+ {
+ swap(optionIndexes, menuEntries, index, menuEntries.length - 1);
+ menuEntry.setParent(null);
+ }
}
// don't perform swaps on items when shift is held; instead prefer the client menu swap, which
@@ -1441,29 +1500,27 @@ private void swapMenuEntry(MenuEntry[] menuEntries, int index, MenuEntry menuEnt
}
// Custom left-click item swap
- if (itemOp && config.leftClickCustomization())
+ if (w != null && WidgetUtil.componentToInterface(w.getId()) == InterfaceID.INVENTORY
+ && config.leftClickCustomization())
{
- Integer swapIndex = getItemSwapConfig(false, menuEntry.getItemId());
+ Integer swapIndex = getItemSwapConfig(false, w.getItemId());
if (swapIndex != null)
{
- final int swapAction = swapIndex >= 0
- ? 1 + swapIndex
- : -1;
-
- if (swapAction == -1)
+ if (swapIndex == -1)
{
swap(menuEntries, "use", target, index, true);
}
- else if (swapAction == menuEntry.getItemOp())
+ else if (swapIndex + 1 == menuEntry.getItemOp()
+ || (menuEntry.getParent() != null && menuEntry.getOption().hashCode() == swapIndex))
{
swap(optionIndexes, menuEntries, index, menuEntries.length - 1);
+ menuEntry.setParent(null);
}
return;
}
}
// Worn items swap
- final Widget w = menuEntry.getWidget();
if (w != null && WidgetUtil.componentToInterface(w.getId()) == InterfaceID.EQUIPMENT)
{
Widget child = w.getChild(1);
@@ -1472,9 +1529,11 @@ else if (swapAction == menuEntry.getItemOp())
final Integer wornItemSwapConfig = getWornItemSwapConfig(shiftModifier(), child.getItemId());
if (wornItemSwapConfig != null)
{
- if (wornItemSwapConfig == menuEntry.getIdentifier())
+ if (wornItemSwapConfig == menuEntry.getIdentifier()
+ || (menuEntry.getParent() != null && menuEntry.getOption().hashCode() == wornItemSwapConfig))
{
swap(optionIndexes, menuEntries, index, menuEntries.length - 1);
+ menuEntry.setParent(null); // Move from a submenu to a top level menu
}
return;
}
@@ -1534,7 +1593,8 @@ else if (swapAction == menuEntry.getItemOp())
if ((menuAction == MenuAction.CC_OP || menuAction == MenuAction.CC_OP_LOW_PRIORITY || menuAction == MenuAction.WIDGET_TARGET)
&& w != null && (w.getIndex() == -1 || w.getItemId() != -1)
&& w.getActions() != null
- && !itemOp && WidgetUtil.componentToInterface(w.getId()) != InterfaceID.EQUIPMENT)
+ && WidgetUtil.componentToInterface(w.getId()) != InterfaceID.INVENTORY
+ && WidgetUtil.componentToInterface(w.getId()) != InterfaceID.EQUIPMENT)
{
// fast check to avoid hitting config on components with single ops
if ((index > 0 && menuEntries[index - 1].getWidget() == w) ||
@@ -1711,7 +1771,7 @@ public void onPostItemComposition(PostItemComposition event)
ItemComposition itemComposition = event.getItemComposition();
Integer option = getItemSwapConfig(true, itemComposition.getId());
- if (option != null && option < itemComposition.getInventoryActions().length)
+ if (option != null && option >= 0 && option < itemComposition.getInventoryActions().length)
{
itemComposition.setShiftClickActionIndex(option);
}
@@ -1944,4 +2004,245 @@ private void unsetUiSwapConfig(boolean shift, int componentId, int itemId)
configManager.unsetConfiguration(MenuEntrySwapperConfig.GROUP,
(shift ? UI_SHIFT_KEY_PREFIX : UI_KEY_PREFIX) + componentId + (itemId != -1 ? "_" + itemId : ""));
}
+
+ private void setupTeleportSwaps()
+ {
+ // region Max cape opworn
+ teleportSwap("Fishing Teleports", ItemID.MAX_CAPE_13342)
+ .worn()
+ .addSub("Fishing Guild", () -> pauseresume(ComponentID.DIALOG_OPTION_OPTIONS, 1))
+ .addSub("Otto's Grotto", () -> pauseresume(ComponentID.DIALOG_OPTION_OPTIONS, 2));
+ teleportSwap("POH Portals", ItemID.MAX_CAPE_13342)
+ .worn()
+ .addSub("Home", () -> pauseresume(ComponentID.ADVENTURE_LOG_OPTIONS, 0))
+ .addSub("Rimmington", () -> pauseresume(ComponentID.ADVENTURE_LOG_OPTIONS, 1))
+ .addSub("Taverley", () -> pauseresume(ComponentID.ADVENTURE_LOG_OPTIONS, 2))
+ .addSub("Pollnivneach", () -> pauseresume(ComponentID.ADVENTURE_LOG_OPTIONS, 3))
+ .addSub("Hosidius", () -> pauseresume(ComponentID.ADVENTURE_LOG_OPTIONS, 4))
+ .addSub("Rellekka", () -> pauseresume(ComponentID.ADVENTURE_LOG_OPTIONS, 5))
+ .addSub("Brimhaven", () -> pauseresume(ComponentID.ADVENTURE_LOG_OPTIONS, 6))
+ .addSub("Yanille", () -> pauseresume(ComponentID.ADVENTURE_LOG_OPTIONS, 7))
+ .addSub("Prifddinas", () -> pauseresume(ComponentID.ADVENTURE_LOG_OPTIONS, 8));
+ teleportSwap("Other Teleports", ItemID.MAX_CAPE_13342)
+ .worn()
+ .addSub("Feldip hills", () ->
+ {
+ pauseresume(ComponentID.DIALOG_OPTION_OPTIONS, 1); // Chinchompa Teleports
+ pauseresume(ComponentID.DIALOG_OPTION_OPTIONS, 1); // Carnivorous chinchompas (Feldip Hills)
+ })
+ .addSub("Black chinchompas", () ->
+ {
+ pauseresume(ComponentID.DIALOG_OPTION_OPTIONS, 1); // Chinchompa Teleports
+ pauseresume(ComponentID.DIALOG_OPTION_OPTIONS, 2); // Black chinchompas (Wilderness)
+ })
+ .addSub("Hunter Guild", () ->
+ {
+ pauseresume(ComponentID.DIALOG_OPTION_OPTIONS, 1); // Chinchompa Teleports
+ pauseresume(ComponentID.DIALOG_OPTION_OPTIONS, 3); // Hunter Guild
+ })
+ .addSub("Farming Guild", () -> pauseresume(ComponentID.DIALOG_OPTION_OPTIONS, 2));
+ // endregion
+
+ // region Max cape opheld
+ teleportSwap("Teleports", ItemID.MAX_CAPE)
+ .held()
+ .addSub("Warriors' Guild", () -> pauseresume(ComponentID.ADVENTURE_LOG_OPTIONS, 0))
+ .addSub("Fishing Guild", () -> pauseresume(ComponentID.ADVENTURE_LOG_OPTIONS, 1))
+ .addSub("Crafting Guild", () -> pauseresume(ComponentID.ADVENTURE_LOG_OPTIONS, 2))
+ .addSub("Farming Guild", () -> pauseresume(ComponentID.ADVENTURE_LOG_OPTIONS, 3))
+ .addSub("Otto's Grotto", () -> pauseresume(ComponentID.ADVENTURE_LOG_OPTIONS, 4))
+ .addSub("Feldip hills", () ->
+ {
+ pauseresume(ComponentID.ADVENTURE_LOG_OPTIONS, 5); // Chinchompas
+ pauseresume(ComponentID.DIALOG_OPTION_OPTIONS, 1); // Carnivorous chinchompas (Feldip Hills)
+ })
+ .addSub("Black chinchompas", () ->
+ {
+ pauseresume(ComponentID.ADVENTURE_LOG_OPTIONS, 5); // Chinchompas
+ pauseresume(ComponentID.DIALOG_OPTION_OPTIONS, 2); // Black chinchompas (Wilderness)
+ })
+ .addSub("Hunter Guild", () ->
+ {
+ pauseresume(ComponentID.ADVENTURE_LOG_OPTIONS, 5); // Chinchompas
+ pauseresume(ComponentID.DIALOG_OPTION_OPTIONS, 3); // Hunter Guild
+ })
+ .addSub("Home", () ->
+ {
+ pauseresume(ComponentID.ADVENTURE_LOG_OPTIONS, 6); // POH Portals
+ pauseresume(ComponentID.ADVENTURE_LOG_OPTIONS, 0);
+ })
+ .addSub("Rimmington", () ->
+ {
+ pauseresume(ComponentID.ADVENTURE_LOG_OPTIONS, 6); // POH Portals
+ pauseresume(ComponentID.ADVENTURE_LOG_OPTIONS, 1);
+ })
+ .addSub("Taverley", () ->
+ {
+ pauseresume(ComponentID.ADVENTURE_LOG_OPTIONS, 6); // POH Portals
+ pauseresume(ComponentID.ADVENTURE_LOG_OPTIONS, 2);
+ })
+ .addSub("Pollnivneach", () ->
+ {
+ pauseresume(ComponentID.ADVENTURE_LOG_OPTIONS, 6); // POH Portals
+ pauseresume(ComponentID.ADVENTURE_LOG_OPTIONS, 3);
+ })
+ .addSub("Hosidius", () ->
+ {
+ pauseresume(ComponentID.ADVENTURE_LOG_OPTIONS, 6); // POH Portals
+ pauseresume(ComponentID.ADVENTURE_LOG_OPTIONS, 4);
+ })
+ .addSub("Rellekka", () ->
+ {
+ pauseresume(ComponentID.ADVENTURE_LOG_OPTIONS, 6); // POH Portals
+ pauseresume(ComponentID.ADVENTURE_LOG_OPTIONS, 5);
+ })
+ .addSub("Yanille", () ->
+ {
+ pauseresume(ComponentID.ADVENTURE_LOG_OPTIONS, 6); // POH Portals
+ pauseresume(ComponentID.ADVENTURE_LOG_OPTIONS, 6);
+ })
+ .addSub("Prifddinas", () ->
+ {
+ pauseresume(ComponentID.ADVENTURE_LOG_OPTIONS, 6); // POH Portals
+ pauseresume(ComponentID.ADVENTURE_LOG_OPTIONS, 7);
+ });
+ // endregion
+
+ // region Con cape
+ teleportSwap("Teleport", ItemID.CONSTRUCT_CAPE, ItemID.CONSTRUCT_CAPET)
+ .worn()
+ .held()
+ .addSub("Home", () -> pauseresume(ComponentID.ADVENTURE_LOG_OPTIONS, 0))
+ .addSub("Rimmington", () -> pauseresume(ComponentID.ADVENTURE_LOG_OPTIONS, 1))
+ .addSub("Taverley", () -> pauseresume(ComponentID.ADVENTURE_LOG_OPTIONS, 2))
+ .addSub("Pollnivneach", () -> pauseresume(ComponentID.ADVENTURE_LOG_OPTIONS, 3))
+ .addSub("Hosidius", () -> pauseresume(ComponentID.ADVENTURE_LOG_OPTIONS, 4))
+ .addSub("Rellekka", () -> pauseresume(ComponentID.ADVENTURE_LOG_OPTIONS, 5))
+ .addSub("Brimhaven", () -> pauseresume(ComponentID.ADVENTURE_LOG_OPTIONS, 6))
+ .addSub("Yanille", () -> pauseresume(ComponentID.ADVENTURE_LOG_OPTIONS, 7))
+ .addSub("Prifddinas", () -> pauseresume(ComponentID.ADVENTURE_LOG_OPTIONS, 8));
+ // endregion
+
+ // region Achievement diary cape
+ teleportSwap("Teleport", ItemID.ACHIEVEMENT_DIARY_CAPE, ItemID.ACHIEVEMENT_DIARY_CAPE_T)
+ .worn()
+ .held()
+ .addSub("Two-pints", () -> pauseresume(ComponentID.ADVENTURE_LOG_OPTIONS, 0))
+ .addSub("Jarr", () -> pauseresume(ComponentID.ADVENTURE_LOG_OPTIONS, 1))
+ .addSub("Sir Rebral", () -> pauseresume(ComponentID.ADVENTURE_LOG_OPTIONS, 2))
+ .addSub("Thorodin", () -> pauseresume(ComponentID.ADVENTURE_LOG_OPTIONS, 3))
+ .addSub("Flax keeper", () -> pauseresume(ComponentID.ADVENTURE_LOG_OPTIONS, 4))
+ .addSub("Pirate Jackie the Fruit", () -> pauseresume(ComponentID.ADVENTURE_LOG_OPTIONS, 5))
+ .addSub("Kaleb Paramaya", () -> pauseresume(ComponentID.ADVENTURE_LOG_OPTIONS, 6))
+ .addSub("Jungle forester", () -> pauseresume(ComponentID.ADVENTURE_LOG_OPTIONS, 7))
+ .addSub("TzHaar-Mej", () -> pauseresume(ComponentID.ADVENTURE_LOG_OPTIONS, 8))
+ .addSub("Elise", () -> pauseresume(ComponentID.ADVENTURE_LOG_OPTIONS, 9))
+ .addSub("Hatius Cosaintus", () -> pauseresume(ComponentID.ADVENTURE_LOG_OPTIONS, 10))
+ .addSub("Le-sabrè", () -> pauseresume(ComponentID.ADVENTURE_LOG_OPTIONS, 11))
+ .addSub("Toby", () -> pauseresume(ComponentID.ADVENTURE_LOG_OPTIONS, 12))
+ .addSub("Lesser Fanatic", () -> pauseresume(ComponentID.ADVENTURE_LOG_OPTIONS, 13))
+ .addSub("Elder Gnome child", () -> pauseresume(ComponentID.ADVENTURE_LOG_OPTIONS, 14))
+ .addSub("Twiggy O'Korn", () -> pauseresume(ComponentID.ADVENTURE_LOG_OPTIONS, 15));
+ // endregion
+ }
+
+ private TeleportSwap teleportSwap(String option, int... items)
+ {
+ Preconditions.checkArgument(items.length > 0, "no items");
+ var ts = new TeleportSwap();
+ ts.option = option;
+ for (int item : items)
+ {
+ teleportSwaps.put(item, ts);
+ }
+ return ts;
+ }
+
+ @Subscribe
+ public void onMenuEntryAdded(MenuEntryAdded menuEntryAdded)
+ {
+ var me = menuEntryAdded.getMenuEntry();
+ if (me.getWidget() != null && me.getWidget().getId() == ComponentID.EQUIPMENT_CAPE)
+ {
+ var item = me.getWidget().getChild(1);
+ var swap = teleportSwaps.get(item.getItemId())
+ .stream()
+ .filter(ts -> ts.worn)
+ .filter(ts -> ts.option.equals(me.getOption()))
+ .findAny()
+ .orElse(null);
+ if (swap != null && config.teleportSubmenus())
+ {
+ me.setType(MenuAction.RUNELITE_SUBMENU_WIDGET);
+ me.onClick(e -> client.menuAction(e.getParam0(), e.getParam1(), MenuAction.CC_OP,
+ e.getIdentifier(), e.getItemId(), e.getOption(), e.getTarget()));
+
+ int off = 0;
+ final int p0 = me.getParam0();
+ final int p1 = me.getParam1();
+ final int id = me.getIdentifier();
+ final int itemId = me.getItemId();
+ final String option = me.getOption();
+ final String target = me.getTarget();
+ for (TeleportSub sub : swap.subs)
+ {
+ client.createMenuEntry(-1 - off++)
+ .setParam0(p0)
+ .setParam1(p1)
+ .setOption(sub.option)
+ .setTarget(target)
+ .setType(MenuAction.RUNELITE)
+ .setParent(me)
+ .onClick(e -> clientThread.invokeLater(() ->
+ {
+ client.menuAction(p0, p1, MenuAction.CC_OP, id, itemId, option, target);
+ sub.execute.run();
+ }));
+ }
+ }
+ }
+ else if (me.getWidget() != null && me.getWidget().getId() == ComponentID.INVENTORY_CONTAINER)
+ {
+ var swap = teleportSwaps.get(me.getItemId())
+ .stream()
+ .filter(ts -> ts.held)
+ .filter(ts -> ts.option.equals(me.getOption()))
+ .findAny()
+ .orElse(null);
+ if (swap != null && config.teleportSubmenus())
+ {
+ me.setType(MenuAction.RUNELITE_SUBMENU_WIDGET);
+ me.onClick(e -> client.menuAction(e.getParam0(), e.getParam1(), MenuAction.CC_OP,
+ e.getIdentifier(), e.getItemId(), e.getOption(), e.getTarget()));
+
+ int off = 0;
+ final int p0 = me.getParam0();
+ final int p1 = me.getParam1();
+ final int id = me.getIdentifier();
+ final int itemId = me.getItemId();
+ final String option = me.getOption();
+ final String target = me.getTarget();
+ for (TeleportSub sub : swap.subs)
+ {
+ client.createMenuEntry(-1 - off++)
+ .setParam0(p0)
+ .setParam1(p1)
+ .setOption(sub.option)
+ .setTarget(target)
+ .setType(MenuAction.RUNELITE)
+ .setParent(me)
+ .onClick(e -> clientThread.invokeLater(() ->
+ {
+ client.menuAction(p0, p1, MenuAction.CC_OP, id, itemId, option, target);
+ sub.execute.run();
+ }));
+ }
+ }
+ }
+ }
+
+ private void pauseresume(@Component int comp, int op)
+ {
+ client.menuAction(op, comp, MenuAction.WIDGET_CONTINUE, -1, -1, "", "");
+ }
}
diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/menuentryswapper/TeleportSwap.java b/runelite-client/src/main/java/net/runelite/client/plugins/menuentryswapper/TeleportSwap.java
new file mode 100644
index 0000000000..b88ad961eb
--- /dev/null
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/menuentryswapper/TeleportSwap.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2024, Adam
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package net.runelite.client.plugins.menuentryswapper;
+
+import java.util.ArrayList;
+import java.util.List;
+
+class TeleportSwap
+{
+ boolean worn;
+ boolean held;
+ String option;
+ List subs = new ArrayList<>();
+
+ TeleportSwap addSub(String option, Runnable r)
+ {
+ var sub = new TeleportSub();
+ sub.option = option;
+ sub.execute = r;
+ subs.add(sub);
+ return this;
+ }
+
+ TeleportSwap worn()
+ {
+ worn = true;
+ return this;
+ }
+
+ TeleportSwap held()
+ {
+ held = true;
+ return this;
+ }
+}
+
+class TeleportSub
+{
+ String option;
+ Runnable execute;
+}
diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/minimap/MinimapPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/minimap/MinimapPlugin.java
index d86f9eaac2..5a2d6d9527 100644
--- a/runelite-client/src/main/java/net/runelite/client/plugins/minimap/MinimapPlugin.java
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/minimap/MinimapPlugin.java
@@ -122,6 +122,7 @@ else if (event.getKey().equals("zoom"))
return;
}
+ restoreOriginalDots();
replaceMapDots();
}
diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/nightmarezone/NightmareZoneConfig.java b/runelite-client/src/main/java/net/runelite/client/plugins/nightmarezone/NightmareZoneConfig.java
index d808a21abf..84df55c157 100644
--- a/runelite-client/src/main/java/net/runelite/client/plugins/nightmarezone/NightmareZoneConfig.java
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/nightmarezone/NightmareZoneConfig.java
@@ -28,6 +28,7 @@
import net.runelite.client.config.Config;
import net.runelite.client.config.ConfigGroup;
import net.runelite.client.config.ConfigItem;
+import net.runelite.client.config.Notification;
import net.runelite.client.config.Range;
import net.runelite.client.config.Units;
@@ -51,9 +52,9 @@ default boolean moveOverlay()
description = "Toggles notifications when a power surge power-up appears",
position = 2
)
- default boolean powerSurgeNotification()
+ default Notification powerSurgeNotification()
{
- return false;
+ return Notification.OFF;
}
@ConfigItem(
@@ -62,9 +63,9 @@ default boolean powerSurgeNotification()
description = "Toggles notifications when a recurrent damage power-up appears",
position = 3
)
- default boolean recurrentDamageNotification()
+ default Notification recurrentDamageNotification()
{
- return false;
+ return Notification.OFF;
}
@ConfigItem(
@@ -73,9 +74,9 @@ default boolean recurrentDamageNotification()
description = "Toggles notifications when a zapper power-up appears",
position = 4
)
- default boolean zapperNotification()
+ default Notification zapperNotification()
{
- return false;
+ return Notification.OFF;
}
@ConfigItem(
@@ -84,9 +85,9 @@ default boolean zapperNotification()
description = "Toggles notifications when an ultimate force power-up appears",
position = 5
)
- default boolean ultimateForceNotification()
+ default Notification ultimateForceNotification()
{
- return false;
+ return Notification.OFF;
}
@ConfigItem(
@@ -95,9 +96,9 @@ default boolean ultimateForceNotification()
description = "Toggles notifications when your overload runs out",
position = 6
)
- default boolean overloadNotification()
+ default Notification overloadNotification()
{
- return true;
+ return Notification.ON;
}
@Range(
@@ -122,9 +123,9 @@ default int overloadEarlyWarningSeconds()
description = "Toggles notifications when your absorption points gets below your threshold",
position = 8
)
- default boolean absorptionNotification()
+ default Notification absorptionNotification()
{
- return true;
+ return Notification.ON;
}
@ConfigItem(
diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/nightmarezone/NightmareZonePlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/nightmarezone/NightmareZonePlugin.java
index 16aab455a5..499be796e3 100644
--- a/runelite-client/src/main/java/net/runelite/client/plugins/nightmarezone/NightmareZonePlugin.java
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/nightmarezone/NightmareZonePlugin.java
@@ -157,12 +157,9 @@ public void onGameTick(GameTick event)
return;
}
- if (config.absorptionNotification())
- {
- checkAbsorption();
- }
+ checkAbsorption();
- if (overloadNotificationSend && config.overloadNotification() && config.overloadEarlyWarningSeconds() > 0)
+ if (overloadNotificationSend && config.overloadEarlyWarningSeconds() > 0)
{
checkOverload();
}
@@ -189,40 +186,25 @@ public void onChatMessage(ChatMessage event)
// Prevents notification from being sent after overload expiry, if the user disables and re-enables warnings
overloadNotificationSend = false;
- if (config.overloadNotification())
- {
- notifier.notify("Your overload has worn off");
- }
+ notifier.notify(config.overloadNotification(), "Your overload has worn off");
}
else if (msg.contains("A power-up has spawned:"))
{
if (msg.contains("Power surge"))
{
- if (config.powerSurgeNotification())
- {
- notifier.notify(msg);
- }
+ notifier.notify(config.powerSurgeNotification(), msg);
}
else if (msg.contains("Recurrent damage"))
{
- if (config.recurrentDamageNotification())
- {
- notifier.notify(msg);
- }
+ notifier.notify(config.recurrentDamageNotification(), msg);
}
else if (msg.contains("Zapper"))
{
- if (config.zapperNotification())
- {
- notifier.notify(msg);
- }
+ notifier.notify(config.zapperNotification(), msg);
}
else if (msg.contains("Ultimate force"))
{
- if (config.ultimateForceNotification())
- {
- notifier.notify(msg);
- }
+ notifier.notify(config.ultimateForceNotification(), msg);
}
}
else if (msg.contains("You drink some of your overload potion."))
@@ -237,7 +219,7 @@ private void checkOverload()
if (Instant.now().isAfter(lastOverload.plus(OVERLOAD_DURATION).
minus(Duration.ofSeconds(config.overloadEarlyWarningSeconds()))))
{
- notifier.notify("Your overload potion is about to expire!");
+ notifier.notify(config.overloadNotification(), "Your overload potion is about to expire!");
overloadNotificationSend = false;
}
}
@@ -250,7 +232,7 @@ private void checkAbsorption()
{
if (absorptionPoints < config.absorptionThreshold())
{
- notifier.notify("Absorption points below: " + config.absorptionThreshold());
+ notifier.notify(config.absorptionNotification(), "Absorption points below: " + config.absorptionThreshold());
absorptionNotificationSend = true;
}
}
diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/npcunaggroarea/NpcAggroAreaConfig.java b/runelite-client/src/main/java/net/runelite/client/plugins/npcunaggroarea/NpcAggroAreaConfig.java
index e830c1b0bb..691998050c 100644
--- a/runelite-client/src/main/java/net/runelite/client/plugins/npcunaggroarea/NpcAggroAreaConfig.java
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/npcunaggroarea/NpcAggroAreaConfig.java
@@ -29,6 +29,7 @@
import net.runelite.client.config.Config;
import net.runelite.client.config.ConfigGroup;
import net.runelite.client.config.ConfigItem;
+import net.runelite.client.config.Notification;
@ConfigGroup("npcUnaggroArea")
public interface NpcAggroAreaConfig extends Config
@@ -113,9 +114,9 @@ default Color unaggroAreaColor()
description = "Send a notification when the unaggressive timer expires",
position = 7
)
- default boolean notifyExpire()
+ default Notification notifyExpire()
{
- return false;
+ return Notification.OFF;
}
@ConfigItem(
diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/npcunaggroarea/NpcAggroAreaPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/npcunaggroarea/NpcAggroAreaPlugin.java
index 49e52b0b13..9237d8087c 100644
--- a/runelite-client/src/main/java/net/runelite/client/plugins/npcunaggroarea/NpcAggroAreaPlugin.java
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/npcunaggroarea/NpcAggroAreaPlugin.java
@@ -340,10 +340,7 @@ public void onGameTick(GameTick event)
if (active && notifyOnce && Instant.now().isAfter(endTime))
{
- if (config.notifyExpire())
- {
- notifier.notify("NPC aggression has expired!");
- }
+ notifier.notify(config.notifyExpire(), "NPC aggression has expired!");
notifyOnce = false;
}
diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/randomevents/RandomEventConfig.java b/runelite-client/src/main/java/net/runelite/client/plugins/randomevents/RandomEventConfig.java
index 30c948071d..c45f8bd298 100644
--- a/runelite-client/src/main/java/net/runelite/client/plugins/randomevents/RandomEventConfig.java
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/randomevents/RandomEventConfig.java
@@ -29,6 +29,7 @@
import net.runelite.client.config.ConfigGroup;
import net.runelite.client.config.ConfigItem;
import net.runelite.client.config.ConfigSection;
+import net.runelite.client.config.Notification;
@ConfigGroup("randomevents")
public interface RandomEventConfig extends Config
@@ -58,9 +59,9 @@ default boolean removeMenuOptions()
position = -2,
section = notificationSection
)
- default boolean notifyAllEvents()
+ default Notification notifyAllEvents()
{
- return false;
+ return Notification.OFF;
}
@ConfigItem(
@@ -69,9 +70,9 @@ default boolean notifyAllEvents()
description = "",
section = notificationSection
)
- default boolean notifyArnav()
+ default Notification notifyArnav()
{
- return false;
+ return Notification.OFF;
}
@ConfigItem(
@@ -80,9 +81,9 @@ default boolean notifyArnav()
description = "",
section = notificationSection
)
- default boolean notifyBeekeeper()
+ default Notification notifyBeekeeper()
{
- return false;
+ return Notification.OFF;
}
@ConfigItem(
@@ -91,9 +92,9 @@ default boolean notifyBeekeeper()
description = "",
section = notificationSection
)
- default boolean notifyBob()
+ default Notification notifyBob()
{
- return false;
+ return Notification.OFF;
}
@ConfigItem(
@@ -102,9 +103,9 @@ default boolean notifyBob()
description = "",
section = notificationSection
)
- default boolean notifyCerters()
+ default Notification notifyCerters()
{
- return false;
+ return Notification.OFF;
}
@ConfigItem(
@@ -113,9 +114,9 @@ default boolean notifyCerters()
description = "",
section = notificationSection
)
- default boolean notifyDemon()
+ default Notification notifyDemon()
{
- return false;
+ return Notification.OFF;
}
@ConfigItem(
@@ -124,9 +125,9 @@ default boolean notifyDemon()
description = "",
section = notificationSection
)
- default boolean notifyDunce()
+ default Notification notifyDunce()
{
- return false;
+ return Notification.OFF;
}
@ConfigItem(
@@ -135,9 +136,9 @@ default boolean notifyDunce()
description = "",
section = notificationSection
)
- default boolean notifyDwarf()
+ default Notification notifyDwarf()
{
- return false;
+ return Notification.OFF;
}
@ConfigItem(
@@ -146,9 +147,9 @@ default boolean notifyDwarf()
description = "",
section = notificationSection
)
- default boolean notifyForester()
+ default Notification notifyForester()
{
- return false;
+ return Notification.OFF;
}
@ConfigItem(
@@ -157,9 +158,9 @@ default boolean notifyForester()
description = "",
section = notificationSection
)
- default boolean notifyFlippa()
+ default Notification notifyFlippa()
{
- return false;
+ return Notification.OFF;
}
@ConfigItem(
@@ -168,9 +169,9 @@ default boolean notifyFlippa()
description = "",
section = notificationSection
)
- default boolean notifyFrog()
+ default Notification notifyFrog()
{
- return false;
+ return Notification.OFF;
}
@ConfigItem(
@@ -179,9 +180,9 @@ default boolean notifyFrog()
description = "",
section = notificationSection
)
- default boolean notifyGenie()
+ default Notification notifyGenie()
{
- return false;
+ return Notification.OFF;
}
@ConfigItem(
@@ -190,9 +191,9 @@ default boolean notifyGenie()
description = "",
section = notificationSection
)
- default boolean notifyGravedigger()
+ default Notification notifyGravedigger()
{
- return false;
+ return Notification.OFF;
}
@ConfigItem(
@@ -201,9 +202,9 @@ default boolean notifyGravedigger()
description = "",
section = notificationSection
)
- default boolean notifyJekyll()
+ default Notification notifyJekyll()
{
- return false;
+ return Notification.OFF;
}
@ConfigItem(
@@ -212,9 +213,9 @@ default boolean notifyJekyll()
description = "",
section = notificationSection
)
- default boolean notifyMaze()
+ default Notification notifyMaze()
{
- return false;
+ return Notification.OFF;
}
@ConfigItem(
@@ -223,9 +224,9 @@ default boolean notifyMaze()
description = "",
section = notificationSection
)
- default boolean notifyMime()
+ default Notification notifyMime()
{
- return false;
+ return Notification.OFF;
}
@ConfigItem(
@@ -234,9 +235,9 @@ default boolean notifyMime()
description = "",
section = notificationSection
)
- default boolean notifyMoM()
+ default Notification notifyMoM()
{
- return false;
+ return Notification.OFF;
}
@ConfigItem(
@@ -245,9 +246,9 @@ default boolean notifyMoM()
description = "",
section = notificationSection
)
- default boolean notifyPillory()
+ default Notification notifyPillory()
{
- return false;
+ return Notification.OFF;
}
@ConfigItem(
@@ -256,9 +257,9 @@ default boolean notifyPillory()
description = "",
section = notificationSection
)
- default boolean notifyPrison()
+ default Notification notifyPrison()
{
- return false;
+ return Notification.OFF;
}
@ConfigItem(
@@ -267,9 +268,9 @@ default boolean notifyPrison()
description = "",
section = notificationSection
)
- default boolean notifyQuiz()
+ default Notification notifyQuiz()
{
- return false;
+ return Notification.OFF;
}
@ConfigItem(
@@ -278,9 +279,9 @@ default boolean notifyQuiz()
description = "",
section = notificationSection
)
- default boolean notifySandwich()
+ default Notification notifySandwich()
{
- return false;
+ return Notification.OFF;
}
@ConfigItem(
@@ -289,9 +290,9 @@ default boolean notifySandwich()
description = "",
section = notificationSection
)
- default boolean notifyTurpentine()
+ default Notification notifyTurpentine()
{
- return false;
+ return Notification.OFF;
}
@ConfigItem(
@@ -300,9 +301,9 @@ default boolean notifyTurpentine()
description = "",
section = notificationSection
)
- default boolean notifyTwin()
+ default Notification notifyTwin()
{
- return false;
+ return Notification.OFF;
}
@ConfigItem(
@@ -311,8 +312,8 @@ default boolean notifyTwin()
description = "",
section = notificationSection
)
- default boolean notifyCountCheck()
+ default Notification notifyCountCheck()
{
- return false;
+ return Notification.OFF;
}
}
diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/randomevents/RandomEventPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/randomevents/RandomEventPlugin.java
index 04f8b89b5f..9386462efd 100644
--- a/runelite-client/src/main/java/net/runelite/client/plugins/randomevents/RandomEventPlugin.java
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/randomevents/RandomEventPlugin.java
@@ -42,6 +42,7 @@
import net.runelite.api.events.NpcDespawned;
import net.runelite.client.Notifier;
import net.runelite.client.config.ConfigManager;
+import net.runelite.client.config.Notification;
import net.runelite.client.eventbus.Subscribe;
import net.runelite.client.plugins.Plugin;
import net.runelite.client.plugins.PluginDescriptor;
@@ -136,10 +137,7 @@ public void onInteractingChanged(InteractingChanged event)
{
lastNotificationTick = client.getTickCount();
- if (shouldNotify(currentRandomEvent.getId()))
- {
- notifier.notify("Random event spawned: " + currentRandomEvent.getName());
- }
+ notifier.notify(shouldNotify(currentRandomEvent.getId()), "Random event spawned: " + currentRandomEvent.getName());
}
}
@@ -169,73 +167,97 @@ public void onMenuEntryAdded(MenuEntryAdded event)
}
}
- private boolean shouldNotify(int id)
+ private Notification shouldNotify(int id)
{
- if (config.notifyAllEvents())
- {
- return true;
- }
-
+ Notification notification = null;
switch (id)
{
case NpcID.BEE_KEEPER_6747:
- return config.notifyBeekeeper();
+ notification = config.notifyBeekeeper();
+ break;
case NpcID.CAPT_ARNAV:
- return config.notifyArnav();
+ notification = config.notifyArnav();
+ break;
case NpcID.DRUNKEN_DWARF:
- return config.notifyDwarf();
+ notification = config.notifyDwarf();
+ break;
case NpcID.SERGEANT_DAMIEN_6743:
- return config.notifyDemon();
+ notification = config.notifyDemon();
+ break;
case NpcID.FREAKY_FORESTER_6748:
- return config.notifyForester();
+ notification = config.notifyForester();
+ break;
case NpcID.FROG_5429:
- return config.notifyFrog();
+ notification = config.notifyFrog();
+ break;
case NpcID.GENIE:
case NpcID.GENIE_327:
- return config.notifyGenie();
+ notification = config.notifyGenie();
+ break;
case NpcID.GILES:
case NpcID.GILES_5441:
case NpcID.NILES:
case NpcID.NILES_5439:
case NpcID.MILES:
case NpcID.MILES_5440:
- return config.notifyCerters();
+ notification = config.notifyCerters();
+ break;
case NpcID.DR_JEKYLL:
case NpcID.DR_JEKYLL_314:
- return config.notifyJekyll();
+ notification = config.notifyJekyll();
+ break;
case NpcID.EVIL_BOB:
- return config.notifyBob();
+ notification = config.notifyBob();
+ break;
case NpcID.EVIL_BOB_6754:
- return config.notifyPrison();
+ notification = config.notifyPrison();
+ break;
case NpcID.LEO_6746:
- return config.notifyGravedigger();
+ notification = config.notifyGravedigger();
+ break;
case NpcID.MYSTERIOUS_OLD_MAN_6750:
case NpcID.MYSTERIOUS_OLD_MAN_6751:
- return config.notifyMoM();
+ notification = config.notifyMoM();
+ break;
case NpcID.MYSTERIOUS_OLD_MAN_6752:
- return config.notifyMaze();
+ notification = config.notifyMaze();
+ break;
case NpcID.MYSTERIOUS_OLD_MAN_6753:
- return config.notifyMime();
+ notification = config.notifyMime();
+ break;
case NpcID.PILLORY_GUARD:
- return config.notifyPillory();
+ notification = config.notifyPillory();
+ break;
case NpcID.POSTIE_PETE_6738:
- return config.notifyTwin();
+ notification = config.notifyTwin();
+ break;
case NpcID.QUIZ_MASTER_6755:
- return config.notifyQuiz();
+ notification = config.notifyQuiz();
+ break;
case NpcID.RICK_TURPENTINE:
case NpcID.RICK_TURPENTINE_376:
- return config.notifyTurpentine();
+ notification = config.notifyTurpentine();
+ break;
case NpcID.DUNCE_6749:
- return config.notifyDunce();
+ notification = config.notifyDunce();
+ break;
case NpcID.SANDWICH_LADY:
- return config.notifySandwich();
+ notification = config.notifySandwich();
+ break;
case NpcID.FLIPPA_6744:
- return config.notifyFlippa();
+ notification = config.notifyFlippa();
+ break;
case NpcID.COUNT_CHECK_12551:
case NpcID.COUNT_CHECK_12552:
- return config.notifyCountCheck();
- default:
- return false;
+ notification = config.notifyCountCheck();
+ break;
}
+
+ if (notification != null && notification.isEnabled())
+ {
+ return notification;
+ }
+
+ return config.notifyAllEvents();
}
}
diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/regenmeter/RegenMeterPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/regenmeter/RegenMeterPlugin.java
index c8224571a5..447efb450a 100644
--- a/runelite-client/src/main/java/net/runelite/client/plugins/regenmeter/RegenMeterPlugin.java
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/regenmeter/RegenMeterPlugin.java
@@ -130,7 +130,9 @@ public void onItemContainerChanged(ItemContainerChanged event)
return;
}
- ticksSinceSpecRegen = 0;
+ // Lightbearer switch preserves time until next spec regen if <25 ticks remain
+ // If unequipping Lightbearer, this will always evaluate to 0
+ ticksSinceSpecRegen = Math.max(0, ticksSinceSpecRegen - 25);
wearingLightbearer = hasLightbearer;
}
diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/runecraft/RunecraftConfig.java b/runelite-client/src/main/java/net/runelite/client/plugins/runecraft/RunecraftConfig.java
index cddc8da594..b0f263cbfc 100644
--- a/runelite-client/src/main/java/net/runelite/client/plugins/runecraft/RunecraftConfig.java
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/runecraft/RunecraftConfig.java
@@ -29,6 +29,7 @@
import net.runelite.client.config.ConfigGroup;
import net.runelite.client.config.ConfigItem;
import net.runelite.client.config.ConfigSection;
+import net.runelite.client.config.Notification;
@ConfigGroup(RunecraftConfig.GROUP)
public interface RunecraftConfig extends Config
@@ -239,8 +240,8 @@ default boolean hightlightDarkMage()
description = "Send a notification when a pouch degrades",
position = 19
)
- default boolean degradingNotification()
+ default Notification degradingNotification()
{
- return true;
+ return Notification.ON;
}
}
diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/runecraft/RunecraftPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/runecraft/RunecraftPlugin.java
index 55339b884a..563658238a 100644
--- a/runelite-client/src/main/java/net/runelite/client/plugins/runecraft/RunecraftPlugin.java
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/runecraft/RunecraftPlugin.java
@@ -130,12 +130,9 @@ public void onChatMessage(ChatMessage event)
return;
}
- if (config.degradingNotification())
+ if (event.getMessage().contains(POUCH_DECAYED_MESSAGE))
{
- if (event.getMessage().contains(POUCH_DECAYED_MESSAGE))
- {
- notifier.notify(POUCH_DECAYED_NOTIFICATION_MESSAGE);
- }
+ notifier.notify(config.degradingNotification(), POUCH_DECAYED_NOTIFICATION_MESSAGE);
}
}
diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/skillcalculator/CalculatorType.java b/runelite-client/src/main/java/net/runelite/client/plugins/skillcalculator/CalculatorType.java
index 8c27d8a509..43bb5f5991 100644
--- a/runelite-client/src/main/java/net/runelite/client/plugins/skillcalculator/CalculatorType.java
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/skillcalculator/CalculatorType.java
@@ -35,8 +35,8 @@
enum CalculatorType
{
MINING(Skill.MINING, MiningBonus.values(), MiningAction.values()),
- AGILITY(Skill.AGILITY, null, AgilityAction.values()),
- SMITHING(Skill.SMITHING, null, SmithingAction.values()),
+ AGILITY(Skill.AGILITY, AgilityBonus.values(), AgilityAction.values()),
+ SMITHING(Skill.SMITHING, SmithingBonus.values(), SmithingAction.values()),
HERBLORE(Skill.HERBLORE, null, HerbloreAction.values()),
FISHING(Skill.FISHING, FishingBonus.values(), FishingAction.values()),
THIEVING(Skill.THIEVING, null, ThievingAction.values()),
diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/skillcalculator/SkillCalculator.java b/runelite-client/src/main/java/net/runelite/client/plugins/skillcalculator/SkillCalculator.java
index f029397385..6fa9f9aed7 100644
--- a/runelite-client/src/main/java/net/runelite/client/plugins/skillcalculator/SkillCalculator.java
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/skillcalculator/SkillCalculator.java
@@ -25,6 +25,7 @@
*/
package net.runelite.client.plugins.skillcalculator;
+import com.google.common.annotations.VisibleForTesting;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
@@ -36,7 +37,11 @@
import java.awt.event.MouseEvent;
import java.text.NumberFormat;
import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
import java.util.List;
+import java.util.Map;
+import java.util.Set;
import java.util.function.Consumer;
import java.util.stream.Collectors;
import javax.inject.Inject;
@@ -84,7 +89,7 @@ class SkillCalculator extends JPanel
private final List uiActionSlots = new ArrayList<>();
private final UICombinedActionSlot combinedActionSlot;
private final ArrayList combinedActionSlots = new ArrayList<>();
- private final List bonusCheckBoxes = new ArrayList<>();
+ private final Map bonusCheckBoxes = new HashMap<>();
private final IconTextField searchBar = new IconTextField();
private CalculatorType currentCalculator;
@@ -92,7 +97,7 @@ class SkillCalculator extends JPanel
private int currentXP = Experience.getXpForLevel(currentLevel);
private int targetLevel = currentLevel + 1;
private int targetXP = Experience.getXpForLevel(targetLevel);
- private SkillBonus currentBonus = null;
+ private final Set currentBonuses = new HashSet<>();
@Inject
SkillCalculator(Client client, ClientThread clientThread, UICalculatorInputArea uiInput, SpriteManager spriteManager, ItemManager itemManager)
@@ -153,7 +158,7 @@ void openCalculator(CalculatorType calculatorType, boolean forceReload)
if (forceReload || currentCalculator != calculatorType)
{
currentCalculator = calculatorType;
- currentBonus = null;
+ currentBonuses.clear();
@Varp int endGoalVarp = endGoalVarpForSkill(calculatorType.getSkill());
int endGoal = client.getVarpValue(endGoalVarp);
@@ -268,7 +273,7 @@ private void renderBonusOptions()
private JPanel buildCheckboxPanel(SkillBonus bonus)
{
JPanel uiOption = new JPanel(new BorderLayout());
- JLabel uiLabel = new JLabel(bonus.getName());
+ JLabel uiLabel = new JLabel(generateDisplayNameForBonus(bonus));
JCheckBox uiCheckbox = new JCheckBox();
uiLabel.setForeground(Color.WHITE);
@@ -281,22 +286,54 @@ private JPanel buildCheckboxPanel(SkillBonus bonus)
uiOption.add(uiLabel, BorderLayout.WEST);
uiOption.add(uiCheckbox, BorderLayout.EAST);
- bonusCheckBoxes.add(uiCheckbox);
+ bonusCheckBoxes.put(bonus, uiCheckbox);
return uiOption;
}
+ private static String generateDisplayNameForBonus(SkillBonus bonus)
+ {
+ return bonus.getName() + " (" + formatBonusPercentage(bonus.getValue()) + "%)";
+ }
+
+ @VisibleForTesting
+ static String formatBonusPercentage(float bonus)
+ {
+ final int bonusValue = Math.round(10_000 * bonus);
+ final float bonusPercent = bonusValue / 100f;
+ final int bonusPercentInt = (int) bonusPercent;
+
+ if (bonusPercent == bonusPercentInt)
+ {
+ return String.valueOf(bonusPercentInt);
+ }
+ else
+ {
+ return String.valueOf(bonusPercent);
+ }
+ }
+
private void adjustCheckboxes(JCheckBox target, SkillBonus bonus)
{
- for (JCheckBox otherSelectedCheckbox : bonusCheckBoxes)
+ // Check if target is stackable with any other bonuses
+ for (Map.Entry entry : bonusCheckBoxes.entrySet())
{
- if (otherSelectedCheckbox != target)
+ if (entry.getValue() != target && !entry.getKey().getCanBeStackedWith().contains(bonus))
{
- otherSelectedCheckbox.setSelected(false);
+ currentBonuses.remove(entry.getKey());
+ entry.getValue().setSelected(false);
}
}
- adjustXPBonus(target.isSelected() ? bonus : null);
+ if (target.isSelected())
+ {
+ currentBonuses.add(bonus);
+ }
+ else
+ {
+ currentBonuses.remove(bonus);
+ }
+ calculate();
}
private void renderActionSlots()
@@ -387,11 +424,14 @@ private void calculate()
int neededXP = targetXP - currentXP;
SkillAction action = slot.getAction();
float bonus = 1f;
- if (currentBonus != null && action.isBonusApplicable(currentBonus))
+ for (SkillBonus skillBonus : currentBonuses)
{
- bonus = currentBonus.getValue();
+ if (action.isBonusApplicable(skillBonus))
+ {
+ bonus *= skillBonus.getValue();
+ }
}
- final int xp = Math.round(action.getXp() * bonus * 10f);
+ final int xp = (int) Math.floor(action.getXp() * 10f * bonus);
if (neededXP > 0)
{
@@ -434,12 +474,6 @@ private void updateInputFields()
calculate();
}
- private void adjustXPBonus(SkillBonus bonus)
- {
- currentBonus = bonus;
- calculate();
- }
-
private void onFieldCurrentLevelUpdated()
{
currentLevel = enforceSkillBounds(uiInput.getCurrentLevelInput());
diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/skillcalculator/skills/AgilityAction.java b/runelite-client/src/main/java/net/runelite/client/plugins/skillcalculator/skills/AgilityAction.java
index f4b32eaf6d..4c31032db8 100644
--- a/runelite-client/src/main/java/net/runelite/client/plugins/skillcalculator/skills/AgilityAction.java
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/skillcalculator/skills/AgilityAction.java
@@ -24,10 +24,15 @@
*/
package net.runelite.client.plugins.skillcalculator.skills;
+import java.util.EnumSet;
+import java.util.Set;
import lombok.AllArgsConstructor;
import lombok.Getter;
import net.runelite.api.ItemID;
import net.runelite.client.game.ItemManager;
+import static net.runelite.client.plugins.skillcalculator.skills.AgilityBonus.WILDERNESS_AGILITY_TICKET_101_PLUS;
+import static net.runelite.client.plugins.skillcalculator.skills.AgilityBonus.WILDERNESS_AGILITY_TICKET_11_TO_50;
+import static net.runelite.client.plugins.skillcalculator.skills.AgilityBonus.WILDERNESS_AGILITY_TICKET_51_TO_100;
@AllArgsConstructor
@Getter
@@ -38,16 +43,17 @@ public enum AgilityAction implements NamedSkillAction
DRAYNOR_VILLAGE_ROOFTOP("Draynor Village Rooftop", 10, 120, ItemID.MARK_OF_GRACE),
LEAPING_TROUT("Leaping trout", 15, 5, ItemID.LEAPING_TROUT),
AL_KHARID_ROOFTOP("Al Kharid Rooftop", 20, 180, ItemID.MARK_OF_GRACE),
+ LEAPING_SALMON("Leaping salmon", 30, 6, ItemID.LEAPING_SALMON),
VARROCK_ROOFTOP("Varrock Rooftop", 30, 238, ItemID.MARK_OF_GRACE),
PENGUIN_AGILITY_COURSE("Penguin Agility Course", 30, 540, ItemID.CLOCKWORK_SUIT),
- LEAPING_SALMON("Leaping salmon", 30, 6, ItemID.LEAPING_SALMON),
BARBARIAN_OUTPOST("Barbarian Outpost", 35, 152.5f, ItemID.STEEL_BATTLEAXE),
CANIFIS_ROOFTOP("Canifis Rooftop", 40, 240, ItemID.MARK_OF_GRACE),
LEAPING_STURGEON("Leaping sturgeon", 45, 7, ItemID.LEAPING_STURGEON),
- APE_ATOLL_COURSE("Ape Atoll", 48, 580, ItemID.GORILLA_GREEGREE),
SHAYZIEN_ADVANCED_COURSE("Shayzien Advanced Course", 48, 474.3f, ItemID.SHAYZIEN_HELM_5),
+ APE_ATOLL_COURSE("Ape Atoll", 48, 580, ItemID.GORILLA_GREEGREE),
FALADOR_ROOFTOP("Falador Rooftop", 50, 440, ItemID.MARK_OF_GRACE),
- WILDERNESS_AGILITY_COURSE("Wilderness Agility Course", 52, 571, ItemID.SKULL),
+ WILDERNESS_AGILITY_COURSE_TICKET("Wilderness Agility Ticket", 52, 200, ItemID.WILDERNESS_AGILITY_TICKET),
+ WILDERNESS_AGILITY_COURSE("Wilderness Agility Course", 52, 571.4f, ItemID.SKULL),
HALLOWED_SEPULCHRE_FLOOR_1("Hallowed Sepulchre Floor 1", 52, 575, ItemID.RING_OF_ENDURANCE),
SEERS_VILLAGE_ROOFTOP("Seers' Village Rooftop", 60, 570, ItemID.MARK_OF_GRACE),
WEREWOLF_AGILITY_COURSE("Werewolf Agility Course", 60, 730, ItemID.STICK),
@@ -72,4 +78,19 @@ public boolean isMembers(final ItemManager itemManager)
{
return true;
}
+
+ @Override
+ public Set getExcludedSkillBonuses()
+ {
+ final EnumSet others = EnumSet.allOf(AgilityBonus.class);
+
+ if (this == WILDERNESS_AGILITY_COURSE_TICKET)
+ {
+ others.remove(WILDERNESS_AGILITY_TICKET_11_TO_50);
+ others.remove(WILDERNESS_AGILITY_TICKET_51_TO_100);
+ others.remove(WILDERNESS_AGILITY_TICKET_101_PLUS);
+ }
+
+ return others;
+ }
}
diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/skillcalculator/skills/AgilityBonus.java b/runelite-client/src/main/java/net/runelite/client/plugins/skillcalculator/skills/AgilityBonus.java
new file mode 100644
index 0000000000..d84b78f7b7
--- /dev/null
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/skillcalculator/skills/AgilityBonus.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2024, DapperMickie
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package net.runelite.client.plugins.skillcalculator.skills;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+@AllArgsConstructor
+@Getter(onMethod_ = @Override)
+public enum AgilityBonus implements SkillBonus
+{
+ WILDERNESS_AGILITY_TICKET_11_TO_50("11-50 Wilderness Tickets", 1.05f),
+ WILDERNESS_AGILITY_TICKET_51_TO_100("51-100 Wilderness Tickets", 1.1f),
+ WILDERNESS_AGILITY_TICKET_101_PLUS("101+ Wilderness Tickets", 1.15f),
+ ;
+
+ private final String name;
+ private final float value;
+}
diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/skillcalculator/skills/ConstructionAction.java b/runelite-client/src/main/java/net/runelite/client/plugins/skillcalculator/skills/ConstructionAction.java
index 9e0665e2b8..8f0197d78e 100644
--- a/runelite-client/src/main/java/net/runelite/client/plugins/skillcalculator/skills/ConstructionAction.java
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/skillcalculator/skills/ConstructionAction.java
@@ -33,71 +33,69 @@
@Getter
public enum ConstructionAction implements NamedSkillAction
{
- EXIT_PORTAL("Exit Portal", 1, 100, ItemID.EXIT_PORTAL),
PLANK("Plank", 1, 29, ItemID.PLANK),
- OAK_PLANK("Oak Plank", 1, 60, ItemID.OAK_PLANK),
- TEAK_PLANK("Teak Plank", 1, 90, ItemID.TEAK_PLANK),
- MAHOGANY_PLANK("Mahogany Plank", 1, 140, ItemID.MAHOGANY_PLANK),
- PLANT("Plant", 1, 31, ItemID.PLANT),
+ DOCK_LEAF("Dock Leaf", 1, 31, ItemID.DOCK_LEAF),
FERN_BIG_PLANT("Fern (big plant)", 1, 31, ItemID.FERN_8186),
+ PLANT("Plant", 1, 31, ItemID.PLANT),
SHORT_PLANT("Short Plant", 1, 31, ItemID.SHORT_PLANT),
- DOCK_LEAF("Dock Leaf", 1, 31, ItemID.DOCK_LEAF),
CRUDE_WOODEN_CHAIR("Crude Wooden Chair", 1, 58, ItemID.CRUDE_WOODEN_CHAIR),
+ EXIT_PORTAL("Exit Portal", 1, 100, ItemID.EXIT_PORTAL),
BROWN_RUG("Brown Rug", 2, 30, ItemID.BROWN_RUG),
TORN_CURTAINS("Torn Curtains", 2, 132, ItemID.TORN_CURTAINS),
CLAY_FIREPLACE("Clay Fireplace", 3, 30, ItemID.CLAY_FIREPLACE),
WOODEN_BOOKCASE("Wooden Bookcase", 4, 115, ItemID.WOODEN_BOOKCASE),
- FIREPIT("Firepit", 5, 40, ItemID.FIREPIT),
CAT_BLANKET("Cat Blanket", 5, 15, ItemID.CAT_BLANKET),
- DECORATIVE_ROCK("Decorative Rock", 5, 100, ItemID.DECORATIVE_ROCK),
TREE("Tree", 5, 31, ItemID.TREE),
- SMALL_FERN("Small Fern", 6, 70, ItemID.SMALL_FERN),
- THISTLE("Thistle", 6, 70, ItemID.THISTLE),
+ FIREPIT("Firepit", 5, 40, ItemID.FIREPIT),
+ DECORATIVE_ROCK("Decorative Rock", 5, 100, ItemID.DECORATIVE_ROCK),
BUSH("Bush", 6, 70, ItemID.BUSH),
LARGE_LEAF_BUSH("Large Leaf Bush", 6, 70, ItemID.LARGELEAF_PLANT),
+ SMALL_FERN("Small Fern", 6, 70, ItemID.SMALL_FERN),
+ THISTLE("Thistle", 6, 70, ItemID.THISTLE),
WOODEN_SHELVES_1("Wooden Shelves 1", 6, 87, ItemID.WOODEN_SHELVES_1),
- PUMP_AND_DRAIN("Pump and Drain", 7, 100, ItemID.PUMP_AND_DRAIN),
BEER_BARREL("Beer Barrel", 7, 87, ItemID.BEER_BARREL),
+ PUMP_AND_DRAIN("Pump and Drain", 7, 100, ItemID.PUMP_AND_DRAIN),
WOODEN_CHAIR("Wooden Chair", 8, 87, ItemID.WOODEN_CHAIR),
WOODEN_LARDER("Wooden Larder", 9, 228, ItemID.WOODEN_LARDER),
- WOOD_DINING_TABLE("Wood Dining Table", 10, 115, ItemID.WOOD_DINING_TABLE),
- POND("Pond", 10, 100, ItemID.POND),
NICE_TREE("Nice Tree", 10, 44, ItemID.NICE_TREE),
+ POND("Pond", 10, 100, ItemID.POND),
WOODEN_BENCH("Wooden Bench", 10, 115, ItemID.WOODEN_BENCH),
+ WOOD_DINING_TABLE("Wood Dining Table", 10, 115, ItemID.WOOD_DINING_TABLE),
FIREPIT_WITH_HOOK("Firepit with Hook", 11, 60, ItemID.FIREPIT_WITH_HOOK),
- REEDS("Reeds", 12, 100, ItemID.REEDS),
- FERN_SMALL_PLANT("Fern (small plant)", 12, 100, ItemID.FERN),
- CIDER_BARREL("Cider Barrel", 12, 91, ItemID.CIDER_BARREL),
- WOODEN_SHELVES_2("Wooden Shelves 2", 12, 147, ItemID.WOODEN_SHELVES_2),
WOOD_TABLE("Wood Table", 12, 87, ItemID.WOOD_DINING_TABLE),
+ CIDER_BARREL("Cider Barrel", 12, 91, ItemID.CIDER_BARREL),
+ FERN_SMALL_PLANT("Fern (small plant)", 12, 100, ItemID.FERN),
HUGE_PLANT("Huge Plant", 12, 100, ItemID.HUGE_PLANT),
+ REEDS("Reeds", 12, 100, ItemID.REEDS),
TALL_PLANT("Tall Plant", 12, 100, ItemID.TALL_PLANT),
+ WOODEN_SHELVES_2("Wooden Shelves 2", 12, 147, ItemID.WOODEN_SHELVES_2),
RUG("Rug", 13, 60, ItemID.RUG),
ROCKING_CHAIR("Rocking Chair", 14, 87, ItemID.ROCKING_CHAIR),
- IMP_STATUE("Imp Statue", 15, 150, ItemID.IMP_STATUE),
+ OAK_PLANK("Oak Plank", 15, 60, ItemID.OAK_PLANK),
OAK_TREE("Oak Tree", 15, 70, ItemID.OAK_TREE),
+ IMP_STATUE("Imp Statue", 15, 150, ItemID.IMP_STATUE),
OAK_DECORATION("Oak Decoration", 16, 120, ItemID.OAK_DECORATION),
FIREPIT_WITH_POT("Firepit with Pot", 17, 80, ItemID.FIREPIT_WITH_POT),
- CURTAINS("Curtains", 18, 225, ItemID.CURTAINS),
ASGARNIAN_ALE("Asgarnian Ale", 18, 184, ItemID.ASGARNIAN_ALE),
+ CURTAINS("Curtains", 18, 225, ItemID.CURTAINS),
CAT_BASKET("Cat Basket", 19, 58, ItemID.CAT_BASKET),
OAK_CHAIR("Oak Chair", 19, 120, ItemID.OAK_CHAIR),
- WOODEN_BED("Wooden Bed", 20, 117, ItemID.WOODEN_BED),
SHOE_BOX("Shoe Box", 20, 58, ItemID.SHOE_BOX),
+ WOODEN_BED("Wooden Bed", 20, 117, ItemID.WOODEN_BED),
SHAVING_STAND("Shaving Stand", 21, 30, ItemID.SHAVING_STAND),
- OAK_DINING_TABLE("Oak Dining Table", 22, 240, ItemID.OAK_DINING_TABLE),
OAK_BENCH("Oak Bench", 22, 240, ItemID.OAK_BENCH),
+ OAK_DINING_TABLE("Oak Dining Table", 22, 240, ItemID.OAK_DINING_TABLE),
WOODEN_SHELVES_3("Wooden Shelves 3", 23, 147, ItemID.WOODEN_SHELVES_3),
SMALL_OVEN("Small Oven", 24, 80, ItemID.SMALL_OVEN),
OAK_CLOCK("Oak Clock", 25, 142, ItemID.OAK_CLOCK),
- GREENMANS_ALE("Greenman's Ale", 26, 184, ItemID.GREENMANS_ALE),
- OAK_ARMCHAIR("Oak Armchair", 26, 180, ItemID.OAK_ARMCHAIR),
ROPE_BELL_PULL("Rope Bell-Pull", 26, 64, ItemID.ROPE_BELLPULL),
- PUMP_AND_TUB("Pump and Tub", 27, 200, ItemID.PUMP_AND_TUB),
+ OAK_ARMCHAIR("Oak Armchair", 26, 180, ItemID.OAK_ARMCHAIR),
+ GREENMANS_ALE("Greenman's Ale", 26, 184, ItemID.GREENMANS_ALE),
OAK_DRAWERS("Oak Drawers", 27, 120, ItemID.OAK_DRAWERS),
- OAK_BOOKCASE("Oak Bookcase", 29, 180, ItemID.OAK_BOOKCASE),
- LARGE_OVEN("Large Oven", 29, 100, ItemID.LARGE_OVEN),
+ PUMP_AND_TUB("Pump and Tub", 27, 200, ItemID.PUMP_AND_TUB),
OAK_SHAVING_STAND("Oak Shaving Stand", 29, 61, ItemID.OAK_SHAVING_STAND),
+ LARGE_OVEN("Large Oven", 29, 100, ItemID.LARGE_OVEN),
+ OAK_BOOKCASE("Oak Bookcase", 29, 180, ItemID.OAK_BOOKCASE),
WILLOW_TREE("Willow Tree", 30, 100, ItemID.WILLOW_TREE),
OAK_BED("Oak Bed", 30, 210, ItemID.OAK_BED),
LONG_BONE("Long Bone", 30, 4500, ItemID.LONG_BONE),
@@ -106,27 +104,29 @@ public enum ConstructionAction implements NamedSkillAction
CARVED_OAK_TABLE("Carved Oak Table", 31, 360, ItemID.CARVED_OAK_TABLE),
OAK_KITCHEN_TABLE("Oak Kitchen Table", 32, 180, ItemID.TEAK_TABLE),
BOXING_RING("Boxing Ring", 32, 420, ItemID.BOXING_RING),
- OAK_LARDER("Oak Larder", 33, 480, ItemID.OAK_LARDER),
- CUSHIONED_BASKET("Cushioned Basket", 33, 58, ItemID.CUSHIONED_BASKET),
STONE_FIREPLACE("Stone Fireplace", 33, 40, ItemID.STONE_FIREPLACE),
+ CUSHIONED_BASKET("Cushioned Basket", 33, 58, ItemID.CUSHIONED_BASKET),
+ OAK_LARDER("Oak Larder", 33, 480, ItemID.OAK_LARDER),
+ GLOVE_RACK("Glove Rack", 34, 120, ItemID.GLOVE_RACK),
STEEL_RANGE("Steel Range", 34, 120, ItemID.STEEL_RANGE),
OAK_SHELVES_1("Oak Shelves 1", 34, 240, ItemID.OAK_SHELVES_1),
- GLOVE_RACK("Glove Rack", 34, 120, ItemID.GLOVE_RACK),
LARGE_OAK_BED("Large Oak Bed", 34, 330, ItemID.LARGE_OAK_BED),
+ TEAK_PLANK("Teak Plank", 35, 90, ItemID.TEAK_PLANK),
TEAK_ARMCHAIR("Teak Armchair", 35, 180, ItemID.TEAK_ARMCHAIR),
- DRAGON_BITTER("Dragon Bitter", 36, 224, ItemID.DRAGON_BITTER),
TEAK_DECORATION("Teak Decoration", 36, 180, ItemID.TEAK_DECORATION),
+ DRAGON_BITTER("Dragon Bitter", 36, 224, ItemID.DRAGON_BITTER),
BELL_PULL("Bell-Pull", 37, 120, ItemID.BELLPULL),
OAK_DRESSER("Oak Dresser", 37, 121, ItemID.OAK_DRESSER),
TEAK_BENCH("Teak Bench", 38, 360, ItemID.CARVED_TEAK_BENCH),
TEAK_TABLE("Teak Table", 38, 360, ItemID.TEAK_TABLE),
OAK_WARDROBE("Oak Wardrobe", 39, 180, ItemID.OAK_WARDROBE),
- TEAK_BED("Teak Bed", 40, 300, ItemID.TEAK_BED),
- MAHOGANY_BOOKCASE("Mahogany Bookcase", 40, 420, ItemID.MAHOGANY_BOOKCASE),
OAK_LECTERN("Oak Lectern", 40, 60, ItemID.OAK_LECTERN),
+ MAHOGANY_PLANK("Mahogany Plank", 40, 140, ItemID.MAHOGANY_PLANK),
+ TEAK_BED("Teak Bed", 40, 300, ItemID.TEAK_BED),
OPULENT_CURTAINS("Opulent Curtains", 40, 315, ItemID.OPULENT_CURTAINS),
- FENCING_RING("Fencing Ring", 41, 570, ItemID.FENCING_RING),
+ MAHOGANY_BOOKCASE("Mahogany Bookcase", 40, 420, ItemID.MAHOGANY_BOOKCASE),
GLOBE("Globe", 41, 180, ItemID.GLOBE),
+ FENCING_RING("Fencing Ring", 41, 570, ItemID.FENCING_RING),
FANCY_RANGE("Fancy Range", 42, 160, ItemID.FANCY_RANGE),
CRYSTAL_BALL("Crystal Ball", 42, 280, ItemID.CRYSTAL_BALL),
ALCHEMICAL_CHART("Alchemical Chart", 43, 30, ItemID.ALCHEMICAL_CHART),
@@ -134,20 +134,20 @@ public enum ConstructionAction implements NamedSkillAction
WOODEN_TELESCOPE("Wooden Telescope", 44, 121, ItemID.OAK_TELESCOPE),
WEAPONS_RACK("Weapons Rack", 44, 180, ItemID.WEAPONS_RACK),
CARVED_TEAK_BENCH("Carved Teak Bench", 44, 360, ItemID.CARVED_TEAK_BENCH),
+ MAPLE_TREE("Maple Tree", 45, 122, ItemID.MAPLE_TREE),
OAK_SHELVES_2("Oak Shelves 2", 45, 240, ItemID.OAK_SHELVES_2),
- CARVED_TEAK_TABLE("Carved Teak Table", 45, 600, ItemID.CARVED_TEAK_TABLE),
LARGE_TEAK_BED("Large Teak Bed", 45, 480, ItemID.LARGE_TEAK_BED),
- MAPLE_TREE("Maple Tree", 45, 122, ItemID.MAPLE_TREE),
+ CARVED_TEAK_TABLE("Carved Teak Table", 45, 600, ItemID.CARVED_TEAK_TABLE),
TEAK_DRESSER("Teak Dresser", 46, 181, ItemID.TEAK_DRESSER),
- SINK("Sink", 47, 300, ItemID.SINK),
- EAGLE_LECTERN("Eagle Lectern", 47, 120, ItemID.EAGLE_LECTERN),
DEMON_LECTERN("Demon Lectern", 47, 120, ItemID.DEMON_LECTERN),
+ EAGLE_LECTERN("Eagle Lectern", 47, 120, ItemID.EAGLE_LECTERN),
+ SINK("Sink", 47, 300, ItemID.SINK),
MOUNTED_MYTHICAL_CAPE("Mounted Mythical Cape", 47, 370, ItemID.MYTHICAL_CAPE),
CHEFS_DELIGHT("Chef's Delight", 48, 224, ItemID.CHEFS_DELIGHT),
+ TELEPORT_FOCUS("Teleport Focus", 50, 40, ItemID.TELEPORT_FOCUS),
+ ORNAMENTAL_GLOBE("Ornamental Globe", 50, 270, ItemID.ORNAMENTAL_GLOBE),
TEAK_PORTAL("Teak Portal", 50, 270, ItemID.TEAK_PORTAL),
MAHOGANY_ARMCHAIR("Mahogany Armchair", 50, 280, ItemID.MAHOGANY_ARMCHAIR),
- ORNAMENTAL_GLOBE("Ornamental Globe", 50, 270, ItemID.ORNAMENTAL_GLOBE),
- TELEPORT_FOCUS("Teleport Focus", 50, 40, ItemID.TELEPORT_FOCUS),
TEAK_DRAWERS("Teak Drawers", 51, 180, ItemID.TEAK_DRAWERS),
COMBAT_RING("Combat Ring", 51, 630, ItemID.COMBAT_RING),
TEAK_KITCHEN_TABLE("Teak Kitchen Table", 52, 270, ItemID.TEAK_TABLE),
@@ -157,41 +157,41 @@ public enum ConstructionAction implements NamedSkillAction
EXTRA_WEAPONS_RACK("Extra Weapons Rack", 54, 440, ItemID.EXTRA_WEAPONS_RACK),
ELEMENTAL_SPHERE("Elemental Sphere", 54, 580, ItemID.ELEMENTAL_SPHERE),
TEAK_CLOCK("Teak Clock", 55, 202, ItemID.TEAK_CLOCK),
- GILDED_DECORATION("Gilded Decoration", 56, 1020, ItemID.GILDED_DECORATION),
FANCY_TEAK_DRESSER("Fancy Teak Dresser", 56, 182, ItemID.FANCY_TEAK_DRESSER),
TEAK_SHELVES_1("Teak Shelves 1", 56, 330, ItemID.TEAK_SHELVES_1),
- TEAK_EAGLE_LECTERN("Teak Eagle Lectern", 57, 180, ItemID.TEAK_EAGLE_LECTERN),
+ GILDED_DECORATION("Gilded Decoration", 56, 1020, ItemID.GILDED_DECORATION),
TEAK_DEMON_LECTERN("Teak Demon Lectern", 57, 180, ItemID.TEAK_DEMON_LECTERN),
+ TEAK_EAGLE_LECTERN("Teak Eagle Lectern", 57, 180, ItemID.TEAK_EAGLE_LECTERN),
LIMESTONE_ATTACK_STONE("Limestone attack stone", 59, 200, ItemID.ATTACK_STONE),
LUNAR_GLOBE("Lunar Globe", 59, 570, ItemID.LUNAR_GLOBE),
- GILDED_FOUR_POSTER_BED("Gilded 4-Poster Bed", 60, 1330, ItemID.GILDED_4POSTER),
- POSH_BELL_PULL("Posh Bell-Pull", 60, 420, ItemID.POSH_BELLPULL),
- SPICE_RACK("Spice Rack", 60, 374, ItemID.SPICE_RACK),
YEW_TREE("Yew Tree", 60, 141, ItemID.YEW_TREE),
+ SPICE_RACK("Spice Rack", 60, 374, ItemID.SPICE_RACK),
+ POSH_BELL_PULL("Posh Bell-Pull", 60, 420, ItemID.POSH_BELLPULL),
+ GILDED_FOUR_POSTER_BED("Gilded 4-Poster Bed", 60, 1330, ItemID.GILDED_4POSTER),
GILDED_BENCH("Gilded Bench", 61, 1760, ItemID.GILDED_BENCH),
+ ASTRONOMICAL_CHART("Astronomical Chart", 63, 45, ItemID.ASTRONOMICAL_CHART),
TEAK_WARDROBE("Teak Wardrobe", 63, 270, ItemID.TEAK_WARDROBE),
MARBLE_FIREPLACE("Marble Fireplace", 63, 500, ItemID.MARBLE_FIREPLACE),
- ASTRONOMICAL_CHART("Astronomical Chart", 63, 45, ItemID.ASTRONOMICAL_CHART),
TEAK_TELESCOPE("Teak Telescope", 64, 181, ItemID.TEAK_TELESCOPE),
MAHOGANY_DRESSER("Mahogany Dresser", 64, 281, ItemID.MAHOGANY_DRESSER),
+ OPULENT_RUG("Opulent Rug", 65, 360, ItemID.OPULENT_RUG),
MAHOGANY_PORTAL("Mahogany Portal", 65, 420, ItemID.MAHOGANY_PORTAL),
GREATER_FOCUS("Greater Focus", 65, 500, ItemID.GREATER_FOCUS),
- OPULENT_RUG("Opulent Rug", 65, 360, ItemID.OPULENT_RUG),
TEAK_GARDEN_BENCH("Teak Garden Bench", 66, 540, ItemID.TEAK_GARDEN_BENCH),
CRYSTAL_OF_POWER("Crystal of Power", 66, 890, ItemID.CRYSTAL_OF_POWER),
+ MAHOGANY_DEMON_LECTERN("Mahogany Demon Lectern", 67, 580, ItemID.MAHOGANY_DEMON),
+ MAHOGANY_EAGLE_LECTERN("Mahogany Eagle Lectern", 67, 580, ItemID.MAHOGANY_EAGLE),
TEAK_SHELVES_2("Teak Shelves 2", 67, 930, ItemID.TEAK_SHELVES_2),
- MAHOGANY_DEMON_LECTERN("Mahogany Demon Lectern", 67, 580, ItemID.TEAK_DEMON_LECTERN),
- MAHOGANY_EAGLE_LECTERN("Mahogany Eagle Lectern", 67, 580, ItemID.TEAK_DEMON_LECTERN),
CELESTIAL_GLOBE("Celestial Globe", 68, 570, ItemID.CELESTIAL_GLOBE),
DUNGEON_ENTRANCE("Dungeon Entrance", 70, 500, ItemID.DUNGEON_ENTRANCE),
RANGING_PEDESTALS("Ranging Pedestals", 71, 720, ItemID.RANGING_PEDESTALS),
OPULENT_TABLE("Opulent Table", 72, 3100, ItemID.OPULENT_TABLE),
- OAK_DOOR("Oak Door", 74, 600, ItemID.OAK_DOOR),
GILDED_DRESSER("Gilded Dresser", 74, 582, ItemID.GILDED_DRESSER),
- MAHOGANY_WARDROBE("Mahogany Wardrobe", 75, 420, ItemID.MAHOGANY_WARDROBE),
+ OAK_DOOR("Oak Door", 74, 600, ItemID.OAK_DOOR),
MAGIC_TREE("Magic Tree", 75, 223, ItemID.MAGIC_TREE),
- ARMILLARY_GLOBE("Armillary Globe", 77, 960, ItemID.GLOBE),
+ MAHOGANY_WARDROBE("Mahogany Wardrobe", 75, 420, ItemID.MAHOGANY_WARDROBE),
GNOME_BENCH("Gnome Bench", 77, 840, ItemID.GNOME_BENCH),
+ ARMILLARY_GLOBE("Armillary Globe", 77, 960, ItemID.GLOBE),
MARBLE_PORTAL("Marble Portal", 80, 1500, ItemID.MARBLE_PORTAL),
SCRYING_POOL("Scrying Pool", 80, 2000, ItemID.SCRYING_POOL),
BALANCE_BEAM("Balance Beam", 81, 1000, ItemID.BALANCE_BEAM),
diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/skillcalculator/skills/ConstructionBonus.java b/runelite-client/src/main/java/net/runelite/client/plugins/skillcalculator/skills/ConstructionBonus.java
index e5d1ca54d4..477cbb0e23 100644
--- a/runelite-client/src/main/java/net/runelite/client/plugins/skillcalculator/skills/ConstructionBonus.java
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/skillcalculator/skills/ConstructionBonus.java
@@ -31,7 +31,7 @@
@Getter(onMethod_ = @Override)
public enum ConstructionBonus implements SkillBonus
{
- CARPENTERS_OUTFIT("Carpenter's Outfit (+2.5%)", 1.025f),
+ CARPENTERS_OUTFIT("Carpenter's Outfit", 1.025f),
;
private final String name;
diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/skillcalculator/skills/CookingAction.java b/runelite-client/src/main/java/net/runelite/client/plugins/skillcalculator/skills/CookingAction.java
index 1613e7b46d..97803716f7 100644
--- a/runelite-client/src/main/java/net/runelite/client/plugins/skillcalculator/skills/CookingAction.java
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/skillcalculator/skills/CookingAction.java
@@ -34,19 +34,19 @@
public enum CookingAction implements ItemSkillAction
{
SINEW(ItemID.SINEW, 1, 3),
- SHRIMPS(ItemID.SHRIMPS, 1, 30),
+ ANCHOVIES(ItemID.ANCHOVIES, 1, 30),
COOKED_CHICKEN(ItemID.COOKED_CHICKEN, 1, 30),
COOKED_MEAT(ItemID.COOKED_MEAT, 1, 30),
COOKED_RABBIT(ItemID.COOKED_RABBIT, 1, 30),
- ANCHOVIES(ItemID.ANCHOVIES, 1, 30),
+ SHRIMPS(ItemID.SHRIMPS, 1, 30),
+ BREAD(ItemID.BREAD, 1, 40),
SARDINE(ItemID.SARDINE, 1, 40),
- POISON_KARAMBWAN(ItemID.POISON_KARAMBWAN, 1, 80),
UGTHANKI_MEAT(ItemID.UGTHANKI_MEAT, 1, 40),
- BREAD(ItemID.BREAD, 1, 40),
+ POISON_KARAMBWAN(ItemID.POISON_KARAMBWAN, 1, 80),
HERRING(ItemID.HERRING, 5, 50),
FRUIT_BLAST(ItemID.FRUIT_BLAST, 6, 50),
- BAKED_POTATO(ItemID.BAKED_POTATO, 7, 15),
GUPPY(ItemID.GUPPY, 7, 12),
+ BAKED_POTATO(ItemID.BAKED_POTATO, 7, 15),
PINEAPPLE_PUNCH(ItemID.PINEAPPLE_PUNCH, 8, 70),
SPICY_SAUCE(ItemID.SPICY_SAUCE, 9, 25),
MACKEREL(ItemID.MACKEREL, 10, 60),
@@ -57,104 +57,114 @@ public enum CookingAction implements ItemSkillAction
THIN_SNAIL_MEAT(ItemID.THIN_SNAIL_MEAT, 12, 70),
SPICY_CRUNCHIES(ItemID.SPICY_CRUNCHIES, 12, 100),
SCRAMBLED_EGG(ItemID.SCRAMBLED_EGG, 13, 50),
- CIDER(ItemID.CIDER, 14, 182),
WORM_CRUNCHIES(ItemID.WORM_CRUNCHIES, 14, 104),
+ CIDER(ItemID.CIDER, 14, 182),
TROUT(ItemID.TROUT, 15, 70),
- SPIDER_ON_STICK(ItemID.SPIDER_ON_STICK, 16, 80),
- SPIDER_ON_SHAFT(ItemID.SPIDER_ON_SHAFT, 16, 80),
ROAST_RABBIT(ItemID.ROAST_RABBIT, 16, 72.5f),
+ SPIDER_ON_SHAFT(ItemID.SPIDER_ON_SHAFT, 16, 80),
+ SPIDER_ON_STICK(ItemID.SPIDER_ON_STICK, 16, 80),
CHOCCHIP_CRUNCHIES(ItemID.CHOCCHIP_CRUNCHIES, 16, 100),
LEAN_SNAIL_MEAT(ItemID.LEAN_SNAIL_MEAT, 17, 80),
COD(ItemID.COD, 18, 75),
WIZARD_BLIZZARD(ItemID.WIZARD_BLIZZARD, 18, 110),
DWARVEN_STOUT(ItemID.DWARVEN_STOUT, 19, 215, true),
- SHORT_GREEN_GUY(ItemID.SHORT_GREEN_GUY, 20, 120),
- MEAT_PIE(ItemID.MEAT_PIE, 20, 110),
- PIKE(ItemID.PIKE, 20, 80),
- CUP_OF_TEA(ItemID.CUP_OF_TEA, 20, 52),
CAVEFISH(ItemID.CAVEFISH, 20, 23),
+ CUP_OF_TEA(ItemID.CUP_OF_TEA, 20, 52),
+ PIKE(ItemID.PIKE, 20, 80),
+ MEAT_PIE(ItemID.MEAT_PIE, 20, 110),
+ SHORT_GREEN_GUY(ItemID.SHORT_GREEN_GUY, 20, 120),
+ POT_OF_CREAM(ItemID.POT_OF_CREAM, 21, 18),
ROAST_BEAST_MEAT(ItemID.ROAST_BEAST_MEAT, 21, 82.5f),
COOKED_CRAB_MEAT(ItemID.COOKED_CRAB_MEAT, 21, 100),
- POT_OF_CREAM(ItemID.POT_OF_CREAM, 21, 18),
FAT_SNAIL_MEAT(ItemID.FAT_SNAIL_MEAT, 22, 95),
EGG_AND_TOMATO(ItemID.EGG_AND_TOMATO, 23, 50),
+ COOKED_WILD_KEBBIT(ItemID.COOKED_WILD_KEBBIT, 23, 73),
ASGARNIAN_ALE(ItemID.ASGARNIAN_ALE, 24, 248, true),
SALMON(ItemID.SALMON, 25, 90),
STEW(ItemID.STEW, 25, 117),
FRUIT_BATTA(ItemID.FRUIT_BATTA, 25, 150),
TOAD_BATTA(ItemID.TOAD_BATTA, 26, 152),
WORM_BATTA(ItemID.WORM_BATTA, 27, 154),
- VEGETABLE_BATTA(ItemID.VEGETABLE_BATTA, 28, 156),
- SWEETCORN(ItemID.COOKED_SWEETCORN, 28, 104),
COOKED_SLIMY_EEL(ItemID.COOKED_SLIMY_EEL, 28, 95),
+ SWEETCORN(ItemID.COOKED_SWEETCORN, 28, 104),
+ VEGETABLE_BATTA(ItemID.VEGETABLE_BATTA, 28, 156),
MUD_PIE(ItemID.MUD_PIE, 29, 128),
- GREENMANS_ALE(ItemID.GREENMANS_ALE, 29, 281),
CHEESE_AND_TOMATO_BATTA(ItemID.CHEESETOM_BATTA, 29, 158),
+ GREENMANS_ALE(ItemID.GREENMANS_ALE, 29, 281),
+ COOKED_BREAM(ItemID.COOKED_BREAM, 30, 45),
+ COOKED_MOSS_LIZARD(ItemID.COOKED_MOSS_LIZARD, 30, 60),
+ ROASTED_CHOMPY(ItemID.COOKED_CHOMPY, 30, 100),
TUNA(ItemID.TUNA, 30, 100),
APPLE_PIE(ItemID.APPLE_PIE, 30, 130),
WORM_HOLE(ItemID.WORM_HOLE, 30, 170),
COOKED_KARAMBWAN(ItemID.COOKED_KARAMBWAN, 30, 190),
- ROASTED_CHOMPY(ItemID.COOKED_CHOMPY, 30, 100),
+ COOKED_LARUPIA(ItemID.COOKED_LARUPIA, 31, 92),
FISHCAKE(ItemID.COOKED_FISHCAKE, 31, 100),
+ COOKED_BARBTAILED_KEBBIT(ItemID.COOKED_BARBTAILED_KEBBIT, 32, 106),
DRUNK_DRAGON(ItemID.DRUNK_DRAGON, 32, 160),
- CHOC_SATURDAY(ItemID.CHOC_SATURDAY, 33, 170),
TETRA(ItemID.TETRA, 33, 31),
+ CHOC_SATURDAY(ItemID.CHOC_SATURDAY, 33, 170),
GARDEN_PIE(ItemID.GARDEN_PIE, 34, 138),
WIZARDS_MIND_BOMB(ItemID.WIZARDS_MIND_BOMB, 34, 314, true),
- JUG_OF_WINE(ItemID.JUG_OF_WINE, 35, 200),
- PLAIN_PIZZA(ItemID.PLAIN_PIZZA, 35, 143),
RAINBOW_FISH(ItemID.RAINBOW_FISH, 35, 110),
+ PLAIN_PIZZA(ItemID.PLAIN_PIZZA, 35, 143),
VEG_BALL(ItemID.VEG_BALL, 35, 175),
+ JUG_OF_WINE(ItemID.JUG_OF_WINE, 35, 200),
BLURBERRY_SPECIAL(ItemID.BLURBERRY_SPECIAL, 37, 180),
- CAVE_EEL(ItemID.CAVE_EEL, 38, 115),
PAT_OF_BUTTER(ItemID.PAT_OF_BUTTER, 38, 40.5f),
- DRAGON_BITTER(ItemID.DRAGON_BITTER, 39, 347),
+ CAVE_EEL(ItemID.CAVE_EEL, 38, 115),
POTATO_WITH_BUTTER(ItemID.POTATO_WITH_BUTTER, 39, 40),
+ DRAGON_BITTER(ItemID.DRAGON_BITTER, 39, 347),
LOBSTER(ItemID.LOBSTER, 40, 120),
CAKE(ItemID.CAKE, 40, 180),
TANGLED_TOADS_LEGS(ItemID.TANGLED_TOADS_LEGS, 40, 185),
- CHILLI_POTATO(ItemID.CHILLI_POTATO, 41, 165.5f),
+ COOKED_GRAAHK(ItemID.COOKED_GRAAHK, 41, 124),
COOKED_JUBBLY(ItemID.COOKED_JUBBLY, 41, 160),
- CHOCOLATE_BOMB(ItemID.CHOCOLATE_BOMB, 42, 190),
+ CHILLI_POTATO(ItemID.CHILLI_POTATO, 41, 165.5f),
FRIED_ONIONS(ItemID.FRIED_ONIONS, 42, 60),
+ CHOCOLATE_BOMB(ItemID.CHOCOLATE_BOMB, 42, 190),
BASS(ItemID.BASS, 43, 130),
MOONLIGHT_MEAD(ItemID.MOONLIGHT_MEAD, 44, 380),
SWORDFISH(ItemID.SWORDFISH, 45, 140),
MEAT_PIZZA(ItemID.MEAT_PIZZA, 45, 169),
- FRIED_MUSHROOMS(ItemID.FRIED_MUSHROOMS, 46, 60),
CATFISH(ItemID.CATFISH, 46, 43),
- FISH_PIE(ItemID.FISH_PIE, 47, 164),
+ FRIED_MUSHROOMS(ItemID.FRIED_MUSHROOMS, 46, 60),
POTATO_WITH_CHEESE(ItemID.POTATO_WITH_CHEESE, 47, 40),
+ FISH_PIE(ItemID.FISH_PIE, 47, 164),
CHEESE(ItemID.CHEESE, 48, 64, true),
AXEMANS_FOLLY(ItemID.AXEMANS_FOLLY, 49, 413),
COOKED_OOMLIE_WRAP(ItemID.COOKED_OOMLIE_WRAP, 50, 30),
CHOCOLATE_CAKE(ItemID.CHOCOLATE_CAKE, 50, 210),
+ COOKED_KYATT(ItemID.COOKED_KYATT, 51, 143),
EGG_POTATO(ItemID.EGG_POTATO, 51, 195.5f),
BOTANICAL_PIE(ItemID.BOTANICAL_PIE, 52, 180),
LAVA_EEL(ItemID.LAVA_EEL, 53, 30),
CHEFS_DELIGHT(ItemID.CHEFS_DELIGHT, 54, 446),
ANCHOVY_PIZZA(ItemID.ANCHOVY_PIZZA, 55, 182),
MUSHROOM_AND_ONION(ItemID.MUSHROOM__ONION, 57, 120),
- UGTHANKI_KEBAB_FRESH(ItemID.UGTHANKI_KEBAB, 58, 80),
PITTA_BREAD(ItemID.PITTA_BREAD, 58, 40),
+ UGTHANKI_KEBAB_FRESH(ItemID.UGTHANKI_KEBAB, 58, 80),
SLAYERS_RESPITE(ItemID.SLAYERS_RESPITE, 59, 479),
- CURRY(ItemID.CURRY, 60, 280),
MUSHROOM_PIE(ItemID.MUSHROOM_PIE, 60, 200),
+ CURRY(ItemID.CURRY, 60, 280),
MONKFISH(ItemID.MONKFISH, 62, 150),
MUSHROOM_POTATO(ItemID.MUSHROOM_POTATO, 64, 270.5f),
PINEAPPLE_PIZZA(ItemID.PINEAPPLE_PIZZA, 65, 188),
WINE_OF_ZAMORAK(ItemID.WINE_OF_ZAMORAK, 65, 200, true),
TUNA_AND_CORN(ItemID.TUNA_AND_CORN, 67, 204),
+ COOKED_SUNLIGHT_ANTELOPE(ItemID.COOKED_SUNLIGHT_ANTELOPE, 68, 175),
TUNA_POTATO(ItemID.TUNA_POTATO, 68, 309.5f),
ADMIRAL_PIE(ItemID.ADMIRAL_PIE, 70, 210),
SACRED_EEL(ItemID.SACRED_EEL, 72, 109),
DRAGONFRUIT_PIE(ItemID.DRAGONFRUIT_PIE, 73, 220),
SHARK(ItemID.SHARK, 80, 210),
SEA_TURTLE(ItemID.SEA_TURTLE, 82, 211.3f),
+ COOKED_DASHING_KEBBIT(ItemID.COOKED_DASHING_KEBBIT, 82, 215),
ANGLERFISH(ItemID.ANGLERFISH, 84, 230),
WILD_PIE(ItemID.WILD_PIE, 85, 240),
DARK_CRAB(ItemID.DARK_CRAB, 90, 215),
MANTA_RAY(ItemID.MANTA_RAY, 91, 216.3f),
+ COOKED_MOONLIGHT_ANTELOPE(ItemID.COOKED_MOONLIGHT_ANTELOPE, 92, 220),
SUMMER_PIE(ItemID.SUMMER_PIE, 95, 260),
;
diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/skillcalculator/skills/CraftingAction.java b/runelite-client/src/main/java/net/runelite/client/plugins/skillcalculator/skills/CraftingAction.java
index 5f3618468e..9806fa02e9 100644
--- a/runelite-client/src/main/java/net/runelite/client/plugins/skillcalculator/skills/CraftingAction.java
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/skillcalculator/skills/CraftingAction.java
@@ -34,27 +34,27 @@
public enum CraftingAction implements ItemSkillAction
{
BALL_OF_WOOL(ItemID.BALL_OF_WOOL, 1, 2.5f),
- UNFIRED_POT(ItemID.UNFIRED_POT, 1, 6.3f),
POT(ItemID.POT, 1, 6.3f),
+ UNFIRED_POT(ItemID.UNFIRED_POT, 1, 6.3f),
+ OPAL_RING(ItemID.OPAL_RING, 1, 10),
LEATHER_GLOVES(ItemID.LEATHER_GLOVES, 1, 13.8f),
OPAL(ItemID.OPAL, 1, 15),
- OPAL_RING(ItemID.OPAL_RING, 1, 10),
- MOLTEN_GLASS(ItemID.MOLTEN_GLASS, 1, 20),
BEER_GLASS(ItemID.BEER_GLASS, 1, 17.5f, true),
+ MOLTEN_GLASS(ItemID.MOLTEN_GLASS, 1, 20),
EMPTY_CANDLE_LANTERN(ItemID.EMPTY_CANDLE_LANTERN, 4, 19),
- GOLD_RING(ItemID.GOLD_RING, 5, 15),
BIRD_HOUSE(ItemID.BIRD_HOUSE, 5, 15),
+ GOLD_RING(ItemID.GOLD_RING, 5, 15),
GOLD_NECKLACE(ItemID.GOLD_NECKLACE, 6, 20),
- LEATHER_BOOTS(ItemID.LEATHER_BOOTS, 7, 16.3f),
- UNFIRED_PIE_DISH(ItemID.UNFIRED_PIE_DISH, 7, 15),
PIE_DISH(ItemID.PIE_DISH, 7, 10),
+ UNFIRED_PIE_DISH(ItemID.UNFIRED_PIE_DISH, 7, 15),
+ LEATHER_BOOTS(ItemID.LEATHER_BOOTS, 7, 16.3f),
GOLD_BRACELET(ItemID.GOLD_BRACELET_11069, 7, 25),
- UNFIRED_BOWL(ItemID.UNFIRED_BOWL, 8, 18),
BOWL(ItemID.BOWL, 8, 15),
+ UNFIRED_BOWL(ItemID.UNFIRED_BOWL, 8, 18),
GOLD_AMULET_U(ItemID.GOLD_AMULET_U, 8, 30),
COWL(ItemID.LEATHER_COWL, 9, 18.5f),
- CROSSBOW_STRING(ItemID.CROSSBOW_STRING, 10, 15),
BOW_STRING(ItemID.BOW_STRING, 10, 15),
+ CROSSBOW_STRING(ItemID.CROSSBOW_STRING, 10, 15),
LEATHER_VAMBRACES(ItemID.LEATHER_VAMBRACES, 11, 22),
EMPTY_OIL_LAMP(ItemID.EMPTY_OIL_LAMP, 12, 25),
JADE(ItemID.JADE, 13, 20),
@@ -62,79 +62,79 @@ public enum CraftingAction implements ItemSkillAction
LEATHER_BODY(ItemID.LEATHER_BODY, 14, 25),
OAK_BIRD_HOUSE(ItemID.OAK_BIRD_HOUSE, 15, 20),
RED_TOPAZ(ItemID.RED_TOPAZ, 16, 25),
+ OPAL_NECKLACE(ItemID.OPAL_NECKLACE, 16, 35),
TOPAZ_RING(ItemID.TOPAZ_RING, 16, 35),
HOLY_SYMBOL(ItemID.HOLY_SYMBOL, 16, 50),
- OPAL_NECKLACE(ItemID.OPAL_NECKLACE, 16, 35),
UNHOLY_SYMBOL(ItemID.UNHOLY_SYMBOL, 17, 50),
LEATHER_CHAPS(ItemID.LEATHER_CHAPS, 18, 27),
- UNFIRED_PLANT_POT(ItemID.UNFIRED_PLANT_POT, 19, 20),
EMPTY_PLANT_POT(ItemID.EMPTY_PLANT_POT, 19, 17.5f),
+ UNFIRED_PLANT_POT(ItemID.UNFIRED_PLANT_POT, 19, 20),
MAGIC_STRING(ItemID.MAGIC_STRING, 19, 30),
- SAPPHIRE(ItemID.SAPPHIRE, 20, 50),
SAPPHIRE_RING(ItemID.SAPPHIRE_RING, 20, 40),
+ SAPPHIRE(ItemID.SAPPHIRE, 20, 50),
EMPTY_SACK(ItemID.EMPTY_SACK, 21, 38),
- SAPPHIRE_NECKLACE(ItemID.SAPPHIRE_NECKLACE, 22, 55),
OPAL_BRACELET(ItemID.OPAL_BRACELET, 22, 45),
- SAPPHIRE_BRACELET(ItemID.SAPPHIRE_BRACELET_11072, 23, 60),
+ SAPPHIRE_NECKLACE(ItemID.SAPPHIRE_NECKLACE, 22, 55),
TIARA(ItemID.TIARA, 23, 52.5f),
+ SAPPHIRE_BRACELET(ItemID.SAPPHIRE_BRACELET_11072, 23, 60),
SAPPHIRE_AMULET_U(ItemID.SAPPHIRE_AMULET_U, 24, 65),
- UNFIRED_POT_LID(ItemID.UNFIRED_POT_LID, 25, 20),
POT_LID(ItemID.POT_LID, 25, 20),
- JADE_NECKLACE(ItemID.JADE_NECKLACE, 25, 54),
+ UNFIRED_POT_LID(ItemID.UNFIRED_POT_LID, 25, 20),
WILLOW_BIRD_HOUSE(ItemID.WILLOW_BIRD_HOUSE, 25, 25),
+ JADE_NECKLACE(ItemID.JADE_NECKLACE, 25, 54),
DRIFT_NET(ItemID.DRIFT_NET, 26, 55),
- EMERALD(ItemID.EMERALD, 27, 67.5f),
EMERALD_RING(ItemID.EMERALD_RING, 27, 55),
OPAL_AMULET_U(ItemID.OPAL_AMULET_U, 27, 55),
+ EMERALD(ItemID.EMERALD, 27, 67.5f),
HARDLEATHER_BODY(ItemID.HARDLEATHER_BODY, 28, 35),
EMERALD_NECKLACE(ItemID.EMERALD_NECKLACE, 29, 60),
JADE_BRACELET(ItemID.JADE_BRACELET, 29, 60),
- EMERALD_BRACELET(ItemID.EMERALD_BRACELET, 30, 65),
ROPE(ItemID.ROPE, 30, 25, true),
+ EMERALD_BRACELET(ItemID.EMERALD_BRACELET, 30, 65),
EMERALD_AMULET_U(ItemID.EMERALD_AMULET_U, 31, 70),
SPIKY_VAMBRACES(ItemID.SPIKY_VAMBRACES, 32, 6),
TOPAZ_NECKLACE(ItemID.TOPAZ_NECKLACE, 32, 70),
VIAL(ItemID.VIAL, 33, 35, true),
- RUBY(ItemID.RUBY, 34, 85),
- RUBY_RING(ItemID.RUBY_RING, 34, 70),
JADE_AMULET_U(ItemID.JADE_AMULET_U, 34, 70),
- BROODOO_SHIELD(ItemID.BROODOO_SHIELD, 35, 100),
+ RUBY_RING(ItemID.RUBY_RING, 34, 70),
+ RUBY(ItemID.RUBY, 34, 85),
TEAK_BIRD_HOUSE(ItemID.TEAK_BIRD_HOUSE, 35, 30),
+ BROODOO_SHIELD(ItemID.BROODOO_SHIELD, 35, 100),
BASKET(ItemID.BASKET, 36, 56),
COIF(ItemID.COIF, 38, 37, true),
TOPAZ_BRACELET(ItemID.TOPAZ_BRACELET, 38, 75),
RUBY_NECKLACE(ItemID.RUBY_NECKLACE, 40, 75),
HARD_LEATHER_SHIELD(ItemID.HARD_LEATHER_SHIELD, 41, 70),
- RUBY_BRACELET(ItemID.RUBY_BRACELET, 42, 80),
FISHBOWL(ItemID.FISHBOWL, 42, 42.5f),
- DIAMOND(ItemID.DIAMOND, 43, 107.5f),
+ RUBY_BRACELET(ItemID.RUBY_BRACELET, 42, 80),
DIAMOND_RING(ItemID.DIAMOND_RING, 43, 85),
- TOPAZ_AMULET_U(ItemID.TOPAZ_AMULET_U, 45, 80),
+ DIAMOND(ItemID.DIAMOND, 43, 107.5f),
SNAKESKIN_BOOTS(ItemID.SNAKESKIN_BOOTS, 45, 30),
MAPLE_BIRD_HOUSE(ItemID.MAPLE_BIRD_HOUSE, 45, 35),
+ TOPAZ_AMULET_U(ItemID.TOPAZ_AMULET_U, 45, 80),
UNPOWERED_ORB(ItemID.UNPOWERED_ORB, 46, 52.5f),
SNAKESKIN_VAMBRACES(ItemID.SNAKESKIN_VAMBRACES, 47, 35),
SNAKESKIN_BANDANA(ItemID.SNAKESKIN_BANDANA, 48, 45),
LANTERN_LENS(ItemID.LANTERN_LENS, 49, 55),
- RUBY_AMULET_U(ItemID.RUBY_AMULET_U, 50, 85),
MAHOGANY_BIRD_HOUSE(ItemID.MAHOGANY_BIRD_HOUSE, 50, 40),
+ RUBY_AMULET_U(ItemID.RUBY_AMULET_U, 50, 85),
SNAKESKIN_CHAPS(ItemID.SNAKESKIN_CHAPS, 51, 50),
SNAKESKIN_BODY(ItemID.SNAKESKIN_BODY, 53, 55),
WATER_BATTLESTAFF(ItemID.WATER_BATTLESTAFF, 54, 100),
- DRAGONSTONE(ItemID.DRAGONSTONE, 55, 137.5f),
DRAGONSTONE_RING(ItemID.DRAGONSTONE_RING, 55, 100),
+ DRAGONSTONE(ItemID.DRAGONSTONE, 55, 137.5f),
DIAMOND_NECKLACE(ItemID.DIAMOND_NECKLACE, 56, 90),
SNAKESKIN_SHIELD(ItemID.SNAKESKIN_SHIELD, 56, 100),
GREEN_DHIDE_VAMB(ItemID.GREEN_DHIDE_VAMBRACES, 57, 62, true),
DIAMOND_BRACELET(ItemID.DIAMOND_BRACELET, 58, 95),
EARTH_BATTLESTAFF(ItemID.EARTH_BATTLESTAFF, 58, 112.5f),
- GREEN_DHIDE_CHAPS(ItemID.GREEN_DHIDE_CHAPS, 60, 124, true),
YEW_BIRD_HOUSE(ItemID.YEW_BIRD_HOUSE, 60, 45),
- FIRE_BATTLESTAFF(ItemID.FIRE_BATTLESTAFF, 62, 125),
+ GREEN_DHIDE_CHAPS(ItemID.GREEN_DHIDE_CHAPS, 60, 124, true),
GREEN_DHIDE_SHIELD(ItemID.GREEN_DHIDE_SHIELD, 62, 124),
+ FIRE_BATTLESTAFF(ItemID.FIRE_BATTLESTAFF, 62, 125),
GREEN_DHIDE_BODY(ItemID.GREEN_DHIDE_BODY, 63, 186, true),
- AIR_BATTLESTAFF(ItemID.AIR_BATTLESTAFF, 66, 137.5f),
BLUE_DHIDE_VAMB(ItemID.BLUE_DHIDE_VAMBRACES, 66, 70),
+ AIR_BATTLESTAFF(ItemID.AIR_BATTLESTAFF, 66, 137.5f),
ONYX_RING(ItemID.ONYX_RING, 67, 115),
ONYX(ItemID.ONYX, 67, 167.5f),
BLUE_DHIDE_CHAPS(ItemID.BLUE_DHIDE_CHAPS, 68, 140),
@@ -144,26 +144,26 @@ public enum CraftingAction implements ItemSkillAction
DRAGONSTONE_NECKLACE(ItemID.DRAGON_NECKLACE, 72, 105),
RED_DHIDE_VAMB(ItemID.RED_DHIDE_VAMBRACES, 73, 78),
DRAGONSTONE_BRACELET(ItemID.DRAGONSTONE_BRACELET, 74, 110),
- RED_DHIDE_CHAPS(ItemID.RED_DHIDE_CHAPS, 75, 156),
MAGIC_BIRD_HOUSE(ItemID.MAGIC_BIRD_HOUSE, 75, 50),
+ RED_DHIDE_CHAPS(ItemID.RED_DHIDE_CHAPS, 75, 156),
RED_DHIDE_SHIELD(ItemID.RED_DHIDE_SHIELD, 76, 156),
RED_DHIDE_BODY(ItemID.RED_DHIDE_BODY, 77, 234),
BLACK_DHIDE_VAMB(ItemID.BLACK_DHIDE_VAMBRACES, 79, 86),
DRAGONSTONE_AMULET_U(ItemID.DRAGONSTONE_AMULET_U, 80, 150),
- BLACK_DHIDE_CHAPS(ItemID.BLACK_DHIDE_CHAPS, 82, 172),
ONYX_NECKLACE(ItemID.ONYX_NECKLACE, 82, 120),
+ BLACK_DHIDE_CHAPS(ItemID.BLACK_DHIDE_CHAPS, 82, 172),
AMETHYST_BOLT_TIPS(ItemID.AMETHYST_BOLT_TIPS, 83, 4),
BLACK_DHIDE_SHIELD(ItemID.BLACK_DHIDE_SHIELD, 83, 172),
- BLACK_DHIDE_BODY(ItemID.BLACK_DHIDE_BODY, 84, 258),
ONYX_BRACELET(ItemID.ONYX_BRACELET, 84, 125),
+ BLACK_DHIDE_BODY(ItemID.BLACK_DHIDE_BODY, 84, 258),
AMETHYST_ARROWTIPS(ItemID.AMETHYST_ARROWTIPS, 85, 4),
AMETHYST_JAVELIN_HEADS(ItemID.AMETHYST_JAVELIN_HEADS, 87, 12),
LIGHT_ORB(ItemID.LIGHT_ORB, 87, 70),
AMETHYST_DART_TIP(ItemID.AMETHYST_DART_TIP, 89, 7.5f),
- ZENYTE(ItemID.ZENYTE, 89, 200),
ZENYTE_RING(ItemID.ZENYTE_RING, 89, 150),
- ONYX_AMULET_U(ItemID.ONYX_AMULET_U, 90, 165),
+ ZENYTE(ItemID.ZENYTE, 89, 200),
REDWOOD_BIRD_HOUSE(ItemID.REDWOOD_BIRD_HOUSE, 90, 55),
+ ONYX_AMULET_U(ItemID.ONYX_AMULET_U, 90, 165),
ZENYTE_NECKLACE(ItemID.ZENYTE_NECKLACE, 92, 165),
ZENYTE_BRACELET(ItemID.ZENYTE_BRACELET_19532, 95, 180),
ZENYTE_AMULET_U(ItemID.ZENYTE_AMULET_U, 98, 200),
diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/skillcalculator/skills/FarmingAction.java b/runelite-client/src/main/java/net/runelite/client/plugins/skillcalculator/skills/FarmingAction.java
index 2ce70b1cce..24ff6014a8 100644
--- a/runelite-client/src/main/java/net/runelite/client/plugins/skillcalculator/skills/FarmingAction.java
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/skillcalculator/skills/FarmingAction.java
@@ -34,23 +34,23 @@
@Getter
public enum FarmingAction implements NamedSkillAction
{
- PLANT("Plant", 1, 31, ItemID.PLANT),
+ POTATOES("Potatoes", 1, 8, ItemID.POTATO),
+ WINTER_SQIRK("Winter Sq'irk", 1, 30, ItemID.WINTER_SQIRK),
+ DOCK_LEAF("Dock Leaf", 1, 31, ItemID.DOCK_LEAF),
FERN_BIG_PLANT("Fern (big plant)", 1, 31, ItemID.FERN_8186),
+ PLANT("Plant", 1, 31, ItemID.PLANT),
SHORT_PLANT("Short Plant", 1, 31, ItemID.SHORT_PLANT),
- DOCK_LEAF("Dock Leaf", 1, 31, ItemID.DOCK_LEAF),
- SMALL_FERN("Small Fern", 1, 70, ItemID.SMALL_FERN),
- THISTLE("Thistle", 1, 70, ItemID.THISTLE),
+ SPRING_SQIRK("Spring Sq'irk", 1, 40, ItemID.SPRING_SQIRK),
+ AUTUMN_SQIRK("Autumn Sq'irk", 1, 50, ItemID.AUTUMN_SQIRK),
+ SUMMER_SQIRK("Summer Sq'irk", 1, 60, ItemID.SUMMER_SQIRK),
BUSH("Bush", 1, 70, ItemID.BUSH),
LARGE_LEAF_BUSH("Large Leaf Bush", 1, 70, ItemID.LARGELEAF_PLANT),
+ SMALL_FERN("Small Fern", 1, 70, ItemID.SMALL_FERN),
+ THISTLE("Thistle", 1, 70, ItemID.THISTLE),
+ FERN_SMALL_PLANT("Fern (small plant)", 1, 100, ItemID.FERN),
HUGE_PLANT("Huge Plant", 1, 100, ItemID.HUGE_PLANT),
- TALL_PLANT("Tall Plant", 1, 100, ItemID.TALL_PLANT),
REEDS("Reeds", 1, 100, ItemID.REEDS),
- FERN_SMALL_PLANT("Fern (small plant)", 1, 100, ItemID.FERN),
- WINTER_SQIRK("Winter Sq'irk", 1, 30, ItemID.WINTER_SQIRK),
- SPRING_SQIRK("Spring Sq'irk", 1, 40, ItemID.SPRING_SQIRK),
- AUTUMN_SQIRK("Autumn Sq'irk", 1, 50, ItemID.AUTUMN_SQIRK),
- SUMMER_SQIRK("Summer Sq'irk", 1, 60, ItemID.SUMMER_SQIRK),
- POTATOES("Potatoes", 1, 8, ItemID.POTATO),
+ TALL_PLANT("Tall Plant", 1, 100, ItemID.TALL_PLANT),
ONIONS("Onions", 5, 10, ItemID.ONION),
CABBAGES("Cabbages", 7, 10, ItemID.CABBAGE),
GUAM_LEAF("Guam Leaf", 9, 11, ItemID.GUAM_LEAF),
@@ -94,8 +94,8 @@ public enum FarmingAction implements NamedSkillAction
DWARF_WEED("Dwarf Weed", 79, 170.5f, ItemID.DWARF_WEED),
DRAGONFRUIT_TREE("Dragonfruit Tree", 81, 17895, ItemID.DRAGONFRUIT),
SPIRIT_TREE("Spirit Tree", 83, 19501.3f, ItemID.SPIRIT_TREE),
- CELASTRUS_TREE("Celastrus Tree", 85, 14334, ItemID.CELASTRUS_BARK),
TORSTOL("Torstol", 85, 199.5f, ItemID.TORSTOL),
+ CELASTRUS_TREE("Celastrus Tree", 85, 14334, ItemID.CELASTRUS_BARK),
REDWOOD_TREE("Redwood Tree", 90, 22680, ItemID.REDWOOD_LOGS),
;
diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/skillcalculator/skills/FarmingBonus.java b/runelite-client/src/main/java/net/runelite/client/plugins/skillcalculator/skills/FarmingBonus.java
index 7328772073..e29ae4fa40 100644
--- a/runelite-client/src/main/java/net/runelite/client/plugins/skillcalculator/skills/FarmingBonus.java
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/skillcalculator/skills/FarmingBonus.java
@@ -31,7 +31,7 @@
@Getter(onMethod_ = @Override)
public enum FarmingBonus implements SkillBonus
{
- FARMERS_OUTFIT("Farmer's Outfit (+2.5%)", 1.025f),
+ FARMERS_OUTFIT("Farmer's Outfit", 1.025f),
;
private final String name;
diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/skillcalculator/skills/FiremakingAction.java b/runelite-client/src/main/java/net/runelite/client/plugins/skillcalculator/skills/FiremakingAction.java
index 424fb851a8..f75baa737f 100644
--- a/runelite-client/src/main/java/net/runelite/client/plugins/skillcalculator/skills/FiremakingAction.java
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/skillcalculator/skills/FiremakingAction.java
@@ -32,8 +32,8 @@
@Getter
public enum FiremakingAction implements ItemSkillAction
{
- LOGS(ItemID.LOGS, 1, 40),
ACHEY_TREE_LOGS(ItemID.ACHEY_TREE_LOGS, 1, 40),
+ LOGS(ItemID.LOGS, 1, 40),
OAK_LOGS(ItemID.OAK_LOGS, 15, 60),
WILLOW_LOGS(ItemID.WILLOW_LOGS, 30, 90),
TEAK_LOGS(ItemID.TEAK_LOGS, 35, 105),
diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/skillcalculator/skills/FiremakingBonus.java b/runelite-client/src/main/java/net/runelite/client/plugins/skillcalculator/skills/FiremakingBonus.java
index 4483b65309..b20f6fca8b 100644
--- a/runelite-client/src/main/java/net/runelite/client/plugins/skillcalculator/skills/FiremakingBonus.java
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/skillcalculator/skills/FiremakingBonus.java
@@ -24,6 +24,8 @@
*/
package net.runelite.client.plugins.skillcalculator.skills;
+import java.util.EnumSet;
+import java.util.Set;
import lombok.AllArgsConstructor;
import lombok.Getter;
@@ -31,9 +33,18 @@
@Getter(onMethod_ = @Override)
public enum FiremakingBonus implements SkillBonus
{
- PYROMANCER_OUTFIT("Pyromancer Outfit (+2.5%)", 1.025f),
+ PYROMANCER_OUTFIT("Pyromancer Outfit", 1.025f),
+ FORESTERS_CAMPFIRE("Forester's Campfire", 0.33333333f),
;
private final String name;
private final float value;
+
+ @Override
+ public Set getCanBeStackedWith()
+ {
+ final EnumSet others = EnumSet.allOf(FiremakingBonus.class);
+ others.remove(this);
+ return others;
+ }
}
diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/skillcalculator/skills/FishingAction.java b/runelite-client/src/main/java/net/runelite/client/plugins/skillcalculator/skills/FishingAction.java
index 386ec964c8..ba20354c81 100644
--- a/runelite-client/src/main/java/net/runelite/client/plugins/skillcalculator/skills/FishingAction.java
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/skillcalculator/skills/FishingAction.java
@@ -33,25 +33,26 @@
public enum FishingAction implements ItemSkillAction
{
RAW_SHRIMPS(ItemID.RAW_SHRIMPS, 1, 10),
- RAW_SARDINE(ItemID.RAW_SARDINE, 5, 20),
RAW_KARAMBWANJI(ItemID.RAW_KARAMBWANJI, 5, 5),
+ RAW_SARDINE(ItemID.RAW_SARDINE, 5, 20),
RAW_GUPPY(ItemID.RAW_GUPPY, 7, 8),
RAW_HERRING(ItemID.RAW_HERRING, 10, 30),
RAW_ANCHOVIES(ItemID.RAW_ANCHOVIES, 15, 40),
RAW_MACKEREL(ItemID.RAW_MACKEREL, 16, 20),
- RAW_TROUT(ItemID.RAW_TROUT, 20, 50),
RAW_CAVEFISH(ItemID.RAW_CAVEFISH, 20, 16),
+ RAW_BREAM(ItemID.RAW_BREAM, 20, 20),
+ RAW_TROUT(ItemID.RAW_TROUT, 20, 50),
RAW_COD(ItemID.RAW_COD, 23, 45),
RAW_PIKE(ItemID.RAW_PIKE, 25, 60),
RAW_SLIMY_EEL(ItemID.RAW_SLIMY_EEL, 28, 80),
RAW_SALMON(ItemID.RAW_SALMON, 30, 70),
RAW_TETRA(ItemID.RAW_TETRA, 33, 24),
RAW_TUNA(ItemID.RAW_TUNA, 35, 80),
- RAW_RAINBOW_FISH(ItemID.RAW_RAINBOW_FISH, 38, 80),
RAW_CAVE_EEL(ItemID.RAW_CAVE_EEL, 38, 80),
+ RAW_RAINBOW_FISH(ItemID.RAW_RAINBOW_FISH, 38, 80),
RAW_LOBSTER(ItemID.RAW_LOBSTER, 40, 90),
- RAW_BASS(ItemID.RAW_BASS, 46, 100),
RAW_CATFISH(ItemID.RAW_CATFISH, 46, 33),
+ RAW_BASS(ItemID.RAW_BASS, 46, 100),
LEAPING_TROUT(ItemID.LEAPING_TROUT, 48, 50),
RAW_SWORDFISH(ItemID.RAW_SWORDFISH, 50, 100),
LEAPING_SALMON(ItemID.LEAPING_SALMON, 58, 70),
@@ -62,8 +63,8 @@ public enum FishingAction implements ItemSkillAction
RAW_SEA_TURTLE(ItemID.RAW_SEA_TURTLE, 79, 38),
INFERNAL_EEL(ItemID.INFERNAL_EEL, 80, 95),
RAW_MANTA_RAY(ItemID.RAW_MANTA_RAY, 81, 46),
- RAW_ANGLERFISH(ItemID.RAW_ANGLERFISH, 82, 120),
MINNOW(ItemID.MINNOW, 82, 26.5f),
+ RAW_ANGLERFISH(ItemID.RAW_ANGLERFISH, 82, 120),
RAW_DARK_CRAB(ItemID.RAW_DARK_CRAB, 85, 130),
SACRED_EEL(ItemID.SACRED_EEL, 87, 105),
;
diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/skillcalculator/skills/FishingBonus.java b/runelite-client/src/main/java/net/runelite/client/plugins/skillcalculator/skills/FishingBonus.java
index 832e7ff44f..b3b7567223 100644
--- a/runelite-client/src/main/java/net/runelite/client/plugins/skillcalculator/skills/FishingBonus.java
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/skillcalculator/skills/FishingBonus.java
@@ -31,7 +31,7 @@
@Getter(onMethod_ = @Override)
public enum FishingBonus implements SkillBonus
{
- ANGLERS_OUTFIT("Angler's Outfit (+2.5%)", 1.025f),
+ ANGLERS_OUTFIT("Angler's Outfit", 1.025f),
;
private final String name;
diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/skillcalculator/skills/FletchingAction.java b/runelite-client/src/main/java/net/runelite/client/plugins/skillcalculator/skills/FletchingAction.java
index 2e8726ee55..f30e06e7df 100644
--- a/runelite-client/src/main/java/net/runelite/client/plugins/skillcalculator/skills/FletchingAction.java
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/skillcalculator/skills/FletchingAction.java
@@ -38,81 +38,82 @@ public enum FletchingAction implements ItemSkillAction
BRONZE_ARROW(ItemID.BRONZE_ARROW, 1, 1.3f),
BRONZE_JAVELIN(ItemID.BRONZE_JAVELIN, 3, 1),
OGRE_ARROW(ItemID.OGRE_ARROW, 5, 1),
- SHORTBOW_U(ItemID.SHORTBOW_U, 5, 5),
SHORTBOW(ItemID.SHORTBOW, 5, 5),
+ SHORTBOW_U(ItemID.SHORTBOW_U, 5, 5),
BRONZE_BOLTS(ItemID.BRONZE_BOLTS, 9, 0.5f),
+ BRONZE_CROSSBOW(ItemID.BRONZE_CROSSBOW, 9, 6),
WOODEN_STOCK(ItemID.WOODEN_STOCK, 9, 6),
BRONZE_CROSSBOW_U(ItemID.BRONZE_CROSSBOW_U, 9, 12),
- BRONZE_CROSSBOW(ItemID.BRONZE_CROSSBOW, 9, 6),
BRONZE_DART(ItemID.BRONZE_DART, 10, 1.8f),
LONGBOW(ItemID.LONGBOW, 10, 10),
LONGBOW_U(ItemID.LONGBOW_U, 10, 10),
OPAL_BOLTS(ItemID.OPAL_BOLTS, 11, 1.6f),
IRON_ARROW(ItemID.IRON_ARROW, 15, 2.5f),
IRON_JAVELIN(ItemID.IRON_JAVELIN, 17, 2),
- OAK_SHORTBOW_U(ItemID.OAK_SHORTBOW_U, 20, 16.5f),
OAK_SHORTBOW(ItemID.OAK_SHORTBOW, 20, 16.5f),
+ OAK_SHORTBOW_U(ItemID.OAK_SHORTBOW_U, 20, 16.5f),
IRON_DART(ItemID.IRON_DART, 22, 3.8f),
+ BLURITE_CROSSBOW(ItemID.BLURITE_CROSSBOW, 24, 16),
OAK_STOCK(ItemID.OAK_STOCK, 24, 16),
BLURITE_CROSSBOW_U(ItemID.BLURITE_CROSSBOW_U, 24, 32),
- BLURITE_CROSSBOW(ItemID.BLURITE_CROSSBOW, 24, 16),
- OAK_LONGBOW_U(ItemID.OAK_LONGBOW_U, 25, 25),
OAK_LONGBOW(ItemID.OAK_LONGBOW, 25, 25),
+ OAK_LONGBOW_U(ItemID.OAK_LONGBOW_U, 25, 25),
OAK_SHIELD(ItemID.OAK_SHIELD, 27, 50),
STEEL_ARROW(ItemID.STEEL_ARROW, 30, 5),
- STEEL_JAVELIN(ItemID.STEEL_JAVELIN, 32, 5),
KEBBIT_BOLTS(ItemID.KEBBIT_BOLTS, 32, 1),
- WILLOW_SHORTBOW_U(ItemID.WILLOW_SHORTBOW_U, 35, 33.3f),
+ STEEL_JAVELIN(ItemID.STEEL_JAVELIN, 32, 5),
WILLOW_SHORTBOW(ItemID.WILLOW_SHORTBOW, 35, 33.3f),
+ WILLOW_SHORTBOW_U(ItemID.WILLOW_SHORTBOW_U, 35, 33.3f),
STEEL_DART(ItemID.STEEL_DART, 37, 7.5f),
IRON_BOLTS(ItemID.IRON_BOLTS, 39, 1.5f),
+ IRON_CROSSBOW(ItemID.IRON_CROSSBOW, 39, 22),
WILLOW_STOCK(ItemID.WILLOW_STOCK, 39, 22),
IRON_CROSSBOW_U(ItemID.IRON_CROSSBOW_U, 39, 44),
- IRON_CROSSBOW(ItemID.IRON_CROSSBOW, 39, 22),
- WILLOW_LONGBOW_U(ItemID.WILLOW_LONGBOW_U, 40, 41.5f),
WILLOW_LONGBOW(ItemID.WILLOW_LONGBOW, 40, 41.5f),
+ WILLOW_LONGBOW_U(ItemID.WILLOW_LONGBOW_U, 40, 41.5f),
BATTLESTAFF(ItemID.BATTLESTAFF, 40, 80),
PEARL_BOLTS(ItemID.PEARL_BOLTS, 41, 3.2f),
- WILLOW_SHIELD(ItemID.WILLOW_SHIELD, 42, 83),
LONG_KEBBIT_BOLTS(ItemID.LONG_KEBBIT_BOLTS, 42, 1.3f),
+ WILLOW_SHIELD(ItemID.WILLOW_SHIELD, 42, 83),
SILVER_BOLTS(ItemID.SILVER_BOLTS, 43, 2.5f),
MITHRIL_ARROW(ItemID.MITHRIL_ARROW, 45, 7.5f),
STEEL_BOLTS(ItemID.STEEL_BOLTS, 46, 3.5f),
+ STEEL_CROSSBOW(ItemID.STEEL_CROSSBOW, 46, 27),
TEAK_STOCK(ItemID.TEAK_STOCK, 46, 27),
STEEL_CROSSBOW_U(ItemID.STEEL_CROSSBOW_U, 46, 54),
- STEEL_CROSSBOW(ItemID.STEEL_CROSSBOW, 46, 27),
MITHRIL_JAVELIN(ItemID.MITHRIL_JAVELIN, 47, 8),
- MAPLE_SHORTBOW_U(ItemID.MAPLE_SHORTBOW_U, 50, 50),
MAPLE_SHORTBOW(ItemID.MAPLE_SHORTBOW, 50, 50),
+ MAPLE_SHORTBOW_U(ItemID.MAPLE_SHORTBOW_U, 50, 50),
BARBED_BOLTS(ItemID.BARBED_BOLTS, 51, 9.5f),
- MITHRIL_DART(ItemID.MITHRIL_DART, 52, 11.2f),
BROAD_ARROWS(ItemID.BROAD_ARROWS, 52, 10),
+ MITHRIL_DART(ItemID.MITHRIL_DART, 52, 11.2f),
TOXIC_BLOWPIPE(ItemID.TOXIC_BLOWPIPE, 53, 120),
- MITH_CROSSBOW(ItemID.MITHRIL_CROSSBOW, 54, 32),
- MAPLE_STOCK(ItemID.MAPLE_STOCK, 54, 32),
MITHRIL_BOLTS(ItemID.MITHRIL_BOLTS, 54, 5),
+ MAPLE_STOCK(ItemID.MAPLE_STOCK, 54, 32),
+ MITHRIL_CROSSBOW(ItemID.MITHRIL_CROSSBOW, 54, 32),
MITHRIL_CROSSBOW_U(ItemID.MITHRIL_CROSSBOW_U, 54, 64),
- MAPLE_LONGBOW_U(ItemID.MAPLE_LONGBOW_U, 55, 58.3f),
BROAD_BOLTS(ItemID.BROAD_BOLTS, 55, 3),
- MAPLE_LONGBOW(ItemID.MAPLE_LONGBOW, 55, 58),
+ MAPLE_LONGBOW(ItemID.MAPLE_LONGBOW, 55, 58.2f),
+ MAPLE_LONGBOW_U(ItemID.MAPLE_LONGBOW_U, 55, 58.3f),
SAPPHIRE_BOLTS(ItemID.SAPPHIRE_BOLTS, 56, 4.7f),
MAPLE_SHIELD(ItemID.MAPLE_SHIELD, 57, 116.5f),
EMERALD_BOLTS(ItemID.EMERALD_BOLTS, 58, 5.5f),
+ HUNTERS_SPEAR(ItemID.HUNTERS_SPEAR, 60, 9.5f),
ADAMANT_ARROW(ItemID.ADAMANT_ARROW, 60, 10),
ADAMANT_BOLTS(ItemID.ADAMANT_BOLTS, 61, 7),
+ ADAMANT_CROSSBOW(ItemID.ADAMANT_CROSSBOW, 61, 41),
MAHOGANY_STOCK(ItemID.MAHOGANY_STOCK, 61, 41),
ADAMANT_CROSSBOW_U(ItemID.ADAMANT_CROSSBOW_U, 61, 82),
- ADAMANT_CROSSBOW(ItemID.ADAMANT_CROSSBOW, 61, 41),
ADAMANT_JAVELIN(ItemID.ADAMANT_JAVELIN, 62, 10),
RUBY_BOLTS(ItemID.RUBY_BOLTS, 63, 6.3f),
DIAMOND_BOLTS(ItemID.DIAMOND_BOLTS, 65, 7),
YEW_SHORTBOW(ItemID.YEW_SHORTBOW, 65, 67.5f),
YEW_SHORTBOW_U(ItemID.YEW_SHORTBOW_U, 65, 67.5f),
ADAMANT_DART(ItemID.ADAMANT_DART, 67, 15),
- RUNITE_CROSSBOW_U(ItemID.RUNITE_CROSSBOW_U, 69, 100),
+ RUNITE_BOLTS(ItemID.RUNITE_BOLTS, 69, 10),
RUNE_CROSSBOW(ItemID.RUNE_CROSSBOW, 69, 50),
YEW_STOCK(ItemID.YEW_STOCK, 69, 50),
- RUNITE_BOLTS(ItemID.RUNITE_BOLTS, 69, 10),
+ RUNITE_CROSSBOW_U(ItemID.RUNITE_CROSSBOW_U, 69, 100),
YEW_LONGBOW(ItemID.YEW_LONGBOW, 70, 75),
YEW_LONGBOW_U(ItemID.YEW_LONGBOW_U, 70, 75),
DRAGONSTONE_BOLTS(ItemID.DRAGONSTONE_BOLTS, 71, 8.2f),
@@ -121,9 +122,9 @@ public enum FletchingAction implements ItemSkillAction
RUNE_ARROW(ItemID.RUNE_ARROW, 75, 12.5f),
AMETHYST_BROAD_BOLTS(ItemID.AMETHYST_BROAD_BOLTS, 76, 10.6f),
RUNE_JAVELIN(ItemID.RUNE_JAVELIN, 77, 12.4f),
+ DRAGON_CROSSBOW(ItemID.DRAGON_CROSSBOW, 78, 70),
MAGIC_STOCK(ItemID.MAGIC_STOCK, 78, 70),
DRAGON_CROSSBOW_U(ItemID.DRAGON_CROSSBOW_U, 78, 135),
- DRAGON_CROSSBOW(ItemID.DRAGON_CROSSBOW, 78, 70),
MAGIC_SHORTBOW(ItemID.MAGIC_SHORTBOW, 80, 83.3f),
MAGIC_SHORTBOW_U(ItemID.MAGIC_SHORTBOW_U, 80, 83.3f),
RUNE_DART(ItemID.RUNE_DART, 81, 18.8f),
@@ -133,8 +134,8 @@ public enum FletchingAction implements ItemSkillAction
MAGIC_LONGBOW(ItemID.MAGIC_LONGBOW, 85, 91.5f),
MAGIC_LONGBOW_U(ItemID.MAGIC_LONGBOW_U, 85, 91.5f),
MAGIC_SHIELD(ItemID.MAGIC_SHIELD, 87, 183),
- AMETHYST_DART(ItemID.AMETHYST_DART, 90, 21),
DRAGON_ARROW(ItemID.DRAGON_ARROW, 90, 15),
+ AMETHYST_DART(ItemID.AMETHYST_DART, 90, 21),
DRAGON_JAVELIN(ItemID.DRAGON_JAVELIN, 92, 15),
REDWOOD_SHIELD(ItemID.REDWOOD_SHIELD, 92, 216),
DRAGON_DART(ItemID.DRAGON_DART, 95, 25),
diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/skillcalculator/skills/HerbloreAction.java b/runelite-client/src/main/java/net/runelite/client/plugins/skillcalculator/skills/HerbloreAction.java
index 025022ffd5..2e1ac43c4f 100644
--- a/runelite-client/src/main/java/net/runelite/client/plugins/skillcalculator/skills/HerbloreAction.java
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/skillcalculator/skills/HerbloreAction.java
@@ -33,8 +33,8 @@
@Getter
public enum HerbloreAction implements ItemSkillAction
{
- ATTACK_POTION_3(ItemID.ATTACK_POTION3, 3, 25),
GUAM_LEAF(ItemID.GUAM_LEAF, 3, 2.5f),
+ ATTACK_POTION_3(ItemID.ATTACK_POTION3, 3, 25),
MARRENTILL(ItemID.MARRENTILL, 5, 3.8f),
ANTIPOISON_3(ItemID.ANTIPOISON3, 5, 37.5f),
RELICYMS_BALM_3(ItemID.RELICYMS_BALM3, 8, 40),
@@ -58,8 +58,8 @@ public enum HerbloreAction implements ItemSkillAction
IRIT_LEAF(ItemID.IRIT_LEAF, 40, 8.8f),
HARRALANDER_TAR(ItemID.HARRALANDER_TAR, 44, 72.5f),
SUPER_ATTACK_3(ItemID.SUPER_ATTACK3, 45, 100),
- SUPERANTIPOISON_3(ItemID.SUPERANTIPOISON3, 48, 106.3f),
AVANTOE(ItemID.AVANTOE, 48, 10),
+ SUPERANTIPOISON_3(ItemID.SUPERANTIPOISON3, 48, 106.3f),
FISHING_POTION_3(ItemID.FISHING_POTION3, 50, 112.5f),
SUPER_ENERGY_3(ItemID.SUPER_ENERGY3, 52, 117.5f),
HUNTER_POTION_3(ItemID.HUNTER_POTION3, 53, 120),
diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/skillcalculator/skills/HunterAction.java b/runelite-client/src/main/java/net/runelite/client/plugins/skillcalculator/skills/HunterAction.java
index 4fac817a16..fc2b8d2370 100644
--- a/runelite-client/src/main/java/net/runelite/client/plugins/skillcalculator/skills/HunterAction.java
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/skillcalculator/skills/HunterAction.java
@@ -33,8 +33,8 @@
@Getter
public enum HunterAction implements NamedSkillAction
{
- CRIMSON_SWIFT("Crimson Swift", 1, 34, ItemID.CRIMSON_SWIFT),
POLAR_KEBBIT("Polar Kebbit", 1, 30, ItemID.KEBBIT),
+ CRIMSON_SWIFT("Crimson Swift", 1, 34, ItemID.CRIMSON_SWIFT),
COMMON_KEBBIT("Common Kebbit", 3, 36, ItemID.KEBBIT_9954),
GOLDEN_WARBLER("Golden Warbler", 5, 47, ItemID.GOLDEN_WARBLER),
REGULAR_BIRD_HOUSE("Regular Bird House", 5, 280, ItemID.BIRD_HOUSE),
@@ -46,6 +46,7 @@ public enum HunterAction implements NamedSkillAction
RUBY_HARVEST("Ruby Harvest", 15, 24, ItemID.BUTTERFLY),
BABY_IMPLING("Baby Impling", 17, 18, ItemID.BABY_IMPLING_JAR),
TROPICAL_WAGTAIL("Tropical Wagtail", 19, 95, ItemID.TROPICAL_WAGTAIL),
+ MOSS_LIZARD("Moss Lizard", 20, 90, ItemID.RAW_MOSS_LIZARD),
YOUNG_IMPLING("Young Impling", 22, 20, ItemID.YOUNG_IMPLING_JAR),
WILD_KEBBIT("Wild Kebbit", 23, 128, ItemID.KEBBIT),
WILLOW_BIRD_HOUSE("Willow Bird House", 24, 560, ItemID.WILLOW_BIRD_HOUSE),
@@ -60,6 +61,7 @@ public enum HunterAction implements NamedSkillAction
SNOWY_KNIGHT("Snowy Knight", 35, 44, ItemID.BUTTERFLY_9972),
EARTH_IMPLING("Earth Impling", 36, 25, ItemID.EARTH_IMPLING_JAR),
PRICKLY_KEBBIT("Prickly Kebbit", 37, 204, ItemID.KEBBIT_9957),
+ EMBERTAILED_JERBOA("Embertailed Jerboa", 39, 137, ItemID.EMBERTAILED_JERBOA),
HORNED_GRAAHK("Horned Graahk", 41, 240, ItemID.GRAAHK_HEADDRESS),
ESSENCE_IMPLING("Essence Impling", 42, 27, ItemID.ESSENCE_IMPLING_JAR),
SPOTTED_KEBBIT("Spotted Kebbit", 43, 104, ItemID.KEBBIT_9960),
@@ -73,24 +75,30 @@ public enum HunterAction implements NamedSkillAction
CHINCHOMPA("Chinchompa", 53, 198.4f, ItemID.CHINCHOMPA),
SABRE_TOOTHED_KYATT("Sabre-toothed Kyatt", 55, 300, ItemID.KYATT_HAT),
DARK_KEBBIT("Dark Kebbit", 57, 132, ItemID.KEBBIT_9963),
+ PYRE_FOX("Pyre Fox", 57, 222, ItemID.PYRE_FOX),
NATURE_IMPLING("Nature Impling", 58, 34, ItemID.NATURE_IMPLING_JAR),
RED_SALAMANDER("Red Salamander", 59, 272, ItemID.RED_SALAMANDER),
YEW_BIRD_HOUSE("Yew Bird House", 59, 1020, ItemID.YEW_BIRD_HOUSE),
MANIACAL_MONKEY("Maniacal Monkey", 60, 1000, ItemID.MONKEY_19556),
CARNIVOROUS_CHINCHOMPA("Carnivorous Chinchompa", 63, 265, ItemID.RED_CHINCHOMPA),
MAGPIE_IMPLING("Magpie Impling", 65, 44, ItemID.MAGPIE_IMPLING_JAR),
+ SUNLIGHT_MOTH("Sunlight Moth", 65, 74, ItemID.SUNLIGHT_MOTH),
MAGPIE_IMPLING_GIELINOR("Magpie Impling (Gielinor)", 65, 216, ItemID.MAGPIE_IMPLING_JAR),
BLACK_SALAMANDER("Black Salamander", 67, 319.5f, ItemID.BLACK_SALAMANDER),
DASHING_KEBBIT("Dashing Kebbit", 69, 156, ItemID.KEBBIT_9964),
+ SUNLIGHT_ANTELOPE("Sunlight Antelope", 72, 380, ItemID.SUNLIGHT_ANTELOPE),
BLACK_CHINCHOMPA("Black Chinchompa", 73, 315, ItemID.BLACK_CHINCHOMPA),
- MAGIC_BIRD_HOUSE("Magic Bird House", 74, 1140, ItemID.MAGIC_BIRD_HOUSE),
NINJA_IMPLING("Ninja Impling", 74, 52, ItemID.NINJA_IMPLING_JAR),
NINJA_IMPLING_GIELINOR("Ninja Impling (Gielinor)", 74, 240, ItemID.NINJA_IMPLING_JAR),
+ MAGIC_BIRD_HOUSE("Magic Bird House", 74, 1140, ItemID.MAGIC_BIRD_HOUSE),
+ MOONLIGHT_MOTH("Moonlight Moth", 75, 84, ItemID.MOONLIGHT_MOTH),
+ TECU_SALAMANDER("Tecu Salamander", 79, 344, ItemID.TECU_SALAMANDER),
CRYSTAL_IMPLING("Crystal Impling", 80, 280, ItemID.CRYSTAL_IMPLING_JAR),
DRAGON_IMPLING("Dragon Impling", 83, 65, ItemID.DRAGON_IMPLING_JAR),
DRAGON_IMPLING_GIELINOR("Dragon Impling (Gielinor)", 83, 300, ItemID.DRAGON_IMPLING_JAR),
- REDWOOD_BIRD_HOUSE("Redwood Bird House", 89, 1200, ItemID.REDWOOD_BIRD_HOUSE),
LUCKY_IMPLING("Lucky Impling", 89, 380, ItemID.LUCKY_IMPLING_JAR),
+ REDWOOD_BIRD_HOUSE("Redwood Bird House", 89, 1200, ItemID.REDWOOD_BIRD_HOUSE),
+ MOONLIGHT_ANTELOPE("Moonlight Antelope", 91, 450, ItemID.MOONLIGHT_ANTELOPE),
;
private final String name;
diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/skillcalculator/skills/MagicAction.java b/runelite-client/src/main/java/net/runelite/client/plugins/skillcalculator/skills/MagicAction.java
index bb3547fe71..620107e806 100644
--- a/runelite-client/src/main/java/net/runelite/client/plugins/skillcalculator/skills/MagicAction.java
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/skillcalculator/skills/MagicAction.java
@@ -38,27 +38,27 @@ public enum MagicAction implements SkillAction
ENCHANT_OPAL_BOLT("Enchant Opal Bolt", 4, 9, SpriteID.SPELL_ENCHANT_CROSSBOW_BOLT, true),
WATER_STRIKE("Water Strike", 5, 7.5f, SpriteID.SPELL_WATER_STRIKE, false),
ARCEUUS_LIBRARY_TELEPORT("Arceuus Library Teleport", 6, 10, SpriteID.SPELL_ARCEUUS_LIBRARY_TELEPORT, true),
- ENCHANT_SAPPHIRE_JEWELLERY("Enchant Sapphire Jewellery", 7, 17.5f, SpriteID.SPELL_LVL_1_ENCHANT, false),
ENCHANT_SAPPHIRE_BOLT("Enchant Sapphire Bolt", 7, 17.5f, SpriteID.SPELL_ENCHANT_CROSSBOW_BOLT, true),
+ ENCHANT_SAPPHIRE_JEWELLERY("Enchant Sapphire Jewellery", 7, 17.5f, SpriteID.SPELL_LVL_1_ENCHANT, false),
EARTH_STRIKE("Earth Strike", 9, 9.5f, SpriteID.SPELL_EARTH_STRIKE, false),
WEAKEN("Weaken", 11, 21, SpriteID.SPELL_WEAKEN, false),
FIRE_STRIKE("Fire Strike", 13, 11.5f, SpriteID.SPELL_FIRE_STRIKE, false),
ENCHANT_JADE_BOLT("Enchant Jade Bolt", 14, 19, SpriteID.SPELL_ENCHANT_CROSSBOW_BOLT, true),
BONES_TO_BANANAS("Bones To Bananas", 15, 25, SpriteID.SPELL_BONES_TO_BANANAS, false),
BASIC_REANIMATION("Basic Reanimation", 16, 32, SpriteID.SPELL_BASIC_REANIMATION, true),
- DRAYNOR_MANOR_TELEPORT("Draynor Manor Teleport", 17, 16, SpriteID.SPELL_DRAYNOR_MANOR_TELEPORT, true),
WIND_BOLT("Wind Bolt", 17, 13.5f, SpriteID.SPELL_WIND_BOLT, false),
+ DRAYNOR_MANOR_TELEPORT("Draynor Manor Teleport", 17, 16, SpriteID.SPELL_DRAYNOR_MANOR_TELEPORT, true),
CURSE("Curse", 19, 29, SpriteID.SPELL_CURSE, false),
BIND("Bind", 20, 30, SpriteID.SPELL_BIND, false),
LOW_LEVEL_ALCHEMY("Low Level Alchemy", 21, 31, SpriteID.SPELL_LOW_LEVEL_ALCHEMY, false),
WATER_BOLT("Water Bolt", 23, 16.5f, SpriteID.SPELL_WATER_BOLT, false),
ENCHANT_PEARL_BOLT("Enchant Pearl Bolt", 24, 29, SpriteID.SPELL_ENCHANT_CROSSBOW_BOLT, true),
VARROCK_TELEPORT("Varrock Teleport", 25, 35, SpriteID.SPELL_VARROCK_TELEPORT, false),
- ENCHANT_EMERALD_JEWELLERY("Enchant Emerald Jewellery", 27, 37, SpriteID.SPELL_LVL_2_ENCHANT, false),
ENCHANT_EMERALD_BOLT("Enchant Emerald Bolt", 27, 37, SpriteID.SPELL_ENCHANT_CROSSBOW_BOLT, true),
+ ENCHANT_EMERALD_JEWELLERY("Enchant Emerald Jewellery", 27, 37, SpriteID.SPELL_LVL_2_ENCHANT, false),
MIND_ALTAR_TELEPORT("Mind Altar Teleport", 28, 22, SpriteID.SPELL_MIND_ALTAR_TELEPORT, true),
- ENCHANT_TOPAZ_BOLT("Enchant Topaz Bolt", 29, 33, SpriteID.SPELL_ENCHANT_CROSSBOW_BOLT, true),
EARTH_BOLT("Earth Bolt", 29, 19.5f, SpriteID.SPELL_EARTH_BOLT, false),
+ ENCHANT_TOPAZ_BOLT("Enchant Topaz Bolt", 29, 33, SpriteID.SPELL_ENCHANT_CROSSBOW_BOLT, true),
LUMBRIDGE_TELEPORT("Lumbridge Teleport", 31, 41, SpriteID.SPELL_LUMBRIDGE_TELEPORT, false),
TELEKINETIC_GRAB("Telekinetic Grab", 33, 43, SpriteID.SPELL_TELEKINETIC_GRAB, false),
RESPAWN_TELEPORT("Respawn Teleport", 34, 27, SpriteID.SPELL_RESPAWN_TELEPORT, true),
@@ -69,138 +69,140 @@ public enum MagicAction implements SkillAction
CRUMBLE_UNDEAD("Crumble Undead", 39, 24.5f, SpriteID.SPELL_CRUMBLE_UNDEAD, false),
SALVE_GRAVEYARD_TELEPORT("Salve Graveyard Teleport", 40, 30, SpriteID.SPELL_SALVE_GRAVEYARD_TELEPORT, true),
TELEPORT_TO_HOUSE("Teleport To House", 40, 30, SpriteID.SPELL_TELEPORT_TO_HOUSE, true),
- ADEPT_REANIMATION("Adept Reanimation", 41, 80, SpriteID.SPELL_ADEPT_REANIMATION, true),
WIND_BLAST("Wind Blast", 41, 25.5f, SpriteID.SPELL_WIND_BLAST, false),
+ ADEPT_REANIMATION("Adept Reanimation", 41, 80, SpriteID.SPELL_ADEPT_REANIMATION, true),
SUPERHEAT_ITEM("Superheat Item", 43, 53, SpriteID.SPELL_SUPERHEAT_ITEM, false),
INFERIOR_DEMONBANE("Inferior Demonbane", 44, 27, SpriteID.SPELL_INFERIOR_DEMONBANE, true),
CAMELOT_TELEPORT("Camelot Teleport", 45, 55.5f, SpriteID.SPELL_CAMELOT_TELEPORT, true),
WATER_BLAST("Water Blast", 47, 28.5f, SpriteID.SPELL_WATER_BLAST, false),
SHADOW_VEIL("Shadow Veil", 47, 58, SpriteID.SPELL_SHADOW_VEIL, true),
FENKENSTRAINS_CASTLE_TELEPORT("Fenkenstrain's Castle Teleport", 48, 50, SpriteID.SPELL_FENKENSTRAINS_CASTLE_TELEPORT, true),
- ENCHANT_RUBY_JEWELLERY("Enchant Ruby Jewellery", 49, 59, SpriteID.SPELL_LVL_3_ENCHANT, false),
+ KOUREND_CASTLE_TELEPORT("Kourend Castle Teleport", 48, 58, SpriteID.SPELL_TELEPORT_TO_KOUREND, true),
ENCHANT_RUBY_BOLT("Enchant Ruby Bolt", 49, 59, SpriteID.SPELL_ENCHANT_CROSSBOW_BOLT, true),
+ ENCHANT_RUBY_JEWELLERY("Enchant Ruby Jewellery", 49, 59, SpriteID.SPELL_LVL_3_ENCHANT, false),
IBAN_BLAST("Iban Blast", 50, 30, SpriteID.SPELL_IBAN_BLAST, true),
- SMOKE_RUSH("Smoke Rush", 50, 30, SpriteID.SPELL_SMOKE_RUSH, true),
MAGIC_DART("Magic Dart", 50, 30, SpriteID.SPELL_MAGIC_DART, true),
- SNARE("Snare", 50, 60, SpriteID.SPELL_SNARE, false),
+ SMOKE_RUSH("Smoke Rush", 50, 30, SpriteID.SPELL_SMOKE_RUSH, true),
DARK_LURE("Dark Lure", 50, 60, SpriteID.SPELL_DARK_LURE, true),
+ SNARE("Snare", 50, 60, SpriteID.SPELL_SNARE, false),
ARDOUGNE_TELEPORT("Ardougne Teleport", 51, 61, SpriteID.SPELL_ARDOUGNE_TELEPORT, true),
SHADOW_RUSH("Shadow Rush", 52, 31, SpriteID.SPELL_SHADOW_RUSH, true),
EARTH_BLAST("Earth Blast", 53, 31.5f, SpriteID.SPELL_EARTH_BLAST, false),
+ CIVITAS_ILLA_FORTIS_TELEPORT("Civitas illa Fortis Teleport", 54, 64, SpriteID.SPELL_CIVITAS_ILLA_FORTIS_TELEPORT, true),
PADDEWWA_TELEPORT("Paddewwa Teleport", 54, 64, SpriteID.SPELL_PADDEWWA_TELEPORT, true),
HIGH_LEVEL_ALCHEMY("High Level Alchemy", 55, 65, SpriteID.SPELL_HIGH_LEVEL_ALCHEMY, false),
- CHARGE_WATER_ORB("Charge Water Orb", 56, 66, SpriteID.SPELL_CHARGE_WATER_ORB, true),
BLOOD_RUSH("Blood Rush", 56, 33, SpriteID.SPELL_BLOOD_RUSH, true),
SKELETAL_GRASP("Skeletal Grasp", 56, 33, SpriteID.SPELL_SKELETAL_GRASP, true),
- ENCHANT_DIAMOND_JEWELLERY("Enchant Diamond Jewellery", 57, 67, SpriteID.SPELL_LVL_4_ENCHANT, false),
+ CHARGE_WATER_ORB("Charge Water Orb", 56, 66, SpriteID.SPELL_CHARGE_WATER_ORB, true),
ENCHANT_DIAMOND_BOLT("Enchant Diamond Bolt", 57, 67, SpriteID.SPELL_ENCHANT_CROSSBOW_BOLT, true),
+ ENCHANT_DIAMOND_JEWELLERY("Enchant Diamond Jewellery", 57, 67, SpriteID.SPELL_LVL_4_ENCHANT, false),
RESURRECT_SUPERIOR_THRALL("Resurrect Superior Thrall", 57, 70, SpriteID.SPELL_RESURRECT_SUPERIOR_SKELETON, true),
- WATCHTOWER_TELEPORT("Watchtower Teleport", 58, 68, SpriteID.SPELL_WATCHTOWER_TELEPORT, true),
ICE_RUSH("Ice Rush", 58, 34, SpriteID.SPELL_ICE_RUSH, true),
+ WATCHTOWER_TELEPORT("Watchtower Teleport", 58, 68, SpriteID.SPELL_WATCHTOWER_TELEPORT, true),
FIRE_BLAST("Fire Blast", 59, 34.5f, SpriteID.SPELL_FIRE_BLAST, false),
MARK_OF_DARKNESS("Mark of Darkness", 59, 70, SpriteID.SPELL_MARK_OF_DARKNESS, true),
- SENNTISTEN_TELEPORT("Senntisten Teleport", 60, 70, SpriteID.SPELL_SENNTISTEN_TELEPORT, true),
CLAWS_OF_GUTHIX("Claws Of Guthix", 60, 35, SpriteID.SPELL_CLAWS_OF_GUTHIX, true),
FLAMES_OF_ZAMORAK("Flames Of Zamorak", 60, 35, SpriteID.SPELL_FLAMES_OF_ZAMORAK, true),
SARADOMIN_STRIKE("Saradomin Strike", 60, 35, SpriteID.SPELL_SARADOMIN_STRIKE, true),
- CHARGE_EARTH_ORB("Charge Earth Orb", 60, 70, SpriteID.SPELL_CHARGE_EARTH_ORB, true),
BONES_TO_PEACHES("Bones To Peaches", 60, 35.5f, SpriteID.SPELL_BONES_TO_PEACHES, true),
- WEST_ARDOUGNE_TELEPORT("West Ardougne Teleport", 61, 68, SpriteID.SPELL_WEST_ARDOUGNE_TELEPORT, true),
+ CHARGE_EARTH_ORB("Charge Earth Orb", 60, 70, SpriteID.SPELL_CHARGE_EARTH_ORB, true),
+ SENNTISTEN_TELEPORT("Senntisten Teleport", 60, 70, SpriteID.SPELL_SENNTISTEN_TELEPORT, true),
TROLLHEIM_TELEPORT("Trollheim Teleport", 61, 68, SpriteID.SPELL_TROLLHEIM_TELEPORT, true),
+ WEST_ARDOUGNE_TELEPORT("West Ardougne Teleport", 61, 68, SpriteID.SPELL_WEST_ARDOUGNE_TELEPORT, true),
SMOKE_BURST("Smoke Burst", 62, 36, SpriteID.SPELL_SMOKE_BURST, true),
- WIND_WAVE("Wind Wave", 62, 36, SpriteID.SPELL_WIND_WAVE, true),
SUPERIOR_DEMONBANE("Superior Demonbane", 62, 36, SpriteID.SPELL_SUPERIOR_DEMONBANE, true),
+ WIND_WAVE("Wind Wave", 62, 36, SpriteID.SPELL_WIND_WAVE, true),
CHARGE_FIRE_ORB("Charge Fire Orb", 63, 73, SpriteID.SPELL_CHARGE_FIRE_ORB, true),
SHADOW_BURST("Shadow Burst", 64, 37, SpriteID.SPELL_SHADOW_BURST, true),
TELEPORT_APE_ATOLL("Teleport Ape Atoll", 64, 74, SpriteID.SPELL_TELEPORT_TO_APE_ATOLL, true),
LESSER_CORRUPTION("Lesser Corruption", 64, 75, SpriteID.SPELL_LESSER_CORRUPTION, true),
+ WATER_WAVE("Water Wave", 65, 37.5f, SpriteID.SPELL_WATER_WAVE, true),
BAKE_PIE("Bake Pie", 65, 60, SpriteID.SPELL_BAKE_PIE, true),
- HARMONY_ISLAND_TELEPORT("Harmony Island Teleport", 65, 74, SpriteID.SPELL_HARMONY_ISLAND_TELEPORT, true),
GEOMANCY("Geomancy", 65, 60, SpriteID.SPELL_GEOMANCY, true),
- WATER_WAVE("Water Wave", 65, 37.5f, SpriteID.SPELL_WATER_WAVE, true),
- CHARGE_AIR_ORB("Charge Air Orb", 66, 76, SpriteID.SPELL_CHARGE_AIR_ORB, true),
+ HARMONY_ISLAND_TELEPORT("Harmony Island Teleport", 65, 74, SpriteID.SPELL_HARMONY_ISLAND_TELEPORT, true),
CURE_PLANT("Cure Plant", 66, 60, SpriteID.SPELL_CURE_PLANT, true),
- KHARYRLL_TELEPORT("Kharyrll Teleport", 66, 76, SpriteID.SPELL_KHARYRLL_TELEPORT, true),
- VULNERABILITY("Vulnerability", 66, 76, SpriteID.SPELL_VULNERABILITY, true),
MONSTER_EXAMINE("Monster Examine", 66, 61, SpriteID.SPELL_MONSTER_EXAMINE, true),
+ CHARGE_AIR_ORB("Charge Air Orb", 66, 76, SpriteID.SPELL_CHARGE_AIR_ORB, true),
+ KHARYRLL_TELEPORT("Kharyrll Teleport", 66, 76, SpriteID.SPELL_KHARYRLL_TELEPORT, true),
VILE_VIGOUR("Vile Vigour", 66, 76, SpriteID.SPELL_VILE_VIGOUR, true),
+ VULNERABILITY("Vulnerability", 66, 76, SpriteID.SPELL_VULNERABILITY, true),
NPC_CONTACT("Npc Contact", 67, 63, SpriteID.SPELL_NPC_CONTACT, true),
BLOOD_BURST("Blood Burst", 68, 39, SpriteID.SPELL_BLOOD_BURST, true),
CURE_OTHER("Cure Other", 68, 65, SpriteID.SPELL_CURE_OTHER, true),
- ENCHANT_DRAGONSTONE_JEWELLERY("Enchant Dragonstone Jewellery", 68, 78, SpriteID.SPELL_LVL_5_ENCHANT, true),
- ENCHANT_DRAGONSTONE_BOLT("Enchant Dragonstone Bolt", 68, 78, SpriteID.SPELL_ENCHANT_CROSSBOW_BOLT, true),
HUMIDIFY("Humidify", 68, 65, SpriteID.SPELL_HUMIDIFY, true),
+ ENCHANT_DRAGONSTONE_BOLT("Enchant Dragonstone Bolt", 68, 78, SpriteID.SPELL_ENCHANT_CROSSBOW_BOLT, true),
+ ENCHANT_DRAGONSTONE_JEWELLERY("Enchant Dragonstone Jewellery", 68, 78, SpriteID.SPELL_LVL_5_ENCHANT, true),
MOONCLAN_TELEPORT("Moonclan Teleport", 69, 66, SpriteID.SPELL_MOONCLAN_TELEPORT, true),
EARTH_WAVE("Earth Wave", 70, 40, SpriteID.SPELL_EARTH_WAVE, true),
ICE_BURST("Ice Burst", 70, 40, SpriteID.SPELL_ICE_BURST, true),
TELE_GROUP_MOONCLAN("Tele Group Moonclan", 70, 67, SpriteID.SPELL_TELE_GROUP_MOONCLAN, true),
DEGRIME("Degrime", 70, 83, SpriteID.SPELL_DEGRIME, true),
- OURANIA_TELEPORT("Ourania Teleport", 71, 69, SpriteID.SPELL_OURANIA_TELEPORT, true),
- CEMETERY_TELEPORT("Cemetery Teleport", 71, 82, SpriteID.SPELL_CEMETERY_TELEPORT, true),
CURE_ME("Cure Me", 71, 69, SpriteID.SPELL_CURE_ME, true),
+ OURANIA_TELEPORT("Ourania Teleport", 71, 69, SpriteID.SPELL_OURANIA_TELEPORT, true),
HUNTER_KIT("Hunter Kit", 71, 70, SpriteID.SPELL_HUNTER_KIT, true),
- EXPERT_REANIMATION("Expert Reanimation", 72, 138, SpriteID.SPELL_EXPERT_REANIMATION, true),
- LASSAR_TELEPORT("Lassar Teleport", 72, 82, SpriteID.SPELL_LASSAR_TELEPORT, true),
+ CEMETERY_TELEPORT("Cemetery Teleport", 71, 82, SpriteID.SPELL_CEMETERY_TELEPORT, true),
WATERBIRTH_TELEPORT("Waterbirth Teleport", 72, 71, SpriteID.SPELL_WATERBIRTH_TELEPORT, true),
+ LASSAR_TELEPORT("Lassar Teleport", 72, 82, SpriteID.SPELL_LASSAR_TELEPORT, true),
+ EXPERT_REANIMATION("Expert Reanimation", 72, 138, SpriteID.SPELL_EXPERT_REANIMATION, true),
TELE_GROUP_WATERBIRTH("Tele Group Waterbirth", 73, 72, SpriteID.SPELL_TELE_GROUP_WATERBIRTH, true),
ENFEEBLE("Enfeeble", 73, 83, SpriteID.SPELL_ENFEEBLE, true),
WARD_OF_ARCEUUS("Ward of Arceuus", 73, 83, SpriteID.SPELL_WARD_OF_ARCEUUS, true),
- TELEOTHER_LUMBRIDGE("Teleother Lumbridge", 74, 84, SpriteID.SPELL_TELEOTHER_LUMBRIDGE, true),
SMOKE_BLITZ("Smoke Blitz", 74, 42, SpriteID.SPELL_SMOKE_BLITZ, true),
CURE_GROUP("Cure Group", 74, 74, SpriteID.SPELL_CURE_GROUP, true),
- STAT_SPY("Stat Spy", 75, 76, SpriteID.SPELL_STAT_SPY, true),
- BARBARIAN_TELEPORT("Barbarian Teleport", 75, 76, SpriteID.SPELL_BARBARIAN_TELEPORT, true),
+ TELEOTHER_LUMBRIDGE("Teleother Lumbridge", 74, 84, SpriteID.SPELL_TELEOTHER_LUMBRIDGE, true),
FIRE_WAVE("Fire Wave", 75, 42.5f, SpriteID.SPELL_FIRE_WAVE, true),
- TELE_GROUP_BARBARIAN("Tele Group Barbarian", 76, 77, SpriteID.SPELL_TELE_GROUP_ICE_PLATEAU, true),
+ BARBARIAN_TELEPORT("Barbarian Teleport", 75, 76, SpriteID.SPELL_BARBARIAN_TELEPORT, true),
+ STAT_SPY("Stat Spy", 75, 76, SpriteID.SPELL_STAT_SPY, true),
SHADOW_BLITZ("Shadow Blitz", 76, 43, SpriteID.SPELL_SHADOW_BLITZ, true),
SPIN_FLAX("Spin Flax", 76, 75, SpriteID.SPELL_SPIN_FLAX, true),
+ TELE_GROUP_BARBARIAN("Tele Group Barbarian", 76, 77, SpriteID.SPELL_TELE_GROUP_ICE_PLATEAU, true),
RESURRECT_GREATER_THRALL("Resurrect Greater Thrall", 76, 88, SpriteID.SPELL_RESURRECT_GREATER_ZOMBIE, true),
SUPERGLASS_MAKE("Superglass Make", 77, 78, SpriteID.SPELL_SUPERGLASS_MAKE, true),
- TAN_LEATHER("Tan Leather", 78, 81, SpriteID.SPELL_TAN_LEATHER, true),
KHAZARD_TELEPORT("Khazard Teleport", 78, 80, SpriteID.SPELL_KHAZARD_TELEPORT, true),
+ TAN_LEATHER("Tan Leather", 78, 81, SpriteID.SPELL_TAN_LEATHER, true),
DAREEYAK_TELEPORT("Dareeyak Teleport", 78, 88, SpriteID.SPELL_DAREEYAK_TELEPORT, true),
RESURRECT_CROPS("Resurrect Crops", 78, 90, SpriteID.SPELL_RESURRECT_CROPS, true),
- ENTANGLE("Entangle", 79, 89, SpriteID.SPELL_ENTANGLE, true),
+ UNDEAD_GRASP("Undead Grasp", 79, 46.5f, SpriteID.SPELL_UNDEAD_GRASP, true),
TELE_GROUP_KHAZARD("Tele Group Khazard", 79, 81, SpriteID.SPELL_TELE_GROUP_KHAZARD, true),
DREAM("Dream", 79, 82, SpriteID.SPELL_DREAM, true),
- UNDEAD_GRASP("Undead Grasp", 79, 46.5f, SpriteID.SPELL_UNDEAD_GRASP, true),
- CHARGE("Charge", 80, 180, SpriteID.SPELL_CHARGE, true),
+ ENTANGLE("Entangle", 79, 89, SpriteID.SPELL_ENTANGLE, true),
BLOOD_BLITZ("Blood Blitz", 80, 45, SpriteID.SPELL_BLOOD_BLITZ, true),
- STUN("Stun", 80, 90, SpriteID.SPELL_STUN, true),
STRING_JEWELLERY("String Jewellery", 80, 83, SpriteID.SPELL_STRING_JEWELLERY, true),
DEATH_CHARGE("Death Charge", 80, 90, SpriteID.SPELL_DEATH_CHARGE, true),
- STAT_RESTORE_POT_SHARE("Stat Restore Pot Share", 81, 84, SpriteID.SPELL_STAT_RESTORE_POT_SHARE, true),
+ STUN("Stun", 80, 90, SpriteID.SPELL_STUN, true),
+ CHARGE("Charge", 80, 180, SpriteID.SPELL_CHARGE, true),
WIND_SURGE("Wind Surge", 81, 44, SpriteID.SPELL_WIND_SURGE, true),
- TELEOTHER_FALADOR("Teleother Falador", 82, 92, SpriteID.SPELL_TELEOTHER_FALADOR, true),
- MAGIC_IMBUE("Magic Imbue", 82, 86, SpriteID.SPELL_MAGIC_IMBUE, true),
- ICE_BLITZ("Ice Blitz", 82, 46, SpriteID.SPELL_ICE_BLITZ, true),
+ STAT_RESTORE_POT_SHARE("Stat Restore Pot Share", 81, 84, SpriteID.SPELL_STAT_RESTORE_POT_SHARE, true),
DARK_DEMONBANE("Dark Demonbane", 82, 43.5f, SpriteID.SPELL_DARK_DEMONBANE, true),
+ ICE_BLITZ("Ice Blitz", 82, 46, SpriteID.SPELL_ICE_BLITZ, true),
+ MAGIC_IMBUE("Magic Imbue", 82, 86, SpriteID.SPELL_MAGIC_IMBUE, true),
+ TELEOTHER_FALADOR("Teleother Falador", 82, 92, SpriteID.SPELL_TELEOTHER_FALADOR, true),
FERTILE_SOIL("Fertile Soil", 83, 87, SpriteID.SPELL_FERTILE_SOIL, true),
BARROWS_TELEPORT("Barrows Teleport", 83, 90, SpriteID.SPELL_BARROWS_TELEPORT, true),
CARRALLANGER_TELEPORT("Carrallanger Teleport", 84, 82, SpriteID.SPELL_CARRALLANGAR_TELEPORT, true),
BOOST_POTION_SHARE("Boost Potion Share", 84, 88, SpriteID.SPELL_BOOST_POTION_SHARE, true),
DEMONIC_OFFERING("Demonic Offering", 84, 175, SpriteID.SPELL_DEMONIC_OFFERING, true),
+ TELEPORT_TO_TARGET("Teleport To Target", 85, 45, SpriteID.SPELL_TELEPORT_TO_BOUNTY_TARGET, true),
WATER_SURGE("Water Surge", 85, 46, SpriteID.SPELL_WATER_SURGE, true),
- FISHING_GUILD_TELEPORT("Fishing Guild Teleport", 85, 89, SpriteID.SPELL_FISHING_GUILD_TELEPORT, true),
TELE_BLOCK("Tele Block", 85, 80, SpriteID.SPELL_TELE_BLOCK, false),
- TELEPORT_TO_TARGET("Teleport To Target", 85, 45, SpriteID.SPELL_TELEPORT_TO_BOUNTY_TARGET, true),
+ FISHING_GUILD_TELEPORT("Fishing Guild Teleport", 85, 89, SpriteID.SPELL_FISHING_GUILD_TELEPORT, true),
GREATER_CORRUPTION("Greater Corruption", 85, 95, SpriteID.SPELL_GREATER_CORRUPTION, true),
SMOKE_BARRAGE("Smoke Barrage", 86, 48, SpriteID.SPELL_SMOKE_BARRAGE, true),
- TELE_GROUP_FISHING_GUILD("Tele Group Fishing Guild", 86, 90, SpriteID.SPELL_TELE_GROUP_FISHING_GUILD, true),
PLANK_MAKE("Plank Make", 86, 90, SpriteID.SPELL_PLANK_MAKE, true),
+ TELE_GROUP_FISHING_GUILD("Tele Group Fishing Guild", 86, 90, SpriteID.SPELL_TELE_GROUP_FISHING_GUILD, true),
CATHERBY_TELEPORT("Catherby Teleport", 87, 92, SpriteID.SPELL_CATHERBY_TELEPORT, true),
- ENCHANT_ONYX_JEWELLERY("Enchant Onyx Jewellery", 87, 97, SpriteID.SPELL_LVL_6_ENCHANT, true),
ENCHANT_ONYX_BOLT("Enchant Onyx Bolt", 87, 97, SpriteID.SPELL_ENCHANT_CROSSBOW_BOLT, true),
+ ENCHANT_ONYX_JEWELLERY("Enchant Onyx Jewellery", 87, 97, SpriteID.SPELL_LVL_6_ENCHANT, true),
SHADOW_BARRAGE("Shadow Barrage", 88, 48, SpriteID.SPELL_SHADOW_BARRAGE, true),
TELE_GROUP_CATHERBY("Tele Group Catherby", 88, 93, SpriteID.SPELL_TELE_GROUP_CATHERBY, true),
ICE_PLATEAU_TELEPORT("Ice Plateau Teleport", 89, 96, SpriteID.SPELL_ICE_PLATEAU_TELEPORT, true),
RECHARGE_DRAGONSTONE("Recharge Dragonstone", 89, 97.5f, SpriteID.SPELL_RECHARGE_DRAGONSTONE, true),
- ANNAKARL_TELEPORT("Annakarl Teleport", 90, 100, SpriteID.SPELL_ANNAKARL_TELEPORT, true),
EARTH_SURGE("Earth Surge", 90, 48, SpriteID.SPELL_EARTH_SURGE, true),
- MASTER_REANIMATION("Master Reanimation", 90, 170, SpriteID.SPELL_MASTER_REANIMATION, true),
TELE_GROUP_ICE_PLATEAU("Tele Group Ice Plateau", 90, 99, SpriteID.SPELL_TELE_GROUP_ICE_PLATEAU, true),
- TELEOTHER_CAMELOT("Teleother Camelot", 90, 100, SpriteID.SPELL_TELEOTHER_CAMELOT, true),
+ ANNAKARL_TELEPORT("Annakarl Teleport", 90, 100, SpriteID.SPELL_ANNAKARL_TELEPORT, true),
APE_ATOLL_TELEPORT("Ape Atoll Teleport", 90, 100, SpriteID.SPELL_APE_ATOLL_TELEPORT, true),
+ TELEOTHER_CAMELOT("Teleother Camelot", 90, 100, SpriteID.SPELL_TELEOTHER_CAMELOT, true),
+ MASTER_REANIMATION("Master Reanimation", 90, 170, SpriteID.SPELL_MASTER_REANIMATION, true),
ENERGY_TRANSFER("Energy Transfer", 91, 100, SpriteID.SPELL_ENERGY_TRANSFER, true),
BLOOD_BARRAGE("Blood Barrage", 92, 51, SpriteID.SPELL_BLOOD_BARRAGE, true),
HEAL_OTHER("Heal Other", 92, 101, SpriteID.SPELL_HEAL_OTHER, true),
@@ -209,8 +211,8 @@ public enum MagicAction implements SkillAction
ENCHANT_ZENYTE_JEWELLERY("Enchant Zenyte Jewellery", 93, 110, SpriteID.SPELL_LVL_7_ENCHANT, true),
ICE_BARRAGE("Ice Barrage", 94, 52, SpriteID.SPELL_ICE_BARRAGE, true),
VENGEANCE("Vengeance", 94, 112, SpriteID.SPELL_VENGEANCE, true),
- HEAL_GROUP("Heal Group", 95, 124, SpriteID.SPELL_HEAL_GROUP, true),
FIRE_SURGE("Fire Surge", 95, 51, SpriteID.SPELL_FIRE_SURGE, true),
+ HEAL_GROUP("Heal Group", 95, 124, SpriteID.SPELL_HEAL_GROUP, true),
GHORROCK_TELEPORT("Ghorrock Teleport", 96, 106, SpriteID.SPELL_GHORROCK_TELEPORT, true),
SPELLBOOK_SWAP("Spellbook Swap", 96, 130, SpriteID.SPELL_SPELLBOOK_SWAP, true),
;
diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/skillcalculator/skills/MiningAction.java b/runelite-client/src/main/java/net/runelite/client/plugins/skillcalculator/skills/MiningAction.java
index bd6a71f689..18d49f8c3b 100644
--- a/runelite-client/src/main/java/net/runelite/client/plugins/skillcalculator/skills/MiningAction.java
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/skillcalculator/skills/MiningAction.java
@@ -64,13 +64,21 @@ public boolean isMembers(final ItemManager itemManager)
SANDSTONE_5KG(ItemID.SANDSTONE_5KG, 35, 50),
SANDSTONE_10KG(ItemID.SANDSTONE_10KG, 35, 60),
DENSE_ESSENCE_BLOCK(ItemID.DENSE_ESSENCE_BLOCK, 38, 12),
- GOLD_ORE(ItemID.GOLD_ORE, 40, 65),
GEM_ROCKS(ItemID.UNCUT_RED_TOPAZ, 40, 65)
+ {
+ @Override
+ public String getName(final ItemManager itemManager)
+ {
+ return "Gem rocks";
+ }
+ },
+ GOLD_ORE(ItemID.GOLD_ORE, 40, 65),
+ CALCIFIED_ROCKS(ItemID.BLESSED_BONE_SHARDS, 41, 33)
{
@Override
public String getName(final ItemManager itemManager)
{
- return "Gem rocks";
+ return "Calcified Rocks";
}
},
GRANITE_500G(ItemID.GRANITE_500G, 45, 50),
diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/skillcalculator/skills/MiningBonus.java b/runelite-client/src/main/java/net/runelite/client/plugins/skillcalculator/skills/MiningBonus.java
index 910237ddc4..11d2ce7855 100644
--- a/runelite-client/src/main/java/net/runelite/client/plugins/skillcalculator/skills/MiningBonus.java
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/skillcalculator/skills/MiningBonus.java
@@ -31,7 +31,7 @@
@Getter(onMethod_ = @Override)
public enum MiningBonus implements SkillBonus
{
- PROSPECTOR_KIT("Prospector Kit (+2.5%)", 1.025f),
+ PROSPECTOR_KIT("Prospector Kit", 1.025f),
;
private final String name;
diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/skillcalculator/skills/PrayerAction.java b/runelite-client/src/main/java/net/runelite/client/plugins/skillcalculator/skills/PrayerAction.java
index 83364b5edc..9d43a15479 100644
--- a/runelite-client/src/main/java/net/runelite/client/plugins/skillcalculator/skills/PrayerAction.java
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/skillcalculator/skills/PrayerAction.java
@@ -24,92 +24,126 @@
*/
package net.runelite.client.plugins.skillcalculator.skills;
-import java.util.Arrays;
import java.util.EnumSet;
+import java.util.Set;
+import lombok.AllArgsConstructor;
import lombok.Getter;
import net.runelite.api.ItemID;
+import static net.runelite.client.plugins.skillcalculator.skills.PrayerBonus.BLESSED_SUNFIRE_WINE;
+import static net.runelite.client.plugins.skillcalculator.skills.PrayerBonus.DEMONIC_OFFERING;
+import static net.runelite.client.plugins.skillcalculator.skills.PrayerBonus.MORYTANIA_DIARY_3_SHADES;
+import static net.runelite.client.plugins.skillcalculator.skills.PrayerBonus.ZEALOT_ROBES;
+@AllArgsConstructor
@Getter
public enum PrayerAction implements ItemSkillAction
{
- ENSOULED_GOBLIN_HEAD(ItemID.ENSOULED_GOBLIN_HEAD, 1, 130),
- ENSOULED_MONKEY_HEAD(ItemID.ENSOULED_MONKEY_HEAD, 1, 182),
- ENSOULED_IMP_HEAD(ItemID.ENSOULED_IMP_HEAD, 1, 286),
- ENSOULED_MINOTAUR_HEAD(ItemID.ENSOULED_MINOTAUR_HEAD, 1, 364),
- ENSOULED_SCORPION_HEAD(ItemID.ENSOULED_SCORPION_HEAD, 1, 454),
- ENSOULED_BEAR_HEAD(ItemID.ENSOULED_BEAR_HEAD, 1, 480),
- ENSOULED_UNICORN_HEAD(ItemID.ENSOULED_UNICORN_HEAD, 1, 494),
- ENSOULED_DOG_HEAD(ItemID.ENSOULED_DOG_HEAD, 1, 520),
- ENSOULED_CHAOS_DRUID_HEAD(ItemID.ENSOULED_CHAOS_DRUID_HEAD, 1, 584),
- ENSOULED_GIANT_HEAD(ItemID.ENSOULED_GIANT_HEAD, 1, 650),
- ENSOULED_OGRE_HEAD(ItemID.ENSOULED_OGRE_HEAD, 1, 716),
- ENSOULED_ELF_HEAD(ItemID.ENSOULED_ELF_HEAD, 1, 754),
- ENSOULED_TROLL_HEAD(ItemID.ENSOULED_TROLL_HEAD, 1, 780),
- ENSOULED_HORROR_HEAD(ItemID.ENSOULED_HORROR_HEAD, 1, 832),
- ENSOULED_KALPHITE_HEAD(ItemID.ENSOULED_KALPHITE_HEAD, 1, 884),
- ENSOULED_DAGANNOTH_HEAD(ItemID.ENSOULED_DAGANNOTH_HEAD, 1, 936),
- ENSOULED_BLOODVELD_HEAD(ItemID.ENSOULED_BLOODVELD_HEAD, 1, 1040),
- ENSOULED_TZHAAR_HEAD(ItemID.ENSOULED_TZHAAR_HEAD, 1, 1104),
- ENSOULED_DEMON_HEAD(ItemID.ENSOULED_DEMON_HEAD, 1, 1170),
- ENSOULED_HELLHOUND_HEAD(ItemID.ENSOULED_HELLHOUND_HEAD, 1, 1200),
- ENSOULED_AVIANSIE_HEAD(ItemID.ENSOULED_AVIANSIE_HEAD, 1, 1234),
- ENSOULED_ABYSSAL_HEAD(ItemID.ENSOULED_ABYSSAL_HEAD, 1, 1300),
- ENSOULED_DRAGON_HEAD(ItemID.ENSOULED_DRAGON_HEAD, 1, 1560),
- FIENDISH_ASHES(ItemID.FIENDISH_ASHES, 1, 10, PrayerBonus.DEMONIC_OFFERING),
- VILE_ASHES(ItemID.VILE_ASHES, 1, 25, PrayerBonus.DEMONIC_OFFERING),
- MALICIOUS_ASHES(ItemID.MALICIOUS_ASHES, 1, 65, PrayerBonus.DEMONIC_OFFERING),
- ABYSSAL_ASHES(ItemID.ABYSSAL_ASHES, 1, 85, PrayerBonus.DEMONIC_OFFERING),
- INFERNAL_ASHES(ItemID.INFERNAL_ASHES, 1, 110, PrayerBonus.DEMONIC_OFFERING),
- BONES(ItemID.BONES, 1, 4.5f, PrayerBonus.BONE_BONUSES),
- WOLF_BONES(ItemID.WOLF_BONES, 1, 4.5f, PrayerBonus.BONE_BONUSES),
- LOAR_REMAINS(ItemID.LOAR_REMAINS, 1, 33, PrayerBonus.MORYTANIA_DIARY_3_SHADES),
- BURNT_BONES(ItemID.BURNT_BONES, 1, 4.5f, PrayerBonus.BONE_BONUSES),
- MONKEY_BONES(ItemID.MONKEY_BONES, 1, 5, PrayerBonus.BONE_BONUSES),
- BAT_BONES(ItemID.BAT_BONES, 1, 5.3f, PrayerBonus.BONE_BONUSES),
- JOGRE_BONES(ItemID.JOGRE_BONES, 1, 15, PrayerBonus.BONE_BONUSES),
- BIG_BONES(ItemID.BIG_BONES, 1, 15, PrayerBonus.BONE_BONUSES),
- ZOGRE_BONES(ItemID.ZOGRE_BONES, 1, 22.5f, PrayerBonus.BONE_BONUSES),
- SHAIKAHAN_BONES(ItemID.SHAIKAHAN_BONES, 1, 25, PrayerBonus.BONE_BONUSES),
- BABYDRAGON_BONES(ItemID.BABYDRAGON_BONES, 1, 30, PrayerBonus.BONE_BONUSES),
- PHRIN_REMAINS(ItemID.PHRIN_REMAINS, 1, 46.5f, PrayerBonus.MORYTANIA_DIARY_3_SHADES),
- WYRM_BONES(ItemID.WYRM_BONES, 1, 50, PrayerBonus.BONE_BONUSES),
- RIYL_REMAINS(ItemID.RIYL_REMAINS, 1, 59.5f, PrayerBonus.MORYTANIA_DIARY_3_SHADES),
- WYVERN_BONES(ItemID.WYVERN_BONES, 1, 72, PrayerBonus.BONE_BONUSES),
- DRAGON_BONES(ItemID.DRAGON_BONES, 1, 72, PrayerBonus.BONE_BONUSES),
- DRAKE_BONES(ItemID.DRAKE_BONES, 1, 80, PrayerBonus.BONE_BONUSES),
- ASYN_REMAINS(ItemID.ASYN_REMAINS, 1, 82.5f, PrayerBonus.MORYTANIA_DIARY_3_SHADES),
- FAYRG_BONES(ItemID.FAYRG_BONES, 1, 84, PrayerBonus.BONE_BONUSES),
- FIYR_REMAINS(ItemID.FIYR_REMAINS, 1, 84, PrayerBonus.MORYTANIA_DIARY_3_SHADES),
- LAVA_DRAGON_BONES(ItemID.LAVA_DRAGON_BONES, 1, 85, PrayerBonus.BONE_BONUSES),
- RAURG_BONES(ItemID.RAURG_BONES, 1, 96, PrayerBonus.BONE_BONUSES),
- HYDRA_BONES(ItemID.HYDRA_BONES, 1, 110, PrayerBonus.BONE_BONUSES),
- DAGANNOTH_BONES(ItemID.DAGANNOTH_BONES, 1, 125, PrayerBonus.BONE_BONUSES),
- OURG_BONES(ItemID.OURG_BONES, 1, 140, PrayerBonus.BONE_BONUSES),
- URIUM_REMAINS(ItemID.URIUM_REMAINS, 1, 120, PrayerBonus.MORYTANIA_DIARY_3_SHADES),
- GUPPY(ItemID.GUPPY, 1, 4),
- CAVEFISH(ItemID.CAVEFISH, 1, 7),
- TETRA(ItemID.TETRA, 1, 10),
- CATFISH(ItemID.CATFISH, 1, 16),
- SUPERIOR_DRAGON_BONES(ItemID.SUPERIOR_DRAGON_BONES, 70, 150, PrayerBonus.BONE_BONUSES),
+ GUPPY(ItemID.GUPPY, 1, 4, PrayerMethod.PREPARED_FISH),
+ BONES(ItemID.BONES, 1, 4.5f, PrayerMethod.BONES),
+ BURNT_BONES(ItemID.BURNT_BONES, 1, 4.5f, PrayerMethod.BONES),
+ WOLF_BONES(ItemID.WOLF_BONES, 1, 4.5f, PrayerMethod.BONES),
+ MONKEY_BONES(ItemID.MONKEY_BONES, 1, 5, PrayerMethod.BONES),
+ BAT_BONES(ItemID.BAT_BONES, 1, 5.3f, PrayerMethod.BONES),
+ CAVEFISH(ItemID.CAVEFISH, 1, 7, PrayerMethod.PREPARED_FISH),
+ FIENDISH_ASHES(ItemID.FIENDISH_ASHES, 1, 10, PrayerMethod.DEMONIC_ASHES),
+ TETRA(ItemID.TETRA, 1, 10, PrayerMethod.PREPARED_FISH),
+ BIG_BONES(ItemID.BIG_BONES, 1, 15, PrayerMethod.BONES),
+ JOGRE_BONES(ItemID.JOGRE_BONES, 1, 15, PrayerMethod.BONES),
+ CATFISH(ItemID.CATFISH, 1, 16, PrayerMethod.PREPARED_FISH),
+ WYRMLING_BONES(ItemID.WYRMLING_BONES, 1, 21, PrayerMethod.BONES),
+ ZOGRE_BONES(ItemID.ZOGRE_BONES, 1, 22.5f, PrayerMethod.BONES),
+ SHAIKAHAN_BONES(ItemID.SHAIKAHAN_BONES, 1, 25, PrayerMethod.BONES),
+ VILE_ASHES(ItemID.VILE_ASHES, 1, 25, PrayerMethod.DEMONIC_ASHES),
+ BABYDRAGON_BONES(ItemID.BABYDRAGON_BONES, 1, 30, PrayerMethod.BONES),
+ LOAR_REMAINS(ItemID.LOAR_REMAINS, 1, 33, PrayerMethod.SHADE_REMAINS),
+ PHRIN_REMAINS(ItemID.PHRIN_REMAINS, 1, 46.5f, PrayerMethod.SHADE_REMAINS),
+ WYRM_BONES(ItemID.WYRM_BONES, 1, 50, PrayerMethod.BONES),
+ RIYL_REMAINS(ItemID.RIYL_REMAINS, 1, 59.5f, PrayerMethod.SHADE_REMAINS),
+ MALICIOUS_ASHES(ItemID.MALICIOUS_ASHES, 1, 65, PrayerMethod.DEMONIC_ASHES),
+ DRAGON_BONES(ItemID.DRAGON_BONES, 1, 72, PrayerMethod.BONES),
+ WYVERN_BONES(ItemID.WYVERN_BONES, 1, 72, PrayerMethod.BONES),
+ DRAKE_BONES(ItemID.DRAKE_BONES, 1, 80, PrayerMethod.BONES),
+ ASYN_REMAINS(ItemID.ASYN_REMAINS, 1, 82.5f, PrayerMethod.SHADE_REMAINS),
+ FAYRG_BONES(ItemID.FAYRG_BONES, 1, 84, PrayerMethod.BONES),
+ FIYR_REMAINS(ItemID.FIYR_REMAINS, 1, 84, PrayerMethod.SHADE_REMAINS),
+ ABYSSAL_ASHES(ItemID.ABYSSAL_ASHES, 1, 85, PrayerMethod.DEMONIC_ASHES),
+ LAVA_DRAGON_BONES(ItemID.LAVA_DRAGON_BONES, 1, 85, PrayerMethod.BONES),
+ RAURG_BONES(ItemID.RAURG_BONES, 1, 96, PrayerMethod.BONES),
+ HYDRA_BONES(ItemID.HYDRA_BONES, 1, 110, PrayerMethod.BONES),
+ INFERNAL_ASHES(ItemID.INFERNAL_ASHES, 1, 110, PrayerMethod.DEMONIC_ASHES),
+ URIUM_REMAINS(ItemID.URIUM_REMAINS, 1, 120, PrayerMethod.SHADE_REMAINS),
+ DAGANNOTH_BONES(ItemID.DAGANNOTH_BONES, 1, 125, PrayerMethod.BONES),
+ ENSOULED_GOBLIN_HEAD(ItemID.ENSOULED_GOBLIN_HEAD, 1, 130, PrayerMethod.ENSOULED_HEAD),
+ OURG_BONES(ItemID.OURG_BONES, 1, 140, PrayerMethod.BONES),
+ ENSOULED_MONKEY_HEAD(ItemID.ENSOULED_MONKEY_HEAD, 1, 182, PrayerMethod.ENSOULED_HEAD),
+ ENSOULED_IMP_HEAD(ItemID.ENSOULED_IMP_HEAD, 1, 286, PrayerMethod.ENSOULED_HEAD),
+ ENSOULED_MINOTAUR_HEAD(ItemID.ENSOULED_MINOTAUR_HEAD, 1, 364, PrayerMethod.ENSOULED_HEAD),
+ ENSOULED_SCORPION_HEAD(ItemID.ENSOULED_SCORPION_HEAD, 1, 454, PrayerMethod.ENSOULED_HEAD),
+ ENSOULED_BEAR_HEAD(ItemID.ENSOULED_BEAR_HEAD, 1, 480, PrayerMethod.ENSOULED_HEAD),
+ ENSOULED_UNICORN_HEAD(ItemID.ENSOULED_UNICORN_HEAD, 1, 494, PrayerMethod.ENSOULED_HEAD),
+ ENSOULED_DOG_HEAD(ItemID.ENSOULED_DOG_HEAD, 1, 520, PrayerMethod.ENSOULED_HEAD),
+ ENSOULED_CHAOS_DRUID_HEAD(ItemID.ENSOULED_CHAOS_DRUID_HEAD, 1, 584, PrayerMethod.ENSOULED_HEAD),
+ ENSOULED_GIANT_HEAD(ItemID.ENSOULED_GIANT_HEAD, 1, 650, PrayerMethod.ENSOULED_HEAD),
+ ENSOULED_OGRE_HEAD(ItemID.ENSOULED_OGRE_HEAD, 1, 716, PrayerMethod.ENSOULED_HEAD),
+ ENSOULED_ELF_HEAD(ItemID.ENSOULED_ELF_HEAD, 1, 754, PrayerMethod.ENSOULED_HEAD),
+ ENSOULED_TROLL_HEAD(ItemID.ENSOULED_TROLL_HEAD, 1, 780, PrayerMethod.ENSOULED_HEAD),
+ ENSOULED_HORROR_HEAD(ItemID.ENSOULED_HORROR_HEAD, 1, 832, PrayerMethod.ENSOULED_HEAD),
+ ENSOULED_KALPHITE_HEAD(ItemID.ENSOULED_KALPHITE_HEAD, 1, 884, PrayerMethod.ENSOULED_HEAD),
+ ENSOULED_DAGANNOTH_HEAD(ItemID.ENSOULED_DAGANNOTH_HEAD, 1, 936, PrayerMethod.ENSOULED_HEAD),
+ ENSOULED_BLOODVELD_HEAD(ItemID.ENSOULED_BLOODVELD_HEAD, 1, 1040, PrayerMethod.ENSOULED_HEAD),
+ ENSOULED_TZHAAR_HEAD(ItemID.ENSOULED_TZHAAR_HEAD, 1, 1104, PrayerMethod.ENSOULED_HEAD),
+ ENSOULED_DEMON_HEAD(ItemID.ENSOULED_DEMON_HEAD, 1, 1170, PrayerMethod.ENSOULED_HEAD),
+ ENSOULED_HELLHOUND_HEAD(ItemID.ENSOULED_HELLHOUND_HEAD, 1, 1200, PrayerMethod.ENSOULED_HEAD),
+ ENSOULED_AVIANSIE_HEAD(ItemID.ENSOULED_AVIANSIE_HEAD, 1, 1234, PrayerMethod.ENSOULED_HEAD),
+ ENSOULED_ABYSSAL_HEAD(ItemID.ENSOULED_ABYSSAL_HEAD, 1, 1300, PrayerMethod.ENSOULED_HEAD),
+ ENSOULED_DRAGON_HEAD(ItemID.ENSOULED_DRAGON_HEAD, 1, 1560, PrayerMethod.ENSOULED_HEAD),
+ BLESSED_BONE_SHARDS(ItemID.BLESSED_BONE_SHARDS, 30, 5, PrayerMethod.BLESSED_SUNFIRE_WINE),
+ SUPERIOR_DRAGON_BONES(ItemID.SUPERIOR_DRAGON_BONES, 70, 150, PrayerMethod.BONES),
;
+ private enum PrayerMethod
+ {
+ BONES,
+ DEMONIC_ASHES,
+ ENSOULED_HEAD,
+ PREPARED_FISH,
+ SHADE_REMAINS,
+ BLESSED_SUNFIRE_WINE,
+ }
+
+ private static final Set EXCLUDED_BONUSES_FOR_BONES = EnumSet.of(
+ MORYTANIA_DIARY_3_SHADES,
+ DEMONIC_OFFERING,
+ BLESSED_SUNFIRE_WINE
+ );
+ private static final Set EXCLUDED_BONUSES_FOR_ASHES = EnumSet.complementOf(EnumSet.of(DEMONIC_OFFERING));
+ private static final Set EXCLUDED_BONUSES_FOR_REMAINS = EnumSet.complementOf(EnumSet.of(MORYTANIA_DIARY_3_SHADES));
+ private static final Set EXCLUDED_BONUSES_FOR_BLESSED_SUNFIRE_WINE = EnumSet.complementOf(EnumSet.of(ZEALOT_ROBES, BLESSED_SUNFIRE_WINE));
+ private static final Set EXCLUDE_ALL_EXCEPT_ZEALOT_ROBES = EnumSet.complementOf(EnumSet.of(ZEALOT_ROBES));
+
private final int itemId;
private final int level;
private final float xp;
- private final EnumSet applicableBonuses;
-
- PrayerAction(int itemId, int level, float xp, PrayerBonus... applicableBonuses)
- {
- this.itemId = itemId;
- this.level = level;
- this.xp = xp;
- this.applicableBonuses = EnumSet.noneOf(PrayerBonus.class);
- this.applicableBonuses.addAll(Arrays.asList(applicableBonuses));
- }
+ private final PrayerMethod methodType;
@Override
- public boolean isBonusApplicable(SkillBonus skillBonus)
+ public Set getExcludedSkillBonuses()
{
- return skillBonus instanceof PrayerBonus && applicableBonuses.contains(skillBonus);
+ switch (getMethodType())
+ {
+ case BONES:
+ return EXCLUDED_BONUSES_FOR_BONES;
+ case DEMONIC_ASHES:
+ return EXCLUDED_BONUSES_FOR_ASHES;
+ case ENSOULED_HEAD:
+ case PREPARED_FISH:
+ return EXCLUDE_ALL_EXCEPT_ZEALOT_ROBES;
+ case SHADE_REMAINS:
+ return EXCLUDED_BONUSES_FOR_REMAINS;
+ case BLESSED_SUNFIRE_WINE:
+ return EXCLUDED_BONUSES_FOR_BLESSED_SUNFIRE_WINE;
+ default:
+ return EnumSet.allOf(PrayerBonus.class);
+ }
}
}
diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/skillcalculator/skills/PrayerBonus.java b/runelite-client/src/main/java/net/runelite/client/plugins/skillcalculator/skills/PrayerBonus.java
index fe19f43b8b..d512790c7a 100644
--- a/runelite-client/src/main/java/net/runelite/client/plugins/skillcalculator/skills/PrayerBonus.java
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/skillcalculator/skills/PrayerBonus.java
@@ -24,6 +24,8 @@
*/
package net.runelite.client.plugins.skillcalculator.skills;
+import java.util.EnumSet;
+import java.util.Set;
import lombok.AllArgsConstructor;
import lombok.Getter;
@@ -31,25 +33,38 @@
@Getter(onMethod_ = @Override)
public enum PrayerBonus implements SkillBonus
{
- LIT_GILDED_ALTAR("Lit Gilded Altar (350%)", 3.5f),
- ECTOFUNTUS("Ectofuntus (400%)", 4),
- CHAOS_ALTAR("Chaos Altar (700%)", 7),
- MORYTANIA_DIARY_3_SHADES("Morytania Diary 3 Shades (150%)", 1.5f),
- BONECRUSHER("Bonecrusher (50%)", 0.5f),
- SINISTER_OFFERING("Sinister Offering (300%)", 3),
- DEMONIC_OFFERING("Demonic Offering (300%)", 3),
- SACRED_BONE_BURNER("Sacred Bone Burner (300%)", 3),
+ BONECRUSHER("Bonecrusher", 0.5f),
+ SACRED_BONE_BURNER("Sacred Bone Burner", 3),
+ SINISTER_OFFERING("Sinister Offering", 3),
+ LIT_GILDED_ALTAR("Lit Gilded Altar", 3.5f),
+ ECTOFUNTUS("Ectofuntus", 4),
+ CHAOS_ALTAR("Chaos Altar", 7),
+ BLESSED_SUNFIRE_WINE("Blessed Sunfire Wine", 1.2f),
+ DEMONIC_OFFERING("Demonic Offering", 3),
+ MORYTANIA_DIARY_3_SHADES("Morytania Diary 3 Shades", 1.5f),
+ ZEALOT_ROBES("Zealot Robes", 1.05f),
;
- static final PrayerBonus[] BONE_BONUSES = {
- LIT_GILDED_ALTAR,
- ECTOFUNTUS,
- CHAOS_ALTAR,
- BONECRUSHER,
- SINISTER_OFFERING,
- SACRED_BONE_BURNER,
- };
-
private final String name;
private final float value;
+
+ @Override
+ public Set getCanBeStackedWith()
+ {
+ switch (this)
+ {
+ case ECTOFUNTUS:
+ case LIT_GILDED_ALTAR:
+ case CHAOS_ALTAR:
+ case SINISTER_OFFERING:
+ return EnumSet.complementOf(EnumSet.of(ECTOFUNTUS, LIT_GILDED_ALTAR, CHAOS_ALTAR, SINISTER_OFFERING, SACRED_BONE_BURNER, BONECRUSHER));
+ case BONECRUSHER:
+ case SACRED_BONE_BURNER:
+ return EnumSet.complementOf(EnumSet.of(ECTOFUNTUS, LIT_GILDED_ALTAR, CHAOS_ALTAR, SINISTER_OFFERING, SACRED_BONE_BURNER, BONECRUSHER, ZEALOT_ROBES));
+ case ZEALOT_ROBES:
+ return EnumSet.complementOf(EnumSet.of(BONECRUSHER, SACRED_BONE_BURNER, ZEALOT_ROBES));
+ default:
+ return EnumSet.complementOf(EnumSet.of(this));
+ }
+ }
}
diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/skillcalculator/skills/RunecraftAction.java b/runelite-client/src/main/java/net/runelite/client/plugins/skillcalculator/skills/RunecraftAction.java
index 2e1c1b586b..6820a7abc4 100644
--- a/runelite-client/src/main/java/net/runelite/client/plugins/skillcalculator/skills/RunecraftAction.java
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/skillcalculator/skills/RunecraftAction.java
@@ -24,6 +24,9 @@
*/
package net.runelite.client.plugins.skillcalculator.skills;
+import java.util.Collections;
+import java.util.EnumSet;
+import java.util.Set;
import lombok.AllArgsConstructor;
import lombok.Getter;
import net.runelite.api.ItemID;
@@ -33,6 +36,7 @@
@Getter
public enum RunecraftAction implements ItemSkillAction
{
+ AIR_RUNE(ItemID.AIR_RUNE, 1, 5, false),
AIR_TIARA(ItemID.AIR_TIARA, 1, 25, true),
MIND_TIARA(ItemID.MIND_TIARA, 1, 27.5f, true),
WATER_TIARA(ItemID.WATER_TIARA, 1, 30, true),
@@ -45,7 +49,6 @@ public enum RunecraftAction implements ItemSkillAction
LAW_TIARA(ItemID.LAW_TIARA, 1, 47.5f, true),
DEATH_TIARA(ItemID.DEATH_TIARA, 1, 50, true),
WRATH_TIARA(ItemID.WRATH_TIARA, 1, 52.5f, true),
- AIR_RUNE(ItemID.AIR_RUNE, 1, 5, false),
MIND_RUNE(ItemID.MIND_RUNE, 2, 5.5f, false),
MIND_CORE(ItemID.MIND_CORE, 2, 55, true),
WATER_RUNE(ItemID.WATER_RUNE, 5, 6, false),
@@ -60,32 +63,35 @@ public enum RunecraftAction implements ItemSkillAction
BODY_CORE(ItemID.BODY_CORE, 20, 75, true),
LAVA_RUNE(ItemID.LAVA_RUNE, 23, 10.5f, false),
COSMIC_RUNE(ItemID.COSMIC_RUNE, 27, 8, false, true),
+ SUNFIRE_RUNE(ItemID.SUNFIRE_RUNE, 33, 9, false),
CHAOS_RUNE(ItemID.CHAOS_RUNE, 35, 8.5f, false, true),
CHAOS_CORE(ItemID.CHAOS_CORE, 35, 85, true),
ASTRAL_RUNE(ItemID.ASTRAL_RUNE, 40, 8.7f, false),
NATURE_RUNE(ItemID.NATURE_RUNE, 44, 9, false, true),
LAW_RUNE(ItemID.LAW_RUNE, 54, 9.5f, false, true),
DEATH_RUNE(ItemID.DEATH_RUNE, 65, 10, false, true),
- ZEAH_BLOOD_RUNE(ItemID.BLOOD_RUNE, 77, 24.425f, true)
+ TRUE_BLOOD_RUNE(ItemID.BLOOD_RUNE, 77, 10.5f, false)
{
@Override
public String getName(final ItemManager itemManager)
{
- return "Blood rune (Zeah)";
+ return "Blood rune (True Altar)";
}
},
- TRUE_BLOOD_RUNE(ItemID.BLOOD_RUNE, 77, 10.5f, false)
+ ZEAH_BLOOD_RUNE(ItemID.BLOOD_RUNE, 77, 24.425f, true)
{
@Override
public String getName(final ItemManager itemManager)
{
- return "Blood rune (True Altar)";
+ return "Blood rune (Zeah)";
}
},
SOUL_RUNE(ItemID.SOUL_RUNE, 90, 30.325f, true),
WRATH_RUNE(ItemID.WRATH_RUNE, 95, 8, false),
;
+ private static final Set RUNECRAFT_BONUSES = EnumSet.allOf(RunecraftBonus.class);
+
private final int itemId;
private final int level;
private final float xp;
@@ -98,8 +104,13 @@ public String getName(final ItemManager itemManager)
}
@Override
- public boolean isBonusApplicable(SkillBonus bonus)
+ public Set getExcludedSkillBonuses()
{
- return !ignoreBonus;
+ if (ignoreBonus)
+ {
+ return RUNECRAFT_BONUSES;
+ }
+
+ return Collections.emptySet();
}
}
diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/skillcalculator/skills/RunecraftBonus.java b/runelite-client/src/main/java/net/runelite/client/plugins/skillcalculator/skills/RunecraftBonus.java
index 85bd47facd..c64fb13113 100644
--- a/runelite-client/src/main/java/net/runelite/client/plugins/skillcalculator/skills/RunecraftBonus.java
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/skillcalculator/skills/RunecraftBonus.java
@@ -31,7 +31,7 @@
@Getter(onMethod_ = @Override)
public enum RunecraftBonus implements SkillBonus
{
- DAEYALT_ESSENCE("Daeyalt essence (+50%)", 1.5f),
+ DAEYALT_ESSENCE("Daeyalt essence", 1.5f),
;
private final String name;
diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/skillcalculator/skills/SkillAction.java b/runelite-client/src/main/java/net/runelite/client/plugins/skillcalculator/skills/SkillAction.java
index ec9a7726ab..fe5dd97ca6 100644
--- a/runelite-client/src/main/java/net/runelite/client/plugins/skillcalculator/skills/SkillAction.java
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/skillcalculator/skills/SkillAction.java
@@ -24,6 +24,8 @@
*/
package net.runelite.client.plugins.skillcalculator.skills;
+import java.util.Collections;
+import java.util.Set;
import net.runelite.api.ItemComposition;
import net.runelite.client.game.ItemManager;
@@ -92,8 +94,13 @@ default int getSprite()
*/
default boolean isBonusApplicable(SkillBonus bonus)
{
- return true;
+ return !getExcludedSkillBonuses().contains(bonus);
}
boolean isMembers(final ItemManager itemManager);
+
+ default Set extends SkillBonus> getExcludedSkillBonuses()
+ {
+ return Collections.emptySet();
+ }
}
diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/skillcalculator/skills/SkillBonus.java b/runelite-client/src/main/java/net/runelite/client/plugins/skillcalculator/skills/SkillBonus.java
index 2ff350b58a..69afd5e489 100644
--- a/runelite-client/src/main/java/net/runelite/client/plugins/skillcalculator/skills/SkillBonus.java
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/skillcalculator/skills/SkillBonus.java
@@ -24,6 +24,9 @@
*/
package net.runelite.client.plugins.skillcalculator.skills;
+import java.util.Collections;
+import java.util.Set;
+
/**
* An object representing a skill bonus, such as from a skilling outfit or activity granting boosted xp.
*/
@@ -44,4 +47,15 @@ public interface SkillBonus
* @return The skill bonus multiplier.
*/
float getValue();
+
+
+ /**
+ * Gets the list of skill bonuses this skill bonus can be stacked with.
+ *
+ * @return List of stackable skill bonuses
+ */
+ default Set extends SkillBonus> getCanBeStackedWith()
+ {
+ return Collections.emptySet();
+ }
}
diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/skillcalculator/skills/SmithingAction.java b/runelite-client/src/main/java/net/runelite/client/plugins/skillcalculator/skills/SmithingAction.java
index 46275cc703..a2662c87cf 100644
--- a/runelite-client/src/main/java/net/runelite/client/plugins/skillcalculator/skills/SmithingAction.java
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/skillcalculator/skills/SmithingAction.java
@@ -24,10 +24,11 @@
*/
package net.runelite.client.plugins.skillcalculator.skills;
+import java.util.EnumSet;
+import java.util.Set;
import lombok.AllArgsConstructor;
import lombok.Getter;
import net.runelite.api.ItemID;
-import net.runelite.client.game.ItemManager;
@AllArgsConstructor
@Getter
@@ -37,19 +38,19 @@ public enum SmithingAction implements ItemSkillAction
BRONZE_AXE(ItemID.BRONZE_AXE, 1, 12.5f),
BRONZE_DAGGER(ItemID.BRONZE_DAGGER, 1, 12.5f),
BRONZE_MACE(ItemID.BRONZE_MACE, 2, 12.5f),
- BRONZE_MED_HELM(ItemID.BRONZE_MED_HELM, 3, 12.5f),
BRONZE_BOLTS_UNF(ItemID.BRONZE_BOLTS_UNF, 3, 12.5f),
+ BRONZE_MED_HELM(ItemID.BRONZE_MED_HELM, 3, 12.5f),
+ BRONZE_DART_TIP(ItemID.BRONZE_DART_TIP, 4, 12.5f),
BRONZE_NAILS(ItemID.BRONZE_NAILS, 4, 12.5f),
BRONZE_SWORD(ItemID.BRONZE_SWORD, 4, 12.5f),
BRONZE_WIRE(ItemID.BRONZE_WIRE, 4, 12.5f),
- BRONZE_DART_TIP(ItemID.BRONZE_DART_TIP, 4, 12.5f),
BRONZE_ARROWTIPS(ItemID.BRONZE_ARROWTIPS, 5, 12.5f),
- BRONZE_SCIMITAR(ItemID.BRONZE_SCIMITAR, 5, 25),
BRONZE_HASTA(ItemID.BRONZE_HASTA, 5, 25),
+ BRONZE_SCIMITAR(ItemID.BRONZE_SCIMITAR, 5, 25),
BRONZE_SPEAR(ItemID.BRONZE_SPEAR, 5, 25),
BRONZE_JAVELIN_HEADS(ItemID.BRONZE_JAVELIN_HEADS, 6, 12.5f),
- BRONZE_LONGSWORD(ItemID.BRONZE_LONGSWORD, 6, 25),
BRONZE_LIMBS(ItemID.BRONZE_LIMBS, 6, 12.5f),
+ BRONZE_LONGSWORD(ItemID.BRONZE_LONGSWORD, 6, 25),
BRONZE_KNIFE(ItemID.BRONZE_KNIFE, 7, 12.5f),
BRONZE_FULL_HELM(ItemID.BRONZE_FULL_HELM, 7, 25),
BRONZE_SQ_SHIELD(ItemID.BRONZE_SQ_SHIELD, 8, 25),
@@ -58,30 +59,30 @@ public enum SmithingAction implements ItemSkillAction
BRONZE_CHAINBODY(ItemID.BRONZE_CHAINBODY, 11, 37.5f),
BRONZE_KITESHIELD(ItemID.BRONZE_KITESHIELD, 12, 37.5f),
BRONZE_CLAWS(ItemID.BRONZE_CLAWS, 13, 25),
- BRONZE_2H_SWORD(ItemID.BRONZE_2H_SWORD, 14, 37.5f),
BARRONITE_DEPOSITS(ItemID.BARRONITE_DEPOSIT, 14, 30),
+ BRONZE_2H_SWORD(ItemID.BRONZE_2H_SWORD, 14, 37.5f),
IRON_BAR(ItemID.IRON_BAR, 15, 12.5f),
IRON_DAGGER(ItemID.IRON_DAGGER, 15, 25),
IRON_AXE(ItemID.IRON_AXE, 16, 25),
BRONZE_PLATELEGS(ItemID.BRONZE_PLATELEGS, 16, 37.5f),
BRONZE_PLATESKIRT(ItemID.BRONZE_PLATESKIRT, 16, 37.5f),
- IRON_SPIT(ItemID.IRON_SPIT, 17, 25),
IRON_MACE(ItemID.IRON_MACE, 17, 25),
+ IRON_SPIT(ItemID.IRON_SPIT, 17, 25),
IRON_BOLTS_UNF(ItemID.IRON_BOLTS_UNF, 18, 25),
- BRONZE_PLATEBODY(ItemID.BRONZE_PLATEBODY, 18, 62.5f),
IRON_MED_HELM(ItemID.IRON_MED_HELM, 18, 25),
- IRON_NAILS(ItemID.IRON_NAILS, 19, 25),
+ BRONZE_PLATEBODY(ItemID.BRONZE_PLATEBODY, 18, 62.5f),
IRON_DART_TIP(ItemID.IRON_DART_TIP, 19, 25),
+ IRON_NAILS(ItemID.IRON_NAILS, 19, 25),
IRON_SWORD(ItemID.IRON_SWORD, 19, 25),
SILVER_BAR(ItemID.SILVER_BAR, 20, 13.7f),
IRON_ARROWTIPS(ItemID.IRON_ARROWTIPS, 20, 25),
- IRON_SCIMITAR(ItemID.IRON_SCIMITAR, 20, 50),
IRON_HASTA(ItemID.IRON_HASTA, 20, 50),
+ IRON_SCIMITAR(ItemID.IRON_SCIMITAR, 20, 50),
IRON_SPEAR(ItemID.IRON_SPEAR, 20, 50),
- IRON_LONGSWORD(ItemID.IRON_LONGSWORD, 21, 50),
IRON_JAVELIN_HEADS(ItemID.IRON_JAVELIN_HEADS, 21, 25),
- IRON_FULL_HELM(ItemID.IRON_FULL_HELM, 22, 50),
+ IRON_LONGSWORD(ItemID.IRON_LONGSWORD, 21, 50),
IRON_KNIFE(ItemID.IRON_KNIFE, 22, 25),
+ IRON_FULL_HELM(ItemID.IRON_FULL_HELM, 22, 50),
IRON_LIMBS(ItemID.IRON_LIMBS, 23, 25),
IRON_SQ_SHIELD(ItemID.IRON_SQ_SHIELD, 23, 50),
IRON_WARHAMMER(ItemID.IRON_WARHAMMER, 24, 75),
@@ -91,47 +92,33 @@ public enum SmithingAction implements ItemSkillAction
IRON_KITESHIELD(ItemID.IRON_KITESHIELD, 27, 75),
IRON_CLAWS(ItemID.IRON_CLAWS, 28, 50),
IRON_2H_SWORD(ItemID.IRON_2H_SWORD, 29, 75),
- STEEL_DAGGER(ItemID.STEEL_DAGGER, 30, 37.5f),
STEEL_BAR(ItemID.STEEL_BAR, 30, 17.5f),
- IRON_PLATESKIRT(ItemID.IRON_PLATESKIRT, 31, 75),
- IRON_PLATELEGS(ItemID.IRON_PLATELEGS, 31, 75),
+ STEEL_DAGGER(ItemID.STEEL_DAGGER, 30, 37.5f),
STEEL_AXE(ItemID.STEEL_AXE, 31, 37.5f),
+ IRON_PLATELEGS(ItemID.IRON_PLATELEGS, 31, 75),
+ IRON_PLATESKIRT(ItemID.IRON_PLATESKIRT, 31, 75),
STEEL_MACE(ItemID.STEEL_MACE, 32, 37.5f),
- IRON_PLATEBODY(ItemID.IRON_PLATEBODY, 33, 125),
- STEEL_MED_HELM(ItemID.STEEL_MED_HELM, 33, 37.5f),
STEEL_BOLTS_UNF(ItemID.STEEL_BOLTS_UNF, 33, 37.5f),
+ STEEL_MED_HELM(ItemID.STEEL_MED_HELM, 33, 37.5f),
+ IRON_PLATEBODY(ItemID.IRON_PLATEBODY, 33, 125),
STEEL_DART_TIP(ItemID.STEEL_DART_TIP, 34, 37.5f),
STEEL_NAILS(ItemID.STEEL_NAILS, 34, 37.5f),
STEEL_SWORD(ItemID.STEEL_SWORD, 34, 37.5f),
CANNONBALL(ItemID.CANNONBALL, 35, 25.6f),
- STEEL_SCIMITAR(ItemID.STEEL_SCIMITAR, 35, 75),
STEEL_ARROWTIPS(ItemID.STEEL_ARROWTIPS, 35, 37.5f),
STEEL_HASTA(ItemID.STEEL_HASTA, 35, 75),
+ STEEL_SCIMITAR(ItemID.STEEL_SCIMITAR, 35, 75),
STEEL_SPEAR(ItemID.STEEL_SPEAR, 35, 75),
+ STEEL_JAVELIN_HEADS(ItemID.STEEL_JAVELIN_HEADS, 36, 37.5f),
STEEL_LIMBS(ItemID.STEEL_LIMBS, 36, 37.5f),
STEEL_STUDS(ItemID.STEEL_STUDS, 36, 37.5f),
STEEL_LONGSWORD(ItemID.STEEL_LONGSWORD, 36, 75),
- STEEL_JAVELIN_HEADS(ItemID.STEEL_JAVELIN_HEADS, 36, 37.5f),
STEEL_KNIFE(ItemID.STEEL_KNIFE, 37, 37.5f),
STEEL_FULL_HELM(ItemID.STEEL_FULL_HELM, 37, 75),
STEEL_SQ_SHIELD(ItemID.STEEL_SQ_SHIELD, 38, 75),
STEEL_WARHAMMER(ItemID.STEEL_WARHAMMER, 39, 112.5f),
- STEEL_BATTLEAXE(ItemID.STEEL_BATTLEAXE, 40, 112.5f),
- GOLD_BAR_GOLDSMITH_GAUNTLETS(ItemID.GOLD_BAR, 40, 56.2f)
- {
- @Override
- public String getName(final ItemManager itemManager)
- {
- return "Gold bar (Goldsmith gauntlets)";
- }
-
- @Override
- public boolean isMembers(final ItemManager itemManager)
- {
- return true;
- }
- },
GOLD_BAR(ItemID.GOLD_BAR, 40, 22.5f),
+ STEEL_BATTLEAXE(ItemID.STEEL_BATTLEAXE, 40, 112.5f),
STEEL_CHAINBODY(ItemID.STEEL_CHAINBODY, 41, 112.5f),
STEEL_KITESHIELD(ItemID.STEEL_KITESHIELD, 42, 112.5f),
STEEL_CLAWS(ItemID.STEEL_CLAWS, 43, 75),
@@ -140,24 +127,24 @@ public boolean isMembers(final ItemManager itemManager)
STEEL_PLATESKIRT(ItemID.STEEL_PLATESKIRT, 46, 112.5f),
STEEL_PLATEBODY(ItemID.STEEL_PLATEBODY, 48, 187.5f),
BULLSEYE_LANTERN_UNF(ItemID.BULLSEYE_LANTERN_UNF, 49, 37),
- MITHRIL_DAGGER(ItemID.MITHRIL_DAGGER, 50, 50),
MITHRIL_BAR(ItemID.MITHRIL_BAR, 50, 30),
+ MITHRIL_DAGGER(ItemID.MITHRIL_DAGGER, 50, 50),
MITHRIL_AXE(ItemID.MITHRIL_AXE, 51, 50),
MITHRIL_MACE(ItemID.MITHRIL_MACE, 52, 50),
- MITHRIL_MED_HELM(ItemID.MITHRIL_MED_HELM, 53, 50),
MITHRIL_BOLTS_UNF(ItemID.MITHRIL_BOLTS_UNF, 53, 50),
- MITHRIL_SWORD(ItemID.MITHRIL_SWORD, 54, 50),
+ MITHRIL_MED_HELM(ItemID.MITHRIL_MED_HELM, 53, 50),
MITHRIL_DART_TIP(ItemID.MITHRIL_DART_TIP, 54, 50),
MITHRIL_NAILS(ItemID.MITHRIL_NAILS, 54, 50),
+ MITHRIL_SWORD(ItemID.MITHRIL_SWORD, 54, 50),
MITHRIL_ARROWTIPS(ItemID.MITHRIL_ARROWTIPS, 55, 50),
- MITHRIL_SCIMITAR(ItemID.MITHRIL_SCIMITAR, 55, 100),
MITHRIL_HASTA(ItemID.MITHRIL_HASTA, 55, 100),
+ MITHRIL_SCIMITAR(ItemID.MITHRIL_SCIMITAR, 55, 100),
MITHRIL_SPEAR(ItemID.MITHRIL_SPEAR, 55, 100),
- MITHRIL_LONGSWORD(ItemID.MITHRIL_LONGSWORD, 56, 100),
MITHRIL_JAVELIN_HEADS(ItemID.MITHRIL_JAVELIN_HEADS, 56, 50),
MITHRIL_LIMBS(ItemID.MITHRIL_LIMBS, 56, 50),
- MITHRIL_FULL_HELM(ItemID.MITHRIL_FULL_HELM, 57, 100),
+ MITHRIL_LONGSWORD(ItemID.MITHRIL_LONGSWORD, 56, 100),
MITHRIL_KNIFE(ItemID.MITHRIL_KNIFE, 57, 50),
+ MITHRIL_FULL_HELM(ItemID.MITHRIL_FULL_HELM, 57, 100),
MITHRIL_SQ_SHIELD(ItemID.MITHRIL_SQ_SHIELD, 58, 100),
MITH_GRAPPLE_TIP(ItemID.MITH_GRAPPLE_TIP, 59, 50),
MITHRIL_WARHAMMER(ItemID.MITHRIL_WARHAMMER, 59, 150),
@@ -167,27 +154,27 @@ public boolean isMembers(final ItemManager itemManager)
MITHRIL_KITESHIELD(ItemID.MITHRIL_KITESHIELD, 62, 150),
MITHRIL_CLAWS(ItemID.MITHRIL_CLAWS, 63, 100),
MITHRIL_2H_SWORD(ItemID.MITHRIL_2H_SWORD, 64, 150),
- MITHRIL_PLATESKIRT(ItemID.MITHRIL_PLATESKIRT, 66, 150),
MITHRIL_PLATELEGS(ItemID.MITHRIL_PLATELEGS, 66, 150),
+ MITHRIL_PLATESKIRT(ItemID.MITHRIL_PLATESKIRT, 66, 150),
MITHRIL_PLATEBODY(ItemID.MITHRIL_PLATEBODY, 68, 250),
- ADAMANT_DAGGER(ItemID.ADAMANT_DAGGER, 70, 62.5f),
ADAMANTITE_BAR(ItemID.ADAMANTITE_BAR, 70, 37.5f),
+ ADAMANT_DAGGER(ItemID.ADAMANT_DAGGER, 70, 62.5f),
ADAMANT_AXE(ItemID.ADAMANT_AXE, 71, 62.5f),
ADAMANT_MACE(ItemID.ADAMANT_MACE, 72, 62.5f),
ADAMANT_BOLTS_UNF(ItemID.ADAMANT_BOLTSUNF, 73, 62.5f),
ADAMANT_MED_HELM(ItemID.ADAMANT_MED_HELM, 73, 62.5f),
+ ADAMANTITE_NAILS(ItemID.ADAMANTITE_NAILS, 74, 62.5f),
ADAMANT_DART_TIP(ItemID.ADAMANT_DART_TIP, 74, 62.5f),
ADAMANT_SWORD(ItemID.ADAMANT_SWORD, 74, 62.5f),
- ADAMANTITE_NAILS(ItemID.ADAMANTITE_NAILS, 74, 62.5f),
ADAMANT_ARROWTIPS(ItemID.ADAMANT_ARROWTIPS, 75, 62.5f),
- ADAMANT_SCIMITAR(ItemID.ADAMANT_SCIMITAR, 75, 125),
ADAMANT_HASTA(ItemID.ADAMANT_HASTA, 75, 125),
+ ADAMANT_SCIMITAR(ItemID.ADAMANT_SCIMITAR, 75, 125),
ADAMANT_SPEAR(ItemID.ADAMANT_SPEAR, 75, 125),
ADAMANTITE_LIMBS(ItemID.ADAMANTITE_LIMBS, 76, 62.5f),
- ADAMANT_LONGSWORD(ItemID.ADAMANT_LONGSWORD, 76, 125),
ADAMANT_JAVELIN_HEADS(ItemID.ADAMANT_JAVELIN_HEADS, 76, 62.5f),
- ADAMANT_FULL_HELM(ItemID.ADAMANT_FULL_HELM, 77, 125),
+ ADAMANT_LONGSWORD(ItemID.ADAMANT_LONGSWORD, 76, 125),
ADAMANT_KNIFE(ItemID.ADAMANT_KNIFE, 77, 62.5f),
+ ADAMANT_FULL_HELM(ItemID.ADAMANT_FULL_HELM, 77, 125),
ADAMANT_SQ_SHIELD(ItemID.ADAMANT_SQ_SHIELD, 78, 125),
ADAMANT_WARHAMMER(ItemID.ADAMANT_WARHAMMER, 79, 187.5f),
ADAMANT_BATTLEAXE(ItemID.ADAMANT_BATTLEAXE, 80, 187.5f),
@@ -198,23 +185,23 @@ public boolean isMembers(final ItemManager itemManager)
RUNITE_BAR(ItemID.RUNITE_BAR, 85, 50),
RUNE_DAGGER(ItemID.RUNE_DAGGER, 85, 75),
RUNE_AXE(ItemID.RUNE_AXE, 86, 75),
- ADAMANT_PLATESKIRT(ItemID.ADAMANT_PLATESKIRT, 86, 187.5f),
ADAMANT_PLATELEGS(ItemID.ADAMANT_PLATELEGS, 86, 187.5f),
+ ADAMANT_PLATESKIRT(ItemID.ADAMANT_PLATESKIRT, 86, 187.5f),
RUNE_MACE(ItemID.RUNE_MACE, 87, 75),
- RUNITE_BOLTS_UNF(ItemID.RUNITE_BOLTS_UNF, 88, 75),
RUNE_MED_HELM(ItemID.RUNE_MED_HELM, 88, 75),
+ RUNITE_BOLTS_UNF(ItemID.RUNITE_BOLTS_UNF, 88, 75),
ADAMANT_PLATEBODY(ItemID.ADAMANT_PLATEBODY, 88, 312.5f),
- RUNE_SWORD(ItemID.RUNE_SWORD, 89, 75),
- RUNE_NAILS(ItemID.RUNE_NAILS, 89, 75),
RUNE_DART_TIP(ItemID.RUNE_DART_TIP, 89, 75),
+ RUNE_NAILS(ItemID.RUNE_NAILS, 89, 75),
+ RUNE_SWORD(ItemID.RUNE_SWORD, 89, 75),
RUNE_ARROWTIPS(ItemID.RUNE_ARROWTIPS, 90, 75),
- RUNE_SCIMITAR(ItemID.RUNE_SCIMITAR, 90, 150),
RUNE_HASTA(ItemID.RUNE_HASTA, 90, 150),
+ RUNE_SCIMITAR(ItemID.RUNE_SCIMITAR, 90, 150),
RUNE_SPEAR(ItemID.RUNE_SPEAR, 90, 150),
DRAGONFIRE_SHIELD(ItemID.DRAGONFIRE_SHIELD, 90, 2000),
- RUNE_LONGSWORD(ItemID.RUNE_LONGSWORD, 91, 150),
RUNE_JAVELIN_HEADS(ItemID.RUNE_JAVELIN_HEADS, 91, 75),
RUNITE_LIMBS(ItemID.RUNITE_LIMBS, 91, 75),
+ RUNE_LONGSWORD(ItemID.RUNE_LONGSWORD, 91, 150),
RUNE_KNIFE(ItemID.RUNE_KNIFE, 92, 75),
RUNE_FULL_HELM(ItemID.RUNE_FULL_HELM, 92, 150),
RUNE_SQ_SHIELD(ItemID.RUNE_SQ_SHIELD, 93, 150),
@@ -223,13 +210,26 @@ public boolean isMembers(final ItemManager itemManager)
RUNE_CHAINBODY(ItemID.RUNE_CHAINBODY, 96, 225),
RUNE_KITESHIELD(ItemID.RUNE_KITESHIELD, 97, 225),
RUNE_CLAWS(ItemID.RUNE_CLAWS, 98, 150),
- RUNE_PLATEBODY(ItemID.RUNE_PLATEBODY, 99, 375),
- RUNE_PLATESKIRT(ItemID.RUNE_PLATESKIRT, 99, 225),
- RUNE_PLATELEGS(ItemID.RUNE_PLATELEGS, 99, 225),
RUNE_2H_SWORD(ItemID.RUNE_2H_SWORD, 99, 225),
+ RUNE_PLATELEGS(ItemID.RUNE_PLATELEGS, 99, 225),
+ RUNE_PLATESKIRT(ItemID.RUNE_PLATESKIRT, 99, 225),
+ RUNE_PLATEBODY(ItemID.RUNE_PLATEBODY, 99, 375),
;
private final int itemId;
private final int level;
private final float xp;
+
+ @Override
+ public Set getExcludedSkillBonuses()
+ {
+ final EnumSet others = EnumSet.allOf(SmithingBonus.class);
+
+ if (this == GOLD_BAR)
+ {
+ others.remove(SmithingBonus.GOLDSMITH_GAUNTLETS);
+ }
+
+ return others;
+ }
}
diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/skillcalculator/skills/SmithingBonus.java b/runelite-client/src/main/java/net/runelite/client/plugins/skillcalculator/skills/SmithingBonus.java
new file mode 100644
index 0000000000..38b97bbb46
--- /dev/null
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/skillcalculator/skills/SmithingBonus.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2024, DapperMickie
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package net.runelite.client.plugins.skillcalculator.skills;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+@AllArgsConstructor
+@Getter(onMethod_ = @Override)
+public enum SmithingBonus implements SkillBonus
+{
+ GOLDSMITH_GAUNTLETS("Goldsmith Gauntlets", 2.5f),
+ ;
+
+ private final String name;
+ private final float value;
+}
diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/skillcalculator/skills/ThievingAction.java b/runelite-client/src/main/java/net/runelite/client/plugins/skillcalculator/skills/ThievingAction.java
index c048339bf8..eec464d34f 100644
--- a/runelite-client/src/main/java/net/runelite/client/plugins/skillcalculator/skills/ThievingAction.java
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/skillcalculator/skills/ThievingAction.java
@@ -37,9 +37,9 @@ public enum ThievingAction implements NamedSkillAction
WINTER_SQIRKJUICE("Winter Sq'irkjuice", 1, 350, ItemID.WINTER_SQIRKJUICE),
VEGETABLE_STALL("Vegetable Stall", 2, 10, ItemID.CABBAGE),
CAKE_STALL("Cake Stall", 5, 16, ItemID.CAKE),
- TEA_STALL("Tea Stall", 5, 16, ItemID.CUP_OF_TEA_4242),
CRAFTING_STALL("Crafting Stall", 5, 16, ItemID.CHISEL_5601),
MONKEY_FOOD_STALL("Monkey Food Stall", 5, 16, ItemID.BANANA),
+ TEA_STALL("Tea Stall", 5, 16, ItemID.CUP_OF_TEA_4242),
FARMER("Farmer", 10, 14.5f, ItemID.FARMER),
HAM_MEMBER("H.A.M. Member", 15, 22.2f, ItemID.MALE_HAM),
SILK_STALL("Silk Stall", 20, 24, ItemID.SILK),
@@ -61,23 +61,24 @@ public enum ThievingAction implements NamedSkillAction
CROSSBOW_STALL("Crossbow Stall", 49, 52, ItemID.CROSSBOW),
SILVER_STALL("Silver Stall", 50, 54, ItemID.SILVER_BAR),
WALL_SAFE("Wall Safe", 50, 70, ItemID.STETHOSCOPE),
+ WEALTHY_CITIZEN("Wealthy Citizen", 50, 96, ItemID.WEALTHY_CITIZEN),
DESERT_BANDIT("Desert Bandit", 53, 79.5f, ItemID.BANDIT),
KNIGHT("Knight", 55, 84.3f, ItemID.KNIGHT),
POLLNIVNIAN_BANDIT("Pollnivnian Bandit", 55, 84.3f, ItemID.BANDIT_6781),
STONE_CHEST("Stone Chest", 64, 280, ItemID.XERICIAN_FABRIC),
+ SPICES_STALL("Spices Stall", 65, 81, ItemID.SPICE),
MAGIC_STALL("Magic Stall", 65, 100, ItemID.AIR_RUNE_6422),
SCIMITAR_STALL("Scimitar Stall", 65, 100, ItemID.STEEL_SCIMITAR),
MENAPHITE_THUG("Menaphite Thug", 65, 137.5f, ItemID.MENAPHITE_THUG),
- SPICES_STALL("Spices Stall", 65, 81, ItemID.SPICE),
YANILLE_WATCHMAN("Yanille Watchman", 65, 137.5f, ItemID.WATCHMAN),
SUMMER_SQIRKJUICE("Summer Sq'irkjuice", 65, 3000, ItemID.SUMMER_SQIRKJUICE),
PALADIN("Paladin", 70, 151.8f, ItemID.PALADIN),
- GNOME("Gnome", 75, 198.5f, ItemID.GNOME),
GEMS_STALL("Gems Stall", 75, 160, ItemID.SAPPHIRE),
+ GNOME("Gnome", 75, 198.5f, ItemID.GNOME),
DORGESH_KAAN_RICH_CHEST("Dorgesh-Kaan Rich Chest", 78, 650, ItemID.MINING_HELMET),
HERO("Hero", 80, 275, ItemID.HERO),
VYRE("Vyre", 82, 306.9f, ItemID.VYRE),
- ROGUES_CASTLE_CHEST("Wilderness Rogues' Chest", 84, 100, ItemID.DRAGONSTONE),
+ ROGUES_CASTLE_CHEST("Wilderness Rogues' Chest", 84, 701.7f, ItemID.DRAGONSTONE),
ELF("Elf", 85, 353, ItemID.ELF),
TZHAAR_HUR("TzHaar-Hur", 90, 103.4f, ItemID.TZHAARHUR),
;
diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/skillcalculator/skills/WoodcuttingAction.java b/runelite-client/src/main/java/net/runelite/client/plugins/skillcalculator/skills/WoodcuttingAction.java
index c3e7d56ee3..cf219afb3b 100644
--- a/runelite-client/src/main/java/net/runelite/client/plugins/skillcalculator/skills/WoodcuttingAction.java
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/skillcalculator/skills/WoodcuttingAction.java
@@ -33,11 +33,12 @@
@Getter
public enum WoodcuttingAction implements ItemSkillAction
{
- LOGS(ItemID.LOGS, 1, 25),
ACHEY_TREE_LOGS(ItemID.ACHEY_TREE_LOGS, 1, 25),
+ LOGS(ItemID.LOGS, 1, 25),
OAK_LOGS(ItemID.OAK_LOGS, 15, 37.5f),
WILLOW_LOGS(ItemID.WILLOW_LOGS, 30, 67.5f),
TEAK_LOGS(ItemID.TEAK_LOGS, 35, 85),
+ JUNIPER_LOGS(ItemID.JUNIPER_LOGS, 42, 35),
BARK(ItemID.BARK, 45, 82.5f),
MAPLE_LOGS(ItemID.MAPLE_LOGS, 45, 100),
MAHOGANY_LOGS(ItemID.MAHOGANY_LOGS, 50, 125),
diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/skillcalculator/skills/WoodcuttingBonus.java b/runelite-client/src/main/java/net/runelite/client/plugins/skillcalculator/skills/WoodcuttingBonus.java
index d4ded0e720..af21600d6b 100644
--- a/runelite-client/src/main/java/net/runelite/client/plugins/skillcalculator/skills/WoodcuttingBonus.java
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/skillcalculator/skills/WoodcuttingBonus.java
@@ -24,6 +24,8 @@
*/
package net.runelite.client.plugins.skillcalculator.skills;
+import java.util.EnumSet;
+import java.util.Set;
import lombok.AllArgsConstructor;
import lombok.Getter;
@@ -31,9 +33,18 @@
@Getter(onMethod_ = @Override)
public enum WoodcuttingBonus implements SkillBonus
{
- LUMBERJACK_OUTFIT("Lumberjack Outfit (+2.5%)", 1.025f),
+ LUMBERJACK_OUTFIT("Lumberjack Outfit", 1.025f),
+ FELLING_AXE_RATIONS("Felling Axe + Rations", 1.1f),
;
private final String name;
private final float value;
+
+ @Override
+ public Set getCanBeStackedWith()
+ {
+ final EnumSet others = EnumSet.allOf(WoodcuttingBonus.class);
+ others.remove(this);
+ return others;
+ }
}
diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/slayer/SlayerConfig.java b/runelite-client/src/main/java/net/runelite/client/plugins/slayer/SlayerConfig.java
index 55952cb6d2..4e37d88ba7 100644
--- a/runelite-client/src/main/java/net/runelite/client/plugins/slayer/SlayerConfig.java
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/slayer/SlayerConfig.java
@@ -30,6 +30,7 @@
import net.runelite.client.config.Config;
import net.runelite.client.config.ConfigGroup;
import net.runelite.client.config.ConfigItem;
+import net.runelite.client.config.Notification;
import net.runelite.client.config.Units;
@ConfigGroup(SlayerConfig.GROUP_NAME)
@@ -73,9 +74,9 @@ default boolean showItemOverlay()
name = "Superior foe notification",
description = "Toggles notifications on superior foe encounters"
)
- default boolean showSuperiorNotification()
+ default Notification showSuperiorNotification()
{
- return true;
+ return Notification.ON;
}
@ConfigItem(
@@ -139,7 +140,7 @@ default Color getTargetColor()
position = 9,
keyName = "weaknessPrompt",
name = "Show Monster Weakness",
- description = "Show an overlay on a monster when it is weak enough to finish off (Only Lizards, Gargoyles & Rockslugs)"
+ description = "Show an overlay on a monster when it is weak enough to finish off (Only Lizards, Gargoyles, Rockslugs & Zygomites)"
)
default boolean weaknessPrompt()
{
diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/slayer/SlayerPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/slayer/SlayerPlugin.java
index 46de4c2154..93d98e015a 100644
--- a/runelite-client/src/main/java/net/runelite/client/plugins/slayer/SlayerPlugin.java
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/slayer/SlayerPlugin.java
@@ -458,9 +458,9 @@ public void onChatMessage(ChatMessage event)
String chatMsg = Text.removeTags(event.getMessage()); //remove color and linebreaks
- if (chatMsg.equals(CHAT_SUPERIOR_MESSAGE) && config.showSuperiorNotification())
+ if (chatMsg.equals(CHAT_SUPERIOR_MESSAGE))
{
- notifier.notify(CHAT_SUPERIOR_MESSAGE);
+ notifier.notify(config.showSuperiorNotification(), CHAT_SUPERIOR_MESSAGE);
}
}
diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/specialcounter/SpecialCounterConfig.java b/runelite-client/src/main/java/net/runelite/client/plugins/specialcounter/SpecialCounterConfig.java
index 9773544618..8af77dd7cd 100644
--- a/runelite-client/src/main/java/net/runelite/client/plugins/specialcounter/SpecialCounterConfig.java
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/specialcounter/SpecialCounterConfig.java
@@ -29,6 +29,7 @@
import net.runelite.client.config.Config;
import net.runelite.client.config.ConfigGroup;
import net.runelite.client.config.ConfigItem;
+import net.runelite.client.config.Notification;
@ConfigGroup("specialcounter")
public interface SpecialCounterConfig extends Config
@@ -39,9 +40,9 @@ public interface SpecialCounterConfig extends Config
name = "Threshold Notifications",
description = "Sends a notification when your special attack counter exceeds the threshold"
)
- default boolean thresholdNotification()
+ default Notification thresholdNotification()
{
- return false;
+ return Notification.OFF;
}
@ConfigItem(
diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/specialcounter/SpecialCounterPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/specialcounter/SpecialCounterPlugin.java
index f0acc918c9..b0c1793be2 100644
--- a/runelite-client/src/main/java/net/runelite/client/plugins/specialcounter/SpecialCounterPlugin.java
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/specialcounter/SpecialCounterPlugin.java
@@ -70,6 +70,7 @@
import net.runelite.client.party.WSClient;
import net.runelite.client.plugins.Plugin;
import net.runelite.client.plugins.PluginDescriptor;
+import static net.runelite.client.plugins.specialcounter.SpecialWeapon.TONALZTICS_OF_RALOS;
import net.runelite.client.ui.overlay.OverlayManager;
import net.runelite.client.ui.overlay.infobox.InfoBoxManager;
import net.runelite.client.util.ImageUtil;
@@ -99,7 +100,9 @@ public class SpecialCounterPlugin extends Plugin
private int hitsplatTick;
// most recent hitsplat and the target it was on
private Hitsplat lastSpecHitsplat;
+ private Hitsplat secondToLastSpecHitsplat;
private NPC lastSpecTarget;
+ private int specialAttackHits = 0;
private final Set interactedNpcIndexes = new HashSet<>();
private final SpecialCounter[] specialCounter = new SpecialCounter[SpecialWeapon.values().length];
@@ -163,6 +166,7 @@ protected void shutDown()
specialWeapon = null;
lastSpecTarget = null;
lastSpecHitsplat = null;
+ secondToLastSpecHitsplat = null;
removeCounters();
overlayManager.remove(playerInfoDropOverlay);
wsClient.unregisterMessage(SpecialCounterUpdate.class);
@@ -185,12 +189,25 @@ public void onGameTick(GameTick event)
{
if (lastSpecHitsplat.getAmount() > 0)
{
- specialAttackHit(specialWeapon, lastSpecHitsplat, lastSpecTarget);
+ specialAttackHits++;
+ }
+ if (specialWeapon == TONALZTICS_OF_RALOS && secondToLastSpecHitsplat != null
+ && secondToLastSpecHitsplat.getAmount() > 0)
+ {
+ specialAttackHits++;
+ }
+
+ if (specialAttackHits > 0)
+ {
+ int hit = specialWeapon == TONALZTICS_OF_RALOS ? specialAttackHits : getHit(specialWeapon, lastSpecHitsplat);
+ specialAttackHit(specialWeapon, hit, lastSpecTarget);
}
specialWeapon = null;
lastSpecHitsplat = null;
+ secondToLastSpecHitsplat = null;
lastSpecTarget = null;
+ specialAttackHits = 0;
}
}
@@ -286,16 +303,16 @@ public void onHitsplatApplied(HitsplatApplied hitsplatApplied)
// venge or thralls.
if (hitsplatTick == client.getTickCount())
{
+ secondToLastSpecHitsplat = lastSpecHitsplat;
lastSpecHitsplat = hitsplat;
}
}
- private void specialAttackHit(SpecialWeapon specialWeapon, Hitsplat hitsplat, NPC target)
+ private void specialAttackHit(SpecialWeapon specialWeapon, int hit, NPC target)
{
- int hit = getHit(specialWeapon, hitsplat);
int localPlayerId = client.getLocalPlayer().getId();
- log.debug("Special attack hit {} hitsplat {}", specialWeapon, hitsplat.getAmount());
+ log.debug("Special attack hit {} hitsplat {}", specialWeapon, hit);
if (config.infobox())
{
@@ -446,9 +463,9 @@ private void updateCounter(SpecialWeapon specialWeapon, String name, int hit)
private void sendNotification(SpecialWeapon weapon, SpecialCounter counter)
{
int threshold = weapon.getThreshold().apply(config);
- if (threshold > 0 && counter.getCount() >= threshold && config.thresholdNotification())
+ if (threshold > 0 && counter.getCount() >= threshold)
{
- notifier.notify(weapon.getName() + " special attack threshold reached!");
+ notifier.notify(config.thresholdNotification(), weapon.getName() + " special attack threshold reached!");
}
}
diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/specialcounter/SpecialWeapon.java b/runelite-client/src/main/java/net/runelite/client/plugins/specialcounter/SpecialWeapon.java
index 5806b909db..2628358bdb 100644
--- a/runelite-client/src/main/java/net/runelite/client/plugins/specialcounter/SpecialWeapon.java
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/specialcounter/SpecialWeapon.java
@@ -54,7 +54,12 @@ public enum SpecialWeapon
(distance) -> 46 + distance * 10,
(c) -> 0
),
- ;
+ TONALZTICS_OF_RALOS(
+ "Tonalztics of Ralos",
+ new int[]{ItemID.TONALZTICS_OF_RALOS},
+ false,
+ (distance) -> 50, //The hitsplat is always applied 2t after spec regardless of distance
+ (c) -> 0);
private final String name;
private final int[] itemID;
diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/spellbook/SpellbookConfig.java b/runelite-client/src/main/java/net/runelite/client/plugins/spellbook/SpellbookConfig.java
new file mode 100644
index 0000000000..e11b9d70f0
--- /dev/null
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/spellbook/SpellbookConfig.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2024, Adam
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package net.runelite.client.plugins.spellbook;
+
+import net.runelite.client.config.Config;
+import net.runelite.client.config.ConfigGroup;
+
+@ConfigGroup(SpellbookConfig.GROUP)
+public interface SpellbookConfig extends Config
+{
+ String GROUP = "spellbook";
+}
diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/spellbook/SpellbookPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/spellbook/SpellbookPlugin.java
new file mode 100644
index 0000000000..d45e16d3e6
--- /dev/null
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/spellbook/SpellbookPlugin.java
@@ -0,0 +1,479 @@
+/*
+ * Copyright (c) 2024, Adam
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package net.runelite.client.plugins.spellbook;
+
+import com.google.inject.Provides;
+import java.util.Arrays;
+import java.util.Comparator;
+import java.util.stream.IntStream;
+import javax.inject.Inject;
+import lombok.extern.slf4j.Slf4j;
+import net.runelite.api.ChatMessageType;
+import net.runelite.api.Client;
+import net.runelite.api.EnumComposition;
+import net.runelite.api.EnumID;
+import net.runelite.api.ItemComposition;
+import net.runelite.api.ParamID;
+import net.runelite.api.ScriptID;
+import net.runelite.api.Varbits;
+import net.runelite.api.events.DraggingWidgetChanged;
+import net.runelite.api.events.ScriptCallbackEvent;
+import net.runelite.api.events.ScriptPreFired;
+import net.runelite.api.widgets.ComponentID;
+import net.runelite.api.widgets.InterfaceID;
+import net.runelite.api.widgets.JavaScriptCallback;
+import net.runelite.api.widgets.Widget;
+import static net.runelite.api.widgets.WidgetConfig.DRAG;
+import static net.runelite.api.widgets.WidgetConfig.DRAG_ON;
+import net.runelite.api.widgets.WidgetUtil;
+import net.runelite.client.callback.ClientThread;
+import net.runelite.client.chat.ChatMessageManager;
+import net.runelite.client.chat.QueuedMessage;
+import net.runelite.client.config.ConfigManager;
+import net.runelite.client.eventbus.Subscribe;
+import net.runelite.client.menus.MenuManager;
+import net.runelite.client.menus.WidgetMenuOption;
+import net.runelite.client.plugins.Plugin;
+import net.runelite.client.plugins.PluginDescriptor;
+
+@PluginDescriptor(
+ name = "Spellbook",
+ description = "Reorder and hide spells"
+)
+@Slf4j
+public class SpellbookPlugin extends Plugin
+{
+ private static final String LOCK = "Disable spell reordering";
+ private static final String UNLOCK = "Enable spell reordering";
+ // [proc,magic_spellbook_modifyops] shifts around ops, but seems to only use
+ // 1 2 3 4 5 10. So use 6 for Hide/Unhide.
+ private static final int HIDE_UNHIDE_OP = 6;
+
+ private static final WidgetMenuOption FIXED_MAGIC_TAB_LOCK = new WidgetMenuOption(LOCK,
+ "", ComponentID.FIXED_VIEWPORT_MAGIC_TAB);
+
+ private static final WidgetMenuOption FIXED_MAGIC_TAB_UNLOCK = new WidgetMenuOption(UNLOCK,
+ "", ComponentID.FIXED_VIEWPORT_MAGIC_TAB);
+
+ private static final WidgetMenuOption RESIZABLE_MAGIC_TAB_LOCK = new WidgetMenuOption(LOCK,
+ "", ComponentID.RESIZABLE_VIEWPORT_MAGIC_TAB);
+
+ private static final WidgetMenuOption RESIZABLE_MAGIC_TAB_UNLOCK = new WidgetMenuOption(UNLOCK,
+ "", ComponentID.RESIZABLE_VIEWPORT_MAGIC_TAB);
+
+ private static final WidgetMenuOption RESIZABLE_BOTTOM_LINE_MAGIC_TAB_LOCK = new WidgetMenuOption(LOCK,
+ "", ComponentID.RESIZABLE_VIEWPORT_BOTTOM_LINE_MAGIC_TAB);
+
+ private static final WidgetMenuOption RESIZABLE_BOTTOM_LINE_MAGIC_TAB_UNLOCK = new WidgetMenuOption(UNLOCK,
+ "", ComponentID.RESIZABLE_VIEWPORT_BOTTOM_LINE_MAGIC_TAB);
+
+ @Inject
+ private Client client;
+
+ @Inject
+ private ClientThread clientThread;
+
+ @Inject
+ private MenuManager menuManager;
+
+ @Inject
+ private ChatMessageManager chatMessageManager;
+
+ @Inject
+ private ConfigManager configManager;
+
+ private boolean reordering;
+
+ @Provides
+ SpellbookConfig getConfig(ConfigManager configManager)
+ {
+ return configManager.getConfig(SpellbookConfig.class);
+ }
+
+ @Override
+ protected void startUp()
+ {
+ refreshReorderMenus();
+ clientThread.invokeLater(this::reinitializeSpellbook);
+ }
+
+ @Override
+ protected void shutDown()
+ {
+ clearReoderMenus();
+ clientThread.invokeLater(this::reinitializeSpellbook);
+ }
+
+ @Override
+ public void resetConfiguration()
+ {
+ for (var key : configManager.getConfigurationKeys(SpellbookConfig.GROUP + ".spell_"))
+ {
+ String[] str = key.split("\\.", 2);
+ if (str.length == 2)
+ {
+ configManager.unsetConfiguration(str[0], str[1]);
+ }
+ }
+
+ clientThread.invokeLater(this::redrawSpellbook);
+
+ log.debug("Reset spellbook");
+ }
+
+ private void clearReoderMenus()
+ {
+ menuManager.removeManagedCustomMenu(FIXED_MAGIC_TAB_LOCK);
+ menuManager.removeManagedCustomMenu(RESIZABLE_MAGIC_TAB_LOCK);
+ menuManager.removeManagedCustomMenu(RESIZABLE_BOTTOM_LINE_MAGIC_TAB_LOCK);
+ menuManager.removeManagedCustomMenu(FIXED_MAGIC_TAB_UNLOCK);
+ menuManager.removeManagedCustomMenu(RESIZABLE_MAGIC_TAB_UNLOCK);
+ menuManager.removeManagedCustomMenu(RESIZABLE_BOTTOM_LINE_MAGIC_TAB_UNLOCK);
+ }
+
+ private void refreshReorderMenus()
+ {
+ clearReoderMenus();
+ if (reordering)
+ {
+ menuManager.addManagedCustomMenu(FIXED_MAGIC_TAB_LOCK, e -> reordering(false));
+ menuManager.addManagedCustomMenu(RESIZABLE_MAGIC_TAB_LOCK, e -> reordering(false));
+ menuManager.addManagedCustomMenu(RESIZABLE_BOTTOM_LINE_MAGIC_TAB_LOCK, e -> reordering(false));
+ }
+ else
+ {
+ menuManager.addManagedCustomMenu(FIXED_MAGIC_TAB_UNLOCK, e -> reordering(true));
+ menuManager.addManagedCustomMenu(RESIZABLE_MAGIC_TAB_UNLOCK, e -> reordering(true));
+ menuManager.addManagedCustomMenu(RESIZABLE_BOTTOM_LINE_MAGIC_TAB_UNLOCK, e -> reordering(true));
+ }
+ }
+
+ private void reordering(boolean state)
+ {
+ reordering = state;
+
+ var message = reordering ?
+ "Spell book reordering is now enabled." :
+ "Spell book reordering is now disabled.";
+
+ chatMessageManager.queue(QueuedMessage.builder()
+ .type(ChatMessageType.CONSOLE)
+ .runeLiteFormattedMessage(message)
+ .build());
+
+ refreshReorderMenus();
+
+ redrawSpellbook();
+ }
+
+ @Subscribe
+ public void onScriptPreFired(ScriptPreFired event)
+ {
+ if (event.getScriptId() == ScriptID.MAGIC_SPELLBOOK_INITIALISESPELLS)
+ {
+ int[] stack = client.getIntStack();
+ int sz = client.getIntStackSize();
+ int spellBookEnum = stack[sz - 12]; // eg 1982, 5285, 1983, 1984, 1985
+ clientThread.invokeLater(() -> initializeSpells(spellBookEnum));
+ }
+ }
+
+ @Subscribe
+ public void onDraggingWidgetChanged(DraggingWidgetChanged event)
+ {
+ if (event.isDraggingWidget() && client.getMouseCurrentButton() == 0)
+ {
+ Widget draggedWidget = client.getDraggedWidget();
+ Widget draggedOnWidget = client.getDraggedOnWidget();
+ if (draggedWidget == null || draggedOnWidget == null)
+ {
+ return;
+ }
+
+ int draggedGroupId = WidgetUtil.componentToInterface(draggedWidget.getId());
+ int draggedOnGroupId = WidgetUtil.componentToInterface(draggedOnWidget.getId());
+ if (draggedGroupId != InterfaceID.SPELLBOOK || draggedOnGroupId != InterfaceID.SPELLBOOK)
+ {
+ return;
+ }
+
+ // from ~magic_spellbook_redraw
+ int subSpellbookId = client.getEnum(EnumID.SPELLBOOKS_SUB).getIntValue(client.getVarbitValue(Varbits.SPELLBOOK));
+ int spellbookId = client.getEnum(subSpellbookId).getIntValue(client.getVarbitValue(Varbits.SPELLBOOK_SUBMENU));
+
+ EnumComposition spellbook = client.getEnum(spellbookId);
+ int[] order = calculateSpellbookOrder(spellbookId, spellbook); // in enum indices
+
+ int fromIdx = findSpellIdxForComponent(spellbook, order, draggedWidget);
+ int toIdx = findSpellIdxForComponent(spellbook, order, draggedOnWidget);
+
+ ItemComposition fromSpell = client.getItemDefinition(spellbook.getIntValue(order[fromIdx]));
+ ItemComposition toSpell = client.getItemDefinition(spellbook.getIntValue(order[toIdx]));
+
+ log.debug("Insert {} ({}) at {} ({}) spellbook {}",
+ fromSpell.getStringValue(ParamID.SPELL_NAME), fromIdx,
+ toSpell.getStringValue(ParamID.SPELL_NAME), toIdx,
+ spellbookId);
+
+ log.debug("Set {} to {}", client.getItemDefinition(spellbook.getIntValue(order[fromIdx])).getStringValue(ParamID.SPELL_NAME), toIdx);
+ setPosition(spellbookId, spellbook.getIntValue(order[fromIdx]), toIdx);
+ if (fromIdx < toIdx)
+ {
+ for (int i = fromIdx + 1; i <= toIdx; ++i)
+ {
+ log.debug("Set {} to {}", client.getItemDefinition(spellbook.getIntValue(order[i])).getStringValue(ParamID.SPELL_NAME), i - 1);
+ setPosition(spellbookId, spellbook.getIntValue(order[i]), i - 1);
+ }
+ }
+ else
+ {
+ for (int i = toIdx; i < fromIdx; ++i)
+ {
+ log.debug("Set {} to {}", client.getItemDefinition(spellbook.getIntValue(order[i])).getStringValue(ParamID.SPELL_NAME), i + 1);
+ setPosition(spellbookId, spellbook.getIntValue(order[i]), i + 1);
+ }
+ }
+
+ redrawSpellbook();
+ }
+ }
+
+ private int findSpellIdxForComponent(EnumComposition spellbook, int[] spells, Widget c)
+ {
+ for (int i = 0; i < spells.length; ++i)
+ {
+ ItemComposition spellObj = client.getItemDefinition(spellbook.getIntValue(spells[i]));
+ Widget w = client.getWidget(spellObj.getIntValue(ParamID.SPELL_BUTTON));
+ if (w == c)
+ {
+ return i;
+ }
+ }
+ return -1;
+ }
+
+ @Subscribe
+ public void onScriptCallbackEvent(ScriptCallbackEvent event)
+ {
+ if (!"spellbookSort".equals(event.getEventName()))
+ {
+ return;
+ }
+
+ // this is called after ~magic_spellbook_redraw has built and sorted the array of visible spells
+ // based on the vanilla filtering
+
+ int[] stack = client.getIntStack();
+ int size = client.getIntStackSize();
+
+ int spellbookEnumId = stack[size - 3];
+ int spellArrayId = stack[size - 2];
+ int numSpells = stack[size - 1];
+
+ EnumComposition spellbookEnum = client.getEnum(spellbookEnumId);
+ int[] spells = client.getArray(spellArrayId); // enum indices
+ int[] newSpells = new int[numSpells];
+ int numNewSpells = 0;
+ for (int i = 0; i < numSpells; ++i)
+ {
+ ItemComposition spellObj = client.getItemDefinition(spellbookEnum.getIntValue(spells[i]));
+ Widget w = client.getWidget(spellObj.getIntValue(ParamID.SPELL_BUTTON));
+ boolean hidden = isHidden(spellbookEnumId, spellObj.getId());
+
+ int widgetConfig = w.getClickMask();
+ if (reordering)
+ {
+ if (hidden)
+ {
+ w.setOpacity(100);
+ w.setAction(HIDE_UNHIDE_OP, "Unhide");
+ }
+ else
+ {
+ w.setOpacity(0);
+ w.setAction(HIDE_UNHIDE_OP, "Hide");
+ }
+
+ newSpells[numNewSpells++] = spells[i];
+ widgetConfig |= DRAG | DRAG_ON;
+ }
+ else
+ {
+ if (hidden)
+ {
+ w.setHidden(true);
+ }
+ else
+ {
+ newSpells[numNewSpells++] = spells[i];
+ w.setOpacity(0);
+ w.setAction(HIDE_UNHIDE_OP, null);
+ }
+
+ widgetConfig &= ~(DRAG | DRAG_ON);
+ }
+ w.setClickMask(widgetConfig);
+ }
+
+ // Sort newSpells based on their configured order
+ int[] order = calculateSpellbookOrder(spellbookEnumId, spellbookEnum);
+ int[] indices = new int[order.length];
+ for (int i = 0; i < order.length; ++i)
+ {
+ indices[order[i]] = i;
+ }
+ newSpells = Arrays.stream(newSpells, 0, numNewSpells)
+ .boxed()
+ .sorted(Comparator.comparingInt(i -> indices[i]))
+ .mapToInt(i -> i)
+ .toArray();
+
+ System.arraycopy(newSpells, 0, spells, 0, numNewSpells);
+ stack[size - 1] = numSpells = numNewSpells;
+ }
+
+ private void initializeSpells(int spellbookEnum)
+ {
+ EnumComposition spellbook = client.getEnum(spellbookEnum);
+ for (int i = 0; i < spellbook.size(); ++i)
+ {
+ int spellObjId = spellbook.getIntValue(i);
+ ItemComposition spellObj = client.getItemDefinition(spellObjId);
+ int spellComponent = spellObj.getIntValue(ParamID.SPELL_BUTTON);
+ Widget w = client.getWidget(spellComponent);
+
+ // spells with no target mask have an existing op listener, capture it to
+ // call it later
+ Object[] opListener = w.getOnOpListener();
+ w.setOnOpListener((JavaScriptCallback) e ->
+ {
+ if (e.getOp() == HIDE_UNHIDE_OP + 1)
+ {
+ Widget s = e.getSource();
+
+ boolean hidden = isHidden(spellbookEnum, spellObjId);
+ hidden = !hidden;
+
+ log.debug("Changing {} to hidden: {}", s.getName(), hidden);
+ setHidden(spellbookEnum, spellObjId, hidden);
+
+ s.setOpacity(hidden ? 100 : 0);
+ s.setAction(HIDE_UNHIDE_OP, hidden ? "Unhide" : "Hide");
+ return;
+ }
+
+ if (opListener != null)
+ {
+ client.runScript(opListener);
+ }
+ });
+ }
+ }
+
+ private void reinitializeSpellbook()
+ {
+ Widget w = client.getWidget(ComponentID.SPELLBOOK_PARENT);
+ if (w != null && w.getOnLoadListener() != null)
+ {
+ client.createScriptEvent(w.getOnLoadListener())
+ .setSource(w)
+ .run();
+ }
+ }
+
+ private void redrawSpellbook()
+ {
+ Widget w = client.getWidget(ComponentID.SPELLBOOK_PARENT);
+ if (w != null && w.getOnInvTransmitListener() != null)
+ {
+ client.createScriptEvent(w.getOnInvTransmitListener())
+ .setSource(w)
+ .run();
+ }
+ }
+
+ private int[] calculateSpellbookOrder(int spellbookId, EnumComposition spellbook)
+ {
+ int[] spells = defaultSpellbookOrder(spellbook);
+ int[] indices = new int[spells.length]; // spell to desired index
+ for (int i = 0; i < spells.length; ++i)
+ {
+ int pos = getPosition(spellbookId, spellbook.getIntValue(spells[i]));
+ indices[spells[i]] = pos != -1 ? pos : i;
+ }
+
+ // sort by desired index
+ return Arrays.stream(spells)
+ .boxed()
+ .sorted(Comparator.comparingInt(i -> indices[i]))
+ .mapToInt(i -> i)
+ .toArray();
+ }
+
+ private int[] defaultSpellbookOrder(EnumComposition spellbook)
+ {
+ return IntStream.range(0, spellbook.size())
+ .boxed()
+ .sorted((idx1, idx2) ->
+ {
+ var i1 = client.getItemDefinition(spellbook.getIntValue(idx1));
+ var i2 = client.getItemDefinition(spellbook.getIntValue(idx2));
+ int l1 = i1.getIntValue(ParamID.SPELL_LEVELREQ);
+ int l2 = i2.getIntValue(ParamID.SPELL_LEVELREQ);
+ return Integer.compare(l1, l2);
+ })
+ .mapToInt(i -> i)
+ .toArray();
+ }
+
+ private boolean isHidden(int spellbook, int spell)
+ {
+ Boolean b = configManager.getConfiguration(SpellbookConfig.GROUP, "spell_hidden_book_" + spellbook + "_" + spell, boolean.class);
+ return b == Boolean.TRUE;
+ }
+
+ private void setHidden(int spellbook, int spell, boolean hidden)
+ {
+ if (hidden)
+ {
+ configManager.setConfiguration(SpellbookConfig.GROUP, "spell_hidden_book_" + spellbook + "_" + spell, true);
+ }
+ else
+ {
+ configManager.unsetConfiguration(SpellbookConfig.GROUP, "spell_hidden_book_" + spellbook + "_" + spell);
+ }
+ }
+
+ private int getPosition(int spellbook, int spell)
+ {
+ Integer pos = configManager.getConfiguration(SpellbookConfig.GROUP, "spell_pos_book_" + spellbook + "_" + spell, int.class);
+ return pos == null ? -1 : pos;
+ }
+
+ private void setPosition(int spellbook, int spell, int position)
+ {
+ configManager.setConfiguration(SpellbookConfig.GROUP, "spell_pos_book_" + spellbook + "_" + spell, position);
+ }
+}
diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/timers/ElapsedTimer.java b/runelite-client/src/main/java/net/runelite/client/plugins/timers/ElapsedTimer.java
index 55a06025d4..b9571ae11e 100644
--- a/runelite-client/src/main/java/net/runelite/client/plugins/timers/ElapsedTimer.java
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/timers/ElapsedTimer.java
@@ -68,6 +68,11 @@ public Color getTextColor()
@Override
public String getTooltip()
{
+ if (startTime == null)
+ {
+ return null;
+ }
+
Duration time = Duration.between(startTime, lastTime == null ? Instant.now() : lastTime);
return "Elapsed time: " + DurationFormatUtils.formatDuration(time.toMillis(), "HH:mm:ss", true);
}
diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/timers/TimersPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/timers/TimersPlugin.java
index f275fce21f..257c89cca8 100644
--- a/runelite-client/src/main/java/net/runelite/client/plugins/timers/TimersPlugin.java
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/timers/TimersPlugin.java
@@ -131,7 +131,6 @@ public class TimersPlugin extends Plugin
static final int FIGHT_CAVES_REGION_ID = 9551;
static final int INFERNO_REGION_ID = 9043;
private static final Pattern TZHAAR_WAVE_MESSAGE = Pattern.compile("Wave: (\\d+)");
- private static final String TZHAAR_DEFEATED_MESSAGE = "You have been defeated!";
private static final Pattern TZHAAR_PAUSED_MESSAGE = Pattern.compile("The (?:Inferno|Fight Cave) has been paused. You may now log out.");
private TimerTimer freezeTimer;
@@ -891,15 +890,6 @@ else if (client.getVarbitValue(Varbits.COMBAT_ACHIEVEMENT_TIER_MASTER) == 2)
}
}
- if (message.equals(TZHAAR_DEFEATED_MESSAGE))
- {
- log.debug("Stopping tzhaar timer");
- removeTzhaarTimer();
- config.tzhaarStartTime(null);
- config.tzhaarLastTime(null);
- return;
- }
-
if (TZHAAR_PAUSED_MESSAGE.matcher(message).find())
{
log.debug("Pausing tzhaar timer");
diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/timetracking/TimeTrackingConfig.java b/runelite-client/src/main/java/net/runelite/client/plugins/timetracking/TimeTrackingConfig.java
index e569d82b11..77ed4af5b6 100644
--- a/runelite-client/src/main/java/net/runelite/client/plugins/timetracking/TimeTrackingConfig.java
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/timetracking/TimeTrackingConfig.java
@@ -27,6 +27,7 @@
import net.runelite.client.config.Config;
import net.runelite.client.config.ConfigGroup;
import net.runelite.client.config.ConfigItem;
+import net.runelite.client.config.Notification;
import net.runelite.client.config.Units;
@ConfigGroup("timetracking")
@@ -62,9 +63,9 @@ default TimeFormatMode timeFormatMode()
description = "Notify you whenever a timer has finished counting down",
position = 2
)
- default boolean timerNotification()
+ default Notification timerNotification()
{
- return false;
+ return Notification.OFF;
}
@ConfigItem(
diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/timetracking/clocks/ClockManager.java b/runelite-client/src/main/java/net/runelite/client/plugins/timetracking/clocks/ClockManager.java
index 30d16ff573..d43c295809 100644
--- a/runelite-client/src/main/java/net/runelite/client/plugins/timetracking/clocks/ClockManager.java
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/timetracking/clocks/ClockManager.java
@@ -121,10 +121,7 @@ public boolean checkCompletion()
timer.pause();
changed = true;
- if (config.timerNotification())
- {
- notifier.notify("[" + timer.getName() + "] has finished counting down.");
- }
+ notifier.notify(config.timerNotification(), "[" + timer.getName() + "] has finished counting down.");
if (timer.isLoop())
{
diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/woodcutting/WoodcuttingConfig.java b/runelite-client/src/main/java/net/runelite/client/plugins/woodcutting/WoodcuttingConfig.java
index d668b8ab96..2a08d2d9e4 100644
--- a/runelite-client/src/main/java/net/runelite/client/plugins/woodcutting/WoodcuttingConfig.java
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/woodcutting/WoodcuttingConfig.java
@@ -28,6 +28,7 @@
import net.runelite.client.config.ConfigGroup;
import net.runelite.client.config.ConfigItem;
import net.runelite.client.config.ConfigSection;
+import net.runelite.client.config.Notification;
import net.runelite.client.config.Units;
import net.runelite.client.plugins.woodcutting.config.ClueNestTier;
@@ -59,9 +60,9 @@ default int statTimeout()
name = "Bird nest notification",
description = "Configures whether to notify you of a bird nest spawn"
)
- default boolean showNestNotification()
+ default Notification showNestNotification()
{
- return true;
+ return Notification.ON;
}
@ConfigItem(
@@ -127,9 +128,9 @@ default boolean forestryLeprechaunNotification()
description = "Configures whether to notify you of a Rising Roots event",
section = forestrySection
)
- default boolean forestryRisingRootsNotification()
+ default Notification forestryRisingRootsNotification()
{
- return true;
+ return Notification.ON;
}
@ConfigItem(
@@ -139,9 +140,9 @@ default boolean forestryRisingRootsNotification()
description = "Configures whether to notify you of a Struggling Sapling event",
section = forestrySection
)
- default boolean forestryStrugglingSaplingNotification()
+ default Notification forestryStrugglingSaplingNotification()
{
- return true;
+ return Notification.ON;
}
@ConfigItem(
@@ -151,9 +152,9 @@ default boolean forestryStrugglingSaplingNotification()
description = "Configures whether to notify you of a Flowering Tree event",
section = forestrySection
)
- default boolean forestryFloweringTreeNotification()
+ default Notification forestryFloweringTreeNotification()
{
- return true;
+ return Notification.ON;
}
@ConfigItem(
@@ -163,9 +164,9 @@ default boolean forestryFloweringTreeNotification()
description = "Configures whether to notify you of a Poachers event",
section = forestrySection
)
- default boolean forestryPoachersNotification()
+ default Notification forestryPoachersNotification()
{
- return true;
+ return Notification.ON;
}
@ConfigItem(
@@ -175,9 +176,9 @@ default boolean forestryPoachersNotification()
description = "Configures whether to notify you of a Pheasant Control event",
section = forestrySection
)
- default boolean forestryPheasantControlNotification()
+ default Notification forestryPheasantControlNotification()
{
- return true;
+ return Notification.ON;
}
@ConfigItem(
@@ -187,9 +188,9 @@ default boolean forestryPheasantControlNotification()
description = "Configures whether to notify you of a Bee Hive event",
section = forestrySection
)
- default boolean forestryBeeHiveNotification()
+ default Notification forestryBeeHiveNotification()
{
- return true;
+ return Notification.ON;
}
@ConfigItem(
@@ -199,9 +200,9 @@ default boolean forestryBeeHiveNotification()
description = "Configures whether to notify you of an Enchantment Ritual event",
section = forestrySection
)
- default boolean forestryEnchantmentRitualNotification()
+ default Notification forestryEnchantmentRitualNotification()
{
- return true;
+ return Notification.ON;
}
@ConfigItem(
@@ -211,9 +212,9 @@ default boolean forestryEnchantmentRitualNotification()
description = "Configures whether to notify you of a Friendly Ent event",
section = forestrySection
)
- default boolean forestryFriendlyEntNotification()
+ default Notification forestryFriendlyEntNotification()
{
- return true;
+ return Notification.ON;
}
@ConfigItem(
diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/woodcutting/WoodcuttingPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/woodcutting/WoodcuttingPlugin.java
index d4e721e038..1ec3069d45 100644
--- a/runelite-client/src/main/java/net/runelite/client/plugins/woodcutting/WoodcuttingPlugin.java
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/woodcutting/WoodcuttingPlugin.java
@@ -263,11 +263,11 @@ public void onChatMessage(ChatMessage event)
session.incrementBark(num);
}
- if (msg.contains("A bird's nest falls out of the tree") && config.showNestNotification())
+ if (msg.contains("A bird's nest falls out of the tree"))
{
if (clueTierSpawned == null || clueTierSpawned.ordinal() >= config.clueNestNotifyTier().ordinal())
{
- notifier.notify("A bird nest has spawned!");
+ notifier.notify(config.showNestNotification(), "A bird nest has spawned!");
}
// Clear the clue tier that has previously spawned
clueTierSpawned = null;
@@ -340,9 +340,9 @@ public void onGameObjectSpawned(final GameObjectSpawned event)
case ObjectID.TREE_ROOTS:
case ObjectID.ANIMAINFUSED_TREE_ROOTS:
- if (roots.isEmpty() && config.forestryRisingRootsNotification())
+ if (roots.isEmpty())
{
- notifier.notify("A Rising Roots Forestry event spawned!");
+ notifier.notify(config.forestryRisingRootsNotification(), "A Rising Roots Forestry event spawned!");
}
roots.add(gameObject);
@@ -353,10 +353,7 @@ public void onGameObjectSpawned(final GameObjectSpawned event)
case ObjectID.STRUGGLING_SAPLING_47488:
case ObjectID.STRUGGLING_SAPLING_47490:
case ObjectID.STRUGGLING_SAPLING_47491:
- if (config.forestryStrugglingSaplingNotification())
- {
- notifier.notify("A Struggling Sapling Forestry event spawned!");
- }
+ notifier.notify(config.forestryStrugglingSaplingNotification(), "A Struggling Sapling Forestry event spawned!");
break;
case ObjectID.ROTTING_LEAVES:
case ObjectID.GREEN_LEAVES:
@@ -641,9 +638,9 @@ public void onNpcSpawned(NpcSpawned event)
var id = npc.getId();
if (isFloweringBush(id))
{
- if (flowers.isEmpty() && config.forestryFloweringTreeNotification())
+ if (flowers.isEmpty())
{
- notifier.notify("A Flowering Tree Forestry event spawned!");
+ notifier.notify(config.forestryFloweringTreeNotification(), "A Flowering Tree Forestry event spawned!");
}
flowers.add(npc);
@@ -652,9 +649,9 @@ else if (id == NpcID.WOODCUTTING_LEPRECHAUN && config.forestryLeprechaunNotifica
{
notifier.notify("A Leprechaun event spawned!");
}
- else if ((id == NpcID.FRIGHTENED_FOX || id == NpcID.FRIGHTENED_FOX_12560) && config.forestryPoachersNotification())
+ else if ((id == NpcID.FRIGHTENED_FOX || id == NpcID.FRIGHTENED_FOX_12560))
{
- notifier.notify("A Poachers event spawned!");
+ notifier.notify(config.forestryPoachersNotification(), "A Poachers event spawned!");
}
else if (id == NpcID.FOX_TRAP)
{
@@ -664,17 +661,11 @@ else if (id == NpcID.FREAKY_FORESTER_12536)
{
freakyForester = npc;
- if (config.forestryPheasantControlNotification())
- {
- notifier.notify("A Pheasant Control event has spawned!");
- }
+ notifier.notify(config.forestryPheasantControlNotification(), "A Pheasant Control event has spawned!");
}
else if (id == NpcID.WILD_BEEHIVE)
{
- if (config.forestryBeeHiveNotification())
- {
- notifier.notify("A Bee Hive event has spawned!");
- }
+ notifier.notify(config.forestryBeeHiveNotification(), "A Bee Hive event has spawned!");
}
else if (id == NpcID.UNFINISHED_BEEHIVE || id == NpcID.UNFINISHED_BEEHIVE_12516)
{
@@ -686,17 +677,14 @@ else if (id >= NpcID.RITUAL_CIRCLE_GREEN && id <= NpcID.RITUAL_CIRCLE_RED_12535)
}
else if (id == NpcID.DRYAD_12519)
{
- if (config.forestryEnchantmentRitualNotification())
- {
- notifier.notify("An Enchantment Ritual event has spawned!");
- }
+ notifier.notify(config.forestryEnchantmentRitualNotification(), "An Enchantment Ritual event has spawned!");
}
else if (id == NpcID.ENTLING)
{
entlings.add(npc);
- if (entlings.size() == 1 && config.forestryFriendlyEntNotification())
+ if (entlings.size() == 1)
{
- notifier.notify("A Friendly Ent event has spawned!");
+ notifier.notify(config.forestryFriendlyEntNotification(), "A Friendly Ent event has spawned!");
}
}
}
diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/worldmap/TeleportLocationData.java b/runelite-client/src/main/java/net/runelite/client/plugins/worldmap/TeleportLocationData.java
index d09cec0d5c..9297b8f910 100644
--- a/runelite-client/src/main/java/net/runelite/client/plugins/worldmap/TeleportLocationData.java
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/worldmap/TeleportLocationData.java
@@ -81,6 +81,7 @@ enum TeleportLocationData
PVP_ARENA(TeleportType.JEWELLERY, "Ring of Dueling" , "Al Kharid PvP Arena", new WorldPoint(3315, 3235, 0), "ring_of_dueling_teleport_icon.png"),
FEROX_ENCLAVE(TeleportType.JEWELLERY, "Ring of Dueling" , "Ferox Enclave", new WorldPoint(3151, 3636, 0), "ring_of_dueling_teleport_icon.png"),
CASTLE_WARS(TeleportType.JEWELLERY, "Ring of Dueling" , "Castle Wars", new WorldPoint(2441, 3091, 0), "ring_of_dueling_teleport_icon.png"),
+ FORTIS_COLOSSEUM(TeleportType.JEWELLERY, "Ring of Dueling" , "Fortis Colosseum", new WorldPoint(1793, 3107, 0), "ring_of_dueling_teleport_icon.png"),
WARRIORS_GUILD(TeleportType.JEWELLERY, "Combat Bracelet" , "Warriors' Guild", new WorldPoint(2883, 3549, 0), "combat_bracelet_teleport_icon.png"),
CHAMPIONS_GUILD(TeleportType.JEWELLERY, "Combat Bracelet" , "Champions' Guild", new WorldPoint(3189, 3368, 0), "combat_bracelet_teleport_icon.png"),
EDGEVILLE_MONASTERY(TeleportType.JEWELLERY, "Combat Bracelet" , "Edgeville Monastery", new WorldPoint(3053, 3487, 0), "combat_bracelet_teleport_icon.png"),
diff --git a/runelite-client/src/main/java/net/runelite/client/ui/PluginPanel.java b/runelite-client/src/main/java/net/runelite/client/ui/PluginPanel.java
index e4a89930ea..b699717142 100644
--- a/runelite-client/src/main/java/net/runelite/client/ui/PluginPanel.java
+++ b/runelite-client/src/main/java/net/runelite/client/ui/PluginPanel.java
@@ -72,7 +72,7 @@ protected PluginPanel(boolean wrap)
wrappedPanel = new JPanel();
// Adjust the preferred size to expand to width of scrollbar to
- // to preven scrollbar overlapping over contents
+ // prevent scrollbar overlapping over contents
wrappedPanel.setPreferredSize(OUTER_PREFERRED_SIZE);
wrappedPanel.setLayout(new BorderLayout());
wrappedPanel.add(scrollPane, BorderLayout.CENTER);
diff --git a/runelite-client/src/main/java/net/runelite/client/ui/overlay/OverlayPanel.java b/runelite-client/src/main/java/net/runelite/client/ui/overlay/OverlayPanel.java
index 41afe1149c..53545fe313 100644
--- a/runelite-client/src/main/java/net/runelite/client/ui/overlay/OverlayPanel.java
+++ b/runelite-client/src/main/java/net/runelite/client/ui/overlay/OverlayPanel.java
@@ -96,11 +96,17 @@ else if (getPreferredSize().width <= ComponentConstants.STANDARD_WIDTH * 0.8)
panelComponent.setBackgroundColor(getPreferredColor());
}
- final Dimension dimension = panelComponent.render(graphics);
-
- if (clearChildren)
+ final Dimension dimension;
+ try
+ {
+ dimension = panelComponent.render(graphics);
+ }
+ finally
{
- panelComponent.getChildren().clear();
+ if (clearChildren)
+ {
+ panelComponent.getChildren().clear();
+ }
}
panelComponent.setPreferredSize(oldSize);
diff --git a/runelite-client/src/main/java/net/runelite/client/util/ImageCapture.java b/runelite-client/src/main/java/net/runelite/client/util/ImageCapture.java
index fbaed6d8bb..959eadf167 100644
--- a/runelite-client/src/main/java/net/runelite/client/util/ImageCapture.java
+++ b/runelite-client/src/main/java/net/runelite/client/util/ImageCapture.java
@@ -113,8 +113,7 @@ public void takeScreenshot(@Nullable String subDir, String fileName, boolean inc
public BufferedImage addClientFrame(Image image)
{
// create a new image, paint the client ui to it, and then draw the screenshot to that
- final AffineTransform transform = OSType.getOSType() == OSType.MacOS ? new AffineTransform() :
- clientUi.getGraphicsConfiguration().getDefaultTransform();
+ final AffineTransform transform = clientUi.getGraphicsConfiguration().getDefaultTransform();
// on Windows the insets are the window border
Insets insets = clientUi.getInsets();
diff --git a/runelite-client/src/main/resources/net/runelite/client/plugins/loginscreen/varlamore.jpg b/runelite-client/src/main/resources/net/runelite/client/plugins/loginscreen/varlamore.jpg
new file mode 100644
index 0000000000..3b8a8a6ddf
Binary files /dev/null and b/runelite-client/src/main/resources/net/runelite/client/plugins/loginscreen/varlamore.jpg differ
diff --git a/runelite-client/src/main/resources/net/runelite/client/ui/laf/RuneLiteLAF.properties b/runelite-client/src/main/resources/net/runelite/client/ui/laf/RuneLiteLAF.properties
index 1b1f9afc98..3924f9c117 100644
--- a/runelite-client/src/main/resources/net/runelite/client/ui/laf/RuneLiteLAF.properties
+++ b/runelite-client/src/main/resources/net/runelite/client/ui/laf/RuneLiteLAF.properties
@@ -83,6 +83,9 @@ MenuBar.border=0,0,0,0
MenuItem.iconTextGap=0
MenuItem.minimumIconSize=0,0
+PasswordField.showRevealButton=true
+PasswordField.font=dialog 12
+
RadioButtonUI=net.runelite.client.ui.laf.RuneLiteRadioButtonUI
RootPaneUI=net.runelite.client.ui.laf.RuneLiteRootPaneUI
diff --git a/runelite-client/src/main/scripts/MagicSpellbookRedraw.hash b/runelite-client/src/main/scripts/MagicSpellbookRedraw.hash
new file mode 100644
index 0000000000..1d586f5167
--- /dev/null
+++ b/runelite-client/src/main/scripts/MagicSpellbookRedraw.hash
@@ -0,0 +1 @@
+ACCA9A2E3AE4280269643C9319582C301F5DFE90E03D11EE124824DB4D6E4C17
\ No newline at end of file
diff --git a/runelite-client/src/main/scripts/MagicSpellbookRedraw.rs2asm b/runelite-client/src/main/scripts/MagicSpellbookRedraw.rs2asm
new file mode 100644
index 0000000000..2d46babee6
--- /dev/null
+++ b/runelite-client/src/main/scripts/MagicSpellbookRedraw.rs2asm
@@ -0,0 +1,954 @@
+.id 2611
+.int_stack_count 11
+.string_stack_count 2
+.int_var_count 39
+.string_var_count 2
+ iconst 190
+ istore 11
+ iconst 261
+ istore 12
+ iconst 0
+ istore 13
+ iload 10
+ iconst 1
+ if_icmpeq LABEL10
+ jump LABEL76
+LABEL10:
+ iconst 6
+ iconst 240
+ iconst 1
+ iconst 0
+ iload 3
+ if_setsize
+ iconst 190
+ iconst 6
+ sub
+ iconst 240
+ istore 12
+ istore 11
+ iconst 0
+ iconst 0
+ iconst 1
+ iconst 0
+ iload 3
+ if_setposition
+ iconst 0
+ iload 4
+ if_sethide
+ sload 0
+ iconst 190
+ iconst 494
+ parawidth
+ sload 1
+ iconst 190
+ iconst 494
+ parawidth
+ invoke 1045
+ iconst 14
+ add
+ istore 13
+ iload 13
+ iconst 0
+ iconst 0
+ iconst 1
+ iload 5
+ if_setsize
+ iload 13
+ iconst 0
+ iconst 0
+ iconst 1
+ iload 6
+ if_setsize
+ iconst 190
+ iload 13
+ iconst 2
+ multiply
+ sub
+ iconst 3
+ div
+ istore 13
+ iload 13
+ iconst 0
+ iconst 0
+ iconst 1
+ iload 5
+ if_setposition
+ iload 13
+ iconst 0
+ iconst 2
+ iconst 1
+ iload 6
+ if_setposition
+ jump LABEL147
+LABEL76:
+ get_varbit 6718
+ iconst 1
+ if_icmpeq LABEL80
+ jump LABEL109
+LABEL80:
+ iconst 0
+ iconst 0
+ iconst 1
+ iconst 1
+ iload 3
+ if_setsize
+ iconst 0
+ iconst 0
+ iconst 1
+ iconst 1
+ iload 3
+ if_setposition
+ iconst 1
+ iload 4
+ if_sethide
+ iconst -1
+ iload 10
+ iload 5
+ iload 6
+ iload 0
+ iload 1
+ iload 7
+ iload 8
+ iload 9
+ iload 2
+ sload 0
+ sload 1
+ invoke 2603
+ jump LABEL147
+LABEL109:
+ iconst 6
+ iconst 240
+ iconst 1
+ iconst 0
+ iload 3
+ if_setsize
+ iconst 190
+ iconst 6
+ sub
+ iconst 240
+ istore 12
+ istore 11
+ iconst 0
+ iconst 0
+ iconst 1
+ iconst 0
+ iload 3
+ if_setposition
+ iconst 0
+ iload 4
+ if_sethide
+ sload 1
+ iconst 190
+ iconst 494
+ parawidth
+ iconst 14
+ add
+ iconst 0
+ iconst 0
+ iconst 1
+ iload 6
+ if_setsize
+ iconst 0
+ iconst 0
+ iconst 1
+ iconst 1
+ iload 6
+ if_setposition
+LABEL147:
+ iload 0
+ cc_deleteall
+ iload 1
+ cc_deleteall
+ iload 2
+ cc_deleteall
+ iconst 105
+ iconst 103
+ iconst 1981
+ get_varbit 4070
+ enum
+ istore 14
+ iconst 105
+ iconst 103
+ iconst 5280
+ get_varbit 4070
+ enum
+ istore 15
+ get_varbit 9730
+ iconst 0
+ if_icmpge LABEL169
+ jump LABEL175
+LABEL169:
+ iconst 105
+ iconst 103
+ iload 15
+ get_varbit 9730
+ enum
+ istore 14
+LABEL175:
+ iconst 0
+ istore 16
+ iconst 1981
+ enum_getoutputcount
+ istore 17
+ iconst 1
+ istore 18
+ iconst 0
+ istore 19
+ iconst -1
+ istore 20
+LABEL186:
+ iload 16
+ iload 17
+ if_icmplt LABEL190
+ jump LABEL239
+LABEL190:
+ iconst 105
+ iconst 103
+ iconst 1981
+ iload 16
+ enum
+ istore 20
+ iload 20
+ iload 14
+ if_icmpne LABEL200
+ jump LABEL202
+LABEL200:
+ iload 20
+ invoke 2618
+LABEL202:
+ iconst 105
+ iconst 103
+ iconst 5280
+ iload 16
+ enum
+ istore 15
+ iconst 1
+ istore 18
+ iload 15
+ enum_getoutputcount
+ istore 19
+LABEL213:
+ iload 18
+ iload 19
+ if_icmple LABEL217
+ jump LABEL234
+LABEL217:
+ iconst 105
+ iconst 103
+ iload 15
+ iload 18
+ enum
+ istore 20
+ iload 20
+ iload 14
+ if_icmpne LABEL227
+ jump LABEL229
+LABEL227:
+ iload 20
+ invoke 2618
+LABEL229:
+ iload 18
+ iconst 1
+ add
+ istore 18
+ jump LABEL213
+LABEL234:
+ iload 16
+ iconst 1
+ add
+ istore 16
+ jump LABEL186
+LABEL239:
+ iload 14
+ iconst -1
+ if_icmpeq LABEL243
+ jump LABEL244
+LABEL243:
+ return
+LABEL244:
+ iload 14
+ enum_getoutputcount
+ istore 21
+ iload 21
+ define_array 105
+ iconst 0
+ istore 22
+ iconst -1
+ istore 23
+ iconst 0
+ istore 24
+ iload 10
+ iconst 0
+ if_icmpeq LABEL259
+ jump LABEL298
+LABEL259:
+ get_varbit 6718
+ iconst 1
+ if_icmpeq LABEL263
+ jump LABEL298
+LABEL263:
+ iload 24
+ iload 21
+ if_icmplt LABEL267
+ jump LABEL297
+LABEL267:
+ iconst 105
+ iconst 111
+ iload 14
+ iload 24
+ enum
+ istore 23
+ invoke 3160
+ iconst 1
+ if_icmpeq LABEL277
+ jump LABEL280
+LABEL277:
+ iload 23
+ invoke 3159
+ istore 23
+LABEL280:
+ iconst 0
+ iload 23
+ iconst 596
+ oc_param
+ if_sethide
+ iload 22
+ iload 24
+ set_array_int
+ iload 22
+ iconst 1
+ add
+ istore 22
+ iload 24
+ iconst 1
+ add
+ istore 24
+ jump LABEL263
+LABEL297:
+ jump LABEL343
+LABEL298:
+ iload 24
+ iload 21
+ if_icmplt LABEL302
+ jump LABEL343
+LABEL302:
+ iconst 105
+ iconst 111
+ iload 14
+ iload 24
+ enum
+ istore 23
+ invoke 3160
+ iconst 1
+ if_icmpeq LABEL312
+ jump LABEL315
+LABEL312:
+ iload 23
+ invoke 3159
+ istore 23
+LABEL315:
+ iload 23
+ invoke 2619
+ iconst 1
+ if_icmpeq LABEL320
+ jump LABEL333
+LABEL320:
+ iconst 0
+ iload 23
+ iconst 596
+ oc_param
+ if_sethide
+ iload 22
+ iload 24
+ set_array_int
+ iload 22
+ iconst 1
+ add
+ istore 22
+ jump LABEL338
+LABEL333:
+ iconst 1
+ iload 23
+ iconst 596
+ oc_param
+ if_sethide
+LABEL338:
+ iload 24
+ iconst 1
+ add
+ istore 24
+ jump LABEL298
+LABEL343:
+ iconst 0
+ istore 25
+ iload 22
+ iconst 2
+ if_icmpge LABEL349
+ jump LABEL357
+LABEL349:
+ iconst 0
+ iconst 0
+ iload 22
+ iconst 1
+ sub
+ iload 14
+ invoke 2621
+
+ ; after sorting the spell array
+ iload 14 ; spellbook enum
+ iconst 0 ; spell array id
+ iload 22 ; number of spells
+ sconst "spellbookSort"
+ runelite_callback
+ istore 22 ; number of spells
+ pop_int ; spell array id
+ pop_int ; spellbook enum
+
+ jump LABEL392
+LABEL357:
+ iload 22
+ iconst 0
+ if_icmple LABEL361
+ jump LABEL392
+LABEL361:
+ iload 0
+ iconst 4
+ iload 25
+ cc_create
+ iconst 0
+ iconst 0
+ iconst 1
+ iconst 1
+ cc_setsize
+ iconst 0
+ iconst 0
+ iconst 1
+ iconst 1
+ cc_setposition
+ iconst 16750623
+ cc_setcolour
+ iconst 495
+ cc_settextfont
+ iconst 1
+ cc_settextshadow
+ iconst 1
+ iconst 1
+ iconst 0
+ cc_settextalign
+ sconst "No spells match your selected filters."
+ cc_settext
+ iload 25
+ iconst 1
+ add
+ istore 25
+ return
+LABEL392:
+ iconst 24
+ istore 26
+ iconst 0
+ istore 27
+ iconst 0
+ istore 28
+ iconst 0
+ istore 29
+ iconst 0
+ istore 30
+ iload 12
+ istore 31
+ iload 10
+ iconst 0
+ if_icmpeq LABEL408
+ jump LABEL458
+LABEL408:
+ get_varbit 6718
+ iconst 1
+ if_icmpeq LABEL412
+ jump LABEL458
+LABEL412:
+ get_varbit 4070
+ invoke 6419
+ istore 29
+ istore 30
+ istore 28
+ istore 27
+ get_varbit 4070
+ switch
+ 1: LABEL427
+ 2: LABEL434
+ 3: LABEL441
+ iconst 1
+ iconst 15
+ iconst 1
+ iconst 0
+ iload 0
+ if_setposition
+ jump LABEL447
+LABEL427:
+ iconst 2
+ iconst 8
+ iconst 1
+ iconst 0
+ iload 0
+ if_setposition
+ jump LABEL447
+LABEL434:
+ iconst 0
+ iconst 8
+ iconst 1
+ iconst 0
+ iload 0
+ if_setposition
+ jump LABEL447
+LABEL441:
+ iconst 0
+ iconst 0
+ iconst 1
+ iconst 0
+ iload 0
+ if_setposition
+LABEL447:
+ iload 28
+ iload 26
+ multiply
+ iload 28
+ iconst 1
+ sub
+ iload 29
+ multiply
+ add
+ istore 31
+ jump LABEL641
+LABEL458:
+ get_varbit 6548
+ iconst 1
+ if_icmpeq LABEL472
+ iload 10
+ iconst 0
+ if_icmpeq LABEL465
+ jump LABEL552
+LABEL465:
+ get_varbit 8121
+ iconst 1
+ if_icmpeq LABEL472
+ get_varbit 6549
+ iconst 1
+ if_icmpeq LABEL472
+ jump LABEL552
+LABEL472:
+ iload 22
+ iconst 28
+ if_icmple LABEL476
+ jump LABEL479
+LABEL476:
+ iconst 4
+ istore 27
+ jump LABEL489
+LABEL479:
+ iconst 4
+ iconst 7
+ iload 22
+ iconst 8
+ add
+ iconst 9
+ div
+ invoke 1046
+ invoke 1045
+ istore 27
+LABEL489:
+ iconst 0
+ iload 26
+ iload 11
+ iload 26
+ iload 27
+ multiply
+ sub
+ iload 27
+ iconst 1
+ sub
+ div
+ invoke 1046
+ invoke 1045
+ istore 30
+ iconst 1
+ iload 22
+ iload 27
+ iconst 1
+ sub
+ add
+ iload 27
+ div
+ invoke 1045
+ istore 28
+ iload 28
+ iconst 2
+ if_icmpge LABEL517
+ jump LABEL531
+LABEL517:
+ iconst 0
+ iload 30
+ iload 12
+ iload 26
+ iload 28
+ multiply
+ sub
+ iload 28
+ iconst 1
+ sub
+ div
+ invoke 1046
+ invoke 1045
+ istore 29
+LABEL531:
+ iload 28
+ iload 26
+ multiply
+ iload 28
+ iconst 1
+ sub
+ iload 29
+ multiply
+ add
+ iload 12
+ iconst 30
+ sub
+ invoke 1045
+ istore 31
+ iconst 0
+ iconst 0
+ iconst 1
+ iconst 1
+ iload 0
+ if_setposition
+ jump LABEL641
+LABEL552:
+ iload 22
+ iconst 15
+ if_icmple LABEL556
+ jump LABEL561
+LABEL556:
+ iconst 40
+ iconst 3
+ istore 27
+ istore 26
+ jump LABEL580
+LABEL561:
+ iload 22
+ iconst 20
+ if_icmple LABEL565
+ jump LABEL570
+LABEL565:
+ iconst 40
+ iconst 4
+ istore 27
+ istore 26
+ jump LABEL580
+LABEL570:
+ iconst 4
+ iconst 7
+ iload 22
+ iconst 8
+ add
+ iconst 9
+ div
+ invoke 1046
+ invoke 1045
+ istore 27
+LABEL580:
+ iconst 0
+ iconst 5
+ iconst 7
+ iload 26
+ scale
+ iload 11
+ iload 26
+ iload 27
+ multiply
+ sub
+ iload 27
+ iconst 1
+ sub
+ div
+ invoke 1046
+ invoke 1045
+ istore 30
+ iconst 1
+ iload 22
+ iload 27
+ iconst 1
+ sub
+ add
+ iload 27
+ div
+ invoke 1045
+ istore 28
+ iload 28
+ iconst 2
+ if_icmpge LABEL611
+ jump LABEL625
+LABEL611:
+ iconst 0
+ iload 30
+ iload 12
+ iload 26
+ iload 28
+ multiply
+ sub
+ iload 28
+ iconst 1
+ sub
+ div
+ invoke 1046
+ invoke 1045
+ istore 29
+LABEL625:
+ iload 28
+ iload 26
+ multiply
+ iload 28
+ iconst 1
+ sub
+ iload 29
+ multiply
+ add
+ istore 31
+ iconst 0
+ iconst 0
+ iconst 1
+ iconst 1
+ iload 0
+ if_setposition
+LABEL641:
+ iload 27
+ iload 26
+ multiply
+ iload 27
+ iconst 1
+ sub
+ iload 30
+ multiply
+ add
+ iload 31
+ iconst 0
+ iconst 0
+ iload 0
+ if_setsize
+ iconst 0
+ istore 32
+ iconst -1
+ istore 33
+ iload 26
+ iload 30
+ add
+ istore 34
+ iload 26
+ iload 29
+ add
+ istore 35
+ iconst -1
+ istore 36
+ iconst 0
+ istore 37
+ iconst 0
+ istore 38
+ iconst 0
+ istore 24
+LABEL675:
+ iload 24
+ iload 22
+ if_icmplt LABEL679
+ jump LABEL856
+LABEL679:
+ iconst 105
+ iconst 111
+ iload 14
+ iload 24
+ get_array_int
+ enum
+ istore 23
+ invoke 3160
+ iconst 1
+ if_icmpeq LABEL690
+ jump LABEL693
+LABEL690:
+ iload 23
+ invoke 3159
+ istore 23
+LABEL693:
+ iload 23
+ iconst 596
+ oc_param
+ istore 33
+ iload 26
+ iload 26
+ iconst 0
+ iconst 0
+ iload 33
+ if_setsize
+ iload 24
+ iload 27
+ mod
+ iload 34
+ multiply
+ iload 24
+ iload 27
+ div
+ iload 35
+ multiply
+ istore 38
+ istore 37
+ iload 37
+ iload 38
+ iconst 0
+ iconst 0
+ iload 33
+ if_setposition
+ iload 23
+ iload 33
+ iload 26
+ invoke 2614
+ istore 36
+ istore 32
+ iload 32
+ iconst 1
+ if_icmpeq LABEL731
+ jump LABEL747
+LABEL731:
+ iload 26
+ iconst 40
+ if_icmpge LABEL735
+ jump LABEL741
+LABEL735:
+ iload 23
+ iconst 599
+ oc_param
+ iload 33
+ if_setgraphic
+ jump LABEL746
+LABEL741:
+ iload 23
+ iconst 597
+ oc_param
+ iload 33
+ if_setgraphic
+LABEL746:
+ jump LABEL786
+LABEL747:
+ iload 26
+ iconst 40
+ if_icmpge LABEL751
+ jump LABEL757
+LABEL751:
+ iload 23
+ iconst 600
+ oc_param
+ iload 33
+ if_setgraphic
+ jump LABEL762
+LABEL757:
+ iload 23
+ iconst 598
+ oc_param
+ iload 33
+ if_setgraphic
+LABEL762:
+ iload 36
+ iconst -1
+ if_icmpne LABEL766
+ jump LABEL786
+LABEL766:
+ iload 0
+ iconst 5
+ iload 25
+ cc_create
+ iload 26
+ iload 26
+ iconst 0
+ iconst 0
+ cc_setsize
+ iload 37
+ iload 38
+ iconst 0
+ iconst 0
+ cc_setposition
+ iload 36
+ cc_setgraphic
+ iload 25
+ iconst 1
+ add
+ istore 25
+LABEL786:
+ iload 33
+ invoke 2615
+ iload 10
+ iconst 1
+ if_icmpeq LABEL792
+ jump LABEL819
+LABEL792:
+ iload 1
+ iconst 5
+ iload 24
+ cc_create
+ iload 26
+ iload 26
+ iconst 0
+ iconst 0
+ cc_setsize
+ iload 37
+ iload 38
+ iconst 0
+ iconst 0
+ cc_setposition
+ iload 23
+ iconst 1
+ cc_setobject
+ iconst 255
+ cc_settrans
+ iconst 2612
+ iload 23
+ iload 1
+ iload 2
+ iload 12
+ sconst "oIIi"
+ cc_setonclick
+ jump LABEL851
+LABEL819:
+ iconst 2622
+ iconst 1
+ iload 23
+ iconst -2147483645
+ iconst -1
+ iload 2
+ iload 12
+ iconst 94
+ iconst 3
+ inv_getobj
+ iconst 94
+ iconst 5
+ inv_getobj
+ sconst "1oIiIioo"
+ iload 33
+ if_setonmouserepeat
+ iconst 2622
+ iconst 0
+ iload 23
+ iconst -2147483645
+ iconst -1
+ iload 2
+ iload 12
+ iconst 94
+ iconst 3
+ inv_getobj
+ iconst 94
+ iconst 5
+ inv_getobj
+ sconst "1oIiIioo"
+ iload 33
+ if_setonmouseleave
+LABEL851:
+ iload 24
+ iconst 1
+ add
+ istore 24
+ jump LABEL675
+LABEL856:
+ return
diff --git a/runelite-client/src/test/java/net/runelite/client/plugins/cannon/CannonPluginTest.java b/runelite-client/src/test/java/net/runelite/client/plugins/cannon/CannonPluginTest.java
index e63dbf8a2c..a13e29e046 100644
--- a/runelite-client/src/test/java/net/runelite/client/plugins/cannon/CannonPluginTest.java
+++ b/runelite-client/src/test/java/net/runelite/client/plugins/cannon/CannonPluginTest.java
@@ -35,6 +35,7 @@
import net.runelite.api.events.ChatMessage;
import net.runelite.api.events.VarbitChanged;
import net.runelite.client.Notifier;
+import net.runelite.client.config.Notification;
import net.runelite.client.game.ItemManager;
import net.runelite.client.ui.overlay.OverlayManager;
import net.runelite.client.ui.overlay.infobox.InfoBoxManager;
@@ -44,6 +45,7 @@
import org.junit.Test;
import org.junit.runner.RunWith;
import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.eq;
import org.mockito.Mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.times;
@@ -138,7 +140,7 @@ public void testCannonInfoBox()
@Test
public void testThresholdNotificationShouldNotify()
{
- when(config.showCannonNotifications()).thenReturn(true);
+ when(config.showCannonNotifications()).thenReturn(Notification.ON);
when(config.lowWarningThreshold()).thenReturn(10);
cannonAmmoChanged.setValue(30);
@@ -146,13 +148,13 @@ public void testThresholdNotificationShouldNotify()
cannonAmmoChanged.setValue(10);
plugin.onVarbitChanged(cannonAmmoChanged);
- verify(notifier, times(1)).notify("Your cannon has 10 cannon balls remaining!");
+ verify(notifier, times(1)).notify(Notification.ON, "Your cannon has 10 cannon balls remaining!");
}
@Test
public void testThresholdNotificationShouldNotifyOnce()
{
- when(config.showCannonNotifications()).thenReturn(true);
+ when(config.showCannonNotifications()).thenReturn(Notification.ON);
when(config.lowWarningThreshold()).thenReturn(10);
for (int cballs = 15; cballs >= 8; --cballs)
@@ -161,13 +163,12 @@ public void testThresholdNotificationShouldNotifyOnce()
plugin.onVarbitChanged(cannonAmmoChanged);
}
- verify(notifier, times(1)).notify("Your cannon has 10 cannon balls remaining!");
+ verify(notifier, times(1)).notify(Notification.ON, "Your cannon has 10 cannon balls remaining!");
}
@Test
public void testThresholdNotificationsShouldNotNotify()
{
- when(config.showCannonNotifications()).thenReturn(true);
when(config.lowWarningThreshold()).thenReturn(0);
cannonAmmoChanged.setValue(30);
@@ -175,17 +176,17 @@ public void testThresholdNotificationsShouldNotNotify()
cannonAmmoChanged.setValue(10);
plugin.onVarbitChanged(cannonAmmoChanged);
- verify(notifier, never()).notify("Your cannon has 10 cannon balls remaining!");
+ verify(notifier, never()).notify(any(Notification.class), eq("Your cannon has 10 cannon balls remaining!"));
}
@Test
public void testCannonOutOfAmmo()
{
- when(config.showCannonNotifications()).thenReturn(true);
+ when(config.showCannonNotifications()).thenReturn(Notification.ON);
ChatMessage cannonOutOfAmmo = new ChatMessage(null, ChatMessageType.GAMEMESSAGE, "", "Your cannon is out of ammo!", "", 0);
plugin.onChatMessage(cannonOutOfAmmo);
- verify(notifier, times(1)).notify("Your cannon is out of ammo!");
+ verify(notifier, times(1)).notify(Notification.ON, "Your cannon is out of ammo!");
}
}
diff --git a/runelite-client/src/test/java/net/runelite/client/plugins/chatnotifications/ChatNotificationsPluginTest.java b/runelite-client/src/test/java/net/runelite/client/plugins/chatnotifications/ChatNotificationsPluginTest.java
index 1ec30ad41f..5dde2fcb81 100644
--- a/runelite-client/src/test/java/net/runelite/client/plugins/chatnotifications/ChatNotificationsPluginTest.java
+++ b/runelite-client/src/test/java/net/runelite/client/plugins/chatnotifications/ChatNotificationsPluginTest.java
@@ -86,12 +86,15 @@ public void onChatMessage()
{
when(config.highlightWordsString()).thenReturn("Deathbeam, Deathbeam OSRS , test");
+ var message = "Deathbeam, Deathbeam OSRS";
MessageNode messageNode = mock(MessageNode.class);
- when(messageNode.getValue()).thenReturn("Deathbeam, Deathbeam OSRS");
+ when(messageNode.getValue()).thenReturn(message);
ChatMessage chatMessage = new ChatMessage();
chatMessage.setType(ChatMessageType.PUBLICCHAT);
chatMessage.setMessageNode(messageNode);
+ chatMessage.setMessage(message);
+ chatMessage.setName("");
chatNotificationsPlugin.startUp(); // load highlight config
chatNotificationsPlugin.onChatMessage(chatMessage);
@@ -104,12 +107,15 @@ public void testRegexMultiplePatternsMessage()
{
when(config.highlightRegexString()).thenReturn("brandie+\ntest");
+ var message = "brandieeee testing";
MessageNode messageNode = mock(MessageNode.class);
- when(messageNode.getValue()).thenReturn("brandieeee testing");
+ when(messageNode.getValue()).thenReturn(message);
ChatMessage chatMessage = new ChatMessage();
chatMessage.setType(ChatMessageType.PUBLICCHAT);
chatMessage.setMessageNode(messageNode);
+ chatMessage.setMessage(message);
+ chatMessage.setName("");
chatNotificationsPlugin.startUp();
chatNotificationsPlugin.onChatMessage(chatMessage);
@@ -122,12 +128,15 @@ public void testRegexMultiplePatternsWithOnlyOneMatch()
{
when(config.highlightRegexString()).thenReturn("brandie+\nwillNotMatch");
+ var message = "brandieeee testing";
MessageNode messageNode = mock(MessageNode.class);
- when(messageNode.getValue()).thenReturn("brandieeee testing");
+ when(messageNode.getValue()).thenReturn(message);
ChatMessage chatMessage = new ChatMessage();
chatMessage.setType(ChatMessageType.PUBLICCHAT);
chatMessage.setMessageNode(messageNode);
+ chatMessage.setMessage(message);
+ chatMessage.setName("");
chatNotificationsPlugin.startUp();
chatNotificationsPlugin.onChatMessage(chatMessage);
@@ -147,6 +156,8 @@ public void testLtGt()
ChatMessage chatMessage = new ChatMessage();
chatMessage.setType(ChatMessageType.PUBLICCHAT);
chatMessage.setMessageNode(messageNode);
+ chatMessage.setMessage(message);
+ chatMessage.setName("");
chatNotificationsPlugin.startUp(); // load highlight config
chatNotificationsPlugin.onChatMessage(chatMessage);
@@ -166,6 +177,8 @@ public void testMatchEntireMessage()
ChatMessage chatMessage = new ChatMessage();
chatMessage.setType(ChatMessageType.PUBLICCHAT);
chatMessage.setMessageNode(messageNode);
+ chatMessage.setMessage(message);
+ chatMessage.setName("");
chatNotificationsPlugin.startUp(); // load highlight config
chatNotificationsPlugin.onChatMessage(chatMessage);
@@ -185,6 +198,8 @@ public void testFullStop()
ChatMessage chatMessage = new ChatMessage();
chatMessage.setType(ChatMessageType.PUBLICCHAT);
chatMessage.setMessageNode(messageNode);
+ chatMessage.setMessage(message);
+ chatMessage.setName("");
chatNotificationsPlugin.startUp(); // load highlight config
chatNotificationsPlugin.onChatMessage(chatMessage);
@@ -204,6 +219,8 @@ public void testColor()
ChatMessage chatMessage = new ChatMessage();
chatMessage.setType(ChatMessageType.PUBLICCHAT);
chatMessage.setMessageNode(messageNode);
+ chatMessage.setMessage(message);
+ chatMessage.setName("");
chatNotificationsPlugin.startUp(); // load highlight config
chatNotificationsPlugin.onChatMessage(chatMessage);
@@ -223,6 +240,8 @@ public void testPrecedingColor()
ChatMessage chatMessage = new ChatMessage();
chatMessage.setType(ChatMessageType.PUBLICCHAT);
chatMessage.setMessageNode(messageNode);
+ chatMessage.setMessage(message);
+ chatMessage.setName("");
chatNotificationsPlugin.startUp(); // load highlight config
chatNotificationsPlugin.onChatMessage(chatMessage);
@@ -242,6 +261,8 @@ public void testEmoji()
ChatMessage chatMessage = new ChatMessage();
chatMessage.setType(ChatMessageType.PUBLICCHAT);
chatMessage.setMessageNode(messageNode);
+ chatMessage.setMessage(message);
+ chatMessage.setName("");
chatNotificationsPlugin.startUp(); // load highlight config
chatNotificationsPlugin.onChatMessage(chatMessage);
@@ -261,6 +282,8 @@ public void testNonMatchedColors()
ChatMessage chatMessage = new ChatMessage();
chatMessage.setType(ChatMessageType.PUBLICCHAT);
chatMessage.setMessageNode(messageNode);
+ chatMessage.setName("");
+ chatMessage.setMessage(message);
chatNotificationsPlugin.startUp(); // load highlight config
chatNotificationsPlugin.onChatMessage(chatMessage);
diff --git a/runelite-client/src/test/java/net/runelite/client/plugins/grandexchange/GrandExchangePluginTest.java b/runelite-client/src/test/java/net/runelite/client/plugins/grandexchange/GrandExchangePluginTest.java
index 71fec9339f..0b7b0a900d 100644
--- a/runelite-client/src/test/java/net/runelite/client/plugins/grandexchange/GrandExchangePluginTest.java
+++ b/runelite-client/src/test/java/net/runelite/client/plugins/grandexchange/GrandExchangePluginTest.java
@@ -49,6 +49,7 @@
import net.runelite.client.Notifier;
import net.runelite.client.account.SessionManager;
import net.runelite.client.config.ConfigManager;
+import net.runelite.client.config.Notification;
import net.runelite.client.config.RuneLiteConfig;
import net.runelite.client.game.ItemManager;
import net.runelite.client.input.KeyManager;
@@ -337,7 +338,7 @@ public void testLogin()
@Test
public void testNotifyPartial()
{
- when(grandExchangeConfig.enableNotifications()).thenReturn(true);
+ when(grandExchangeConfig.enableNotifications()).thenReturn(Notification.ON);
ChatMessage chatMessage = new ChatMessage();
chatMessage.setType(ChatMessageType.GAMEMESSAGE);
@@ -345,13 +346,13 @@ public void testNotifyPartial()
grandExchangePlugin.onChatMessage(chatMessage);
- verify(notifier).notify(anyString());
+ verify(notifier).notify(any(Notification.class), anyString());
}
@Test
public void testNotifyComplete()
{
- when(grandExchangeConfig.notifyOnOfferComplete()).thenReturn(true);
+ when(grandExchangeConfig.notifyOnOfferComplete()).thenReturn(Notification.ON);
ChatMessage chatMessage = new ChatMessage();
chatMessage.setType(ChatMessageType.GAMEMESSAGE);
@@ -359,6 +360,6 @@ public void testNotifyComplete()
grandExchangePlugin.onChatMessage(chatMessage);
- verify(notifier).notify(anyString());
+ verify(notifier).notify(any(Notification.class), anyString());
}
}
\ No newline at end of file
diff --git a/runelite-client/src/test/java/net/runelite/client/plugins/idlenotifier/IdleNotifierPluginTest.java b/runelite-client/src/test/java/net/runelite/client/plugins/idlenotifier/IdleNotifierPluginTest.java
index 1991b0d1ff..7a41b880a6 100644
--- a/runelite-client/src/test/java/net/runelite/client/plugins/idlenotifier/IdleNotifierPluginTest.java
+++ b/runelite-client/src/test/java/net/runelite/client/plugins/idlenotifier/IdleNotifierPluginTest.java
@@ -47,6 +47,7 @@
import net.runelite.api.events.HitsplatApplied;
import net.runelite.api.events.InteractingChanged;
import net.runelite.client.Notifier;
+import net.runelite.client.config.Notification;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -123,9 +124,9 @@ public void setUp()
when(client.getLocalPlayer()).thenReturn(player);
// Mock config
- when(config.logoutIdle()).thenReturn(true);
- when(config.animationIdle()).thenReturn(true);
- when(config.interactionIdle()).thenReturn(true);
+ when(config.logoutIdle()).thenReturn(Notification.ON);
+ when(config.animationIdle()).thenReturn(Notification.ON);
+ when(config.interactionIdle()).thenReturn(Notification.ON);
when(config.getIdleNotificationDelay()).thenReturn(0);
when(config.getHitpointsThreshold()).thenReturn(42);
when(config.getPrayerThreshold()).thenReturn(42);
@@ -148,7 +149,7 @@ public void checkAnimationIdle()
when(player.getAnimation()).thenReturn(AnimationID.IDLE);
plugin.onAnimationChanged(animationChanged);
plugin.onGameTick(new GameTick());
- verify(notifier).notify("You are now idle!");
+ verify(notifier).notify(Notification.ON, "You are now idle!");
}
@Test
@@ -204,7 +205,7 @@ public void checkCombatIdle()
when(player.getInteracting()).thenReturn(null);
plugin.onInteractingChanged(new InteractingChanged(player, null));
plugin.onGameTick(new GameTick());
- verify(notifier).notify("You are now out of combat!");
+ verify(notifier).notify(Notification.ON, "You are now out of combat!");
}
@Test
@@ -270,7 +271,7 @@ public void doubleNotifyOnMouseReset()
plugin.onGameTick(new GameTick());
plugin.onGameTick(new GameTick());
- verify(notifier, times(1)).notify(any());
+ verify(notifier, times(1)).notify(any(Notification.class), any());
}
@Test
@@ -295,7 +296,7 @@ public void testSendOneNotificationForAnimationAndInteract()
plugin.onInteractingChanged(new InteractingChanged(player, null));
plugin.onGameTick(new GameTick());
- verify(notifier).notify("You are now idle!");
+ verify(notifier).notify(Notification.ON, "You are now idle!");
}
@Test
@@ -315,7 +316,7 @@ public void testSpecRegen()
@Test
public void testMovementIdle()
{
- when(config.movementIdle()).thenReturn(true);
+ when(config.movementIdle()).thenReturn(Notification.ON);
when(player.getWorldLocation()).thenReturn(new WorldPoint(0, 0, 0));
plugin.onGameTick(new GameTick());
@@ -324,6 +325,6 @@ public void testMovementIdle()
// No movement here
plugin.onGameTick(new GameTick());
- verify(notifier).notify(eq("You have stopped moving!"));
+ verify(notifier).notify(Notification.ON, "You have stopped moving!");
}
}
\ No newline at end of file
diff --git a/runelite-client/src/test/java/net/runelite/client/plugins/menuentryswapper/MenuEntrySwapperPluginTest.java b/runelite-client/src/test/java/net/runelite/client/plugins/menuentryswapper/MenuEntrySwapperPluginTest.java
index 97f75e8e31..6d2cc692c6 100644
--- a/runelite-client/src/test/java/net/runelite/client/plugins/menuentryswapper/MenuEntrySwapperPluginTest.java
+++ b/runelite-client/src/test/java/net/runelite/client/plugins/menuentryswapper/MenuEntrySwapperPluginTest.java
@@ -41,6 +41,7 @@
import net.runelite.client.config.ConfigManager;
import net.runelite.client.game.ItemManager;
import net.runelite.client.menus.TestMenuEntry;
+import org.junit.After;
import static org.junit.Assert.assertArrayEquals;
import org.junit.Before;
import org.junit.Test;
@@ -111,7 +112,13 @@ public void before()
return null;
}).when(client).setMenuEntries(any(MenuEntry[].class));
- menuEntrySwapperPlugin.setupSwaps();
+ menuEntrySwapperPlugin.startUp();
+ }
+
+ @After
+ public void after()
+ {
+ menuEntrySwapperPlugin.shutDown();
}
private MenuEntry menu(String option, String target, MenuAction menuAction)
diff --git a/runelite-client/src/test/java/net/runelite/client/plugins/skillcalculator/CalculatorTypeTest.java b/runelite-client/src/test/java/net/runelite/client/plugins/skillcalculator/CalculatorTypeTest.java
index df5ee04041..355aa3fa8f 100644
--- a/runelite-client/src/test/java/net/runelite/client/plugins/skillcalculator/CalculatorTypeTest.java
+++ b/runelite-client/src/test/java/net/runelite/client/plugins/skillcalculator/CalculatorTypeTest.java
@@ -25,26 +25,74 @@
package net.runelite.client.plugins.skillcalculator;
import net.runelite.client.plugins.skillcalculator.skills.SkillAction;
+import net.runelite.client.plugins.skillcalculator.skills.SkillBonus;
import static org.junit.Assert.fail;
import org.junit.Test;
public class CalculatorTypeTest
{
+
@Test
- public void skillActionsInLevelOrder()
+ public void skillActionsInOrder()
{
for (final CalculatorType calculatorType : CalculatorType.values())
{
- int level = 1;
+ final String skillName = calculatorType.getSkill().getName();
+ int prevLevel = 0;
+ float prevXP = 0.0f;
+ String prevName = "";
for (final SkillAction skillAction : calculatorType.getSkillActions())
{
- if (skillAction.getLevel() < level)
+ int currentLevel = skillAction.getLevel();
+ float currentXP = skillAction.getXp();
+ String currentName = skillAction.toString();
+
+ if (currentLevel < prevLevel)
{
- fail("Skill action " + skillAction + " is out of order for " + calculatorType.getSkill().getName());
+ fail(skillName + " skill action " + skillAction + " is not ordered by level.");
}
+ else if (currentLevel == prevLevel)
+ {
+ if (currentXP < prevXP)
+ {
+ fail(skillName + " skill action " + skillAction + " is not ordered by xp among level " + currentLevel + " actions.");
+ }
+ else if (currentXP == prevXP && currentName.compareTo(prevName) < 0)
+ {
+ fail(skillName + " skill action " + skillAction + " is not ordered alphabetically among " + currentXP + "xp skills at level " + currentLevel + '.');
+ }
+ }
+
+ prevLevel = currentLevel;
+ prevXP = currentXP;
+ prevName = currentName;
+ }
+ }
+ }
- level = skillAction.getLevel();
+ @Test
+ public void testSkillBonusesMutuallyStack()
+ {
+ for (final CalculatorType calculatorType : CalculatorType.values())
+ {
+ final SkillBonus[] skillBonuses = calculatorType.getSkillBonuses();
+ if (skillBonuses == null)
+ {
+ continue;
+ }
+
+ final String skillName = calculatorType.getSkill().getName();
+
+ for (final SkillBonus skillBonus : skillBonuses)
+ {
+ for (final SkillBonus stackedSkillBonus : skillBonus.getCanBeStackedWith())
+ {
+ if (!stackedSkillBonus.getCanBeStackedWith().contains(skillBonus))
+ {
+ fail(skillName + " skill bonus " + skillBonus + " is not mutually stacked with skill bonus " + stackedSkillBonus);
+ }
+ }
}
}
}
diff --git a/runelite-client/src/test/java/net/runelite/client/plugins/skillcalculator/SkillCalculatorTest.java b/runelite-client/src/test/java/net/runelite/client/plugins/skillcalculator/SkillCalculatorTest.java
new file mode 100644
index 0000000000..4b9b36b964
--- /dev/null
+++ b/runelite-client/src/test/java/net/runelite/client/plugins/skillcalculator/SkillCalculatorTest.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2024, Jordan Atwood
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package net.runelite.client.plugins.skillcalculator;
+
+import static net.runelite.client.plugins.skillcalculator.SkillCalculator.formatBonusPercentage;
+import static org.junit.Assert.assertEquals;
+import org.junit.Test;
+
+public class SkillCalculatorTest
+{
+ @Test
+ public void testFormatBonusPercentage()
+ {
+ assertEquals("33.33", formatBonusPercentage(0.33333333f));
+ assertEquals("50", formatBonusPercentage(0.5f));
+ assertEquals("102.5", formatBonusPercentage(1.025f));
+ assertEquals("105", formatBonusPercentage(1.05f));
+ assertEquals("110", formatBonusPercentage(1.1f));
+ assertEquals("115", formatBonusPercentage(1.15f));
+ assertEquals("120", formatBonusPercentage(1.2f));
+ assertEquals("150", formatBonusPercentage(1.5f));
+ assertEquals("250", formatBonusPercentage(2.5f));
+ assertEquals("300", formatBonusPercentage(3f));
+ assertEquals("350", formatBonusPercentage(3.5f));
+ assertEquals("400", formatBonusPercentage(4f));
+ assertEquals("700", formatBonusPercentage(7f));
+ }
+}
diff --git a/runelite-client/src/test/java/net/runelite/client/plugins/slayer/SlayerPluginTest.java b/runelite-client/src/test/java/net/runelite/client/plugins/slayer/SlayerPluginTest.java
index 0fd2c1c632..7f36e52e4d 100644
--- a/runelite-client/src/test/java/net/runelite/client/plugins/slayer/SlayerPluginTest.java
+++ b/runelite-client/src/test/java/net/runelite/client/plugins/slayer/SlayerPluginTest.java
@@ -51,6 +51,7 @@
import net.runelite.client.chat.ChatClient;
import net.runelite.client.chat.ChatCommandManager;
import net.runelite.client.config.ConfigManager;
+import net.runelite.client.config.Notification;
import net.runelite.client.game.ItemManager;
import net.runelite.client.game.npcoverlay.NpcOverlayService;
import net.runelite.client.ui.overlay.OverlayManager;
@@ -71,7 +72,6 @@
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.verifyNoMoreInteractions;
import static org.mockito.Mockito.when;
import org.mockito.junit.MockitoJUnitRunner;
@@ -181,13 +181,9 @@ public void testSuperiorNotification()
{
ChatMessage chatMessageEvent = new ChatMessage(null, GAMEMESSAGE, "Superior", SUPERIOR_MESSAGE, null, 0);
- when(slayerConfig.showSuperiorNotification()).thenReturn(true);
+ when(slayerConfig.showSuperiorNotification()).thenReturn(Notification.ON);
slayerPlugin.onChatMessage(chatMessageEvent);
- verify(notifier).notify(SUPERIOR_MESSAGE);
-
- when(slayerConfig.showSuperiorNotification()).thenReturn(false);
- slayerPlugin.onChatMessage(chatMessageEvent);
- verifyNoMoreInteractions(notifier);
+ verify(notifier).notify(Notification.ON, SUPERIOR_MESSAGE);
}
@Test
diff --git a/runelite-client/src/test/java/net/runelite/client/plugins/specialcounter/SpecialCounterPluginTest.java b/runelite-client/src/test/java/net/runelite/client/plugins/specialcounter/SpecialCounterPluginTest.java
index 6d83d32766..a1c26dc38a 100644
--- a/runelite-client/src/test/java/net/runelite/client/plugins/specialcounter/SpecialCounterPluginTest.java
+++ b/runelite-client/src/test/java/net/runelite/client/plugins/specialcounter/SpecialCounterPluginTest.java
@@ -48,6 +48,7 @@
import net.runelite.api.events.VarbitChanged;
import net.runelite.client.Notifier;
import net.runelite.client.callback.ClientThread;
+import net.runelite.client.config.Notification;
import net.runelite.client.game.ItemManager;
import net.runelite.client.party.PartyService;
import net.runelite.client.party.WSClient;
@@ -194,7 +195,7 @@ public void testNotification()
when(client.getLocalPlayer()).thenReturn(player);
when(specialCounterConfig.bandosGodswordThreshold()).thenReturn(2);
- when(specialCounterConfig.thresholdNotification()).thenReturn(true);
+ when(specialCounterConfig.thresholdNotification()).thenReturn(Notification.ON);
when(client.getTickCount()).thenReturn(0);
@@ -240,7 +241,7 @@ public void testNotification()
specialCounterPlugin.onGameTick(new GameTick());
- verify(notifier).notify("Bandos Godsword special attack threshold reached!");
+ verify(notifier).notify(Notification.ON, "Bandos Godsword special attack threshold reached!");
}
@Test
@@ -253,7 +254,7 @@ public void testNotificationNotThreshold()
when(client.getLocalPlayer()).thenReturn(player);
when(player.getInteracting()).thenReturn(target);
when(specialCounterConfig.bandosGodswordThreshold()).thenReturn(3);
- lenient().when(specialCounterConfig.thresholdNotification()).thenReturn(true);
+ lenient().when(specialCounterConfig.thresholdNotification()).thenReturn(Notification.ON);
when(client.getTickCount()).thenReturn(0);
diff --git a/runelite-client/src/test/java/net/runelite/client/plugins/timers/TimersPluginTest.java b/runelite-client/src/test/java/net/runelite/client/plugins/timers/TimersPluginTest.java
index 0ae89c83c1..5499078c2a 100644
--- a/runelite-client/src/test/java/net/runelite/client/plugins/timers/TimersPluginTest.java
+++ b/runelite-client/src/test/java/net/runelite/client/plugins/timers/TimersPluginTest.java
@@ -34,9 +34,11 @@
import java.util.function.Predicate;
import net.runelite.api.ChatMessageType;
import net.runelite.api.Client;
+import net.runelite.api.GameState;
import net.runelite.api.Skill;
import net.runelite.api.Varbits;
import net.runelite.api.events.ChatMessage;
+import net.runelite.api.events.GameStateChanged;
import net.runelite.api.events.VarbitChanged;
import net.runelite.client.events.ConfigChanged;
import net.runelite.client.game.ItemManager;
@@ -301,7 +303,11 @@ class InstantRef
// test timer remove: verify the infobox was removed (and no more were added)
chatMessage = new ChatMessage(null, ChatMessageType.GAMEMESSAGE, "", "You have been defeated!", "", 0);
+ final GameStateChanged gameStateChanged = new GameStateChanged();
+ gameStateChanged.setGameState(GameState.LOADING);
+ when(client.getMapRegions()).thenReturn(new int[0]);
timersPlugin.onChatMessage(chatMessage);
+ timersPlugin.onGameStateChanged(gameStateChanged);
verify(infoBoxManager, times(3)).removeInfoBox(captor.capture());
verify(infoBoxManager, times(3)).addInfoBox(captor.capture());
}
diff --git a/runelite-client/src/test/java/net/runelite/client/plugins/woodcutting/WoodcuttingPluginTest.java b/runelite-client/src/test/java/net/runelite/client/plugins/woodcutting/WoodcuttingPluginTest.java
index 59ef70d7d6..36fb61f468 100644
--- a/runelite-client/src/test/java/net/runelite/client/plugins/woodcutting/WoodcuttingPluginTest.java
+++ b/runelite-client/src/test/java/net/runelite/client/plugins/woodcutting/WoodcuttingPluginTest.java
@@ -41,6 +41,7 @@
import net.runelite.api.events.GameObjectSpawned;
import net.runelite.api.events.ItemSpawned;
import net.runelite.client.Notifier;
+import net.runelite.client.config.Notification;
import net.runelite.client.plugins.woodcutting.config.ClueNestTier;
import net.runelite.client.ui.overlay.OverlayManager;
import static org.junit.Assert.assertEquals;
@@ -52,7 +53,6 @@
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoInteractions;
-import static org.mockito.Mockito.verifyNoMoreInteractions;
import static org.mockito.Mockito.when;
import org.mockito.junit.MockitoJUnitRunner;
@@ -131,13 +131,9 @@ public void testBirdsNest()
{
ChatMessage chatMessage = new ChatMessage(null, ChatMessageType.GAMEMESSAGE, "", BIRDS_NEST_MESSAGE, "", 0);
- when(woodcuttingConfig.showNestNotification()).thenReturn(true);
+ when(woodcuttingConfig.showNestNotification()).thenReturn(Notification.ON);
woodcuttingPlugin.onChatMessage(chatMessage);
- verify(notifier).notify("A bird nest has spawned!");
-
- when(woodcuttingConfig.showNestNotification()).thenReturn(false);
- woodcuttingPlugin.onChatMessage(chatMessage);
- verifyNoMoreInteractions(notifier);
+ verify(notifier).notify(Notification.ON, "A bird nest has spawned!");
}
@Test
@@ -149,12 +145,12 @@ public void testClueNestConfigSameAsSpawn()
when(beginnerTileItem.getId()).thenReturn(ItemID.CLUE_NEST_BEGINNER);
ItemSpawned beginnerClueSpawned = new ItemSpawned(tile, beginnerTileItem);
- when(woodcuttingConfig.showNestNotification()).thenReturn(true);
+ when(woodcuttingConfig.showNestNotification()).thenReturn(Notification.ON);
when(woodcuttingConfig.clueNestNotifyTier()).thenReturn(ClueNestTier.BEGINNER);
woodcuttingPlugin.onItemSpawned(beginnerClueSpawned);
woodcuttingPlugin.onChatMessage(nestChatMessage);
woodcuttingPlugin.onGameTick(null);
- verify(notifier).notify("A bird nest has spawned!");
+ verify(notifier).notify(Notification.ON, "A bird nest has spawned!");
}
@Test
@@ -166,12 +162,12 @@ public void testClueNestConfigSmallerThanSpawn()
when(eliteTileItem.getId()).thenReturn(ItemID.CLUE_NEST_ELITE);
ItemSpawned eliteClueSpawned = new ItemSpawned(tile, eliteTileItem);
- when(woodcuttingConfig.showNestNotification()).thenReturn(true);
+ when(woodcuttingConfig.showNestNotification()).thenReturn(Notification.ON);
when(woodcuttingConfig.clueNestNotifyTier()).thenReturn(ClueNestTier.BEGINNER);
woodcuttingPlugin.onItemSpawned(eliteClueSpawned);
woodcuttingPlugin.onChatMessage(nestChatMessage);
woodcuttingPlugin.onGameTick(null);
- verify(notifier).notify("A bird nest has spawned!");
+ verify(notifier).notify(Notification.ON, "A bird nest has spawned!");
}
@Test
@@ -183,7 +179,6 @@ public void testClueNestDisabledConfig()
when(eliteTileItem.getId()).thenReturn(ItemID.CLUE_NEST_ELITE);
ItemSpawned eliteClueSpawned = new ItemSpawned(tile, eliteTileItem);
- when(woodcuttingConfig.showNestNotification()).thenReturn(true);
when(woodcuttingConfig.clueNestNotifyTier()).thenReturn(ClueNestTier.DISABLED);
woodcuttingPlugin.onItemSpawned(eliteClueSpawned);
woodcuttingPlugin.onChatMessage(nestChatMessage);
@@ -200,7 +195,6 @@ public void testClueNestConfigLargerThanSpawn()
when(beginnerTileItem.getId()).thenReturn(ItemID.CLUE_NEST_BEGINNER);
ItemSpawned beginnerClueSpawned = new ItemSpawned(tile, beginnerTileItem);
- when(woodcuttingConfig.showNestNotification()).thenReturn(true);
when(woodcuttingConfig.clueNestNotifyTier()).thenReturn(ClueNestTier.HARD);
woodcuttingPlugin.onItemSpawned(beginnerClueSpawned);
woodcuttingPlugin.onChatMessage(nestChatMessage);
@@ -220,7 +214,7 @@ public void testClueNestPlayerDrop()
when(nestTileItem.getId()).thenReturn(ItemID.BIRD_NEST_22798);
ItemSpawned regularNestSpawned = new ItemSpawned(tile, nestTileItem);
- when(woodcuttingConfig.showNestNotification()).thenReturn(true);
+ when(woodcuttingConfig.showNestNotification()).thenReturn(Notification.ON);
// Player drops clue nest
woodcuttingPlugin.onItemSpawned(beginnerClueSpawned);
@@ -230,7 +224,7 @@ public void testClueNestPlayerDrop()
woodcuttingPlugin.onItemSpawned(regularNestSpawned);
woodcuttingPlugin.onChatMessage(nestChatMessage);
woodcuttingPlugin.onGameTick(null);
- verify(notifier).notify("A bird nest has spawned!");
+ verify(notifier).notify(Notification.ON, "A bird nest has spawned!");
}
@Test
@@ -244,7 +238,7 @@ public void testClueNestOtherItemSpawn()
TileItem anotherItemTileItem = mock(TileItem.class);
ItemSpawned anotherItemSpawned = new ItemSpawned(tile, anotherItemTileItem);
- when(woodcuttingConfig.showNestNotification()).thenReturn(true);
+ when(woodcuttingConfig.showNestNotification()).thenReturn(Notification.ON);
when(woodcuttingConfig.clueNestNotifyTier()).thenReturn(ClueNestTier.BEGINNER);
woodcuttingPlugin.onItemSpawned(beginnerClueSpawned);
@@ -252,7 +246,7 @@ public void testClueNestOtherItemSpawn()
woodcuttingPlugin.onChatMessage(nestChatMessage);
woodcuttingPlugin.onGameTick(null);
- verify(notifier).notify("A bird nest has spawned!");
+ verify(notifier).notify(Notification.ON, "A bird nest has spawned!");
}
@Test
diff --git a/runelite-jshell/pom.xml b/runelite-jshell/pom.xml
index b2a7d8e681..a5d8640445 100644
--- a/runelite-jshell/pom.xml
+++ b/runelite-jshell/pom.xml
@@ -30,7 +30,7 @@
net.runelite
runelite-parent
- 1.10.26.4
+ 1.10.27
jshell
diff --git a/runelite-maven-plugin/pom.xml b/runelite-maven-plugin/pom.xml
index ff6057eea8..868f013e4b 100644
--- a/runelite-maven-plugin/pom.xml
+++ b/runelite-maven-plugin/pom.xml
@@ -29,7 +29,7 @@
net.runelite
runelite-parent
- 1.10.26.4
+ 1.10.27
runelite-maven-plugin