diff --git a/buildSrc/src/main/kotlin/Dependencies.kt b/buildSrc/src/main/kotlin/Dependencies.kt index cf329910d8..2ffce44d4c 100644 --- a/buildSrc/src/main/kotlin/Dependencies.kt +++ b/buildSrc/src/main/kotlin/Dependencies.kt @@ -23,13 +23,11 @@ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -const val kotlinVersion = "1.3.50" - object ProjectVersions { const val launcherVersion = "2.0.4" - const val rlVersion = "1.5.44-SNAPSHOT" + const val rlVersion = "1.5.43" - const val openosrsVersion = "2.1.18-SNAPSHOT" + const val openosrsVersion = "2.1.18" const val rsversion = 187 const val cacheversion = 165 @@ -64,13 +62,8 @@ object Libraries { const val guice = "4.2.2" const val h2 = "1.4.200" const val hamcrest = "2.2" - const val httpcore = "4.4.12" - const val httpmime = "4.5.10" - const val javassist = "3.26.0-GA" const val javax = "1.3.2" const val javaxInject = "1" - const val jbsdiff = "1.0" - const val jclCore = "2.8" const val jedis = "3.1.0" const val jna = "5.5.0" const val jogamp = "2.3.2" @@ -114,7 +107,6 @@ object Libraries { const val apacheCommonsText = "org.apache.commons:commons-text:${Versions.apacheCommonsText}" const val asmAll = "org.ow2.asm:asm:${Versions.asm}" const val asmUtil = "org.ow2.asm:asm-util:${Versions.asm}" - const val asmTree = "org.ow2.asm:asm-tree:${Versions.asm}" const val commonsCli = "commons-cli:commons-cli:${Versions.commonsCli}" const val discord = "net.runelite:discord:${Versions.discord}" const val fernflower = "net.runelite:fernflower:${Versions.fernflower}" @@ -126,13 +118,8 @@ object Libraries { const val guiceTestlib = "com.google.inject.extensions:guice-testlib:${Versions.guice}" const val h2 = "com.h2database:h2:${Versions.h2}" const val hamcrest = "org.hamcrest:hamcrest-library:${Versions.hamcrest}" - const val httpcore = "org.apache.httpcomponents:httpcore:${Versions.httpcore}" - const val httpmime = "org.apache.httpcomponents:httpmime:${Versions.httpmime}" - const val javassist = "org.javassist:javassist:${Versions.javassist}" const val javax = "javax.annotation:javax.annotation-api:${Versions.javax}" const val javaxInject = "javax.inject:javax.inject:${Versions.javaxInject}" - const val jbsdiff = "io.sigpipe:jbsdiff:${Versions.jbsdiff}" - const val jclCore = "org.xeustechnologies:jcl-core:${Versions.jclCore}" const val jedis = "redis.clients:jedis:${Versions.jedis}" const val jna = "net.java.dev.jna:jna:${Versions.jna}" const val jnaPlatform = "net.java.dev.jna:jna-platform:${Versions.jna}" diff --git a/http-api/src/main/java/net/runelite/http/api/hiscore/HiscoreResult.java b/http-api/src/main/java/net/runelite/http/api/hiscore/HiscoreResult.java index 57f29c2910..3edb616233 100644 --- a/http-api/src/main/java/net/runelite/http/api/hiscore/HiscoreResult.java +++ b/http-api/src/main/java/net/runelite/http/api/hiscore/HiscoreResult.java @@ -65,6 +65,49 @@ public class HiscoreResult private Skill clueScrollElite; private Skill clueScrollMaster; private Skill lastManStanding; + private Skill abyssalSire; + private Skill alchemicalHydra; + private Skill barrowsChests; + private Skill bryophyta; + private Skill callisto; + private Skill cerberus; + private Skill chambersOfXeric; + private Skill chambersOfXericChallengeMode; + private Skill chaosElemental; + private Skill chaosFanatic; + private Skill commanderZilyana; + private Skill corporealBeast; + private Skill crazyArchaeologist; + private Skill dagannothPrime; + private Skill dagannothRex; + private Skill dagannothSupreme; + private Skill derangedArchaeologist; + private Skill generalGraardor; + private Skill giantMole; + private Skill grotesqueGuardians; + private Skill hespori; + private Skill kalphiteQueen; + private Skill kingBlackDragon; + private Skill kraken; + private Skill kreearra; + private Skill krilTsutsaroth; + private Skill mimic; + private Skill obor; + private Skill sarachnis; + private Skill scorpia; + private Skill skotizo; + private Skill gauntlet; + private Skill corruptedGauntlet; + private Skill theatreOfBlood; + private Skill thermonuclearSmokeDevil; + private Skill tzKalZuk; + private Skill tzTokJad; + private Skill venenatis; + private Skill vetion; + private Skill vorkath; + private Skill wintertodt; + private Skill zalcano; + private Skill zulrah; public Skill getSkill(HiscoreSkill skill) { @@ -140,8 +183,94 @@ public class HiscoreResult return getClueScrollMaster(); case LAST_MAN_STANDING: return getLastManStanding(); + case ABYSSAL_SIRE: + return abyssalSire; + case ALCHEMICAL_HYDRA: + return alchemicalHydra; + case BARROWS_CHESTS: + return barrowsChests; + case BRYOPHYTA: + return bryophyta; + case CALLISTO: + return callisto; + case CERBERUS: + return cerberus; + case CHAMBERS_OF_XERIC: + return chambersOfXeric; + case CHAMBERS_OF_XERIC_CHALLENGE_MODE: + return chambersOfXericChallengeMode; + case CHAOS_ELEMENTAL: + return chaosElemental; + case CHAOS_FANATIC: + return chaosFanatic; + case COMMMANDER_ZILYANA: + return commanderZilyana; + case CORPOREAL_BEAST: + return corporealBeast; + case CRAZY_ARCHAEOLOGIST: + return crazyArchaeologist; + case DAGANNOTH_PRIME: + return dagannothPrime; + case DAGANNOTH_REX: + return dagannothRex; + case DAGANNOTH_SUPREME: + return dagannothSupreme; + case DERANGED_ARCHAEOLOGIST: + return derangedArchaeologist; + case GENERAL_GRAARDOR: + return generalGraardor; + case GIANT_MOLE: + return giantMole; + case GROTESQUE_GUARDIANS: + return grotesqueGuardians; + case HESPORI: + return hespori; + case KALPHITE_QUEEN: + return kalphiteQueen; + case KING_BLACK_DRAGON: + return kingBlackDragon; + case KRAKEN: + return kraken; + case KREEARRA: + return kreearra; + case KRIL_TSUTSAROTH: + return krilTsutsaroth; + case MIMIC: + return mimic; + case OBOR: + return obor; + case SARACHNIS: + return sarachnis; + case SCORPIA: + return scorpia; + case SKOTIZO: + return skotizo; + case THE_GAUNTLET: + return gauntlet; + case THE_CORRUPTED_GAUNTLET: + return corruptedGauntlet; + case THEATRE_OF_BLOOD: + return theatreOfBlood; + case THERMONUCLEAR_SMOKE_DEVIL: + return thermonuclearSmokeDevil; + case TZKAL_ZUK: + return tzKalZuk; + case TZTOK_JAD: + return tzTokJad; + case VENENATIS: + return venenatis; + case VETION: + return vetion; + case VORKATH: + return vorkath; + case WINTERTODT: + return wintertodt; + case ZALCANO: + return zalcano; + case ZULRAH: + return zulrah; + default: + throw new IllegalArgumentException("Invalid hiscore skill"); } - - throw new IllegalArgumentException("Invalid hiscore item"); } } diff --git a/http-api/src/main/java/net/runelite/http/api/hiscore/HiscoreResultBuilder.java b/http-api/src/main/java/net/runelite/http/api/hiscore/HiscoreResultBuilder.java index 10394b4919..b9efab4e20 100644 --- a/http-api/src/main/java/net/runelite/http/api/hiscore/HiscoreResultBuilder.java +++ b/http-api/src/main/java/net/runelite/http/api/hiscore/HiscoreResultBuilder.java @@ -27,7 +27,7 @@ package net.runelite.http.api.hiscore; import java.util.ArrayList; import java.util.List; -public class HiscoreResultBuilder +class HiscoreResultBuilder { private String player; private final List skills = new ArrayList<>(); @@ -37,7 +37,7 @@ public class HiscoreResultBuilder this.player = player; } - public void setNextSkill(Skill skill) + void setNextSkill(Skill skill) { skills.add(skill); } @@ -51,41 +51,89 @@ public class HiscoreResultBuilder { HiscoreResult hiscoreResult = new HiscoreResult(); hiscoreResult.setPlayer(player); - hiscoreResult.setOverall(skills.get(0)); - hiscoreResult.setAttack(skills.get(1)); - hiscoreResult.setDefence(skills.get(2)); - hiscoreResult.setStrength(skills.get(3)); - hiscoreResult.setHitpoints(skills.get(4)); - hiscoreResult.setRanged(skills.get(5)); - hiscoreResult.setPrayer(skills.get(6)); - hiscoreResult.setMagic(skills.get(7)); - hiscoreResult.setCooking(skills.get(8)); - hiscoreResult.setWoodcutting(skills.get(9)); - hiscoreResult.setFletching(skills.get(10)); - hiscoreResult.setFishing(skills.get(11)); - hiscoreResult.setFiremaking(skills.get(12)); - hiscoreResult.setCrafting(skills.get(13)); - hiscoreResult.setSmithing(skills.get(14)); - hiscoreResult.setMining(skills.get(15)); - hiscoreResult.setHerblore(skills.get(16)); - hiscoreResult.setAgility(skills.get(17)); - hiscoreResult.setThieving(skills.get(18)); - hiscoreResult.setSlayer(skills.get(19)); - hiscoreResult.setFarming(skills.get(20)); - hiscoreResult.setRunecraft(skills.get(21)); - hiscoreResult.setHunter(skills.get(22)); - hiscoreResult.setConstruction(skills.get(23)); - hiscoreResult.setLeaguePoints(skills.get(24)); - hiscoreResult.setBountyHunterHunter(skills.get(25)); - hiscoreResult.setBountyHunterRogue(skills.get(26)); - hiscoreResult.setClueScrollAll(skills.get(27)); - hiscoreResult.setClueScrollBeginner(skills.get(28)); - hiscoreResult.setClueScrollEasy(skills.get(29)); - hiscoreResult.setClueScrollMedium(skills.get(30)); - hiscoreResult.setClueScrollHard(skills.get(31)); - hiscoreResult.setClueScrollElite(skills.get(32)); - hiscoreResult.setClueScrollMaster(skills.get(33)); - hiscoreResult.setLastManStanding(skills.get(34)); + int index = 0; + hiscoreResult.setOverall(skills.get(index++)); + hiscoreResult.setAttack(skills.get(index++)); + hiscoreResult.setDefence(skills.get(index++)); + hiscoreResult.setStrength(skills.get(index++)); + hiscoreResult.setHitpoints(skills.get(index++)); + hiscoreResult.setRanged(skills.get(index++)); + hiscoreResult.setPrayer(skills.get(index++)); + hiscoreResult.setMagic(skills.get(index++)); + hiscoreResult.setCooking(skills.get(index++)); + hiscoreResult.setWoodcutting(skills.get(index++)); + hiscoreResult.setFletching(skills.get(index++)); + hiscoreResult.setFishing(skills.get(index++)); + hiscoreResult.setFiremaking(skills.get(index++)); + hiscoreResult.setCrafting(skills.get(index++)); + hiscoreResult.setSmithing(skills.get(index++)); + hiscoreResult.setMining(skills.get(index++)); + hiscoreResult.setHerblore(skills.get(index++)); + hiscoreResult.setAgility(skills.get(index++)); + hiscoreResult.setThieving(skills.get(index++)); + hiscoreResult.setSlayer(skills.get(index++)); + hiscoreResult.setFarming(skills.get(index++)); + hiscoreResult.setRunecraft(skills.get(index++)); + hiscoreResult.setHunter(skills.get(index++)); + hiscoreResult.setConstruction(skills.get(index++)); + hiscoreResult.setLeaguePoints(skills.get(index++)); + hiscoreResult.setBountyHunterHunter(skills.get(index++)); + hiscoreResult.setBountyHunterRogue(skills.get(index++)); + hiscoreResult.setClueScrollAll(skills.get(index++)); + hiscoreResult.setClueScrollBeginner(skills.get(index++)); + hiscoreResult.setClueScrollEasy(skills.get(index++)); + hiscoreResult.setClueScrollMedium(skills.get(index++)); + hiscoreResult.setClueScrollHard(skills.get(index++)); + hiscoreResult.setClueScrollElite(skills.get(index++)); + hiscoreResult.setClueScrollMaster(skills.get(index++)); + hiscoreResult.setLastManStanding(skills.get(index++)); + // seasonal doesn't have boss hiscores + if (index < skills.size()) + { + hiscoreResult.setAbyssalSire(skills.get(index++)); + hiscoreResult.setAlchemicalHydra(skills.get(index++)); + hiscoreResult.setBarrowsChests(skills.get(index++)); + hiscoreResult.setBryophyta(skills.get(index++)); +// hiscoreResult.setCallisto(skills.get(index++)); +// hiscoreResult.setCerberus(skills.get(index++)); + hiscoreResult.setChambersOfXeric(skills.get(index++)); + hiscoreResult.setChambersOfXericChallengeMode(skills.get(index++)); + hiscoreResult.setChaosElemental(skills.get(index++)); + hiscoreResult.setChaosFanatic(skills.get(index++)); + hiscoreResult.setCommanderZilyana(skills.get(index++)); + hiscoreResult.setCorporealBeast(skills.get(index++)); + hiscoreResult.setCrazyArchaeologist(skills.get(index++)); + hiscoreResult.setDagannothPrime(skills.get(index++)); + hiscoreResult.setDagannothRex(skills.get(index++)); + hiscoreResult.setDagannothSupreme(skills.get(index++)); + hiscoreResult.setDerangedArchaeologist(skills.get(index++)); + hiscoreResult.setGeneralGraardor(skills.get(index++)); + hiscoreResult.setGiantMole(skills.get(index++)); + hiscoreResult.setGrotesqueGuardians(skills.get(index++)); + hiscoreResult.setHespori(skills.get(index++)); + hiscoreResult.setKalphiteQueen(skills.get(index++)); + hiscoreResult.setKingBlackDragon(skills.get(index++)); + hiscoreResult.setKraken(skills.get(index++)); + hiscoreResult.setKreearra(skills.get(index++)); + hiscoreResult.setKrilTsutsaroth(skills.get(index++)); + hiscoreResult.setMimic(skills.get(index++)); + hiscoreResult.setObor(skills.get(index++)); + hiscoreResult.setSarachnis(skills.get(index++)); + hiscoreResult.setScorpia(skills.get(index++)); + hiscoreResult.setSkotizo(skills.get(index++)); + hiscoreResult.setGauntlet(skills.get(index++)); + hiscoreResult.setCorruptedGauntlet(skills.get(index++)); + hiscoreResult.setTheatreOfBlood(skills.get(index++)); + hiscoreResult.setThermonuclearSmokeDevil(skills.get(index++)); + hiscoreResult.setTzKalZuk(skills.get(index++)); + hiscoreResult.setTzTokJad(skills.get(index++)); + hiscoreResult.setVenenatis(skills.get(index++)); + hiscoreResult.setVetion(skills.get(index++)); + hiscoreResult.setVorkath(skills.get(index++)); + hiscoreResult.setWintertodt(skills.get(index++)); + hiscoreResult.setZalcano(skills.get(index++)); + hiscoreResult.setZulrah(skills.get(index++)); + } return hiscoreResult; } } diff --git a/http-api/src/main/java/net/runelite/http/api/hiscore/HiscoreSkill.java b/http-api/src/main/java/net/runelite/http/api/hiscore/HiscoreSkill.java index f0864a9424..bcbaf96860 100644 --- a/http-api/src/main/java/net/runelite/http/api/hiscore/HiscoreSkill.java +++ b/http-api/src/main/java/net/runelite/http/api/hiscore/HiscoreSkill.java @@ -24,6 +24,11 @@ */ package net.runelite.http.api.hiscore; +import lombok.AllArgsConstructor; +import lombok.Getter; + +@AllArgsConstructor +@Getter public enum HiscoreSkill { OVERALL("Overall"), @@ -60,17 +65,50 @@ public enum HiscoreSkill CLUE_SCROLL_HARD("Clue Scrolls (hard)"), CLUE_SCROLL_ELITE("Clue Scrolls (elite)"), CLUE_SCROLL_MASTER("Clue Scrolls (master)"), - LAST_MAN_STANDING("Last Man Standing"); + LAST_MAN_STANDING("Last Man Standing"), + ABYSSAL_SIRE("Abyssal Sire"), + ALCHEMICAL_HYDRA("Alchemical Hydra"), + BARROWS_CHESTS("Barrows Chests"), + BRYOPHYTA("Bryophyta"), + CALLISTO("Callisto"), + CERBERUS("Cerberus"), + CHAMBERS_OF_XERIC("Chambers of Xeric"), + CHAMBERS_OF_XERIC_CHALLENGE_MODE("Chambers of Xeric: Challenge Mode"), + CHAOS_ELEMENTAL("Chaos Elemental"), + CHAOS_FANATIC("Chaos Fanatic"), + COMMMANDER_ZILYANA("Commander Zilyana"), + CORPOREAL_BEAST("Corporeal Beast"), + CRAZY_ARCHAEOLOGIST("Crazy Archaeologist"), + DAGANNOTH_PRIME("Dagannoth Prime"), + DAGANNOTH_REX("Dagannoth Rex"), + DAGANNOTH_SUPREME("Dagannoth Supreme"), + DERANGED_ARCHAEOLOGIST("Deranged Archaeologist"), + GENERAL_GRAARDOR("General Graardor"), + GIANT_MOLE("Giant Mole"), + GROTESQUE_GUARDIANS("Grotesque Guardians"), + HESPORI("Hespori"), + KALPHITE_QUEEN("Kalphite Queen"), + KING_BLACK_DRAGON("King Black Dragon"), + KRAKEN("Kraken"), + KREEARRA("Kree'Arra"), + KRIL_TSUTSAROTH("K'ril Tsutsaroth"), + MIMIC("Mimic"), + OBOR("Obor"), + SARACHNIS("Sarachnis"), + SCORPIA("Scorpia"), + SKOTIZO("Skotizo"), + THE_GAUNTLET("The Gauntlet"), + THE_CORRUPTED_GAUNTLET("The Corrupted Gauntlet"), + THEATRE_OF_BLOOD("Theatre of Blood"), + THERMONUCLEAR_SMOKE_DEVIL("Thermonuclear Smoke Devil"), + TZKAL_ZUK("TzKal-Zuk"), + TZTOK_JAD("TzTok-Jad"), + VENENATIS("Venenatis"), + VETION("Vet'ion"), + VORKATH("Vorkath"), + WINTERTODT("Wintertodt"), + ZALCANO("Zalcano"), + ZULRAH("Zulrah"); private final String name; - - HiscoreSkill(String name) - { - this.name = name; - } - - public String getName() - { - return name; - } } 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 2dbf70873b..a268b12dd1 100644 --- a/runelite-api/src/main/java/net/runelite/api/ScriptID.java +++ b/runelite-api/src/main/java/net/runelite/api/ScriptID.java @@ -217,5 +217,15 @@ public final class ScriptID */ @ScriptArguments(string = 1) public static final int PUBLICMSG = 13337; + + /** + * Attempts to kick the specified player from the Clan Chat + * + */ + @ScriptArguments(string = 1) + public static final int CLAN_SEND_KICK = 215; + } diff --git a/runelite-api/src/main/java/net/runelite/api/widgets/WidgetInfo.java b/runelite-api/src/main/java/net/runelite/api/widgets/WidgetInfo.java index 9b4e46336c..ddf73940e6 100644 --- a/runelite-api/src/main/java/net/runelite/api/widgets/WidgetInfo.java +++ b/runelite-api/src/main/java/net/runelite/api/widgets/WidgetInfo.java @@ -466,7 +466,7 @@ public enum WidgetInfo FISHING_TRAWLER_TIMER(WidgetID.FISHING_TRAWLER_GROUP_ID, 14), - TITHE_FARM(WidgetID.TITHE_FARM_GROUP_ID, 1), + TITHE_FARM(WidgetID.TITHE_FARM_GROUP_ID, 3), BARROWS_INFO(WidgetID.BARROWS_GROUP_ID, 0), BARROWS_BROTHERS(WidgetID.BARROWS_GROUP_ID, WidgetID.Barrows.BARROWS_BROTHERS), 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 0585c7a026..40f9fba7af 100644 --- a/runelite-client/src/main/java/net/runelite/client/Notifier.java +++ b/runelite-client/src/main/java/net/runelite/client/Notifier.java @@ -32,6 +32,9 @@ import java.awt.Graphics2D; import java.awt.Rectangle; import java.awt.Toolkit; import java.awt.TrayIcon; +import java.io.BufferedInputStream; +import java.io.File; +import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.nio.file.Files; @@ -42,6 +45,13 @@ import java.util.List; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; import javax.inject.Singleton; +import javax.sound.sampled.AudioInputStream; +import javax.sound.sampled.AudioSystem; +import javax.sound.sampled.Clip; +import javax.sound.sampled.LineUnavailableException; +import javax.sound.sampled.UnsupportedAudioFileException; +import lombok.Getter; +import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import net.runelite.api.ChatMessageType; import net.runelite.api.Client; @@ -60,6 +70,23 @@ import net.runelite.client.util.OSType; @Slf4j public class Notifier { + @Getter + @RequiredArgsConstructor + public enum NativeCustomOff + { + NATIVE("Native"), + CUSTOM("Custom"), + OFF("Off"); + + private final String name; + + @Override + public String toString() + { + return name; + } + } + // Default timeout of notification in milliseconds private static final int DEFAULT_TIMEOUT = 10000; private static final String DOUBLE_QUOTE = "\""; @@ -127,9 +154,13 @@ public class Notifier sendNotification(appName, message, type); } - if (runeLiteConfig.enableNotificationSound()) + switch (runeLiteConfig.notificationSound()) { - Toolkit.getDefaultToolkit().beep(); + case NATIVE: + Toolkit.getDefaultToolkit().beep(); + break; + case CUSTOM: + executorService.submit(this::playCustomSound); } if (runeLiteConfig.enableGameMessageNotification() && client.getGameState() == GameState.LOGGED_IN) @@ -366,4 +397,48 @@ public class Notifier return "normal"; } } + + private void playCustomSound() + { + Clip clip = null; + + // Try to load the user sound from ~/.runelite/notification.wav + File file = new File(RuneLite.RUNELITE_DIR, "notification.wav"); + if (file.exists()) + { + try + { + InputStream fileStream = new BufferedInputStream(new FileInputStream(file)); + try (AudioInputStream sound = AudioSystem.getAudioInputStream(fileStream)) + { + clip = AudioSystem.getClip(); + clip.open(sound); + } + } + catch (UnsupportedAudioFileException | IOException | LineUnavailableException e) + { + clip = null; + log.warn("Unable to play notification sound", e); + } + } + + if (clip == null) + { + // Otherwise load from the classpath + InputStream fileStream = new BufferedInputStream(Notifier.class.getResourceAsStream("notification.wav")); + try (AudioInputStream sound = AudioSystem.getAudioInputStream(fileStream)) + { + clip = AudioSystem.getClip(); + clip.open(sound); + } + catch (UnsupportedAudioFileException | IOException | LineUnavailableException e) + { + log.warn("Unable to play builtin notification sound", e); + + Toolkit.getDefaultToolkit().beep(); + return; + } + } + clip.start(); + } } diff --git a/runelite-client/src/main/java/net/runelite/client/config/RuneLiteConfig.java b/runelite-client/src/main/java/net/runelite/client/config/RuneLiteConfig.java index ebda1d9ba9..6ed48df53d 100644 --- a/runelite-client/src/main/java/net/runelite/client/config/RuneLiteConfig.java +++ b/runelite-client/src/main/java/net/runelite/client/config/RuneLiteConfig.java @@ -26,6 +26,7 @@ package net.runelite.client.config; import java.awt.Dimension; import net.runelite.api.Constants; +import net.runelite.client.Notifier; import net.runelite.client.ui.ContainableFrame; @ConfigGroup("runelite") @@ -213,14 +214,14 @@ public interface RuneLiteConfig extends Config @ConfigItem( keyName = "notificationSound", - name = "Enable sound on notifications", + name = "Notification sound", description = "Enables the playing of a beep sound when notifications are displayed", position = 16, titleSection = "notificationsTitle" ) - default boolean enableNotificationSound() + default Notifier.NativeCustomOff notificationSound() { - return true; + return Notifier.NativeCustomOff.NATIVE; } @ConfigItem( diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/clanchat/ClanChatConfig.java b/runelite-client/src/main/java/net/runelite/client/plugins/clanchat/ClanChatConfig.java index 7700bff76e..9c99a369bc 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/clanchat/ClanChatConfig.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/clanchat/ClanChatConfig.java @@ -148,4 +148,15 @@ public interface ClanChatConfig extends Config { return ""; } + + @ConfigItem( + keyName = "confirmKicks", + name = "Confirm Kicks", + description = "Shows a chat prompt to confirm kicks", + position = 10 + ) + default boolean confirmKicks() + { + return false; + } } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/clanchat/ClanChatPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/clanchat/ClanChatPlugin.java index acd9988a4b..9d553d82b9 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/clanchat/ClanChatPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/clanchat/ClanChatPlugin.java @@ -28,6 +28,7 @@ package net.runelite.client.plugins.clanchat; import com.google.common.base.Strings; import com.google.common.collect.Lists; +import com.google.common.util.concurrent.Runnables; import com.google.inject.Provides; import java.awt.Color; import java.awt.image.BufferedImage; @@ -74,6 +75,7 @@ import net.runelite.client.eventbus.Subscribe; import net.runelite.client.events.ConfigChanged; import net.runelite.client.game.ClanManager; import net.runelite.client.game.SpriteManager; +import net.runelite.client.game.chatbox.ChatboxPanelManager; import net.runelite.client.plugins.Plugin; import net.runelite.client.plugins.PluginDescriptor; import static net.runelite.client.ui.JagexColors.CHAT_CLAN_NAME_OPAQUE_BACKGROUND; @@ -120,6 +122,9 @@ public class ClanChatPlugin extends Plugin @Inject private ClientThread clientThread; + @Inject + private ChatboxPanelManager chatboxPanelManager; + private List chats = new ArrayList<>(); private ClanChatIndicator clanMemberCounter; private int clanJoinedTick; @@ -134,6 +139,8 @@ public class ClanChatPlugin extends Plugin private boolean clanTabChat; private String clanname; + private boolean kickConfirmed = false; + @SuppressWarnings("unchecked") public static CopyOnWriteArrayList getClanMembers() { @@ -521,14 +528,37 @@ public class ClanChatPlugin extends Plugin @Subscribe private void onScriptCallbackEvent(ScriptCallbackEvent scriptCallbackEvent) { - if (!scriptCallbackEvent.getEventName().equalsIgnoreCase("clanchatInput")) + switch (scriptCallbackEvent.getEventName()) { - return; - } + case "clanchatInput": + { + final int[] intStack = client.getIntStack(); + final int size = client.getIntStackSize(); + intStack[size - 1] = config.clanTabChat() ? 1 : 0; + break; + } + case "confirmClanKick": + { + if (!config.confirmKicks() || kickConfirmed) + { + break; + } - final int[] intStack = client.getIntStack(); - final int size = client.getIntStackSize(); - intStack[size - 1] = this.clanTabChat ? 1 : 0; + // Set a flag so the script doesn't instantly kick them + final int[] intStack = client.getIntStack(); + final int size = client.getIntStackSize(); + intStack[size - 1] = 1; + + // Get name of player we are trying to kick + final String[] stringStack = client.getStringStack(); + final int stringSize = client.getStringStackSize(); + final String kickPlayerName = stringStack[stringSize - 1]; + + // Show a chatbox panel confirming the kick + clientThread.invokeLater(() -> confirmKickPlayer(kickPlayerName)); + break; + } + } } int getClanAmount() @@ -642,6 +672,21 @@ public class ClanChatPlugin extends Plugin clanMemberCounter = null; } + private void confirmKickPlayer(final String kickPlayerName) + { + chatboxPanelManager.openTextMenuInput("Attempting to kick: " + kickPlayerName) + .option("1. Confirm kick", () -> + clientThread.invoke(() -> + { + kickConfirmed = true; + client.runScript(ScriptID.CLAN_SEND_KICK, kickPlayerName); + kickConfirmed = false; + }) + ) + .option("2. Cancel", Runnables::doNothing) + .build(); + } + private void addClanCounter() { if (!this.showClanCounter || clanMemberCounter != null || clanMembers.isEmpty()) 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 91876b555c..fd46f60843 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 @@ -26,28 +26,33 @@ package net.runelite.client.plugins.devtools; import java.awt.GridLayout; +import java.awt.TrayIcon; import javax.inject.Inject; +import javax.swing.JButton; import javax.swing.JPanel; import net.runelite.api.Client; +import net.runelite.client.Notifier; import net.runelite.client.ui.ColorScheme; import net.runelite.client.ui.PluginPanel; class DevToolsPanel extends PluginPanel { private final Client client; + private final Notifier notifier; private final DevToolsPlugin plugin; private final WidgetInspector widgetInspector; private final VarInspector varInspector; @Inject - private DevToolsPanel(Client client, DevToolsPlugin plugin, WidgetInspector widgetInspector, VarInspector varInspector) + private DevToolsPanel(Client client, DevToolsPlugin plugin, WidgetInspector widgetInspector, VarInspector varInspector, Notifier notifier) { super(); this.client = client; this.plugin = plugin; this.widgetInspector = widgetInspector; this.varInspector = varInspector; + this.notifier = notifier; setBackground(ColorScheme.DARK_GRAY_COLOR); @@ -135,6 +140,13 @@ class DevToolsPanel extends PluginPanel container.add(plugin.getSoundEffects()); + final JButton notificationBtn = new JButton("Notification"); + notificationBtn.addActionListener(e -> + { + notifier.notify("Wow!", TrayIcon.MessageType.ERROR); + }); + container.add(notificationBtn); + return container; } } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/itemidentification/ItemIdentification.java b/runelite-client/src/main/java/net/runelite/client/plugins/itemidentification/ItemIdentification.java index 8d411a4aaa..4659d14e8f 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/itemidentification/ItemIdentification.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/itemidentification/ItemIdentification.java @@ -38,7 +38,7 @@ enum ItemIdentification RANARR_SEED(Type.SEED, "Ranarr", "R", ItemID.RANARR_SEED), TOADFLAX_SEED(Type.SEED, "Toad", "TOA", ItemID.TOADFLAX_SEED), IRIT_SEED(Type.SEED, "Irit", "I", ItemID.IRIT_SEED), - AVANTOE_SEED(Type.SEED, "Avantoe", "A", ItemID.AVANTOE_SEED), + AVANTOE_SEED(Type.SEED, "Avan", "A", ItemID.AVANTOE_SEED), KWUARM_SEED(Type.SEED, "Kwuarm", "K", ItemID.KWUARM_SEED), SNAPDRAGON_SEED(Type.SEED, "Snap", "S", ItemID.SNAPDRAGON_SEED), CADANTINE_SEED(Type.SEED, "Cadan", "C", ItemID.CADANTINE_SEED), @@ -56,7 +56,7 @@ enum ItemIdentification RANARR(Type.HERB, "Ranarr", "R", ItemID.RANARR_WEED, ItemID.GRIMY_RANARR_WEED), TOADFLAX(Type.HERB, "Toad", "TOA", ItemID.TOADFLAX, ItemID.GRIMY_TOADFLAX), IRIT(Type.HERB, "Irit", "I", ItemID.IRIT_LEAF, ItemID.GRIMY_IRIT_LEAF), - AVANTOE(Type.HERB, "Avantoe", "A", ItemID.AVANTOE, ItemID.GRIMY_AVANTOE), + AVANTOE(Type.HERB, "Avan", "A", ItemID.AVANTOE, ItemID.GRIMY_AVANTOE), KWUARM(Type.HERB, "Kwuarm", "K", ItemID.KWUARM, ItemID.GRIMY_KWUARM), SNAPDRAGON(Type.HERB, "Snap", "S", ItemID.SNAPDRAGON, ItemID.GRIMY_SNAPDRAGON), CADANTINE(Type.HERB, "Cadan", "C", ItemID.CADANTINE, ItemID.GRIMY_CADANTINE), 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 75edf8c6ac..b8960e7b89 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 @@ -129,7 +129,7 @@ public class SlayerPlugin extends Plugin //NPC messages private static final Pattern NPC_ASSIGN_MESSAGE = Pattern.compile(".*(?:Your new task is to kill|You are to bring balance to)\\s*(?\\d+) (?.+?)(?: (?:in|on|south of) (?:the )?(?.+))?\\."); private static final Pattern NPC_ASSIGN_BOSS_MESSAGE = Pattern.compile("^Excellent. You're now assigned to kill (?:the )?(.*) (\\d+) times.*Your reward point tally is (.*)\\.$"); - private static final Pattern NPC_ASSIGN_FIRST_MESSAGE = Pattern.compile("^We'll start you off hunting (.*), you'll need to kill (\\d*) of them."); + private static final Pattern NPC_ASSIGN_FIRST_MESSAGE = Pattern.compile("^We'll start you off (?:hunting|bringing balance to) (.*), you'll need to kill (\\d*) of them\\.$"); private static final Pattern NPC_CURRENT_MESSAGE = Pattern.compile("^You're still (?:hunting|bringing balance to) (?.+)(?: (?:in|on|south of) (?:the )?(?.+), with|; you have) (?\\d+) to go\\..*"); private static final int GROTESQUE_GUARDIANS_REGION = 6727; diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/twitch/TwitchPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/twitch/TwitchPlugin.java index 871089c4a4..cff49cc0a8 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/twitch/TwitchPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/twitch/TwitchPlugin.java @@ -172,6 +172,7 @@ public class TwitchPlugin extends Plugin implements TwitchListener, ChatboxInput .sender("Twitch") .name(sender) .runeLiteFormattedMessage(chatMessage) + .timestamp((int) (System.currentTimeMillis() / 1000)) .build()); } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/woodcutting/TreeRespawn.java b/runelite-client/src/main/java/net/runelite/client/plugins/woodcutting/TreeRespawn.java index a3022ca8f3..ef05dc67b0 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/woodcutting/TreeRespawn.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/woodcutting/TreeRespawn.java @@ -28,14 +28,16 @@ package net.runelite.client.plugins.woodcutting; import java.time.Instant; import lombok.AllArgsConstructor; import lombok.Getter; -import net.runelite.api.coords.LocalPoint; +import net.runelite.api.coords.WorldPoint; @AllArgsConstructor @Getter class TreeRespawn { private final Tree tree; - private final LocalPoint location; + private final int lenX; + private final int lenY; + private final WorldPoint worldLocation; private final Instant startTime; private final int respawnTime; 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 1ae325f534..01036cecb4 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 @@ -42,6 +42,8 @@ import net.runelite.api.GameObject; import net.runelite.api.ItemID; import net.runelite.api.MenuOpcode; import net.runelite.api.Player; +import net.runelite.api.Point; +import net.runelite.api.coords.WorldPoint; import net.runelite.api.events.AnimationChanged; import net.runelite.api.events.ChatMessage; import net.runelite.api.events.GameObjectChanged; @@ -217,8 +219,12 @@ public class WoodcuttingPlugin extends Plugin { if (tree.getRespawnTime() != null && !recentlyLoggedIn) { + Point max = object.getSceneMaxLocation(); + Point min = object.getSceneMinLocation(); + int lenX = max.getX() - min.getX(); + int lenY = max.getY() - min.getY(); log.debug("Adding respawn timer for {} tree at {}", tree, object.getLocalLocation()); - TreeRespawn treeRespawn = new TreeRespawn(tree, object.getLocalLocation(), Instant.now(), (int) tree.getRespawnTime().toMillis()); + TreeRespawn treeRespawn = new TreeRespawn(tree, lenX, lenY, WorldPoint.fromScene(client, min.getX(), min.getY(), client.getPlane()), Instant.now(), (int) tree.getRespawnTime().toMillis()); respawns.add(treeRespawn); } @@ -240,9 +246,9 @@ public class WoodcuttingPlugin extends Plugin { switch (event.getGameState()) { - case LOADING: case HOPPING: respawns.clear(); + case LOADING: treeObjects.clear(); break; case LOGGED_IN: diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/woodcutting/WoodcuttingTreesOverlay.java b/runelite-client/src/main/java/net/runelite/client/plugins/woodcutting/WoodcuttingTreesOverlay.java index 990e1bc6eb..1e23f1af9c 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/woodcutting/WoodcuttingTreesOverlay.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/woodcutting/WoodcuttingTreesOverlay.java @@ -103,10 +103,17 @@ class WoodcuttingTreesOverlay extends Overlay Instant now = Instant.now(); for (TreeRespawn treeRespawn : respawns) { - LocalPoint loc = treeRespawn.getLocation(); + LocalPoint minLocation = LocalPoint.fromWorld(client, treeRespawn.getWorldLocation()); + if (minLocation == null) + { + continue; + } + LocalPoint centeredLocation = new LocalPoint( + minLocation.getX() + treeRespawn.getLenX() * Perspective.LOCAL_HALF_TILE_SIZE, + minLocation.getY() + treeRespawn.getLenY() * Perspective.LOCAL_HALF_TILE_SIZE); float percent = (now.toEpochMilli() - treeRespawn.getStartTime().toEpochMilli()) / (float) treeRespawn.getRespawnTime(); - Point point = Perspective.localToCanvas(client, loc, client.getPlane()); + Point point = Perspective.localToCanvas(client, centeredLocation, client.getPlane()); if (point == null || percent > 1.0f) { continue; diff --git a/runelite-client/src/main/resources/net/runelite/client/notification.txt b/runelite-client/src/main/resources/net/runelite/client/notification.txt new file mode 100644 index 0000000000..e3a7245c61 --- /dev/null +++ b/runelite-client/src/main/resources/net/runelite/client/notification.txt @@ -0,0 +1,2 @@ +Notification is cloud from +https://github.com/akx/Notifications \ No newline at end of file diff --git a/runelite-client/src/main/resources/net/runelite/client/notification.wav b/runelite-client/src/main/resources/net/runelite/client/notification.wav new file mode 100644 index 0000000000..60321281c3 Binary files /dev/null and b/runelite-client/src/main/resources/net/runelite/client/notification.wav differ diff --git a/runelite-client/src/main/scripts/ClanSendKick.hash b/runelite-client/src/main/scripts/ClanSendKick.hash new file mode 100644 index 0000000000..e1fb1db404 --- /dev/null +++ b/runelite-client/src/main/scripts/ClanSendKick.hash @@ -0,0 +1 @@ +9B3B448D76D57F6D63C9CDA06E58695F6DEBE91F9EDF2D2C4876E064D1067FD6 \ No newline at end of file diff --git a/runelite-client/src/main/scripts/ClanSendKick.rs2asm b/runelite-client/src/main/scripts/ClanSendKick.rs2asm new file mode 100644 index 0000000000..1da495029f --- /dev/null +++ b/runelite-client/src/main/scripts/ClanSendKick.rs2asm @@ -0,0 +1,34 @@ +.id 215 +.int_stack_count 0 +.string_stack_count 1 +.int_var_count 0 +.string_var_count 1 +; callback "confirmClanKick" +; Used by the ClanChat plugin to show a chatbox panel confirming the requested kick +; Also requires the "confirmKicks" option of ClanChatConfig to be enabled + invoke 1942 + iconst 1 + if_icmpeq LABEL4 + jump CONFIRM_KICK ; Jump to our new label instead +LABEL4: + sconst "You can't kick players from your team during Wilderness Wars." + mes + return +LABEL7: + sconst "-Attempting to kick player from friends chat..." + iconst 2 + invoke 96 + sload 0 + clan_kickuser + jump LABEL73 +LABEL73: + return +CONFIRM_KICK: + sload 0 ; Username we are trying to kick + iconst 0 ; Modified if we are confirming the kick inside the plugin + sconst "confirmClanKick" + runelite_callback + pop_string ; Pop username + iconst 0 ; Compare against zero + if_icmpgt LABEL73 ; Early return for chatbox panel confirmation + jump LABEL7 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 1d838d8bc5..43050ae12b 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 @@ -76,6 +76,7 @@ public class SlayerPluginTest private static final String TASK_NEW_KONAR_2 = "You are to bring balance to 142 Hellhounds in Witchhaven Dungeon."; private static final String TASK_NEW_KONAR_3 = "You are to bring balance to 135 Trolls south of Mount Quidamortem."; private static final String TASK_NEW_FIRST = "We'll start you off hunting goblins, you'll need to kill 17 of them."; + private static final String TASK_NEW_FIRST_KONAR = "We'll start you off bringing balance to cows, you'll need to kill 44 of them."; private static final String TASK_NEW_NPC_CONTACT = "Excellent, you're doing great. Your new task is to kill
211 Suqahs."; private static final String TASK_NEW_FROM_PARTNER = "You have received a new Slayer assignment from breaklulz: Dust Devils (377)"; private static final String TASK_CHECKSLAYERGEM = "You're assigned to kill Suqahs; only 211 more to go."; @@ -223,6 +224,18 @@ public class SlayerPluginTest assertEquals(17, slayerPlugin.getCurrentTask().getAmount()); } + @Test + public void testFirstTaskKonar() + { + Widget npcDialog = mock(Widget.class); + when(npcDialog.getText()).thenReturn(TASK_NEW_FIRST_KONAR); + when(client.getWidget(WidgetInfo.DIALOG_NPC_TEXT)).thenReturn(npcDialog); + slayerPlugin.onGameTick(GameTick.INSTANCE); + + assertEquals("cows", slayerPlugin.getCurrentTask().getTaskName()); + assertEquals(44, slayerPlugin.getCurrentTask().getAmount()); + } + @Test public void testNewNpcContactTask() {