From 22c4a291fc66691f48f960b308793efbd4670be0 Mon Sep 17 00:00:00 2001 From: Wayne Li Date: Fri, 17 Dec 2021 01:51:04 -0800 Subject: [PATCH 01/51] clue: Update area descriptions of anagram clues --- .../cluescrolls/clues/AnagramClue.java | 96 +++++++++---------- 1 file changed, 48 insertions(+), 48 deletions(-) diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/clues/AnagramClue.java b/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/clues/AnagramClue.java index 8a35abd738..286d9b6f4a 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/clues/AnagramClue.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/clues/AnagramClue.java @@ -53,15 +53,15 @@ public class AnagramClue extends ClueScroll implements TextClueScroll, NpcClueSc private static final Set CLUES = ImmutableSet.of( new AnagramClue("A BAKER", "Baraek", new WorldPoint(3217, 3434, 0), "Varrock square", "How many stalls are there in Varrock Square?", "5"), - new AnagramClue("A BASIC ANTI POT", "Captain Tobias", new WorldPoint(3026, 3216, 0), "Port Sarim", "How many ships are there docked at Port Sarim currently?", "6"), + new AnagramClue("A BASIC ANTI POT", "Captain Tobias", new WorldPoint(3026, 3216, 0), "Port Sarim docks", "How many ships are there docked at Port Sarim currently?", "6"), new AnagramClue("A ELF KNOWS", "Snowflake", new WorldPoint(2872, 3934, 0), "Weiss"), new AnagramClue("A HEART", "Aretha", new WorldPoint(1814, 3851, 0), "Soul altar", "32 - 5x = 22, what is x?", "2"), new AnagramClue("AHA JAR", "Jaraah", new WorldPoint(3359, 3276, 0), "Duel Arena hospital"), - new AnagramClue("ARC O LINE", "Caroline", new WorldPoint(2715, 3302, 0), "North Witchaven next to the row boat", "How many fishermen are there on the fishing platform?", "11"), - new AnagramClue("ARE COL", "Oracle", new WorldPoint(3013, 3501, 0), "Ice Mountain West of Edgeville", "If x is 15 and y is 3 what is 3x + y?", "48"), - new AnagramClue("ARMCHAIR THE PELT", "Charlie the Tramp", new WorldPoint(3209, 3392, 0), "South entrance of Varrock", "How many coins would I have if I have 0 coins and attempt to buy 10 loaves of bread for 3 coins each?", "0"), - new AnagramClue("AT HERG", "Regath", new WorldPoint(1719, 3723, 0), "General Store, Arceuus, Zeah", "What is -5 to the power of 2?", "25"), - new AnagramClue("A BAS", "Saba", new WorldPoint(2858, 3577, 0), "Death Plateau"), + new AnagramClue("ARC O LINE", "Caroline", new WorldPoint(2715, 3302, 0), "North of Witchaven, near row boat", "How many fishermen are there on the fishing platform?", "11"), + new AnagramClue("ARE COL", "Oracle", new WorldPoint(3013, 3501, 0), "Ice Mountain", "If x is 15 and y is 3 what is 3x + y?", "48"), + new AnagramClue("ARMCHAIR THE PELT", "Charlie the Tramp", new WorldPoint(3209, 3392, 0), "Varrock south entrance", "How many coins would I have if I have 0 coins and attempt to buy 10 loaves of bread for 3 coins each?", "0"), + new AnagramClue("AT HERG", "Regath", new WorldPoint(1719, 3723, 0), "Arceuus general store", "What is -5 to the power of 2?", "25"), + new AnagramClue("A BAS", "Saba", new WorldPoint(2858, 3577, 0), "Death Plateau cave, north of the Warriors' Guild"), new AnagramClue("AREA CHEF TREK", "Father Aereck", new WorldPoint(3243, 3208, 0), "Lumbridge Church", "How many gravestones are in the church graveyard?", "19 or 20"), new AnagramClue("BAIL TRIMS", "Brimstail", new WorldPoint(2402, 3419, 0), "West of Stronghold Slayer Cave"), new AnagramClue("BAKER CLIMB", "Brambickle", new WorldPoint(2783, 3861, 0), "Trollweiss mountain"), @@ -71,85 +71,85 @@ public class AnagramClue extends ClueScroll implements TextClueScroll, NpcClueSc new AnagramClue("CAR IF ICES", "Sacrifice", new WorldPoint(2209, 3056, 0), "Zul-Andra"), new AnagramClue("CAREER IN MOON", "Oneiromancer", new WorldPoint(2150, 3866, 0), "Astral altar", "How many Suqah inhabit Lunar isle?", "25"), new AnagramClue("CLASH ION", "Nicholas", new WorldPoint(1841, 3803, 0), "North of Port Piscarilius fishing shop", "How many windows are in Tynan's shop?", "4"), - new AnagramClue("C ON GAME HOC", "Gnome Coach", new WorldPoint(2395, 3486, 0), "Gnome Ball course", "How many gnomes on the Gnome ball field have red patches on their uniforms?", "6"), + new AnagramClue("C ON GAME HOC", "Gnome Coach", new WorldPoint(2395, 3486, 0), "Circling the Gnome Ball course", "How many gnomes on the Gnome ball field have red patches on their uniforms?", "6"), new AnagramClue("COOL NERD", "Old crone", new WorldPoint(3462, 3557, 0), "East of the Slayer Tower", "What is the combined combat level of each species that live in Slayer tower?", "619"), new AnagramClue("COPPER ORE CRYPTS", "Prospector Percy", new WorldPoint(3061, 3377, 0), "Motherlode Mine", "During a party, everyone shook hands with everybody else. There were 66 handshakes. How many people were at the party?", "12"), - new AnagramClue("DARN DRAKE", "Daer Krand", new WorldPoint(3728, 3302, 0), "Sisterhood Sanctuary (Slepe Dungeon, northeast of Nightmare Arena)"), - new AnagramClue("DED WAR", "Edward", new WorldPoint(3284, 3943, 0), "Inside Rogue's Castle"), + new AnagramClue("DARN DRAKE", "Daer Krand", new WorldPoint(3728, 3302, 0), "Sisterhood Sanctuary, northeast of the Nightmare Arena"), + new AnagramClue("DED WAR", "Edward", new WorldPoint(3284, 3943, 0), "Around or within Rogues' Castle"), new AnagramClue("DEKAGRAM", "Dark mage", new WorldPoint(3039, 4835, 0), "Centre of the Abyss", "How many rifts are found here in the abyss?", "13"), new AnagramClue("DO SAY MORE", "Doomsayer", new WorldPoint(3230, 3230, 0), "East of Lumbridge Castle", "What is 40 divided by 1/2 plus 15?", "95"), new AnagramClue("DIM THARN", "Mandrith", new WorldPoint(3182, 3946, 0), "Wilderness Resource Area"), new AnagramClue("DR HITMAN", "Mandrith", new WorldPoint(3182, 3946, 0), "Wilderness Resource Area", "How many scorpions live under the pit?", "28"), - new AnagramClue("DR WARDEN FUNK", "Drunken Dwarf", new WorldPoint(2913, 10221, 0), "East Side of Keldagrim"), + new AnagramClue("DR WARDEN FUNK", "Drunken Dwarf", new WorldPoint(2913, 10221, 0), "East Keldagrim"), new AnagramClue("DRAGONS LAMENT", "Strange Old Man", new WorldPoint(3564, 3288, 0), "Barrows", "One pipe fills a barrel in 1 hour while another pipe can fill the same barrel in 2 hours. How many minutes will it take to fill the tank if both pipes are used?", "40"), - new AnagramClue("DT RUN B", "Brundt the Chieftain", new WorldPoint(2658, 3670, 0), "Rellekka, main hall", "How many people are waiting for the next bard to perform?", "4"), - new AnagramClue("DUO PLUG", "Dugopul", new WorldPoint(2803, 2744, 0), "Graveyard on Ape Atoll"), + new AnagramClue("DT RUN B", "Brundt the Chieftain", new WorldPoint(2658, 3670, 0), "Rellekka main hall", "How many people are waiting for the next bard to perform?", "4"), + new AnagramClue("DUO PLUG", "Dugopul", new WorldPoint(2803, 2744, 0), "Ape Atoll graveyard"), new AnagramClue("EEK ZERO OP", "Zoo keeper", new WorldPoint(2613, 3269, 0), "Ardougne Zoo", "How many animals in total are there in the zoo?", "40"), new AnagramClue("EL OW", "Lowe", new WorldPoint(3233, 3423, 0), "Varrock archery store"), - new AnagramClue("FORLUN", "Runolf", new WorldPoint(2512, 10256, 0), "Miscellania & Etceteria Dungeon"), + new AnagramClue("FORLUN", "Runolf", new WorldPoint(2512, 10256, 0), "Miscellania Dungeon"), new AnagramClue("GOBLIN KERN", "King Bolren", new WorldPoint(2541, 3170, 0), "Tree Gnome Village"), - new AnagramClue("GOT A BOY", "Gabooty", new WorldPoint(2790, 3066, 0), "Centre of Tai Bwo Wannai", "How many buildings are in the village?", "11"), + new AnagramClue("GOT A BOY", "Gabooty", new WorldPoint(2790, 3066, 0), "Tai Bwo Wannai", "How many buildings are in the village?", "11"), new AnagramClue("GOBLETS ODD TOES", "Otto Godblessed", new WorldPoint(2501, 3487, 0), "Otto's Grotto", "How many types of dragon are there beneath the whirlpool's cavern?", "2"), new AnagramClue("HALT US", "Luthas", new WorldPoint(2938, 3152, 0), "Banana plantation, Karamja"), - new AnagramClue("HEORIC", "Eohric", new WorldPoint(2900, 3565, 0), "Top floor of Burthorpe Castle", "King Arthur and Merlin sit down at the Round Table with 8 knights. How many degrees does each get?", "36"), - new AnagramClue("HIS PHOR", "Horphis", new WorldPoint(1639, 3812, 0), "Arceuus Library, Zeah", "On a scale of 1-10, how helpful is Logosia?", "1"), - new AnagramClue("I AM SIR", "Marisi", new WorldPoint(1737, 3557, 0), "Allotment patch, South of Hosidius chapel", "How many cities form the Kingdom of Great Kourend?", "5"), + new AnagramClue("HEORIC", "Eohric", new WorldPoint(2900, 3565, 0), "Burthorpe Castle, top floor", "King Arthur and Merlin sit down at the Round Table with 8 knights. How many degrees does each get?", "36"), + new AnagramClue("HIS PHOR", "Horphis", new WorldPoint(1639, 3812, 0), "Arceuus Library", "On a scale of 1-10, how helpful is Logosia?", "1"), + new AnagramClue("I AM SIR", "Marisi", new WorldPoint(1737, 3557, 0), "Hosidius allotment patch", "How many cities form the Kingdom of Great Kourend?", "5"), new AnagramClue("ICY FE", "Fycie", new WorldPoint(2630, 2997, 0), "East Feldip Hills"), new AnagramClue("I DOOM ICON INN", "Dominic Onion", new WorldPoint(2609, 3116, 0), "Nightmare Zone", "How many reward points does a herb box cost?", "9,500"), - new AnagramClue("I EVEN", "Nieve", new WorldPoint(2432, 3422, 0), "The slayer master in Gnome Stronghold", "How many farming patches are there in Gnome stronghold?", "2"), - new AnagramClue("IM N ZEZIM", "Immenizz", new WorldPoint(2592, 4324, 0), "The Imp inside Puro-Puro"), - new AnagramClue("KAY SIR", "Sir Kay", new WorldPoint(2760, 3496, 0), "The courtyard in Camelot Castle", "How many fountains are there within the grounds of Camelot castle?", "6"), - new AnagramClue("LEAKEY", "Kaylee", new WorldPoint(2957, 3370, 0), "Rising Sun Inn in Falador", "How many chairs are there in the Rising Sun?", "18"), - new AnagramClue("LARK IN DOG", "King Roald", new WorldPoint(3220, 3476, 0), "Ground floor of Varrock castle", "How many bookcases are there in the palace library?", "24"), - new AnagramClue("LOW LAG", "Gallow", new WorldPoint(1805, 3566, 0), "Vinery in the Great Kourend", "How many vine patches can you find in this vinery?", "12"), + new AnagramClue("I EVEN", "Nieve", new WorldPoint(2432, 3422, 0), "Gnome Stronghold, outside the Stronghold Slayer Cave", "How many farming patches are there in Gnome stronghold?", "2"), + new AnagramClue("IM N ZEZIM", "Immenizz", new WorldPoint(2592, 4324, 0), "Puro-Puro"), + new AnagramClue("KAY SIR", "Sir Kay", new WorldPoint(2760, 3496, 0), "Camelot Castle courtyard", "How many fountains are there within the grounds of Camelot castle?", "6"), + new AnagramClue("LEAKEY", "Kaylee", new WorldPoint(2957, 3370, 0), "Falador pub", "How many chairs are there in the Rising Sun?", "18"), + new AnagramClue("LARK IN DOG", "King Roald", new WorldPoint(3220, 3476, 0), "Varrock Castle, ground floor", "How many bookcases are there in the palace library?", "24"), + new AnagramClue("LOW LAG", "Gallow", new WorldPoint(1805, 3566, 0), "Hosidius vinery", "How many vine patches can you find in this vinery?", "12"), new AnagramClue("LADDER MEMO GUV", "Guard Vemmeldo", new WorldPoint(2447, 3418, 1), "Gnome Stronghold Bank", "How many magic trees can you find inside the Gnome Stronghold?", "3"), - new AnagramClue("MAL IN TAU", "Luminata", new WorldPoint(3508, 3237, 0), "Near Burgh de Rott entrance"), - new AnagramClue("MACHETE CLAM", "Cam the Camel", new WorldPoint(3300, 3231, 0), "Outside Duel Arena", "How many items can carry water in Gielinor?", "6"), - new AnagramClue("ME IF", "Femi", new WorldPoint(2461, 3382, 0), "Gates of Tree Gnome Stronghold"), + new AnagramClue("MAL IN TAU", "Luminata", new WorldPoint(3508, 3237, 0), "Burgh de Rott, near general store"), + new AnagramClue("MACHETE CLAM", "Cam the Camel", new WorldPoint(3300, 3231, 0), "West of the Duel Arena entrance", "How many items can carry water in Gielinor?", "6"), + new AnagramClue("ME IF", "Femi", new WorldPoint(2461, 3382, 0), "Tree Gnome Stronghold entrance"), new AnagramClue("MOLD LA RAN", "Old Man Ral", new WorldPoint(3602, 3209, 0), "Meiyerditch"), - new AnagramClue("MOTHERBOARD", "Brother Omad", new WorldPoint(2606, 3211, 0), "Monastery south of Ardougne", "What is the next number? 12, 13, 15, 17, 111, 113, 117, 119, 123....?", "129"), + new AnagramClue("MOTHERBOARD", "Brother Omad", new WorldPoint(2606, 3211, 0), "Ardougne Monastery", "What is the next number? 12, 13, 15, 17, 111, 113, 117, 119, 123....?", "129"), new AnagramClue("MUS KIL READER", "Radimus Erkle", new WorldPoint(2726, 3368, 0), "Legends' Guild"), new AnagramClue("MY MANGLE LAL", "Lammy Langle", new WorldPoint(1688, 3540, 0), "Hosidius spirit tree patch"), - new AnagramClue("NO OWNER", "Oronwen", new WorldPoint(1162, 3178, 0), "Lletya Seamstress shop in Lletya", "What is the minimum amount of quest points required to reach Lletya?", "20"), - new AnagramClue("NOD MED", "Edmond", new WorldPoint(2566, 3332, 0), "Behind the most NW house in East Ardougne", "How many pigeon cages are there around the back of Jerico's house?", "3"), + new AnagramClue("NO OWNER", "Oronwen", new WorldPoint(1162, 3178, 0), "Lletya seamstress shop", "What is the minimum amount of quest points required to reach Lletya?", "20"), + new AnagramClue("NOD MED", "Edmond", new WorldPoint(2566, 3332, 0), "East Ardougne, north-west house", "How many pigeon cages are there around the back of Jerico's house?", "3"), new AnagramClue("O BIRDZ A ZANY EN PC", "Cap'n Izzy No-Beard", new WorldPoint(2807, 3191, 0), "Brimhaven Agility Arena", "How many Banana Trees are there in the plantation?", "33"), - new AnagramClue("OK CO", "Cook", new WorldPoint(3207, 3214, 0), "Ground floor of Lumbridge Castle", "How many cannons does Lumbridge Castle have?", "9"), + new AnagramClue("OK CO", "Cook", new WorldPoint(3207, 3214, 0), "Lumbridge Castle, ground floor", "How many cannons does Lumbridge Castle have?", "9"), new AnagramClue("OUR OWN NEEDS", "Nurse Wooned", new WorldPoint(1511, 3619, 0), "Shayzien Infirmary", "How many wounded soldiers are there in the camp?", "16"), - new AnagramClue("PACINNG A TAIE", "Captain Ginea", new WorldPoint(1504, 3632, 0), "Tent east of Shayzien Encampment war tent", "1 soldier can deal with 6 lizardmen. How many soldiers do we need for an army of 678 lizardmen?", "113"), - new AnagramClue("PEAK REFLEX", "Flax keeper", new WorldPoint(2744, 3444, 0), "Flax field south of Seers Village", "If I have 1014 flax, and I spin a third of them into bowstring, how many flax do I have left?", "676"), + new AnagramClue("PACINNG A TAIE", "Captain Ginea", new WorldPoint(1504, 3632, 0), "East of the Shayzien Encampment war tent", "1 soldier can deal with 6 lizardmen. How many soldiers do we need for an army of 678 lizardmen?", "113"), + new AnagramClue("PEAK REFLEX", "Flax keeper", new WorldPoint(2744, 3444, 0), "Seers' Village flax field", "If I have 1014 flax, and I spin a third of them into bowstring, how many flax do I have left?", "676"), new AnagramClue("PEATY PERT", "Party Pete", new WorldPoint(3047, 3376, 0), "Falador Party Room"), new AnagramClue("QUIT HORRIBLE TYRANT", "Brother Tranquility", new WorldPoint(3681, 2963, 0), "Mos Le'Harmless or Harmony Island", "If I have 49 bottles of rum to share between 7 pirates, how many would each pirate get?", "7"), - new AnagramClue("QUE SIR", "Squire", new WorldPoint(2975, 3343, 0), "Falador Castle Courtyard", "White knights are superior to black knights. 2 white knights can handle 3 black knights. How many knights do we need for an army of 981 black knights?", "654"), - new AnagramClue("R AK MI", "Karim", new WorldPoint(3273, 3181, 0), "Al Kharid Kebab shop", "I have 16 kebabs, I eat one myself and then share the rest equally between 3 friends. How many do they have each?", "5"), + new AnagramClue("QUE SIR", "Squire", new WorldPoint(2975, 3343, 0), "Falador Castle courtyard", "White knights are superior to black knights. 2 white knights can handle 3 black knights. How many knights do we need for an army of 981 black knights?", "654"), + new AnagramClue("R AK MI", "Karim", new WorldPoint(3273, 3181, 0), "Al Kharid kebab shop", "I have 16 kebabs, I eat one myself and then share the rest equally between 3 friends. How many do they have each?", "5"), new AnagramClue("RAT MAT WITHIN", "Martin Thwait", new WorldPoint(2906, 3537, 0), "Rogues' Den", "How many natural fires burn in Rogue's Den?", "2"), new AnagramClue("RATAI", "Taria", new WorldPoint(2940, 3223, 0), "Rimmington bush patch", "How many buildings are there in Rimmington?", "7"), - new AnagramClue("R SLICER", "Clerris", new WorldPoint(1761, 3850, 0), "Arceuus mine, Zeah", "If I have 1,000 blood runes, and cast 131 ice barrage spells, how many blood runes do I have left?", "738"), - new AnagramClue("RIP MAUL", "Primula", new WorldPoint(2454, 2853, 1), "Myth's Guild, first floor"), - new AnagramClue("SAND NUT", "Dunstan", new WorldPoint(2919, 3574, 0), "Anvil in north east Burthorpe", "How much smithing experience does one receive for smelting a blurite bar?", "8"), - new AnagramClue("SLAM DUSTER GRAIL", "Guildmaster Lars", new WorldPoint(1649, 3498, 0), "Woodcutting guild, Zeah"), + new AnagramClue("R SLICER", "Clerris", new WorldPoint(1761, 3850, 0), "Arceuus mine", "If I have 1,000 blood runes, and cast 131 ice barrage spells, how many blood runes do I have left?", "738"), + new AnagramClue("RIP MAUL", "Primula", new WorldPoint(2454, 2853, 1), "Myths' Guild, first floor"), + new AnagramClue("SAND NUT", "Dunstan", new WorldPoint(2919, 3574, 0), "Anvil, north-east Burthorpe", "How much smithing experience does one receive for smelting a blurite bar?", "8"), + new AnagramClue("SLAM DUSTER GRAIL", "Guildmaster Lars", new WorldPoint(1649, 3498, 0), "Woodcutting Guild, Hosidius"), new AnagramClue("SLIDE WOMAN", "Wise Old Man", new WorldPoint(3088, 3253, 0), "Draynor Village", "How many bookcases are in the Wise Old Man's house?", "28"), new AnagramClue("SNAKES SO I SAIL", "Lisse Isaakson", new WorldPoint(2351, 3801, 0), "Neitiznot", "How many arctic logs are required to make a large fremennik round shield?", "2"), new AnagramClue("TAMED ROCKS", "Dockmaster", new WorldPoint(1822, 3739, 0), "Port Piscarilius, NE of General store", "What is the cube root of 125?", "5"), - new AnagramClue("TEN WIGS ON", "Wingstone", new WorldPoint(3389, 2877, 0), "Between Nardah & Agility Pyramid"), - new AnagramClue("THICKNO", "Hickton", new WorldPoint(2822, 3442, 0), "Catherby fletching shop", "How many ranges are there in Catherby?", "2"), + new AnagramClue("TEN WIGS ON", "Wingstone", new WorldPoint(3389, 2877, 0), "North of Agility Pyramid"), + new AnagramClue("THICKNO", "Hickton", new WorldPoint(2822, 3442, 0), "Catherby ranging shop", "How many ranges are there in Catherby?", "2"), new AnagramClue("TWENTY CURE IRON", "New Recruit Tony", new WorldPoint(1503, 3553, 0), "Shayzien Graveyard"), - new AnagramClue("UNLEASH NIGHT MIST", "Sigli the Huntsman", new WorldPoint(2660, 3654, 0), "Rellekka", "What is the combined slayer requirement of every monster in the slayer cave?", "302"), - new AnagramClue("VESTE", "Steve", new WorldPoint(2432, 3423, 0), "Upstairs Wyvern Area or Stronghold Slayer Cave", "How many farming patches are there in Gnome stronghold?", "2"), + new AnagramClue("UNLEASH NIGHT MIST", "Sigli the Huntsman", new WorldPoint(2660, 3654, 0), "Rellekka entrance", "What is the combined slayer requirement of every monster in the slayer cave?", "302"), + new AnagramClue("VESTE", "Steve", new WorldPoint(2432, 3423, 0), "Upstairs Skeletal Wyvern area or Stronghold Slayer Cave (after Monkey Madness 2)", "How many farming patches are there in Gnome stronghold?", "2"), new AnagramClue("VEIL VEDA", "Evil Dave", new WorldPoint(3079, 9892, 0), "Doris' basement, Edgeville", "What is 333 multiplied by 2?", "666"), new AnagramClue("WOO AN EGG KIWI", "Awowogei", ObjectID.AWOWOGEI, new WorldPoint(2802, 2765, 0), "Ape Atoll", "If I have 303 bananas, and share them between 31 friends evenly, only handing out full bananas. How many will I have left over?", "24"), new AnagramClue("MAJORS LAVA BADS AIR", "Ambassador Alvijar", new WorldPoint(2736, 5351, 1), "Dorgesh-Kaan, NE Middle Level", "Double the miles before the initial Dorgeshuun veteran.", "2505"), new AnagramClue("AN EARL", "Ranael", new WorldPoint(3315, 3163, 0), "Al Kharid skirt shop"), new AnagramClue("CARPET AHOY", "Apothecary", new WorldPoint(3195, 3404, 0), "Southwest Varrock"), new AnagramClue("DISORDER", "Sedridor", new WorldPoint(3102, 9570, 0), "Wizards' Tower basement"), - new AnagramClue("I CORD", "Doric", new WorldPoint(2951, 3450, 0), "North of Falador"), + new AnagramClue("I CORD", "Doric", new WorldPoint(2951, 3450, 0), "Doric's house, north of Falador"), new AnagramClue("IN BAR", "Brian", new WorldPoint(3026, 3246, 0), "Port Sarim battleaxe shop"), new AnagramClue("RAIN COVE", "Veronica", new WorldPoint(3110, 3330, 0), "Outside Draynor Manor"), - new AnagramClue("RUG DETER", "Gertrude", new WorldPoint(3151, 3412, 0), "West of Varrock, south of the Cooks' Guild"), - new AnagramClue("SIR SHARE RED", "Hairdresser", new WorldPoint(2944, 3381, 0), "Western Falador"), - new AnagramClue("TAUNT ROOF", "Fortunato", new WorldPoint(3080, 3250, 0), "Draynor Village Market"), - new AnagramClue("HICK JET", "Jethick", new WorldPoint(2541, 3305, 0), "West Ardougne", "How many graves are there in the city graveyard?", "38"), + new AnagramClue("RUG DETER", "Gertrude", new WorldPoint(3151, 3412, 0), "Gertrude's house, west of Varrock"), + new AnagramClue("SIR SHARE RED", "Hairdresser", new WorldPoint(2944, 3381, 0), "Falador hairdresser"), + new AnagramClue("TAUNT ROOF", "Fortunato", new WorldPoint(3080, 3250, 0), "Draynor Village market"), + new AnagramClue("HICK JET", "Jethick", new WorldPoint(2541, 3305, 0), "West Ardougne town square", "How many graves are there in the city graveyard?", "38"), new AnagramClue("RUE GO", "Goreu", new WorldPoint(2335, 3162, 0), "Lletya"), - new AnagramClue("BRUCIE CATNAP", "Captain Bruce", new WorldPoint(1520, 3558, 0), "Graveyard of Heroes"), + new AnagramClue("BRUCIE CATNAP", "Captain Bruce", new WorldPoint(1520, 3558, 0), "Shayzien"), new AnagramClue("UESNKRL NRIEDDO", "Drunken soldier", new WorldPoint(1551, 3565, 0), "Shayzien pub", "If 13 Shayzien Soldiers kill 46 Lizardmen each in a day, how many Lizardmen have they killed in total in a single day?", "598") ); From 513c250d2819809cffa6b3293a733296bde106f2 Mon Sep 17 00:00:00 2001 From: Adam Date: Tue, 11 Jan 2022 21:27:42 -0500 Subject: [PATCH 02/51] chat notifications: restore normal color after own name highlight --- .../plugins/chatnotifications/ChatNotificationsPlugin.java | 2 +- .../plugins/chatnotifications/ChatNotificationsPluginTest.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) 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 9f74205102..e275efc076 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 @@ -245,7 +245,7 @@ public class ChatNotificationsPlugin extends Plugin { final int start = matcher.start(); final String username = client.getLocalPlayer().getName(); - final String closeColor = MoreObjects.firstNonNull(getLastColor(message.substring(0, start)), ""); + final String closeColor = MoreObjects.firstNonNull(getLastColor(message.substring(0, start)), "'); final String replacement = "" + username + "" + closeColor; messageNode.setValue(matcher.replaceAll(replacement)); update = true; 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 0ca58fa457..760503f9fe 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 @@ -307,7 +307,7 @@ public class ChatNotificationsPluginTest ChatMessage chatMessage = new ChatMessage(messageNode, ChatMessageType.GAMEMESSAGE, "", "", "", 0); chatNotificationsPlugin.onChatMessage(chatMessage); - verify(messageNode).setValue("Logic Knot received a drop: Adamant longsword"); + verify(messageNode).setValue("Logic Knot received a drop: Adamant longsword"); } @Test From d5fe57865debff1a4fe3ce7229a548be48146095 Mon Sep 17 00:00:00 2001 From: Adam Date: Tue, 11 Jan 2022 21:30:16 -0500 Subject: [PATCH 03/51] chat message manager: support game chat color settings This will use the configured in-game setting for default chat colors, if configured. --- .../net/runelite/api/ChatMessageType.java | 4 +- .../main/java/net/runelite/api/VarPlayer.java | 33 ++++- .../net/runelite/client/chat/ChatColor.java | 20 ++- .../client/chat/ChatMessageManager.java | 123 +++++++++++++++--- 4 files changed, 149 insertions(+), 31 deletions(-) diff --git a/runelite-api/src/main/java/net/runelite/api/ChatMessageType.java b/runelite-api/src/main/java/net/runelite/api/ChatMessageType.java index d631395b89..e1bc085ab0 100644 --- a/runelite-api/src/main/java/net/runelite/api/ChatMessageType.java +++ b/runelite-api/src/main/java/net/runelite/api/ChatMessageType.java @@ -173,9 +173,9 @@ public enum ChatMessageType */ CLAN_CREATION_INVITATION(109), /** - * Clan wars challenge for clans rather than FCs + * Challenge offer for the clan tab */ - CLAN_CLAN_WARS_CHALLENGE(110), + CHALREQ_CLANCHAT(110), CLAN_GIM_FORM_GROUP(111), CLAN_GIM_GROUP_WITH(112), diff --git a/runelite-api/src/main/java/net/runelite/api/VarPlayer.java b/runelite-api/src/main/java/net/runelite/api/VarPlayer.java index c11574e662..6868dcd7c3 100644 --- a/runelite-api/src/main/java/net/runelite/api/VarPlayer.java +++ b/runelite-api/src/main/java/net/runelite/api/VarPlayer.java @@ -190,7 +190,38 @@ public enum VarPlayer /** * {@link NpcID} for the HP HUD */ - HP_HUD_NPC_ID(1683); + HP_HUD_NPC_ID(1683), + + /** + * Colors for chat messages + */ + SETTINGS_OPAQUE_CHAT_PUBLIC(2992), + SETTINGS_OPAQUE_CHAT_PRIVATE(2993), + SETTINGS_OPAQUE_CHAT_AUTO(2994), + SETTINGS_OPAQUE_CHAT_BROADCAST(2995), + SETTINGS_OPAQUE_CHAT_FRIEND(2996), + SETTINGS_OPAQUE_CHAT_CLAN(2997), + SETTINGS_OPAQUE_CHAT_GUEST_CLAN(3060), + SETTINGS_OPAQUE_CHAT_CLAN_BROADCAST(3192), + SETTINGS_OPAQUE_CHAT_IRON_GROUP_CHAT(3191), + SETTINGS_OPAQUE_CHAT_IRON_GROUP_BROADCAST(3193), + SETTINGS_OPAQUE_CHAT_TRADE_REQUEST(2998), + SETTINGS_OPAQUE_CHAT_CHALLENGE_REQUEST(2999), + + SETTINGS_TRANSPARENT_CHAT_PUBLIC(3000), + SETTINGS_TRANSPARENT_CHAT_PRIVATE(3001), + SETTINGS_TRANSPARENT_CHAT_AUTO(3002), + SETTINGS_TRANSPARENT_CHAT_BROADCAST(3003), + SETTINGS_TRANSPARENT_CHAT_FRIEND(3004), + SETTINGS_TRANSPARENT_CHAT_CLAN(3005), + SETTINGS_TRANSPARENT_CHAT_GUEST_CLAN(3061), + SETTINGS_TRANSPARENT_CHAT_CLAN_BROADCAST(3195), + SETTINGS_TRANSPARENT_CHAT_IRON_GROUP_CHAT(3194), + SETTINGS_TRANSPARENT_CHAT_IRON_GROUP_BROADCAST(3196), + SETTINGS_TRANSPARENT_CHAT_TRADE_REQUEST(3006), + SETTINGS_TRANSPARENT_CHAT_CHALLENGE_REQUEST(3007), + + ; private final int id; } diff --git a/runelite-client/src/main/java/net/runelite/client/chat/ChatColor.java b/runelite-client/src/main/java/net/runelite/client/chat/ChatColor.java index 0a6dfdfaf2..6db6101328 100644 --- a/runelite-client/src/main/java/net/runelite/client/chat/ChatColor.java +++ b/runelite-client/src/main/java/net/runelite/client/chat/ChatColor.java @@ -25,28 +25,26 @@ package net.runelite.client.chat; import java.awt.Color; +import javax.annotation.Nullable; +import lombok.AllArgsConstructor; import lombok.Data; import lombok.EqualsAndHashCode; +import net.runelite.api.VarPlayer; @Data -@EqualsAndHashCode(exclude = {"color", "isDefault"}) -public class ChatColor +@EqualsAndHashCode(exclude = {"color", "isDefault", "setting"}) +@AllArgsConstructor +class ChatColor { private ChatColorType type; private Color color; private boolean transparent; private boolean isDefault; + @Nullable + private VarPlayer setting; // varp for the in-game chat color setting public ChatColor(ChatColorType type, Color color, boolean transparent) { - this(type, color, transparent, false); - } - - public ChatColor(ChatColorType type, Color color, boolean transparent, boolean isDefault) - { - this.type = type; - this.color = color; - this.transparent = transparent; - this.isDefault = isDefault; + this(type, color, transparent, false, null); } } diff --git a/runelite-client/src/main/java/net/runelite/client/chat/ChatMessageManager.java b/runelite-client/src/main/java/net/runelite/client/chat/ChatMessageManager.java index 42bc06a17f..9f4ccb441a 100644 --- a/runelite-client/src/main/java/net/runelite/client/chat/ChatMessageManager.java +++ b/runelite-client/src/main/java/net/runelite/client/chat/ChatMessageManager.java @@ -37,13 +37,13 @@ import java.util.Objects; import java.util.Queue; import java.util.Set; import java.util.concurrent.ConcurrentLinkedQueue; -import java.util.concurrent.atomic.AtomicReference; import javax.inject.Inject; import javax.inject.Singleton; import net.runelite.api.ChatMessageType; import net.runelite.api.Client; import net.runelite.api.MessageNode; import net.runelite.api.Player; +import net.runelite.api.VarPlayer; import net.runelite.api.Varbits; import net.runelite.api.events.ResizeableChanged; import net.runelite.api.events.ScriptCallbackEvent; @@ -311,6 +311,86 @@ public class ChatMessageManager return null; } + // get the variable holding the chat color from the settings, from script4484 + private static VarPlayer getSettingsColor(ChatMessageType type, boolean transparent) + { + if (transparent) + { + switch (type) + { + case PUBLICCHAT: + case MODCHAT: + return VarPlayer.SETTINGS_TRANSPARENT_CHAT_PUBLIC; + case PRIVATECHATOUT: + case MODPRIVATECHAT: + case PRIVATECHAT: + case LOGINLOGOUTNOTIFICATION: + return VarPlayer.SETTINGS_TRANSPARENT_CHAT_PRIVATE; + case AUTOTYPER: + case MODAUTOTYPER: + return VarPlayer.SETTINGS_TRANSPARENT_CHAT_AUTO; + case BROADCAST: + return VarPlayer.SETTINGS_TRANSPARENT_CHAT_BROADCAST; + case FRIENDSCHAT: + return VarPlayer.SETTINGS_TRANSPARENT_CHAT_FRIEND; + case CLAN_CHAT: + return VarPlayer.SETTINGS_TRANSPARENT_CHAT_CLAN; + case TRADEREQ: + return VarPlayer.SETTINGS_TRANSPARENT_CHAT_TRADE_REQUEST; + case CHALREQ_TRADE: + case CHALREQ_FRIENDSCHAT: + case CHALREQ_CLANCHAT: + return VarPlayer.SETTINGS_TRANSPARENT_CHAT_CHALLENGE_REQUEST; + case CLAN_GUEST_CHAT: + return VarPlayer.SETTINGS_TRANSPARENT_CHAT_GUEST_CLAN; + case CLAN_GIM_CHAT: + return VarPlayer.SETTINGS_TRANSPARENT_CHAT_IRON_GROUP_CHAT; + case CLAN_MESSAGE: + return VarPlayer.SETTINGS_TRANSPARENT_CHAT_CLAN_BROADCAST; + case CLAN_GIM_MESSAGE: + return VarPlayer.SETTINGS_TRANSPARENT_CHAT_IRON_GROUP_BROADCAST; + } + } + else + { + switch (type) + { + case PUBLICCHAT: + case MODCHAT: + return VarPlayer.SETTINGS_OPAQUE_CHAT_PUBLIC; + case PRIVATECHATOUT: + case MODPRIVATECHAT: + case PRIVATECHAT: + case LOGINLOGOUTNOTIFICATION: + return VarPlayer.SETTINGS_OPAQUE_CHAT_PRIVATE; + case AUTOTYPER: + case MODAUTOTYPER: + return VarPlayer.SETTINGS_OPAQUE_CHAT_AUTO; + case BROADCAST: + return VarPlayer.SETTINGS_OPAQUE_CHAT_BROADCAST; + case FRIENDSCHAT: + return VarPlayer.SETTINGS_OPAQUE_CHAT_FRIEND; + case CLAN_CHAT: + return VarPlayer.SETTINGS_OPAQUE_CHAT_CLAN; + case TRADEREQ: + return VarPlayer.SETTINGS_OPAQUE_CHAT_TRADE_REQUEST; + case CHALREQ_TRADE: + case CHALREQ_FRIENDSCHAT: + case CHALREQ_CLANCHAT: + return VarPlayer.SETTINGS_OPAQUE_CHAT_CHALLENGE_REQUEST; + case CLAN_GUEST_CHAT: + return VarPlayer.SETTINGS_OPAQUE_CHAT_GUEST_CLAN; + case CLAN_GIM_CHAT: + return VarPlayer.SETTINGS_OPAQUE_CHAT_IRON_GROUP_CHAT; + case CLAN_MESSAGE: + return VarPlayer.SETTINGS_OPAQUE_CHAT_CLAN_BROADCAST; + case CLAN_GIM_MESSAGE: + return VarPlayer.SETTINGS_OPAQUE_CHAT_IRON_GROUP_BROADCAST; + } + } + return null; + } + /** * Load all configured colors */ @@ -324,13 +404,13 @@ public class ChatMessageManager Color defaultTransparent = getDefaultColor(chatMessageType, true); if (defaultTransparent != null) { - cacheColor(new ChatColor(ChatColorType.NORMAL, defaultTransparent, true, true), chatMessageType); + cacheColor(new ChatColor(ChatColorType.NORMAL, defaultTransparent, true, true, getSettingsColor(chatMessageType, true)), chatMessageType); } Color defaultOpaque = getDefaultColor(chatMessageType, false); if (defaultOpaque != null) { - cacheColor(new ChatColor(ChatColorType.NORMAL, defaultOpaque, false, true), chatMessageType); + cacheColor(new ChatColor(ChatColorType.NORMAL, defaultOpaque, false, true, getSettingsColor(chatMessageType, false)), chatMessageType); } } @@ -785,23 +865,32 @@ public class ChatMessageManager final boolean transparent = client.isResized() && transparencyVarbit != 0; final Collection chatColors = colorCache.get(type); - - if (chatColors == null || chatColors.isEmpty()) + for (ChatColor chatColor : chatColors) { - return runeLiteFormatMessage; + if (chatColor.isTransparent() == transparent) + { + Color color = chatColor.getColor(); + + VarPlayer varp = chatColor.getSetting(); + if (varp != null) + { + // Apply configured color from game settings, if set + assert chatColor.isDefault(); + int v = client.getVar(varp); + if (v != 0) + { + color = new Color(v - 1); + } + } + + // Replace custom formatting with actual colors + runeLiteFormatMessage = runeLiteFormatMessage.replaceAll( + "", + ColorUtil.colorTag(color)); + } } - final AtomicReference resultMessage = new AtomicReference<>(runeLiteFormatMessage); - - // Replace custom formatting with actual colors - chatColors.stream() - .filter(chatColor -> chatColor.isTransparent() == transparent) - .forEach(chatColor -> - resultMessage.getAndUpdate(oldMessage -> oldMessage.replaceAll( - "", - ColorUtil.colorTag(chatColor.getColor())))); - - return resultMessage.get(); + return runeLiteFormatMessage; } private void refreshAll() From c7e6ffb4de22f687bcdf1f1d3db2bb3bd7bc9d6e Mon Sep 17 00:00:00 2001 From: Adam Date: Tue, 11 Jan 2022 21:30:18 -0500 Subject: [PATCH 04/51] chat notifications: fix restoring last color on own name highlight This was an issue with multiple name matches, since it was applying the replacement with its close color to all matches, even though only scanning the message for the last color up until the first match --- .../ChatNotificationsPlugin.java | 20 +++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) 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 e275efc076..04d3e9fc8d 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 @@ -243,12 +243,24 @@ public class ChatNotificationsPlugin extends Plugin Matcher matcher = usernameMatcher.matcher(message); if (matcher.find()) { - final int start = matcher.start(); final String username = client.getLocalPlayer().getName(); - final String closeColor = MoreObjects.firstNonNull(getLastColor(message.substring(0, start)), "'); - final String replacement = "" + username + "" + closeColor; - messageNode.setValue(matcher.replaceAll(replacement)); + StringBuffer stringBuffer = new StringBuffer(); + do + { + final int start = matcher.start(); + final String closeColor = MoreObjects.firstNonNull( + getLastColor(message.substring(0, start)), + "'); + final String replacement = "" + username + "" + closeColor; + matcher.appendReplacement(stringBuffer, replacement); + } + while (matcher.find()); + + matcher.appendTail(stringBuffer); + + messageNode.setValue(stringBuffer.toString()); update = true; + if (config.notifyOnOwnName() && (chatMessage.getType() == ChatMessageType.PUBLICCHAT || chatMessage.getType() == ChatMessageType.PRIVATECHAT || chatMessage.getType() == ChatMessageType.FRIENDSCHAT From 9ff0538cf8affa00cc92714a0c851955730fe6f4 Mon Sep 17 00:00:00 2001 From: Adam Date: Tue, 11 Jan 2022 21:58:39 -0500 Subject: [PATCH 05/51] chat notifications: simplify finding closing color in pattern matching Searching the replacement isn't necessary since it won't ever have any additional col tags except for the ones identified by getLastColor, which would be identified even when searching the original message. Instead, just search the original message up to and including the match. --- .../ChatNotificationsPlugin.java | 28 ++++++------------- 1 file changed, 9 insertions(+), 19 deletions(-) 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 04d3e9fc8d..e0f4f174c9 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 @@ -247,7 +247,7 @@ public class ChatNotificationsPlugin extends Plugin StringBuffer stringBuffer = new StringBuffer(); do { - final int start = matcher.start(); + final int start = matcher.start(); // start not end, since username won't contain a col tag final String closeColor = MoreObjects.firstNonNull( getLastColor(message.substring(0, start)), "'); @@ -291,26 +291,16 @@ public class ChatNotificationsPlugin extends Plugin do { - String value = matcher.group(); - - // Determine the ending color by: - // 1) use the color from value if it has one - // 2) use the last color from stringBuffer + - // To do #2 we just search for the last col tag after calling appendReplacement - String endColor = getLastColor(value); - + final int end = matcher.end(); + // Determine the ending color by finding the last color tag up to and + // including the match. + final String closeColor = MoreObjects.firstNonNull( + getLastColor(nodeValue.substring(0, end)), + "'); // Strip color tags from the highlighted region so that it remains highlighted correctly - value = stripColor(value); + final String value = stripColor(matcher.group()); - matcher.appendReplacement(stringBuffer, "' + value); - - if (endColor == null) - { - endColor = getLastColor(stringBuffer.toString()); - } - - // Append end color - stringBuffer.append(endColor == null ? "" : endColor); + matcher.appendReplacement(stringBuffer, "' + value + closeColor); update = true; matchesHighlight = true; From 5960a2f43ef58703191b251464a4f43b8248a6b2 Mon Sep 17 00:00:00 2001 From: Adam Date: Tue, 11 Jan 2022 23:50:53 -0500 Subject: [PATCH 06/51] chat message manager: format rl-messages at chat build time This allows different final messages being built for split chat vs normal chat, fixing incorrectly applying the default chatbox color to split chat. --- .../client/chat/ChatMessageManager.java | 106 ++++++++---------- .../chatcommands/ChatCommandsPlugin.java | 15 --- .../ChatNotificationsPlugin.java | 5 - .../client/plugins/raids/RaidsPlugin.java | 1 - .../client/plugins/slayer/SlayerPlugin.java | 5 - .../plugins/wintertodt/WintertodtPlugin.java | 5 - .../net/runelite/client/ui/JagexColors.java | 4 +- .../src/main/scripts/ChatBuilder.rs2asm | 4 +- .../src/main/scripts/ChatSplitBuilder.rs2asm | 4 +- .../client/chat/ChatMessageManagerTest.java | 10 +- .../chatcommands/ChatCommandsPluginTest.java | 5 - .../ChatNotificationsPluginTest.java | 7 +- .../plugins/slayer/SlayerPluginTest.java | 15 +-- .../wintertodt/WintertodtPluginTest.java | 5 - 14 files changed, 63 insertions(+), 128 deletions(-) diff --git a/runelite-client/src/main/java/net/runelite/client/chat/ChatMessageManager.java b/runelite-client/src/main/java/net/runelite/client/chat/ChatMessageManager.java index 9f4ccb441a..91d7c99683 100644 --- a/runelite-client/src/main/java/net/runelite/client/chat/ChatMessageManager.java +++ b/runelite-client/src/main/java/net/runelite/client/chat/ChatMessageManager.java @@ -31,9 +31,7 @@ import com.google.common.collect.HashMultimap; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Multimap; import java.awt.Color; -import java.util.Arrays; import java.util.Collection; -import java.util.Objects; import java.util.Queue; import java.util.Set; import java.util.concurrent.ConcurrentLinkedQueue; @@ -45,9 +43,7 @@ import net.runelite.api.MessageNode; import net.runelite.api.Player; import net.runelite.api.VarPlayer; import net.runelite.api.Varbits; -import net.runelite.api.events.ResizeableChanged; import net.runelite.api.events.ScriptCallbackEvent; -import net.runelite.api.events.VarbitChanged; import net.runelite.client.callback.ClientThread; import net.runelite.client.config.ChatColorConfig; import net.runelite.client.eventbus.EventBus; @@ -66,7 +62,6 @@ public class ChatMessageManager private final Client client; private final ChatColorConfig chatColorConfig; private final ClientThread clientThread; - private int transparencyVarbit = -1; private final Queue queuedMessages = new ConcurrentLinkedQueue<>(); @Inject @@ -83,40 +78,25 @@ public class ChatMessageManager loadColors(); } - @Subscribe - public void onVarbitChanged(VarbitChanged event) - { - int setting = client.getVar(Varbits.TRANSPARENT_CHATBOX); - - if (transparencyVarbit != setting) - { - transparencyVarbit = setting; - refreshAll(); - } - } - - @Subscribe - public void onResizeableChanged(ResizeableChanged event) - { - refreshAll(); - } - @Subscribe public void onConfigChanged(ConfigChanged event) { if (event.getGroup().equals("textrecolor")) { loadColors(); - clientThread.invokeLater(this::refreshAll); + clientThread.invokeLater(client::refreshChat); } } @VisibleForTesting void colorChatMessage() { + final int[] intStack = client.getIntStack(); final String[] stringStack = client.getStringStack(); final int size = client.getStringStackSize(); - final int uid = client.getIntStack()[client.getIntStackSize() - 1]; + final int isize = client.getIntStackSize(); + final int uid = intStack[isize - 1]; + final boolean splitpmbox = intStack[isize - 2] == 1; final MessageNode messageNode = client.getMessages().get(uid); assert messageNode != null : "chat message build for unknown message"; @@ -184,6 +164,12 @@ public class ChatMessageManager stringStack[size - 4] = ColorUtil.wrapWithColorTag(channel, channelColor); } + if (messageNode.getRuneLiteFormatMessage() != null) + { + stringStack[size - 2] = message = formatRuneLiteMessage(messageNode.getRuneLiteFormatMessage(), + chatMessageType, splitpmbox); + } + final Collection chatColors = colorCache.get(chatMessageType); for (ChatColor chatColor : chatColors) { @@ -824,13 +810,11 @@ public class ChatMessageManager return; } - final String formattedMessage = formatRuneLiteMessage(message.getRuneLiteFormattedMessage(), message.getType()); - // this updates chat cycle final MessageNode line = client.addChatMessage( message.getType(), MoreObjects.firstNonNull(message.getName(), ""), - MoreObjects.firstNonNull(formattedMessage, message.getValue()), + MoreObjects.firstNonNull(message.getRuneLiteFormattedMessage(), message.getValue()), message.getSender()); // Update the message with RuneLite additions @@ -843,64 +827,64 @@ public class ChatMessageManager } /** - * Rebuild the message node message from the RuneLite format message + * Rebuild the message node message from the RuneLite format message. + * DEPRECATED: no longer needs to be called. * * @param messageNode message node */ + @Deprecated public void update(final MessageNode messageNode) { - String message = formatRuneLiteMessage(messageNode.getRuneLiteFormatMessage(), messageNode.getType()); - if (message != null) - { - messageNode.setValue(message); - } } - private String formatRuneLiteMessage(String runeLiteFormatMessage, ChatMessageType type) + @VisibleForTesting + String formatRuneLiteMessage(String runeLiteFormatMessage, ChatMessageType type, boolean pmbox) { - if (Strings.isNullOrEmpty(runeLiteFormatMessage)) - { - return null; - } - - final boolean transparent = client.isResized() && transparencyVarbit != 0; + final boolean transparentChatbox = client.getVar(Varbits.TRANSPARENT_CHATBOX) != 0; + final boolean transparent = client.isResized() && transparentChatbox; final Collection chatColors = colorCache.get(type); for (ChatColor chatColor : chatColors) { if (chatColor.isTransparent() == transparent) { - Color color = chatColor.getColor(); + String colstr; - VarPlayer varp = chatColor.getSetting(); - if (varp != null) + if (pmbox && chatColor.getType() == ChatColorType.NORMAL) { - // Apply configured color from game settings, if set - assert chatColor.isDefault(); - int v = client.getVar(varp); - if (v != 0) + // The default ChatColors for private have the chatbox text color, not the split chat color, + // and the split chat color is set by widget color, so just use . The in-game + // private chat color doesn't apply to split chat either so using that here also is incorrect. + // + // If we recolor the final message later we replace with the desired color in + // colorChatMessage() + colstr = ColorUtil.CLOSING_COLOR_TAG; + } + else + { + Color color = chatColor.getColor(); + + VarPlayer varp = chatColor.getSetting(); + if (varp != null) { - color = new Color(v - 1); + // Apply configured color from game settings, if set + assert chatColor.isDefault(); + int v = client.getVar(varp); + if (v != 0) + { + color = new Color(v - 1); + } } + + colstr = ColorUtil.colorTag(color); } // Replace custom formatting with actual colors runeLiteFormatMessage = runeLiteFormatMessage.replaceAll( "", - ColorUtil.colorTag(color)); + colstr); } } return runeLiteFormatMessage; } - - private void refreshAll() - { - client.getChatLineMap().values().stream() - .filter(Objects::nonNull) - .flatMap(clb -> Arrays.stream(clb.getLines())) - .filter(Objects::nonNull) - .forEach(this::update); - - client.refreshChat(); - } } 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 61da99f6fd..f1e72c9303 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 @@ -77,7 +77,6 @@ import net.runelite.client.chat.ChatClient; import net.runelite.client.chat.ChatColorType; import net.runelite.client.chat.ChatCommandManager; import net.runelite.client.chat.ChatMessageBuilder; -import net.runelite.client.chat.ChatMessageManager; import net.runelite.client.config.ConfigManager; import net.runelite.client.config.RuneLiteConfig; import net.runelite.client.eventbus.Subscribe; @@ -175,9 +174,6 @@ public class ChatCommandsPlugin extends Plugin @Inject private ItemManager itemManager; - @Inject - private ChatMessageManager chatMessageManager; - @Inject private ChatCommandManager chatCommandManager; @@ -840,7 +836,6 @@ public class ChatCommandsPlugin extends Plugin log.debug("Setting response {}", response); final MessageNode messageNode = chatMessage.getMessageNode(); messageNode.setRuneLiteFormatMessage(response); - chatMessageManager.update(messageNode); client.refreshChat(); } @@ -930,7 +925,6 @@ public class ChatCommandsPlugin extends Plugin log.debug("Setting response {}", response); final MessageNode messageNode = chatMessage.getMessageNode(); messageNode.setRuneLiteFormatMessage(response); - chatMessageManager.update(messageNode); client.refreshChat(); } @@ -974,7 +968,6 @@ public class ChatCommandsPlugin extends Plugin log.debug("Setting response {}", response); final MessageNode messageNode = chatMessage.getMessageNode(); messageNode.setRuneLiteFormatMessage(response); - chatMessageManager.update(messageNode); client.refreshChat(); } @@ -1061,7 +1054,6 @@ public class ChatCommandsPlugin extends Plugin log.debug("Setting response {}", response); final MessageNode messageNode = chatMessage.getMessageNode(); messageNode.setRuneLiteFormatMessage(response); - chatMessageManager.update(messageNode); client.refreshChat(); } @@ -1137,7 +1129,6 @@ public class ChatCommandsPlugin extends Plugin log.debug("Setting response {}", response); final MessageNode messageNode = chatMessage.getMessageNode(); messageNode.setRuneLiteFormatMessage(response); - chatMessageManager.update(messageNode); client.refreshChat(); } @@ -1231,7 +1222,6 @@ public class ChatCommandsPlugin extends Plugin log.debug("Setting response {}", response); final MessageNode messageNode = chatMessage.getMessageNode(); messageNode.setRuneLiteFormatMessage(response); - chatMessageManager.update(messageNode); client.refreshChat(); } @@ -1321,7 +1311,6 @@ public class ChatCommandsPlugin extends Plugin log.debug("Setting response {}", response); messageNode.setRuneLiteFormatMessage(response); - chatMessageManager.update(messageNode); client.refreshChat(); } } @@ -1403,7 +1392,6 @@ public class ChatCommandsPlugin extends Plugin log.debug("Setting response {}", response); final MessageNode messageNode = chatMessage.getMessageNode(); messageNode.setRuneLiteFormatMessage(response); - chatMessageManager.update(messageNode); client.refreshChat(); } catch (IOException ex) @@ -1488,7 +1476,6 @@ public class ChatCommandsPlugin extends Plugin log.debug("Setting response {}", response); final MessageNode messageNode = chatMessage.getMessageNode(); messageNode.setRuneLiteFormatMessage(response); - chatMessageManager.update(messageNode); client.refreshChat(); } catch (IOException ex) @@ -1616,7 +1603,6 @@ public class ChatCommandsPlugin extends Plugin log.debug("Setting response {}", response); final MessageNode messageNode = chatMessage.getMessageNode(); messageNode.setRuneLiteFormatMessage(response); - chatMessageManager.update(messageNode); client.refreshChat(); } catch (IOException ex) @@ -1710,7 +1696,6 @@ public class ChatCommandsPlugin extends Plugin log.debug("Setting response {}", response); final MessageNode messageNode = chatMessage.getMessageNode(); messageNode.setRuneLiteFormatMessage(response); - chatMessageManager.update(messageNode); client.refreshChat(); } catch (IOException ex) 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 e0f4f174c9..44a04477b3 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 @@ -47,7 +47,6 @@ import net.runelite.api.events.ChatMessage; import net.runelite.api.events.GameStateChanged; import net.runelite.client.Notifier; import net.runelite.client.chat.ChatColorType; -import net.runelite.client.chat.ChatMessageManager; import net.runelite.client.config.ConfigManager; import net.runelite.client.eventbus.Subscribe; import net.runelite.client.events.ConfigChanged; @@ -69,9 +68,6 @@ public class ChatNotificationsPlugin extends Plugin @Inject private ChatNotificationsConfig config; - @Inject - private ChatMessageManager chatMessageManager; - @Inject private Notifier notifier; @@ -324,7 +320,6 @@ public class ChatNotificationsPlugin extends Plugin if (update) { messageNode.setRuneLiteFormatMessage(messageNode.getValue()); - chatMessageManager.update(messageNode); } } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/raids/RaidsPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/raids/RaidsPlugin.java index 4722d85d85..dd1b96bd3f 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/raids/RaidsPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/raids/RaidsPlugin.java @@ -830,7 +830,6 @@ public class RaidsPlugin extends Plugin log.debug("Setting response {}", response); final MessageNode messageNode = chatMessage.getMessageNode(); messageNode.setRuneLiteFormatMessage(response); - chatMessageManager.update(messageNode); client.refreshChat(); } 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 0a2333ae2e..f7913a57c5 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 @@ -79,7 +79,6 @@ import net.runelite.client.chat.ChatClient; import net.runelite.client.chat.ChatColorType; import net.runelite.client.chat.ChatCommandManager; import net.runelite.client.chat.ChatMessageBuilder; -import net.runelite.client.chat.ChatMessageManager; import net.runelite.client.config.ConfigManager; import net.runelite.client.eventbus.Subscribe; import net.runelite.client.events.ChatInput; @@ -161,9 +160,6 @@ public class SlayerPlugin extends Plugin @Inject private TargetWeaknessOverlay targetWeaknessOverlay; - @Inject - private ChatMessageManager chatMessageManager; - @Inject private ChatCommandManager chatCommandManager; @@ -875,7 +871,6 @@ public class SlayerPlugin extends Plugin final MessageNode messageNode = chatMessage.getMessageNode(); messageNode.setRuneLiteFormatMessage(response); - chatMessageManager.update(messageNode); client.refreshChat(); } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/wintertodt/WintertodtPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/wintertodt/WintertodtPlugin.java index 63b7f61331..bc7d374c60 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/wintertodt/WintertodtPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/wintertodt/WintertodtPlugin.java @@ -69,7 +69,6 @@ import net.runelite.api.events.GameTick; import net.runelite.api.events.ItemContainerChanged; import net.runelite.api.events.VarbitChanged; import net.runelite.client.Notifier; -import net.runelite.client.chat.ChatMessageManager; import net.runelite.client.config.ConfigManager; import net.runelite.client.eventbus.Subscribe; import net.runelite.client.plugins.Plugin; @@ -105,9 +104,6 @@ public class WintertodtPlugin extends Plugin @Inject private WintertodtConfig config; - @Inject - private ChatMessageManager chatMessageManager; - @Getter(AccessLevel.PACKAGE) private WintertodtActivity currentActivity = WintertodtActivity.IDLE; @@ -314,7 +310,6 @@ public class WintertodtPlugin extends Plugin // Recolor message for damage notification messageNode.setRuneLiteFormatMessage(ColorUtil.wrapWithColorTag(messageNode.getValue(), config.damageNotificationColor())); - chatMessageManager.update(messageNode); client.refreshChat(); // all actions except woodcutting and idle are interrupted from damage diff --git a/runelite-client/src/main/java/net/runelite/client/ui/JagexColors.java b/runelite-client/src/main/java/net/runelite/client/ui/JagexColors.java index aaab638696..1f61f5346a 100644 --- a/runelite-client/src/main/java/net/runelite/client/ui/JagexColors.java +++ b/runelite-client/src/main/java/net/runelite/client/ui/JagexColors.java @@ -35,7 +35,7 @@ public class JagexColors * Colors of chat text when displayed on an opaque background. */ public static final Color CHAT_PUBLIC_TEXT_OPAQUE_BACKGROUND = Color.BLUE; - public static final Color CHAT_PRIVATE_MESSAGE_TEXT_OPAQUE_BACKGROUND = Color.CYAN; + public static final Color CHAT_PRIVATE_MESSAGE_TEXT_OPAQUE_BACKGROUND = new Color(0x7F0000); // in chatbox, not split chat public static final Color CHAT_FC_TEXT_OPAQUE_BACKGROUND = new Color(127, 0, 0); public static final Color CHAT_FC_NAME_OPAQUE_BACKGROUND = Color.BLUE; public static final Color CHAT_GAME_EXAMINE_TEXT_OPAQUE_BACKGROUND = Color.BLACK; @@ -45,7 +45,7 @@ public class JagexColors * Colors of chat text when displayed on a transparent background. */ public static final Color CHAT_PUBLIC_TEXT_TRANSPARENT_BACKGROUND = new Color(144, 144, 255); - public static final Color CHAT_PRIVATE_MESSAGE_TEXT_TRANSPARENT_BACKGROUND = Color.CYAN; + public static final Color CHAT_PRIVATE_MESSAGE_TEXT_TRANSPARENT_BACKGROUND = new Color(0xBF2020); // in chatbox, not split chat public static final Color CHAT_FC_TEXT_TRANSPARENT_BACKGROUND = new Color(239, 80, 80); public static final Color CHAT_FC_NAME_TRANSPARENT_BACKGROUND = new Color(144, 112, 255); public static final Color CHAT_GAME_EXAMINE_TEXT_TRANSPARENT_BACKGROUND = Color.WHITE; diff --git a/runelite-client/src/main/scripts/ChatBuilder.rs2asm b/runelite-client/src/main/scripts/ChatBuilder.rs2asm index e3739e6da4..eeb6f602dd 100644 --- a/runelite-client/src/main/scripts/ChatBuilder.rs2asm +++ b/runelite-client/src/main/scripts/ChatBuilder.rs2asm @@ -440,14 +440,16 @@ LABEL391: if_icmpeq LABEL406 jump LABEL1751 LABEL406: + iconst 0 ; splitpmbox iload 10 ; message uid sload 17 ; message channel sload 16 ; message name sload 18 ; message sload 21 ; message timestamp sconst "chatMessageBuilding" - runelite_callback + runelite_callback pop_int ; pop uid + pop_int ; splitpmbox sstore 21 ; message timestamp sstore 18 ; message sstore 16 ; message name diff --git a/runelite-client/src/main/scripts/ChatSplitBuilder.rs2asm b/runelite-client/src/main/scripts/ChatSplitBuilder.rs2asm index eb8907443e..e68c16f9db 100644 --- a/runelite-client/src/main/scripts/ChatSplitBuilder.rs2asm +++ b/runelite-client/src/main/scripts/ChatSplitBuilder.rs2asm @@ -413,14 +413,16 @@ CHAT_FILTER: if_icmpeq LABEL369 ; Check if we are building this message jump LABEL555 LABEL369: + iconst 1 ; splitpmbox iload 12 ; message uid sconst "" ; message channel sload 1 ; message name sload 0 ; message sload 2 ; message timestamp sconst "chatMessageBuilding" - runelite_callback + runelite_callback pop_int ; uid + pop_int ; splitpmbox sstore 2 ; message timestamp sstore 0 ; message sstore 1 ; message name diff --git a/runelite-client/src/test/java/net/runelite/client/chat/ChatMessageManagerTest.java b/runelite-client/src/test/java/net/runelite/client/chat/ChatMessageManagerTest.java index f389702dce..5f5d2d59a9 100644 --- a/runelite-client/src/test/java/net/runelite/client/chat/ChatMessageManagerTest.java +++ b/runelite-client/src/test/java/net/runelite/client/chat/ChatMessageManagerTest.java @@ -43,7 +43,6 @@ import org.junit.runner.RunWith; import static org.mockito.ArgumentMatchers.anyLong; import org.mockito.Mock; import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import org.mockito.junit.MockitoJUnitRunner; @@ -86,6 +85,7 @@ public class ChatMessageManagerTest "" }; istack = new int[]{ + 0, // splitpmbox 1 }; when(client.getStringStack()).thenReturn(sstack); @@ -183,12 +183,8 @@ public class ChatMessageManagerTest .append("%)") .build(); - MessageNode messageNode = mock(MessageNode.class); - when(messageNode.getType()).thenReturn(ChatMessageType.FRIENDSCHATNOTIFICATION); - when(messageNode.getRuneLiteFormatMessage()).thenReturn(chatMessage); + String formattedMessage = chatMessageManager.formatRuneLiteMessage(chatMessage, ChatMessageType.FRIENDSCHATNOTIFICATION, false); - chatMessageManager.update(messageNode); - - verify(messageNode).setValue("Total points: 42, Personal points: 43 (44%)"); + assertEquals("Total points: 42, Personal points: 43 (44%)", formattedMessage); } } \ No newline at end of file diff --git a/runelite-client/src/test/java/net/runelite/client/plugins/chatcommands/ChatCommandsPluginTest.java b/runelite-client/src/test/java/net/runelite/client/plugins/chatcommands/ChatCommandsPluginTest.java index 918732d049..42d5b729c5 100644 --- a/runelite-client/src/test/java/net/runelite/client/plugins/chatcommands/ChatCommandsPluginTest.java +++ b/runelite-client/src/test/java/net/runelite/client/plugins/chatcommands/ChatCommandsPluginTest.java @@ -51,7 +51,6 @@ import static net.runelite.api.widgets.WidgetID.DIARY_QUEST_GROUP_ID; import net.runelite.api.widgets.WidgetInfo; import net.runelite.client.chat.ChatClient; import net.runelite.client.chat.ChatCommandManager; -import net.runelite.client.chat.ChatMessageManager; import net.runelite.client.config.ChatColorConfig; import net.runelite.client.config.ConfigManager; import net.runelite.client.config.RuneLiteConfig; @@ -105,10 +104,6 @@ public class ChatCommandsPluginTest @Bind HiscoreClient hiscoreClient; - @Mock - @Bind - ChatMessageManager chatMessageManager; - @Mock @Bind ChatClient chatClient; 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 760503f9fe..1ec30ad41f 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 @@ -37,14 +37,13 @@ import net.runelite.api.MessageNode; import net.runelite.api.Player; import net.runelite.api.events.ChatMessage; import net.runelite.client.Notifier; -import net.runelite.client.chat.ChatMessageManager; import net.runelite.client.util.Text; import static org.junit.Assert.assertEquals; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; -import org.mockito.Mock; import static org.mockito.ArgumentMatchers.any; +import org.mockito.Mock; import static org.mockito.Mockito.lenient; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.times; @@ -63,10 +62,6 @@ public class ChatNotificationsPluginTest @Bind private ChatNotificationsConfig config; - @Mock - @Bind - private ChatMessageManager chatMessageManager; - @Mock @Bind private Notifier notifier; 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 fcdc75db13..3fc570c233 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 @@ -54,7 +54,6 @@ import net.runelite.api.widgets.WidgetInfo; import net.runelite.client.Notifier; import net.runelite.client.chat.ChatClient; import net.runelite.client.chat.ChatCommandManager; -import net.runelite.client.chat.ChatMessageManager; import net.runelite.client.config.ConfigManager; import net.runelite.client.game.ItemManager; import net.runelite.client.game.npcoverlay.NpcOverlayService; @@ -158,10 +157,6 @@ public class SlayerPluginTest @Bind Notifier notifier; - @Mock - @Bind - ChatMessageManager chatMessageManager; - @Mock @Bind ChatCommandManager chatCommandManager; @@ -788,14 +783,15 @@ public class SlayerPluginTest when(slayerConfig.taskCommand()).thenReturn(true); when(chatClient.getTask(anyString())).thenReturn(task); + MessageNode messageNode = mock(MessageNode.class); ChatMessage setMessage = new ChatMessage(); setMessage.setType(ChatMessageType.PUBLICCHAT); setMessage.setName("Adam"); - setMessage.setMessageNode(mock(MessageNode.class)); + setMessage.setMessageNode(messageNode); slayerPlugin.taskLookup(setMessage, "!task"); - verify(chatMessageManager).update(any(MessageNode.class)); + verify(messageNode).setRuneLiteFormatMessage(anyString()); } @Test @@ -810,14 +806,15 @@ public class SlayerPluginTest when(slayerConfig.taskCommand()).thenReturn(true); when(chatClient.getTask(anyString())).thenReturn(task); + MessageNode messageNode = mock(MessageNode.class); ChatMessage chatMessage = new ChatMessage(); chatMessage.setType(ChatMessageType.PUBLICCHAT); chatMessage.setName("Adam"); - chatMessage.setMessageNode(mock(MessageNode.class)); + chatMessage.setMessageNode(messageNode); slayerPlugin.taskLookup(chatMessage, "!task"); - verify(chatMessageManager, never()).update(any(MessageNode.class)); + verify(messageNode, never()).setRuneLiteFormatMessage(anyString()); } @Test diff --git a/runelite-client/src/test/java/net/runelite/client/plugins/wintertodt/WintertodtPluginTest.java b/runelite-client/src/test/java/net/runelite/client/plugins/wintertodt/WintertodtPluginTest.java index 3abf2f919f..3d57b80a3f 100644 --- a/runelite-client/src/test/java/net/runelite/client/plugins/wintertodt/WintertodtPluginTest.java +++ b/runelite-client/src/test/java/net/runelite/client/plugins/wintertodt/WintertodtPluginTest.java @@ -33,7 +33,6 @@ import net.runelite.api.Client; import net.runelite.api.Varbits; import net.runelite.api.events.VarbitChanged; import net.runelite.client.Notifier; -import net.runelite.client.chat.ChatMessageManager; import net.runelite.client.ui.overlay.OverlayManager; import org.junit.Before; import org.junit.Test; @@ -62,10 +61,6 @@ public class WintertodtPluginTest @Bind OverlayManager overlayManager; - @Mock - @Bind - ChatMessageManager chatMessageManager; - @Mock @Bind Notifier notifier; From ac547210f7e2e11ff8453b16965ba87aae292d4c Mon Sep 17 00:00:00 2001 From: Adam Date: Wed, 12 Jan 2022 14:30:19 -0500 Subject: [PATCH 07/51] ground items: fix show item quantities to work with no item highlight mode This also cleans up the telegrab highlighting code --- .../grounditems/GroundItemsPlugin.java | 36 ++++++------------- 1 file changed, 11 insertions(+), 25 deletions(-) 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 25338d4285..01055a6d96 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 @@ -116,8 +116,6 @@ public class GroundItemsPlugin extends Plugin // ItemID for coins private static final int COINS = ItemID.COINS_995; - private static final String TELEGRAB_TEXT = ColorUtil.wrapWithColorTag("Telekinetic Grab", Color.GREEN) + ColorUtil.prependColorTag(" -> ", Color.WHITE); - @Getter(AccessLevel.PACKAGE) @Setter(AccessLevel.PACKAGE) private Map.Entry textBoxBounds; @@ -481,14 +479,11 @@ public class GroundItemsPlugin extends Plugin @Subscribe public void onMenuEntryAdded(MenuEntryAdded event) { - if (config.itemHighlightMode() == ItemHighlightMode.MENU || config.itemHighlightMode() == ItemHighlightMode.BOTH) + MenuAction type = MenuAction.of(event.getType()); + if (type == MenuAction.GROUND_ITEM_FIRST_OPTION || type == MenuAction.GROUND_ITEM_SECOND_OPTION || + type == MenuAction.GROUND_ITEM_THIRD_OPTION || type == MenuAction.GROUND_ITEM_FOURTH_OPTION || + type == MenuAction.GROUND_ITEM_FIFTH_OPTION || type == MenuAction.SPELL_CAST_ON_GROUND_ITEM) { - final boolean telegrabEntry = event.getOption().equals("Cast") && event.getTarget().startsWith(TELEGRAB_TEXT) && event.getType() == MenuAction.SPELL_CAST_ON_GROUND_ITEM.getId(); - if (!(event.getOption().equals("Take") && event.getType() == MenuAction.GROUND_ITEM_THIRD_OPTION.getId()) && !telegrabEntry) - { - return; - } - final int itemId = event.getIdentifier(); final int sceneX = event.getActionParam0(); final int sceneY = event.getActionParam1(); @@ -507,33 +502,24 @@ public class GroundItemsPlugin extends Plugin final Color color = getItemColor(highlighted, hidden); final boolean canBeRecolored = highlighted != null || (hidden != null && config.recolorMenuHiddenItems()); - if (color != null && canBeRecolored && !color.equals(config.defaultColor())) + if ((config.itemHighlightMode() == ItemHighlightMode.MENU || config.itemHighlightMode() == ItemHighlightMode.BOTH) && + (color != null && canBeRecolored && !color.equals(config.defaultColor()))) { final MenuHighlightMode mode = config.menuHighlightMode(); if (mode == BOTH || mode == OPTION) { - final String optionText = telegrabEntry ? "Cast" : "Take"; - lastEntry.setOption(ColorUtil.prependColorTag(optionText, color)); + lastEntry.setOption(ColorUtil.prependColorTag(lastEntry.getOption(), color)); } if (mode == BOTH || mode == NAME) { + // Logs + // Telekinetic Grab -> Logs String target = lastEntry.getTarget(); - if (telegrabEntry) - { - target = target.substring(TELEGRAB_TEXT.length()); - } - - target = ColorUtil.prependColorTag(target.substring(target.indexOf('>') + 1), color); - - if (telegrabEntry) - { - target = TELEGRAB_TEXT + target; - } - - lastEntry.setTarget(target); + int i = target.lastIndexOf('>'); + lastEntry.setTarget(target.substring(0, i - 11) + ColorUtil.colorTag(color) + target.substring(i + 1)); } } From 077c0a78b36d0220c02be8b12d06835b07d079d6 Mon Sep 17 00:00:00 2001 From: Adam Date: Wed, 12 Jan 2022 14:30:22 -0500 Subject: [PATCH 08/51] ground items: add option to deprioritize hidden item options --- .../client/plugins/grounditems/GroundItemsConfig.java | 11 +++++++++++ .../client/plugins/grounditems/GroundItemsPlugin.java | 5 +++++ 2 files changed, 16 insertions(+) diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/grounditems/GroundItemsConfig.java b/runelite-client/src/main/java/net/runelite/client/plugins/grounditems/GroundItemsConfig.java index 01693334e1..2e32a8e336 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/grounditems/GroundItemsConfig.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/grounditems/GroundItemsConfig.java @@ -131,6 +131,17 @@ public interface GroundItemsConfig extends Config { return false; } + + @ConfigItem( + keyName = "deprioritizeHiddenItems", + name = "Deprioritize Menu Hidden Items", + description = "Depriotizies the menu options for items which are hidden, requiring a right click to pick up.", + position = 5 + ) + default boolean deprioritizeHiddenItems() + { + return false; + } @ConfigItem( keyName = "highlightTiles", 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 01055a6d96..773fd8b044 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 @@ -527,6 +527,11 @@ public class GroundItemsPlugin extends Plugin { lastEntry.setTarget(lastEntry.getTarget() + " (" + quantity + ")"); } + + if (hidden != null && highlighted == null && config.deprioritizeHiddenItems()) + { + lastEntry.setDeprioritized(true); + } } } From fa8bc363eea3be6ad8ecf3c0f56a272fc022967e Mon Sep 17 00:00:00 2001 From: Adam Date: Wed, 12 Jan 2022 15:25:47 -0500 Subject: [PATCH 09/51] api: make ClanMember an interface --- .../src/main/java/net/runelite/api/clan/ClanMember.java | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/runelite-api/src/main/java/net/runelite/api/clan/ClanMember.java b/runelite-api/src/main/java/net/runelite/api/clan/ClanMember.java index 896939a505..dfe4151764 100644 --- a/runelite-api/src/main/java/net/runelite/api/clan/ClanMember.java +++ b/runelite-api/src/main/java/net/runelite/api/clan/ClanMember.java @@ -24,21 +24,18 @@ */ package net.runelite.api.clan; -import lombok.Value; - /** * A member of a clan. */ -@Value -public class ClanMember +public interface ClanMember { /** * The clan member's name */ - String name; + String getName(); /** * The clan member's rank */ - ClanRank rank; + ClanRank getRank(); } From 0d76c441d30dd506110292bb472493a0d41b8cc0 Mon Sep 17 00:00:00 2001 From: Adam Date: Fri, 14 Jan 2022 11:21:57 -0500 Subject: [PATCH 10/51] api: remove tileitem spawn time This was never used and has limited use --- runelite-api/src/main/java/net/runelite/api/TileItem.java | 6 ------ 1 file changed, 6 deletions(-) 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 87d820241c..8c1b08541e 100644 --- a/runelite-api/src/main/java/net/runelite/api/TileItem.java +++ b/runelite-api/src/main/java/net/runelite/api/TileItem.java @@ -36,10 +36,4 @@ public interface TileItem extends Renderable int getId(); int getQuantity(); - - /** - * Time in game ticks when the item spawned (relative to us) - * @return - */ - int getSpawnTime(); } From dbf1b3b011a03141ebc1fc3c53054d4d5ce1afe5 Mon Sep 17 00:00:00 2001 From: Adam Date: Fri, 14 Jan 2022 19:40:03 -0500 Subject: [PATCH 11/51] api: combine projectileid and graphicid --- runelite-api/pom.xml | 1 - .../main/java/net/runelite/api/GraphicID.java | 12 ++++-- .../java/net/runelite/api/Projectile.java | 2 +- .../java/net/runelite/api/ProjectileID.java | 38 ------------------- .../client/plugins/cannon/CannonPlugin.java | 4 +- .../client/plugins/zalcano/ZalcanoPlugin.java | 2 +- 6 files changed, 12 insertions(+), 47 deletions(-) delete mode 100644 runelite-api/src/main/java/net/runelite/api/ProjectileID.java diff --git a/runelite-api/pom.xml b/runelite-api/pom.xml index 9f0d692fe8..3a6481dfca 100644 --- a/runelite-api/pom.xml +++ b/runelite-api/pom.xml @@ -107,7 +107,6 @@ net/runelite/api/ObjectID.class net/runelite/api/Opcodes.class net/runelite/api/ParamID.class - net/runelite/api/ProjectileID.class net/runelite/api/ScriptID.class net/runelite/api/SettingID.class net/runelite/api/SoundEffectID.class diff --git a/runelite-api/src/main/java/net/runelite/api/GraphicID.java b/runelite-api/src/main/java/net/runelite/api/GraphicID.java index f6c6138da6..d172a7af77 100644 --- a/runelite-api/src/main/java/net/runelite/api/GraphicID.java +++ b/runelite-api/src/main/java/net/runelite/api/GraphicID.java @@ -27,9 +27,11 @@ package net.runelite.api; public final class GraphicID { public static final int WINE_MAKE = 47; + public static final int CANNONBALL = 53; public static final int SPLASH = 85; - public static final int TELEPORT = 111; public static final int GREY_BUBBLE_TELEPORT = 86; + public static final int TELEPORT = 111; + public static final int TELEKINETIC_SPELL = 143; public static final int ENTANGLE = 179; public static final int SNARE = 180; public static final int BIND = 181; @@ -39,14 +41,16 @@ public final class GraphicID public static final int ICE_BARRAGE = 369; public static final int VENGEANCE_OTHER = 725; public static final int VENGEANCE = 726; + public static final int NPC_CONTACT = 728; + public static final int POT_SHARE = 733; + public static final int BAKE_PIE = 746; public static final int BOOK_HOME_TELEPORT_1 = 800; public static final int BOOK_HOME_TELEPORT_2 = 802; public static final int BOOK_HOME_TELEPORT_3 = 803; public static final int BOOK_HOME_TELEPORT_4 = 804; public static final int STAFF_OF_THE_DEAD = 1228; public static final int FLYING_FISH = 1387; - public static final int NPC_CONTACT = 728; - public static final int POT_SHARE = 733; - public static final int BAKE_PIE = 746; + public static final int GRANITE_CANNONBALL = 1443; public static final int GRAPHICS_OBJECT_ROCKFALL = 1727; + public static final int ZALCANO_PROJECTILE_FIREBALL = 1728; } diff --git a/runelite-api/src/main/java/net/runelite/api/Projectile.java b/runelite-api/src/main/java/net/runelite/api/Projectile.java index 2f371611d3..a4b98cecfd 100644 --- a/runelite-api/src/main/java/net/runelite/api/Projectile.java +++ b/runelite-api/src/main/java/net/runelite/api/Projectile.java @@ -33,7 +33,7 @@ public interface Projectile extends Renderable * Gets the ID of the projectile. * * @return the projectile ID - * @see ProjectileID + * @see GraphicID */ int getId(); diff --git a/runelite-api/src/main/java/net/runelite/api/ProjectileID.java b/runelite-api/src/main/java/net/runelite/api/ProjectileID.java deleted file mode 100644 index 4030f92e56..0000000000 --- a/runelite-api/src/main/java/net/runelite/api/ProjectileID.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright (c) 2017, Adam - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package net.runelite.api; - -/** - * Utility class used for mapping projectile IDs. - *

- * Note: This class is not complete and may be missing mapped IDs. - */ -public final class ProjectileID -{ - public static final int CANNONBALL = 53; - public static final int GRANITE_CANNONBALL = 1443; - public static final int TELEKINETIC_SPELL = 143; - public static final int ZALCANO_PROJECTILE_FIREBALL = 1728; -} 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 bb825bb037..cc5d47324d 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 @@ -37,6 +37,8 @@ import net.runelite.api.ChatMessageType; import net.runelite.api.Client; import net.runelite.api.GameObject; import net.runelite.api.GameState; +import static net.runelite.api.GraphicID.CANNONBALL; +import static net.runelite.api.GraphicID.GRANITE_CANNONBALL; import net.runelite.api.InventoryID; import net.runelite.api.Item; import net.runelite.api.ItemContainer; @@ -46,8 +48,6 @@ import net.runelite.api.ObjectID; import static net.runelite.api.ObjectID.CANNON_BASE; import net.runelite.api.Player; import net.runelite.api.Projectile; -import static net.runelite.api.ProjectileID.CANNONBALL; -import static net.runelite.api.ProjectileID.GRANITE_CANNONBALL; import net.runelite.api.coords.LocalPoint; import net.runelite.api.coords.WorldPoint; import net.runelite.api.events.ChatMessage; diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/zalcano/ZalcanoPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/zalcano/ZalcanoPlugin.java index b529c54aef..7ce702347b 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/zalcano/ZalcanoPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/zalcano/ZalcanoPlugin.java @@ -33,6 +33,7 @@ import net.runelite.api.Client; import net.runelite.api.GameObject; import net.runelite.api.GameState; import static net.runelite.api.GraphicID.GRAPHICS_OBJECT_ROCKFALL; +import static net.runelite.api.GraphicID.ZALCANO_PROJECTILE_FIREBALL; import net.runelite.api.GraphicsObject; import net.runelite.api.Hitsplat; import net.runelite.api.NPC; @@ -40,7 +41,6 @@ import net.runelite.api.NpcID; import static net.runelite.api.NpcID.ZALCANO; import net.runelite.api.ObjectID; import net.runelite.api.Projectile; -import static net.runelite.api.ProjectileID.ZALCANO_PROJECTILE_FIREBALL; import net.runelite.api.VarPlayer; import net.runelite.api.coords.LocalPoint; import net.runelite.api.coords.WorldPoint; From a37dfd8de550e0eee39ff3c982e744f3ff79e09f Mon Sep 17 00:00:00 2001 From: Adam Date: Fri, 14 Jan 2022 16:56:12 -0500 Subject: [PATCH 12/51] api: add actor graphic height accessors --- .../src/main/java/net/runelite/api/Actor.java | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/runelite-api/src/main/java/net/runelite/api/Actor.java b/runelite-api/src/main/java/net/runelite/api/Actor.java index 3e53351626..850ff1aab7 100644 --- a/runelite-api/src/main/java/net/runelite/api/Actor.java +++ b/runelite-api/src/main/java/net/runelite/api/Actor.java @@ -268,6 +268,18 @@ public interface Actor extends Renderable */ void setGraphic(int graphic); + /** + * Get the height of the graphic/spotanim on the actor + * @return + */ + int getGraphicHeight(); + + /** + * Set the height of the graphic/spotanim on the actor + * @param height + */ + void setGraphicHeight(int height); + /** * Get the frame of the currently playing spotanim * From 28a694f69f4a68c40367f81e183c0afc4f255edd Mon Sep 17 00:00:00 2001 From: Adam Date: Fri, 14 Jan 2022 17:12:19 -0500 Subject: [PATCH 13/51] api: use deques for projectiles and graphicsobjects --- runelite-api/src/main/java/net/runelite/api/Client.java | 4 ++-- .../runelite/client/plugins/devtools/DevToolsOverlay.java | 8 ++------ 2 files changed, 4 insertions(+), 8 deletions(-) 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 af78dedce3..5bbc86cc59 100644 --- a/runelite-api/src/main/java/net/runelite/api/Client.java +++ b/runelite-api/src/main/java/net/runelite/api/Client.java @@ -1039,14 +1039,14 @@ public interface Client extends GameEngine * * @return all projectiles */ - List getProjectiles(); + Deque getProjectiles(); /** * Gets a list of all graphics objects currently drawn. * * @return all graphics objects */ - List getGraphicsObjects(); + Deque getGraphicsObjects(); /** * Creates a RuneLiteObject, which is a modified {@link GraphicsObject} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/devtools/DevToolsOverlay.java b/runelite-client/src/main/java/net/runelite/client/plugins/devtools/DevToolsOverlay.java index d7c293d0e9..4217036796 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/devtools/DevToolsOverlay.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/devtools/DevToolsOverlay.java @@ -427,9 +427,7 @@ class DevToolsOverlay extends Overlay private void renderProjectiles(Graphics2D graphics) { - List projectiles = client.getProjectiles(); - - for (Projectile projectile : projectiles) + for (Projectile projectile : client.getProjectiles()) { int projectileId = projectile.getId(); String text = "(ID: " + projectileId + ")"; @@ -446,9 +444,7 @@ class DevToolsOverlay extends Overlay private void renderGraphicsObjects(Graphics2D graphics) { - List graphicsObjects = client.getGraphicsObjects(); - - for (GraphicsObject graphicsObject : graphicsObjects) + for (GraphicsObject graphicsObject : client.getGraphicsObjects()) { LocalPoint lp = graphicsObject.getLocation(); Polygon poly = Perspective.getCanvasTilePoly(client, lp); From 07f96a6abbe828db793c7d27e0d154f7606fe9fe Mon Sep 17 00:00:00 2001 From: Adam Date: Fri, 14 Jan 2022 17:16:42 -0500 Subject: [PATCH 14/51] api: add projectile target and end cycle setter --- .../java/net/runelite/api/Projectile.java | 28 ++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) diff --git a/runelite-api/src/main/java/net/runelite/api/Projectile.java b/runelite-api/src/main/java/net/runelite/api/Projectile.java index a4b98cecfd..4a18937c7a 100644 --- a/runelite-api/src/main/java/net/runelite/api/Projectile.java +++ b/runelite-api/src/main/java/net/runelite/api/Projectile.java @@ -24,6 +24,8 @@ */ package net.runelite.api; +import net.runelite.api.coords.LocalPoint; + /** * Represents a projectile entity. (ie. cannonball, arrow) */ @@ -37,6 +39,21 @@ public interface Projectile extends Renderable */ int getId(); + /** + * Gets the actor that is targeted by this projectile. + * + * @return the target actor, or null if this projectile is an AoE attack + */ + Actor getInteracting(); + + /** + * Get the target point of the projectile. For projectiles with an actor target, + * this is updated each frame to the actor position. + * + * @return + */ + LocalPoint getTarget(); + /** * Gets the original x-axis coordinate that this projectile started from. * @@ -77,7 +94,7 @@ public interface Projectile extends Renderable * * @return the start game cycle */ - int getStartMovementCycle(); + int getStartCycle(); /** * Gets the game cycle that the projectile will reach its target at. @@ -86,6 +103,15 @@ public interface Projectile extends Renderable */ int getEndCycle(); + /** + * Sets the game cycle the projectile will reach its target at. The + * projectile automatically despawns after this time, and setting the + * end cycle to a time in the past is an effective way of removing the + * projectile. + * @param cycle + */ + void setEndCycle(int cycle); + /** * Gets the remaining game cycles until the projectile reaches its * target and despawns. From e31bfa66fec7f5adc2e69e10738297e0d1191a37 Mon Sep 17 00:00:00 2001 From: Adam Date: Fri, 14 Jan 2022 17:59:14 -0500 Subject: [PATCH 15/51] api: add GraphicsObject finished setter --- .../src/main/java/net/runelite/api/GraphicsObject.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/runelite-api/src/main/java/net/runelite/api/GraphicsObject.java b/runelite-api/src/main/java/net/runelite/api/GraphicsObject.java index da3f944bfc..73ee342777 100644 --- a/runelite-api/src/main/java/net/runelite/api/GraphicsObject.java +++ b/runelite-api/src/main/java/net/runelite/api/GraphicsObject.java @@ -72,4 +72,10 @@ public interface GraphicsObject extends Renderable * @return */ boolean finished(); + + /** + * Set if this spotanim is done animating. If finished, the spotanim will despawn next frame. + * @param finished + */ + void setFinished(boolean finished); } From 82514e0c76ac69500eacd88dcf1404a2f529ed64 Mon Sep 17 00:00:00 2001 From: Adam Date: Fri, 14 Jan 2022 18:12:23 -0500 Subject: [PATCH 16/51] api: add projectile creation api --- .../main/java/net/runelite/api/Client.java | 20 +++++++++++++++++++ .../src/main/java/net/runelite/api/Deque.java | 6 ++++++ 2 files changed, 26 insertions(+) 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 5bbc86cc59..e354a3e5d6 100644 --- a/runelite-api/src/main/java/net/runelite/api/Client.java +++ b/runelite-api/src/main/java/net/runelite/api/Client.java @@ -1034,6 +1034,26 @@ public interface Client extends GameEngine @Nullable LocalPoint getLocalDestinationLocation(); + /** + * Create a projectile. + * @param id projectile/spotanim id + * @param plane plane the projectile is on + * @param startX local x coordinate the projectile starts at + * @param startY local y coordinate the projectile starts at + * @param startZ local z coordinate the projectile starts at - includes tile height + * @param startCycle cycle the project starts + * @param endCycle cycle the projectile ends + * @param slope + * @param startHeight start height of projectile - excludes tile height + * @param endHeight end height of projectile - excludes tile height + * @param target optional actor target + * @param targetX target x - if an actor target is supplied should be the target x + * @param targetY taret y - if an actor target is supplied should be the target y + * @return the new projectile + */ + Projectile createProjectile(int id, int plane, int startX, int startY, int startZ, int startCycle, int endCycle, + int slope, int startHeight, int endHeight, @Nullable Actor target, int targetX, int targetY); + /** * Gets a list of all projectiles currently spawned. * diff --git a/runelite-api/src/main/java/net/runelite/api/Deque.java b/runelite-api/src/main/java/net/runelite/api/Deque.java index 482306b6de..e949f7e7b2 100644 --- a/runelite-api/src/main/java/net/runelite/api/Deque.java +++ b/runelite-api/src/main/java/net/runelite/api/Deque.java @@ -29,6 +29,12 @@ package net.runelite.api; */ public interface Deque extends Iterable { + /** + * Add a new element to the end of the deque + * @param t the element + */ + void addLast(T t); + /** * clear the deque */ From c57301c0d349eee321ba6b3725218d2b1189f37f Mon Sep 17 00:00:00 2001 From: Owain van Brakel Date: Sun, 16 Jan 2022 04:02:25 +0100 Subject: [PATCH 17/51] project: Mixins --- .../injectors/raw/CopyRuneLiteClasses.java | 5 +- .../runelite/mixins/RSClanSettingsMixin.java | 7 +- .../net/runelite/mixins/RSClientMixin.java | 49 ++++--- .../runelite/mixins/RSProjectileMixin.java | 15 +++ .../java/net/runelite/rs/api/RSActor.java | 8 ++ .../java/net/runelite/rs/api/RSClient.java | 7 + .../net/runelite/rs/api/RSProjectile.java | 9 +- .../runelite/rs/api/RSRuneLiteClanMember.java | 11 ++ runescape-client/src/main/java/Actor.java | 3 +- .../GrandExchangeOfferOwnWorldComparator.java | 2 +- runescape-client/src/main/java/NPC.java | 2 +- runescape-client/src/main/java/Player.java | 2 +- .../src/main/java/RuneLiteClanMember.java | 124 ++++++++++++++++++ runescape-client/src/main/java/class65.java | 2 +- 14 files changed, 214 insertions(+), 32 deletions(-) create mode 100644 runescape-api/src/main/java/net/runelite/rs/api/RSRuneLiteClanMember.java create mode 100644 runescape-client/src/main/java/RuneLiteClanMember.java diff --git a/injector/src/main/java/com/openosrs/injector/injectors/raw/CopyRuneLiteClasses.java b/injector/src/main/java/com/openosrs/injector/injectors/raw/CopyRuneLiteClasses.java index 9296d10b8f..f2b8bc85fd 100644 --- a/injector/src/main/java/com/openosrs/injector/injectors/raw/CopyRuneLiteClasses.java +++ b/injector/src/main/java/com/openosrs/injector/injectors/raw/CopyRuneLiteClasses.java @@ -35,11 +35,12 @@ import org.objectweb.asm.Opcodes; public class CopyRuneLiteClasses extends AbstractInjector { private static final List RUNELITE_OBJECTS = List.of( - "RuneLiteObject", + "RuneLiteClanMember", "RuneLiteIterableLinkDeque", "RuneLiteIterableNodeDeque", "RuneLiteIterableNodeHashTable", - "RuneLiteMenuEntry" + "RuneLiteMenuEntry", + "RuneLiteObject" ); public CopyRuneLiteClasses(InjectData inject) diff --git a/runelite-mixins/src/main/java/net/runelite/mixins/RSClanSettingsMixin.java b/runelite-mixins/src/main/java/net/runelite/mixins/RSClanSettingsMixin.java index d181dd7c91..f48bc9e341 100644 --- a/runelite-mixins/src/main/java/net/runelite/mixins/RSClanSettingsMixin.java +++ b/runelite-mixins/src/main/java/net/runelite/mixins/RSClanSettingsMixin.java @@ -47,13 +47,11 @@ public abstract class RSClanSettingsMixin implements RSClanSettings public List getMembers() { int memberCount = getMemberCount(); - String[] memberNames = getMemberNames(); - byte[] memberRanks = getMemberRanks(); List memberList = new ArrayList<>(memberCount); for (int i = 0; i < memberCount; i++) { - // memberList.add(new ClanMember(memberNames[i], client.getClanRankFromRs(memberRanks[i]))); + memberList.add((ClanMember) client.runeliteClanMember(this, i)); } return memberList; @@ -65,7 +63,6 @@ public abstract class RSClanSettingsMixin implements RSClanSettings { name = name.replace(" ", "\u00A0").toLowerCase(); String[] memberNames = getMemberNames(); - byte[] memberRanks = getMemberRanks(); int[] sorted = getSortedMembers(); int i = 0; @@ -82,7 +79,7 @@ public abstract class RSClanSettingsMixin implements RSClanSettings } else if (compare == 0) { - // return new ClanMember(memberName, client.getClanRankFromRs(memberRanks[tag])); + return (ClanMember) client.runeliteClanMember(this, memberIndex); } else { diff --git a/runelite-mixins/src/main/java/net/runelite/mixins/RSClientMixin.java b/runelite-mixins/src/main/java/net/runelite/mixins/RSClientMixin.java index 398ad47f69..ceadb07016 100644 --- a/runelite-mixins/src/main/java/net/runelite/mixins/RSClientMixin.java +++ b/runelite-mixins/src/main/java/net/runelite/mixins/RSClientMixin.java @@ -39,8 +39,10 @@ import java.util.Map; import java.util.Set; import javax.annotation.Nonnull; import javax.annotation.Nullable; +import net.runelite.api.Actor; import net.runelite.api.Animation; import net.runelite.api.ChatMessageType; +import net.runelite.api.Deque; import net.runelite.api.EnumComposition; import net.runelite.api.FriendContainer; import net.runelite.api.GameState; @@ -70,7 +72,6 @@ import net.runelite.api.Model; import net.runelite.api.NPC; import net.runelite.api.NPCComposition; import net.runelite.api.NameableContainer; -import net.runelite.api.Node; import net.runelite.api.NodeCache; import net.runelite.api.ObjectComposition; import net.runelite.api.Perspective; @@ -158,6 +159,8 @@ import net.runelite.rs.api.RSNodeDeque; import net.runelite.rs.api.RSNodeHashTable; import net.runelite.rs.api.RSPacketBuffer; import net.runelite.rs.api.RSPlayer; +import net.runelite.rs.api.RSProjectile; +import net.runelite.rs.api.RSRuneLiteClanMember; import net.runelite.rs.api.RSRuneLiteMenuEntry; import net.runelite.rs.api.RSScene; import net.runelite.rs.api.RSScriptEvent; @@ -1046,34 +1049,36 @@ public abstract class RSClientMixin implements RSClient @Inject @Override - public List getProjectiles() + public Projectile createProjectile(int id, int plane, int startX, int startY, int startZ, int startCycle, int endCycle, int slope, int startHeight, int endHeight, Actor target, int targetX, int targetY) { - List projectiles = new ArrayList(); - RSNodeDeque projectileDeque = this.getProjectilesDeque(); - Node head = projectileDeque.getSentinel(); - - for (Node node = head.getNext(); node != head; node = node.getNext()) + int targetIndex = 0; + if (target instanceof NPC) { - projectiles.add((Projectile) node); + targetIndex = ((NPC)target).getIndex() + 1; + } + else if (target instanceof Player) + { + targetIndex = -(((Player)target).getPlayerId() + 1); } - return projectiles; + RSProjectile projectile = client.newProjectile(id, plane, startX, startY, startZ, startCycle, endCycle, slope, startHeight, targetIndex, endHeight); + projectile.setDestination(targetX, targetY, Perspective.getTileHeight(client, new LocalPoint(targetX, targetY), client.getPlane()), startCycle + client.getGameCycle()); + + return projectile; } @Inject @Override - public List getGraphicsObjects() + public Deque getProjectiles() { - List graphicsObjects = new ArrayList(); - RSNodeDeque graphicsObjectDeque = this.getGraphicsObjectDeque(); - Node head = graphicsObjectDeque.getSentinel(); + return this.getProjectilesDeque(); + } - for (Node node = head.getNext(); node != head; node = node.getNext()) - { - graphicsObjects.add((GraphicsObject) node); - } - - return graphicsObjects; + @Inject + @Override + public Deque getGraphicsObjects() + { + return this.getGraphicsObjectDeque(); } @Inject @@ -1448,6 +1453,12 @@ public abstract class RSClientMixin implements RSClient } } + @Inject + public static RSRuneLiteClanMember runeLiteClanMember() + { + throw new NotImplementedException(); + } + @FieldHook("friendsChat") @Inject public static void clanMemberManagerChanged(int idx) diff --git a/runelite-mixins/src/main/java/net/runelite/mixins/RSProjectileMixin.java b/runelite-mixins/src/main/java/net/runelite/mixins/RSProjectileMixin.java index e33cea8d1f..a802784762 100644 --- a/runelite-mixins/src/main/java/net/runelite/mixins/RSProjectileMixin.java +++ b/runelite-mixins/src/main/java/net/runelite/mixins/RSProjectileMixin.java @@ -43,6 +43,12 @@ public abstract class RSProjectileMixin implements RSProjectile @Shadow("client") private static RSClient client; + @Inject + private int targetX; + + @Inject + private int targetY; + @Inject RSProjectileMixin() { @@ -90,6 +96,13 @@ public abstract class RSProjectileMixin implements RSProjectile } } + @Inject + @Override + public LocalPoint getTarget() + { + return new LocalPoint(this.targetX, this.targetY); + } + /** * Called when a projectile is set to move towards a point. For * projectiles that target the ground, like AoE projectiles from @@ -104,6 +117,8 @@ public abstract class RSProjectileMixin implements RSProjectile @MethodHook("setDestination") public void projectileMoved(int targetX, int targetY, int targetZ, int cycle) { + this.targetX = targetX; + this.targetY = targetY; final LocalPoint position = new LocalPoint(targetX, targetY); final ProjectileMoved projectileMoved = new ProjectileMoved(); projectileMoved.setProjectile(this); diff --git a/runescape-api/src/main/java/net/runelite/rs/api/RSActor.java b/runescape-api/src/main/java/net/runelite/rs/api/RSActor.java index 925b3ae6c1..dfa62b8662 100644 --- a/runescape-api/src/main/java/net/runelite/rs/api/RSActor.java +++ b/runescape-api/src/main/java/net/runelite/rs/api/RSActor.java @@ -98,6 +98,14 @@ public interface RSActor extends RSRenderable, Actor @Override void setGraphic(int id); + @Import("spotAnimationHeight") + @Override + int getGraphicHeight(); + + @Import("spotAnimationHeight") + @Override + void setGraphicHeight(int id); + @Import("spotAnimationFrame") int getSpotAnimFrame(); diff --git a/runescape-api/src/main/java/net/runelite/rs/api/RSClient.java b/runescape-api/src/main/java/net/runelite/rs/api/RSClient.java index 12a87220d3..1e662044d5 100644 --- a/runescape-api/src/main/java/net/runelite/rs/api/RSClient.java +++ b/runescape-api/src/main/java/net/runelite/rs/api/RSClient.java @@ -32,6 +32,7 @@ import net.runelite.api.Deque; import net.runelite.api.SpritePixels; import net.runelite.api.World; import net.runelite.api.clan.ClanRank; +import net.runelite.api.clan.ClanSettings; import net.runelite.api.widgets.Widget; import net.runelite.mapping.Construct; import net.runelite.mapping.Import; @@ -1562,4 +1563,10 @@ public interface RSClient extends RSGameEngine, Client @Construct RSIterableNodeHashTable createIterableNodeHashTable(int size); + + @Construct + RSRuneLiteClanMember runeliteClanMember(ClanSettings var1, int var2); + + @Construct + RSProjectile newProjectile(int var1, int var2, int var3, int var4, int var5, int var6, int var7, int var8, int var9, int var10, int var11); } diff --git a/runescape-api/src/main/java/net/runelite/rs/api/RSProjectile.java b/runescape-api/src/main/java/net/runelite/rs/api/RSProjectile.java index 5f6283632c..d1c3f4aa72 100644 --- a/runescape-api/src/main/java/net/runelite/rs/api/RSProjectile.java +++ b/runescape-api/src/main/java/net/runelite/rs/api/RSProjectile.java @@ -62,12 +62,16 @@ public interface RSProjectile extends RSRenderable, Projectile @Import("cycleStart") @Override - int getStartMovementCycle(); + int getStartCycle(); @Import("cycleEnd") @Override int getEndCycle(); + @Import("cycleEnd") + @Override + void setEndCycle(int cycle); + @Import("slope") @Override int getSlope(); @@ -103,4 +107,7 @@ public interface RSProjectile extends RSRenderable, Projectile @Import("speedZ") @Override double getVelocityZ(); + + @Import("setDestination") + void setDestination(int targetX, int targetY, int targetZ, int cycle); } diff --git a/runescape-api/src/main/java/net/runelite/rs/api/RSRuneLiteClanMember.java b/runescape-api/src/main/java/net/runelite/rs/api/RSRuneLiteClanMember.java new file mode 100644 index 0000000000..1da0b11561 --- /dev/null +++ b/runescape-api/src/main/java/net/runelite/rs/api/RSRuneLiteClanMember.java @@ -0,0 +1,11 @@ +package net.runelite.rs.api; + +import net.runelite.api.MenuEntry; +import net.runelite.api.clan.ClanRank; + +public interface RSRuneLiteClanMember extends MenuEntry +{ + ClanRank getRank(); + + String getName(); +} diff --git a/runescape-client/src/main/java/Actor.java b/runescape-client/src/main/java/Actor.java index b007374c5e..3ca6f70d55 100644 --- a/runescape-client/src/main/java/Actor.java +++ b/runescape-client/src/main/java/Actor.java @@ -233,7 +233,8 @@ public abstract class Actor extends Renderable { @ObfuscatedGetter( intValue = -2034554825 ) - int field1131; + @Export("spotAnimationHeight") + int spotAnimationHeight; @ObfuscatedName("bo") @ObfuscatedGetter( intValue = -873586319 diff --git a/runescape-client/src/main/java/GrandExchangeOfferOwnWorldComparator.java b/runescape-client/src/main/java/GrandExchangeOfferOwnWorldComparator.java index a6bc2953d1..86e4f4fe6e 100644 --- a/runescape-client/src/main/java/GrandExchangeOfferOwnWorldComparator.java +++ b/runescape-client/src/main/java/GrandExchangeOfferOwnWorldComparator.java @@ -358,7 +358,7 @@ public class GrandExchangeOfferOwnWorldComparator implements Comparator { if ((var5 & 2) != 0) { var15.spotAnimation = var1.method7403(); var6 = var1.method7412(); - var15.field1131 = var6 >> 16; + var15.spotAnimationHeight = var6 >> 16; var15.field1130 = (var6 & 65535) + Client.cycle; var15.spotAnimationFrame = 0; var15.spotAnimationFrameCycle = 0; diff --git a/runescape-client/src/main/java/NPC.java b/runescape-client/src/main/java/NPC.java index 54bc07a1b2..bc80ef444f 100644 --- a/runescape-client/src/main/java/NPC.java +++ b/runescape-client/src/main/java/NPC.java @@ -118,7 +118,7 @@ public final class NPC extends Actor { if (super.spotAnimation != -1 && super.spotAnimationFrame != -1) { Model var4 = AccessFile.SpotAnimationDefinition_get(super.spotAnimation).getModel(super.spotAnimationFrame); if (var4 != null) { - var4.offsetBy(0, -super.field1131, 0); + var4.offsetBy(0, -super.spotAnimationHeight, 0); Model[] var5 = new Model[]{var3, var4}; var3 = new Model(var5, 2); } diff --git a/runescape-client/src/main/java/Player.java b/runescape-client/src/main/java/Player.java index b0e15a332a..0da892fe7a 100644 --- a/runescape-client/src/main/java/Player.java +++ b/runescape-client/src/main/java/Player.java @@ -337,7 +337,7 @@ public final class Player extends Actor { if (!this.isUnanimated && super.spotAnimation != -1 && super.spotAnimationFrame != -1) { var4 = AccessFile.SpotAnimationDefinition_get(super.spotAnimation).getModel(super.spotAnimationFrame); if (var4 != null) { - var4.offsetBy(0, -super.field1131, 0); + var4.offsetBy(0, -super.spotAnimationHeight, 0); var5 = new Model[]{var3, var4}; var3 = new Model(var5, 2); } diff --git a/runescape-client/src/main/java/RuneLiteClanMember.java b/runescape-client/src/main/java/RuneLiteClanMember.java new file mode 100644 index 0000000000..6e4d758a3d --- /dev/null +++ b/runescape-client/src/main/java/RuneLiteClanMember.java @@ -0,0 +1,124 @@ +import net.runelite.api.clan.ClanMember; +import net.runelite.api.clan.ClanRank; + +public class RuneLiteClanMember implements ClanMember +{ + public final int idx; + public final ClanSettings clanSettings; + + public RuneLiteClanMember(ClanSettings clanSettings, int idx) { + this.clanSettings = clanSettings; + this.idx = idx; + } + + public ClanRank getRank() { + return getClanRank(this.clanSettings.memberRanks[this.idx]); + } + + public String getName() { + return this.clanSettings.memberNames[this.idx]; + } + + public ClanRank getClanRank(int rank) + { + switch (rank) + { + case -1: + return ClanRank.GUEST; + case 10: + return ClanRank.CLAN_RANK_2; + case 20: + return ClanRank.CLAN_RANK_3; + case 30: + return ClanRank.CLAN_RANK_4; + case 40: + return ClanRank.CLAN_RANK_5; + case 50: + return ClanRank.CLAN_RANK_6; + case 60: + return ClanRank.CLAN_RANK_7; + case 70: + return ClanRank.CLAN_RANK_8; + case 80: + return ClanRank.CLAN_RANK_9; + case 90: + return ClanRank.CLAN_RANK_10; + case 100: + return ClanRank.ADMINISTRATOR; + case 105: + return ClanRank.CLAN_RANK_11; + case 110: + return ClanRank.CLAN_RANK_12; + case 115: + return ClanRank.CLAN_RANK_13; + case 120: + return ClanRank.CLAN_RANK_14; + case 125: + return ClanRank.DEPUTY_OWNER; + case 126: + return ClanRank.OWNER; + case 127: + return ClanRank.JMOD; + default: + return ClanRank.CLAN_RANK_1; + } + } + + public boolean instanceOf(Object o) { + return o instanceof RuneLiteClanMember; + } + + @Override + public boolean equals(Object o) { + if (o == this) { + return true; + } else if (!(o instanceof RuneLiteClanMember)) { + return false; + } else { + RuneLiteClanMember clanMember = (RuneLiteClanMember)o; + if (!clanMember.instanceOf(this)) { + return false; + } else { + String thisName = this.getName(); + String objName = clanMember.getName(); + + if (thisName == null) { + if (objName != null) { + return false; + } + } else if (!thisName.equals(objName)) { + return false; + } + + ClanRank thisRank = this.getRank(); + ClanRank objRank = clanMember.getRank(); + + if (thisRank == null) { + if (objRank != null) { + return false; + } + } else if (!thisRank.equals(objRank)) { + return false; + } + + return true; + } + } + } + + @Override + public int hashCode() { + byte b = 1; + + String name = this.getName(); + int hash = b * 59 + (name == null ? 43 : name.hashCode()); + ClanRank rank = this.getRank(); + hash = hash * 59 + (rank == null ? 43 : rank.hashCode()); + + return hash; + } + + public String toString() { + return "ClanMemberImpl(getName=" + this.getName() + ", getRank=" + this.getRank() + ")"; + } +} diff --git a/runescape-client/src/main/java/class65.java b/runescape-client/src/main/java/class65.java index 54b360adc0..9df06b3019 100644 --- a/runescape-client/src/main/java/class65.java +++ b/runescape-client/src/main/java/class65.java @@ -180,7 +180,7 @@ public class class65 { if ((var3 & 2048) != 0) { var2.spotAnimation = var0.method7499(); var5 = var0.method7412(); - var2.field1131 = var5 >> 16; + var2.spotAnimationHeight = var5 >> 16; var2.field1130 = (var5 & 65535) + Client.cycle; var2.spotAnimationFrame = 0; var2.spotAnimationFrameCycle = 0; From 82d190884ca74239df9e95031cf050c24b7b6132 Mon Sep 17 00:00:00 2001 From: Wayne Li Date: Thu, 6 Jan 2022 00:42:32 -0800 Subject: [PATCH 18/51] clue: Refactor Anagrams into builder model --- .../cluescrolls/clues/AnagramClue.java | 860 +++++++++++++++--- 1 file changed, 733 insertions(+), 127 deletions(-) diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/clues/AnagramClue.java b/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/clues/AnagramClue.java index 286d9b6f4a..5592d08141 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/clues/AnagramClue.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/clues/AnagramClue.java @@ -24,11 +24,12 @@ */ package net.runelite.client.plugins.cluescrolls.clues; -import com.google.common.collect.ImmutableSet; +import com.google.common.collect.ImmutableList; import java.awt.Color; import java.awt.Graphics2D; -import java.util.Set; +import java.util.List; import javax.annotation.Nullable; +import lombok.Builder; import lombok.Getter; import net.runelite.api.NPC; import net.runelite.api.ObjectID; @@ -46,111 +47,737 @@ import net.runelite.client.ui.overlay.components.PanelComponent; import net.runelite.client.ui.overlay.components.TitleComponent; @Getter +@Builder public class AnagramClue extends ClueScroll implements TextClueScroll, NpcClueScroll, ObjectClueScroll { private static final String ANAGRAM_TEXT = "This anagram reveals who to speak to next: "; private static final String ANAGRAM_TEXT_BEGINNER = "The anagram reveals who to speak to next: "; - private static final Set CLUES = ImmutableSet.of( - new AnagramClue("A BAKER", "Baraek", new WorldPoint(3217, 3434, 0), "Varrock square", "How many stalls are there in Varrock Square?", "5"), - new AnagramClue("A BASIC ANTI POT", "Captain Tobias", new WorldPoint(3026, 3216, 0), "Port Sarim docks", "How many ships are there docked at Port Sarim currently?", "6"), - new AnagramClue("A ELF KNOWS", "Snowflake", new WorldPoint(2872, 3934, 0), "Weiss"), - new AnagramClue("A HEART", "Aretha", new WorldPoint(1814, 3851, 0), "Soul altar", "32 - 5x = 22, what is x?", "2"), - new AnagramClue("AHA JAR", "Jaraah", new WorldPoint(3359, 3276, 0), "Duel Arena hospital"), - new AnagramClue("ARC O LINE", "Caroline", new WorldPoint(2715, 3302, 0), "North of Witchaven, near row boat", "How many fishermen are there on the fishing platform?", "11"), - new AnagramClue("ARE COL", "Oracle", new WorldPoint(3013, 3501, 0), "Ice Mountain", "If x is 15 and y is 3 what is 3x + y?", "48"), - new AnagramClue("ARMCHAIR THE PELT", "Charlie the Tramp", new WorldPoint(3209, 3392, 0), "Varrock south entrance", "How many coins would I have if I have 0 coins and attempt to buy 10 loaves of bread for 3 coins each?", "0"), - new AnagramClue("AT HERG", "Regath", new WorldPoint(1719, 3723, 0), "Arceuus general store", "What is -5 to the power of 2?", "25"), - new AnagramClue("A BAS", "Saba", new WorldPoint(2858, 3577, 0), "Death Plateau cave, north of the Warriors' Guild"), - new AnagramClue("AREA CHEF TREK", "Father Aereck", new WorldPoint(3243, 3208, 0), "Lumbridge Church", "How many gravestones are in the church graveyard?", "19 or 20"), - new AnagramClue("BAIL TRIMS", "Brimstail", new WorldPoint(2402, 3419, 0), "West of Stronghold Slayer Cave"), - new AnagramClue("BAKER CLIMB", "Brambickle", new WorldPoint(2783, 3861, 0), "Trollweiss mountain"), - new AnagramClue("BLUE GRIM GUIDED", "Lumbridge Guide", new WorldPoint(3238, 3220, 0), "Lumbridge"), - new AnagramClue("BY LOOK", "Bolkoy", new WorldPoint(2529, 3162, 0), "Tree Gnome Village general store", "How many flowers are there in the clearing below this platform?", "13"), - new AnagramClue("CALAMARI MADE MUD", "Madame Caldarium", new WorldPoint(2553, 2868, 0), "Corsair Cove", "What is 3(5-3)?", "6"), - new AnagramClue("CAR IF ICES", "Sacrifice", new WorldPoint(2209, 3056, 0), "Zul-Andra"), - new AnagramClue("CAREER IN MOON", "Oneiromancer", new WorldPoint(2150, 3866, 0), "Astral altar", "How many Suqah inhabit Lunar isle?", "25"), - new AnagramClue("CLASH ION", "Nicholas", new WorldPoint(1841, 3803, 0), "North of Port Piscarilius fishing shop", "How many windows are in Tynan's shop?", "4"), - new AnagramClue("C ON GAME HOC", "Gnome Coach", new WorldPoint(2395, 3486, 0), "Circling the Gnome Ball course", "How many gnomes on the Gnome ball field have red patches on their uniforms?", "6"), - new AnagramClue("COOL NERD", "Old crone", new WorldPoint(3462, 3557, 0), "East of the Slayer Tower", "What is the combined combat level of each species that live in Slayer tower?", "619"), - new AnagramClue("COPPER ORE CRYPTS", "Prospector Percy", new WorldPoint(3061, 3377, 0), "Motherlode Mine", "During a party, everyone shook hands with everybody else. There were 66 handshakes. How many people were at the party?", "12"), - new AnagramClue("DARN DRAKE", "Daer Krand", new WorldPoint(3728, 3302, 0), "Sisterhood Sanctuary, northeast of the Nightmare Arena"), - new AnagramClue("DED WAR", "Edward", new WorldPoint(3284, 3943, 0), "Around or within Rogues' Castle"), - new AnagramClue("DEKAGRAM", "Dark mage", new WorldPoint(3039, 4835, 0), "Centre of the Abyss", "How many rifts are found here in the abyss?", "13"), - new AnagramClue("DO SAY MORE", "Doomsayer", new WorldPoint(3230, 3230, 0), "East of Lumbridge Castle", "What is 40 divided by 1/2 plus 15?", "95"), - new AnagramClue("DIM THARN", "Mandrith", new WorldPoint(3182, 3946, 0), "Wilderness Resource Area"), - new AnagramClue("DR HITMAN", "Mandrith", new WorldPoint(3182, 3946, 0), "Wilderness Resource Area", "How many scorpions live under the pit?", "28"), - new AnagramClue("DR WARDEN FUNK", "Drunken Dwarf", new WorldPoint(2913, 10221, 0), "East Keldagrim"), - new AnagramClue("DRAGONS LAMENT", "Strange Old Man", new WorldPoint(3564, 3288, 0), "Barrows", "One pipe fills a barrel in 1 hour while another pipe can fill the same barrel in 2 hours. How many minutes will it take to fill the tank if both pipes are used?", "40"), - new AnagramClue("DT RUN B", "Brundt the Chieftain", new WorldPoint(2658, 3670, 0), "Rellekka main hall", "How many people are waiting for the next bard to perform?", "4"), - new AnagramClue("DUO PLUG", "Dugopul", new WorldPoint(2803, 2744, 0), "Ape Atoll graveyard"), - new AnagramClue("EEK ZERO OP", "Zoo keeper", new WorldPoint(2613, 3269, 0), "Ardougne Zoo", "How many animals in total are there in the zoo?", "40"), - new AnagramClue("EL OW", "Lowe", new WorldPoint(3233, 3423, 0), "Varrock archery store"), - new AnagramClue("FORLUN", "Runolf", new WorldPoint(2512, 10256, 0), "Miscellania Dungeon"), - new AnagramClue("GOBLIN KERN", "King Bolren", new WorldPoint(2541, 3170, 0), "Tree Gnome Village"), - new AnagramClue("GOT A BOY", "Gabooty", new WorldPoint(2790, 3066, 0), "Tai Bwo Wannai", "How many buildings are in the village?", "11"), - new AnagramClue("GOBLETS ODD TOES", "Otto Godblessed", new WorldPoint(2501, 3487, 0), "Otto's Grotto", "How many types of dragon are there beneath the whirlpool's cavern?", "2"), - new AnagramClue("HALT US", "Luthas", new WorldPoint(2938, 3152, 0), "Banana plantation, Karamja"), - new AnagramClue("HEORIC", "Eohric", new WorldPoint(2900, 3565, 0), "Burthorpe Castle, top floor", "King Arthur and Merlin sit down at the Round Table with 8 knights. How many degrees does each get?", "36"), - new AnagramClue("HIS PHOR", "Horphis", new WorldPoint(1639, 3812, 0), "Arceuus Library", "On a scale of 1-10, how helpful is Logosia?", "1"), - new AnagramClue("I AM SIR", "Marisi", new WorldPoint(1737, 3557, 0), "Hosidius allotment patch", "How many cities form the Kingdom of Great Kourend?", "5"), - new AnagramClue("ICY FE", "Fycie", new WorldPoint(2630, 2997, 0), "East Feldip Hills"), - new AnagramClue("I DOOM ICON INN", "Dominic Onion", new WorldPoint(2609, 3116, 0), "Nightmare Zone", "How many reward points does a herb box cost?", "9,500"), - new AnagramClue("I EVEN", "Nieve", new WorldPoint(2432, 3422, 0), "Gnome Stronghold, outside the Stronghold Slayer Cave", "How many farming patches are there in Gnome stronghold?", "2"), - new AnagramClue("IM N ZEZIM", "Immenizz", new WorldPoint(2592, 4324, 0), "Puro-Puro"), - new AnagramClue("KAY SIR", "Sir Kay", new WorldPoint(2760, 3496, 0), "Camelot Castle courtyard", "How many fountains are there within the grounds of Camelot castle?", "6"), - new AnagramClue("LEAKEY", "Kaylee", new WorldPoint(2957, 3370, 0), "Falador pub", "How many chairs are there in the Rising Sun?", "18"), - new AnagramClue("LARK IN DOG", "King Roald", new WorldPoint(3220, 3476, 0), "Varrock Castle, ground floor", "How many bookcases are there in the palace library?", "24"), - new AnagramClue("LOW LAG", "Gallow", new WorldPoint(1805, 3566, 0), "Hosidius vinery", "How many vine patches can you find in this vinery?", "12"), - new AnagramClue("LADDER MEMO GUV", "Guard Vemmeldo", new WorldPoint(2447, 3418, 1), "Gnome Stronghold Bank", "How many magic trees can you find inside the Gnome Stronghold?", "3"), - new AnagramClue("MAL IN TAU", "Luminata", new WorldPoint(3508, 3237, 0), "Burgh de Rott, near general store"), - new AnagramClue("MACHETE CLAM", "Cam the Camel", new WorldPoint(3300, 3231, 0), "West of the Duel Arena entrance", "How many items can carry water in Gielinor?", "6"), - new AnagramClue("ME IF", "Femi", new WorldPoint(2461, 3382, 0), "Tree Gnome Stronghold entrance"), - new AnagramClue("MOLD LA RAN", "Old Man Ral", new WorldPoint(3602, 3209, 0), "Meiyerditch"), - new AnagramClue("MOTHERBOARD", "Brother Omad", new WorldPoint(2606, 3211, 0), "Ardougne Monastery", "What is the next number? 12, 13, 15, 17, 111, 113, 117, 119, 123....?", "129"), - new AnagramClue("MUS KIL READER", "Radimus Erkle", new WorldPoint(2726, 3368, 0), "Legends' Guild"), - new AnagramClue("MY MANGLE LAL", "Lammy Langle", new WorldPoint(1688, 3540, 0), "Hosidius spirit tree patch"), - new AnagramClue("NO OWNER", "Oronwen", new WorldPoint(1162, 3178, 0), "Lletya seamstress shop", "What is the minimum amount of quest points required to reach Lletya?", "20"), - new AnagramClue("NOD MED", "Edmond", new WorldPoint(2566, 3332, 0), "East Ardougne, north-west house", "How many pigeon cages are there around the back of Jerico's house?", "3"), - new AnagramClue("O BIRDZ A ZANY EN PC", "Cap'n Izzy No-Beard", new WorldPoint(2807, 3191, 0), "Brimhaven Agility Arena", "How many Banana Trees are there in the plantation?", "33"), - new AnagramClue("OK CO", "Cook", new WorldPoint(3207, 3214, 0), "Lumbridge Castle, ground floor", "How many cannons does Lumbridge Castle have?", "9"), - new AnagramClue("OUR OWN NEEDS", "Nurse Wooned", new WorldPoint(1511, 3619, 0), "Shayzien Infirmary", "How many wounded soldiers are there in the camp?", "16"), - new AnagramClue("PACINNG A TAIE", "Captain Ginea", new WorldPoint(1504, 3632, 0), "East of the Shayzien Encampment war tent", "1 soldier can deal with 6 lizardmen. How many soldiers do we need for an army of 678 lizardmen?", "113"), - new AnagramClue("PEAK REFLEX", "Flax keeper", new WorldPoint(2744, 3444, 0), "Seers' Village flax field", "If I have 1014 flax, and I spin a third of them into bowstring, how many flax do I have left?", "676"), - new AnagramClue("PEATY PERT", "Party Pete", new WorldPoint(3047, 3376, 0), "Falador Party Room"), - new AnagramClue("QUIT HORRIBLE TYRANT", "Brother Tranquility", new WorldPoint(3681, 2963, 0), "Mos Le'Harmless or Harmony Island", "If I have 49 bottles of rum to share between 7 pirates, how many would each pirate get?", "7"), - new AnagramClue("QUE SIR", "Squire", new WorldPoint(2975, 3343, 0), "Falador Castle courtyard", "White knights are superior to black knights. 2 white knights can handle 3 black knights. How many knights do we need for an army of 981 black knights?", "654"), - new AnagramClue("R AK MI", "Karim", new WorldPoint(3273, 3181, 0), "Al Kharid kebab shop", "I have 16 kebabs, I eat one myself and then share the rest equally between 3 friends. How many do they have each?", "5"), - new AnagramClue("RAT MAT WITHIN", "Martin Thwait", new WorldPoint(2906, 3537, 0), "Rogues' Den", "How many natural fires burn in Rogue's Den?", "2"), - new AnagramClue("RATAI", "Taria", new WorldPoint(2940, 3223, 0), "Rimmington bush patch", "How many buildings are there in Rimmington?", "7"), - new AnagramClue("R SLICER", "Clerris", new WorldPoint(1761, 3850, 0), "Arceuus mine", "If I have 1,000 blood runes, and cast 131 ice barrage spells, how many blood runes do I have left?", "738"), - new AnagramClue("RIP MAUL", "Primula", new WorldPoint(2454, 2853, 1), "Myths' Guild, first floor"), - new AnagramClue("SAND NUT", "Dunstan", new WorldPoint(2919, 3574, 0), "Anvil, north-east Burthorpe", "How much smithing experience does one receive for smelting a blurite bar?", "8"), - new AnagramClue("SLAM DUSTER GRAIL", "Guildmaster Lars", new WorldPoint(1649, 3498, 0), "Woodcutting Guild, Hosidius"), - new AnagramClue("SLIDE WOMAN", "Wise Old Man", new WorldPoint(3088, 3253, 0), "Draynor Village", "How many bookcases are in the Wise Old Man's house?", "28"), - new AnagramClue("SNAKES SO I SAIL", "Lisse Isaakson", new WorldPoint(2351, 3801, 0), "Neitiznot", "How many arctic logs are required to make a large fremennik round shield?", "2"), - new AnagramClue("TAMED ROCKS", "Dockmaster", new WorldPoint(1822, 3739, 0), "Port Piscarilius, NE of General store", "What is the cube root of 125?", "5"), - new AnagramClue("TEN WIGS ON", "Wingstone", new WorldPoint(3389, 2877, 0), "North of Agility Pyramid"), - new AnagramClue("THICKNO", "Hickton", new WorldPoint(2822, 3442, 0), "Catherby ranging shop", "How many ranges are there in Catherby?", "2"), - new AnagramClue("TWENTY CURE IRON", "New Recruit Tony", new WorldPoint(1503, 3553, 0), "Shayzien Graveyard"), - new AnagramClue("UNLEASH NIGHT MIST", "Sigli the Huntsman", new WorldPoint(2660, 3654, 0), "Rellekka entrance", "What is the combined slayer requirement of every monster in the slayer cave?", "302"), - new AnagramClue("VESTE", "Steve", new WorldPoint(2432, 3423, 0), "Upstairs Skeletal Wyvern area or Stronghold Slayer Cave (after Monkey Madness 2)", "How many farming patches are there in Gnome stronghold?", "2"), - new AnagramClue("VEIL VEDA", "Evil Dave", new WorldPoint(3079, 9892, 0), "Doris' basement, Edgeville", "What is 333 multiplied by 2?", "666"), - new AnagramClue("WOO AN EGG KIWI", "Awowogei", ObjectID.AWOWOGEI, new WorldPoint(2802, 2765, 0), "Ape Atoll", "If I have 303 bananas, and share them between 31 friends evenly, only handing out full bananas. How many will I have left over?", "24"), - new AnagramClue("MAJORS LAVA BADS AIR", "Ambassador Alvijar", new WorldPoint(2736, 5351, 1), "Dorgesh-Kaan, NE Middle Level", "Double the miles before the initial Dorgeshuun veteran.", "2505"), - new AnagramClue("AN EARL", "Ranael", new WorldPoint(3315, 3163, 0), "Al Kharid skirt shop"), - new AnagramClue("CARPET AHOY", "Apothecary", new WorldPoint(3195, 3404, 0), "Southwest Varrock"), - new AnagramClue("DISORDER", "Sedridor", new WorldPoint(3102, 9570, 0), "Wizards' Tower basement"), - new AnagramClue("I CORD", "Doric", new WorldPoint(2951, 3450, 0), "Doric's house, north of Falador"), - new AnagramClue("IN BAR", "Brian", new WorldPoint(3026, 3246, 0), "Port Sarim battleaxe shop"), - new AnagramClue("RAIN COVE", "Veronica", new WorldPoint(3110, 3330, 0), "Outside Draynor Manor"), - new AnagramClue("RUG DETER", "Gertrude", new WorldPoint(3151, 3412, 0), "Gertrude's house, west of Varrock"), - new AnagramClue("SIR SHARE RED", "Hairdresser", new WorldPoint(2944, 3381, 0), "Falador hairdresser"), - new AnagramClue("TAUNT ROOF", "Fortunato", new WorldPoint(3080, 3250, 0), "Draynor Village market"), - new AnagramClue("HICK JET", "Jethick", new WorldPoint(2541, 3305, 0), "West Ardougne town square", "How many graves are there in the city graveyard?", "38"), - new AnagramClue("RUE GO", "Goreu", new WorldPoint(2335, 3162, 0), "Lletya"), - new AnagramClue("BRUCIE CATNAP", "Captain Bruce", new WorldPoint(1520, 3558, 0), "Shayzien"), - new AnagramClue("UESNKRL NRIEDDO", "Drunken soldier", new WorldPoint(1551, 3565, 0), "Shayzien pub", "If 13 Shayzien Soldiers kill 46 Lizardmen each in a day, how many Lizardmen have they killed in total in a single day?", "598") + private static final List CLUES = ImmutableList.of( + // Beginner + AnagramClue.builder() + .text("AN EARL") + .npc("Ranael") + .location(new WorldPoint(3315, 3163, 0)) + .area("Al Kharid skirt shop") + .build(), + AnagramClue.builder() + .text("CARPET AHOY") + .npc("Apothecary") + .location(new WorldPoint(3195, 3404, 0)) + .area("Southwest Varrock") + .build(), + AnagramClue.builder() + .text("DISORDER") + .npc("Sedridor") + .location(new WorldPoint(3102, 9570, 0)) + .area("Wizards' Tower basement") + .build(), + AnagramClue.builder() + .text("I CORD") + .npc("Doric") + .location(new WorldPoint(2951, 3450, 0)) + .area("Doric's house, north of Falador") + .build(), + AnagramClue.builder() + .text("IN BAR") + .npc("Brian") + .location(new WorldPoint(3026, 3246, 0)) + .area("Port Sarim battleaxe shop") + .build(), + AnagramClue.builder() + .text("RAIN COVE") + .npc("Veronica") + .location(new WorldPoint(3110, 3330, 0)) + .area("Outside Draynor Manor") + .build(), + AnagramClue.builder() + .text("RUG DETER") + .npc("Gertrude") + .location(new WorldPoint(3151, 3412, 0)) + .area("Gertrude's house, west of Varrock") + .build(), + AnagramClue.builder() + .text("SIR SHARE RED") + .npc("Hairdresser") + .location(new WorldPoint(2944, 3381, 0)) + .area("Falador hairdresser") + .build(), + AnagramClue.builder() + .text("TAUNT ROOF") + .npc("Fortunato") + .location(new WorldPoint(3080, 3250, 0)) + .area("Draynor Village market") + .build(), + + // Medium + AnagramClue.builder() + .text("A BAKER") + .npc("Baraek") + .location(new WorldPoint(3217, 3434, 0)) + .area("Varrock square") + .question("How many stalls are there in Varrock Square?") + .answer("5") + .build(), + AnagramClue.builder() + .text("A BAS") + .npc("Saba") + .location(new WorldPoint(2858, 3577, 0)) + .area("Death Plateau cave, north of the Warriors' Guild") + .build(), + AnagramClue.builder() + .text("A BASIC ANTI POT") + .npc("Captain Tobias") + .location(new WorldPoint(3026, 3216, 0)) + .area("Port Sarim docks") + .question("How many ships are there docked at Port Sarim currently?") + .answer("6") + .build(), + AnagramClue.builder() + .text("AHA JAR") + .npc("Jaraah") + .location(new WorldPoint(3359, 3276, 0)) + .area("Duel Arena hospital") + .build(), + AnagramClue.builder() + .text("A HEART") + .npc("Aretha") + .location(new WorldPoint(1814, 3851, 0)) + .area("Soul altar") + .question("32 - 5x = 22, what is x?") + .answer("2") + .build(), + AnagramClue.builder() + .text("ARC O LINE") + .npc("Caroline") + .location(new WorldPoint(2715, 3302, 0)) + .area("North of Witchaven, near row boat") + .question("How many fishermen are there on the fishing platform?") + .answer("11") + .build(), + AnagramClue.builder() + .text("AREA CHEF TREK") + .npc("Father Aereck") + .location(new WorldPoint(3243, 3208, 0)) + .area("Lumbridge Church") + .question("How many gravestones are in the church graveyard?") + .answer("19 or 20") + .build(), + AnagramClue.builder() + .text("ARE COL") + .npc("Oracle") + .location(new WorldPoint(3013, 3501, 0)) + .area("Ice Mountain") + .question("If x is 15 and y is 3 what is 3x + y?") + .answer("48") + .build(), + AnagramClue.builder() + .text("ARMCHAIR THE PELT") + .npc("Charlie the Tramp") + .location(new WorldPoint(3209, 3392, 0)) + .area("Varrock south entrance") + .question("How many coins would I have if I have 0 coins and attempt to buy 10 loaves of bread for 3 coins each?") + .answer("0") + .build(), + AnagramClue.builder() + .text("BAIL TRIMS") + .npc("Brimstail") + .location(new WorldPoint(2402, 3419, 0)) + .area("West of Stronghold Slayer Cave") + .build(), + AnagramClue.builder() + .text("CALAMARI MADE MUD") + .npc("Madame Caldarium") + .location(new WorldPoint(2553, 2868, 0)) + .area("Corsair Cove") + .question("What is 3(5-3)?") + .answer("6") + .build(), + AnagramClue.builder() + .text("CLASH ION") + .npc("Nicholas") + .location(new WorldPoint(1841, 3803, 0)) + .area("North of Port Piscarilius fishing shop") + .question("How many windows are in Tynan's shop?") + .answer("4") + .build(), + AnagramClue.builder() + .text("DT RUN B") + .npc("Brundt the Chieftain") + .location(new WorldPoint(2658, 3670, 0)) + .area("Rellekka main hall") + .question("How many people are waiting for the next bard to perform?") + .answer("4") + .build(), + AnagramClue.builder() + .text("EEK ZERO OP") + .npc("Zoo keeper") + .location(new WorldPoint(2613, 3269, 0)) + .area("Ardougne Zoo") + .question("How many animals in total are there in the zoo?") + .answer("40") + .build(), + AnagramClue.builder() + .text("EL OW") + .npc("Lowe") + .location(new WorldPoint(3233, 3423, 0)) + .area("Varrock archery store") + .build(), + AnagramClue.builder() + .text("GOBLETS ODD TOES") + .npc("Otto Godblessed") + .location(new WorldPoint(2501, 3487, 0)) + .area("Otto's Grotto") + .question("How many types of dragon are there beneath the whirlpool's cavern?") + .answer("2") + .build(), + AnagramClue.builder() + .text("GOBLIN KERN") + .npc("King Bolren") + .location(new WorldPoint(2541, 3170, 0)) + .area("Tree Gnome Village") + .build(), + AnagramClue.builder() + .text("GOT A BOY") + .npc("Gabooty") + .location(new WorldPoint(2790, 3066, 0)) + .area("Tai Bwo Wannai") + .question("How many buildings are in the village?") + .answer("11") + .build(), + AnagramClue.builder() + .text("HALT US") + .npc("Luthas") + .location(new WorldPoint(2938, 3152, 0)) + .area("Banana plantation, Karamja") + .build(), + AnagramClue.builder() + .text("HEORIC") + .npc("Eohric") + .location(new WorldPoint(2900, 3565, 1)) + .area("Burthorpe Castle, top floor") + .question("King Arthur and Merlin sit down at the Round Table with 8 knights. How many degrees does each get?") + .answer("36") + .build(), + AnagramClue.builder() + .text("HICK JET") + .npc("Jethick") + .location(new WorldPoint(2541, 3305, 0)) + .area("West Ardougne town square") + .question("How many graves are there in the city graveyard?") + .answer("38") + .build(), + AnagramClue.builder() + .text("HIS PHOR") + .npc("Horphis") + .location(new WorldPoint(1639, 3812, 0)) + .area("Arceuus Library") + .question("On a scale of 1-10, how helpful is Logosia?") + .answer("1") + .build(), + AnagramClue.builder() + .text("I AM SIR") + .npc("Marisi") + .location(new WorldPoint(1737, 3557, 0)) + .area("Hosidius allotment patch") + .question("How many cities form the Kingdom of Great Kourend?") + .answer("5") + .build(), + AnagramClue.builder() + .text("ICY FE") + .npc("Fycie") + .location(new WorldPoint(2630, 2997, 0)) + .area("East Feldip Hills") + .build(), + AnagramClue.builder() + .text("I DOOM ICON INN") + .npc("Dominic Onion") + .location(new WorldPoint(2609, 3116, 0)) + .area("Nightmare Zone") + .question("How many reward points does a herb box cost?") + .answer("9,500") + .build(), + AnagramClue.builder() + .text("I EVEN") + .npc("Nieve") + .location(new WorldPoint(2432, 3422, 0)) + .area("Gnome Stronghold, outside the Stronghold Slayer Cave") + .question("How many farming patches are there in Gnome stronghold?") + .answer("2") + .build(), + AnagramClue.builder() + .text("KAY SIR") + .npc("Sir Kay") + .location(new WorldPoint(2760, 3496, 0)) + .area("Camelot Castle courtyard") + .question("How many fountains are there within the grounds of Camelot castle?") + .answer("6") + .build(), + AnagramClue.builder() + .text("LARK IN DOG") + .npc("King Roald") + .location(new WorldPoint(3220, 3476, 0)) + .area("Varrock Castle, ground floor") + .question("How many bookcases are there in the palace library?") + .answer("24") + .build(), + AnagramClue.builder() + .text("LEAKEY") + .npc("Kaylee") + .location(new WorldPoint(2957, 3370, 0)) + .area("Falador pub") + .question("How many chairs are there in the Rising Sun?") + .answer("18") + .build(), + AnagramClue.builder() + .text("LOW LAG") + .npc("Gallow") + .location(new WorldPoint(1805, 3566, 0)) + .area("Hosidius vinery") + .question("How many vine patches can you find in this vinery?") + .answer("12") + .build(), + AnagramClue.builder() + .text("ME IF") + .npc("Femi") + .location(new WorldPoint(2461, 3382, 0)) + .area("Tree Gnome Stronghold entrance") + .build(), + AnagramClue.builder() + .text("NOD MED") + .npc("Edmond") + .location(new WorldPoint(2566, 3332, 0)) + .area("East Ardougne, north-west house") + .question("How many pigeon cages are there around the back of Jerico's house?") + .answer("3") + .build(), + AnagramClue.builder() + .text("OK CO") + .npc("Cook") + .location(new WorldPoint(3207, 3214, 0)) + .area("Lumbridge Castle, ground floor") + .question("How many cannons does Lumbridge Castle have?") + .answer("9") + .build(), + AnagramClue.builder() + .text("PACINNG A TAIE") + .npc("Captain Ginea") + .location(new WorldPoint(1504, 3632, 0)) + .area("East of the Shayzien Encampment war tent") + .question("1 soldier can deal with 6 lizardmen. How many soldiers do we need for an army of 678 lizardmen?") + .answer("113") + .build(), + AnagramClue.builder() + .text("PEAK REFLEX") + .npc("Flax keeper") + .location(new WorldPoint(2744, 3444, 0)) + .area("Seers' Village flax field") + .question("If I have 1014 flax, and I spin a third of them into bowstring, how many flax do I have left?") + .answer("676") + .build(), + AnagramClue.builder() + .text("PEATY PERT") + .npc("Party Pete") + .location(new WorldPoint(3047, 3376, 0)) + .area("Falador Party Room") + .build(), + AnagramClue.builder() + .text("QUE SIR") + .npc("Squire") + .location(new WorldPoint(2975, 3343, 0)) + .area("Falador Castle courtyard") + .question("White knights are superior to black knights. 2 white knights can handle 3 black knights. How many knights do we need for an army of 981 black knights?") + .answer("654") + .build(), + AnagramClue.builder() + .text("R AK MI") + .npc("Karim") + .location(new WorldPoint(3273, 3181, 0)) + .area("Al Kharid kebab shop") + .question("I have 16 kebabs, I eat one myself and then share the rest equally between 3 friends. How many do they have each?") + .answer("5") + .build(), + AnagramClue.builder() + .text("RATAI") + .npc("Taria") + .location(new WorldPoint(2940, 3223, 0)) + .area("Rimmington bush patch") + .question("How many buildings are there in Rimmington?") + .answer("7") + .build(), + AnagramClue.builder() + .text("R SLICER") + .npc("Clerris") + .location(new WorldPoint(1761, 3850, 0)) + .area("Arceuus mine") + .question("If I have 1,000 blood runes, and cast 131 ice barrage spells, how many blood runes do I have left?") + .answer("738") + .build(), + AnagramClue.builder() + .text("SAND NUT") + .npc("Dunstan") + .location(new WorldPoint(2919, 3574, 0)) + .area("Anvil, north-east Burthorpe") + .question("How much smithing experience does one receive for smelting a blurite bar?") + .answer("8") + .build(), + AnagramClue.builder() + .text("TAMED ROCKS") + .npc("Dockmaster") + .location(new WorldPoint(1822, 3739, 0)) + .area("Port Piscarilius, NE of General store") + .question("What is the cube root of 125?") + .answer("5") + .build(), + AnagramClue.builder() + .text("THICKNO") + .npc("Hickton") + .location(new WorldPoint(2822, 3442, 0)) + .area("Catherby ranging shop") + .question("How many ranges are there in Catherby?") + .answer("2") + .build(), + AnagramClue.builder() + .text("UESNKRL NRIEDDO") + .npc("Drunken soldier") + .location(new WorldPoint(1551, 3565, 0)) + .area("Shayzien pub") + .question("If 13 Shayzien Soldiers kill 46 Lizardmen each in a day, how many Lizardmen have they killed in total in a single day?") + .answer("598") + .build(), + AnagramClue.builder() + .text("VESTE") + .npc("Steve") + .location(new WorldPoint(2432, 3423, 0)) + .area("Upstairs Skeletal Wyvern area or Stronghold Slayer Cave (after Monkey Madness 2)") + .question("How many farming patches are there in Gnome stronghold?") + .answer("2") + .build(), + + // Hard + AnagramClue.builder() + .text("BAKER CLIMB") + .npc("Brambickle") + .location(new WorldPoint(2783, 3861, 0)) + .area("Trollweiss mountain") + .build(), + AnagramClue.builder() + .text("BLUE GRIM GUIDED") + .npc("Lumbridge Guide") + .location(new WorldPoint(3238, 3220, 0)) + .area("Lumbridge") + .build(), + AnagramClue.builder() + .text("BY LOOK") + .npc("Bolkoy") + .location(new WorldPoint(2529, 3162, 1)) + .area("Tree Gnome Village general store") + .question("How many flowers are there in the clearing below this platform?") + .answer("13") + .build(), + AnagramClue.builder() + .text("C ON GAME HOC") + .npc("Gnome Coach") + .location(new WorldPoint(2395, 3486, 0)) + .area("Circling the Gnome Ball course") + .question("How many gnomes on the Gnome ball field have red patches on their uniforms?") + .answer("6") + .build(), + AnagramClue.builder() + .text("COPPER ORE CRYPTS") + .npc("Prospector Percy") + .location(new WorldPoint(3756, 5666, 0)) + .area("Motherlode Mine") + .question("During a party, everyone shook hands with everybody else. There were 66 handshakes. How many people were at the party?") + .answer("12") + .build(), + AnagramClue.builder() + .text("DARN DRAKE") + .npc("Daer Krand") + .location(new WorldPoint(3821, 9778, 2)) + .area("Sisterhood Sanctuary, northeast of the Nightmare Arena") + .build(), + AnagramClue.builder() + .text("DEKAGRAM") + .npc("Dark mage") + .location(new WorldPoint(3039, 4835, 0)) + .area("Centre of the Abyss") + .question("How many rifts are found here in the abyss?") + .answer("13") + .build(), + AnagramClue.builder() + .text("DO SAY MORE") + .npc("Doomsayer") + .location(new WorldPoint(3232, 3223, 0)) + .area("East of Lumbridge Castle") + .question("What is 40 divided by 1/2 plus 15?") + .answer("95") + .build(), + AnagramClue.builder() + .text("DRAGONS LAMENT") + .npc("Strange Old Man") + .location(new WorldPoint(3564, 3288, 0)) + .area("Barrows") + .question("One pipe fills a barrel in 1 hour while another pipe can fill the same barrel in 2 hours. How many minutes will it take to fill the tank if both pipes are used?") + .answer("40") + .build(), + AnagramClue.builder() + .text("DR WARDEN FUNK") + .npc("Drunken Dwarf") + .location(new WorldPoint(2913, 10221, 0)) + .area("East Keldagrim") + .build(), + AnagramClue.builder() + .text("MOTHERBOARD") + .npc("Brother Omad") + .location(new WorldPoint(2606, 3211, 0)) + .area("Ardougne Monastery") + .question("What is the next number? 12, 13, 15, 17, 111, 113, 117, 119, 123....?") + .answer("129") + .build(), + AnagramClue.builder() + .text("MY MANGLE LAL") + .npc("Lammy Langle") + .location(new WorldPoint(1688, 3540, 0)) + .area("Hosidius spirit tree patch") + .build(), + AnagramClue.builder() + .text("O BIRDZ A ZANY EN PC") + .npc("Cap'n Izzy No-Beard") + .location(new WorldPoint(2807, 3191, 0)) + .area("Brimhaven Agility Arena") + .question("How many Banana Trees are there in the plantation?") + .answer("33") + .build(), + AnagramClue.builder() + .text("QUIT HORRIBLE TYRANT") + .npc("Brother Tranquility") + .location(new WorldPoint(3681, 2963, 0)) + .area("Mos Le'Harmless or Harmony Island") + .question("If I have 49 bottles of rum to share between 7 pirates, how many would each pirate get?") + .answer("7") + .build(), + AnagramClue.builder() + .text("RAT MAT WITHIN") + .npc("Martin Thwait") + .location(new WorldPoint(2906, 3537, 0)) + .area("Rogues' Den") + .question("How many natural fires burn in Rogue's Den?") + .answer("2") + .build(), + AnagramClue.builder() + .text("SLIDE WOMAN") + .npc("Wise Old Man") + .location(new WorldPoint(3088, 3253, 0)) + .area("Draynor Village") + .question("How many bookcases are in the Wise Old Man's house?") + .answer("28") + .build(), + AnagramClue.builder() + .text("VEIL VEDA") + .npc("Evil Dave") + .location(new WorldPoint(3079, 9892, 0)) + .area("Doris' basement, Edgeville") + .question("What is 333 multiplied by 2?") + .answer("666") + .build(), + AnagramClue.builder() + .text("WOO AN EGG KIWI") + .npc("Awowogei") + .objectId(ObjectID.AWOWOGEI) + .location(new WorldPoint(2802, 2765, 0)) + .area("Ape Atoll") + .question("If I have 303 bananas, and share them between 31 friends evenly, only handing out full bananas. How many will I have left over?") + .answer("24") + .build(), + + // Elite + AnagramClue.builder() + .text("AT HERG") + .npc("Regath") + .location(new WorldPoint(1719, 3723, 0)) + .area("Arceuus general store") + .question("What is -5 to the power of 2?") + .answer("25") + .build(), + AnagramClue.builder() + .text("CAREER IN MOON") + .npc("Oneiromancer") + .location(new WorldPoint(2150, 3866, 0)) + .area("Astral altar") + .question("How many Suqah inhabit Lunar isle?") + .answer("25") + .build(), + AnagramClue.builder() + .text("COOL NERD") + .npc("Old crone") + .location(new WorldPoint(3462, 3557, 0)) + .area("East of the Slayer Tower") + .question("What is the combined combat level of each species that live in Slayer tower?") + .answer("619") + .build(), + AnagramClue.builder() + .text("DR HITMAN") + .npc("Mandrith") + .location(new WorldPoint(3182, 3946, 0)) + .area("Wilderness Resource Area") + .question("How many scorpions live under the pit?") + .answer("28") + .build(), + AnagramClue.builder() + .text("LADDER MEMO GUV") + .npc("Guard Vemmeldo") + .location(new WorldPoint(2447, 3418, 1)) + .area("Gnome Stronghold Bank") + .question("How many magic trees can you find inside the Gnome Stronghold?") + .answer("3") + .build(), + AnagramClue.builder() + .text("MACHETE CLAM") + .npc("Cam the Camel") + .location(new WorldPoint(3300, 3231, 0)) + .area("West of the Duel Arena entrance") + .question("How many items can carry water in Gielinor?") + .answer("6") + .build(), + AnagramClue.builder() + .text("MAJORS LAVA BADS AIR") + .npc("Ambassador Alvijar") + .location(new WorldPoint(2736, 5351, 1)) + .area("Dorgesh-Kaan, NE Middle Level") + .question("Double the miles before the initial Dorgeshuun veteran.") + .answer("2505") + .build(), + AnagramClue.builder() + .text("NO OWNER") + .npc("Oronwen") + .location(new WorldPoint(1162, 3178, 0)) + .area("Lletya seamstress shop") + .question("What is the minimum amount of quest points required to reach Lletya?") + .answer("20") + .build(), + AnagramClue.builder() + .text("OUR OWN NEEDS") + .npc("Nurse Wooned") + .location(new WorldPoint(1511, 3619, 0)) + .area("Shayzien Infirmary") + .question("How many wounded soldiers are there in the camp?") + .answer("16") + .build(), + AnagramClue.builder() + .text("SNAKES SO I SAIL") + .npc("Lisse Isaakson") + .location(new WorldPoint(2351, 3801, 0)) + .area("Neitiznot") + .question("How many arctic logs are required to make a large fremennik round shield?") + .answer("2") + .build(), + AnagramClue.builder() + .text("UNLEASH NIGHT MIST") + .npc("Sigli the Huntsman") + .location(new WorldPoint(2660, 3654, 0)) + .area("Rellekka entrance") + .question("What is the combined slayer requirement of every monster in the slayer cave?") + .answer("302") + .build(), + + // Master + AnagramClue.builder() + .text("A ELF KNOWS") + .npc("Snowflake") + .location(new WorldPoint(2872, 3934, 0)) + .area("Weiss") + .build(), + AnagramClue.builder() + .text("BRUCIE CATNAP") + .npc("Captain Bruce") + .location(new WorldPoint(1520, 3558, 0)) + .area("Shayzien") + .build(), + AnagramClue.builder() + .text("CAR IF ICES") + .npc("Sacrifice") + .location(new WorldPoint(2209, 3056, 0)) + .area("Zul-Andra") + .build(), + AnagramClue.builder() + .text("DED WAR") + .npc("Edward") + .location(new WorldPoint(3284, 3943, 0)) + .area("Around or within Rogues' Castle") + .build(), + AnagramClue.builder() + .text("DIM THARN") + .npc("Mandrith") + .location(new WorldPoint(3182, 3946, 0)) + .area("Wilderness Resource Area") + .build(), + AnagramClue.builder() + .text("DUO PLUG") + .npc("Dugopul") + .location(new WorldPoint(2803, 2744, 0)) + .area("Ape Atoll graveyard") + .build(), + AnagramClue.builder() + .text("FORLUN") + .npc("Runolf") + .location(new WorldPoint(2512, 10256, 0)) + .area("Miscellania Dungeon") + .build(), + AnagramClue.builder() + .text("IM N ZEZIM") + .npc("Immenizz") + .location(new WorldPoint(2592, 4324, 0)) + .area("Puro-Puro") + .build(), + AnagramClue.builder() + .text("MAL IN TAU") + .npc("Luminata") + .location(new WorldPoint(3508, 3237, 0)) + .area("Burgh de Rott, near general store") + .build(), + AnagramClue.builder() + .text("MOLD LA RAN") + .npc("Old Man Ral") + .location(new WorldPoint(3602, 3209, 0)) + .area("Meiyerditch") + .build(), + AnagramClue.builder() + .text("MUS KIL READER") + .npc("Radimus Erkle") + .location(new WorldPoint(2726, 3368, 0)) + .area("Legends' Guild") + .build(), + AnagramClue.builder() + .text("RIP MAUL") + .npc("Primula") + .location(new WorldPoint(2454, 2853, 1)) + .area("Myths' Guild, first floor") + .build(), + AnagramClue.builder() + .text("RUE GO") + .npc("Goreu") + .location(new WorldPoint(2335, 3162, 0)) + .area("Lletya") + .build(), + AnagramClue.builder() + .text("SLAM DUSTER GRAIL") + .npc("Guildmaster Lars") + .location(new WorldPoint(1649, 3498, 0)) + .area("Woodcutting Guild, Hosidius") + .build(), + AnagramClue.builder() + .text("TEN WIGS ON") + .npc("Wingstone") + .location(new WorldPoint(3389, 2877, 0)) + .area("North of Agility Pyramid") + .build(), + AnagramClue.builder() + .text("TWENTY CURE IRON") + .npc("New Recruit Tony") + .location(new WorldPoint(1503, 3553, 0)) + .area("Shayzien Graveyard") + .build() ); private final String text; @@ -161,29 +788,8 @@ public class AnagramClue extends ClueScroll implements TextClueScroll, NpcClueSc private final String question; @Nullable private final String answer; - private int objectId; - - private AnagramClue(String text, String npc, WorldPoint location, String area) - { - this(text, npc, location, area, null, null); - } - - private AnagramClue(String text, String npc, WorldPoint location, String area, @Nullable String question, @Nullable String answer) - { - this.text = text; - this.npc = npc; - this.location = location; - this.area = area; - this.question = question; - this.answer = answer; - this.objectId = -1; - } - - private AnagramClue(String text, String npc, int objectId, WorldPoint location, String area, String question, String answer) - { - this(text, npc, location, area, question, answer); - this.objectId = objectId; - } + @Builder.Default + private final int objectId = -1; @Override public void makeOverlayHint(PanelComponent panelComponent, ClueScrollPlugin plugin) @@ -261,12 +867,12 @@ public class AnagramClue extends ClueScroll implements TextClueScroll, NpcClueSc @Override public String[] getNpcs() { - return new String[] {npc}; + return new String[]{npc}; } @Override public int[] getObjectIds() { - return new int[] {objectId}; + return new int[]{objectId}; } } From e8856ce4188cbd5d5083323c9c052c969c372fcc Mon Sep 17 00:00:00 2001 From: Adam Date: Sun, 16 Jan 2022 18:13:59 -0500 Subject: [PATCH 19/51] Revert "Merge pull request #14512 from wayne-li2/anagram-clue-builder" This reverts commit 72f55d8ce9542dde88efbe4345496d8afa87bbe7, reversing changes made to 82514e0c76ac69500eacd88dcf1404a2f529ed64. --- .../cluescrolls/clues/AnagramClue.java | 860 +++--------------- 1 file changed, 127 insertions(+), 733 deletions(-) diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/clues/AnagramClue.java b/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/clues/AnagramClue.java index 5592d08141..8a35abd738 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/clues/AnagramClue.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/clues/AnagramClue.java @@ -24,12 +24,11 @@ */ package net.runelite.client.plugins.cluescrolls.clues; -import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableSet; import java.awt.Color; import java.awt.Graphics2D; -import java.util.List; +import java.util.Set; import javax.annotation.Nullable; -import lombok.Builder; import lombok.Getter; import net.runelite.api.NPC; import net.runelite.api.ObjectID; @@ -47,737 +46,111 @@ import net.runelite.client.ui.overlay.components.PanelComponent; import net.runelite.client.ui.overlay.components.TitleComponent; @Getter -@Builder public class AnagramClue extends ClueScroll implements TextClueScroll, NpcClueScroll, ObjectClueScroll { private static final String ANAGRAM_TEXT = "This anagram reveals who to speak to next: "; private static final String ANAGRAM_TEXT_BEGINNER = "The anagram reveals who to speak to next: "; - private static final List CLUES = ImmutableList.of( - // Beginner - AnagramClue.builder() - .text("AN EARL") - .npc("Ranael") - .location(new WorldPoint(3315, 3163, 0)) - .area("Al Kharid skirt shop") - .build(), - AnagramClue.builder() - .text("CARPET AHOY") - .npc("Apothecary") - .location(new WorldPoint(3195, 3404, 0)) - .area("Southwest Varrock") - .build(), - AnagramClue.builder() - .text("DISORDER") - .npc("Sedridor") - .location(new WorldPoint(3102, 9570, 0)) - .area("Wizards' Tower basement") - .build(), - AnagramClue.builder() - .text("I CORD") - .npc("Doric") - .location(new WorldPoint(2951, 3450, 0)) - .area("Doric's house, north of Falador") - .build(), - AnagramClue.builder() - .text("IN BAR") - .npc("Brian") - .location(new WorldPoint(3026, 3246, 0)) - .area("Port Sarim battleaxe shop") - .build(), - AnagramClue.builder() - .text("RAIN COVE") - .npc("Veronica") - .location(new WorldPoint(3110, 3330, 0)) - .area("Outside Draynor Manor") - .build(), - AnagramClue.builder() - .text("RUG DETER") - .npc("Gertrude") - .location(new WorldPoint(3151, 3412, 0)) - .area("Gertrude's house, west of Varrock") - .build(), - AnagramClue.builder() - .text("SIR SHARE RED") - .npc("Hairdresser") - .location(new WorldPoint(2944, 3381, 0)) - .area("Falador hairdresser") - .build(), - AnagramClue.builder() - .text("TAUNT ROOF") - .npc("Fortunato") - .location(new WorldPoint(3080, 3250, 0)) - .area("Draynor Village market") - .build(), - - // Medium - AnagramClue.builder() - .text("A BAKER") - .npc("Baraek") - .location(new WorldPoint(3217, 3434, 0)) - .area("Varrock square") - .question("How many stalls are there in Varrock Square?") - .answer("5") - .build(), - AnagramClue.builder() - .text("A BAS") - .npc("Saba") - .location(new WorldPoint(2858, 3577, 0)) - .area("Death Plateau cave, north of the Warriors' Guild") - .build(), - AnagramClue.builder() - .text("A BASIC ANTI POT") - .npc("Captain Tobias") - .location(new WorldPoint(3026, 3216, 0)) - .area("Port Sarim docks") - .question("How many ships are there docked at Port Sarim currently?") - .answer("6") - .build(), - AnagramClue.builder() - .text("AHA JAR") - .npc("Jaraah") - .location(new WorldPoint(3359, 3276, 0)) - .area("Duel Arena hospital") - .build(), - AnagramClue.builder() - .text("A HEART") - .npc("Aretha") - .location(new WorldPoint(1814, 3851, 0)) - .area("Soul altar") - .question("32 - 5x = 22, what is x?") - .answer("2") - .build(), - AnagramClue.builder() - .text("ARC O LINE") - .npc("Caroline") - .location(new WorldPoint(2715, 3302, 0)) - .area("North of Witchaven, near row boat") - .question("How many fishermen are there on the fishing platform?") - .answer("11") - .build(), - AnagramClue.builder() - .text("AREA CHEF TREK") - .npc("Father Aereck") - .location(new WorldPoint(3243, 3208, 0)) - .area("Lumbridge Church") - .question("How many gravestones are in the church graveyard?") - .answer("19 or 20") - .build(), - AnagramClue.builder() - .text("ARE COL") - .npc("Oracle") - .location(new WorldPoint(3013, 3501, 0)) - .area("Ice Mountain") - .question("If x is 15 and y is 3 what is 3x + y?") - .answer("48") - .build(), - AnagramClue.builder() - .text("ARMCHAIR THE PELT") - .npc("Charlie the Tramp") - .location(new WorldPoint(3209, 3392, 0)) - .area("Varrock south entrance") - .question("How many coins would I have if I have 0 coins and attempt to buy 10 loaves of bread for 3 coins each?") - .answer("0") - .build(), - AnagramClue.builder() - .text("BAIL TRIMS") - .npc("Brimstail") - .location(new WorldPoint(2402, 3419, 0)) - .area("West of Stronghold Slayer Cave") - .build(), - AnagramClue.builder() - .text("CALAMARI MADE MUD") - .npc("Madame Caldarium") - .location(new WorldPoint(2553, 2868, 0)) - .area("Corsair Cove") - .question("What is 3(5-3)?") - .answer("6") - .build(), - AnagramClue.builder() - .text("CLASH ION") - .npc("Nicholas") - .location(new WorldPoint(1841, 3803, 0)) - .area("North of Port Piscarilius fishing shop") - .question("How many windows are in Tynan's shop?") - .answer("4") - .build(), - AnagramClue.builder() - .text("DT RUN B") - .npc("Brundt the Chieftain") - .location(new WorldPoint(2658, 3670, 0)) - .area("Rellekka main hall") - .question("How many people are waiting for the next bard to perform?") - .answer("4") - .build(), - AnagramClue.builder() - .text("EEK ZERO OP") - .npc("Zoo keeper") - .location(new WorldPoint(2613, 3269, 0)) - .area("Ardougne Zoo") - .question("How many animals in total are there in the zoo?") - .answer("40") - .build(), - AnagramClue.builder() - .text("EL OW") - .npc("Lowe") - .location(new WorldPoint(3233, 3423, 0)) - .area("Varrock archery store") - .build(), - AnagramClue.builder() - .text("GOBLETS ODD TOES") - .npc("Otto Godblessed") - .location(new WorldPoint(2501, 3487, 0)) - .area("Otto's Grotto") - .question("How many types of dragon are there beneath the whirlpool's cavern?") - .answer("2") - .build(), - AnagramClue.builder() - .text("GOBLIN KERN") - .npc("King Bolren") - .location(new WorldPoint(2541, 3170, 0)) - .area("Tree Gnome Village") - .build(), - AnagramClue.builder() - .text("GOT A BOY") - .npc("Gabooty") - .location(new WorldPoint(2790, 3066, 0)) - .area("Tai Bwo Wannai") - .question("How many buildings are in the village?") - .answer("11") - .build(), - AnagramClue.builder() - .text("HALT US") - .npc("Luthas") - .location(new WorldPoint(2938, 3152, 0)) - .area("Banana plantation, Karamja") - .build(), - AnagramClue.builder() - .text("HEORIC") - .npc("Eohric") - .location(new WorldPoint(2900, 3565, 1)) - .area("Burthorpe Castle, top floor") - .question("King Arthur and Merlin sit down at the Round Table with 8 knights. How many degrees does each get?") - .answer("36") - .build(), - AnagramClue.builder() - .text("HICK JET") - .npc("Jethick") - .location(new WorldPoint(2541, 3305, 0)) - .area("West Ardougne town square") - .question("How many graves are there in the city graveyard?") - .answer("38") - .build(), - AnagramClue.builder() - .text("HIS PHOR") - .npc("Horphis") - .location(new WorldPoint(1639, 3812, 0)) - .area("Arceuus Library") - .question("On a scale of 1-10, how helpful is Logosia?") - .answer("1") - .build(), - AnagramClue.builder() - .text("I AM SIR") - .npc("Marisi") - .location(new WorldPoint(1737, 3557, 0)) - .area("Hosidius allotment patch") - .question("How many cities form the Kingdom of Great Kourend?") - .answer("5") - .build(), - AnagramClue.builder() - .text("ICY FE") - .npc("Fycie") - .location(new WorldPoint(2630, 2997, 0)) - .area("East Feldip Hills") - .build(), - AnagramClue.builder() - .text("I DOOM ICON INN") - .npc("Dominic Onion") - .location(new WorldPoint(2609, 3116, 0)) - .area("Nightmare Zone") - .question("How many reward points does a herb box cost?") - .answer("9,500") - .build(), - AnagramClue.builder() - .text("I EVEN") - .npc("Nieve") - .location(new WorldPoint(2432, 3422, 0)) - .area("Gnome Stronghold, outside the Stronghold Slayer Cave") - .question("How many farming patches are there in Gnome stronghold?") - .answer("2") - .build(), - AnagramClue.builder() - .text("KAY SIR") - .npc("Sir Kay") - .location(new WorldPoint(2760, 3496, 0)) - .area("Camelot Castle courtyard") - .question("How many fountains are there within the grounds of Camelot castle?") - .answer("6") - .build(), - AnagramClue.builder() - .text("LARK IN DOG") - .npc("King Roald") - .location(new WorldPoint(3220, 3476, 0)) - .area("Varrock Castle, ground floor") - .question("How many bookcases are there in the palace library?") - .answer("24") - .build(), - AnagramClue.builder() - .text("LEAKEY") - .npc("Kaylee") - .location(new WorldPoint(2957, 3370, 0)) - .area("Falador pub") - .question("How many chairs are there in the Rising Sun?") - .answer("18") - .build(), - AnagramClue.builder() - .text("LOW LAG") - .npc("Gallow") - .location(new WorldPoint(1805, 3566, 0)) - .area("Hosidius vinery") - .question("How many vine patches can you find in this vinery?") - .answer("12") - .build(), - AnagramClue.builder() - .text("ME IF") - .npc("Femi") - .location(new WorldPoint(2461, 3382, 0)) - .area("Tree Gnome Stronghold entrance") - .build(), - AnagramClue.builder() - .text("NOD MED") - .npc("Edmond") - .location(new WorldPoint(2566, 3332, 0)) - .area("East Ardougne, north-west house") - .question("How many pigeon cages are there around the back of Jerico's house?") - .answer("3") - .build(), - AnagramClue.builder() - .text("OK CO") - .npc("Cook") - .location(new WorldPoint(3207, 3214, 0)) - .area("Lumbridge Castle, ground floor") - .question("How many cannons does Lumbridge Castle have?") - .answer("9") - .build(), - AnagramClue.builder() - .text("PACINNG A TAIE") - .npc("Captain Ginea") - .location(new WorldPoint(1504, 3632, 0)) - .area("East of the Shayzien Encampment war tent") - .question("1 soldier can deal with 6 lizardmen. How many soldiers do we need for an army of 678 lizardmen?") - .answer("113") - .build(), - AnagramClue.builder() - .text("PEAK REFLEX") - .npc("Flax keeper") - .location(new WorldPoint(2744, 3444, 0)) - .area("Seers' Village flax field") - .question("If I have 1014 flax, and I spin a third of them into bowstring, how many flax do I have left?") - .answer("676") - .build(), - AnagramClue.builder() - .text("PEATY PERT") - .npc("Party Pete") - .location(new WorldPoint(3047, 3376, 0)) - .area("Falador Party Room") - .build(), - AnagramClue.builder() - .text("QUE SIR") - .npc("Squire") - .location(new WorldPoint(2975, 3343, 0)) - .area("Falador Castle courtyard") - .question("White knights are superior to black knights. 2 white knights can handle 3 black knights. How many knights do we need for an army of 981 black knights?") - .answer("654") - .build(), - AnagramClue.builder() - .text("R AK MI") - .npc("Karim") - .location(new WorldPoint(3273, 3181, 0)) - .area("Al Kharid kebab shop") - .question("I have 16 kebabs, I eat one myself and then share the rest equally between 3 friends. How many do they have each?") - .answer("5") - .build(), - AnagramClue.builder() - .text("RATAI") - .npc("Taria") - .location(new WorldPoint(2940, 3223, 0)) - .area("Rimmington bush patch") - .question("How many buildings are there in Rimmington?") - .answer("7") - .build(), - AnagramClue.builder() - .text("R SLICER") - .npc("Clerris") - .location(new WorldPoint(1761, 3850, 0)) - .area("Arceuus mine") - .question("If I have 1,000 blood runes, and cast 131 ice barrage spells, how many blood runes do I have left?") - .answer("738") - .build(), - AnagramClue.builder() - .text("SAND NUT") - .npc("Dunstan") - .location(new WorldPoint(2919, 3574, 0)) - .area("Anvil, north-east Burthorpe") - .question("How much smithing experience does one receive for smelting a blurite bar?") - .answer("8") - .build(), - AnagramClue.builder() - .text("TAMED ROCKS") - .npc("Dockmaster") - .location(new WorldPoint(1822, 3739, 0)) - .area("Port Piscarilius, NE of General store") - .question("What is the cube root of 125?") - .answer("5") - .build(), - AnagramClue.builder() - .text("THICKNO") - .npc("Hickton") - .location(new WorldPoint(2822, 3442, 0)) - .area("Catherby ranging shop") - .question("How many ranges are there in Catherby?") - .answer("2") - .build(), - AnagramClue.builder() - .text("UESNKRL NRIEDDO") - .npc("Drunken soldier") - .location(new WorldPoint(1551, 3565, 0)) - .area("Shayzien pub") - .question("If 13 Shayzien Soldiers kill 46 Lizardmen each in a day, how many Lizardmen have they killed in total in a single day?") - .answer("598") - .build(), - AnagramClue.builder() - .text("VESTE") - .npc("Steve") - .location(new WorldPoint(2432, 3423, 0)) - .area("Upstairs Skeletal Wyvern area or Stronghold Slayer Cave (after Monkey Madness 2)") - .question("How many farming patches are there in Gnome stronghold?") - .answer("2") - .build(), - - // Hard - AnagramClue.builder() - .text("BAKER CLIMB") - .npc("Brambickle") - .location(new WorldPoint(2783, 3861, 0)) - .area("Trollweiss mountain") - .build(), - AnagramClue.builder() - .text("BLUE GRIM GUIDED") - .npc("Lumbridge Guide") - .location(new WorldPoint(3238, 3220, 0)) - .area("Lumbridge") - .build(), - AnagramClue.builder() - .text("BY LOOK") - .npc("Bolkoy") - .location(new WorldPoint(2529, 3162, 1)) - .area("Tree Gnome Village general store") - .question("How many flowers are there in the clearing below this platform?") - .answer("13") - .build(), - AnagramClue.builder() - .text("C ON GAME HOC") - .npc("Gnome Coach") - .location(new WorldPoint(2395, 3486, 0)) - .area("Circling the Gnome Ball course") - .question("How many gnomes on the Gnome ball field have red patches on their uniforms?") - .answer("6") - .build(), - AnagramClue.builder() - .text("COPPER ORE CRYPTS") - .npc("Prospector Percy") - .location(new WorldPoint(3756, 5666, 0)) - .area("Motherlode Mine") - .question("During a party, everyone shook hands with everybody else. There were 66 handshakes. How many people were at the party?") - .answer("12") - .build(), - AnagramClue.builder() - .text("DARN DRAKE") - .npc("Daer Krand") - .location(new WorldPoint(3821, 9778, 2)) - .area("Sisterhood Sanctuary, northeast of the Nightmare Arena") - .build(), - AnagramClue.builder() - .text("DEKAGRAM") - .npc("Dark mage") - .location(new WorldPoint(3039, 4835, 0)) - .area("Centre of the Abyss") - .question("How many rifts are found here in the abyss?") - .answer("13") - .build(), - AnagramClue.builder() - .text("DO SAY MORE") - .npc("Doomsayer") - .location(new WorldPoint(3232, 3223, 0)) - .area("East of Lumbridge Castle") - .question("What is 40 divided by 1/2 plus 15?") - .answer("95") - .build(), - AnagramClue.builder() - .text("DRAGONS LAMENT") - .npc("Strange Old Man") - .location(new WorldPoint(3564, 3288, 0)) - .area("Barrows") - .question("One pipe fills a barrel in 1 hour while another pipe can fill the same barrel in 2 hours. How many minutes will it take to fill the tank if both pipes are used?") - .answer("40") - .build(), - AnagramClue.builder() - .text("DR WARDEN FUNK") - .npc("Drunken Dwarf") - .location(new WorldPoint(2913, 10221, 0)) - .area("East Keldagrim") - .build(), - AnagramClue.builder() - .text("MOTHERBOARD") - .npc("Brother Omad") - .location(new WorldPoint(2606, 3211, 0)) - .area("Ardougne Monastery") - .question("What is the next number? 12, 13, 15, 17, 111, 113, 117, 119, 123....?") - .answer("129") - .build(), - AnagramClue.builder() - .text("MY MANGLE LAL") - .npc("Lammy Langle") - .location(new WorldPoint(1688, 3540, 0)) - .area("Hosidius spirit tree patch") - .build(), - AnagramClue.builder() - .text("O BIRDZ A ZANY EN PC") - .npc("Cap'n Izzy No-Beard") - .location(new WorldPoint(2807, 3191, 0)) - .area("Brimhaven Agility Arena") - .question("How many Banana Trees are there in the plantation?") - .answer("33") - .build(), - AnagramClue.builder() - .text("QUIT HORRIBLE TYRANT") - .npc("Brother Tranquility") - .location(new WorldPoint(3681, 2963, 0)) - .area("Mos Le'Harmless or Harmony Island") - .question("If I have 49 bottles of rum to share between 7 pirates, how many would each pirate get?") - .answer("7") - .build(), - AnagramClue.builder() - .text("RAT MAT WITHIN") - .npc("Martin Thwait") - .location(new WorldPoint(2906, 3537, 0)) - .area("Rogues' Den") - .question("How many natural fires burn in Rogue's Den?") - .answer("2") - .build(), - AnagramClue.builder() - .text("SLIDE WOMAN") - .npc("Wise Old Man") - .location(new WorldPoint(3088, 3253, 0)) - .area("Draynor Village") - .question("How many bookcases are in the Wise Old Man's house?") - .answer("28") - .build(), - AnagramClue.builder() - .text("VEIL VEDA") - .npc("Evil Dave") - .location(new WorldPoint(3079, 9892, 0)) - .area("Doris' basement, Edgeville") - .question("What is 333 multiplied by 2?") - .answer("666") - .build(), - AnagramClue.builder() - .text("WOO AN EGG KIWI") - .npc("Awowogei") - .objectId(ObjectID.AWOWOGEI) - .location(new WorldPoint(2802, 2765, 0)) - .area("Ape Atoll") - .question("If I have 303 bananas, and share them between 31 friends evenly, only handing out full bananas. How many will I have left over?") - .answer("24") - .build(), - - // Elite - AnagramClue.builder() - .text("AT HERG") - .npc("Regath") - .location(new WorldPoint(1719, 3723, 0)) - .area("Arceuus general store") - .question("What is -5 to the power of 2?") - .answer("25") - .build(), - AnagramClue.builder() - .text("CAREER IN MOON") - .npc("Oneiromancer") - .location(new WorldPoint(2150, 3866, 0)) - .area("Astral altar") - .question("How many Suqah inhabit Lunar isle?") - .answer("25") - .build(), - AnagramClue.builder() - .text("COOL NERD") - .npc("Old crone") - .location(new WorldPoint(3462, 3557, 0)) - .area("East of the Slayer Tower") - .question("What is the combined combat level of each species that live in Slayer tower?") - .answer("619") - .build(), - AnagramClue.builder() - .text("DR HITMAN") - .npc("Mandrith") - .location(new WorldPoint(3182, 3946, 0)) - .area("Wilderness Resource Area") - .question("How many scorpions live under the pit?") - .answer("28") - .build(), - AnagramClue.builder() - .text("LADDER MEMO GUV") - .npc("Guard Vemmeldo") - .location(new WorldPoint(2447, 3418, 1)) - .area("Gnome Stronghold Bank") - .question("How many magic trees can you find inside the Gnome Stronghold?") - .answer("3") - .build(), - AnagramClue.builder() - .text("MACHETE CLAM") - .npc("Cam the Camel") - .location(new WorldPoint(3300, 3231, 0)) - .area("West of the Duel Arena entrance") - .question("How many items can carry water in Gielinor?") - .answer("6") - .build(), - AnagramClue.builder() - .text("MAJORS LAVA BADS AIR") - .npc("Ambassador Alvijar") - .location(new WorldPoint(2736, 5351, 1)) - .area("Dorgesh-Kaan, NE Middle Level") - .question("Double the miles before the initial Dorgeshuun veteran.") - .answer("2505") - .build(), - AnagramClue.builder() - .text("NO OWNER") - .npc("Oronwen") - .location(new WorldPoint(1162, 3178, 0)) - .area("Lletya seamstress shop") - .question("What is the minimum amount of quest points required to reach Lletya?") - .answer("20") - .build(), - AnagramClue.builder() - .text("OUR OWN NEEDS") - .npc("Nurse Wooned") - .location(new WorldPoint(1511, 3619, 0)) - .area("Shayzien Infirmary") - .question("How many wounded soldiers are there in the camp?") - .answer("16") - .build(), - AnagramClue.builder() - .text("SNAKES SO I SAIL") - .npc("Lisse Isaakson") - .location(new WorldPoint(2351, 3801, 0)) - .area("Neitiznot") - .question("How many arctic logs are required to make a large fremennik round shield?") - .answer("2") - .build(), - AnagramClue.builder() - .text("UNLEASH NIGHT MIST") - .npc("Sigli the Huntsman") - .location(new WorldPoint(2660, 3654, 0)) - .area("Rellekka entrance") - .question("What is the combined slayer requirement of every monster in the slayer cave?") - .answer("302") - .build(), - - // Master - AnagramClue.builder() - .text("A ELF KNOWS") - .npc("Snowflake") - .location(new WorldPoint(2872, 3934, 0)) - .area("Weiss") - .build(), - AnagramClue.builder() - .text("BRUCIE CATNAP") - .npc("Captain Bruce") - .location(new WorldPoint(1520, 3558, 0)) - .area("Shayzien") - .build(), - AnagramClue.builder() - .text("CAR IF ICES") - .npc("Sacrifice") - .location(new WorldPoint(2209, 3056, 0)) - .area("Zul-Andra") - .build(), - AnagramClue.builder() - .text("DED WAR") - .npc("Edward") - .location(new WorldPoint(3284, 3943, 0)) - .area("Around or within Rogues' Castle") - .build(), - AnagramClue.builder() - .text("DIM THARN") - .npc("Mandrith") - .location(new WorldPoint(3182, 3946, 0)) - .area("Wilderness Resource Area") - .build(), - AnagramClue.builder() - .text("DUO PLUG") - .npc("Dugopul") - .location(new WorldPoint(2803, 2744, 0)) - .area("Ape Atoll graveyard") - .build(), - AnagramClue.builder() - .text("FORLUN") - .npc("Runolf") - .location(new WorldPoint(2512, 10256, 0)) - .area("Miscellania Dungeon") - .build(), - AnagramClue.builder() - .text("IM N ZEZIM") - .npc("Immenizz") - .location(new WorldPoint(2592, 4324, 0)) - .area("Puro-Puro") - .build(), - AnagramClue.builder() - .text("MAL IN TAU") - .npc("Luminata") - .location(new WorldPoint(3508, 3237, 0)) - .area("Burgh de Rott, near general store") - .build(), - AnagramClue.builder() - .text("MOLD LA RAN") - .npc("Old Man Ral") - .location(new WorldPoint(3602, 3209, 0)) - .area("Meiyerditch") - .build(), - AnagramClue.builder() - .text("MUS KIL READER") - .npc("Radimus Erkle") - .location(new WorldPoint(2726, 3368, 0)) - .area("Legends' Guild") - .build(), - AnagramClue.builder() - .text("RIP MAUL") - .npc("Primula") - .location(new WorldPoint(2454, 2853, 1)) - .area("Myths' Guild, first floor") - .build(), - AnagramClue.builder() - .text("RUE GO") - .npc("Goreu") - .location(new WorldPoint(2335, 3162, 0)) - .area("Lletya") - .build(), - AnagramClue.builder() - .text("SLAM DUSTER GRAIL") - .npc("Guildmaster Lars") - .location(new WorldPoint(1649, 3498, 0)) - .area("Woodcutting Guild, Hosidius") - .build(), - AnagramClue.builder() - .text("TEN WIGS ON") - .npc("Wingstone") - .location(new WorldPoint(3389, 2877, 0)) - .area("North of Agility Pyramid") - .build(), - AnagramClue.builder() - .text("TWENTY CURE IRON") - .npc("New Recruit Tony") - .location(new WorldPoint(1503, 3553, 0)) - .area("Shayzien Graveyard") - .build() + private static final Set CLUES = ImmutableSet.of( + new AnagramClue("A BAKER", "Baraek", new WorldPoint(3217, 3434, 0), "Varrock square", "How many stalls are there in Varrock Square?", "5"), + new AnagramClue("A BASIC ANTI POT", "Captain Tobias", new WorldPoint(3026, 3216, 0), "Port Sarim", "How many ships are there docked at Port Sarim currently?", "6"), + new AnagramClue("A ELF KNOWS", "Snowflake", new WorldPoint(2872, 3934, 0), "Weiss"), + new AnagramClue("A HEART", "Aretha", new WorldPoint(1814, 3851, 0), "Soul altar", "32 - 5x = 22, what is x?", "2"), + new AnagramClue("AHA JAR", "Jaraah", new WorldPoint(3359, 3276, 0), "Duel Arena hospital"), + new AnagramClue("ARC O LINE", "Caroline", new WorldPoint(2715, 3302, 0), "North Witchaven next to the row boat", "How many fishermen are there on the fishing platform?", "11"), + new AnagramClue("ARE COL", "Oracle", new WorldPoint(3013, 3501, 0), "Ice Mountain West of Edgeville", "If x is 15 and y is 3 what is 3x + y?", "48"), + new AnagramClue("ARMCHAIR THE PELT", "Charlie the Tramp", new WorldPoint(3209, 3392, 0), "South entrance of Varrock", "How many coins would I have if I have 0 coins and attempt to buy 10 loaves of bread for 3 coins each?", "0"), + new AnagramClue("AT HERG", "Regath", new WorldPoint(1719, 3723, 0), "General Store, Arceuus, Zeah", "What is -5 to the power of 2?", "25"), + new AnagramClue("A BAS", "Saba", new WorldPoint(2858, 3577, 0), "Death Plateau"), + new AnagramClue("AREA CHEF TREK", "Father Aereck", new WorldPoint(3243, 3208, 0), "Lumbridge Church", "How many gravestones are in the church graveyard?", "19 or 20"), + new AnagramClue("BAIL TRIMS", "Brimstail", new WorldPoint(2402, 3419, 0), "West of Stronghold Slayer Cave"), + new AnagramClue("BAKER CLIMB", "Brambickle", new WorldPoint(2783, 3861, 0), "Trollweiss mountain"), + new AnagramClue("BLUE GRIM GUIDED", "Lumbridge Guide", new WorldPoint(3238, 3220, 0), "Lumbridge"), + new AnagramClue("BY LOOK", "Bolkoy", new WorldPoint(2529, 3162, 0), "Tree Gnome Village general store", "How many flowers are there in the clearing below this platform?", "13"), + new AnagramClue("CALAMARI MADE MUD", "Madame Caldarium", new WorldPoint(2553, 2868, 0), "Corsair Cove", "What is 3(5-3)?", "6"), + new AnagramClue("CAR IF ICES", "Sacrifice", new WorldPoint(2209, 3056, 0), "Zul-Andra"), + new AnagramClue("CAREER IN MOON", "Oneiromancer", new WorldPoint(2150, 3866, 0), "Astral altar", "How many Suqah inhabit Lunar isle?", "25"), + new AnagramClue("CLASH ION", "Nicholas", new WorldPoint(1841, 3803, 0), "North of Port Piscarilius fishing shop", "How many windows are in Tynan's shop?", "4"), + new AnagramClue("C ON GAME HOC", "Gnome Coach", new WorldPoint(2395, 3486, 0), "Gnome Ball course", "How many gnomes on the Gnome ball field have red patches on their uniforms?", "6"), + new AnagramClue("COOL NERD", "Old crone", new WorldPoint(3462, 3557, 0), "East of the Slayer Tower", "What is the combined combat level of each species that live in Slayer tower?", "619"), + new AnagramClue("COPPER ORE CRYPTS", "Prospector Percy", new WorldPoint(3061, 3377, 0), "Motherlode Mine", "During a party, everyone shook hands with everybody else. There were 66 handshakes. How many people were at the party?", "12"), + new AnagramClue("DARN DRAKE", "Daer Krand", new WorldPoint(3728, 3302, 0), "Sisterhood Sanctuary (Slepe Dungeon, northeast of Nightmare Arena)"), + new AnagramClue("DED WAR", "Edward", new WorldPoint(3284, 3943, 0), "Inside Rogue's Castle"), + new AnagramClue("DEKAGRAM", "Dark mage", new WorldPoint(3039, 4835, 0), "Centre of the Abyss", "How many rifts are found here in the abyss?", "13"), + new AnagramClue("DO SAY MORE", "Doomsayer", new WorldPoint(3230, 3230, 0), "East of Lumbridge Castle", "What is 40 divided by 1/2 plus 15?", "95"), + new AnagramClue("DIM THARN", "Mandrith", new WorldPoint(3182, 3946, 0), "Wilderness Resource Area"), + new AnagramClue("DR HITMAN", "Mandrith", new WorldPoint(3182, 3946, 0), "Wilderness Resource Area", "How many scorpions live under the pit?", "28"), + new AnagramClue("DR WARDEN FUNK", "Drunken Dwarf", new WorldPoint(2913, 10221, 0), "East Side of Keldagrim"), + new AnagramClue("DRAGONS LAMENT", "Strange Old Man", new WorldPoint(3564, 3288, 0), "Barrows", "One pipe fills a barrel in 1 hour while another pipe can fill the same barrel in 2 hours. How many minutes will it take to fill the tank if both pipes are used?", "40"), + new AnagramClue("DT RUN B", "Brundt the Chieftain", new WorldPoint(2658, 3670, 0), "Rellekka, main hall", "How many people are waiting for the next bard to perform?", "4"), + new AnagramClue("DUO PLUG", "Dugopul", new WorldPoint(2803, 2744, 0), "Graveyard on Ape Atoll"), + new AnagramClue("EEK ZERO OP", "Zoo keeper", new WorldPoint(2613, 3269, 0), "Ardougne Zoo", "How many animals in total are there in the zoo?", "40"), + new AnagramClue("EL OW", "Lowe", new WorldPoint(3233, 3423, 0), "Varrock archery store"), + new AnagramClue("FORLUN", "Runolf", new WorldPoint(2512, 10256, 0), "Miscellania & Etceteria Dungeon"), + new AnagramClue("GOBLIN KERN", "King Bolren", new WorldPoint(2541, 3170, 0), "Tree Gnome Village"), + new AnagramClue("GOT A BOY", "Gabooty", new WorldPoint(2790, 3066, 0), "Centre of Tai Bwo Wannai", "How many buildings are in the village?", "11"), + new AnagramClue("GOBLETS ODD TOES", "Otto Godblessed", new WorldPoint(2501, 3487, 0), "Otto's Grotto", "How many types of dragon are there beneath the whirlpool's cavern?", "2"), + new AnagramClue("HALT US", "Luthas", new WorldPoint(2938, 3152, 0), "Banana plantation, Karamja"), + new AnagramClue("HEORIC", "Eohric", new WorldPoint(2900, 3565, 0), "Top floor of Burthorpe Castle", "King Arthur and Merlin sit down at the Round Table with 8 knights. How many degrees does each get?", "36"), + new AnagramClue("HIS PHOR", "Horphis", new WorldPoint(1639, 3812, 0), "Arceuus Library, Zeah", "On a scale of 1-10, how helpful is Logosia?", "1"), + new AnagramClue("I AM SIR", "Marisi", new WorldPoint(1737, 3557, 0), "Allotment patch, South of Hosidius chapel", "How many cities form the Kingdom of Great Kourend?", "5"), + new AnagramClue("ICY FE", "Fycie", new WorldPoint(2630, 2997, 0), "East Feldip Hills"), + new AnagramClue("I DOOM ICON INN", "Dominic Onion", new WorldPoint(2609, 3116, 0), "Nightmare Zone", "How many reward points does a herb box cost?", "9,500"), + new AnagramClue("I EVEN", "Nieve", new WorldPoint(2432, 3422, 0), "The slayer master in Gnome Stronghold", "How many farming patches are there in Gnome stronghold?", "2"), + new AnagramClue("IM N ZEZIM", "Immenizz", new WorldPoint(2592, 4324, 0), "The Imp inside Puro-Puro"), + new AnagramClue("KAY SIR", "Sir Kay", new WorldPoint(2760, 3496, 0), "The courtyard in Camelot Castle", "How many fountains are there within the grounds of Camelot castle?", "6"), + new AnagramClue("LEAKEY", "Kaylee", new WorldPoint(2957, 3370, 0), "Rising Sun Inn in Falador", "How many chairs are there in the Rising Sun?", "18"), + new AnagramClue("LARK IN DOG", "King Roald", new WorldPoint(3220, 3476, 0), "Ground floor of Varrock castle", "How many bookcases are there in the palace library?", "24"), + new AnagramClue("LOW LAG", "Gallow", new WorldPoint(1805, 3566, 0), "Vinery in the Great Kourend", "How many vine patches can you find in this vinery?", "12"), + new AnagramClue("LADDER MEMO GUV", "Guard Vemmeldo", new WorldPoint(2447, 3418, 1), "Gnome Stronghold Bank", "How many magic trees can you find inside the Gnome Stronghold?", "3"), + new AnagramClue("MAL IN TAU", "Luminata", new WorldPoint(3508, 3237, 0), "Near Burgh de Rott entrance"), + new AnagramClue("MACHETE CLAM", "Cam the Camel", new WorldPoint(3300, 3231, 0), "Outside Duel Arena", "How many items can carry water in Gielinor?", "6"), + new AnagramClue("ME IF", "Femi", new WorldPoint(2461, 3382, 0), "Gates of Tree Gnome Stronghold"), + new AnagramClue("MOLD LA RAN", "Old Man Ral", new WorldPoint(3602, 3209, 0), "Meiyerditch"), + new AnagramClue("MOTHERBOARD", "Brother Omad", new WorldPoint(2606, 3211, 0), "Monastery south of Ardougne", "What is the next number? 12, 13, 15, 17, 111, 113, 117, 119, 123....?", "129"), + new AnagramClue("MUS KIL READER", "Radimus Erkle", new WorldPoint(2726, 3368, 0), "Legends' Guild"), + new AnagramClue("MY MANGLE LAL", "Lammy Langle", new WorldPoint(1688, 3540, 0), "Hosidius spirit tree patch"), + new AnagramClue("NO OWNER", "Oronwen", new WorldPoint(1162, 3178, 0), "Lletya Seamstress shop in Lletya", "What is the minimum amount of quest points required to reach Lletya?", "20"), + new AnagramClue("NOD MED", "Edmond", new WorldPoint(2566, 3332, 0), "Behind the most NW house in East Ardougne", "How many pigeon cages are there around the back of Jerico's house?", "3"), + new AnagramClue("O BIRDZ A ZANY EN PC", "Cap'n Izzy No-Beard", new WorldPoint(2807, 3191, 0), "Brimhaven Agility Arena", "How many Banana Trees are there in the plantation?", "33"), + new AnagramClue("OK CO", "Cook", new WorldPoint(3207, 3214, 0), "Ground floor of Lumbridge Castle", "How many cannons does Lumbridge Castle have?", "9"), + new AnagramClue("OUR OWN NEEDS", "Nurse Wooned", new WorldPoint(1511, 3619, 0), "Shayzien Infirmary", "How many wounded soldiers are there in the camp?", "16"), + new AnagramClue("PACINNG A TAIE", "Captain Ginea", new WorldPoint(1504, 3632, 0), "Tent east of Shayzien Encampment war tent", "1 soldier can deal with 6 lizardmen. How many soldiers do we need for an army of 678 lizardmen?", "113"), + new AnagramClue("PEAK REFLEX", "Flax keeper", new WorldPoint(2744, 3444, 0), "Flax field south of Seers Village", "If I have 1014 flax, and I spin a third of them into bowstring, how many flax do I have left?", "676"), + new AnagramClue("PEATY PERT", "Party Pete", new WorldPoint(3047, 3376, 0), "Falador Party Room"), + new AnagramClue("QUIT HORRIBLE TYRANT", "Brother Tranquility", new WorldPoint(3681, 2963, 0), "Mos Le'Harmless or Harmony Island", "If I have 49 bottles of rum to share between 7 pirates, how many would each pirate get?", "7"), + new AnagramClue("QUE SIR", "Squire", new WorldPoint(2975, 3343, 0), "Falador Castle Courtyard", "White knights are superior to black knights. 2 white knights can handle 3 black knights. How many knights do we need for an army of 981 black knights?", "654"), + new AnagramClue("R AK MI", "Karim", new WorldPoint(3273, 3181, 0), "Al Kharid Kebab shop", "I have 16 kebabs, I eat one myself and then share the rest equally between 3 friends. How many do they have each?", "5"), + new AnagramClue("RAT MAT WITHIN", "Martin Thwait", new WorldPoint(2906, 3537, 0), "Rogues' Den", "How many natural fires burn in Rogue's Den?", "2"), + new AnagramClue("RATAI", "Taria", new WorldPoint(2940, 3223, 0), "Rimmington bush patch", "How many buildings are there in Rimmington?", "7"), + new AnagramClue("R SLICER", "Clerris", new WorldPoint(1761, 3850, 0), "Arceuus mine, Zeah", "If I have 1,000 blood runes, and cast 131 ice barrage spells, how many blood runes do I have left?", "738"), + new AnagramClue("RIP MAUL", "Primula", new WorldPoint(2454, 2853, 1), "Myth's Guild, first floor"), + new AnagramClue("SAND NUT", "Dunstan", new WorldPoint(2919, 3574, 0), "Anvil in north east Burthorpe", "How much smithing experience does one receive for smelting a blurite bar?", "8"), + new AnagramClue("SLAM DUSTER GRAIL", "Guildmaster Lars", new WorldPoint(1649, 3498, 0), "Woodcutting guild, Zeah"), + new AnagramClue("SLIDE WOMAN", "Wise Old Man", new WorldPoint(3088, 3253, 0), "Draynor Village", "How many bookcases are in the Wise Old Man's house?", "28"), + new AnagramClue("SNAKES SO I SAIL", "Lisse Isaakson", new WorldPoint(2351, 3801, 0), "Neitiznot", "How many arctic logs are required to make a large fremennik round shield?", "2"), + new AnagramClue("TAMED ROCKS", "Dockmaster", new WorldPoint(1822, 3739, 0), "Port Piscarilius, NE of General store", "What is the cube root of 125?", "5"), + new AnagramClue("TEN WIGS ON", "Wingstone", new WorldPoint(3389, 2877, 0), "Between Nardah & Agility Pyramid"), + new AnagramClue("THICKNO", "Hickton", new WorldPoint(2822, 3442, 0), "Catherby fletching shop", "How many ranges are there in Catherby?", "2"), + new AnagramClue("TWENTY CURE IRON", "New Recruit Tony", new WorldPoint(1503, 3553, 0), "Shayzien Graveyard"), + new AnagramClue("UNLEASH NIGHT MIST", "Sigli the Huntsman", new WorldPoint(2660, 3654, 0), "Rellekka", "What is the combined slayer requirement of every monster in the slayer cave?", "302"), + new AnagramClue("VESTE", "Steve", new WorldPoint(2432, 3423, 0), "Upstairs Wyvern Area or Stronghold Slayer Cave", "How many farming patches are there in Gnome stronghold?", "2"), + new AnagramClue("VEIL VEDA", "Evil Dave", new WorldPoint(3079, 9892, 0), "Doris' basement, Edgeville", "What is 333 multiplied by 2?", "666"), + new AnagramClue("WOO AN EGG KIWI", "Awowogei", ObjectID.AWOWOGEI, new WorldPoint(2802, 2765, 0), "Ape Atoll", "If I have 303 bananas, and share them between 31 friends evenly, only handing out full bananas. How many will I have left over?", "24"), + new AnagramClue("MAJORS LAVA BADS AIR", "Ambassador Alvijar", new WorldPoint(2736, 5351, 1), "Dorgesh-Kaan, NE Middle Level", "Double the miles before the initial Dorgeshuun veteran.", "2505"), + new AnagramClue("AN EARL", "Ranael", new WorldPoint(3315, 3163, 0), "Al Kharid skirt shop"), + new AnagramClue("CARPET AHOY", "Apothecary", new WorldPoint(3195, 3404, 0), "Southwest Varrock"), + new AnagramClue("DISORDER", "Sedridor", new WorldPoint(3102, 9570, 0), "Wizards' Tower basement"), + new AnagramClue("I CORD", "Doric", new WorldPoint(2951, 3450, 0), "North of Falador"), + new AnagramClue("IN BAR", "Brian", new WorldPoint(3026, 3246, 0), "Port Sarim battleaxe shop"), + new AnagramClue("RAIN COVE", "Veronica", new WorldPoint(3110, 3330, 0), "Outside Draynor Manor"), + new AnagramClue("RUG DETER", "Gertrude", new WorldPoint(3151, 3412, 0), "West of Varrock, south of the Cooks' Guild"), + new AnagramClue("SIR SHARE RED", "Hairdresser", new WorldPoint(2944, 3381, 0), "Western Falador"), + new AnagramClue("TAUNT ROOF", "Fortunato", new WorldPoint(3080, 3250, 0), "Draynor Village Market"), + new AnagramClue("HICK JET", "Jethick", new WorldPoint(2541, 3305, 0), "West Ardougne", "How many graves are there in the city graveyard?", "38"), + new AnagramClue("RUE GO", "Goreu", new WorldPoint(2335, 3162, 0), "Lletya"), + new AnagramClue("BRUCIE CATNAP", "Captain Bruce", new WorldPoint(1520, 3558, 0), "Graveyard of Heroes"), + new AnagramClue("UESNKRL NRIEDDO", "Drunken soldier", new WorldPoint(1551, 3565, 0), "Shayzien pub", "If 13 Shayzien Soldiers kill 46 Lizardmen each in a day, how many Lizardmen have they killed in total in a single day?", "598") ); private final String text; @@ -788,8 +161,29 @@ public class AnagramClue extends ClueScroll implements TextClueScroll, NpcClueSc private final String question; @Nullable private final String answer; - @Builder.Default - private final int objectId = -1; + private int objectId; + + private AnagramClue(String text, String npc, WorldPoint location, String area) + { + this(text, npc, location, area, null, null); + } + + private AnagramClue(String text, String npc, WorldPoint location, String area, @Nullable String question, @Nullable String answer) + { + this.text = text; + this.npc = npc; + this.location = location; + this.area = area; + this.question = question; + this.answer = answer; + this.objectId = -1; + } + + private AnagramClue(String text, String npc, int objectId, WorldPoint location, String area, String question, String answer) + { + this(text, npc, location, area, question, answer); + this.objectId = objectId; + } @Override public void makeOverlayHint(PanelComponent panelComponent, ClueScrollPlugin plugin) @@ -867,12 +261,12 @@ public class AnagramClue extends ClueScroll implements TextClueScroll, NpcClueSc @Override public String[] getNpcs() { - return new String[]{npc}; + return new String[] {npc}; } @Override public int[] getObjectIds() { - return new int[]{objectId}; + return new int[] {objectId}; } } From 22c02e4055722db427a7e1035f491e60b6f2c537 Mon Sep 17 00:00:00 2001 From: Adam Date: Sun, 16 Jan 2022 18:40:22 -0500 Subject: [PATCH 20/51] anagram clue: use builder pattern --- .../cluescrolls/clues/AnagramClue.java | 851 +++++++++++++++--- 1 file changed, 724 insertions(+), 127 deletions(-) diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/clues/AnagramClue.java b/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/clues/AnagramClue.java index 8a35abd738..33cc38e477 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/clues/AnagramClue.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/clues/AnagramClue.java @@ -24,11 +24,12 @@ */ package net.runelite.client.plugins.cluescrolls.clues; -import com.google.common.collect.ImmutableSet; +import com.google.common.collect.ImmutableList; import java.awt.Color; import java.awt.Graphics2D; -import java.util.Set; +import java.util.List; import javax.annotation.Nullable; +import lombok.Builder; import lombok.Getter; import net.runelite.api.NPC; import net.runelite.api.ObjectID; @@ -46,111 +47,728 @@ import net.runelite.client.ui.overlay.components.PanelComponent; import net.runelite.client.ui.overlay.components.TitleComponent; @Getter +@Builder public class AnagramClue extends ClueScroll implements TextClueScroll, NpcClueScroll, ObjectClueScroll { private static final String ANAGRAM_TEXT = "This anagram reveals who to speak to next: "; private static final String ANAGRAM_TEXT_BEGINNER = "The anagram reveals who to speak to next: "; - private static final Set CLUES = ImmutableSet.of( - new AnagramClue("A BAKER", "Baraek", new WorldPoint(3217, 3434, 0), "Varrock square", "How many stalls are there in Varrock Square?", "5"), - new AnagramClue("A BASIC ANTI POT", "Captain Tobias", new WorldPoint(3026, 3216, 0), "Port Sarim", "How many ships are there docked at Port Sarim currently?", "6"), - new AnagramClue("A ELF KNOWS", "Snowflake", new WorldPoint(2872, 3934, 0), "Weiss"), - new AnagramClue("A HEART", "Aretha", new WorldPoint(1814, 3851, 0), "Soul altar", "32 - 5x = 22, what is x?", "2"), - new AnagramClue("AHA JAR", "Jaraah", new WorldPoint(3359, 3276, 0), "Duel Arena hospital"), - new AnagramClue("ARC O LINE", "Caroline", new WorldPoint(2715, 3302, 0), "North Witchaven next to the row boat", "How many fishermen are there on the fishing platform?", "11"), - new AnagramClue("ARE COL", "Oracle", new WorldPoint(3013, 3501, 0), "Ice Mountain West of Edgeville", "If x is 15 and y is 3 what is 3x + y?", "48"), - new AnagramClue("ARMCHAIR THE PELT", "Charlie the Tramp", new WorldPoint(3209, 3392, 0), "South entrance of Varrock", "How many coins would I have if I have 0 coins and attempt to buy 10 loaves of bread for 3 coins each?", "0"), - new AnagramClue("AT HERG", "Regath", new WorldPoint(1719, 3723, 0), "General Store, Arceuus, Zeah", "What is -5 to the power of 2?", "25"), - new AnagramClue("A BAS", "Saba", new WorldPoint(2858, 3577, 0), "Death Plateau"), - new AnagramClue("AREA CHEF TREK", "Father Aereck", new WorldPoint(3243, 3208, 0), "Lumbridge Church", "How many gravestones are in the church graveyard?", "19 or 20"), - new AnagramClue("BAIL TRIMS", "Brimstail", new WorldPoint(2402, 3419, 0), "West of Stronghold Slayer Cave"), - new AnagramClue("BAKER CLIMB", "Brambickle", new WorldPoint(2783, 3861, 0), "Trollweiss mountain"), - new AnagramClue("BLUE GRIM GUIDED", "Lumbridge Guide", new WorldPoint(3238, 3220, 0), "Lumbridge"), - new AnagramClue("BY LOOK", "Bolkoy", new WorldPoint(2529, 3162, 0), "Tree Gnome Village general store", "How many flowers are there in the clearing below this platform?", "13"), - new AnagramClue("CALAMARI MADE MUD", "Madame Caldarium", new WorldPoint(2553, 2868, 0), "Corsair Cove", "What is 3(5-3)?", "6"), - new AnagramClue("CAR IF ICES", "Sacrifice", new WorldPoint(2209, 3056, 0), "Zul-Andra"), - new AnagramClue("CAREER IN MOON", "Oneiromancer", new WorldPoint(2150, 3866, 0), "Astral altar", "How many Suqah inhabit Lunar isle?", "25"), - new AnagramClue("CLASH ION", "Nicholas", new WorldPoint(1841, 3803, 0), "North of Port Piscarilius fishing shop", "How many windows are in Tynan's shop?", "4"), - new AnagramClue("C ON GAME HOC", "Gnome Coach", new WorldPoint(2395, 3486, 0), "Gnome Ball course", "How many gnomes on the Gnome ball field have red patches on their uniforms?", "6"), - new AnagramClue("COOL NERD", "Old crone", new WorldPoint(3462, 3557, 0), "East of the Slayer Tower", "What is the combined combat level of each species that live in Slayer tower?", "619"), - new AnagramClue("COPPER ORE CRYPTS", "Prospector Percy", new WorldPoint(3061, 3377, 0), "Motherlode Mine", "During a party, everyone shook hands with everybody else. There were 66 handshakes. How many people were at the party?", "12"), - new AnagramClue("DARN DRAKE", "Daer Krand", new WorldPoint(3728, 3302, 0), "Sisterhood Sanctuary (Slepe Dungeon, northeast of Nightmare Arena)"), - new AnagramClue("DED WAR", "Edward", new WorldPoint(3284, 3943, 0), "Inside Rogue's Castle"), - new AnagramClue("DEKAGRAM", "Dark mage", new WorldPoint(3039, 4835, 0), "Centre of the Abyss", "How many rifts are found here in the abyss?", "13"), - new AnagramClue("DO SAY MORE", "Doomsayer", new WorldPoint(3230, 3230, 0), "East of Lumbridge Castle", "What is 40 divided by 1/2 plus 15?", "95"), - new AnagramClue("DIM THARN", "Mandrith", new WorldPoint(3182, 3946, 0), "Wilderness Resource Area"), - new AnagramClue("DR HITMAN", "Mandrith", new WorldPoint(3182, 3946, 0), "Wilderness Resource Area", "How many scorpions live under the pit?", "28"), - new AnagramClue("DR WARDEN FUNK", "Drunken Dwarf", new WorldPoint(2913, 10221, 0), "East Side of Keldagrim"), - new AnagramClue("DRAGONS LAMENT", "Strange Old Man", new WorldPoint(3564, 3288, 0), "Barrows", "One pipe fills a barrel in 1 hour while another pipe can fill the same barrel in 2 hours. How many minutes will it take to fill the tank if both pipes are used?", "40"), - new AnagramClue("DT RUN B", "Brundt the Chieftain", new WorldPoint(2658, 3670, 0), "Rellekka, main hall", "How many people are waiting for the next bard to perform?", "4"), - new AnagramClue("DUO PLUG", "Dugopul", new WorldPoint(2803, 2744, 0), "Graveyard on Ape Atoll"), - new AnagramClue("EEK ZERO OP", "Zoo keeper", new WorldPoint(2613, 3269, 0), "Ardougne Zoo", "How many animals in total are there in the zoo?", "40"), - new AnagramClue("EL OW", "Lowe", new WorldPoint(3233, 3423, 0), "Varrock archery store"), - new AnagramClue("FORLUN", "Runolf", new WorldPoint(2512, 10256, 0), "Miscellania & Etceteria Dungeon"), - new AnagramClue("GOBLIN KERN", "King Bolren", new WorldPoint(2541, 3170, 0), "Tree Gnome Village"), - new AnagramClue("GOT A BOY", "Gabooty", new WorldPoint(2790, 3066, 0), "Centre of Tai Bwo Wannai", "How many buildings are in the village?", "11"), - new AnagramClue("GOBLETS ODD TOES", "Otto Godblessed", new WorldPoint(2501, 3487, 0), "Otto's Grotto", "How many types of dragon are there beneath the whirlpool's cavern?", "2"), - new AnagramClue("HALT US", "Luthas", new WorldPoint(2938, 3152, 0), "Banana plantation, Karamja"), - new AnagramClue("HEORIC", "Eohric", new WorldPoint(2900, 3565, 0), "Top floor of Burthorpe Castle", "King Arthur and Merlin sit down at the Round Table with 8 knights. How many degrees does each get?", "36"), - new AnagramClue("HIS PHOR", "Horphis", new WorldPoint(1639, 3812, 0), "Arceuus Library, Zeah", "On a scale of 1-10, how helpful is Logosia?", "1"), - new AnagramClue("I AM SIR", "Marisi", new WorldPoint(1737, 3557, 0), "Allotment patch, South of Hosidius chapel", "How many cities form the Kingdom of Great Kourend?", "5"), - new AnagramClue("ICY FE", "Fycie", new WorldPoint(2630, 2997, 0), "East Feldip Hills"), - new AnagramClue("I DOOM ICON INN", "Dominic Onion", new WorldPoint(2609, 3116, 0), "Nightmare Zone", "How many reward points does a herb box cost?", "9,500"), - new AnagramClue("I EVEN", "Nieve", new WorldPoint(2432, 3422, 0), "The slayer master in Gnome Stronghold", "How many farming patches are there in Gnome stronghold?", "2"), - new AnagramClue("IM N ZEZIM", "Immenizz", new WorldPoint(2592, 4324, 0), "The Imp inside Puro-Puro"), - new AnagramClue("KAY SIR", "Sir Kay", new WorldPoint(2760, 3496, 0), "The courtyard in Camelot Castle", "How many fountains are there within the grounds of Camelot castle?", "6"), - new AnagramClue("LEAKEY", "Kaylee", new WorldPoint(2957, 3370, 0), "Rising Sun Inn in Falador", "How many chairs are there in the Rising Sun?", "18"), - new AnagramClue("LARK IN DOG", "King Roald", new WorldPoint(3220, 3476, 0), "Ground floor of Varrock castle", "How many bookcases are there in the palace library?", "24"), - new AnagramClue("LOW LAG", "Gallow", new WorldPoint(1805, 3566, 0), "Vinery in the Great Kourend", "How many vine patches can you find in this vinery?", "12"), - new AnagramClue("LADDER MEMO GUV", "Guard Vemmeldo", new WorldPoint(2447, 3418, 1), "Gnome Stronghold Bank", "How many magic trees can you find inside the Gnome Stronghold?", "3"), - new AnagramClue("MAL IN TAU", "Luminata", new WorldPoint(3508, 3237, 0), "Near Burgh de Rott entrance"), - new AnagramClue("MACHETE CLAM", "Cam the Camel", new WorldPoint(3300, 3231, 0), "Outside Duel Arena", "How many items can carry water in Gielinor?", "6"), - new AnagramClue("ME IF", "Femi", new WorldPoint(2461, 3382, 0), "Gates of Tree Gnome Stronghold"), - new AnagramClue("MOLD LA RAN", "Old Man Ral", new WorldPoint(3602, 3209, 0), "Meiyerditch"), - new AnagramClue("MOTHERBOARD", "Brother Omad", new WorldPoint(2606, 3211, 0), "Monastery south of Ardougne", "What is the next number? 12, 13, 15, 17, 111, 113, 117, 119, 123....?", "129"), - new AnagramClue("MUS KIL READER", "Radimus Erkle", new WorldPoint(2726, 3368, 0), "Legends' Guild"), - new AnagramClue("MY MANGLE LAL", "Lammy Langle", new WorldPoint(1688, 3540, 0), "Hosidius spirit tree patch"), - new AnagramClue("NO OWNER", "Oronwen", new WorldPoint(1162, 3178, 0), "Lletya Seamstress shop in Lletya", "What is the minimum amount of quest points required to reach Lletya?", "20"), - new AnagramClue("NOD MED", "Edmond", new WorldPoint(2566, 3332, 0), "Behind the most NW house in East Ardougne", "How many pigeon cages are there around the back of Jerico's house?", "3"), - new AnagramClue("O BIRDZ A ZANY EN PC", "Cap'n Izzy No-Beard", new WorldPoint(2807, 3191, 0), "Brimhaven Agility Arena", "How many Banana Trees are there in the plantation?", "33"), - new AnagramClue("OK CO", "Cook", new WorldPoint(3207, 3214, 0), "Ground floor of Lumbridge Castle", "How many cannons does Lumbridge Castle have?", "9"), - new AnagramClue("OUR OWN NEEDS", "Nurse Wooned", new WorldPoint(1511, 3619, 0), "Shayzien Infirmary", "How many wounded soldiers are there in the camp?", "16"), - new AnagramClue("PACINNG A TAIE", "Captain Ginea", new WorldPoint(1504, 3632, 0), "Tent east of Shayzien Encampment war tent", "1 soldier can deal with 6 lizardmen. How many soldiers do we need for an army of 678 lizardmen?", "113"), - new AnagramClue("PEAK REFLEX", "Flax keeper", new WorldPoint(2744, 3444, 0), "Flax field south of Seers Village", "If I have 1014 flax, and I spin a third of them into bowstring, how many flax do I have left?", "676"), - new AnagramClue("PEATY PERT", "Party Pete", new WorldPoint(3047, 3376, 0), "Falador Party Room"), - new AnagramClue("QUIT HORRIBLE TYRANT", "Brother Tranquility", new WorldPoint(3681, 2963, 0), "Mos Le'Harmless or Harmony Island", "If I have 49 bottles of rum to share between 7 pirates, how many would each pirate get?", "7"), - new AnagramClue("QUE SIR", "Squire", new WorldPoint(2975, 3343, 0), "Falador Castle Courtyard", "White knights are superior to black knights. 2 white knights can handle 3 black knights. How many knights do we need for an army of 981 black knights?", "654"), - new AnagramClue("R AK MI", "Karim", new WorldPoint(3273, 3181, 0), "Al Kharid Kebab shop", "I have 16 kebabs, I eat one myself and then share the rest equally between 3 friends. How many do they have each?", "5"), - new AnagramClue("RAT MAT WITHIN", "Martin Thwait", new WorldPoint(2906, 3537, 0), "Rogues' Den", "How many natural fires burn in Rogue's Den?", "2"), - new AnagramClue("RATAI", "Taria", new WorldPoint(2940, 3223, 0), "Rimmington bush patch", "How many buildings are there in Rimmington?", "7"), - new AnagramClue("R SLICER", "Clerris", new WorldPoint(1761, 3850, 0), "Arceuus mine, Zeah", "If I have 1,000 blood runes, and cast 131 ice barrage spells, how many blood runes do I have left?", "738"), - new AnagramClue("RIP MAUL", "Primula", new WorldPoint(2454, 2853, 1), "Myth's Guild, first floor"), - new AnagramClue("SAND NUT", "Dunstan", new WorldPoint(2919, 3574, 0), "Anvil in north east Burthorpe", "How much smithing experience does one receive for smelting a blurite bar?", "8"), - new AnagramClue("SLAM DUSTER GRAIL", "Guildmaster Lars", new WorldPoint(1649, 3498, 0), "Woodcutting guild, Zeah"), - new AnagramClue("SLIDE WOMAN", "Wise Old Man", new WorldPoint(3088, 3253, 0), "Draynor Village", "How many bookcases are in the Wise Old Man's house?", "28"), - new AnagramClue("SNAKES SO I SAIL", "Lisse Isaakson", new WorldPoint(2351, 3801, 0), "Neitiznot", "How many arctic logs are required to make a large fremennik round shield?", "2"), - new AnagramClue("TAMED ROCKS", "Dockmaster", new WorldPoint(1822, 3739, 0), "Port Piscarilius, NE of General store", "What is the cube root of 125?", "5"), - new AnagramClue("TEN WIGS ON", "Wingstone", new WorldPoint(3389, 2877, 0), "Between Nardah & Agility Pyramid"), - new AnagramClue("THICKNO", "Hickton", new WorldPoint(2822, 3442, 0), "Catherby fletching shop", "How many ranges are there in Catherby?", "2"), - new AnagramClue("TWENTY CURE IRON", "New Recruit Tony", new WorldPoint(1503, 3553, 0), "Shayzien Graveyard"), - new AnagramClue("UNLEASH NIGHT MIST", "Sigli the Huntsman", new WorldPoint(2660, 3654, 0), "Rellekka", "What is the combined slayer requirement of every monster in the slayer cave?", "302"), - new AnagramClue("VESTE", "Steve", new WorldPoint(2432, 3423, 0), "Upstairs Wyvern Area or Stronghold Slayer Cave", "How many farming patches are there in Gnome stronghold?", "2"), - new AnagramClue("VEIL VEDA", "Evil Dave", new WorldPoint(3079, 9892, 0), "Doris' basement, Edgeville", "What is 333 multiplied by 2?", "666"), - new AnagramClue("WOO AN EGG KIWI", "Awowogei", ObjectID.AWOWOGEI, new WorldPoint(2802, 2765, 0), "Ape Atoll", "If I have 303 bananas, and share them between 31 friends evenly, only handing out full bananas. How many will I have left over?", "24"), - new AnagramClue("MAJORS LAVA BADS AIR", "Ambassador Alvijar", new WorldPoint(2736, 5351, 1), "Dorgesh-Kaan, NE Middle Level", "Double the miles before the initial Dorgeshuun veteran.", "2505"), - new AnagramClue("AN EARL", "Ranael", new WorldPoint(3315, 3163, 0), "Al Kharid skirt shop"), - new AnagramClue("CARPET AHOY", "Apothecary", new WorldPoint(3195, 3404, 0), "Southwest Varrock"), - new AnagramClue("DISORDER", "Sedridor", new WorldPoint(3102, 9570, 0), "Wizards' Tower basement"), - new AnagramClue("I CORD", "Doric", new WorldPoint(2951, 3450, 0), "North of Falador"), - new AnagramClue("IN BAR", "Brian", new WorldPoint(3026, 3246, 0), "Port Sarim battleaxe shop"), - new AnagramClue("RAIN COVE", "Veronica", new WorldPoint(3110, 3330, 0), "Outside Draynor Manor"), - new AnagramClue("RUG DETER", "Gertrude", new WorldPoint(3151, 3412, 0), "West of Varrock, south of the Cooks' Guild"), - new AnagramClue("SIR SHARE RED", "Hairdresser", new WorldPoint(2944, 3381, 0), "Western Falador"), - new AnagramClue("TAUNT ROOF", "Fortunato", new WorldPoint(3080, 3250, 0), "Draynor Village Market"), - new AnagramClue("HICK JET", "Jethick", new WorldPoint(2541, 3305, 0), "West Ardougne", "How many graves are there in the city graveyard?", "38"), - new AnagramClue("RUE GO", "Goreu", new WorldPoint(2335, 3162, 0), "Lletya"), - new AnagramClue("BRUCIE CATNAP", "Captain Bruce", new WorldPoint(1520, 3558, 0), "Graveyard of Heroes"), - new AnagramClue("UESNKRL NRIEDDO", "Drunken soldier", new WorldPoint(1551, 3565, 0), "Shayzien pub", "If 13 Shayzien Soldiers kill 46 Lizardmen each in a day, how many Lizardmen have they killed in total in a single day?", "598") + private static final List CLUES = ImmutableList.of( + AnagramClue.builder() + .text("A BAKER") + .npc("Baraek") + .location(new WorldPoint(3217, 3434, 0)) + .area("Varrock square") + .question("How many stalls are there in Varrock Square?") + .answer("5") + .build(), + AnagramClue.builder() + .text("A BASIC ANTI POT") + .npc("Captain Tobias") + .location(new WorldPoint(3026, 3216, 0)) + .area("Port Sarim") + .question("How many ships are there docked at Port Sarim currently?") + .answer("6") + .build(), + AnagramClue.builder() + .text("A ELF KNOWS") + .npc("Snowflake") + .location(new WorldPoint(2872, 3934, 0)) + .area("Weiss") + .build(), + AnagramClue.builder() + .text("A HEART") + .npc("Aretha") + .location(new WorldPoint(1814, 3851, 0)) + .area("Soul altar") + .question("32 - 5x = 22, what is x?") + .answer("2") + .build(), + AnagramClue.builder() + .text("AHA JAR") + .npc("Jaraah") + .location(new WorldPoint(3359, 3276, 0)) + .area("Duel Arena hospital") + .build(), + AnagramClue.builder() + .text("ARC O LINE") + .npc("Caroline") + .location(new WorldPoint(2715, 3302, 0)) + .area("North Witchaven next to the row boat") + .question("How many fishermen are there on the fishing platform?") + .answer("11") + .build(), + AnagramClue.builder() + .text("ARE COL") + .npc("Oracle") + .location(new WorldPoint(3013, 3501, 0)) + .area("Ice Mountain West of Edgeville") + .question("If x is 15 and y is 3 what is 3x + y?") + .answer("48") + .build(), + AnagramClue.builder() + .text("ARMCHAIR THE PELT") + .npc("Charlie the Tramp") + .location(new WorldPoint(3209, 3392, 0)) + .area("South entrance of Varrock") + .question("How many coins would I have if I have 0 coins and attempt to buy 10 loaves of bread for 3 coins each?") + .answer("0") + .build(), + AnagramClue.builder() + .text("AT HERG") + .npc("Regath") + .location(new WorldPoint(1719, 3723, 0)) + .area("General Store, Arceuus, Zeah") + .question("What is -5 to the power of 2?") + .answer("25") + .build(), + AnagramClue.builder() + .text("A BAS") + .npc("Saba") + .location(new WorldPoint(2858, 3577, 0)) + .area("Death Plateau") + .build(), + AnagramClue.builder() + .text("AREA CHEF TREK") + .npc("Father Aereck") + .location(new WorldPoint(3243, 3208, 0)) + .area("Lumbridge Church") + .question("How many gravestones are in the church graveyard?") + .answer("19 or 20") + .build(), + AnagramClue.builder() + .text("BAIL TRIMS") + .npc("Brimstail") + .location(new WorldPoint(2402, 3419, 0)) + .area("West of Stronghold Slayer Cave") + .build(), + AnagramClue.builder() + .text("BAKER CLIMB") + .npc("Brambickle") + .location(new WorldPoint(2783, 3861, 0)) + .area("Trollweiss mountain") + .build(), + AnagramClue.builder() + .text("BLUE GRIM GUIDED") + .npc("Lumbridge Guide") + .location(new WorldPoint(3238, 3220, 0)) + .area("Lumbridge") + .build(), + AnagramClue.builder() + .text("BY LOOK") + .npc("Bolkoy") + .location(new WorldPoint(2529, 3162, 0)) + .area("Tree Gnome Village general store") + .question("How many flowers are there in the clearing below this platform?") + .answer("13") + .build(), + AnagramClue.builder() + .text("CALAMARI MADE MUD") + .npc("Madame Caldarium") + .location(new WorldPoint(2553, 2868, 0)) + .area("Corsair Cove") + .question("What is 3(5-3)?") + .answer("6") + .build(), + AnagramClue.builder() + .text("CAR IF ICES") + .npc("Sacrifice") + .location(new WorldPoint(2209, 3056, 0)) + .area("Zul-Andra") + .build(), + AnagramClue.builder() + .text("CAREER IN MOON") + .npc("Oneiromancer") + .location(new WorldPoint(2150, 3866, 0)) + .area("Astral altar") + .question("How many Suqah inhabit Lunar isle?") + .answer("25") + .build(), + AnagramClue.builder() + .text("CLASH ION") + .npc("Nicholas") + .location(new WorldPoint(1841, 3803, 0)) + .area("North of Port Piscarilius fishing shop") + .question("How many windows are in Tynan's shop?") + .answer("4") + .build(), + AnagramClue.builder() + .text("C ON GAME HOC") + .npc("Gnome Coach") + .location(new WorldPoint(2395, 3486, 0)) + .area("Gnome Ball course") + .question("How many gnomes on the Gnome ball field have red patches on their uniforms?") + .answer("6") + .build(), + AnagramClue.builder() + .text("COOL NERD") + .npc("Old crone") + .location(new WorldPoint(3462, 3557, 0)) + .area("East of the Slayer Tower") + .question("What is the combined combat level of each species that live in Slayer tower?") + .answer("619") + .build(), + AnagramClue.builder() + .text("COPPER ORE CRYPTS") + .npc("Prospector Percy") + .location(new WorldPoint(3061, 3377, 0)) + .area("Motherlode Mine") + .question("During a party, everyone shook hands with everybody else. There were 66 handshakes. How many people were at the party?") + .answer("12") + .build(), + AnagramClue.builder() + .text("DARN DRAKE") + .npc("Daer Krand") + .location(new WorldPoint(3728, 3302, 0)) + .area("Sisterhood Sanctuary (Slepe Dungeon, northeast of Nightmare Arena)") + .build(), + AnagramClue.builder() + .text("DED WAR") + .npc("Edward") + .location(new WorldPoint(3284, 3943, 0)) + .area("Inside Rogue's Castle") + .build(), + AnagramClue.builder() + .text("DEKAGRAM") + .npc("Dark mage") + .location(new WorldPoint(3039, 4835, 0)) + .area("Centre of the Abyss") + .question("How many rifts are found here in the abyss?") + .answer("13") + .build(), + AnagramClue.builder() + .text("DO SAY MORE") + .npc("Doomsayer") + .location(new WorldPoint(3230, 3230, 0)) + .area("East of Lumbridge Castle") + .question("What is 40 divided by 1/2 plus 15?") + .answer("95") + .build(), + AnagramClue.builder() + .text("DIM THARN") + .npc("Mandrith") + .location(new WorldPoint(3182, 3946, 0)) + .area("Wilderness Resource Area") + .build(), + AnagramClue.builder() + .text("DR HITMAN") + .npc("Mandrith") + .location(new WorldPoint(3182, 3946, 0)) + .area("Wilderness Resource Area") + .question("How many scorpions live under the pit?") + .answer("28") + .build(), + AnagramClue.builder() + .text("DR WARDEN FUNK") + .npc("Drunken Dwarf") + .location(new WorldPoint(2913, 10221, 0)) + .area("East Side of Keldagrim") + .build(), + AnagramClue.builder() + .text("DRAGONS LAMENT") + .npc("Strange Old Man") + .location(new WorldPoint(3564, 3288, 0)) + .area("Barrows") + .question("One pipe fills a barrel in 1 hour while another pipe can fill the same barrel in 2 hours. How many minutes will it take to fill the tank if both pipes are used?") + .answer("40") + .build(), + AnagramClue.builder() + .text("DT RUN B") + .npc("Brundt the Chieftain") + .location(new WorldPoint(2658, 3670, 0)) + .area("Rellekka, main hall") + .question("How many people are waiting for the next bard to perform?") + .answer("4") + .build(), + AnagramClue.builder() + .text("DUO PLUG") + .npc("Dugopul") + .location(new WorldPoint(2803, 2744, 0)) + .area("Graveyard on Ape Atoll") + .build(), + AnagramClue.builder() + .text("EEK ZERO OP") + .npc("Zoo keeper") + .location(new WorldPoint(2613, 3269, 0)) + .area("Ardougne Zoo") + .question("How many animals in total are there in the zoo?") + .answer("40") + .build(), + AnagramClue.builder() + .text("EL OW") + .npc("Lowe") + .location(new WorldPoint(3233, 3423, 0)) + .area("Varrock archery store") + .build(), + AnagramClue.builder() + .text("FORLUN") + .npc("Runolf") + .location(new WorldPoint(2512, 10256, 0)) + .area("Miscellania & Etceteria Dungeon") + .build(), + AnagramClue.builder() + .text("GOBLIN KERN") + .npc("King Bolren") + .location(new WorldPoint(2541, 3170, 0)) + .area("Tree Gnome Village") + .build(), + AnagramClue.builder() + .text("GOT A BOY") + .npc("Gabooty") + .location(new WorldPoint(2790, 3066, 0)) + .area("Centre of Tai Bwo Wannai") + .question("How many buildings are in the village?") + .answer("11") + .build(), + AnagramClue.builder() + .text("GOBLETS ODD TOES") + .npc("Otto Godblessed") + .location(new WorldPoint(2501, 3487, 0)) + .area("Otto's Grotto") + .question("How many types of dragon are there beneath the whirlpool's cavern?") + .answer("2") + .build(), + AnagramClue.builder() + .text("HALT US") + .npc("Luthas") + .location(new WorldPoint(2938, 3152, 0)) + .area("Banana plantation, Karamja") + .build(), + AnagramClue.builder() + .text("HEORIC") + .npc("Eohric") + .location(new WorldPoint(2900, 3565, 0)) + .area("Top floor of Burthorpe Castle") + .question("King Arthur and Merlin sit down at the Round Table with 8 knights. How many degrees does each get?") + .answer("36") + .build(), + AnagramClue.builder() + .text("HIS PHOR") + .npc("Horphis") + .location(new WorldPoint(1639, 3812, 0)) + .area("Arceuus Library, Zeah") + .question("On a scale of 1-10, how helpful is Logosia?") + .answer("1") + .build(), + AnagramClue.builder() + .text("I AM SIR") + .npc("Marisi") + .location(new WorldPoint(1737, 3557, 0)) + .area("Allotment patch, South of Hosidius chapel") + .question("How many cities form the Kingdom of Great Kourend?") + .answer("5") + .build(), + AnagramClue.builder() + .text("ICY FE") + .npc("Fycie") + .location(new WorldPoint(2630, 2997, 0)) + .area("East Feldip Hills") + .build(), + AnagramClue.builder() + .text("I DOOM ICON INN") + .npc("Dominic Onion") + .location(new WorldPoint(2609, 3116, 0)) + .area("Nightmare Zone") + .question("How many reward points does a herb box cost?") + .answer("9,500") + .build(), + AnagramClue.builder() + .text("I EVEN") + .npc("Nieve") + .location(new WorldPoint(2432, 3422, 0)) + .area("The slayer master in Gnome Stronghold") + .question("How many farming patches are there in Gnome stronghold?") + .answer("2") + .build(), + AnagramClue.builder() + .text("IM N ZEZIM") + .npc("Immenizz") + .location(new WorldPoint(2592, 4324, 0)) + .area("The Imp inside Puro-Puro") + .build(), + AnagramClue.builder() + .text("KAY SIR") + .npc("Sir Kay") + .location(new WorldPoint(2760, 3496, 0)) + .area("The courtyard in Camelot Castle") + .question("How many fountains are there within the grounds of Camelot castle?") + .answer("6") + .build(), + AnagramClue.builder() + .text("LEAKEY") + .npc("Kaylee") + .location(new WorldPoint(2957, 3370, 0)) + .area("Rising Sun Inn in Falador") + .question("How many chairs are there in the Rising Sun?") + .answer("18") + .build(), + AnagramClue.builder() + .text("LARK IN DOG") + .npc("King Roald") + .location(new WorldPoint(3220, 3476, 0)) + .area("Ground floor of Varrock castle") + .question("How many bookcases are there in the palace library?") + .answer("24") + .build(), + AnagramClue.builder() + .text("LOW LAG") + .npc("Gallow") + .location(new WorldPoint(1805, 3566, 0)) + .area("Vinery in the Great Kourend") + .question("How many vine patches can you find in this vinery?") + .answer("12") + .build(), + AnagramClue.builder() + .text("LADDER MEMO GUV") + .npc("Guard Vemmeldo") + .location(new WorldPoint(2447, 3418, 1)) + .area("Gnome Stronghold Bank") + .question("How many magic trees can you find inside the Gnome Stronghold?") + .answer("3") + .build(), + AnagramClue.builder() + .text("MAL IN TAU") + .npc("Luminata") + .location(new WorldPoint(3508, 3237, 0)) + .area("Near Burgh de Rott entrance") + .build(), + AnagramClue.builder() + .text("MACHETE CLAM") + .npc("Cam the Camel") + .location(new WorldPoint(3300, 3231, 0)) + .area("Outside Duel Arena") + .question("How many items can carry water in Gielinor?") + .answer("6") + .build(), + AnagramClue.builder() + .text("ME IF") + .npc("Femi") + .location(new WorldPoint(2461, 3382, 0)) + .area("Gates of Tree Gnome Stronghold") + .build(), + AnagramClue.builder() + .text("MOLD LA RAN") + .npc("Old Man Ral") + .location(new WorldPoint(3602, 3209, 0)) + .area("Meiyerditch") + .build(), + AnagramClue.builder() + .text("MOTHERBOARD") + .npc("Brother Omad") + .location(new WorldPoint(2606, 3211, 0)) + .area("Monastery south of Ardougne") + .question("What is the next number? 12, 13, 15, 17, 111, 113, 117, 119, 123....?") + .answer("129") + .build(), + AnagramClue.builder() + .text("MUS KIL READER") + .npc("Radimus Erkle") + .location(new WorldPoint(2726, 3368, 0)) + .area("Legends' Guild") + .build(), + AnagramClue.builder() + .text("MY MANGLE LAL") + .npc("Lammy Langle") + .location(new WorldPoint(1688, 3540, 0)) + .area("Hosidius spirit tree patch") + .build(), + AnagramClue.builder() + .text("NO OWNER") + .npc("Oronwen") + .location(new WorldPoint(1162, 3178, 0)) + .area("Lletya Seamstress shop in Lletya") + .question("What is the minimum amount of quest points required to reach Lletya?") + .answer("20") + .build(), + AnagramClue.builder() + .text("NOD MED") + .npc("Edmond") + .location(new WorldPoint(2566, 3332, 0)) + .area("Behind the most NW house in East Ardougne") + .question("How many pigeon cages are there around the back of Jerico's house?") + .answer("3") + .build(), + AnagramClue.builder() + .text("O BIRDZ A ZANY EN PC") + .npc("Cap'n Izzy No-Beard") + .location(new WorldPoint(2807, 3191, 0)) + .area("Brimhaven Agility Arena") + .question("How many Banana Trees are there in the plantation?") + .answer("33") + .build(), + AnagramClue.builder() + .text("OK CO") + .npc("Cook") + .location(new WorldPoint(3207, 3214, 0)) + .area("Ground floor of Lumbridge Castle") + .question("How many cannons does Lumbridge Castle have?") + .answer("9") + .build(), + AnagramClue.builder() + .text("OUR OWN NEEDS") + .npc("Nurse Wooned") + .location(new WorldPoint(1511, 3619, 0)) + .area("Shayzien Infirmary") + .question("How many wounded soldiers are there in the camp?") + .answer("16") + .build(), + AnagramClue.builder() + .text("PACINNG A TAIE") + .npc("Captain Ginea") + .location(new WorldPoint(1504, 3632, 0)) + .area("Tent east of Shayzien Encampment war tent") + .question("1 soldier can deal with 6 lizardmen. How many soldiers do we need for an army of 678 lizardmen?") + .answer("113") + .build(), + AnagramClue.builder() + .text("PEAK REFLEX") + .npc("Flax keeper") + .location(new WorldPoint(2744, 3444, 0)) + .area("Flax field south of Seers Village") + .question("If I have 1014 flax, and I spin a third of them into bowstring, how many flax do I have left?") + .answer("676") + .build(), + AnagramClue.builder() + .text("PEATY PERT") + .npc("Party Pete") + .location(new WorldPoint(3047, 3376, 0)) + .area("Falador Party Room") + .build(), + AnagramClue.builder() + .text("QUIT HORRIBLE TYRANT") + .npc("Brother Tranquility") + .location(new WorldPoint(3681, 2963, 0)) + .area("Mos Le'Harmless or Harmony Island") + .question("If I have 49 bottles of rum to share between 7 pirates, how many would each pirate get?") + .answer("7") + .build(), + AnagramClue.builder() + .text("QUE SIR") + .npc("Squire") + .location(new WorldPoint(2975, 3343, 0)) + .area("Falador Castle Courtyard") + .question("White knights are superior to black knights. 2 white knights can handle 3 black knights. How many knights do we need for an army of 981 black knights?") + .answer("654") + .build(), + AnagramClue.builder() + .text("R AK MI") + .npc("Karim") + .location(new WorldPoint(3273, 3181, 0)) + .area("Al Kharid Kebab shop") + .question("I have 16 kebabs, I eat one myself and then share the rest equally between 3 friends. How many do they have each?") + .answer("5") + .build(), + AnagramClue.builder() + .text("RAT MAT WITHIN") + .npc("Martin Thwait") + .location(new WorldPoint(2906, 3537, 0)) + .area("Rogues' Den") + .question("How many natural fires burn in Rogue's Den?") + .answer("2") + .build(), + AnagramClue.builder() + .text("RATAI") + .npc("Taria") + .location(new WorldPoint(2940, 3223, 0)) + .area("Rimmington bush patch") + .question("How many buildings are there in Rimmington?") + .answer("7") + .build(), + AnagramClue.builder() + .text("R SLICER") + .npc("Clerris") + .location(new WorldPoint(1761, 3850, 0)) + .area("Arceuus mine, Zeah") + .question("If I have 1,000 blood runes, and cast 131 ice barrage spells, how many blood runes do I have left?") + .answer("738") + .build(), + AnagramClue.builder() + .text("RIP MAUL") + .npc("Primula") + .location(new WorldPoint(2454, 2853, 1)) + .area("Myth's Guild, first floor") + .build(), + AnagramClue.builder() + .text("SAND NUT") + .npc("Dunstan") + .location(new WorldPoint(2919, 3574, 0)) + .area("Anvil in north east Burthorpe") + .question("How much smithing experience does one receive for smelting a blurite bar?") + .answer("8") + .build(), + AnagramClue.builder() + .text("SLAM DUSTER GRAIL") + .npc("Guildmaster Lars") + .location(new WorldPoint(1649, 3498, 0)) + .area("Woodcutting guild, Zeah") + .build(), + AnagramClue.builder() + .text("SLIDE WOMAN") + .npc("Wise Old Man") + .location(new WorldPoint(3088, 3253, 0)) + .area("Draynor Village") + .question("How many bookcases are in the Wise Old Man's house?") + .answer("28") + .build(), + AnagramClue.builder() + .text("SNAKES SO I SAIL") + .npc("Lisse Isaakson") + .location(new WorldPoint(2351, 3801, 0)) + .area("Neitiznot") + .question("How many arctic logs are required to make a large fremennik round shield?") + .answer("2") + .build(), + AnagramClue.builder() + .text("TAMED ROCKS") + .npc("Dockmaster") + .location(new WorldPoint(1822, 3739, 0)) + .area("Port Piscarilius, NE of General store") + .question("What is the cube root of 125?") + .answer("5") + .build(), + AnagramClue.builder() + .text("TEN WIGS ON") + .npc("Wingstone") + .location(new WorldPoint(3389, 2877, 0)) + .area("Between Nardah & Agility Pyramid") + .build(), + AnagramClue.builder() + .text("THICKNO") + .npc("Hickton") + .location(new WorldPoint(2822, 3442, 0)) + .area("Catherby fletching shop") + .question("How many ranges are there in Catherby?") + .answer("2") + .build(), + AnagramClue.builder() + .text("TWENTY CURE IRON") + .npc("New Recruit Tony") + .location(new WorldPoint(1503, 3553, 0)) + .area("Shayzien Graveyard") + .build(), + AnagramClue.builder() + .text("UNLEASH NIGHT MIST") + .npc("Sigli the Huntsman") + .location(new WorldPoint(2660, 3654, 0)) + .area("Rellekka") + .question("What is the combined slayer requirement of every monster in the slayer cave?") + .answer("302") + .build(), + AnagramClue.builder() + .text("VESTE") + .npc("Steve") + .location(new WorldPoint(2432, 3423, 0)) + .area("Upstairs Wyvern Area or Stronghold Slayer Cave") + .question("How many farming patches are there in Gnome stronghold?") + .answer("2") + .build(), + AnagramClue.builder() + .text("VEIL VEDA") + .npc("Evil Dave") + .location(new WorldPoint(3079, 9892, 0)) + .area("Doris' basement, Edgeville") + .question("What is 333 multiplied by 2?") + .answer("666") + .build(), + AnagramClue.builder() + .text("WOO AN EGG KIWI") + .npc("Awowogei") + .objectId(ObjectID.AWOWOGEI) + .location(new WorldPoint(2802, 2765, 0)) + .area("Ape Atoll") + .question("If I have 303 bananas, and share them between 31 friends evenly, only handing out full bananas. How many will I have left over?") + .answer("24") + .build(), + AnagramClue.builder() + .text("MAJORS LAVA BADS AIR") + .npc("Ambassador Alvijar") + .location(new WorldPoint(2736, 5351, 1)) + .area("Dorgesh-Kaan, NE Middle Level") + .question("Double the miles before the initial Dorgeshuun veteran.") + .answer("2505") + .build(), + AnagramClue.builder() + .text("AN EARL") + .npc("Ranael") + .location(new WorldPoint(3315, 3163, 0)) + .area("Al Kharid skirt shop") + .build(), + AnagramClue.builder() + .text("CARPET AHOY") + .npc("Apothecary") + .location(new WorldPoint(3195, 3404, 0)) + .area("Southwest Varrock") + .build(), + AnagramClue.builder() + .text("DISORDER") + .npc("Sedridor") + .location(new WorldPoint(3102, 9570, 0)) + .area("Wizards' Tower basement") + .build(), + AnagramClue.builder() + .text("I CORD") + .npc("Doric") + .location(new WorldPoint(2951, 3450, 0)) + .area("North of Falador") + .build(), + AnagramClue.builder() + .text("IN BAR") + .npc("Brian") + .location(new WorldPoint(3026, 3246, 0)) + .area("Port Sarim battleaxe shop") + .build(), + AnagramClue.builder() + .text("RAIN COVE") + .npc("Veronica") + .location(new WorldPoint(3110, 3330, 0)) + .area("Outside Draynor Manor") + .build(), + AnagramClue.builder() + .text("RUG DETER") + .npc("Gertrude") + .location(new WorldPoint(3151, 3412, 0)) + .area("West of Varrock, south of the Cooks' Guild") + .build(), + AnagramClue.builder() + .text("SIR SHARE RED") + .npc("Hairdresser") + .location(new WorldPoint(2944, 3381, 0)) + .area("Western Falador") + .build(), + AnagramClue.builder() + .text("TAUNT ROOF") + .npc("Fortunato") + .location(new WorldPoint(3080, 3250, 0)) + .area("Draynor Village Market") + .build(), + AnagramClue.builder() + .text("HICK JET") + .npc("Jethick") + .location(new WorldPoint(2541, 3305, 0)) + .area("West Ardougne") + .question("How many graves are there in the city graveyard?") + .answer("38") + .build(), + AnagramClue.builder() + .text("RUE GO") + .npc("Goreu") + .location(new WorldPoint(2335, 3162, 0)) + .area("Lletya") + .build(), + AnagramClue.builder() + .text("BRUCIE CATNAP") + .npc("Captain Bruce") + .location(new WorldPoint(1520, 3558, 0)) + .area("Graveyard of Heroes") + .build(), + AnagramClue.builder() + .text("UESNKRL NRIEDDO") + .npc("Drunken soldier") + .location(new WorldPoint(1551, 3565, 0)) + .area("Shayzien pub") + .question("If 13 Shayzien Soldiers kill 46 Lizardmen each in a day, how many Lizardmen have they killed in total in a single day?") + .answer("598") + .build() ); private final String text; @@ -161,29 +779,8 @@ public class AnagramClue extends ClueScroll implements TextClueScroll, NpcClueSc private final String question; @Nullable private final String answer; - private int objectId; - - private AnagramClue(String text, String npc, WorldPoint location, String area) - { - this(text, npc, location, area, null, null); - } - - private AnagramClue(String text, String npc, WorldPoint location, String area, @Nullable String question, @Nullable String answer) - { - this.text = text; - this.npc = npc; - this.location = location; - this.area = area; - this.question = question; - this.answer = answer; - this.objectId = -1; - } - - private AnagramClue(String text, String npc, int objectId, WorldPoint location, String area, String question, String answer) - { - this(text, npc, location, area, question, answer); - this.objectId = objectId; - } + @Builder.Default + private final int objectId = -1; @Override public void makeOverlayHint(PanelComponent panelComponent, ClueScrollPlugin plugin) @@ -261,12 +858,12 @@ public class AnagramClue extends ClueScroll implements TextClueScroll, NpcClueSc @Override public String[] getNpcs() { - return new String[] {npc}; + return new String[]{npc}; } @Override public int[] getObjectIds() { - return new int[] {objectId}; + return new int[]{objectId}; } } From f859ec9dc84d1afefaa0520e131871bb00228abf Mon Sep 17 00:00:00 2001 From: Adam Date: Sun, 16 Jan 2022 18:57:58 -0500 Subject: [PATCH 21/51] clues: use lists instead of sets for clues --- .../client/plugins/cluescrolls/clues/CipherClue.java | 6 +++--- .../client/plugins/cluescrolls/clues/CrypticClue.java | 6 +++--- .../client/plugins/cluescrolls/clues/EmoteClue.java | 6 +++--- .../client/plugins/cluescrolls/clues/FairyRingClue.java | 6 +++--- .../runelite/client/plugins/cluescrolls/clues/MapClue.java | 6 +++--- .../plugins/cluescrolls/clues/SkillChallengeClue.java | 5 ++--- 6 files changed, 17 insertions(+), 18 deletions(-) diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/clues/CipherClue.java b/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/clues/CipherClue.java index e9fc62186f..1c9bb01b7c 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/clues/CipherClue.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/clues/CipherClue.java @@ -24,10 +24,10 @@ */ package net.runelite.client.plugins.cluescrolls.clues; -import com.google.common.collect.ImmutableSet; +import com.google.common.collect.ImmutableList; import java.awt.Color; import java.awt.Graphics2D; -import java.util.Set; +import java.util.List; import javax.annotation.Nullable; import lombok.Getter; import net.runelite.api.NPC; @@ -43,7 +43,7 @@ import net.runelite.client.ui.overlay.components.TitleComponent; @Getter public class CipherClue extends ClueScroll implements TextClueScroll, NpcClueScroll, LocationClueScroll { - private static final Set CLUES = ImmutableSet.of( + private static final List CLUES = ImmutableList.of( new CipherClue("BMJ UIF LFCBC TFMMFS", "Ali the Kebab seller", new WorldPoint(3354, 2974, 0), "Pollnivneach", "How many coins would you need to purchase 133 kebabs from me?", "399"), new CipherClue("GUHCHO", "Drezel", new WorldPoint(3440, 9895, 0), "Paterdomus", "Please solve this for x: 7x - 28=21", "7"), new CipherClue("HQNM LZM STSNQ", "Iron Man tutor", new WorldPoint(3227, 3227, 0), "Outside Lumbridge castle", "How many snakeskins are needed in order to craft 44 boots, 29 vambraces and 34 bandanas?", "666"), diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/clues/CrypticClue.java b/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/clues/CrypticClue.java index 7c4b03c4c8..fc64ab21ed 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/clues/CrypticClue.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/clues/CrypticClue.java @@ -24,10 +24,10 @@ */ package net.runelite.client.plugins.cluescrolls.clues; -import com.google.common.collect.ImmutableSet; +import com.google.common.collect.ImmutableList; import java.awt.Color; import java.awt.Graphics2D; -import java.util.Set; +import java.util.List; import javax.annotation.Nullable; import lombok.Getter; import net.runelite.api.NPC; @@ -51,7 +51,7 @@ import net.runelite.client.ui.overlay.components.TitleComponent; @Getter public class CrypticClue extends ClueScroll implements TextClueScroll, NpcClueScroll, ObjectClueScroll { - public static final Set CLUES = ImmutableSet.of( + public static final List CLUES = ImmutableList.of( new CrypticClue("Show this to Sherlock.", "Sherlock", new WorldPoint(2733, 3415, 0), "Sherlock is located to the east of the Sorcerer's tower in Seers' Village."), new CrypticClue("Talk to the bartender of the Rusty Anchor in Port Sarim.", "Bartender", new WorldPoint(3045, 3256, 0), "The Rusty Anchor is located in the north of Port Sarim."), new CrypticClue("The keeper of Melzars... Spare? Skeleton? Anar?", "Oziach", new WorldPoint(3068, 3516, 0), "Speak to Oziach in Edgeville."), 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 50178bb1a8..f2f552ad68 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 @@ -24,11 +24,11 @@ */ package net.runelite.client.plugins.cluescrolls.clues; -import com.google.common.collect.ImmutableSet; +import com.google.common.collect.ImmutableList; import java.awt.Color; import java.awt.Graphics2D; import java.awt.Polygon; -import java.util.Set; +import java.util.List; import javax.annotation.Nonnull; import javax.annotation.Nullable; import lombok.Getter; @@ -100,7 +100,7 @@ public class EmoteClue extends ClueScroll implements TextClueScroll, LocationClu item(TZKAL_SLAYER_HELMET_I_25914) ); - private static final Set CLUES = ImmutableSet.of( + private static final List CLUES = ImmutableList.of( new EmoteClue("Beckon on the east coast of the Kharazi Jungle. Beware of double agents! Equip any vestment stole and a heraldic rune shield.", "Kharazi Jungle", NORTHEAST_CORNER_OF_THE_KHARAZI_JUNGLE, new WorldPoint(2954, 2933, 0), DOUBLE_AGENT_108, BECKON, any("Any stole", item(GUTHIX_STOLE), item(SARADOMIN_STOLE), item(ZAMORAK_STOLE), item(ARMADYL_STOLE), item(BANDOS_STOLE), item(ANCIENT_STOLE)), any("Any heraldic rune shield", item(RUNE_SHIELD_H1), item(RUNE_SHIELD_H2), item(RUNE_SHIELD_H3), item(RUNE_SHIELD_H4), item(RUNE_SHIELD_H5))), new EmoteClue("Cheer in the Barbarian Agility Arena. Headbang before you talk to me. Equip a steel platebody, maple shortbow and a Wilderness cape.", "Barbarian Outpost", BARBARIAN_OUTPOST_OBSTACLE_COURSE, new WorldPoint(2552, 3556, 0), CHEER, HEADBANG, item(STEEL_PLATEBODY), item(MAPLE_SHORTBOW), range("Any team cape", TEAM1_CAPE, TEAM50_CAPE)), new EmoteClue("Bow upstairs in the Edgeville Monastery. Equip a completed prayer book.", "Edgeville Monastery", SOUTHEAST_CORNER_OF_THE_MONASTERY, new WorldPoint(3056, 3484, 1), BOW, any("Any god book", item(HOLY_BOOK), item(BOOK_OF_BALANCE), item(UNHOLY_BOOK), item(BOOK_OF_LAW), item(BOOK_OF_WAR), item(BOOK_OF_DARKNESS))), diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/clues/FairyRingClue.java b/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/clues/FairyRingClue.java index 6fc915db54..baf0ce8752 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/clues/FairyRingClue.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/clues/FairyRingClue.java @@ -24,10 +24,10 @@ */ package net.runelite.client.plugins.cluescrolls.clues; -import com.google.common.collect.ImmutableSet; +import com.google.common.collect.ImmutableList; import java.awt.Color; import java.awt.Graphics2D; -import java.util.Set; +import java.util.List; import lombok.Getter; import net.runelite.api.coords.LocalPoint; import net.runelite.api.coords.WorldPoint; @@ -41,7 +41,7 @@ import net.runelite.client.ui.overlay.components.TitleComponent; @Getter public class FairyRingClue extends ClueScroll implements TextClueScroll, LocationClueScroll { - private static final Set CLUES = ImmutableSet.of( + private static final List CLUES = ImmutableList.of( new FairyRingClue("A I R 2 3 3 1", new WorldPoint(2702, 3246, 0)), new FairyRingClue("A I Q 0 4 4 0", new WorldPoint(3000, 3110, 0)), new FairyRingClue("A L P 1 1 4 0", new WorldPoint(2504, 3633, 0)), diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/clues/MapClue.java b/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/clues/MapClue.java index fcc6153f89..7b32258b23 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/clues/MapClue.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/clues/MapClue.java @@ -24,10 +24,10 @@ */ package net.runelite.client.plugins.cluescrolls.clues; -import com.google.common.collect.ImmutableSet; +import com.google.common.collect.ImmutableList; import java.awt.Color; import java.awt.Graphics2D; -import java.util.Set; +import java.util.List; import lombok.Getter; import static net.runelite.api.ItemID.*; import net.runelite.api.ObjectComposition; @@ -58,7 +58,7 @@ public class MapClue extends ClueScroll implements ObjectClueScroll public static final String WIZARDS_TOWER_DIS = "On the south side of the Wizard's Tower (DIS)"; public static final String SOUTH_OF_DRAYNOR_BANK = "South of Draynor Village Bank"; - private static final Set CLUES = ImmutableSet.of( + private static final List CLUES = ImmutableList.of( new MapClue(CLUE_SCROLL_EASY_12179, new WorldPoint(3300, 3291, 0), "Al Kharid mine"), new MapClue(CLUE_SCROLL_EASY_2713, new WorldPoint(3166, 3361, 0), CHAMPIONS_GUILD), new MapClue(CLUE_SCROLL_EASY_2716, new WorldPoint(3290, 3374, 0), VARROCK_EAST_MINE), 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 1b7925b380..aaf8006d5a 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 @@ -24,12 +24,11 @@ */ package net.runelite.client.plugins.cluescrolls.clues; -import com.google.common.collect.ImmutableSet; +import com.google.common.collect.ImmutableList; import java.awt.Color; import java.awt.Graphics2D; import java.util.ArrayList; import java.util.List; -import java.util.Set; import lombok.AllArgsConstructor; import lombok.Getter; import lombok.Setter; @@ -129,7 +128,7 @@ public class SkillChallengeClue extends ClueScroll implements NpcClueScroll, Nam item(ItemID.IMCANDO_HAMMER) ); - private static final Set CLUES = ImmutableSet.of( + private static final List CLUES = ImmutableList.of( // Charlie Tasks new SkillChallengeClue("Cook a Pike", "i need to cook charlie a pike.", "i need to take the cooked pike to charlie.", item(ItemID.PIKE), item(ItemID.RAW_PIKE)), new SkillChallengeClue("Cook a Trout", "i need to cook charlie a trout.", "i need to take the cooked trout to charlie.", item(ItemID.TROUT), item(ItemID.RAW_TROUT)), From 4410e173e32f3cb992790dd0cc78cc6147236ed5 Mon Sep 17 00:00:00 2001 From: Tomas Slusny Date: Mon, 17 Jan 2022 19:26:02 +0100 Subject: [PATCH 22/51] discord: accept animated avatars in matcher Discord avatarId can contain underscores when the image is animated (it has prefix a_ when that happens). Fixes #14594 Signed-off-by: Tomas Slusny --- .../net/runelite/client/plugins/discord/DiscordPlugin.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/discord/DiscordPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/discord/DiscordPlugin.java index a4bb4c7d1e..031ba10941 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/discord/DiscordPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/discord/DiscordPlugin.java @@ -233,8 +233,10 @@ public class DiscordPlugin extends Plugin return; } - CharMatcher matcher = CharMatcher.anyOf("abcdef0123456789"); - if (!matcher.matchesAllOf(event.getUserId()) || !matcher.matchesAllOf(event.getAvatarId())) + final CharMatcher matcher = CharMatcher.anyOf("abcdef0123456789"); + + // animated avatars contain a_ as prefix so we need to get rid of that first to check against matcher + if (!matcher.matchesAllOf(event.getUserId()) || !matcher.matchesAllOf(event.getAvatarId().replace("a_", ""))) { // userid is actually a snowflake, but the matcher is sufficient return; From 212915578cddf0b8ad8a3708d0dc92c9cc8bb070 Mon Sep 17 00:00:00 2001 From: Owain van Brakel Date: Mon, 17 Jan 2022 22:54:49 +0100 Subject: [PATCH 23/51] project: Mixins --- .../net/runelite/mixins/RSLinkDequeMixin.java | 17 +++++++ .../net/runelite/mixins/RSNodeDequeMixin.java | 51 +++++++++++++++++++ .../main/java/net/runelite/rs/api/RSLink.java | 9 ++++ .../main/java/net/runelite/rs/api/RSNode.java | 12 +++-- .../java/net/runelite/rs/api/RSNodeDeque.java | 3 ++ 5 files changed, 89 insertions(+), 3 deletions(-) create mode 100644 runelite-mixins/src/main/java/net/runelite/mixins/RSNodeDequeMixin.java diff --git a/runelite-mixins/src/main/java/net/runelite/mixins/RSLinkDequeMixin.java b/runelite-mixins/src/main/java/net/runelite/mixins/RSLinkDequeMixin.java index 1ab3935574..70448db66d 100644 --- a/runelite-mixins/src/main/java/net/runelite/mixins/RSLinkDequeMixin.java +++ b/runelite-mixins/src/main/java/net/runelite/mixins/RSLinkDequeMixin.java @@ -32,6 +32,23 @@ import net.runelite.rs.api.RSLinkDeque; @Mixin(RSLinkDeque.class) public abstract class RSLinkDequeMixin implements RSLinkDeque { + @Inject + @Override + public void addLast(Object o) + { + RSLink var1 = (RSLink) o; + + if (var1.getNext() != null) + { + var1.remove(); + } + + var1.setNext(this.getSentinel()); + var1.setPrevious(this.getSentinel().getPrevious()); + var1.getNext().setPrevious(var1); + var1.getPrevious().setNext(var1); + } + @Inject @Override public void clear() diff --git a/runelite-mixins/src/main/java/net/runelite/mixins/RSNodeDequeMixin.java b/runelite-mixins/src/main/java/net/runelite/mixins/RSNodeDequeMixin.java new file mode 100644 index 0000000000..db22beb887 --- /dev/null +++ b/runelite-mixins/src/main/java/net/runelite/mixins/RSNodeDequeMixin.java @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2016-2017, Adam + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package net.runelite.mixins; + +import net.runelite.api.mixins.Inject; +import net.runelite.api.mixins.Mixin; +import net.runelite.rs.api.RSNode; +import net.runelite.rs.api.RSNodeDeque; + +@Mixin(RSNodeDeque.class) +public abstract class RSNodeDequeMixin implements RSNodeDeque +{ + @Inject + @Override + public void addLast(Object o) + { + RSNode var1 = (RSNode) o; + + if (var1.getNext() != null) + { + var1.unlink(); + } + + var1.setNext(this.getSentinel()); + var1.setPrevious(this.getSentinel().getPrevious()); + var1.getNext().setPrevious(var1); + var1.getPrevious().setNext(var1); + } +} \ No newline at end of file diff --git a/runescape-api/src/main/java/net/runelite/rs/api/RSLink.java b/runescape-api/src/main/java/net/runelite/rs/api/RSLink.java index 800b172b12..901ff570f1 100644 --- a/runescape-api/src/main/java/net/runelite/rs/api/RSLink.java +++ b/runescape-api/src/main/java/net/runelite/rs/api/RSLink.java @@ -7,9 +7,18 @@ public interface RSLink @Import("previous") RSLink getPrevious(); + @Import("previous") + void setPrevious(RSLink var1); + @Import("next") RSLink next(); + @Import("next") + RSLink getNext(); + + @Import("next") + void setNext(RSLink var1); + @Import("remove") void remove(); } diff --git a/runescape-api/src/main/java/net/runelite/rs/api/RSNode.java b/runescape-api/src/main/java/net/runelite/rs/api/RSNode.java index ddb124464d..590a805e40 100644 --- a/runescape-api/src/main/java/net/runelite/rs/api/RSNode.java +++ b/runescape-api/src/main/java/net/runelite/rs/api/RSNode.java @@ -33,14 +33,20 @@ public interface RSNode extends Node @Override RSNode getNext(); - @Import("key") - @Override - long getHash(); + @Import("previous") + void setNext(RSNode var1); @Import("next") @Override RSNode getPrevious(); + @Import("next") + void setPrevious(RSNode var1); + + @Import("key") + @Override + long getHash(); + @Import("remove") void unlink(); diff --git a/runescape-api/src/main/java/net/runelite/rs/api/RSNodeDeque.java b/runescape-api/src/main/java/net/runelite/rs/api/RSNodeDeque.java index 7411f0b19c..0661a11bd0 100644 --- a/runescape-api/src/main/java/net/runelite/rs/api/RSNodeDeque.java +++ b/runescape-api/src/main/java/net/runelite/rs/api/RSNodeDeque.java @@ -44,6 +44,9 @@ public interface RSNodeDeque extends Deque @Import("addFirst") void addFirst(RSNode val); + @Import("addLast") + void addLast(RSNode val); + @Import("removeLast") RSNode removeLast(); From 713f7950c26db2f257f1cabb2d2eca620ecb67cd Mon Sep 17 00:00:00 2001 From: Hydrox6 Date: Mon, 17 Jan 2022 16:56:17 +0000 Subject: [PATCH 24/51] clientUI: show if the client is in safe mode in the window title --- .../src/main/java/net/runelite/client/ui/ClientUI.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/runelite-client/src/main/java/net/runelite/client/ui/ClientUI.java b/runelite-client/src/main/java/net/runelite/client/ui/ClientUI.java index 84a2e4858f..f08e97807a 100644 --- a/runelite-client/src/main/java/net/runelite/client/ui/ClientUI.java +++ b/runelite-client/src/main/java/net/runelite/client/ui/ClientUI.java @@ -164,7 +164,7 @@ public class ClientUI this.clientThreadProvider = clientThreadProvider; this.eventBus = eventBus; this.safeMode = safeMode; - this.title = title; + this.title = title + (safeMode ? " (safe mode)" : ""); } @Subscribe From 2d43cc419aa4146d73fc5a9e63c641a24dba5189 Mon Sep 17 00:00:00 2001 From: dekvall Date: Mon, 17 Jan 2022 19:25:02 +0100 Subject: [PATCH 25/51] worldmap: use vanilla icons for lovakengj mining site --- .../runelite/client/plugins/worldmap/MiningSiteLocation.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/worldmap/MiningSiteLocation.java b/runelite-client/src/main/java/net/runelite/client/plugins/worldmap/MiningSiteLocation.java index 85fef484b9..3e60e1a1a1 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/worldmap/MiningSiteLocation.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/worldmap/MiningSiteLocation.java @@ -144,7 +144,8 @@ enum MiningSiteLocation LOVAKENGJ_SOUTH(new WorldPoint(1476, 3779, 0), new Rock(4, Ore.IRON), new Rock(6, Ore.COAL), new Rock(1, Ore.MITHRIL)), LOVAKENGJ_SULPHUR_EAST(new WorldPoint(1445, 3870, 0), new Rock(3, Ore.VOLCANIC_SULPHUR)), LOVAKENGJ_SULPHUR_WEST(new WorldPoint(1427, 3870, 0), new Rock(2, Ore.VOLCANIC_SULPHUR)), - LOVAKENGJ_WEST(new WorldPoint(1432, 3845, 0), true, new Rock(45, Ore.COAL), new Rock(80, Ore.LOVAKITE)), + LOVAKENGJ_WEST_1(new WorldPoint(1430, 3849, 0), new Rock(33, Ore.COAL), new Rock(58, Ore.LOVAKITE)), + LOVAKENGJ_WEST_2(new WorldPoint(1447, 3840, 0), new Rock(12, Ore.COAL), new Rock(22, Ore.LOVAKITE)), LUMBRIDGE_SWAMP_EAST(new WorldPoint(3226, 3146, 0), new Rock(5, Ore.COPPER), new Rock(5, Ore.TIN)), LUMBRIDGE_SWAMP_WEST(new WorldPoint(3148, 3149, 0), new Rock(7, Ore.COAL), new Rock(5, Ore.MITHRIL), new Rock(2, Ore.ADAMANTITE)), From 53a8b5a6b9f0592872d805298a48ea447ac71bc6 Mon Sep 17 00:00:00 2001 From: Hydrox6 Date: Sat, 8 Jan 2022 04:18:49 +0000 Subject: [PATCH 26/51] login screen: add nex login screen --- .../loginscreen/LoginScreenOverride.java | 1 + .../client/plugins/loginscreen/nex.jpg | Bin 0 -> 161866 bytes 2 files changed, 1 insertion(+) create mode 100644 runelite-client/src/main/resources/net/runelite/client/plugins/loginscreen/nex.jpg 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 e083db40b0..f7a3e87722 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 @@ -44,6 +44,7 @@ public enum LoginScreenOverride PRIFDDINAS("prifddinas.jpg"), THEATRE_OF_BLOOD("tob.jpg"), A_KINGDOM_DIVIDED("akd.jpg"), + NEX("nex.jpg"), CUSTOM, RANDOM; diff --git a/runelite-client/src/main/resources/net/runelite/client/plugins/loginscreen/nex.jpg b/runelite-client/src/main/resources/net/runelite/client/plugins/loginscreen/nex.jpg new file mode 100644 index 0000000000000000000000000000000000000000..c2a3719440a4cfe8c03e48b238dd344b16801b9b GIT binary patch literal 161866 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�?E>bycdPXxV3^MZdwf0ld4nw1R|BM7WNNo|9tc0OyMn|mOa z17oY@TdC%ju?Ix|MB;x_QI$PhLg4c#X%`Phr9JE=g_J#OCBxFEf3vjxh{leJ7~Y9C z-w-9X<|ueBG7!0Ma}HRj<7kcg5<6oggXsSB#@$iEX5#dSk*Yhl=TYU#o=}($Wku;(?jNAMxs_8E~_o8at=Cq(6 zinyXO>nvW~T_<>Y$lQ&tiDhHB8SFGdP^0`e##?W+zPcNR0^X*dWSf%2yQN*X12tv7{-cOCaL6o=<@xTJsKydjzCJJ8Aw=97$g!zukz z-2`T!vcHmgdX*Qads{#KCvan*zGI#K*(PLYD(gam7*mN7hr>{jk^m4R&hbS$6J@16 z|15C^D8Liiix!7${smQ)#9aI)4{%K?LxBguMM z$cSJxTN-Dc1ld-`ME$C94<>`g8(o@IsiOZ*A$EaA26l^lW0$AFeH~+s40sIo^``bL zdfAt1n`2>_?uDjdZ2@<5zuI}^mw8WeQtcQkYM%RdQ-l}iQ}q{SwGYhr(Jn9U9VM~= z&dpw{S+_;1$)EP#c-3xX_l^KB-9ek{!xowr)&4om^ugYpjWxJp#4F2(qc+hFkTMcn z@fN512|fJiW+Yn3E!w!wYlI6EwP^TSW}8n;-%`Z*1#P@jL|vHKzG9uI94$4+cGnqU56^t8Pjtmcv2fwqo5qM{|qAh8{6{VQ;G0pS;n3 zj1fG(*A$@Iuf}DRJc`j2=fxYUx*uD18xuGpX{EoTq=M581SM$*1Zp%&p$q>(&(EmN zx}R_0`s5l39<|d>a+8`GpVa22^9uBvOJn5S>>#CL-~CSV1l_Bs5Cv%dXT=2A{_+06 z!;tkv)QkeVE1H$@*LlGOV0q)~p$RQv9?OHD(6{*wr%#wLDI1;9Hux-yG@X$u%4$Q; zzBTsL8EPq)OzZqF$B-*v=XyDDEg?@y(m;8}F!_SekVSW9ziI9b#Wd-b4dPCtIYH#w zXf)to`9A=jdE!<^E}c+*q|^fv0}}l3!~>XhbNa^qV&{3l`<{7&cjfhy0!3W2W* zW0&sTa{>q`2;Fa3J-^}p**ptNgH3Axi^PYmks~!3AlJRP{wM&wogIHM31Y2(J*?SZ z<^=o;u(OHdpU)mT$SOi3Pf(sJjIsIoaF*&S-h0MSLv%%wLV*2xcE2%zm<6}djS zhPva&{v>%l-mp{{w{YU{WJbbml`dh5x_@|E@hlBh1ILdQMXsqL0iZ zB)z)zb`X&%6L~6>j~azuZ2iRk>BBW>ev;KhSoWwFXm%9E#SW6Is|+y=K*#sx9vcit z2Vdxu(QvViukB1iL*JL7*<*EM1ZrtUoQwBvi4QQ%!Kc#Y1wmiXX^AvX7pE7Y9Sufk zW~K1SKVA~KP}PBXdPOuitn<{0)`IfNuGkxQb<)37sos+hZaUt(=JXS7i%DVE@acZf z+i3~C)k-y%jZiK~AsfZ5K8>s{fM=w{&@-m4k)>kW!?J5q{nDlI*g^Js~Y(pG$h1+C)Sh)M&GbzIEeWm0Wtd@D;4dtY1 z6>lF-MhSW0wUq?$o(0#z2;X!V=?zul)<4+^sDDqV~}1y4Ae0 zVDHi!;%ea(Gh*t}o_m(Q)5^RvoAoYIH`_TwK{y~^K54t;3tIpIKcUQYBQB{iej|O) z*+K|q+5uC?UT)JYS?iJxKCCgUCtmG&DD6)p7`%P78`*h7?dgrFDqd-}FLrw#(rb-+ z_9FkY64UEz_6l1;ZEwc?rag5dcLDZz&b+B2ek4sJtrvT-1NSqBCN8B3R^l{`V7C+^ zn&Pvpafg7nzyh7ctfn;zo)rA}=8pU`b@qOl&KRocnd6h&&!-#Q#c$ZduYUDcej^%P zeLJ*PdKhY#4TsW*1wXDpX0+lLV=fh}yWhRUzHHP&r+w=FE&q!%TUU{q{z41`l7Jio zgeAGb^D^_Hv59Xn*s(7gn(Qp0g}!sxEVR%*VkDHE;NnxJmvy$HdSo8&Q6|RkfBlM~BVfU?X=sKADGeKmi|ih5CE&IkMQ)?W zhxTHq3$gt67zIFPyFABphPUQoUpE*^m~O!`a9q0kGIG6m!h?|~(IY`YXSB@1H>v6A zQ5cfQ7?^w_Iu{EO-Qro26$XG4M^)Od*DB1` zc`=AiBF~L!WRma&l$rTb0`zcf5>nXDC;4gqdSPYL0Mb8PS)`>#j9#QM^J0ra2F5^d zj1ILt_*IfP*3Wb?GqvT}6{B@y-o!xioq|UVDdIRYVpik^qjX9>;-_Wb1o@89K#y`N zDJ7~dDNntqoPK-P$qbuC&=xUq?Re55@kzpN$j9fsbwZVFf7?}=3T%q}u(a~G_zRRl zoTzA|0l4z2zP)vOf&EMw{8^{3LWe=H${Uq85a>=c6B=zY+P%+X^kulqrvgKp_)(W`3DoS6#5X!5i(y|B}-pD>1NiA1DwasX%~pmu9e<3t7N z=jtaJOB1z`hr97gX~kWoi?>mrJma0Rv-~_#+fa0w{50n+lG5>W`!zJZZ;`bWNTke> zK>iPq_iO5pe`NIu|6Oghe~rhXh0>Nr**~E9wwX9E-a`FL(ffvXroC>&;$e?`tSdx^bUA(H^ssDiCm zRm#;oGLu~=M(b4o649o7i9C@|a6c$!g4|Xa_ez~8L;@&3k7wAM3*%;@IjzGWJ^5!D z_I?cxQf+t26MFp6vzTr3pXIoZsE&>T-w$G$IlWNdj6Y=EvT@ljt~>n{tC9kx>qs6mw;NOEYBlrU#ijTlhu%TF#Ex?hC#7vd6Z&4}_(7(Y%klezW?MRi?P)Y>@(V9T)#3c`xy zi%Acacm5Kl;%}@G0wy0(f3tBFRrf&wB9BBkmKX`x78iDEKq{XDGOXC@Vjga7qIzs;+;ewsH7sIwsM z)8OWZ3_suShj+(gRUqIki#BY0G^M z1kJ_vZmO}yYM@!oXfB|E!p}p$$*}mhtdOwvz<+L@@z>jvxoU_PM(3KETw_L(3BQ#_ zNV8xCRG{Hz(WN9dH$(@VN@|dnR>?5;URw|XwnuE{po0|muWApQ0^wpZ++Omx9jS~q zijtG^DHtoHoD_ekrtX1%(Kk70LRL8z8RB`;xTok31Ei6FN`t!}$rDG2hkw08gZl>* zp@5Mm%*zeSTw-FtKGh?`ZT~+De4cSk89-}If~ImC4H|)D{_E0Do!Zl^&^xyOtrP9x zd7sIW1on~8uvvS*^^@`a*1f3Hs!Ih~%oy*>jr`Q@{EgeQ9HxOuQekW9)jkW9=jwcw zFE@Q9B>FzJh1&*mE2IiUni#Ob1X0j5i=%y)Poa0kwOB280xH#6h(jOY*Wso;an=Fq zgSQ#GDzTB~4eqrFQv$m$#`Yvpgz#2%H|vfk3kswGX0etFuz7 zHJw4WSt+?pbV|>WsqU(@`xk#!R+_VG4Y(IeLfX2UBVLPMe@`vjt6d=jv=pgR=oF{= zYEJE!MkTxKuIxqaDpU}=4@kYXh%x8itZ$tAD`ikyyhDlU)&CDo@BfSMlx~bxuyCw0 zEdzoH(pyt|;{Am)Kt7U%XvHtzO7aM5ec9G=koNW(9QNISK}m|X*nA@V%K&T+?Jpks zVGGrn!?E`T+VLu$DUuEH%#LI<*C3WsU_-rq#Y$8!!b;-y!cr8pR`44tct=x=&#J^i z=Oypb;<8h#jdJXczzASZkbuanO1tBkJjFM)6{Iq+d%E~s!vcp`CLnY6r+#%dGsiXe z60)nwm4>eX9N=FbRu!UhS|6{Y$u$Z*I;x4~NU;u4p(}8}JF)if>P>7LW8r=&0)WjL zh&;HspLVF?kW)8TYhiDIPaS?7Dd=#to>-_FwLkSy)+v|a>Vsv3RiRhTtcPx=hr(%> z2mP5kIS*|LND$^lQY9r&6q9TVbzVJ?bqQ|rWDH8O|3b@q2ifKiFJEdHbw+~66kpOO zcGarG==!ObJfGc^XxW;p5X6WQ2?iH#K*@%LC|RdfZ`f;k)*1A*aoa@o8z@Ozd?X<95^H}CYX#?3(75sS>6kbP*eI{K^ASeCn{5W+HlH^*Xfg!1yrEzV5Nq_y zb7i1wXbk!dx*&{$XbKXuc0eN2fb08=c>`p6FCa3AgrU7Qjk`=pTcG9n`#|=~B`5Z& zv#SEx@uWD85p3q}94zbmB5?o;#xA&zdIO<&@ zB96lC0Hmq5wJaeWs|fk1-Huuy4)3*9GC$Bl`%C~HlO!gr1-*-T@)h+_HMLKN-Kg(Y zlWWWzFM=>S!DofGf1ip~+^I8HW{Qp7bpxO&+GV~^pq#E%>f+S|FaF1TLv3zH(4?t28zx`9C}EUp02 z)(!Pt$mqAhPs!8a0*j~9tYZ^57CPm}W0Ydt-Q#QYy!pSCMv0}&e|xXD8C~sGW%h9_ z`dS@(Ws{+@#N9HnRTZx!zbKhddKiIbGgQNAof69**LZ8m;tR$y+#;qQ+!1 z>%*{{MV+f7xqx-e3ffjjJUr@fjBF6vvj%vY$~1k4`Ek_PsL@Jd^BPcBilu8QwBh`4 z^}Nzm;NE9hHBChQOgl}s8zrO^Q+gQIP#KaufM_`NG{H+54lXKGxj4k1&}D8?_GI$C zT{$s4)U7oG@1o+K32wH>ae~w>En|rl(`Z*n`kzbxq#6UK8@WAMCW`CN`DL5m5zCQG z*`hoA*dX$=%0-9p15-L`AvYBGhPYI}Oio18%74|uho>zuw|%>LatB@yKXsdrcQa|u zGMj1WHGi8(bNq3^!)De4^E{R{MrFN1lp2Nl%KwJMtKHPENM4z}{?l33p@L6dyevET z#ZZc>E^~{Y9#FBTFZI9!Vt%<_U`(Td(Z=nGTzCV*A1HroGsW)u%SI9Q7z`Fx)S45j zgy@iT^gZgm>ocO{KLD=~hCkD~29W`9gWGM7IL+j#I{5EPKo)bPZ*`FapDC@5{txh! zazyTnKLc`JpTK`9FHFBHFIVQ?RzrgZLBS9hHDVYs(vBeWuHz@CkE(6Q@`W9E01Mq5 zt+(!5Ot(snn06h~o`a^RlvnYin!0cz5S$72(AiDV{UcBIkNo$x7m;qdWBt@C7Z<7V$Az5nFq#kR(m#$~W!+~bDIAlD2X2B65_%%QF%d(WI$0L<)3~TO?<0x5 zc6-V`M7cjJ)g3G?VV`w{C6uAKtzZ40J^icLpH8qm4g`wQJ0xS--Z5Q$vg(`Dh&X)q zZlZlq8h)kSk#S_VOZ7$mHw;8`wt`AUJ>zp?P=R_MbGTD;r{&RWERW<S6DDp8GcE7c1X`GgONUySzeIwNh>cy{^cCWi#ICCyIwNU)W6p z!9`iOxMDYX+TWO)X`!v8Hdm;`C6v8F?=rpuXyj2bcTZ0?DK-^iB&LM(bMl<}9znJJ zBrK|C(d^lpvgqQVAuBW}Rn82<$Kd&iY*%Oh&mk=pT_I0vSdhaYBJ<3xkh$i)xB;!hu;rz7XF8Q%fm3bh%q?r{3=<#*JW0HQDeDE64rmoM#fo5tWk zp&K!|D{U_!JR)`i!DvM#rli|*bZmp65){!qDP8;Fd2p?StQ1dS70+o~n^IX$gpDZ+ zrP&!-_e0agp_7@3JYoH1AZTLwWsDG5hVQ|vPn`_P{b_mXFHHH$ofX99%`S9$+S?n= zSt$P%Q9lHsrWG3eB`I%pE>Q{)+i^cVf`UW!>`C-d^okhs@@(eahr-m-ory(TYXETC z-;z$#mD@dw%rlYDUDUixd65l6)NnB4s6o)lfcMzWyP*Ea>u=;s#*ejItX~U?mXhGp9=GydGznN zKT$y8$5|^&?SlA&scfx4dfW~HDV>3!zWrfSt$}9P?0~y*7qt`7Z3`pB*e1yKdaR!n z-bnJce4V6uzwIoz%Z8_jt{xLNo}_F(v~pAui)MiFzILwYC@;NrG^qdddG#bf_a)hb zag_35g818yb=5UuT(Hc;Qr%c8kvF|g?EQgJ-bC+n`N5tVvgnX~<2n7I)89Y<;J4_9 z%A>atvp)}-3EuEQ0rw!@{{ggNl57-@%Byr(c>%Qom@FydlQo@C$M#WYx0#QhFtF>^ zAJi|`aHCOZu_IqXgeTlp_Fevqk3tt?H_xz^ck=UzdatSEw4E}20K$l#Opcqm;DKKn zehm*O?ABd^cMTW|_9FisArk!->0ABJ$*tTSFLjMum+*w?`?d1mtQ~PvStvK-E5lzF zC75heF*lTQ$zx3^ZB6^8lYu!+d%2wVIzLQ+TL1?bMT`bMsK;Eorh6C`72vl}YLv9y!5kkvnr||pmVmz{D-f(+ z20oBBni)QbXEQjwU|x1znrtbdivvevk_eN4eG+>9((|K#D(ZZsr0UTEUQzh&?L|eD zA6=(y3{E{XP!VdPyrfCiy9wWO`@s3$lHe|8)o9{ugfgxQ1QRlyGC?9fcYnp+UN?S+ z@)pZ;Ft(RkxO#HKhU3;|^hR{x?UM#SNc{)qYUr0zB0`c097DM9!on`*CfrZ7XQg}IbV1G>bq3{(vm9o%F6tGVR{l1y@j;UDW!MQ z&lLRFc0`!^lA3Pdo`Er`P=VcmD+*PtKMwNx`>A!h04ieAaSb)RH2SmTdov&tpbF@F z>HFvF0(14-a=Hc(u=C~=!+6Zk8Oc5|Z<7Mv_}>CgC?b4$>}%!N>jYo}iL#2GSC^a7 z=JGXU>c{3--n#p5lCP;Xtu_Cn?Y1C~j+#on$87x_X*e!KG>Uboh}K zWLm3(i8CZT&*n5Xj_td+fYg|ButLMyWX$XtE#T>*uU&>R(y&K3NPa_P+aGTKBAiWA zD7jW_v6aN0c%e1vuzvQC$u7_(AWBAKd3(GlN-_JH`p&$r#a#DBotgRf>9vu$IOTR_ zwPZb27WRSv0pd3NW@lUO=%GB3odhliZ~P$XmnB(XL)PD^@QoSkTTN6zQ(+@wvi2Nz(uMWU0(E;%9w$ zy{8MCrQ)A%_(QZ)kjNytc<^7l8Di zDy@f4_`KJ{oaTMi0%e)QY*Z)LRNa_&)7BZMiQ2;bT}jNLt;I{<-m%SAD+Wu(Aznb~4=UuE9c>c2) z;AyBFqwZok2mU+ldjtROuGhr#{>~i+#pNX%>~xkJt-h0}=mD8wP8!`;b66{yfvuSi zTcP6-Ydwmgc%1Qh0-~*2+p+^Mg-bp{Hy-8C@_JdG9HeNUf*TeL8YXhE_^bg!7E!ak z(UjT0Lq?u7CNj<;Kzmgmk-Wyu8(#_o;8=k5qdRIF2J1AHg46td0K%)yrt+!f1JeA$iHsDP-j#q|32WiFTJteb&DD2ic|lGRxnqi-AGccojy@s~q)Di*XN z5&G4L+r_2lz9||E8V3Qq!>5tC%`)3=p6?u3$29y=KN8}<2zvKo6;2h-gP(`wrbWhL zHNAzTTNuh>J10#f)+S`;pP;5+v^-aSnTR;gWQP3xAfQlifdRAeVj^`$J~vbRC!Kkl za>GuqnC;wX6P|V*juCl2y3ChAsrMH4~g&b(FDc~Zv5Ond(U_!Kn`X%$3Z{j zeX24wmErPM*?S`G+1_p_iQpB&F$;}Wx8sCfQ#0I1n@lC9%doG$Qu0yo+_q18Ty^B^ zd@M@KRqHPI?(C;|Ig9{RCVZ7o;^5H<=Hn*ZFnFgm%;wI5t!<9_MUTc)E}6i!3xV#Z zDYzT;!*tZbuz~y$ib7@1$`ki%?GXkUhZeBt&x2Pkq*ls2awBLfB4o>!8^|s5mVXA1 zcciXGf!|t7TFNQu%TlqWiCk&Dm{u8>L`^fVO36Sxiyp=@`oW9ULQ5vF(rs=ZUo|8W zo&!J9P?XXi@g1bQgE7&{%1#Y{924O9-DmXK*yY+35JkKOmYRSi+zumg`g=v}-ub&`scY(XP^|HBxv)-yt z&mshb3j4Gxi)4s;l7DUaC_(sJB|9aLrgmT%^C2m@}6F=T7_bDetVnV4KU}Pk<)>ALxKZpj z^)W1d6={S2=6|)d(xNFVbP(D#@Ya1#L>MVOZ&#F`##A;-VpJPZwEnmiu~GyVIFyT` zXaE!&E&oXSL=683PgB04y3o!q+IdoH>I!N3uS8k=6M)Jwik zGRJ>vkqC_qY?s!A4CH93*6z|s`2dg~% zcj?=}^W9sf>8IfSm*p8|Q!nM1A)_vPD}yuhTR|ZBH&v**ud7 zD&74s$3rRa!UOyJnhkc-jX4B- zA`&#=(LEhFdvbnfAdKfx-&thQn9w3Vh#=wdbXBXU28-m1ODjnHEJm?dbRD~Jx>1Y6 z5vq}2LK-;yC;r}hJ1V;15Hda3m#)`8K6CuerlyLk+3ZC?9(Q%CdB-BiK(jf&cx~aE zkhnuQTNJVCQh=xKah|j{U2x{^^gv;cUDbW*g|kqP*So;kOt?X+sT-N|kH(KwDf~4A z?aJ)T`}@-gvacI#tykkey@=P;l5w2oUggHbP-L2Gm!}{z>u^puK=l%*p&=8=$&6UE z2@h{ic~{o=&-|sqnI}I@v;pi6CzIf8H9YeP&)|Pea=mr1EAyyLSIBXq@ZB-z#Wgy% z>RmGPqN2lZP-sxEp{QhgHfwb?XF3jnJmbE)HB5(z60^RCAog8Xgl1YMI9_QLf;ba6 zIwXvT*%zo-jH=9AUiE*h4@JxT50I>(c-r$x^Rbl;M~w;S@@qQB_rrfU>u4m?6vc77 z+RcBfnBpV|5}cPWE;cI<_ipVsC`NWXw=x}_LCvCko{ zdlobBWSOIFp1;kCZs{n41Js1>e+E;t6Lb@BKAXz!HKuYTr)&gkC%sCp6!zeHZ&BUT z`&m51{3VY5%4Xklp=q@zZzkl9*xgK*40aCa@j?u<3bbpPgAK@rB|IyWs~!x zlqbJ=My0;d&()NYt zuw^k%^2LTllUU>(9dV!lI!+TFi38-{CO-Ti(Q8iYhI>ls()}kvCbGhQkv+aBhUsW8 zSi+b00m|PAqTkGK_~O=K0#6yL^MfCRQm?G=3*~{ltXeyNY22!mM?R)* z@KAoMd`Ar%>2Sl-3u%~$L9yR{*J@t5Wx&nhmz8~Rhlv_vJ1Q->uW-@Rd%_Apz<45Q zM++YQJ6&ervX*@d-LFFd@1oLiRDx}x_EV%vpqFOq>4DlC$5?j>4?-%M+Wtkm(BbvK;<2Uvr&Pe(J-U76DJuW{|Q z3ZHVmMZ@v2mK0280x0rwl)nbQId-F>C@DB~=$O0Du`}SiW<+mMiYj*j`bYFu9>EDb zoUtRIGa`WO>S>#Ml7!6r8n?*&>0eI=Vg=lem;|U$T^` z|H)=Fl`eIC)Fz|CT$!H=r&4nYDSFd?vXiDGDr@r#MrTVUF-a=cgAJU=MK9@DH>W2_ zmJY+5D!l|Bi9AYG8D##&<$gK+R$pcc_ApT5kMg_g%GgYA?$t3~m+qO>gCu^!P#J(dhlB(uz*zKOT-tx^i1%C}%1U5-f!bq?iLKUQ-AhnhC_KzW=Gddpw zMVZ5}21P~V=O9<+wJEKGzo;aNhCIRUiOaJgA?wUI88>n1{b2a$uzXVc2Z^coL)9f; zj(dwAVD@?ngBI^Z%?OO+j6!N$i0#%4VQNjlOmexut)O}eyZt=e@GY0!M zdO5j^^U&r+-4DFKP|a6?ZKEooLV}pc4rJQ(b}b}^Qyg36lPh7pub%q*TziBfqKYcQ z26rT8-omdHC_axvGL;$*r1r=!hu)ylg)JbZY~~m)f_bHTtqP-l%(ku*{XZR+e};|V zLa>VF|op(07j)SndJOJAFd($7jdPh&8`Qg=k3cB=p%yB)m8x+R5vWq=~j^L62E=_ z!h5{O`#kS`U)OnR0*}M8jWL|F1Sd=<%K`tHn=Bp4DX;P=D&|-V3jiQk60BR;pX(4W z6M=j87{A83ou8gvy{r^miCw`vfvmLzT}-UCJe8h4#Q;Ert#E&Un-j}NeyRxSrzL|KWQitp)62zX0*OG5nR1w?pMcJrk>iVJb?wT4G@BoZ9*;-wT()0U}!C> zTPSaxH6NG!Q&$s=p7?!U>F$3232eOu3u-G zvy-x6Z(sT9UFkKOkO`Dne@^38IvasMeH+j++zP>aOw|>Xtuhnfz9B)_-fulrqUG~0 z6y~x*D5bHs1du=8Ywr9+cUrQuHTol#@*m&);<<;VUE>EwUy zB1Gtq;%wnuySSYZ46cXEG|+^L2YKdcpmaWB>pO;5hBlNYJPrf003HJwpOOkbB#i?L5qNn>&0{An7#cgXYIC`uw;Bd`>KLP< z%ORU=$HLDvmKes8Kdu8+QSS_a3p;o?u}{p2)Ke#0-`jprb?#~%g)mxQtjd#Kwy9uO z_KJ-RF(8jMJUpk{X~f8d3>WRmCP={{Fg~|elJiwwi$}%j_CgmFXSaX79{ExTZH$Wk z1FW0K>b?{BJMjdcJ8!*clM|&x(vuTSSK=O#lO?Vs^vRl(;I{W1ce)A30;*4KPRyi= z1)%+6+|vMxi*P7n)_RXLq|GoaqtpUohnAvd!r|!;er}nAZnkmH<$Pz(IGooIW&&is z!X?)lSl$l&>b!@(TYcR2wcOx6c@^0YuX&m6GKu>+-mBGCEi5;_;JrVH0?D-eFyg!_ z5EC+Ga%!&h7L%mMAWlnlI*ib&NO6t{k6CLp^9Ig6&|`81loE`vlzc*`XNh`uIN4aN zM1_D%xOxQUyUCNAZR*o9d?gc*Q_77ea@rBOwKn?>LXYv5Z1waJ1udzpbde|EvGD}| z0e(JvU$G|KShw!jMId7U$Vex4Jo6cuCCCtixHa4@dRFv^8?j45ogv|T7rOJI8ki1! zat1M7?7W!G0_S~^9?aRZ!Z<#qIL|H7G1*^jU9^6BY8UP)Llvi;6_Vtw=wbpGSNkWP z4J2q!u3*knGquxz4_Tu9a0*-yMC>_=F_3ebf|Xuk+}QIytc04K#GGYL9%M`miIlM97qcH~3aAgR! z5|;@Pf`uU%z%05*0+# z4NQQ-;be1sGj*56Wmsbek_+$_a3lZDg3Uww%-;#X z8YT#QTc>AFo|=UC4G1Q$9m7Us-y9s*)~&&fBh5K=Pb3jOs~>yA`_f0bC3>s|O_qRw zlC*@EF|kDNhm2f)I4Uj0R=g7_LKp0VJC;|o$w(YsmWjZDU#ID3gtV!7vlcvOcrX=z zb^d(R#K+zS)s;ZoX8or-`p`52>m_2>fQz_SlA4@M{BarVzqN z@gE+_C*a17WnFBtOZ+xeTYcRsPk3aupj>B4{;k@`x&bI}!hHOqCz=~T$=0k*n@#D~ zcO`O{`VLhgC`bwrn3xZWDTjSuIdSBVgU_xeQ4a2un^X)sX`)uzO*(LY-{oM^yD*iw zp+h?KApg6K+96|x@oPH89H&bMZ{Bu*i4DdT55tg zn>CV9wwkE{uz1jy!x8UPw3& zj;l%Zn4ye#)))_@;ablCMms1BqcxnsEd~c3PCW0*`qz}uO;PbW%7^LYVAMj9#yc^i0;Lo&6gk$ouIPx#P8_~OOHBe9DI?wQ|4NXoONbU$rZ~Rn=UPNw_C#zKgq^*Ysp`p4 z9C^0v;?nWCeGg(JlVI*rTTN?I97MIuM4NJ?v~c6!r)WtT-5`N%r2XZRt+09^8Jlt# zNu4|#)htWli3Cpd@-$7qvr8=l$`w%j18~D~N0wvgy);bT7PWJAF@krWnRcAgA_xv8 z3Rj%j2pVJ00FPqfs#dSfr)&U~OWIVgJa}$ul%+-r(kuTWY};lQi{}O#`Bo(HE(I&{ zgul8EG}{G?FsC2t#`mcP|6EN?v1k^#Tf(2Q+Q&w_QE8O$9DIqC?W(jT3UM#U*T~i=HrLWX_X9XCSmcl zG1-6Z=FT(a&F1+vP!okSeoJhe*}h!$ptUb>gP4S@`4(11Mx6RDq6%eW!|#HP7Ot>l zutB%Cs;jD6<**TcF{$G~@bes>K^{J&XDA9U#!XmM1`zwqwt<}*#RFJzq=l~{>~1&w z_ApU6EBL8mng8`Xu&jAE1XxW_^Kkag6eq_WuleTzqFN_V0HB=~lx`OZ0K_k<{8n!6 zpAaai<`VRXqq6*Y!K%gh(^z0ID8ikdWxBq9brer4X)F8?z}jqx+Dk?LUEf)9RhodF z6DLSkAbzCjs6D!+B68zEAt$2j!8Lm3)T?zJ{sJzM5}ZIi>B4)*bKX zv2K^oaV$7w30ych`Sas&ZZtI(DpUFxue$*6n2%-Tnc~NPor}<2QaUbZ5_XqlIhdLP zp7{zP&Qo(H?-MnMW4cxG9zt+6Rr&q=)f!gz_fO)N=!Ug*k8UIBrSH)A8*(FIkwUqM zyUz>#Fi+{;$q)Lm!qQlt+CHB~nXV-MqVe>Z9|F8V^Fp;S3YAM_9S*@`lUyS{UFFJ8j{JDqA1W+Q?^a1ED3Kd{-#Z=9KARj z$-20Z9nv=49iKY>cPYGFH|-<%%cABb62E>1qq$nz;}6`7KFv95I&SVHif%O%d|F3FvF?` zIo_f#(T_WlWhZj8JD&s?EW7k>WD(lA1~Br_6eS2#TBX!akDfbp(_1XgpL$s}iRAK> zmd$u=HKSIb9dbF9($NTc3#9|5-`ed4 zEK~&0tpx!rXv%fyJTtPTSZ#<0aF!}(q)j_JdA?=;07G^@49GK z5-6bObBNpPwU?BXLw2EcjW=tC1LeS{550d7t0~|hu$E+qg& z^97d}x%YaWtJvGYj|)R|p{9EP0;d~(vEBhdp0>8CMf^bad}|CW{BU5Sb$`X*<*;vp z%p~=P0RLIw<60)yB zzWc4+;5d2lrcad5(3_(yb@qOQYHud7qbZSi#W%7?9L`GSFG*(SJic|3trpccX+Dk9 zOjiMr%fci_CPcW_XVlyDjr|5C^it<=rp4afQuZ%os)~#Z%Y}h1j%ar(;%X^YA(iuqaUb&aNYew{jWHcCR96vl|>d<&qpT9WzFLE$Ea^c z6&LziQr}6PcxltxiqP4t^mU*GcjS`z*rmO`u+tFZq}HIe64ARxM?Y~d_+aK##R`5) zHE}5FM})NB9l6YyEBvpk05sC>5h$JTD+PKh)2F42MdM8L*7)>hoNU`)NrNcM4b!>a z#B;`HA1m8N2L;!pfjd@`*_5Ci*e^y4B(?Qu&&aSn;l|(N{(BL`pzbXEHQ_w=YV_60 zjW6{*E{93mZl(o*|Bv2oZ@BIhIZ2r769;k>9<&Es(L@f9Yuf4_ z7Wzgq%z_D3XI(**l+5&_Jp3ed){pqajkI!RHMR!Kt#ViNC!0 zT({X6R#vLXdEG0P@ev)nkulwKKC2;GcV!x-@UXZpcuZ`hbvyBRuaJZ$1=l4W`my;| z`pUP*z$o`i$G6`e{8?8QeTw+rlso~7Dw9z=>-zdiQStc(Q1cqHxIFQf zt4499#@aoaG8y(6KbJg8=2$5I754Ihwa|#v~ z;l*5uaYqT9HQqTnQGkfwN4@!9Miq zK94>Q+vE#Yq`@l5ai-#oo^03Za?WUj!Lj#t#n4PQRSXO;Zl#?gzy*tdqlrD+U6eH2%{oXq#2@o4$FiBFa}M$C`j00CyU|Fv$R(o>bJ zx`}~9hrO$4paX0tSbwYH-Y4xZ-Ae0-IFIJ$3?>~fP}2rk+Gh=081O3TAef}U+0Y`* zBBh_`#Q@d(Bnae)8^SI+gymRGu*SjB?y7DQMz-~!-g9|;SgAi3W5b-p)rQ8(Stt!` zAnh4>CO_Urj_?U(g{PfPeyN}>6%Z6m|B!^KrPszOuv65hQKELpeIK^bneIKD&*JkuA_lC^EAXRLqbxj1?@xp6k4%#vk>^362x0}xGGA(M&D z+ipJ6zIBc#REl%kI#y}Cwo?5$%36K87z6zRy9yT&FxpmpAt25b%qdoG0hQ-YXCEdgXNFhS9evX`+SimH%;7yx_Z@{D7T zsXn=dENALJK**trL@7afB8KaQ9Nthw*o)wgt6_RWC6S=a;iy^28&%h7kubOZdAoeT zzP5zzl!4}?jm)q{s-&Bl#zqvbs!c{lBCjhIhkQJ;jN~*7%@iW|hykQ5PcHy#FI~7M zYdUgb?`wx0#_>;t@T!(!-DGN1^C#KaK~C@0cn2YQAwc3Quh+$8Eb%eZ#dPQFZy33c zVh-YrpZje8$^u)z9Ie&HLddjSxU`m5{KG>M>5pFC9jvBdqNkmqWZ3sxzlW#iR~kXD z8|Q+df*%_w(JHj;%U1KOdz>4-<+{&0q7u}4lyo*SImWw(vQl~<+=`^UD5tp$FK4}9 zaa5&Mxi#xAea}#=P>-cSdgauw{++A*@eb-_s7@+n3x?Cd01Z@`A|As$cD7uFe;2Ue zehpr#)q(pQT(BheqERQLn$)Jmj#`u+Hjn=NzDzezH}4lTA?{^M?JMV2)hq~7r6wBF zaGBe7b|tV@d_wN7&A1$@W|KNVBLtEE>f!&*CCe3RC|(TVM;Z}6mfVFc98g=a<{nWq zQK}z|f2w)zP1urpRoochB)A!Td`)I zMJ#sJfl90gjIXGf9)1MoeP%uq4T$>gbS#8RQQ|otK}}J`Uf4NLkpQ)4siG)BY(#|* zp%BEwZK~rHOcz*4H(BS2`4vdXAvcLa6r=t+SJBs9iCR0VAJU2jt{HEE zBCGaM!^1(*pJ|s08ewgF$5t~vzoLbYr7RkeW(W~GhONEs%yxX`+>_LZ=##)@+&l`= zV#c?QwuPWqVygmqFTCM3^#MMy5&fsqJ~CK}ri(7dvRO#Tu)t4>C^tSj8oXv>UFWl^ zwb^mq&mwL3{B~kwS7C$&j=ne}TmEIkL0tW#lGk!y^@+X+*O=!{A*7*nR*?F(-}l2P zc?=urUb6pk37=IbUUP9Rr>cotNLF-c1eP!l8K9L(&S?1pv!q!ul6ZFKsv86lVR=z^ zo|iB0gW+m-v7zLPkvI@ecOoP>o`3PF5yGjb zjnlB+lij94z<5c#ilN+Fs?;++T!X=fJ(4!NQfaPCm}biCy&9W-yGIg^5_3efNzZYy zY}}y_iv(1xbgxBy2qe6wHotD=(nCRLr5}L6I9d+18-i+J^x3@+-zT=o&jVaM|0273 z-ZU`r@+7p=`qiyXv+8^rGUcKS{!9WMqzkOET&)+md<)Rd5}E&QIas|fJUv(Wb^2KW zR!WI)U3=EsUw}V=`<7Cy(@EiAs(&-Q?)FaCP31&l@+vQ1;WbbgKtk(JNZcjv^~!A0 zX=TCswIkPNGZA~8_@6gZVHwwZlb?y01JO_mMDl0@HA$1Q!F)i+7&c49VeI0SFJMsT zsIq!Wp;HE${TFS2*1KJRK->5E#tUh5)t0(sp&v|g{LHEG!4&Ir++eQr8+R_xUa(2+yhd_p zHN~+yx#<_$L*N~N;TtwO#Cf_&Bp&vp8 zn2<#Y5xT81?csd|2mAq!efk9Ht=pa<LMq+XkW0B1FYGXEJ%q^R$H{7f;xN(nT- zWYtGA`YN8>r!n=aDa+fU;lRaJZ;$|$lkDeoTK}g+>OJkoK4MFDn$I=lGorQ7UCzk{ z*0;r<9J)9nB%!6x*eHU3bIBDSSD`xndA35sPMJzBlnl+397r8P+CeGx9{S?#_Z|VB zcArF)6CLXek8+3L-H)m_=JX?)qsP&3DX|*M_pTC!>7*3xZN18sRrO2(c5a~YqU0T~ z9xMP((P{#l?e@Q>%;=g>x1g0D1Zx8>^T?_15V^Br0Nebddu`VLaX~Z#^32RuyA&3^ zK6_r47I~JuYzj{G2m8VN<43LRaH)AXJRKVu2LJ0 zc`jqWGF6?`{rVGgMrSQdl7vc}1nnYa_)dK4-Kq>%rv^$0JmhjbhiGAXhVj7@-z%t} zJ(}}lRbRFcHmJ#9cOz|(z*9OR8^5i^C8X8Z>?erIX(uS4x~qw&ru`?WY__C74H?}p zDJJ1UyPbJW1tp($C#6+wj+I*lWqh(4Vi(Xv$0dB>xIIXW!2t>bAacq+L>{z5OtZuJ z^bZjaMD_tlH;jvA^U}O^O{%lZlIENFygMU`zkxw`nTeP-=gp@H z&f^IGuWL9vaf4d6LzJF1`dEWHeI56hLu<)q)6vnyt@+jKY&+wS#IuN z2D{8v{rikJT8l<>Y7$A27oAr{fCv&B3$p72 z26^9~9i*1x9Rc;9*Xs?%4;nk)?Qnjh5;rhS3Hrg!DAoD2*~xY)r)wk}fIf{<8Ws)V}`4_tEzkQci`N z&uj+_A-}bJLir&EHiftM+(41m^IrxjV&-l=MTD}@BwM}65b{H098*;xFH3 zHY3x?dGj6e!Zs6S-zWsxV0ZkAW}$)iPw#k&aC~+I?%aK^)_!%B6NaptO7=q=J%>c; z{8`t&NmLSLH~Pqcub=I?%Qpn34+tdtV#_OGG&Q?+uS^rxW~-q)wsi7C?tk(7YN7w| zA*5Z!=jCq*GVAYl@4W<-3&w5a=}r5sU4B2E!|7gkY&#sZ3(eG#DL?aO8A-?40-px&^!z8z`kL{r52ioL6A^b!(6Xg$zh$?DpFT(3IMB_cc zC5lOzMpu)Xd804y$2icy6^2H>`O?%~=R0O=2}SM27%s~od2 ztqQusi09*I8UJd%&ksJ7U8xNJmEL|8rmcw|t$YmENvWp5DbbZ{vYE2q724|xky16q zVfA1hGNAo~O6p&v&M+{i$ztB9yLkyq>aK2TXB3v!ka&4j9F9kQXjah|!<;3yz|D*_ ze2=*=Nhg4130y;lejdZW(oz_o%MEGbBiDivR%-FcOdj(9KRGks!)_ zQ9wj0rfkr5j6Hr;M~MAH9{kSxpwV`q;fkX2 z(yK3I681W@(To5OiZ~@`Rk|va#c9NXe0%aEr-I)`es_M5DTs)l@T~j=pMP~mci0p;*l21tNu*P47tMW( zM1MYlt!jSxnD;SYB0C-4?6xF4v5|cdq|=#Qoieh^nlSG;|EQF+nyn369~;;L!*UDR zk)80{c;>3&PoAh_`riHh<+*jY%F@>YUw0ns!!5gH8#i1>_F`Iv2_L2@DP(_e6adUy z?=;j+OJhANa7c0p=W-&GSg4t4j?VyCxxHIwUFDgHey0_pq>OMrgG**%ZiP7$4_QCS z8)qEkl^`<`*ql(2+}py1(XjP7?Ebd1r{c?e++hI3KL8u)9yKqFNq3Nyy9kO@cR+r2 zmU7%RFwc#%I|~5d%EU^u`9JoWLNUl|=rgrm%zx} zXE?RjO0%HS8p2o4HYf%jN1Z*%x>OCHLi_nGBq7e)4K_g$2a|hv7@#D_<+GAPIyn&2 z+{%KdgSW>4+iL1$vOfjmB)qvDy=++p)oSJ(jrGKf-hNtF7y*PJgwnI>i)diduNYLO zeaIkTXl@KSdrozh@WAa=N0C^5et#V2_pLD9%RJnMyYwW_S5`-N*2xPq_`T{k7*i%IK?S#$o7b!%R94< zKUjRO6hkk{QG9in{o^+f9zq*4j-lT}c4Z8F?4$Lr4T?#B9&`W6>*IV`THwZx5|{2>q*inm3VR7z_t0#asu6APx&7tCD`$I5?UQNsRlxlCGoc=*6HD# zk!ysHRS|a@E~e&`FYe#8w9;c=roui44;XgI$YB;&_7eUxeaN63CRzP0?fSxc@o-~M z;0Kv+PrDKb-!niwHMkmD@(N5*FNKPuGUXRPFOayE@Z1ZmNHo-eb_iP8tCIM|#LUwI z6Ig<4yGbf=O_k_WJNMqiZK893P$DmHsMUxOxS;3r zKfuM87#yu@vh9L@!ry;@s;J)v$A9=VI+<@6WUw}YXfbbhM99zC(5Ah>?&$HSUautW z$|2mj#Z&h`A|DuIDc*oeNRaGx(443G>cs-60W^CoxK&Gb{=M}}cFh*Js`UQhz7T^WynWBCo4AohO)RuJ_qUVmT-m)UR5O4|dRTZ084atr4_N=%r>Eio={{vl*`y zKoJ&YPv5DmQTT~1=uV5q`~&EWm+xe7Kmk!PDcm9MN|iJLSdA9ud78twq!+Kt9PFyo zX`i90-C zg_aeiy5!q#XGLx;IHfx`xoyz3zQA*ou>b-oFh;MG&8~t~;%}|%mK5?n`D&q!6Ionb zh=~xzpiJJDlh4%xZ(F(=Yv0GVlo%LZC5eq)=7z-d4Y)v3PG#cmGEuMD5irFp7?pv1 za33*IIhQ7^5`BEC({D!0C5aX93Q*AGCKdrl8fYBOjzH2j>G6@-_E11> zV3II>)s&LvDUD=Vu9a*{1e@*0etl!M1V)}=t!38gk7ZR0+vGDhYx+f{V}thrMO;N_ zVcJyXg!2vm3$dWLQs4EXZk1DnY`+utW5@$*Y+jeY{1gZMq^2mtpEBOWhGeF+Fx34y z`Jl|}EBR2-HgM8bED-BK$itATft7M@w6_PAd^krFtjw60K8QU=lOK7soHcG~j+Ud| z6pvw3e`~o_&>~Rb+M|aHbC4$cmDM@)O#u#+isSH&CD>9T8X8%OFc6};E;_UqBB&dW zvE-Gg69AC5(9NVVqHW^z_O*XrZG@SZ!Sl?h{M2u$Xmhui$G~fAN(~Jf;NyRxSKDf`OlAb&g*Fp=zhtx*Czq{P5ss4AX&vykFUjsp zZDCmcDC@A=id5TaSkl%gy6>&KB^`g>8HHn#)w0|_pxRk&UP~qdsvHDRZfHy^%ti$J zc<8`Y!nHFArSiplfcS|OgnQmE$LHBtOi^mAFIu|+u(Z%sdmhsK9B{npoPJpWc|~*Q zFWRzJA`mU`BU8L=wAkRK1+zE=fb|mtV}KlC&)yojK9BwOw6#@tgWNYY6|mV((C}^|ny^43#Tm>ROeu}!kttM$!ulvQk644Y};#bLYq@)-#_PUnjgj#>2{W7;_*PUs& z0DC4u`nKEK`VC1a(^bM7a|ZLSocxh;zbZ%4V^(TS2h9aQ1QrB_Q6nUQYw$j;7>*I5M2sWO{zde`*jws1?o@xrmNH~aO=mfG|72aaht zC;@7Tmj~&;4xLy-1>vQKXrJMgE zYiN@rTL7S8oPtccgs83K>_&dky(FM~^)RR9;5d$*9Q)qWH1>=SDJG(F;Eu7b7F3nY zXf3gtY$;}jeYkLjz<>PRSlx>3Yw?wI{bcP`!C%cO z{poxBQ*T=(xK%3(_D=E3MD~P~p-Fom-%s5sUU1w>a>Jj|OeVIyIn>*0{HwNQ%P`b%>awfZ8#lVwSoS_O z|4Zb;uD!I^>ssawC!g{D9XWNnx5{SGh5wbhVZ>x)<`(V@UspJprREYMS&#(z`k+dj zMUk5vmP!yuYw5OLA~=iGWX52UkYNc^%4H_qlDTnd8@nqPDzyM_P~_5_Bbc1qSrP#k zs$c%mk3gmFU<;Xi02Y;Xw+F9DUxV(KRZbZxwdUro5K#??#(sW^U^t<0N-g+~rY5P` zYeD3#$x8qBt}))2@J+2xi<5x04NLkg-+M@}TTH0Td%g5ZWn`g^J+Sil>qRQzJEWEq zdo4A%KN}!?=M(Q-KBJ@5Rp~W;_Yt{05764t`*7PF`s}@58V`r}Urm8o9Nla?BN~#h z650L+41qwDyn!i_MaXm?A!*)&2w`p3m$Gc3*>oOH#u&@~D*0AYYfGHcwVr1o& z!GCk_1meT#+8B=N^BV@sYpp`czZCJ^XT8~d|w zeMe-vJ*9vCaI9dfz!Ta9szl+kSKWP%{%fpMpK>#+- zpjg?@Lmvg-2@4!I$4K&i^2oLtH7SZcKL4zw5)bEfn8K1PuVmlCG^X01k)JaONg>(F zgvhy|#S-yUPE8Cn8z=<6vyknOe;ax5&}c7TUy#fUm3hkZ${ivhJs(a?^Br|ji^DPz z;xr)O!F*-;g^b?ndx|lI1D?zR{;&+HSs4#)Ep5Y;O4?)=d%do1`kv2*qbJ*F2wkIp zbtof2_QZ^+U#Y@VJ|nWqpIPA&H(qQb#A;$Eq{DG?wEze{rY;vi+~-VN)83+H3qgn-gcLJBTaWq>H(MfJ|Bg1VG>hKdU8geTVF}!=0jvl zwuv(~$>fSDx)&ynl;|C840kc7n8xSTjayzX!Ni3|-2Zk-O6msgp}ZGL+N#utQ7v{@ z5;-X-gku}(p_sh=VM>RE`AuhHvU-AMB--~Xz{h&PXPJIg;ks2&fa-uzN4P%c>fJjf zMF4*!Q$?VP`WJ~JO1irf)98DGVQT_vX9&icBkKoctG!(sh3`Kzeufy&q$|^FXX?Th$?QcKgBRmp}(usz&C@$BJ-J7MqUPCRM;0tN)5P<2>0OL0=G;hBTv3vBL z4fvzld3$Q%*vvI%j*ad|(>w!l*KNJ}Qv*~PXF!F~{j8~&30Bt#zlr|WY&4 zN-L04J$h$2!Z0Hwwb={HmYp^*pp=GBotsVyDVL9RIkid#u5D5^8AnLSpb4iN# ziT*%yOH)~~=dVu?x5D0;H*a-6&E77(pq=w7af004vN-f-eEkW zwjoC(+5$#CmZ7G!?x}{BS&RGhVrzWN+w4frHer?*USLTRgE&)yiZ*(uvN3qh_7&{`q zmdw-$XYumnOG$T&vx}%+FW=+f`|1dT+;PW=Hfk*dJ*r)&=ymihry!&?dQZru6wc?1 zgOM$odyL!*@Do!cqkbOC$OrXhswgV_5^ptrH~^J`)4ejk_o1&S@Z~e(a25J~tZyWl zITnPqpX9dl5)1so2`lFP2OvQ*rZ$|)_zB}(I)6HpIXJW;?it00^^=HKdCE1)1REa? zfH0ZT0>BN$BeG>%Nn%$|V;uH_d_*Xp{NK;a=wFOwu)6HQgT?ER=)5h9-`5Obwv)U9 zXTp7?i8BWGe++Ms;IzHHoKlfGAP~kZ_sYODp6WqxF2Y3Zvb4*X6xxUDjnYmr5t9qCSx;&qVtR3CyAsOmTR2X$p6!IY z9fW?YTFu~IFWP)@>V63|?#e{JG)4P^>&T@yR^%6xZ{#Xfol0IIAkFvi9HdMD}I!+WBuGABUKFa?FoUo(bPQV+FQ1wRp}Z#XLk8FlOnpGpq2 zpP)%Rq90g)>qaZ@h)8>Avm3iZ(zlpW`-wc{J`WwmkxAGQ8&Ph|&n7qU_()dG5j_$b z5_qy}ahCP#+j(cnyMSuC1wxVYrKjDAo?!x3j8e(llc6{4@;Zfmb(h*ta-;C0)YYM3k5^8{~ejv09`zSp9d_4EgnBqr8C$rs+`&Z&@#V+(h^j* z9_g&6w%)mCTA^ag3P$AHB3>-pcZmwSHlyNLPSNk7eMP|+r&yUtYoA2XE&;)kAdH9s z;&Xuk&;TmIwu`kV&x%aUko!ch)rHFx*$4}99z{-+LVc$-HhvA9#O(W=ZLPU5aMp6izoz4`xVf4p*Uxa6WkNVXPsug9w zDJhLp)d==IMbUpPS&0-wOzvzGAw5i-&#-tA2daL9$o>ks@zh5La(Lg|^xO zv2!UgiT70m63sd{`9iD0;EyT+@IMD?t=y^O%%6LVr;JZ=* zh=4Vj1z85;&ePT*cekDF;VLin6nsGcKA$3ev*aD4J?nt5EFF%VkiZL0ZJuzRD9(5p z7rZ-DQvO)*hxr!!w}hG!I#|L`J1jNXic;{_SE7X_;~zj$qT+)i*bEB*7d&GxJ`AHw z$uCpoMk5>@G%?s0!?AP$-5pq|Vq>|~9kK2rK;~&r-)P9)dv?O{VhjNB!>9UDAb(Q7 zwRSv9Ezzd*KY$Sy;vOTtFSh$KOT`(Q(1C1WKKr0gJPG??>y|h>rxJ7J$~)XDr@ht= zS3IHZd9(Pwl5nrl)#P@|<>Y!zbZh2QP09y5?AV0*dg$$t`lGko_k7ZbbJEJ3?8#HH z&||xx`CNslM=}7M(1x>2CPzBgMT!KA4w=BX{q{s^`x1zjPrIGyS5}?en^q{4_n8rh zBJ1OZSOQ)WDQHqzd>`Y_RkvP1{-V8(wy7BWG@E2rMmtwMl-*vt_fw%L^@r!A0g*Q= z=%G{s+m|$fl-;h~;lV7)#{%5C1;TwZVJNOI(V=Mt1}A?QB4|mhi7HSLLz}yvXVVp z{_{1=Jv%7YQBVZLAD;Np^wfR*-XFg2jjf~7DHMI1k=iB7EZWhy5GddG+;#z?!;t^) zo=AF0twGcq*a?f#{_9G%HyZw}UnXzsU0J*mwB-Ss{{X&U`PL1P_{wC$3OQ2c(iusl z?9XW)+GZN_WsPr$Th5_mbaOCUH~3?t5; z0};En>7izq4i7g9zg__RVQnjeN}e|yWcfW7?Wogh$FsW=u?iJlLcrL9?C%NMVkX_J zG^gy$mA0wrN6$$FI5}P@^TBv|PNHO4uy6#OA=|EE474Z|*Wa1L8 zJKTFw2YR5A5hLeii4+X8=R)R096=J<9RTLJ`N59lZC%5-=b@gy8;)9bdC4Kz`pB$X z;R`o-B?X$opiNCqD5Ng*%s~6uM<)VmRsl0KCJG``DOPs1%n|=23pMs0Kvzwfn?pNF zO*EV+t`;kL7XPv7@;*krdZQeHKq*kxG+DVQes4TY)2K*?+|upA{#Q>rydd+Hdp!klgr2e z16Ee7hwjN`4(4%Y#dFqCAJ5(UmTvcsuWw`q7iZMJP-Bqw8f~o|7qi*t-f05XCk0f( z89WBiKO~ZP;TUW8$Vr_b0i}l6#WxKH&}r3nVqVsCC070&5`pGpudhDi^9xonHmb1H zLg661oeUzh_l}$x6I218MnN5zdxTj5PLwdlsxwbhh1uUmb*c+6e$RcD-A5UV=Up!4 zj{Ry92<;3bSMWQ&LlCg6JKTl+@UvBemSPr4`qFI8{N%Bh-kRneJCy53**BZ^`u_m~ zLHxclB=XMqMyI1Bk`iqmp>wN%CP>sQHYd3_REA>n!+xwoVH!!dC)d`&x%3X$s9rxn z%&HPLO-(aENI&;UQT7H_RBvOvK^W$|ddbx%<#Kxq2HBf<$9>@+`~?s|l_>7;qou94 z=)2;#rIi6CB-&tt2E@+Sm?TAo&-|l|u9GbgVBEFAi0#k^0~hqzJ%?D5dWbI`rxRyK zQY6#mtfVVdLJ|UENpVF=NR2iG5e9V?bBj!(PMo;X4yg|eVO~;55T_jl`N6em1fGG5 zxQ7oA?*i;##xJ%*k|u{PqNWMGJu65u2os{`PSRw__K_DD>Cls;B-^7&@7%v#_P|1c z;OZ`3e^M{#9D|1{DB=uhRCn(qbHVz>!P^A^pcZy_ynbTv&R=thII-H&`#1KMiN~F# zDu4hVi2ndfTXV(c)|rwdHu1OV%!cdS?G+aU63-rhlV-i3v)r5Di@ACi8k2jOO@x!& zSQBfRjy>k&J(#y~^MczvcQb(%E%_F4CAjlMIcEY3VKMByC)ge$-Ruu@$R_=NWo2Ni+3Af@T$x+y;TS+6100000z=$QL2HZW^hCi=NN!{el z*~eX**X6kdNvdfE6M322=Y6@DHymSOoG`yb(|~sV_KkbX&dqaX8KzVzHBX}Yj1B0|1Bx9dFP}lyh zsZY|*RC^@H#vY_%4sWfM|mPlh$ix8$89(dgwra{73eAnO6*xWi84T9;5PF-V_qXs zvV|`TDM@>?JamgYi7w{_I;N>BeVRlPe3a^1gcwrE7qA-(CTDZB3@7a-U>w~%x>v0f zQVQDo%31}j@-TS^@G1o~s#hQncyy!}^90L=B#ATW&I8EWl{oB1fRviS;zY{n&XXVl+6VHs>yq;vI=y9r8K4#EvYA4#YDx7fRl1f_9HO%2CWH+1t+THs26*2?Z?@<;<~clm*~`06Vs%1N1c zhLJbxguFcIuVTkhRh|K0CxuT(c)PN_LYju6slrkirg31OPLdiI8{QIZXLvhcLrPMm z5-g=LEFsL>cj<@JxKMyWEwNz?#wEIk^9)w}j+s@NnR!w}YI*WWkPC_`PVw;-o=)B8 z6j?fY^9fp{Bo&g*O0_{Gy{|joP6wG*nnY;;tbiTK0VG+s+4wk_@;Xu&E(FZ1BoIV| zfpKV3jqL(2u#9xsbg)q@H8zmY=F)tlkIxlFX-$a)hhhSxSWGjCZ@wAbN`k!Y^d?pk z+bt2spp|-k)o>3I1R0!GXOg96l#tGpfK2)r-N_(s8p2CCbpcCRbds)yAU*q@(KvkN zR6lm2resQ1lxuL1K?OtADT8Z`{wsqbjjm4MST*r{>`kC<#LVxu*an~!9?l=O{{Sd{ zhS)H}W=5&BdPsq!rhi-QJ+_Quq8L2L*n?|3+vkWWPE=gnhIbqOnYNiPg*MqzkgHFj zz($#nK>2SmJMb|epDBVA#7j$y?YMTeuYf6jVY?L1V=vHO>x}e0GJkEYX5pH8fJm`P zn6gaCDT|Y7jAw_Wt1zD}kV_t2nEwDy2XGqk1(89U;?j1p0N=YeS&f?>ELMuF{*y04 z%A3pSO4goy`j}R!xG>#_iS2U(oA%E!uRlX7A59#-rF5xLPN1V8x>>|pYz{6xm7v*5 z`IRK=%-1PNuoUShN$MSMB<;2dbR8L1ZLB1dPe!7p5DXU;u;TX9JN|eNv(%68CCdtQ zR8==5vvFV#=WH9ssx<(BTUAuB-2hQ`stDPzr4Pl4s%E@>dRXnupROiul%Zalm-L^&+>$4l1aKf+i^1GXVT7tc zQ0p)*K|6V!_qX98u(3M82|i*>2OF82%iE-}gnn*Im)6 zTChO>0C#XENjHU9fqP6yA_n-bNp-g2PHoA19%kEh$6J>VQ2<1wwc1Ztfd2s6F%Tw} zYEr#2q_m*|^CTTQZe|Sc0wnE&6Cun;*+5Ti&&}_1QADJ<9~*9M)NWwgn0vQ+f{?A+ zbO=wD7Icv$g?JltjB&^T~TY@3s>u zD72`+I+Rd!l_jjBGXp5^U0tY4xCg$_rCK4|&HogdzL_G7uL%90yYvKiALEyjlew~Qyz|IY# zh%}f+(#{kb?uKnqGJ-MBvxnmdR=5T4IAOXB@19ELU%>Mu`;Uf}q2rg}5%S(Qr zuGqq`KyHWg-}+%AsGE$kw15E=&T2L`2ov)VNQjsqfg8;Q%3wpb#9T{oMeZe-Mg~?y zGlD?B&(y@sIDpvar&S<+%BzSc@07$DA^}ZQ5DC1=26pTP@J!s0H}`d8s5I?hKB55I z1q*(HUznbaXM$eA=M~2`C+`Z_`j59JE%N^WIO80aY)Xgf3cpRYi#``74eof_{l}%C zwiNP3A2h|zk~?sDw$Mh$x4sfWT>5g{cIN|9tVv+!lm0)T^~ESk6t!>(hZnvWBqU3)o*eYFFfG0Y$v{b}c~ApsGNo8RCVjgRZr@q>OH(Bzq?5Tel3Bmg@_6J_ z>ifKe5?puD>AJrPK_18JzY~tH!RTqrpoC3I%Pd)fU=2Gkl07`k_~*PzpjBWTc@hC> zlE>>9ld0*@%T3xLAP@xVCJB-TqXcqb{zP`jLnSo9bOHiOpph1m&>|g)rDX(MwiaxWbpT~Yl@V)p?lEshnt}lVfn*nLQa~jy*`zUX23b`} zF6Yf0-_|3bo?i{_pb1@lI&`b|bmZPhNhZ)FoAF{mo;TKMf{>73NYu?Pr-KqWV>q2C zN{J)Psctq7-5|1=XmkCfb5Qn7Gw@95&UaEO+jdOmMt$b-!RS`3t?)? z@)n68ouFBO{+NR6qN~J;RG^gx6v}P5Ew)@xoxmq}u_Q>_9L9I}p48=#HGc^yNK7}D zk*U>*Qko9e1<89Tba)+g5Z>{12z}i_BW;Rbmg5uePdEPhL`UwHW=JM47O{@Xi%#a) z>nb3r7GhKx}{Ah_HI01$e+jf05AMP-tr0d`>T>jZcI02jk4+Hbz~ zMM`W^+u=?S0Zg{oAaQBrLAS8QaH4B?ipQJEq!QaDGY$sq2E=cM%JgNBVp7*>Fd4Uq z+D{meSZ)&~AZ~pYIz)jxY6r53leMvU&Zh*kmenG5vF;!@OjdfE?rv_@`*p#!AxUqE zJBbFw&As+Ka~-jO2L!upTYs-xVg*j%^=5mX^AbNS8DXNWB|wp5CIKKpfvHhpa|Fk< z;%G=DxMnU35*^@KuV)deXf`c}9=6_xA z8T05K*!l|F$>wH5(Tg)y>pGa;W zg50=`_>D)QO8#OQ#n=#$cOt-scspVY&uUI>pXPPJUSO!Mb3p9VYbk63sn`Mlo+b_B z&3sb1&iJNov4mBuq@b5=2s&H5Pj(G#cfKD(_g@do&3zBe(#8y}RS5@Csq`3n7Cc2bg9l>P_AKEs8G~ApY(K?j%nLG=-i(j+7_jksN zrqE0{FwwDjFwM)x>-`Uued9c!lmM2z$CN;ep#w-zJcVjVByl~)7OPWAR-)yI06pJ+ zKoDV`(B-vA0uoyPrvF7|@xp<9AulDmL8YHyMAl!UTRc(8(P&0Yn$6kO?Sp+lz-K6~GJoOe)I_CP z&WH&hs`Cmbktq=XqezmlAcbA-H#665%yl^HGKe1i1?;IN9`?Ig$uY(vR%pq2<$)3JjIW@3sidg+>3SekYg7Ghm=TDmpqF;{Y{ze!*4pHCaHu5i5g53a&9hp z07wADciwQ8XoVEH{3PCBwwZh1xaGzwd_~y;(q-X>JsTpE`@I10DWhh(Kpo~RBwKt$sHY?V5TXo4 ztWKd24Tm%Dw|sL|18w+&&mW!JXJ_eXmv@K{F41}YMd0GqcvV5>bx%*FKmfyG%b75W zZU8?N-`WY|9R^4re4qJcnjg|5rPv07BUMb50_Dqt+>b);cjTO1RHVQHAniNeK7EIO z&lg}Y9m{;r`0nEhkAfY8w=6o(_WGSvg(Lz-{{W}={qZ}*Qdz~?%y`&zkL=HYmfZ2b z2blT&Ew(T=pl(Lp?fpguOI+K3nf-5#lFXz8ra8A9ZNLWbEsZDwqDYtD=;P_=*2HxV ze_ieMz{x;P+w*RD`r0PYEf$<(G=G`j*BS(v0Di3j+t&MILfI#2x%y0x)OP%_ylk)} zmjS?jY;DoL``}L{L`W&Tcj86jf794wF$WwTn|5X&r+L7Qvh;}ZqmPKr_xAdp2HZuC z<+gx9`^Q-6jfJE;U+Ort0ruEoE2$e&a;oA}C+?3KPQ&*~f<#F+0Nla$O^A>jG&x8+ zZW_|u9-)T#iCwlX8|D3Y7H4*RbH}S&jH0Jj=Bkj0JQnJ`xfean&F_uoJ~7BeQ7y4Y zAIml@Pkcxy>MbFa_PhT8TR%oMn>Dpdw%qoCxEomZ=Yl?bzHL5Y{L5Y@NVfX|=aMl8 zh}lP%+oOJg5O8NDQA6qzZ4+X4j^Y8E6F*I`ssYp+gK_eR+m86cEUu&wEI&=R+Z5#} zQg32Fkpt5w(h9i=yr|!49E?>k3WDQFB;1IWYnQitZAwWj31Z;Sm;vT2+qjRB7C0vJ z-*d@ol#>dnd&xlfiABP_je%5)?H7zGnW`vwMr4u`S2Ivir(w!Gto96eb1u@wDu29q zl>u=^n5d%(W-dEPU=OQ{vuThbRewn&O~{n(upIBbj@xqdzv8lB1b}%Y!I`lFZzbfu zIy&k$5#|hdCEt>48-eMGZ>MQ}G~ka*OotSGLKdJ(G}`2z_OZ3G=-w4W-O`|wsp(R? zG@X<>yF}T~JYIEAQmUWgSpakp-k0IYxx@CAlJo4gks91Z_qt4~L`b!#xezha(5L4| z`kC5KE)M;6YhM+{CPW{R7w?G~qy&_}m`;%-8A$Ij7qoNUEsNBr&_SKZwTB`iBKN|? z!A!xJ-Gs*ekY%vh&#B#OGE!b`P0I|e2`SSkQ1p-$uvAFm#vsNL%q3~9sY!1rDJ;(O z`Uj>ZML?vKm-8`i<`LTCrtW};xJ=tOszdM ze_~?9Vak&xa$xB?{mWL4!XjzQf#(_l#N4K-41S zUEn*ocbIGfx}J?fNQ9Q_1jqRP@IFvgSK>RXOcbJ`s^AOxP5E>G0OrQ$=m^IZNkX@^ zt5G0?E~p9PMHHq$m{2cb9~P~rz$pR?Dw<0w8(N%fC6xe>c4IiPT{@YsKnWrnSt-mr>bKHFW3{M)+MG!RgfrWFLmPMEnuDgKbq{dFIVRSCb{F3Tyi{M6k-%6CU`i@lc^d-KD(sBl(F;LqsYhZ0rUssDBcvcLPI}d@NhiLmi!* z?G1dYh_=NoFiD*#m`r-yfhe;j3=#

5t+(+)eM!ECNX)ETtP3TN>nrcAFw@Q{Ms<9PRu1K?W!b9 z6(;2;>tb#sgT^)k2zKjscz>n_uQ7d@w|zE#0f)WBJYh|w+yMl~$m#?R(E@G#Z-S)< zppmnZZUOl;M>vUrE?7Y}(q3Db^y1h8neW+|4_M{^l&MKgGem%s=Du{Nec&!_v?Rs^ zs-q{8@r=n>^3oLPG%MaLXorUiE*ew=me}H-?>Wy6%d`3Y;)f_tnN2?n0^e4AK~$`2 zc`7$2TBHGDvQ(ui45|tIxZfUWNdaq5Rb2FU0qo)~WD@qrpcNe_Nw$=S7ls3Ni-Pk# z=Z_5X)h>ucs2trY&^BP2HfEB4^SVpA5Hkcsvg+U3^xGxuRwU}HIL%Tym zbBb6BI$W9BM9s#Q2EZjiwS(ev$g<@%LrR4YQDhYZaVnTmm;}L-1K5r*ja6(&K4v3y zu`grK_U951?n_^dI)ow1&v$|_Ag9a@-o?!u(g`Px(DmrHA3khM$|lpw0cbc@8` z2BJvN6vUlP_=eiFv;aul_Ya6I8dw)FNHOya;qBKCj}7vl-qzMBG7!=jOr(U3Y9xs~ zi)kV)yzr)JWsrdYlA`m~#53_7XA+>2qDdsh-UE}+TsSZC;$3o+&@2jXU~E!BiG$o8 z#(ua+DI|@WKoc(@#_l7GO1eWx0^^|*f1C7em_29f<^#SU(dtToWf^cJ2_Tmf0>^8W zPbs&|RnPHgfJc-8ey-OB-lFFS(@*f~24_)r4Q@WaE{%&>Lr7EQ84?3hY%HJ*sH=g! zxPu#Fbywveaq}!h4v+oulr*BHGrDRHKimI<=24D0L+ymmg^mP1GcOBXtsc zfo}U@Y6DRWKp++_)&%s9Sh}stbvZ^glm3ui{Z8SB=;AY{qan8(gQ-hc34&4x8bJ{k zxF#k!2MnpeB4D__lRHdq-zUUrfaR`8=Y5YH^WNCzH;QFd9ZKnoCCas#gF5P6<~A@6pa%9a zicb{@RdDu5X4uFf$4jt2pkvZ9$!c_hO^|^WK17qT+&_FU7^Nx+K(Q)8Bn1^}D+$$o zGB-9h1L`^Yh?M^T%-|@nf;_f680I@-#VnHB{Rcn;%a7^S-grSqPgPM8newP!Pz5?* zXi5n(QwozYXop8Jv7eK*3IB*a^Pl#Y2HUAMM20lRM3-|l@U8`d|E&#|}ni{LfW z$h3kZh>kh@_?_n&4()rl&!=y;23Arx{{TOyn0#d|5FlG?&;5T~U@iF{(~s5gH7!qO zdvhk|uQuYruw^v9fO`pz#mTrbWb^%;U|F+9#^;_G2NCID#~Mo732A2r-$vd(R-Ak8 z^2s+r(~Yjz@5a9UHq=yF8=_li(^`e zC#!JBkC*f~Z}n3{_Eux1F%&fllN>bQBydRi`&$O4NIq+VEN(+VVr@HIHa1lO+_J&+ zw>@o+arJr>GMbs&?^LSVHGbx(h`qLtmA2kB)b&%wimpZPNI2uGn}fy-73PnX+*^xu zYsS-9vv7R(ExLjC;6#ol^B0Trj(;^P^qu90)HS!p1J`o<&iDOW9?H}My`{hIVq=}g z?pY7TBJ`*MYV!$o~KUFY#*;tL%5;DUfUvLmPny{o`&# z@h6OVQh#Z`v-di^t?))J?VP6eCLfarq2;k#@3Xi60Acv@by@r;H1|L0Eot;@H?u$g z00-~9bVRW9+cHWsvqBJlB9#?3W+Su zuuuiJ!<9TvvcigdAIHy-ieUIgX)a1&k`cKwTj6(W31cn)006J?V5epk_CfIhD_m*> zQ51xO>4<(urV4?)%ngb39Ix$X_GeC+3--ssA6bK%2g(uv4d@HV*khQeJVK(Q!F+Y3 zf_y773DtM<>|0?6m&2(l@Hr5 z?7o_{FWWx`0im-gFKwH+0X`_BRb@-x3~2{saF2;)he1 z(Y2WUm3rQig-#)LF1ly{LrGkeN8SvrU};YK$mVR3`)vJ`6^(w|csM{%C9?s@97XyG z>H`zA_IKk2805QPu=^tlY~UxMH@qA<_&UL?E5M@nb%lz$A#^;krM!Z`n4d zKHB&?MdvUDk5A@4v#>Zx)Mf5m2(swy)Y zzp_7HQ`5Mb)uG2e<*uay}RPVf~rW@w~=+Gwp|irjpf}QWkSb zQ<{q<5DUsk9T~XAu4adb)bQ$AT7C`VMQKG4NBc7{8%k5EbZkebVTrpW{{RHf@iwH) z5amzVQ?HwCA;7hHG|LlXDTn1-Kmc6KagM=Xw=da3kl*yz!I{pk+|ddpZ%$R&%L7YT)%_(H?>|D;yxo> zDACGgYlYRQluC^>i|GKU@PG($gmXDe{S3LSU&H)EElXNc@AEl2)M)#~s3kPY){vb_ zC4xbo&x(ObMEz6k(^D{~->Fb-mcf#@Ry_#`OsJI;D%=1`*jv+(f=ZH-#M#UlfOwI2 z4RM4jEi}@l6*5vCWQzdLak)0;*lxEF{|FSEN7?2HHtJm0n`Nl@K_cuZSs0)JZS~`xmf#?LU?RtxL2y zu{&`80L;VGjqs$>KpIMuJA(j1x8txMJ;1?G0b=mmzhNi8+oMH_Q(|Uf-48!bA~2%J zMafcZYzcrz%6SoUY%+qDAxsHl@g)2tu>$T1E*at7i(q<5jU@6I^V<&2iRkb9K+ZD` zkZ399+39Y!>x{t-5Tc4Mm&mFrDb%sJNv%tAekcYYSkm~tdIv94D5Zr8m6e%VL4{~) zbb`8yi`0=0&TdJt${}>CQ_V7gN4cPtDJ?Y$>Mfza;UI%M&MPe&D%9fifuqa;Guc{a zoyG4lat|2dXn<7UI7lQC3u-q=w2Aq2$8A*UND2Hz0L(xeb}l0F?I#wS!mOmHETdY2 zpa&lyq=0phJy!%7kt1soJ9j<|0LoHOFf}XwVx)d%k?BIC;Y7;AR9 z-rQorW%O!OjU!~KNlv&4^dG~@Zx%7A#7(hcwSsIFXB#`TJfG7HR3$sG1i5p)pXU>Q zn8f=-K(8*HrrPry32C&plpSkur71#EK$4{_r2r5{qj9t+QE3{?BqWk;X(sF}^RPZ! z95RHa18fb0&fCdvtn6`Syk+pr^k0FU032Z_Ghb2u(aszwA;nZ?Icw|kh&D)QXi8$q zI)RW##~?gNr<*8E}$Nz|7K53ECtA%F&3%r}NESeuy7 zpt7>YNS8`Zs;Y%J6SxUL2u!L-F{B;sBt?kDzGA5=(ijw_wK*3rxOSe$tHJ3vx-i6& z;FyaN05@lAJTu|ws!b?_pn_BqwB7;ST>escKU^%8IcJe#56;od4tapCWI;2uK^JTE zi$6xiT3E)<8y4!Gm=rVyq=1H|U`R><1jowa)-o?R($vjjNH2IKmtuC$l&s1wq6`>=A}3-Aypb?3dBaLn-*z^&pV7ar8PrON z>JolOr$fWNxNhcj%UxPUgftG|>XSN5>;MLD0&!oMZ+Pl9EDK%09FB}VOa@XpveklE zf)XOdo!p*US)xR~3)Isgx+=#)5JD*GlvF?=BrvJA#tpSbnV6g?RCT81&X{0Km%mV1 z-)9DJN+-=tr_KQ8=?7u6_cD3MD|+$2H>n;`m1$@YM#EE!lPTU~V`)~=7^Lwseeg2|zkE{=ec}Tj zhyZPMJL&8=`(fmuv+5zAZNM+IH%D(q#l7&Blm7r|)^F*cbnPZBa0Gx45H_^&j)yFC z+@C6X0kFG2C;MSc$Re6aHc%dn?|ZwJFw!R$cs6Zo%+Jf)bGObxjiV1GK)bmc0M9*m z>RbWT;=M(I+6&$H8{4kdiF^tf1L6_%`FH;P?~RhEVB^!*iL~G@c|S9Zc}WD3bGV)( zkUPn-w%c~wxDGy_d|^>63F>!?ZNu>7$6(DmN~E30Hn2Y{bGf-Zj7S(}A1D1V>FJ0S z5=*fL*LHpOF@K$)jzkM2AJ_d(AP6?=^#1@O5i5uvJAZ$sF{F}_r(yZ`xc>RZih%x` z{#c8W!Ju4O`FskL35bsV-_CxU{ym_=N#tiCiLY_lASWM!)<~)eH6WQ?~nWgDKLp zea_4ah>u^aGc{Jv2m8Xv5MWvi$S3P~`tQytvmk|E)4%jTd=MXrhUex0`~Ig1v@1Sg z;KicESp9E*^_e3;-=3eZq<%)Gn) zkd1mqv=-Bp1P~QyDJR^?C*v>u+j|YY9E)6xE7Se6{?UJXW!L)sD{stCn2*>Q0vjkM{)Y0)(WgZsv3S3er6l|NlrH9u~BqW7pO&E?89Bq=Aud_PG{18lG$ zk@$gdX85!@Z`xzU%K8dQ#C1J66%4lN{{YmvIrS+6RmC755jy}PBhwh+t9u#j^(w2T zd_4J7Q~v#BIsX7%@IU$=?C<@afAd+N{`-Uf0JJlo&qx0NppWZ~zx0psfByiPX}|g& zPCbYJ014mow28)l(Ek8uf9&)B0GiDI0QcNy`$IYW^ndyY{}Foc?+z{{Z3X^!}fIaG9Karo3OE%j&AX+In;rnp=Tiv2t+* zBESPkM&v*i--*F!dl&5WTC~tSJ>6+ZAG~HI(vKqbNlhxmIZpnS1C!=Jtp^KZ8Y+5;q^e=x7{ zAhg9g6yep9WKy^mNw{IDhadF>S-3bWaG zHdlxEad#kp_^k83_r*r)U-2dTS!P*-^;vg{^*KIP!q=s?GHivBl6ci!Lq^uLD zi-rZmJzj6e{A5a0B0muZ!@6PKQAWxZ zBRm)+VKXLNz8PN%Q}Ak5i_mOSAh{PW6CQdY8cK!TkxBp98O0{cwgd{b5N zVxNUaOcAC@AiFSOwdK1`AEn{wfCrXIiRzH)hTcnnz*yj_x{<(CptTKTMv_VM7N|-> zCP`8BrXb0^w??mwEEihp3;9w5kVloAsGcCaJ>22SejJZ4@b*=}Z2(J>`%AHhU^nRp z_itwnWwFDpU5JpN&1I7+?EA9Rzuk21npoVa^q zobA&ozdZ?2NlVW%L9&L2)-BwU1YW{l zZ`qxlywLNDr{UICs(glolqDtFc9InmqJ2g*@KjZ~I}tX=e~|)?PJ&4;5R$>bA;|{) zd$Y8e;B&`TW~&(1q1)jR#10ENZATM!L6>=z)QE8s6!K(25)(R185@h+-f=b58djlj zURbk8wD)2hJ{AM<5ebH8za4n7#pnAyczAlhujyW>r}J`tok-2=j*_OFb+sS4FrrVW zt<;r45$s6EBkdQ744;S8Aw*ToA8}56&t(y?03E!}(gO@K95abfEWzNNLz|_6cqQ4u z0~V|8ZIYL~9eSZH0J!w9z#i5&8*x6$=70PuP;9)tRDgHTbqBM# z4}U;$l@jTZ!F!hsrU2NIKDQXDIW}6FOtylYBm&(VK|p^KgHoi)5@dwwfI%E%w_Q?H zSe7a*Ofxfe4F3R0*^H#JW)7EN@LZR7A~@~F6xPyECB%S`0TN6oDnL|$D%4^k@*wU8 zG=)5+$rl7OL!U<6w{e84SfsMMSP3(CkQ&&mJ$;boSx1SrG?}d*Ps60NKZ06jA(tm{qkW@qv2!J~X z0JIZ}aYsU*EtMaLwuJ5o5|osffh1mJ^SyzN z7-L`rUkx7+T273qwEBvjbzuQILZP_T1X?$+l6Kn+WUW!munuqD3ll8-OtEf{D4A8Sl4a6BTITka{7$-}x5J@|Odmr-gY&e!GRN0sv zm>*r?+}jPB>SZdi$QIDp7J!KY0gyL85RL9k+X&ZFDsI+eA=C|=0_1`IpQ<^MPGgn; z4!iYztbTKZob9h8AmITu6Ks%IURNP}qO(Eb1VM16jCF{wu+WF}R#m`?9LY({i!WB*y^U z{P5nkNqxFUU>N#r9^tWY{3E8<)OB(bD9c|`fDmA*vYjUUk|5gS7WBgf7ib$07?L=i zc>p^!g)@W{rOxArfquZx&y$NBrjmrEWG2FN+Gn|mBKzFWz8a&bo|0d9WBTah6}1=w zRN#%GAf28&Tmgd0zpH{z_xgPM;gB8r0)AKsE*}ArJpTZw?fvm?aUz=lC!+!K+vzwO z)e!}`hU+cV^!a1ZJ^uhR{&?1farGb904sM6cpEp)-#`2~&NdKtkFGOWY!sVMJ_8xQ+(VdBz3E<4bzJ_J02WYzmZvB>ac>{IL*-a6LBS2RDC1d~B_Y zH|xL4>wFnyp{PkWKO!LgKk0Zed?AZp`;2WW1b}zqH=FdI(_s&+T1d(BB*nhrP(cKb z`?Y#zOxzg}YYp~*E>Laewf#)`^am4xQ4$B4Bs_s6blh@!8$UUE)d1yA@_zG7nWE)?&Bl(}Fa&b+V z5?C2#c{c*$=We~-vUH^#bp2D`y9qARC0t25hN5-`0KAPrL~ZkpbO1fz7c8ULBna3y*+lJ+ zG|5zIhLN!Zhc+%JlV)azCIjNgVSHKQ&-h)L8t$BJhZm{ZCksSsDj_D|iM$i4B+q-B z@cuVMQqC150GfcPdKn)g8KH;**z~_;^CGrG+?4{V3e%;e0$e)NAZb?Q`D;?N{ zv&Wrcp!l`d2RqDHlu$Z;;X>(cWJvQ}PsM#uQzL|eH1El3iWxeM%#MMGYhFvsVv{*v z-Y-f|kuC!Pcy$Bm<>WDl$0EMjKWa*Dip%Q!E$F(`J=Iy0Iy2hZb?Z(`PT)xty4xlz z9zl}Xg4ii4(|mge?DN>A_?1L>*N9Uo$$fjURGYkQfhNbrwpy)7v^~hS@_iQ)%(a%Aq1Po zK9R}NLTQZwI#M+002>BnFkrwpac1)fc%E%JEV@E};?xB+(moW1Z+W=#xo5@o%PA1k zl=SSj+if(IrKZx5ls408LQ(=mNZBNEFYkvIpp-jEkNKZt>AQE^99dG7RHCb$R+o}w zNhFt^yyKkxP=d!*^&2Xb=+5&bgn=Oh)VQ*5AOmy0$81&BAvF~)2{*aakOW(B8tu7h z^gOGard+UfQbU4o{5T%4&eC2m+NdF(Qx7@`Op| zI`XKN`eC|Ab^u9G1U{`r*~6AB!HJ8r1BMP~R9kI2-LsNoN_`_%kOX?WlWn32Az0;n zM>GH`C7kJJ^Aw#VldzKvWIQ`#p~~gSARrQC^mC`F;BE{|J{t8EickRrrUYvOPST=5 z_(7fKZESOO^NJ*;48yzuA5mzC+C|k2s0>ylT|0CGot$p{F(!Cf(%-hT1ZR1WE6b>A zQYo8MlUG{Y5K2Y7rc4#bBqjh7b0tjG{{VQYD5R$I7Ii+;EK44|xy5&kXMcC1a@0T- z7LPf(MKw4eUDQL7a2t5X&`0=nbXwi;PwfNMFSQ@-ZeP{8T`RgL&7;fua-o8RkO@*! z>eMt3NP`g|VZRft?y2}KB0*JO5u;ql4i#Mq4M0-iQh?3+5b)EB#nZWG-7@UDpUWE4NWfUWkbI;}gAi^4ph{FAL`FNrvJixS zEi?^IE)oQFaAtb$al)-isam4a2?|>6uyVxlvP=Iq7PMcYgXvywO)?D*`b+4IBC_B)}eo~mm` zYt%uU&bbOiDXMj#ea(`w3iPs4vL|)Gn8%I#N#ch$pHdJxi%!DphXz}CE%gtHcfmgnU+cc9Z!pXo z^D;i4b*j3ws1&sQN@2=c5TAuWtv+k11f4Cx60mVgE2@PnOMo165iJqskiuE|;yL?obb-qJUg*xCLK2obhbO0}SxRI5=Ps0zJknauij4l#U?-RLDSV?oIRCJei z=s|OZdMZ_UOv`2qNC(t_Zi^`CH-bTd%!q@FwJF|RTo?H>dNemi!r~mf?9LylBVr;u z+AzZF#)FxbQqlA&EV{i35+tYzR*(kJM8Uqq&L7AT?y6k*!F}%|=`#@57`@3BpzePU zuIJP-Ya6@avbG3Pka;A@g9J^$xD#P%yzzWAc2J%GadyAo?}m_~OSHL;{{TIW{czZQ zja5r35=xRF0)3??g#ZPU18#P$um1oQ_-(Enmi0Zz!gYx?mAHoP*6X}T;u{D(V%TS- zI)&1eN9@;Arb$^OjfJmi7n8}bz*7rKLS;-P0ho(_(16LcE_MoBmubr zwGhNS7QOqs92m%{LbFN%1OV{$M3Vwi6bIqh!P;a2$|z6qsfL1}TyV@p+i}&15HQjV z7?H8+cP#G4@ok=M{{Vxm6y~|rNJp9EW$0{3fS~)N0#5*G2Tbz>gBY{;)WJ=u!2nC8 z$YS#FBl_V?;bfz~V&J5~w|91e+|H^+%8Zlr5n^H>ZEt%VID~+}8`yU}JIS4_F17FZ022 zlOhKH0Fe6Nm>E^t;I~iLcHN0=Y5_Y8W(G@=a4J(DKkxhg;~9-(WS|o;W_a2R%-izY z>xi3!0Lbsh>#)W@*4Q+J$p8xo{{W|J`{NXNxqCfT5|9M34#q1_(24k+9NWMm0>jtszb% z4T(LyOS5r|Osx>)shE-p*mkzo+RQo2*9}Hc9Gc4MX%+%Idqch5XO7)ZbN*e;-zPZmzVS1Qb{uta55ny~MS)2(YY;{&$SHywraA;DEg?gHrz5P`!-;9cND~mPKTwJtcXR)=As`@xRZUb$-g`jV$8wXBkjxyH zVAeYvZap6!#$z$;W-}hfV=;n4K`Jl+B$L1wC+I&+W-yinn+Z6oej(=n0JS=Xr$Wk@ zrXiNXwi+ZDzvA5XHlF?Ggi-fdI%NDy0ID1G!IBQ(aM<#nAIzM`iB@F=Q>JvFf(wA; zzL{00g}w-f=@sEG&y43KUPE)b1n(m z2hsI<^?pV3I70yQ@wy7f_j@kAj{Y>zMvXM4l?pV<5{h61 zfD}Ry0AQ8`T4s4Up7ETfQ6A=klUlGPAt(<{pP06zWf35?$mHVgbQetJeJ|6LS!Ptq zlEZ6t<-Fn5QBzQ;)b&G*=E=idX%;SsA<|}6^ zn)TG`)B->x1gA_5A_$%X7dy5jIui~p!)*ux2;N8pSP%u^8QS;07Ok>*Aio=fJ%6^? z6)~$&;sEsN(8TSwIl0%P%j=%19kaTjxaCPwb_swujpN*6voKG*P=a+mfVdo!*6;&N zzC9HFZ>~5(Q0jL-#36pHoRt z0mX8l1lmn@aHwT7l|VX?NoJWTl0Y*digpdY&4xdEO&sP=E9F&Mxr!*M{)%c*a$E5b z=S#zuEf}wBs9i-ZJwwDH$917ocp*YkouL*NJiwdd&od=!rkaG3>`T}kEFSIi4Jnq# zeL|f&Yg!WiSrH_VTD$kKq0P4QKFG)xy zG^hZsMIW?vf^(TP09uY?B9h+dsKLR#RK8bP-% z*!lkO)5E{^*TlMBoPDPkK)$T0IirXg7Tq&>twM@Yp{qjNQc6dpl_(h-+7Y+m0GybI2H4fnGgy|?pj zlrGCvt+rf$D-$SdFl`r0XaFTIq(XotK_p_|DdMzqo<$#bnJGR}LPFpIX_LO>5&1tW zmaZx!B~F!)1f*`ve7_2*t?^iHy+<#cOrFwN8xsR^K^QeV)s zwA45d(s&aJ9jkq#@h|p&hgPfzO+ue@mvYKoWde{G$kOFRhp`2(hv+1Pn}G6L&3CY7 z1EC{_EsoaZnL?aG64POXCqhvv(w5smhTCpz2Av@w2o{bb!SgwUq^U|)rGKQAI*ENs zo4GvA_c(PaWF+;}?Q4xJ#DGIQ79NKRolDXbx!*}=*#oG)Yn4>eYYEgt?zXbah_oc7 zVKS(h-+02AO!BhX{H|%@jdZM}l9x`Qs1hHS`TFAi9t%4I_?^V?ENn}HWwFVsKA6mx zn+~69k;gM+=1a;EN)lAFSkvoc%Sf>SB`Q%=d?I-m_SI&oiYGW$kwDTF%J%nV0d6~j z0I)H3z}5p2EZ-tp2QX|4yN#P2M)1?ax=x1aOt&JZLPc5-YBPF*2D+Td(30}hMTl)h zC`pn+Q$K`^c;Ae8vb;k-Ub>b1KZh=XDNP~N?x`j(4KNW*kPN?>(nG0|Loj|zHpCK3 zm&I56cXWrH(j5WR&9n=-FIQ90IOr0f&S(LK_GGNS1h%hnI`w5$T-g7Ofz3yDp z3FOit#Pkf~a6sMDtc?m_C5mnwu(tPS`R-03YHD2#wE`3wXlXJCB?E2r_Z(heT01pW zk}S$BZtbU$GH(*zs0dMp0>D~f`@@6UF&K4?Id`e4njvZoQY5J&CR9iyMC=3;B0F0b zejb0_bu|0M0R0%T4$S_qi=4Or01P+tksC-8%Lg(blN;e7>RoCjNxtb&H&Qf#B|8!f z_9sn*3>#5P2foZ0Pj_SahP&aaWP-*=uh?(a+>2qTQIaDM- zi7K>R8tP@JL&NYOlcWwBd3(Fzb%JXv`CW;7faCgzFag6y#J2p7gU?qGRw1~rqCE}0PG@0JH#_GW%m{i2i=d(daZQT zGFO~Y%3vqWSvP>a1O*t{35h@D3DN}AU}QiY1HJhiZZ>>0m_q#CW&pm=Y4s!L(XI!C zRB1>1NaP<&d2>NPlL{`pwE|>_1Ohgab|7KY0v30B!O{Q>;POF{uy!UH4C^&M<+>D~ zNU`qj;f5vx#fj8ndEk%)k_efZ7T=M}K)DtX>jps=?K|{}vIr;4Kx2Kj^)EKN2n1ld z*aQGUfp2-6o5t4n-!n-7_b zi<}cvToLtuTVZ3*E^rZG_m7>&(DNTr?~Doxw%E}5KK}qdF4o(<@qoepAvU!C0G)@{ zJMD>MMYr99eWUemm>sHhF7c%^xjVs&NS~1)0e)?PsYDpG9$&W){qYS&;sknuH@F?e zr=e74jW(S^=d{7?GCk+9k8uUmHwpUicHDUxi%C7W zHu?PoTZ{;oyYIAKN!^J9cLnG1(noDj{Qd;;~J*sst9xE2f3Jw&(G8;`>&PDV=JQEX)}`W^dD!;Ymu9<|xg514vGm z>6V~b9+p;w*caO`VDg?Zny=zM8K)_pAgZco+-4TeN|FOpsH1f_cMk01#;GB6sDgrO z0!FGtfTEH?bSq|ZLP*j}GfVvp{hqvU={}~)=yT4T&uKHRkk1=RnyRIFD->@S2`{pf zuAS!83pFh}rA=N$0HgEIh~(?#Yt*A&nyFW$wIygH;we^@C@9=;MZ;O27kN6`K}y_d zX9{$wDG6{&X55G)cNo51Ihq{5H_G!S78HQ%lA*)7oq=XPxVg^K~0m;*JpW~q8kf&K#&&mrbulQx|D6~E^+8|sQ?j5 zn+6OX!J*9Uyord%kyotR>eMPElBGkEe>2py+|D^I_M-buWPTk`*Yyr}P@3MS&5-+D zDbnmX7gJKOJhonS2qjecZ7RxDQ&zZ2l@!csc}Y$?pJTm`&wEXtPG2sCQpr$KRiDl% z5}IfxQjr?#)DQ0Iqyjw4TO}`w3aVXo6%q~0{uCe*&SBcbw2(qzEx6~?*-mrTT~C;G z=Umh|nrGR&ujU1supCPvWR^i`!la?LQlz&`$N?=hlmzXMv3xVavYr!?%j9yjkxGtP z2~9Ml1^`@=-esyv)MTi@mYmjDok1`>!8)lEhY4T0*%B0348EdJ6nu*)H8|6_*Dvr zPrY3u?vV0S2>_k^t*Jsc1B^-iSw%~ibS`(6QlSj8oQ|os+e%7xAU6Rkw1T)RB<^?K zaF>a!47On;K+C8JZ7`<+fq99Sfr^h0D_@A^YLcyM&7z{!a#ZJ0lE4B$v;e}`=TgzH zC`1KAZYoZYR6R;IHnjGW+rB*MK>q5GB!J_k_}B;=W7%o>b3~H`f@TRK#rCn=Z&{ba z?63A`O*xxXp+9`g+=kvGOO4VXLQ{K`o2c-q0N>$bE{}CbS#Nn!*p>%i1&M1Jer5@$ z@k-{lZ`@Nq!lQJDI;tpnmHz;CIc8$p$vr(yQJZEod1D^BobNHp@}?WqC2rT(F-#kY zkfjByx6no!$|WkUldPwlyu`wc__&`Co9Rcr_>v9oTiu0)V_*n zr$(89=5PsTxi0`%0An3S%QDvLn{~RD()}yQQXgT&rN)-p3t00;U{p&HLKypDz1SGt<1 zx~D1DqPD5&nM#6KqXjyfr*&jFroI`C7RM#+7meogs-u^yQ7Rc^sXBxcQpIW(DoYkS zZ#cfnhfbxqCPDuINCX|OOFK_TFN;A%N`jD(l`BeA16K(ks2h8wB{32J2`~&CadoPZ zWeHGq2~gkqg7Y}AKzL_h`dxtr8SVgs2d7LbRI(FJkqHF2ldRcRxkw06(8Gc*hrhC_mEV>?Hr}DZ@DJ!JRDv_qP zt;FnBpfw?SXHtxF9Y$x`3YEMME#aeDOQ{tW>Sa<&fkFg3avxz9!etCt$V`SLu`-hm z?Bw(|m@~aSB&cdZGDWncg&2b=k)%Kd!sm02T~%Othy)p*sJ`}tV{6Qy3y(2vfGz9r zg3!>VVjKHR^kM3+1iHGB43$)6$)wI{2>`>nbwXV#K#2t@90?=gomjp0S3aDtk7SC9 zN@}T86nITUu(PMkNbFi2@SS>Or&||9=_hBB!hH*k+%saD^an%c9d(&dWqDc?rEM_0 z!mY%w%c7>zkn7GBT`mB0w1NR~#U>##q3Hf6;xxQ3FIO{NWs+KrFnraO=47Vs0Su#I zAd+!dglkYr0Gp`vHzn=H#KT_+pJ<;Ca_*1o{JNhgVQ9;o>9#4>wW%d_74(bJ^Xnv! z-c%t)!jU08?HF^|{{R%J;vNxJu3-NF5N9eZ00`4fW6GYu!;&53PA-Kc(W6ZuGE^Lo zF$F}BPO=@~ovb3~75&x%5K5ssQm{l6owXp$d{PghK~=~GG1I9)t56pQ%ngiu_5i#H zaxEk<=)uH10yr)U&5p->H5;XsIO38&VG5wk>~^_eH)vq^kNjm%-TDr&ULC8a3e+aZ3t8A-VZ>hYpkp!_AM~SH#G5F+t)vIuT$b3AwW~A4I!suTcXwa}@BuH&9+GHe&e6iH z6Y+g+V&-iC2%Hxc#4uj0Irk>fj8#of-VWPK=?$#l4Qw6Mq|;ObG!9<-)O*;8JLl=Z=C-CVYxSKY4=lk z1w{NZbwNB{{PVT1iR$XZb}aVv;=>ULU}o+?6Xra*i0mzmlSv#zRjNV(up%q~ zlQJ(b6~q|12XF+4t7%|h{dfHd?~R11i5*~zvyQXZ)i`JM%U}C5o9;i{ozhA~2?8X7 zN{pKW?PF|WVM-&Y>if4(ig^(eiBTWKrVGl2$6fnx+Z^Qa0k8d3?dSdBfdWK+=BN_@ zO#8vO?-2^`tuF^ki}ZSbKEIH~om9CcnjhprA2vTcRGi_kYE~vxT#n%)`|oH1PMwC( zY?6ot=W)ZRe4uav0n6cHm;syX%a`hByg{)lCSm0QWPFcfZvBnEzUx$dM1?W(m%DjD zJiEB-W7ig0Fd46YpKjZ9wTl%9^H(Ni#VJR>sFGyb-KP6)G3lTcfeuunR7jrPT0I6l zc&RAdzzx-iXNG9>9Ae6UhtG^2IrPttc}ItS8n%r0rn--+8_To2mo{ZpXIxp8;xMsvfwBf@ET#%W@fU}flvXr@!|GfN0b_d=0kvn*B%Q%QBJOXKQW zBKu!>L*c(u=AIe#{{UZQSv_x0=0_^2doVQ&Q)PAG4La>QYt+|~QI~~27Ts2`mf^sl z){@J9W$iEQ_r^RQJgQk*6}&?zx*1yee9)wdE3Zp8mZzDgt1fF)QYs2{5}Jq#Uz`x+ z>TXlPeYx;#_F9cfwN;a-wJj!0dvh z`p>5NyY?f9ps#nQ^Sr+~ZIG&VYH3_kv=tAavilDuO*#*jr6tCabu!={73~Lw=KME0 zPGc)uE{wo6QSWIklbuB?Pn{#ok^_se3O^7S_x}K8JZB-|o*WaE&QQ!$%B$U0O*+)- zDJ+DkD>_t9yI3xjTTobcN`RX!0D=fTjwp{w`cD|@L4WcO+Zp43rT+lRF}56!uk^+_ zc4FMaecz?A??6c_SxgD|L=JsLN=}g+!Tz|;CEoXry-qQ}a$paHmSf&y>)RA_?Fsg% z@DronR!g4vt9<)#V}eG;B|k`)BQkfl;cQq48X;QAoX1W$LD~ z(6Hf138bY0pr8_`EF1#Nrsc1UA8U+*tklyz7f)GPl~h#UEkPky z1_HdNH|>r}x`3dXrizFNO9G~Vs@0%rNR~({0j}zF@(ad1qN}JpQ(ss0JFnH|M=oZa zyuPF;w?^|7FQn;ZP=?UTKtpV$At3sc6l9;Od>_EFUICP+;n_UD?&!-sH6*2$wU3IW zMISQiD7jjRB%2n%a~>sGS!B^dgI8C)RaD7RAbY>`fB_A3voIjw=S))tJ5cc?6r?32 zfC7?ZP#f_8f-h~caVjM{8BtoAHlQKwqndmm{wVMLIqT61eK^oLMrc^F#nSmtjGqi)!;v_M|6H!Y{b1cDZFqAo8T(|1h-~30)27u~_ zGJOdGB``^w$--3_tcCy;6%y8Adsy1mXag4LQ8bWN>d{R!z)^&!R;4K{3t!E5U`*kW z*R>(sn>A?)lI;_%feK2zw6;Q&IEzB2eYPZXUMEl*H4*{-BY|V(Op!Nx{{W_5ad+XA z!fWN#{FM_VOOhFkIA@OA;)rClE3Rp}Hrw-q?}ox5UZS-Gm3JCMz~5*xamdgbsRV&_ z1kIhbX_K|zc0KXxb?SSfs-%EIWJSJWZp<%e2NT_UNTj8u%b7YU=$oc#N%)DS;z@68e<2bvucG9ro@BY*u?Z2foa-0Zj=I34`SdeTJBe z1}siEv*B(><@nFkx{{q4ZFf?W0{Yipw4hD)DmxQn0yiGPnydc+;QDHEO-gh`!w+_n ze4_sV2$&t;6gi}jvIv7!$QINAatm`Opx7ui?Z|SsA9k9N2)oZAE1REMhM;=FQV~;{>LTe-fFjC$_*2rS~|uSx#DtR%x0-KuZiZ(9$3R zgv1a(6!H$%g$s{7%vLp5Q9zeklx9G7`a=QC#x7|93o#)e0q7bJKR4$1dQsAlQmG(; z1cCxIkzxoTR}dsxPWY*)vSXbj8<>kr?(^Jo@Jl7qOSul4F)l(`i6Mo%+AwmlqosmU zq6)oR85(s6PMDYk$V|RYYs0c>SQaNv;VXMhPMr|1K~jhKBgT8zi2 z`l_7BLk?3RgxIV1DF|MZ1_rc{K{8308)59#HB!puRPLe_PQqjb53>+DoFtMKqS}Ij zoH4VAmYy57z>_G_(aNlm9}&ID0Fs;RB2Use#Z5}21|`&DERw5j^4zz|cP>wmE+6A!J|3Y(QzT=@u|ZoLl(EjAlGrG`z)C=|M|Tq7RaiBjFGNzY$YQ@LLMfpqfK{ zWU`eq-=}_9_oTmSzut8{17K>0>XtnrM^=D>kfU^@Z4dw?kgR&2uz|cSWVv*r9Dwdf zI(oPsk8_7}2~ej&Bz_Zc#He0+?n|^0igTHTBAsi6dbJ<`INCvtK$1i!m?XugynQKK zGyp&G8F382_O;&tvJ^uW013Y)#KpsIIea10(ho|MiBO43l%S*eKrz@yaAx>Pbq12h zYwhSHPVcasMv4X7nR6#{(=+RBu@QLn`<{qluw=beP_@m^?y1U!gh1eXgS=ZZ-|-e~ z5|PSWm}4ia{{UO`eheQnr!Wu<@(Xct4%;_ua``NRu&^UpQsy~Yl%k>tl2bcG-0C6; z#A>^>-?z)>J*Hde0NHz>#)yX#Q;}=WAsueTSRg2}!2kVuobao7_4Z->yODgf_kBwT^8Ha8}Di0pR3Nns)R zx2@;t(+GKiUMoyiqP3CvvL=kEE+#F`Dq}|vU{^yvVo(7<&BKx;M`*JLI^fS1l6SxC| z1LkeU)-%s}7?Z@A`ZmL?_U(-TK!uc2CVp4$KD%yY zi(&+lWw?H4hW$n+1he{y>-ysiPY_s8>5Sl5r|zr&0Ky1RnLN(ZDKZ2Z7?MjJ#lg2( zw+XQ(Hh09ShObBf{&sLf67y}@xBBCpJ|i@gWzHZ^{`APwV3_hMOcGDNktC60CgTIB zT&3jbTNfl{da zOK&n`qubQFxGhN8^OpnFwW1BX+p+rFd?j3gI(P5(y9j^ji)@=PCe3TN>G06Y>A_2m zkOD##p+rJK2vm|xY%RXzW7g@13N!GK1)Sa=hP|#X*zpX((541Tgh!YaGcei9w?Z-4 zKe0F2*m$C@kLX^4sLDD=GOOsSF0-u6ssrg2+09N{K~-B>SyaJYTeWXiRFH=h;>9}% zYMGR`O-{>5>GOGy3ifB&8ad_AsYfhmzn>(b?9LgIm$vdDopWRpkRIX>MipROnM$hNQNjqy-5nBuM4+9?*Wt zv&4+og?O5hPNT2GmQbY<2_*>eMFktmlK_w}hv@#!{j$p_E{1c%snrH5BQ&(t0o}z! z&`Oc1gMgvHa4|EZ>@W8FX%x(lwZB@^H%yR*TW`jn5E244NJ^B40^A8DU-1gcfznA9 z#c#a*h!UcGp3EqjKmG=PQdgecwI&pa%rs;5|SmjzaM>Y8yArAhN?mf29T1f=dH+ZJE+&N5Zn`Pra#8 zD5t4P@gRORCUmHX*kcdux7svQsZy?I!qS>ZTGjsZSe-P|R&<2rrU76|Nw5Tv^dIdd zkvEm*{Vh9KwdSwT(eFj%999v?>5vMEQoHdI=i*u!J9k0qwpyO**obf=Vi8 zDE|NukP@P*X{LO^B%~0Pu`XK9Kn+)t6%rPOuTelsSU#OVDJxKUAw?j~+fZUj#8=al z<*G%w2_@G`gjf)eB4d5$`GYv8NE>VzusgrxW&!HhVyR~7KQ_X%?SW7fgn_ID6-3F? zrA1r~LI-;Yi{Ob!4oN)&vvAzY_Lq0SwI#VC$!6{957ETz?aPxnaWI%mju4&W(hqs~ zh%!5KBw;#=(^q)|i@yV-$>wY^x@53umbX^6`+82;P0y-6@0UEYAw|72cnVPT4MTEF zn3)6QZ~_<=a0?4bCFR3@xCGf!OBAF6c74Gra(^zMw^I;}OtDi`52;_fNr*bs2BH)Q zGjkIF+B;&iFs&(4nYIDk7Kv%%WH#}OI%CcfB(RN(U7|yYFd6N9M4f3;O+88!uo5WV zOp)-FHV4Caxs%@VEF+N4)Yd>?G$Cn%RU{EFcDU*~W2*4_Vd<3oT9EPnpa>)A1NN81 z58?Js+fKCN+e*IX(%)XRkX&$+q|g2{Yl{G2aaTg0yQUnMO~?*4tIF(Myr4TfY*-9+ zo+DXHaO4H3BnTmcKV8pDF}4Qk?9mkAF%O(8!Pr6-^>rP%T%%i@FD?Bi6SkwF@hQ8j7@0BK4T zkW?6cBJI+482X;*Dt6|%uoI{Xbtyoo>Ix(Tz~kZqPd2<`$UJtUhq)}_THx6_W&UhW zPUPY~&7Ur4mVe>T{o*DbH9!Y^a#O?1i7j}$;|qW&iaw*wX;GvE=}NO#6r_z%N2Uq? z0F*}Yk6X;<3GlBEl#NtrA2sHPI}_>6_!y_ox9?RFAZuA*EaX6agF{TSZHv9(wp1!J zFTX7UDA1!MYDsayrM>1LL=bLod~m)sT}YwsgZan~E?J7Do;vJ)M#~Q}lWH|E!VFf`>*8Yt)h zr0l^v7H1awhQd@x3UC1>;MjsK)Ppc?0ElZvNlFtWCrLVXB%f7)g$>M+xUna2Bam9( zcDp=-*RA$5w^slTLRvru?=IKB*^AD~NvD*;y+T#B!SsnFMEe^+f<>^ps<9?Pj)Y79 z0CEoTwl|jFvs<6;y^@2Dn&xXCK8}QQ1wZIdq@&tD&)kfATm~>fNr9jSRJJ7 z;hls1FsMK)Dd4l6pLY4R-ppqlzWYo9{{UE0rAJbTu2-m-0Z*wi44L>ulLzS-_s?Sh zM}`v20HOnPpcC?OW)p(u)90tD$O$YTZ9&>+sonZwsAde1T0xSMLWop;5p5tvgqb86 zgYI$HR$C`dapo;V%wwMIw@*q1hd4#B?UmJMmaR$5AzWKN?4ao^ON7(1BS02bV$ zwZl7*UA|Z6?=RF%4oHW7jtqS*ar9w`1MMU{o|m9yK9S|tI6yL?=vn}kL~lEj1_0j; z|<~a z+>UU%0GGTATo;!e+qI(ys1gv8{{Rw{&&cg)JKe#Td|m#6pd+Jb6r_M^t7@Jk+QFK1 z0#&hrx3pO}f=g6TchboWdzNY6^B`}EOzMGH1>6$Aaphv~a!C!ay8_sEB9l$v0kMgj zScwxiB2PQ>f)&FD;q3OFcDGl;E-pHUFW>U8>DwC`VKAhL7mMmYKHaWj+}{uc#~q{8 zZhpAZn7d20!+HX4PutTNG~0t5TqgGdOn1E5BafuD9-H;-Aip;!lPu#bez13Y_uH&- z10tO2k~cP1kOhF=AdW2&%wHNR+xpnr3;gfaF{9RcGyedS2Zp(P4w`tpoBE8{cidXt z`%dr%H01h4oASg(>_)Ba&qf=MPh1R^J{TX@`-`UFT<$JJNdo8f`ft_d0Y9kuw@%k{ z7(CT6AV3>j&!j**oyNzt?SUz5^8mQ()tb(Cn;aA;)Yy;6_E)acg$C&&FZplpdqEb0 z2^WJl#06J(e_M2cXJhw*F(8(K_MU&Qq_}nw?}${f(;3#lec8eY1c4Gs7XoA(SleL+ z2$g&!#J_1Q@7_$ep*WQ^e;$)V)JE2jj8#ag(PMf-vzn|>hx13N(X z2B7Bh#w=|Tp8lIO6vKc?=cEm+PS@jndo5%dhc$Xg7AYifW)&a+M{_1%iNZOxJFs^l zoax}p3;zJ!-{o_YPmwmXoAY2<>^SEJJUsB*t~^ufe5;^*GU;sdt@^t@QRMB;C^E_wqMd{xPSn-9TBf9BDte*jno5?RT+HUOxeT>j&UU>Vu3s*NDyC|+ zMAD>#WT>e}OOmEYlBF<6axvl5a@m~rZiZJYm9Lu3R;Yy1p_ivpy=saQ)albfQiu;w zus&3k7zZ8L{{RV}HNO>l5vM@&Tkw69IT}a`Ybwfo%YslqI-x*;01=BHZ-4z8s1t0r zf+vIV<^IM#_~kvFbo+amD0t3zvmM*sRf+!qOWb4W&8Hm!UPEQ)Kng-al7MGc>r^HP z6LYX212_2zXh|d9C?N&HltEDtERYW^YmiC4K7u7cx)Z5Q1Q0uUj5GD@?}6y(9%X8% zsi}3xoK~eEIIkrK_)?P+03>`P`CwIR(^^wXl_a4E0hCfb;SnlOaO8<%Uz_4osVyX~ zr9!1By8?8MfPCMZ?}Z;N1!2OFRs;fX7Y5U{#}S3xu?|}CgRpns8{;v&dl`(!v6##z zXG%(PY}reV3CkUrLuc*~P9h^rR6H787B=-u^CyCYOe}btf*M<;#+aAiRR* zryn%Yr~#@;2?|)efW>E{Gq%!wF%D&vrMgOX(F&IJE^2<=12I!`kG>tva&2rn~@=00~_u@m;xsl6(z;K+{OeJ31G+P-*Lv{ zqqE^_FScJJmlg~SM5YJDHoc6AgAjWuTjDdY=<{I5XcE)T8l+kvxd!&0KcU`3VXf8c z(#sT}sFkQJ$%PUu+<;G~QjcN;_QK0i2y)~fFFgtB;4^g?wV^9^eIWG_H!N%k9KUiS zyyZw?4AThx(mcmNHY9?rQaJ`>ncMQC&(r}ZO-Eo974nH@9S6~dEwV|}y<58^0OjoG zsc_e`j+LjaGnCaXrIraTr&1QQLXzX9UX-TtKt7egl2f;SMy)`yOp;#WPS)9m&SH0- z>%-_UNm@pzWRq|O!^jNqT6eqSA)_=o5U5ggs;z2qOVDG=MUWCr#-dhDt^g5;A1H6~ z8P7{F`ud)_{pMhyK#-KMoz!R5FfRn{h$pS;ov5j5ft0CE*48yl!QEQjb4p?@r}%^m zcIJmZO0-f)8tPR_QVf*^C<0QOf(dK=E!6l@5|pZ{;S{NS)^dtu+CPRYHF2+do#f=gI^%ejE8)93jJdaob;||Jp!V#$Hjgkn|N{++< z5C{@UkZuHHUGr#pXxfIlg;)viV8AJsb^pH=)C%0^Ht6PmCe&@GK3;i1wC`kCAzyZ2<-}>P} znrTr~lA$Rpiw!^kNF(@#yN>gKsZ2jo$LR+IX?E%B59_yP!d*=!mnvL@fR>c#FeHZC zDH&<#!0^uS97?79M`=1pEFZ{N+tkcE!F+OK?FO$q zttr-!bc#BK7yy&1txHJ~L~rU>1oOE1Gubhx!qg4*r1oThMy_hstRzU!zw3E5`iIeVRh5TsSGbr8VZvl4lA2kQpx-6w;g zl&YW1!H5J%8xNfAd~?waB!O*307)qzpHha?q=ThgNwE+J#HwmYfIw6{U8KKm!OVvt z`h*hU;P**#!JlpQdcE-{bR{7JF;X%;VvY~ux_w8$V!SU4`l*aqaVNy6!*Av+RC*l%-SK!eSqNPte$j0$rkGt7WE zx$MMxZ-4}VA~?9eNVg`mus&kzp>=klC+EGk8S z?oOi{ThtSN0UD>c-04e$B(~5e(fB00eH#%XU=GL3&`$sPBc)_NrV9Z`*MgIVVfDOv73~o%o)9~UY zcR$#7hS;~J@Nh(=U6=wLqnCC7iEhB(gN?DmQMtSg#GR}pfglhq2eH7^yUao9{{VNq zu>6|^4jG)Dm%-*~y&^@ewfpTLM&dz`V~}hzqb&^ZL4U))!#h2?P70I-d5Wb_ZtVL* zJ^A21sAKqvL=)3lwusWYX9|b>#1ng1EbZz#co7g}FQ4V^!q32O$P+j}y47BjTUuLY zB}pG5;vb!cIhW#{IZj z0OVu47Y}1H;y&1<`MW^Ykf8vm$*@o*QUXcd56}sNF)&de!LSFBWjouOe{+Nl%XTkd zMTPFxXLERVHI~!EtC6S?u}Fgn5J-{)Pjl)g+AFhb9$^Fp26iz!*xJV1P3`gysgZCC z?K_RQjmLBKz5f8<+vdMz?x673ue>oCA5C=M+PgE)dX2}ri#MgF8NZ4i8Prf^?lI9B zE@@KhhMV>ijb>H#IaXYnH!D+6&1Fh!kxaGHd7u8#^!>5$<>Y;&qgykc_9rZyojl%C zDry7l_lncZRQEnNnxupe-ZHt8x*30aQB`T>s?*V?f~wM1VBfG`XnX_1JXgfLH^iuA zm7nn>sUN)6q!pV!7P<&UT&7y0)Sz;~Xs?*g(aVY%rD~&9^E4<_MJI3Bv-~eScl$s6 zxcaA~yf)|_s_L%WQY^j!Y{?f(GSPZ0f%WvY8cqMDh! zrbjPMu5PAK(MoG6bm>$@6saL~Nme}f#{U3hemCsj?PEVf!e~^_crwwM@jR}5OQf1< z%J_vEl_(;$Rn$U1cv{M-r64EXE}dmlrkX)5+V(!oemGMrO8Oe1N&pYt=Y24=SP)^v z=Yb|+(Ob%n5>~s2GYv4co)b<1a0NN^F`41NV0R4Um{{Tij zZ~p+q>Hh%y!^403GZAns> zX@0@n`%9DMg&grcrzjie96VqLz`SQxk&s)vKfcO@{{Z6m`gSt>UBJf6`#$*2h#&TS zo04|ZQ#dQt8U`6o%&SIagD^k@U-%OKjHk-gNb5ig$YTS;%O!MNLgYs+`v@%i3bKC~+uaxP9Hl zzw{^V7ykfh{{Rc{oc>!S?C*hA_KPi)ua>7*KT5D&KM~7TMKv$|j*PLZ?`xH*6!Pk< zu}Mow3klYi=lzfUgCoX0nOC&FKkYRy2u^=5nI0A4xookooIW8+wMta7*}8R&B`I2| zRW+zk9`=|HR6W{>;h$9Wi`@y;{ZG*~8J=q>xHgTOm|x+xKcpi~^#SObd{oOehHxaW?}8C6pk! z5?O)iVjkA|VLC*W7zWR=5Y9Wu^x4}P%Ze3D+GGC!i6LW=z0<;yY$KcdVM?#&zrszA zW>h`r(-st)Q~v-cGCG*-1;>>Od|FOFBakSlYxf0><%swx{A9^8^&q)Nl=->MfA9pde{_SW*-KZYBe8)eWjre_`}d5} zOBGYgB-N;Pc>ro=Z88*m&dnnio-vvK0A>3>n5n2HrejW8kqqv%f~VvpGr$L?{{Tz> z0O9`tMB80M;tpg+k(c!K3oVT#0r!WTMw^0}A(ViTAdj2}eY~lwDU+fA39X!NPwE5K`L}Vrw=&Yh6ko%JJ((v56KryHIVL>5`=@BgV zu);a7;%926-^Eb?2MQXAEZ{KuyTx&vsDrOcFAT$Aefa`gfds4Ef0YczORBMGvG9&^Ne-T&GEHO)3q>_<% z0sRe&0MHl>o=zG;^0Q15XVdA@*mTk`g#?|HA|Mb&)nf!3ivU3uGZ)2OWhfI7Hy7c% ze}3}-5*XYLqUFu~Ew;lEUyHB#R5Wx+x~i%YwTUpMsnSdUHzCamH`Bx(ExZvrsw$zf z5JQm8RKP!>AU6Vc!0JJ3%iOVawD4SVceW#Ln*RWEub`_+NKC;qKMUSP}bV9j?V&LEgm?(%xtUye5~IJ`8hd5yBD2U-%ckuXUGc2OjV z7c(HMb9u*|)T^YeAV?$vJMah8TZ~(!E}L8iXZbfKqpF%msa`JrY zrvG@AgHv95=k#;KQ=g3 zW|bsHfFk-dk_eL;LbgzX6*eS;v=EY(@^+A6$4{wdZ|c$nf_*`K{{Xy^BXN9F-?d_N zt)@SRC~jnu6Xz@_L>NksBJ(PXgNsiNP&suozr0W}ay487zc&)lang7~SZ-Xv1ds_X z)^1D*XMKedW|aC>5d=&RNd;1EVo4wpes<>vsAfPnZtNXR^4jwej*S4xAha`=+w=pA zbi}dI6j4E3xG<-HO3}F~8w5t+0#DSP#fDuEw1*L1FN2qj3w=~jS z0;5ZEFiN@+=`Jbh4naad1*zY&f8%+xcjuga_Sre-zVGY4uJ3lsj++QAIG+4Te<vGQ!%9z5+#kAlL&w8KI5%0$!@HE#goVwIYitR| zN3QkS-EUo84W-o})(Q%kV$S-bdrJj0w?4AU7_ALmysD?h8f7xcUSWOm_OP4-+ypqZ z3B;h)>;mhYbM&h`!vLYqIykAmA6MOl0g-UUPN{fFwfD`}yQ!QcVKP+B`87OzZxrgx zvD$;VQ}v=|G_La>O^3`iuU3{QD!f(06pcdX_6J7?`eJ+oLLsYT+o3+0_z!jC7oc>r zlPM>ys)x}j5JFbI7*h|iug%OZah5=iXrBk+v&iwd8aT;6dACeR>D;finF?8uk4ZA3MM z7l4!wp_ts%OPURzIwgomJge4s+LBk6Tl+L>G(8L zZv!9lUTPlSx&pdrCmL_#Og~TiH};c8{xm*E|Kwhbt6mj3?#>#!%2{a*`q7J;-(7$U zjR3)T$;}mNGU-99M(A0XIoxrrlN5OwJF=CNV)7Mj?f(Mb^&HuCW z9-iL^Nzc5}-M)@A#o7BJwEGG&o%luN`{bX#TYWF8b*%-xd+)35`Gw=yn{%2uwn3O5XW6Ld(*DBC(b1;LrVC!)Sn-SaYXqA_oR`PrvjR-z z@9=%{K*;m;IUe!uo-R!E=yOiR{?7ww6kR&?2Ta4?gl}5g&~zzHx$Rfrr8RU#x6%!L zOK4!)Y;EoFiIE~x-@(gsz9`Gow@OrXR_lwY85k9Q)|WIsq_3}KJn9`QHxNmcmUe`o zVo@T+t>8B zEYs&isLuMvV-qvS!wbn@F#SzOAP@`}IM>X@q}b6QaczS7^YymheI`$0ZSn`X;fC(} z6*{g8)+nQikveAG0PI5gQ3&}Mu}16Z`oxkn&kVM1Q^+ZiEwfbUYN14uWU7cQ>lpJS zcOai6s;1@pk^7-B_hoL2cr#(3lB)+S&0RD*i^>#_d*N{}mEy=)k{AK>7 z2Mw=tXd2Cb@w^i_@W~=>mJ+^aCw_wNaj{#b`Y(+9GBW^oQx=GH^>7`NEa{&S=p`me zZ;&|7O{bZiBd#blG^w*J11ld|npWD1Puz;v0?+0C@~#qw$ktipcbnMM{Zc)K1nCBX z!|+PE0V#H2FpM@K1Y2c%`tG;b7L6E`XK$qG#bBbSB!XxE#JQ9#nWdfB?KjHhhfbDG z7qdDRn;x)jXODtyBd3-?kAwAHH;u(OC9O4brb0|gc)j(M_rr@H%a_rRl)4TT%+?FZ z8Kj_WsiwNFaH0>u%X4}1i?)#*&}$#%VclBtA3zu9Ggyn7s`68jLl&N0ajA>q$*DY2 zkJtJZ4tslJX`X*e2E2S{ES{HX(O?#E>)K8dqR;&t{N9C;WP@~n%gl1}q&%a^}6igUO{@%4+`OdP#>byo;+SRxg`g4xvJy^A3^zwT; zng+e3(~=G{g2#e*oZsJbw&(e6IQ^I~P*;+dl(V5+E^T`$Ft{%O2c0)9W&Ml26$w$0 zST#Q)*nXA_p~GSePQg6p1wkq3p_kKsi8l{M#JCyr6U+fa5BLMfK#kRW@Qp$a@5i!B8oaD2&G6=TOs4N$ zYZ9m34Nfe4)=>Mpzc@Vf z6U=*0`r*VKUssnJ9t$JlkbSCMkTh?r_ekb^K-h{d=RIbw@D^kX|4SA(&%O>9hnTv$ z#;qG!Dv*;tH7rA<$s;PlQt*NJ{K2YoXhmo77HUHzR^Z3Kch@ABKSpp@|G55)6aQO| z=Qn;*T48GP%ya}E!r_V3cD1J=&|H+tGx2qw%YgAP*0^kF55$X3Ce(|?46AI%vc{}V z!8k*D47KJS%;A+6N4&b_pi%2W9RNl+T1@Sv-+?qZ-;UO)U z@ZR+8^0zelajR7F+|N+ILZ45LwNG(Pj$CPCf!!> z+wcZrk1x;PH+O&+NOOo$SYX_Do;@FB=wk(ifZFYA10YtY63hrB6H^oZgb*txbn!4x zZ_%hm9nmuv#-Lna%lfT4#$Fpc1U!d9Zzz>JNEC7!@lR8qo6?B0_-g z5-=9~r&s?QltZOL>S$#RNRZ#c%!L$7FEfcYHOgFVhcKhz`I?10lQ?!M-UoZcfJ%Lm zo&yMu)Z{hgL{ixyrF(tb>VJUtFHs_@o%JiEJ;KRi*r)Y@^%1k&B!#QyKmpfwf_SsF zfRVIIElBQ%c7kuG^&{!-*nq@VRQ6sbq9*Go&}Zl>A=Z4zgKFC9R?97F!KJ= zb8t4XIu$et0JehdglI(WshbZta$X^lLgt-q`rX5fT8=*r24Jbyz6C}mIq^7MW(!Ppa zk@W1?ICo7AQ`@LFj);o|o?`RuZI7qz=j7?cC#gdi0J&>GR?8jYl(zQDDYf`~!~iV& z)RpF}p(lXqXB2r2sd;@B}R8Ozu!b8&+GCkjHuTAtFMs5osZ5%V1@KiF?aCgjl*nE#pg*nt4%) z4lRn?HYv{c6)zfHsh_OTHO249{0`_%255!dXjB)FjWt-yJ`#Q^Dw(&kU2%1wf=Pe# zT}g9!KmAT&^A1D$NaB;yjw^W9J(K38iC3EDySp>>}v=|YOrWH$j_$}Z32HuzNjUieAlQahe|I)`B7-#Ip`}Erv!VeLD|)! zqz&99x}VM53@U1y$k1GfCO~3=LD8NE>N=$ z+D`_}<$Elmli|rjj>`E6n-Q8W#qb5T8z^|?Jr!y;U7m)Oo_LizApfDnW^!31p z7r=|qv_cKW4m4{^MD_gah7#)e+e+AT&2mIWukH~3SEdVkKZgZ^m_r9DJ&~iT>xus7 z+E26|%x~o5oDXI%pX{g~b$8#%eSe1>V3kGFf|JR9(q!YA6fI{Q17s#4{q~ zH4zXu1~Ub0@OTl3g+>5m5wlblBlD<^@%WUPkAj*n9fvDBhU0wWsVV*g484Y%#{#Kw zT7Egrk(yQL?nE2D%KWmJ|Mt@#tL*oDb2Iv0DtZTRZyUxOB8yg{j`Xt^^!c(|Ggch~ zJKPFhXo!_#r$vw(QsJ?}p>t(aW*QI_795O?vd7UePd@gLCHWN^aixE+@Uryzi<}9Y zw1^|Q2^;R$Trfyl;k@CPjb|8R?)H1u5qu3*!z-N6HPfQQ#Ay;WTsZQCX?BUw?Brq; z00rWEDcN!K8qTj-4@CIaTRw5ps#LFchT7P1u5mSf&hf%~l1)mu&O7Oj}ttoH!5v)3i8HTGbyT{5TErQN*8kyl2s6kXZb}d08Lxd znvQ_h*yYqRL|8yppIh4J^DL#Idpdyz`D9(}ELJ%pO;gitz$6>OC{y?8wa;JT~ph4PI-!xRM=B7Uc` zJ&WFc!ID;Vz_zh~rB5}R{?y^Uq%;0ArJ^wVKD~x_V23t(J#%uRm@Qy?+HPKTYK3ez zkFneN;>E#z{WsmKkY_Wj6AZCLyE9#R&pl6>*E}lYngN-@^yyzJRJPyMs7}L4BTuXJ6D7op|`nH)H){$ zH=fB3dOsp0lIGai70NCiq3Q@V&UOaa#*|CC}w=)!$5BFZ84jx>AT6b}LBPeVnb zIUg3MO&kMM>%1j!|87>VY5LQIdcJv#{%zH9n$XyPfP`6{5<}guJ=?JYd`cyZ%q`C` ziR9zDKHB5Z4=FWHK+@jd=+Wwr8NX%t5LP1(8!>{kz>>87OLv@QF z&2#D2lt<#Ffr<{=6heHODQ!C+_*a@8r+m4+u&SigX}up=tqC%mORqj2E}Oqv45~;J z2?bevn!#BO?6k!Gb;x7OdUW3qK50+N^2Be;Ank}xvauAB-4sGhYCgf}`AJawd#zzv zdLug*k7k)F_VmBOeqvsA+%{Yg>Zdp{(4B8Tw4eg-LS(-dvpRX50g@GZxhI=#P;yM5 zLr$Cxki+L4JZ!v4Q3FOe-3C5b`q@i&{IZyx%x2&%f*Hi)Q~3bHeCc z_!S!QP%fY|bcPR0`}d}H?A*`;p8*oR_akhS1^i_cH`&S3UuJNV2p#rCmi)lD&XOs6 zkHL+u%>Cq3TyaNBTsq*Wvcf)MfT6$<~(Yx@Bt?J45iR z<1uOrHCRNY>|;VE;393+O~ za(J#AAabJ*bQ2Yp@PMm<=IoGr-h;|+e#h(UQ0y6{jT8L7ziXBPC1phH^cGy4VYy5( zvoDDQV}=eQ^!58p4oAQLz<|2_P&dv5&u!rOR-*JWkdSlWek8B0J( zSzNAIY>f~A7VXg`&ckAC$Zf3Fwx7@)LtEw<1M1gaijw$xXi6zsG+vx^oj0y~L3#rz z8%~pMmUXZDa`3YRgiSrXJ=OKoVG%=5H}4Vl|^Btq+=0ykZZ z%GMt0{{CiOd-SEyQ-+i#A@y&OGI^GG%9h_f@NU~bI7N}}{;aoZSvO)J62ztqSRn?1 z^V?JE{!P|X>bi7h{cyStzKXSrpXg!T-t9~hR~f>HTxM9W60*T71p6C+)lKr};L(he z@A;)#oMpmtV&K-f^Xc#Sl*%Ew$uiUtC$3<{FgB}cd;wt{#r|Kl0&W#)yU1;64fLKU^sqXe6B9^v43LLh<=D!yx%#0J<$QToS#Gk~NVzFOy! z=Z5L92$BdjE$2-iBSe4T;soBwHQ3+RkCYSsnGX*ktHi4vQ4N#BSKg(3%aDC`hr|A9 z%6zjMIwBe4dvIDgXV=xv$9hP{lgigpN9iW3@fq9~E5j@3SmybWvNA-om^k;-8!6;r zl*P~ZgcPW`#9CW@*oqBFZX>bk19b+cz*Mf+2=BX5>PSd<#Y_#=C6XA$r{pUMUDmMwaSg|A+M$x$xr4Y|BMLgw?BTn+%3a( zm!qokoDi=GPzNL`4#eKb#ZtDg!wk9S%r0v<_f&#gSo9^))eKbCALfF~M0`2;-YW1K6O) zx>{G2G%YU~vEXw50ixA4kBGn(Fy;t55Ghxef?yFEr7XKpzN6VAqTpf8^m^FqQi$)!mEsz%kX(wIY0O2!R**q zPr7^RPViCoJX_K3Kdx=sEqab#h@dNtc*W{J7fnMTOSdC(vj#{7)#ra?v>ORsdV0Cpw6(S( zK@ct1?5d*YhA_7kn5wf4V1w~R0F8H^pQaH{1{BACn{y>+T_A(MXQvzs58;b_>ACc4Ux?d(rH zx=`0O>5|6&W~nJoY|@>_#Z4>E}0S^u$F}WxV;Tln5wuC25C%z z@5koc+YOqSmy-2y?&bscfSa_Qge<&%pal5hLcB2!2v|~wV`?*1z`&8()^6!5WSNLo0SbD#6983@c zEQ+)W%1VD25=R6AFQ#wG+;mDk3wHEhcghk;#)P6@)h@-l7#67+C(}vWiv0kFAIb12 zHaj^?U5SL^P4uCY@#gLpAXmp&g4l~KJb&!Rb^ItGr{X0UEi!W`3#h7 zXTYwztH%Ct8rrXW)WdORL;6(Z;@8gjg`A3Ut#U8AM#_<&8N&*5OyhW-{(lNKne3LwX4I&_G{($Wb+wYW6#=-BW?!Pr@_Ch%w=m5gT-(p5=chwXX`_J+$bXtCe}2eR@Zo{nVY;H$PJEx zR5nNCj^YmlsIFndNMuL6^NC&yVYOlQ9o~50;1`Eg(pX$bEjLwp+j^S^yxA?>^iE@e zFo?|B^o%&Osw{ffXDylKdS@oXunqspDCb{jx9G5{WeR?MwU%E8ER=<@1CCa7Io;o5 zbF3Ep3yDoooM&%_MhE|VWRD%d;ukVBCV1b{qdxhGmJk<_(hz7sB!D{@VUKH^8-m|A zG)!x7;*F&5`Sfv$aBo8pMNNan%{t^6#=Px@RFwhR@USvnYS+ZU7%4`XV#GKT+hYgv zA%ZW>{yg}13qI%X;@mN33}M6=H!OPu+ge8LVkju<0MmAlk2+R~9g6tjUH;+1yqG8v zYP{twEP#L=DSLthPV=TTd@_X7McTF?^XHK09+^e^Y4F7A%*7XnwUhlklA5__nHN1H zC2!j)EZkRplcsj8lEr$c3n|+JWUanm)zLUPIkb_rC9a&w`5b*U=q*J6Y&h^@DW+Mk zW0G-w@xD3 zu`^5?&jyBu4{>w7k=CXIu_-fBZyrK(WBY?^?V(93wx&)XyA9mFP;M@Plr~On5X4X} z3?Cd>YkGp?FM6_QlM&jL%UHzRrE?iu#lF=t@WQrbJFj{EMf?t)ph$a;NH|_CPqJ!q zbEFFxposQvr=iW!3q0ndJoL6pvAj0l%HBlRO$+1K^Yy8!y&#|1k;5g3wi`rL6>^j! z^V2<#Ru1IqBe88gcsP9e6;F?R{6Op@Y~StjbZEFGWx<(lu8b>MV*%USDc|gs(ZZnA zdoyxK=u)~;^x$L+9^x#+=iGd_v&UOXaPX6U?<{GCAH#|{MbG`-_V#wC{CoeD4h>Q0 zKQ1U{+YBak(X_jQ*>XtAR6W5UY!6E`r41E1G1|ImR$AQ!U)H57?e&Z}NAlTSJ#hdUxt4yu)6*qUi6vOwL3nKGI=#qcistr#|y?Mh^Fek28MC7dyfAqEjWrOAiWw8%-dVAFh?9x zoz^vIgjQNhY5HY(P$7te4!M-5PEMVr3hi8m zRQqnpNkartbUKuXqkrr>rN{mW&(Z;UR^Jd^n*F?@6wBv5dIb>lElzH}`J+v~oRPs< zwpWj0nE3~}292IM08_1nfZ*t1hW=Xz-1eKK3Vh~J7eCrR!K6iJ9(vGH07w;E&KvOR znu8wi78Oqy5s_RnTCe&twhn^C{R)E^;TCaD=2yr^mDD!O^TKm&i29IdZ zorM5O8yEwXv?=eJsM!s0VE8^w7xjaIuc?82@{}Z&4WrLO_xIRW3AEYxIy(woG{1H~ z{Oz>p{H{N0nZ3{Zj@`MfbHmc0WQidg$+_gJW8#m1w}IQtsjl&ov@{{{X2iv>bs$&` z&ZDmPEYUUt7k{0O$d*h%U5_aAgnwV%!I=Zzb4}AkjhVWVr*I^-cD4Xcn6;wUr|Er) zj9+^-=65GMQP1CZqsXeEBBx4=%wX?Lg^2z0YKWz0w%NWzo`PVIfOvv zJznU6i*c0A%FXX!Qv9S4Hf^XrJb61GHyfw$s>r9WX^`=4x_>W_KN&tC_ ze6=o%5TNDnibiedYlw}|=XX`87?$y{iPb3W%*Ga+oS6O!n@~{jZy% zGQ>O)Ko1Iz38Rt|z~3YHVU~5*GO>VKk?WE46S5a7pS|snW>RfQ<&dT$>hhQIQ0B?h zddJ+*;He7VM9Wv2fz=)4bTuNGw`7Svg8i-3f6=Y=P8`JLMd;2(Kr~N^<#-P;WYl}P z*uhCjLoV?hNR47*HGpNpI6A788rDQ0Y}^Zjr5i|#rj15QmmHrrt^5sh{Ww(wErLxD znTIY3E{7gD*Bhq&Tay{|CN|1n>z*b2w;W7(>9($Hk##h;U$-Ens+vv%yCOMz1);-L zK{JI84d!UT329^berLA)ed>WOB zv!+#62r{iN6F*R*j%&b(l%?@CKT3I>}22^(Z^X9m!$XmypW*wS_ zp|Te5^Z~k8T7GBMLnxa(ddBb$Q>r34jF<_LNUUn@^Eh@l)V{n)u6*ELJOoJ71G&2MQ3QE;QD%} z)DWw3_8)cmSPuR#qa1UWj8817UlvLYzi!=l7$D z0k$eUoeNtb3Kd!n+OyL{@-~%GGQ`$_1V_=yY78LyKHngqpv@6SH3$cb{W>_}w9R6F z?+qO|%06L*ta&%o%Ff{UuK@mBB8ZURmNkf_Q{nf{M%IiDu3Ct*APuEE$yL17XfaW8 zkp;%50iZh#d@YRQd;v0?{MRJb8yS6_r&s}Z?|0h0?3}(CI*9xd^P0iTf;mO}>_wiP zo-kW@t67P6f>Rr*LO;?cab+_=DqD(^&w)cPcpv}8s`KHh{W&W~ecgfDOZ8r{;GeN< z6Y1pY?u@RM3X@Cz=6zgr@Xs7PoEPd8jv6tn_hE{?Jq!BQ0=yGAe?AVqa#Jj%Vb_?P zyS8QMyd|07$j9tadUIYe1Zk@TyIRFae$6UKzQYP*2ijy3E4Gur32%&Ue{8!z$tNNS zmBOR6y}LegTm{vG)Rt&?*hhq9Os4RZXhE`FlwGIq+u359ycq|m z8WbC4$=9VmNy>#sflP)jt?!qHeb1Ol$jC84QGc~W1hRA~ab2IQh7r?tP5;VMBDxZA zd-I@D`|ps<8c~u}!h1jjX!l@MeE%IoPutNn*+UpO;J{O$;^bZ+UR-SK#8z@W+!I4M zN8xet+qE`W;Mz!3XLIelg3Bm~10dy++Z)_TITI6hp?h4RhXHO=NSWz?xp2+}_$*fw z<)2g%_rYjR8<)eK2>uKb>6g}%Rm~8zlfCMfdKOMPQJFbz2jVHvVpQFFa%LM)sh;|r zSF7t2n-34!+UdMBuSW$l1*hA@i9ZO}EO1;Q0l3X;!tpNkzz>C|E1D+SJU^6u>lICp zFf7GV&~AIPh-~7)E768WBm{Wt!z$G0<%s0d0NUU%Sxazg9nA^O?*44#9M%&Uj9dYp!rK zC2NH^q>ne=BM8}Ma}18D!bk>@E3VCD_)9et^MpzcwS@BX4Y=3!Ritlh^vs^jVh4y@vL2)|BGf~rog;X@p$scDCVSUs zFv{C;A@}*M%>4E02O~x^3r0-h#DLGv#_Kz)e!lj?`6g(fX!d+z$qt{kZk2$&^pR0o zh5R6jNIRuXS2|pmJx7*DgD7zgl2X6s{<{~=BwE4EV&8@D_x|?Qvcy+6r_=14pYX_A z>K8_prB4bF#zg_T_&&_-x+bS~tV>0|#>!eW!}1rj#)`omKpb}#-X6h)>rW~jlk-oX zT#+W3gC}HIuLl>#C0jW^7Z#x_Kii~VZj>*(_fSP6Qox~I$yTb62_K2JC-A6I@K?(o zar^!74ME5}49KltJHIB7>b%@@Q%=uW)j+Uj6PD2|s!uHnv}h7pjg-t#Ft5;L2Y}Vn zg9)YQBqd)P&== zNFAFv*7%s#`PA|+;{s8(e|N=dmC;WzWIj|NncwPYX<(F-vBuAE=`DQA1Ne$@xZK#^ z;4K!FJ+@1-Plq1QqR+>$H@l;_mB84g6zM&<>t;-=6PtG3?&($i$(g%(eCFwFaHqdC zjlX}s=E8hi{+#N``Awg$tNIfz``GNi;3DnBC-bx+XWpwixte#^#Dg|eGr*flcCZ;n zcjpH&l@lA^u~i>`tQe8Bh~Tvnt#zg*(t21RdP-w(#P+MGY0VjeHDOTBSH0*G^>*|+ z-V5Uv)No;uk!0LtkgHm%ZIb8tFXi0&-PHnzxYe=WAktLkYvJbQQ~lxdZXYMSmz@&!}bm)+$N$D+<>5q-V5AgfiUx)4V8LqIm(YLK)`&(NXQ!+tn}c~ zg&D|hW*HMq%>^dhj`ZF7IxFb2Bs=b}R_f7N6x_J%*MpEnqruyQmMOD zI<-5dP-F742`)%iDf?EkDrk2n@$>GtpA>2=+rNR%B8Xz9t}*kI)pWq!oA59uxeVgX z@~WfXkrJyms1T4S&6_UH8yJ>0Q9|eiPWZd$2`wIpvX~S{XhmrRHzdR)7PlbF2P}fj zS@utBhoMs*OFv;Ew+Bx6mSQdsLY>p(72-gOWU>ZFQn|)xjhJUkKN|7UiZ`^UOiwKt ze)z1qJ(b1H0=HvKSXPH$X)`*cAo@1utDkYM{a^8SV8ZQ;#b(p%5$QeoV3$HG#@cw> zzy<8Iq*n<0(iA?ILWzG80ptgBP!$u{jeSRaqg2n`s_jwiQ6C=LPr)A+lTgYdN$N^~ zM#Kn+v?qK>BKh`Pu+Z$lnaLk@x!bD`M%5&oVd6pF2mYRR?&{EI34IkurYWzr@(|GID)o$sPS8PBhCf(X?#}|3P{?6 zMk6mCGjm(X>evqu_Ip^)4fdv_`-`@hx%IdZ zBFVqey5;Y=;Q-x^@P<68XKai=9S~_fATQ-Aq~_sF)KMeA@c68fh%&FkxePH5T*86; z`%vXLBHW&!@s>D+l#31K@dkNjc-x)m+}bOP8*Q`IrFd=$b7EF8^m-REWd;?>We3ts3QV3%>6^J6m@9OOx^ZJasl`}*$Z+sZ^NR)$L@(F!r_odsD)rFvh6#s?6nV; z8409erz;kvH&|`6nrvvPCA?1V%P~r9dm5dLL7=($BTK7McG|7gR2AH9VPK@2XlPrs zH$W-7WrOd!Yv-HLz?&Fwrr^(6>BM;IZz5wDzD!JK`tk=tNM8oQ00hq!V2DLuLyM@l z)@LAcfLt+jwbKM^R`Fo=QUXE>aW|tarAtZWynjfk2OX9D1Io5-^sICKysY049Ip5S zlFfX0Qol@i}p)ev$3?>WfsAq_&q(j?OD`TyW9)T1Plx~b1|P*#z;S+MXX5<{G?X^Nq8)q7-PF6M zycV+(IC0t>k%ea7|3^~baewh(#H4oFNix_%60~-Irj9Buh)`VFxmx=V@E<@XdEo75 zdcW1WApXTAQIR9O+%MD9A9J0{>3FrUwZsdu*Hm|Xmkix0=c*W;N^{Xu{k0Wj>#Hp< zp>yv&O3vVAGG^IQ7XU?=O)d^VWy~nrm-jov9Nzf3)Q8;mmK(~kc#_Tmvg+P~_c6(5 zJy*Z_0f#>%{sUy6hhaOh6ufuUW!$hh#3%3jt(og&WiHn)rLH(QabZ6|MS7>+j4JK< z_aDIcSzhUxDpub5tnqRWWmglU$n6o*-%LRB5DwVE@&XD#f@oQXtn7tDvE^f%D11`^ zpB@y4)eZN;ZMYmD9a$;f;3b$Fpyi5v>c#rbAd5rxeA-d2@jarh&_@hXptD4%3YD;o zePXEA#g!EhLf9o>7u(j~4aPiVISW(_u39EsM;cw7__alzh%-fVumYQ}Ax>mc9>sqo0Ix=AI%#PV z9|T=9ctX3f4nInM;_b8~{w0n^`xBtJI}}8m2Mu&=_5W-H_-n`Iz!#5FlHMf)1au;9h7@{Jr`tdUTU3FR+4ZJe8Tt|$(XV&)(A{h66Ft5^~S|1LB z&lV^Fl1o1gS#GDd*&k$9UrPS=8?921&0@Kv--F0OKFV(T;g00Jr4~u*=K;F$lQRFH zT`~f|XK;+(S5@VL&g}q=q04*YlO3~+&I4^Lxukxfa`IH7I8}DBYfD%X%fDR`CYuYR z*5tZb15B0#llk#|!`mHqa&F4?uT7JVhmoHD5~S3@lT|+%N?85U=E(!XT&K9YH2gi@ zmP`s|usjNpZ?YW))~O@CY`GF6HB4R>!I_=Z3Tzg`UolQbm1MlLrx+@QE(B7k=K8BL z{lY-thYXUjLQq;Ic;KgZ!^}L)Vy4XsV=+hWdk$$KjQ!-v9 z@9-vYpsiH&&59?K8#>RRFd51XZJ5d3d=|X*Z%J6WYJ1Qoj+y+tht8ag! zxDjzhTyS^>0(a;B@UkO}Qg?$Vny@TgPbbVNq=eY`w3{1WO~ATD)lHNqA~v_89CcxN zFEng=zfD2l`{&HoWEuBU zir?5bk+gV*i}FoXZ|C*&g;3PAtluFMW=*cswHNsGAxlpsV{MkJv4XmGTg#pRHgVX` z-UvoLCN*vKfdJqsq&_57I<>xzCKkWv{xoi7>MaX$*5$7yfFJykq^CK*6iC+2^6Bi^ zonX7r-ZNo{0BzaYt$np2e zJ=)Yw#@Z(RSX0vwa76hAmy}=TzU)Ux6Zz>!nHBEttCw-w^IUz_fM!8NOc-GpY5yMo z1_Hx^&6#V#*6WBXqjzFBe&PjmQkhu+ZyYQgG;&|R^{)yJeeyQSMvguHJjnS=@@UD1 z9wRbYCOz-N&}K>ew}POv4kX57Ip44X4}^^T2M9?+vw5UKk+}Yme}@zIIQbF9*_8*} z3y?>4M??s}d;fiW{kib|PuA=dcpQRKz_ZMURY5csYeE{Y6gnGkPk>N|wT#V+K@$6# znPMnt`>+VK$@ity2skFN96clkph9q}9=epp%kO+@G_mHy1GO{sjI)*Ls%%Q|jQN2I zQmz^tbr``LZ0jCuSK6-{a=LtRA5}$$x{sb&ZvD=0S)PCs8b)h-NinfckesbLiw|O0 z&voyz6*MH|O#>db{{uuS>(i5a>y^pwv(BpLxtTsU{yxd;@Xwu`zHtVcCT;4o=oR8%hGHKGIXAP1OCG0$ zwu7MQ!4ZcQRl2fNQ}v5PK{Zw(Huq`AAcm1D0YHW-OG1cAjz)avZm7tY=Xty>au!&I z*oPkK=C-_!Yy2!s4QWE5tzw$BN=nQkrbs%J}k+U zlnUKUUbe>79#Ah9*uQeVd`obxvmcR*#zktChEx1=v9z?cr`;t{<^$S_S;DaRAEDM?dxlNm}7qN;2Se?3+`uuJUGVf z(|!;Sa!8H&ByZeJ#;71(F+>S}(72Ijzud+mYJ|ZTb02;r-dsh&k;NF~sGh^=^&)2W z20-A*%7H%*-|~(=qp=ZMI&l90)wyx&$j0K88);D_M)4dA2)Xx}x7H-VxB=p0^!LX7 z>zINIS;^_o+Zvi;KjEcB@;Mfr{{Sn0owVRwfzxx_1WNTkP66KB_4;6BQ9N{*u^`$F zhW`Mh*lIr31dP>4z59JXP+~;1-CxUizSi{}I$=!|Qk^6Ogo0#9D)jq75(hScbKP~+ zcDtXXh}>L@NZWidO;FqRhimKsCf8<|yGO049RC1kYnB>NYxfDCQ3RI(Dp4X614-=z zR*+zTsbG0ZgO}mnAOOv8>PW?oO;28%gXJz|;fM?(&PyHvi{qXiFVck}Ngy9l^$8#W zs2wInfk+@hFa*rNYb&c$y@G=^&uxh$5fbr-bBooa-QBefz9ZB$+=YN!RgJ zIWpX$%X501yynhk`NEQeQ$UI&RnVyvRBWl5ipR}SK5D62G>$g=bq)K{vXwK3T{^=r z?wksunrf99bSWgK$dbji2UVO-K4;5OHIlagq0%If>XI~(VgW98aL(nFy5H=T zE}=`yt0*52vr$g*g)WWiXM$Z~r~)-psVR5@QlxG$J!w;dr6h$ifz*Ws06e87h#)8( zFl2PXL}|Dwe>Cr=BH|nH@rbX*UaQLLdP1u!YcivIGpVkkVxoxO1*J;>D^V&J5RwUI)L^j~f5Wo%24yu3 zH40%WP+3U{B!&PUSlg$jEsxphlHWwqt4W1WWUzaMWyoAi2{)6#Cf&{Ng+K0;gGaih zcZ2TI8|n1eMg^H~c(&PUA5uRoPgt_T*!D9Sf|-LVsGzN(f!w;dOI!4>fUHm)n>1< zGd`fqTRQb3uQaU>RXozQx#m-#wNK?OO%}sPNc2pmLn)9(jI9Jw1bLJLtw4YCDk;`n zL2`cXFelmJNN**g zWlLR6Vp?&P2C}-hwY;QJw1v`_NJ`N}l^2Ubpr(~lNYXzFQ}DSYtI8N80!-aZT_6x~ zO_|8##&VuvD$=znE2&5gNh%Mdxh13rO`tOzbEi62my^}S{{VInosxAaV|7e|okV~n znJ_JNGiOB=t@dE-=T)P2mv#}m;^QO&vov=FM$=$^Q}mGnBg7}ur%sSLCUl7e1i{#U zGqem*l&GgpuQHMeJGxAg%_ncu^+#|AKqIRWu|L>{A>$G!LbW|Gs*TlGoH|AQMHKA>4Mycn z>T){^Uihx6RJ^q$f#$7QMWxihq$mgSg6<#}5G~W+k`sm(%U*wZ!z@-ny`|uT7|4Oyh#Z; zCD}eu$CXQ&upkl%X!&B=sM78de-X3<%WS{^M`v!oN1hOL!a5VeE`;f(+X#7#hK<^^ zX(B4?niWs2Qk0)jbOi%&IRfX3&(#(DLoi*_O+g7D2+%Y{$v$l{&ER9o^EH*2%+{=3 z>Q|^XZ4Sv}AoaGz$&62)8c_=FuIc71O0z0w6rDEE)VieD5EG>Y$RY^$80S2Gu%qEw z<)zqBS^=>oUQvDBK<|Fz7QPWnR&y?p-|?x7Y?mivwcV~_*ta>0>8j212hyPqRILq* zsA)-r1V~Piuo8VYvD+SJmq@3Upq70U(pL8PU2Hdp;ob;?j+(m7Ox1dYibBtnhZ;n~ zw$dhfV}o=@@Z7;Mw32uNHy{8^-qz;}tb*hQOPGdZVKO)TO+PuHdCFa{q(5)yIX3k1 z$WdRPQDzH(!%YQM1f&^pv-^OeqhydItA9uVB<~gG)kh~*i1?PZ1RY<1hFSTro>X0i z8lgxkqDdu^mxjB7kf)F~yzMcGJ*7f|PMCm{f&kK#gSV(A6);Aj_+nrTb9GY5D{cJ7 zW!ah!nIyldJYv}@asf7uzyrSHrmKOo3=fz)rzy-_00kz3u%-@}{{VMZ!}vkErEqqP z0)l_uX{G=*P?0xv2PbFXiTYx7kMNzOB}NJUU6^gXgtpkJULR8{HR_C|g9`$NwAOWe0z(_r}Gu93&Xdsm(rHBDma7Lp2i*3+5 zk&Cdxh*9kp?m^g~0A!P}Py*erk1?toGed$l0fSEaY~*Y%F?NZb10UAEv>Y{o9wrD4SfJ_ppDF(v<^=F|xIgr24Y zp1hHzN=bvHB!q$rW(1E=gAv>jHXBkvB52$vmidpYB`Yy7aH(sZG22{463 z+*n^oGo}n&3;gk-T}em}xdW-Q?pt@;VQG%myfKrt$szzR4Ko;n5`?=}`<|2LR5>GH zM!r%BDJQ&{60Sxs3yNtQd%j(X7my%t9eKk-G^L(FC5RjjqByg3#cA<&k+!<&ZY3!K zs)mW}U>!Q!TaB$i5BXA%OoJogRABjI{0>x-Qen=Muy(M1frMhs3j&dn3!B`CCW zeaJ6-u_#yFU2MVtVQo5trBHy76xm3z3XfERk_4cG7}9_#ECD`kM3CJf#2JPzA>FVd zvv+RZqj#6@^9_r&;m1`csB-a^*SHs(&@=|MpIvPr14F_`spkDCd;tzZ1(G zy8Z1iebqwh0ot1HrNFVedXknb4i_tbEX%QnA~zxRdUd^|GRT4oWQhQiurde+#yf~G zOi0Chyo(#`Kb+=w#(mva`t3S}UPPs(`O-z|vk$+kA-i*I)C z^y7>S)M$y}+VFcrX_&tRR4|K}7mMx1wjF^IZv%0NyL9#I_TQ(bAXYiOxN#-xZk@vjPUsULi4cCW zE-f9q$tMu=D3TPTx0Jy7Sp9HhEfNR-cXQdxS+vJ9A9|ubGJ=nRDWXC(+33wtLV|1`oQ}Z#t-Q>>~xh&O8zlzfpNjJ zf#0|hW}a$zw@Ib8p=wu{6f~%l>IhL)%!u_TU}sW@kHvSAK5-UzS3_>3#QGC_H=0m7 zTK-_b7x+vLd9{cF1}e36C+{vSvN+&~Ao4FeO@KS%!2D|E&#bsRTF2z)34-i42F+(I z5)TBB|RY^>(U51YOJF`aU3}4K)+2e=sbsk%Aj&oxqGg`irDI3Hv}$KTXt~Iny0j@uu?K z{h>tNH&ReA6f`66ZJK=AowPfpX!5E}D%Jv$RyKseQPw3%OQ}mOxK@@Bbt%QdP_7rmybgfzQ%5S3M<|MPs#OI_ zTD7lIl$2^NH2@jQAUSIT1!m0(Yf6f$Rn}8Y!fl}i$p8WYCP*aMlEmWK_+yfsi=^nO zOAb>ZK`N(Vz@WD28)>#_0@A%MC1I2gO2()FpNkzvQlGk_ln6)~Qa4IK00+DP!O4la zVNFq5i<0D$N#vP+CC(%)GlApS%w__8MGQQl0HvoC3D^*VWcyp`zBFBnU5j_y8y6kM zC`X0=0C>u}b1$f)si>x_O@3=q%|$cLF;Pz9b4sRvbo&cKh*0u@B`Qk2MJCb@H{sq) zx*0?ex~0RUhN`g>vkl}I1cQgO3O@9k5E2|e@`;fJzfX>X_&MW`i8+o(p7icvpSfJq z0)#P{R5a1f7-7Ud+m!9sp($BH!)cYNK5}Kqboq+MN0ZG}sFfi{R)QHt+&J8V%OHU& z1wnywX9HGdvQeNcu>?6TpdtY-dy+{%bq=8_b0y9cvR0+#^@U1Wq^U)flBFp|Nhaiz zGkKgeNhRF7g8SbKp!w2E{6YD=`u*`nx~;(0TFYr$X!Gh50H{u+YAOPEF{BF~-Jm(@ zjZ6X-0*G+JKxe-$?Y`LQd?^oHmVlLzK(SHM0se%JjV{rprGBeQX{q0-St%N6>E3xl zRbl(IDs@Z?nIwHGRDI%3l&w%;1G5{D1Eq`yv1yESh$%xUYDF+ERGs3m9-dQyrDLTnpgr(%dTq*WqNt{+E#Ijy1pUl$8 z<^@I7sD#svI;o`&rqm>fByi=x7>L+?+SlBzbg4^ydX|VDgcVC^0aqGFzy!^S?SUw& zr9~-6%%(0LNw@^=Otz8NsKsZC=0A7H z<|?=<_bWhF`qkwCY~kgA0gc!J^et54RaRJJLp05X*g{XFA+Q@|0V?=Ml$3x#us0$O zIAjMxmamCwa`z;u%8LhscRN``Iln$O$XLx}I@s1#kK34cr#yEoq(TRKQY*{5z zWHN{+{!;84bNPwq3e38cH?L9B(qNbtC$SOOfhS@F$-1Q=sXzlR!M>#4H`D_I!{TTq zCr~aE58TQ(mRDL5ec@_R8OeT#kQnJKb zOgob-c-R|0EOHeTYb+BAOgOOy;>2w?Gv5w|-}U)!BsStCsU}1L69;gkat6Q-*sLie z0`3&R0V9bvVg0vrW;r`J>i+=jBybb_OYGh z=%3#*$tiVy@PgzxZBHaT!EceqS0K_>mXwr`;Aw)<0Ly$L-j4xz9@?t2YU;G4tkcsh z4GGky%dTs6#6U38P?8j&U<32VQSC}JWzd3j>sWUzJg@<2qi@!L4(79 zvPj{$Vjg1_u8O593H6;o&*F>veJUadkbY^pXKZ=(N=*JzQ0GY^;&`>0iGsmbn=}## z0M9oPSjmHX10mue%}VeEBo!3=D%_D1CfkxH*#2V`^=X?M+$o~}0AMce(Y4w_n2WJ2 zUJG;b`a9uirwnP-AVEmpM9fY11Lq#tO=yQ{k#>Fz@!O8LU=mn4ZJ71`pO)C?kK2m8 zqadnlP*Uo1e6pP?O3l)i9$J!={wOU+)c3!%{>tdRdS!znFI{%ADg*1Nzg#PySMa;6 z2L!VKPLb25_ij0vNRg{fpGgFORi{SY;BRQTzqDi9s<}y-4#Wp``M2wmaZnOfVC^kC zcD#{=w!jNoLUe@K>_NFc;%*5&w~kc_bb?F};ja!D!}>9_TM`Isvp3=Ccsz9cgPu{* zO#01|ns*#Acp3~um>Q$&1mB$i3X%jl2|UWT^fR+QB!B_3OTq3{W3<}Xgy|bmaH(9n zU;v)vf}ZiLv!!@}L0>UI2Tv0Pr2(`ZP`$N?d|mjz=*e;gbQG$t(m#e({l% z{{XakWk5(rn?$z9cxl~2RA7zI!~9(8wDP2TwT3DngqLEHRF{E2UIrOKbhlQta!Efa z9k7qmS&FGv)eS+_O!CK)wG{%xiV>t!@L2v`<2X=WUx7(@4>H?I< zV=fO+UsLQ{7BV=+tnkdbuBgdNAx*8Nyh5arW{#;Ok3zNVbtPQDCsiki0q!fjq>FcJ zGlvW&C8KOt)~Z5_IAsMs$!TeacydZq9r(q@c9Az$l-!u~i3fSuOdFZ)^T#4wGpPDs zrtCyc{hu3Jo=g+-`+)?!FrK&|JbgU-@nMpO-jMYh`H# z$n7NV0CskS%gTr)Har^=U|VzEK;|UC*;TBK+p!P& zy};u5YKe0s_T8*sjfncr98G1z$|P8T2(;`+1c`_w$@eDFgcntbhkZfcrp@xTp4hUa z4wn!lxAQc55XOCCL5=)FVMys*@@)%11WXac2-;IO;6%>Yg=(una%^K``9u@XOgWQN zRl6SUSZN(4!}>cH$2UA)K=P>6E`NHWBaoC2pQsO!<_IL;WK!#I^)c&k;n}$B7;iGK zJtn)U*}s&Bos0>$&FbZ28r)HfNgxS`Nz@Y?07S*2*X@fnfG2Tt(A=HO_h*ZoCV~w^ z)b1@jap)}#gvGKz0a7pgKE}WS!8eNyyI=+8&KmM0yvT;IJqTxPSyA3g8|k}uVnl%i zZ7qWS3ua$^=+^0$u%|NW+Ny0bbtR=JI@E)~3n~O!@whnp0+|d_HZv|~?7#upvGVvY zs$A+mmiy0c%rP!tnBE-y3QzlKlD35{4mzijRD%i)2GpXGMf9kRN8KqR>9Ht};*a@N z4$%b0?!&A;!H<^z0F03A6iDbslNSV$aMLl0mEv=mdj8bCeARIew@IJ$({3TfYe{*1 zF+{~0o(hmq&1Q!JPoWBBE3#7H32re34Uu zwzTGGpNfWNu(NqpQA9-8xcxb^%^{5{fO%?CL5^BqU`{TNf(V3l61gr=B>fXoq}zYQ ztK*``0zK*EhCfzrpIjoldj3Zf>M7G!q|+^=yoc15l+u7wTuR6aO2M&71chq!>6x}H zRbu>g{HNuBm1z!0OKwXs+D)+_QTS=m6)QupbgoBLnyOdO7KI^5R-j6fU?g1&u}X%dC>#&>oh5?@ zg*k9SjEyD&R9jG(mIBbEYh|h;r2@3Bnv$d`8itaS@dFnv2E)5zg6Dr_x&rH!9U+{# zM4vUn)?J$?&ZkO3&z9RYN&WL_0uYrr9X!~?m3cIYq@^cPT}X{CMUwtt$CAJ>Y5Kj%6%+sX0lvSt-PLfiW4jt78Ym)HKaf$?FDu(!7$S$TPV`2d}-QN?Z zhZNO0HBM&htxJ_zd8DUOR8F5Uz+F)Um?15ZAi>l{q>;+_^66&LmP%IWr&v^|4(td^ z9oUiaG>zLG2ZvFqO;v7%s**thj-=}BpDw4TuX3eIThfD0(iC1=ktR}*5|Qcjl@$pBOq&|K zhlJ*{3tb;{!6cnZQgjeuiE}P>KyYFOtQVOK8QG5BVYFGJVq0?V*o^A>?cC9)sY+X= zqj?KM$#F<7I?DYe4lPiS3ScE7Vocg`eNVwtmsqMbE~sLX0c4xIu`UQ3h-u#n9Kln9 zTu#6i>SP$$6Y|8R;8kW*P1V_bBQ8<4lSx?FVUpQMKw-^VkT(i2PO?%=5E5YHnfB6_ zWquWyT9Z_tdqqJ+5L~S#-)5F+9Yf;7!zxo5gav61>6R|(AwjlsU97^ufc8f}$TIqc zt=z3BrmH8`*wm&SDzc;a90DOg>97SR^XK^t?Q{gw%@tIlY`62Yf(bA zDwqjVzLM-=i&>9zwwA+BOZ4s_e!WK{V19xywMzO(LJy>kAQC_ao%@ZV(sqr4Rj8kcT3|~&hxNVN z45We>LV$At$>`RXef=@bAGYmwrYIOL0$~Pxn7j?}nUC$y z*5`YEa!~<*-a0&=&h34t0@tiFmRGK4O)HxaKqUq}G4B&1NFZY=0=l%=elZ3dJKRYu z>=^7Zpg}Eg;$kKEKR4O9IEb?LiBcfScS>LxAd;Z2eMV*{dyyBmtU*ekf(sb4jhxs9 znFpj`+SF3-)#LK_Iv+TmW3KcsC8Tw*+E5rfB}`YB4Aprt40y4&Z<;B0EST zZbC-883jcoL+sx-1LW}VTEPcN@_=L#WrqI%o0vC(_e;T=VE0yKZQV&~n5jWmDJTsf zT&Sx^1Vz9iaZBR9T%|=ZNg$2Omv*yD%zBx{ZAzYG!P5R|xg@mh+pCytT_sbUzzGME z2%SXi4T*sy4#X28F~_(jVl5?r`7qhbIr?g)K`pl7=6;-gp@;=kt5l?cKkx(m$hGi5pjenE zg;}{V>4k~nbdDL!+e?T9T|<71SkRRXAqu*M<4w6HM|qucY#BtB4R3R9e~Zd(2Nw`1$fM#UiB}x6^LdA1NWrgNG$1TBD^Y zN~4kiFl<1Za&J3NCl%Fdi6o}Z#htg7uxDWQ3>k(jDHb3kkat$^`E<8Q3|;j3AzKR? zB$SYzPUC1IH4(HEaxD@nYUY4Yo?c*IbN(Zi#ib=Eg6(r-%R!eA{ci7wo5eh(%3hGp zRHP~jg@QmQNLr*xld+OS7@6k6S{dI7m^qntID2}+5u=u8mgT3KAf z-*(3?{930zRRqd)H&Y;kXf33eg@7MNYR2NKk=t8C&i}g^4yXgXUG{qzl0% z*zl>fi2!$wxUAI_Yf{zeFjq1+Fr@-Wn;k>AgY}ywCSyv)nheE01`%;E9tlzpa!3{Srw2fQ_NC= z>L^Ok4&Mbrv*?fPb$DiFEx_!NyRT@ndRCEC z9(y{b%yO0~)Vf#0X?5z#Hrj&Xf>fZjreYNWac!0H&k9{p{`pA*Nt(pbNa*zf1h+BM z1E-bDQmln8l}#X!RDtgpu>vXTJ>zgm-xSBiKN0d?qWe^Msb7+2)Oo*7bzXLwY@<5M zs*_PkRGKOV6GKx+RMw<8hm;*O8AxTm-Q=pOx zRFXk+sR4?nK>$OUiX~ZLR08O!RZLPrC^Zz2;XoE(@&kh-7VjYH{I0($qk68nmMX(Y zW~DU_wA$BF(_lQ}Q>c0zP*aJpv5qm)Q>>DN>QL0c834VWTIX>ct%{Zf*n!f1o1c(< zu)F(vCg1j*57McF{G7!7>N)#=Txo|R>-{mO`$3a&nNffK!(;lKXS_(UPd^f8>RX+|BlW=}7xZLfS<|QdEYL+JPa*5;Z>HO_Iw_ zdWyz1cGK%TvVImi13`rr=1$qNX$AGNxIZ^ zB}bA~9ZIozoTL>&k{jKzNazC*w$tg0*^qd@(jFA$IrT?Sy!)AzN-5vVGKxfNtjx&XmfA@w^{D7QiSazIhtsI4%kz}II%#6MhQJQSX&8Zy}KJNl9`DB1=eiPzDRzqkLANtV=ZgO-v}BSxEh%ODkZNKv8*+H8%%VqMhahMX58s z7_<_svWntqEHZ~0PUpLJF8H!TYF44AO9g2jQ>sBo?7)W?>5CneQ)SicBBq7*t7+5{ zrru#`akM1Kf<@A(Hw*Q42cBxJO4RCTs1;1uhBIxR@ca%;VSzy^kR8sUs=@5;HssH) z4QEWIk0H$}j3Bj2v>=rx>QYN#D-$v`0-+OV#`5deUYG=_)}2H$oW@PQ8fA%;}s1A=_N^pg_1-Fx=as=N8&%FE@#8)l&B?XQ$rD@oNRV; zX0RZgu;m=;QmsTOAtY)6oQ{fVFEaA|0g{-`GQ7nF_E7LrG^JrlDKiFAOo0YO5u|an zjB~5YSIetODUl384gA0Z4BwMBEWdoBph(n65|-Xf5Liu{@;D&oPHSsE_G(npLcey< zNR*~#Jk6CUGDMl!o17SC^it4L2|iUQ1H%H)BHX3iZG}yJY9%12i*aY#NiYk5#xUuj zplu^{I1&PGQke-hB#RA&x%b6=O3E%+&Z$nof(`k5bp*i1&02=Z1PjP=FSu=(@{-Lb z5a*56S%VoSTUVFVyGY9!f~o3DJFHY8K^oPh`a-}+JcDUC=zW-{MOCX(sZ9z}sfvgS z{5n{Y1O6+tvAi}SiuEchNh%305|;oKGw=!SIJ6ZS`9qjiIuc*1eaoaQmlkHgfKm(q z4-qkVgE;EzQ9yL12@W_M^Vj9o-L_P%L@2saUPG2)0o~=cB+Z)_L+tBE_f*t%GrGLz zpKgYUL=X5)s%o4IGC*328=av1@#cQnpLi3I3{WYmwLs1RSHL@oEqHz5+`7#*Ah|kJ z7Lpsv3@B{9P;@r&t9`c#m;(z2B%K!v34L_sOB0s*)26FBjDwA2op6oL$w1XxRl zmy_~l$5TqF3_*064#XYy+phA$Mg@B>YPkgtX>kH{D#6(x-3o$aTyFwNj>1l1R11en zqfnBY%ZCtoXDx>iQn*ty9s!YbleoJW=bSg{a+;bVqMc7Pl@b(?b*6nlC?qT47b+X? zVSGPJH%_Py$Wu0wTox>JlEO>y+uIWNL<6Lga^m74=0&Z`wmC2M&aYG1$4oFB0$t5& zR+2SoD{-VCDoOP#O{Yn@5vnKXZ`q|VjJ9<}Govnnupk8z&Gon}_P{gNq#N*()+2)k zY)RjnML4Bg8-jKSixD8}m@~Kr`nLSNBBE4C_(1$qsB{ivptEl{u1RKjB(gw>A(Z@q z5@d83aZ)I(t8xUv9Fn36beq})6L>a(Y$l-0d7=c6+jJJ@b}>(h>PCXkUWF1Xx`ug9gnSrumzN;N?u>PNRCB=7sj7< zv@2EbWc>D+-@U)jMs_>Jq2LHMnCN&Ii--^f_W6L~{PgRA5keNA0#tXk_#E11+}cQ( z6NnW69k|=;{bS~Fpc10M2-{-Y$LA9a#m_aBDMXDk84jL?tOC!)h24_i&9kpBoc|6AuabH_8r+GGzNRE)_X8Yl~ zWl9n>0RI5Y3|*oh<}JZ5yuYXP07^B01%M$FJd!(mi-IBvni~1ATmpIIv-aPXGwF*u zG|LAJJtjZ9i3CO6@baR|nMeSF0QBr2kOTw3I~apEo#zzQ>!`c@Ms7@<>;~s@8Ks=! z+K5VEb~h!=-oeiXZbtZte0!l`u7a<934*0TAb@ypw(_Djw>T$-)TpfO6dP(VZ0Qi^ zXP?Zz99ER1so=nC$SEKmXK@WXt`<48ikJ>hmoFgEHl>AUU=m6GoL@0R*Wek+zi>f@J%F#lCp4t00*J%3ySB zN7HL!bY^!7FD7PL->sd5cO_ewEGE`XuL&t6f67S{>JcMjusbXk#ISPi98T%lL<1cR z;?|hd9J51$THugjhTMzVaVcj$1^5TlZwIr^f#|%}q99aOFw^x36FNicf6fV>0`&aG zK9{SI@SMp8wo@rofdzD_t4OuTVQFY_JmcpypdctAMF5!ysHC~Wpym9M>^WBK~CJ5Hs1g~2jFUt+%i)>R3JM{H|2>1Ex+PbZnbK^)o=5R zGjsm{u#ef>s&cHsjGv}zI&!|MmZ7Q)<0j4XR}NcP;t$>G{^LA!triQCUf9v{ba3WPk#I)$YvPEGaW)d>Wdn{6eCPunIbo;ln5w zJIHjEav+W>__g5|TzDDR)%_XOl#Wv78FQ(s%5!RTxS9;>E-n*8on=p`4>F#hBIy4B zi%U?KDW3^-wI?2B;yxW)!fT3k7EMiBsZ>Ly3#J{Gf+Q#w3L2dy#I~aN(@_kd9Jo?0 z01vwd2H{Zs2rYd)2>UwypuAG(th=k-$@*(9$!qD-yq>eEGn(9^GtQVvPnVdtLraq8 zvqMyZOEoY3)9)HQ=2Gh}rDLz~sy-)}p-#PObWoKb8fK!@ii-!~s!%B`1gIBDbd~`? z7Y7v;GALPBx-0=9%0UoVgq=XRAP0oQa?_vwhF&>okne_pQ92jZy+$v21sZytu<_FFN}T6H$_5g+z< z+HX7XIFIf=Akj}L{{Wh*c8~tl-}}xsJT&iAdL;hulcbsMBUTNl?QWlbUOx-&9 z48o{ZNu`*ir0M}lR+3VcprusQq@OC1pi-h3jpG({(kiCJrA`>7NpR#HNl*k0qzBsJ z?SF#bV?P%@&}&apKC{!kD)N9=SM?ijtyzddidLM9F8$m2qFPWPZwD!|~mP zJ2k#eht3QVf&77^|qFOIS(Xey6v~hb|$(7bYBnH=FF_anc!swvSi@E(wT9 z0LUl)?@~%hm?QBW{&+^A1eRA1X69TLWc{6|4O0ZTxnk@(i@}Y)`(jn;i8MxL3zOPLW*D0cKdD!&>e2wy z156!C*ocph+g9A-nyN;T%Ykj@)W+al#{&if%t*6s=wREJKWrO$?IA5BuUSr|5TcOE zZ)4cG@l0AY-vde>RN*cG4DRgRNZ3If# zrbT0O1f}X#rO=ekq@*epX&Q&IvG8i%=ftwB)J~f9kX`b$~^n$gJkQ1qMWPz)8 zXzSJv823pl)WiTa5O<9t=XPo83r;#S(Rnj{J=6J4R?}d8+L^Ds0sty`&s&L z-{Qlur^8?b-6X(|!@R`E+>1wiQ?8j?l?E*3_p=D>WOT#jKr}i?`)$|OM<-<#-USk= z1u?5o1SlyY0$|^JgBy!p$|{)zG`q7qhBqDp>G8fgmYR%+Zz6QK%u%BNDb1cd1eP(Ugv-AR%`laHl;W5TMvpUqUQQA$_) zLZu*8<|#r^x8l&Qg}+&};V4YwPDalEhp z01yV?D1p0xTX~kZ*8xd&8?YhI0pz~IKGwriCT(h{QiQG$v!u<6tO`;MtS(8@X+5yU zby{gNmn%pmhcCNX>`w7~GbK~WFaDpfk{@f>vBi1uK?Tg}nIwTB^%=UO%pggdn;0Be z2pA?sN%us_AxRcs<*oO9&W4*(>xtCz)*58m+wgk%%H1o#WkM8V7FMoinPgG_u5q9#$rVZf^ zEDa*S4}~`>1dDdZH{);nvJ)rxh$dKAf(U-^2lB;wRp*m47l!D0X*+=~7~9mdu?9xN z*jPej4{4b_@ya;`xb)g@Zi3JYZH-iNd)ss0`#IY9Hr+bHf`ycmX%`S~bdX7oB!g)- zz}B%Li5sD|B!PhH zBXje{JIMrb2l0J+eQrPp8q3)vY12E9W8?$~F*nl@FhKNxkkqW82xVQl+vwrvhn6ph z>PR5S<--PT*hf1Fa(G>)%Mf&%35g@rE&=*leWpy3NGMgz7C$}q?{@k0+%%NCX(PF? z4Skzy*hI!2xn@utFc3lpnF7QEU}aVYBKJ`{+?-Kn^CWNPF3#kZk|Bu~#f1uH96XM? zLxz5SZ*I7BqKJeg4K}wSMLJNKNVE_XqRyQONF;c3|9dq|Nt-_$u<5pWbS$6@;>B z3m}#xsIaw&0iBMeJ|e8)teR;;N4<^#rjuKTb4Ab5XDl; z6gFCvgg}AuB_J%1!*ix2p7+A^sTC9&76b+-%2=KOKB||r8APa}Trnw!{#QKiZs%hS zh;6zuKpJcbCxOPq#^eHG@L+F->Zp01Z@*K1cMaGU!*p&Vhlt+WhY)v7>~JMb475^2 z!jlj--}r&wlM^G1BBoM-2TV+F=t1C{NwzL%2`w8m3pwBN46f5Hq^KqT*>;M<$r8M)QCH7{oCp3dA2vClLcKsf6CaA zx&x}SZjsFzeUCb?FMVigvo2H12z?451u_;?mfl2y+LDyX^r&ejH%mG0RwR_Dr6n)c z>3gUX49*F2B;mZdT{T(INYs-%fpfcXL*cph$<6#P@k1u2=vT5Tiv0U2s%D~-t5Ss0 zR&=|sp$=8i(gniv2H$9 zf`Z8}=9VFMRrDWnB{Mx`4q;*>^SfLKy$CYlnYAq1r* z2?^4Ik^vFr3<6S83o$qFGJJ^yi(JUK4;GZ z^|lC)7NTd)J0VWrKi3$6sX%R0{{TXjh^!~kmQ;uwSnUHipSADYE&c9>1UzPPoPG$M^RStTF-D&*q zEy*e}#-97CR$E;wf3Yc^`>jEFm!347(Ub5=UwYqwGJl?U2 zdRE(NoraT6h8bz3hTCbD10Gr#Z3zf%w4o?U29zWKF!0aTRD0q!0BC{#0CghV6up6n z8+xdL@T6=TV;jS;wd~^_%{)NsT-PqE%IfpCmql2D%}N6_=yAqWeNB1DX)YxS_*4?0 z6rVwan8g18da7GhQlb2=!1n?#%>D5ii>kD#Dp!?FeKzB5po}mw%&AFz;vp#v6$t=> z;$CPc+fYl6X+QHRKuTmikMsF*sii%@NO1eQ}?%+a? z%dQpb^5XqCakQsZKI9XrNF?f$!h}ZS@YwDyl)JmQo|bYWh&%7QVz!cWl*f@`3HWz} zvz>`OjhN#UEFnn-4w1A72b-!BB{9U>@izfAPO=5hXJKMR`^bJsj69TinL(NMXR~#3 z7_f4}9tI??ilkrd7ghw8+LWXNtPrUM3KvbiTm0s1rh2INK`!n~$YvmV6SN1ljv<(& zbcS;4VFbAVyPi(P+V5;yu9B)bgK1&&{_?_gFJyVlfFWR+l_c3o2EjXld~!L(3VM`@ z3T84`ksyYDoXC6u8FE;d7g1BU&RmNT*q!kx(bIsKPpKq=lVX{YN^J!0bj0pA*wWRi z=1Cq~Z^v*z4tL%I5YlL+L`Vzo;w0Wdo;%?+ zmesl7h(Gf?I2Rq`3?Kl`KpJ)|pjqc_Ou&QHgPcnpG=+WEOh=hvr_!kwks{D97lH_Z z80K^89`v{J-TDwfzv-h7Q>IiDEMS0oj=V62>o|Ia22nb0LC_>#Nhv5oNYkP&vL-A+ zCJkF_xnaES7)g8GrJe19`=wZ^MWvcLH`}OpX>3z8rxvxW-Cn6w!iWZD;Hm(ClVLsf z)m4uu1AdSJe$sysnBy8Km@M~s+8EsYAU9(Y>Q7J#x>~wbX;L4ieU$?mL2;F!f|Xp) z3IMf0O25Brn*buJsIHYzSf-*&B$p#r;9QT*?QAF^MT?Xa^!P{?Haoqd9JVW8g&i)s zp0q4fHaw1xH2ic$+NHYuefwU*0UG5jF2 z*awa9^+V=H(zAdt9I0}^}kDPjUT8@D-Jwh=n4r2-nCAf8yF;U!P;%Qbk$m-5hGI) zcG52XgVp1FMUt0M>PJH)LBDKrXYKt;vDO^{n=P<@_0ulWsqOW-O<1+9FgK9mNs>s2 zktZKR{>c`R;l3}IN&f(a;u^wt2~{|9&lUlP@Bo(Svs>+Qi zHc$~DOr5Mfqic>1Af$phxg9=VQqy+WE~L01hLYC}C5#`;yx=aOUYxlJll#h+;am}G zPM`=90E>VDHzswLPn@ZxDO6fbk2k*`Ttx}77duWhp+_1YSqi0`V0ebcc|ovET+D_(?muWt$pPf}oHzu>$1DaPTCzls)_6xp;&U z?@+V}R+O@$L6K!RwLk}*QY23i2X?YaKIvAvOgnrj1HFN~`eF+$r70hXx}nPl`O7>s z5c0{H3m#@=m!%+*YMWV|ic+hRZKl#e?_mIXOtonWJrwaS1O~Yyr*<=is-?jt+fJ{; zW@#3ef1w}-7t6pJQmo@YbwcgX(K7NknHYE zSdu%$OL9Y;DYZwa+f4g_JG3%ow)>AZ%L zV0x4aQ=|YQCL_M_9PSL`pRZJ{YMTZpS0sz}{TIchBpo5cYLMFk%r5dGM0A`N>b&(G zH`Do^a_x;38_H;E0ZM&HDoRog$-XJ}g3_+Q% ziFwvw6xL5njJ1-O6(%38AwmglY92*8RFV&+r87?q(hDga2>i#Z@7~$7}iqOR=%o=#~!JD#S*ukQr&TU%A8u3uD~5z z3r(=cyh0PAm`yZ*!6`@pa>0@X$LjVdLDZ5-CfC|51HrQa^T3SdG9m!M`mz7MU7>kPg7_ zBwj6q4PpwCVdl;*cbB($2er*ACrkn%i5H(Y%p12oaa|kBO1GQ#5pjR@$GWP!TlD3n z{{W^wYffCfzHV9V8~u9WS&XR2hV47)o7_M#B+S~;A51M%GyuH%mgV2d7<|qdMp)gR z+d%XUAE9Y?WSI({uc1Pb@zqm{4hxCiclVjGo#0_JoJd+&#-x&OV()9iunqOY)Ut$- z2;vU?;J?!GFd_c{7;+^40NO8BBgz_oYA6_(B@8xzc9FD!x4&WLvu|FY1T&MA%3F_0KqvGz6E*;UpeMPLnNyjIhI70@>TUJLD=o*# zo9hw!Y$Uyu!pIP=#2XR4j`MsnoXKm4dxG0-`eOe8HB~@67k?Gk(k=Q%rfs+7rP@B6?%ym*o>fGK2jtxtPwSoW6Ln5QM@QqAh8d+}sibXrMsmZC zuR;=3)jnnzZPyf15|ZUyONT;r>I4HLn9tXz{?f>uOiet%Cs7aOI#Np=)JxbqurG_8 zzFdsGU_m2QGtf*lL9jh8!q#ZzpxGkaPMC<1Dv%G((;jBnk4r|bRj zP1+qZ7vO=x*x2s}>3(oT)_u>+{jf7hF8~gWzkDOrt@>u1a+M9aQraFZHteORT`j3C zA<`}qr5IA6z|x=$Mjgx5RXT}VpDA%9d4M4F4hsn7?D$fxDr*9rLQ_pj38+#5UXnm1 zJg8g~y9WY9Ytznn!PSqqQ{~chy#n1>P^kf0nL)TTiB7i)!60fwOL6tYC~bBQsWr>m%H z3x9aZE0C0hORT#}TnZ49l8rzO{V}k;&Kg~GJF!ZPI3R}{CN#SNCxQSLucVBM!cV)* zQ!M61MmL9L4LtN?iKoNLTK@pNJZk7tgqG6Vj?z>i%@U-NpobC^U?<@hP?$KY&(<1J z3dW~!l_fwMi=?pHWw?WgRm##(NKHkZN+fDPdo|t^0TZj7E|LMAEV4wn zGIrU_mNwdBFF-zul>%M-)Wx&Y-##kVF?^0G-kqne87apYCW11uCXMlEi`{?7@d< zw!~ro0Mpd#YKc-3xN_yS1t6rDl0i&^3X%wrQwB-JE^?;2snfbbMaM=5);c-C(?>!| zh!X-sFd^J?d&{=iRvu%{60x9agbrW`Dp9l^(n4Z>BM`IuwA`Q7n|XMW#78>Pr56RI zn(Z5jo%Rg(BMWqm01yY_{8By=brMN16n{?GQl&*XB-m^R76H3ASB^|+1r(%Qkm1@b zsF%5T4K3RTpUkq{y#!n|tEk!6_?-_&xsmm)$N|a8P0KMFXV}t(b zQlUs$r$b0*t5_ff5?twGT*$tou@W&cbl+4A%9*N)tb;$uf|OFKT-J=GNq`Qw7RuBT zl@0#@4E(1Y_IDs?sET>ao@hs&jYPigkd+4{G}wm*&4GKZ1SKj>Q2ziD6i8>>7KxTD z?#?eLE1Ado79ylwh|;ynBXJ`QH=pt*a6Q35!(;ssc8zRf8|L4*gKnki@pH0I|d_E z$1TRuOS#kf4%~G?b(f7O)^%G|Uw9 z07PTjnUd`;^CHsIcW$jS7&4M2Fw=M5z;*?k7jv)}Tc%B|5J0kiB$8$cJKJ+2CPeZT z5(Dx5KK}sGqhK0k^Sc4eDgYP&(&lGz(0@r_9AiB#PEKz@2$ZGGXI+FPI*fq?s7Wz-?XVK6 zTwdV!m>hvSY-IFCx|uu624*oN*uWsTB)!YCV*P!eX%ZajH^sFYHa43AskgNhW?<%klH&oy;6Dp|r4NJBkyaREz?t`K~TK$U@kzl!4oD(y`(4$Ay%no7X5Sb==TmV zVN7=U0R4^ZHtT0)wipDDNwx3wJKpAC+;7~*E9zBHpZmLakHmTko`(QvYT#K>r9O#xKpGQq|0gqayk!Ya^+PjX4N8?D5g!qmj#Oue1c1xj)bM+ z2T)B1Vpyu-w8$*btz5JN+Z@~RR0rLl${Qy`b5~FR1Qq(w%1p?xD_GxjnYKMU!c@kt zVOL>EC5U18h<2C>f(XKNa;emoJ6_}x;M_3u5*}TFjM>Xj+CWH6fSr!f#{R(X`b)KI zl@mRON9Nxs+ZR-6B_Kr1yRn0`z2^Mi20q}Ecmg2$Kzt7llx!Q5;RdZxK->D?}KpwdH;+{|zas9n+Tjlb@vY#PBQY9q& zfMUnnZ>M<0a`S~p;`x#FcAQxwD8cl|h#j|PBfR{u;>oh0jLR>CTknitNe0d)!rS(| z$O1sXQ<&9JApo(kHYx-gLk8?yoCduQI?axv{JWn^xZ2SeaCB8T9W|CK%PEx9!c1&yYE+YA zK=hQI=WmuKik?smw;Y-2u@`&uI1*4mfw>*zx%454+}bejO&D@Ufh2DLo8HD`8(iCS z6MS#pkA#1G(JsVH2a94DS7>*4>9}NjXAa z%H2zc`iJ_DrWF~<62R6|&XYTmM`LlYxDhZUY!_B=s%5*!uLgc{&xR9}3A}f|_xiWf z71zcv%@1DqaP!QiZE4IY!i+|`r>WRM0yk*7hb;tyY37?dTmADQwR|sCF|w8t0o=2z zeYboyPM8#P33gzGcS>JS=<(|U(CVP-3jCM^ASR}XDuYPjgrpx=`@4`-$=}nYwWyUT zr6|rUQ&C8A?jW}1uR9Vu+X=ClW_J6qv2gGA7H7_1n$qWNIQ<}T3T*jrwCX@xYABFp zB}rOM^sOiGok1qS+Eo&!AlyhWQhJZE;L8^PD^BcU@%oWHTLs*sTZZW-cQ(JyPv`#t zTs)e9ZrvH%w11WuRdn@nJ6rnRUk{w7kpYTjzyvgeKoBHZK$w%Vq{I`s1^~K6a=Iw| zKqMz^Ou!F7L<{ua6*V&Y6uzq^xw!@A?(9#{VQ!{}&8H6pe({nLL~hw9R*}7zaBLvl z;Ck6WToHb(0}~OXayPaQm2kk=kQs#adySo<-5vYT)QJeIbs(tz={ud22{y1MB>JR~ z1S&=9^Yxg7o5=yK#P{{LTs*2yDVDaQwW7?=xM$dU%9PaSP*Y+gnX&k0N%a#GKHzg{ z#WLzO&4N86Vrl(+0sYy2=4mo-01Gy?F1F9Y1g5BS3#24iBGV2V8fhUD-kO4c1urUU}5-voX zQk9#$%UU}SI=Pmx+Z*?7Ii!tV}pgdX3$g<5;)pqL;xa8SjNH$J76kWfF;bh zFKOOl{+)3k$w>_4FbM+SvzGzbS%*#u#EFx#w? zDXRO37rRaD#PN&>Br_xcT!w<@$`0J`VEvucbV(X~)u@suR+S|rfJr1tvPG3300~rL zx~*jrQrd63wcr-Ji@$6UC{wc({{W~KcrwrZg}`F?anjQ?kOqXEN+6`5?F51ffr&fm z37!m-iu#pQp$wKL!^}??4p=twEw&4xOj+6-7X-D*ByYfLk}rjtdMZYi7S$ah7FGdt zQ#M?Iu~V8tj0v`~WSPFpDy?OPRa&|QhP7!N`AGmfOmTKDP?Z#bbrjiy+9Z<@2I_KJ z8tbhf=t@aC0Tw71l5C&=ix4*xcs$`}(yg_zl&eWCum$^e9AYY>QkL@+hrX9>oy1In z?pX9V5m|D+I(eN#&{e3~XG)XtZvafh&6J>KE2J=Aoa{na4Y%lC-$4-wFd9MJ>e5H8 zx!@Rr#CDiqC@sc9ok;+K)|Ws@-&i3;>XMs{z#4bNR;3qZmLU0o^0V2kXeQw0^Yl?6Z; zv?+u{1nRh*jy)&#ShAlT&r)#JavJVjd$ptp-bv?U7;`H%THZwv8XiQ%G!CqLo=?+e ztpz}*Qc8%G1p=ZXN8z7N*H`9AIQPW@Qzp$ka?&L1%zYmXDJ)BYC7c-~eKsA0+Y5Br zuAu>yXd1RxsOjKE!R{`0?}!vd<y1O{{N-6r~`SWPlFY5ao{Eb)9qrLJ6%3z^st zt4y)_7Y9es6P!|;`h3?C4a8_XTz@Nz12c$KtOYXV{{RUMXL&3+BdZCq0Xo#qlM>|I zKIY~lr{?DU_zg*;F3+6^Ae#Dg0T)n9GwB}YOo7To1mltMx}`@iAP|+PA5cgqkW4?^ z<5^@)LPRCHK{xFVWVO!NvP?7q+VTa($SIOXb32p7?HJ~kvIEGxzc*p7~lV&VYhhXP--P8Vqz zPo&0?0zm{xHZl$OJ)%#(5UjEsyO8H&9UHe_%Lk@`s0(_PddZu(F)rShFwQ3hjp zxV%ijCIAO<;gTO*&GMI(9bp^%6T;!Xn+I zZ%Vp=NY@M1yj=(8)?nZih49H zN_8X+MGGOv&!$3DbzED}{5p^B`C2p+3#iLb59VD%vI19bb^g51^^cZM|<))kDZ3oh%3zCZ6DFaqzglh zv13RO5(#blL$U0C&J3~=RRj-(P%b#1ru%mMiaCK|9fR%jKRDT-0BkKN0tC6$)Jcxg z(=hw6!n-U$1O-5t06_0C99l>*8{ZW*6kLP(IW23qE$G<0q>B;wW&v)Yrq8iv;{z6_ zjXMBIi$$(&uz?fK*jAxwx!t?8@9IE*RuL8Y>L4Q4wAgpH_m9kb z`0%IT3a`ov+}#Ue^T3EOE0o(D27KGr({isjWQm+r*H zwwvO~G{Xpvt<&V=q_gjZoVJK2x{YxWP|4WutR4Fv1pfe_lU>%I`Gb?RhWUNA!IMfr zV|a*|wZ7Pbyi?1=oo&=+JuX+34MN}+n%>^pt$6x?YL)*0-WExJFc1F#bT|1P{{Y+oZZ8lvF2@ThgG-Ny_AaF#M}9VD4~-GjbjW-+M?!0ml|r3y!oy^U zyJ<^KDL~wfS`Ty!;d=STv3@0if1j*37C0>$0LwYrKARs?yLH2n9a7p5CnXXh!npU3 z{{U2th_$x0uz<~iTf6y$^&Ut2^*iFgQe^xg&f5s}Bh&8~BT?2(={hn~sB!y32;O7; z%hl`-_%O^Q#*;R3KH5Y#Q{3PrH{ousPuAF{zB=_Y`R;#|w$(Bz4obqEY@zQp!u3+x zdQ{;`1fVp@NC-qt#pe}XC!5t)icWg*CoO;iM=Jj&BPmm5(~Qb++ng`lYgC07*lBDEwf1tcgj znF?tJ>}Ek?97`9)ZAvPpqJownkOW#-zV04=w-}H*7M!NGx|ZL*r%Q5Q5h0n}iw%ctOiKD0QDj7T&bEt4piGQe!y%+Mq-&YY9yt=Xak^#6ClqnZ5VQ~kyJJcR>@Ew7){fpfgl5M zKHyw?6NpsK17iRUG6^T6Mfi5U_#$Y6JhyAJ5n$}Yw40kXmwHz#a+KCIJ|8)~G85`V zE)2!}KAE%`=L%;lg=i|5OouP(Hu{UZVWm>kDTnfbw76>x;yOP3$Ll!8cvW6%n<}!p2xge#%yr~ zRDurWgIx6aZN}ztpS!%s4X6;s+Baj#ZaB6iypfl_=-6!vR;eRMBu=Gi011#pT%Vrt ziVWhOqKb$NNDmIo48sshx2s^OqDWFeAQk~r3IIO@%a~?%-d?m+6{=V%rG3H#Ct4vX zNivWDJAekM2IU}0zA7u$q>#p zhkjSlxvg8FC~<`9O#UTl&-Q|t}USD3)z^J0Ar_ms-O{_tSn+uWZ*vW!92Mr@NL1XxJ z>8vY-rQ2c)#Ixux0AE=+E2DJbSyO%G$%g0`(_Qa5q;F2JH$8YJ&Gh(6rypV?c25-=R{W8e}Ai&l4 zT*TOr4#w~f#7Mk%f3oG3dr?poU&FHu-~vayqCjhGTjwT2*;M}k9H*4DNPScC+;ceN zEjcQc5S3m*m2ON4fp2lx0qlN^a1NF&(Vedkyj`z{)Pi>m9QC{q;sGEr7jcILD%5}h z7fCQok;qW65&_fPABbwib!skbNO)rwn+Uw>7HlrCbpQy54|}k%h6K6et{n7)l%Ih? zNrl9ezzWg?gAxy7J4V=DOclF977|(COIY@`+HkVz7h*~BkYK11LZ(Q)&D=0%oG7%j_gj-Je22T*f1P$YpW@~PSZGbJS;s{ZNu6Uq3(-mNgr zTBsO{<6INsAfDR;ic{$ytdPPFH@u` zNk8*R+|Jx{cpydi5^-BqMtY5*iy49FNZ)>0(IM|>n2q{$afcfS2Id5j8xl7^DLY8p z=VMz{Kpww;@c3;h+?hVC-!S`rcxZT`pC=>fDz^}zimKF#I#@8jHNa$|_9#ZT5_r-i z3>U(vd;Ic28k0=xR~kVM`%EVHJK$N$hL&A>DSlLdCDa+fV#EmwI$d@^&lUH z4Fx35>`3`0ci-sFSPWP4(I5E%JDU+`=JN;GM$?XkOSRa;#jZ}#9NaTBn>s)jgBn;E z+8O@<<`PHLFfQXhm;h=pbrbD9&$tj`K-xqHSh=uy?9Y33bL!(3RMJZUW)dHEGkAft zhHK+i8efvsEwJPt%=K@EFQcc>6T!5YJKLLoPW$80DlOl3bN)IEc&#)P zfI2{)9^HPJbJDg9$OLKUaeruo$FTZhzM&+Tw|(08^ux##YY&$gR4$^B8mAVNBA@rG zTF6QelzNJmr4W>%AWDfK00}1xd%_e5hGNgb9)rAn&JK`NLkEyQU$4F^FN)o1lB22f z^On@JnmYAK@>fKpze}siX(dLfC(3asR2gWvJtT#5f#)-cq^he(_l8-wWTmX)NRkA* zCk!7At56z+B`DNfn~>#>pNWjKwDcnko|4a7&FCods>-JgbrWTjF!PJ@o@^Br6C zl9ZTRX@w_Dgp|&ZmwD`ws8By~Mvb zl4xkq+p(&fksEJXFAWD_^K{JI_RVZ~ST0osdfIe^O-wo*1eNgixFnr0(cv}ts)~gyvJFM3=}O2lPRKxI zl3)j5UdI#t$MM!IpTwTu%uEOLwc8U043if9T>IAcsi<&ec}}=1+IPC6g4wJsJ2jl^rS}QTNtD%w9^Sf zL15{1HJytDj_yks5bSRdzRcZw;DhyDNz$%6*1Z=R^Cs!oQZpJVbQ9~ZplwgcWd~5q zXv*7fQ4cVNi-}yT_bD@vz!K{6s$E+0T!s1(hU4S zf>IAsr0(FB#ymOAvh3qEr>e`|4k6llggVlSQ2Prld7+n@1jB<#Hd2tZjYuRLF_p|B zww0k?RX8A-1SQBIaUB}YCl$-2s!AzPVk8hEY)3=id&6REs&vz;DB?@psXOHPXS z3TT-xvXEJ$N=Od|jFcMHg(#B>0z!$K^PbUG%xb4VAK+;BkWZaugAxlef4>+H@MzYk zf&f|^Dxv^XkmO6u5Kkb;af=C8;m<{NN))H*+RH1H6%}+P6w8we^|Y8}>656fDp&BS zB;%Y6ys$#As6+^GJ{K%qEU2Z!YEUF4 zgYp;)+&mZI%SqOTT0krTV$j1#f_bOX{>>w5)-+=DjA%w;za>N!=f^J&n zq&DmW!8<%S#GONuWNe@=yFI5Lh_;uRZ;>KYN{o+$h$1XTDJy1kMOtX(SH`U>=mmoY zJ$f8Uodjt*)nI-Q;DLDrfZ@){+_YiWLjM3nQo4rITR`I0pa4?-@U<0iZlDB>k^#Md z8zEG9n$lJ7>VPg=KuEEc4o6pri8wH&MIK-Z$9G}FTb>wl0~f_FRrKW$46)|CHUXA~ zgqeb&s04|dT0rETs%rRta-elEFZh;vvofyR^MZ=B(moY=gXz))7LyG&67A@4q}N~5 zjX!nETyaSfOYSAGkaiH1-sUWJl6}B@9-)7ESR@$og0m3hsle)CpmvDNGPMM>N0>~& z4qx-$KztcbUgnM{7HR0169fb)(n%l)GwSROpxl`l61*cWmvvQJ2bEZUA-AaR+hbz6 zARF>7;7F2q^zKM$8>c$YFrp~?+bvdV1x|Vr!-G^wLX+q^5&(q@+D-96pYWPFkf4IP zB@6=r`3G)&H#F1!FGA%GMB>1LonMk8vqljfFs26hDR7f{+;NEZr zVkX@aO$1K%RDWam% zN|H{Zks6SYAjq`b9X+-?9A1pTSRU}{ELmG9p0e8$%&@S+KJUyxkHrq*Ezbak65y8D zwKMy9rANS4;YL5(ERd6=4e4_-P;N*eKf+AuGc%7u{g)6us9)i44a@)?^)*Tic#<4A zg8*UNnnK~bl;q?QhVT2bYi;bA?3^r}cP8X>gQlTX=YlPieyMcZp2H=BW2*h=X8#o}hOLsHd z3zRb|(9I4F!RWz&!>W;`dJrU?Q)q!2L7q&1eXtcM5>;Z>H!MqXFtW)mc>oKTefpW& z3yCsUmfoDcxo~u*k>jwEr~qsdEig>lW@d1uMTsAZ2;*nx{A|Yn(h7x(k$4?h<)wzt z!E=h#s&zeEQsN}*eMWCGsGT#a!az|lOc+V!Q&Ex-HrOJPqG{AJFMs+Na0QrMW*~5W23J{cn3Ya~il*UDfEUM|P#+hLSu z=(q(|HkTWYfUu3kvE|iI;xA96B%0=d6Cjc_-)~Au5x1l$Z8LePtKs>B0+mDm0CqmS zg7@X|VM{eYf#w0v`k=ftL+pQ~Lw+jtN;;mphMO;VJD1T@sald0gt=7Wp>mTF8cS#h zSwQtT>}p1txA2Ua%2TUSs!D3DP39xYfg;j%6CvBmmzNT5L4Xs0B_J~i@ zw?Jip7;=?00?f`Edy7ZH*LDm?p}}R*D9nIj2EY>$%=R3aGrh^c4Ny(Up8emG#@EG_ zBf#iGC+xCVWu zK7IGH$~?&5pVRj5v9YAqBkl*$*}mUAMOE3hRgzPhywM65OTfY`xsx zqy8FeYW&Jt0J0R3<**0d>Y;JzBAE&hQ1Y=yn(D!w#_XVC=wgGlF?-7gczR)D$@; zR@Fvro7cD-rln{Q!wA*ubz}Y&H7f}rZ$7Y;p)(|^0+c|^=j)1NQr4pZ{HaJ_RMtvE z&CjU=4S`E8lch53EJ~DIv+PNCwG#IDV)L7BsyDL)972jU=1xWE)tvQ)c4 zN=1WiNx25w13LgFuBhwWi>9hkNm{qws#1K#GfLWAQ%$SjQ>9BlMz}ge$pDiA__p=m$-LSLIIX@keV*K=b?+5C6GJ(7 zP%xF(W}Q1ihMvm0g`Fx}wOMT>Dw(?Qg0~e)gr%CZs5X}BZ0b4h4piqnJ&~9RB~-w4 zSA%r80;9-g3Nm@bRD_m)G9B0#DP!>=oVMCn!SaAclT3PRsk7S3O8VU5rlO-Usm*HM zsx_(o;#^La6v$;jec85_(~P2>C~dY%RMJqCp(#p!7P|E)Ep>HjReF%1%tnx)5`GOT z1v+C(7#LGERM4uQa07La>usEgE)d?h$r8y+d zr5BQRmup#@Yt>4yojR^kR0teeQwuh^k)%Q5alusvSe9U3!}a>KV#bTa+st2r1p2up z&fB@bxxY|3k>xct$bH5gLuy4jQn)6e#OOwZ$poa5Rqfj65XJA`+0GD@lTCPuY-{QOheX-in z%jLpSgwUom1|C^p8HXEL!LV_G`^6IOs~31;&t1gs?Wgig&Le?Nj z{3qi4B+0lKs?MnUy)HpfVkL+U&~DKCeQ~fA&uNS%knx9#}3S;A?KT)fg@2SObM|G z0&N}*8Lr2haA0x-J6 zi^GQ|Tjla;=y$_16y=$W9-IyA@7g$!I(Mt{oT?daq*c?%(@j;WzzI7cLKKo5gVN3}kzlQ9Q6Ix0(k%CoROQPs^08+a zut}+^sH3KR_60Yd(j0Y!t5=p*H6SnHDF;x1LcivXvFG0El`6GqqM@zs)}*4L3|10! zsHE7Dr2hbXTIH*zp@%}{!6CFWxUgkB0jQULa2$T0ryth^vwVOYeE1h}hroWDl7GYR zY(Ty_c%jf<19YptA^3-wRph-KirRWQ+|rjSt<2fW>S~UbS5}G!on0j>iu9_bz?K_P zDO!`yQ|$gzIpdX%M=9==o2O6S1lFzY%FyH;E)-Uzz-A^=_rf(Y6{}Sg^2rJ{9HkBr z39-^xxFX<4p4g<`H~5|4*V>oDx-OgWlg2*{-_9!fgDuTjqv{TzYax5?^sLpk^M7`# z0-#g{KAi~i#HA`$t3mYNWAeTy?5~ZlH{!k*o~c9kIpg?H+sK{bFS*4$^fO-jSqE zm|Ilj5NB4>Iqi=^t@}^*dVwjcN5$zXK@~CzM8o_(=KevU5IOA-@l z!>XI?AL960i@A?SB0wa4{;=$L(?~%{f^}^$E@KI+_O0yFN0yg~s5o=(Y48EPKtz)l z9N=b^LLo9g)|X-~{{Tm6aO4a*DL%tqDIr7u09kBmL4~Se=4-6Bq?g z+OM;bp)bT76XZ~cY*Q+Fz_X{_I+ zO+&Pf1{z&WN<8O*)EiTucRGB*U}JsYh)rt$0Bc^)Yf4p1#55HIsG3P337;_mb{l~A zamk8&HowF|NKcu{gPTHidVmSJnPNHV;unJcBY0JszeU$QBbj8){otmTH1ZWwlGY_s zlp1`_pItdqvZW=bOK)tYCsmJQ;r=<{zAs2t@Z9wb%1A0wQBzH15TZ`HN@b)a!1D=a z5jX`zDJlTCai>X6_Y7>IatJWt;|<)cF0vd`V1T3qN<>bW^w>f7?nIs?)l>`~?&XOQ z&oE=4z7wd2O9pVO+%O+t^ApwZuG6lh3n&>kR?sH$5)6m{X%GYnjA*15^9xH|&mG*{ z`aT6$Lop7)!!rgX*c&tKNU?@>1m;x@%0N+$NS~PW#`}}nF@lmvV!h-(k}vkRe#Z%| z0PyX(n;6t%b|wRk9AI|ys+60gTVv`ofBZ`QV|h1{HmtfBd5L!?ZjKl+jk<4yRDcet z)xR)cGc(w2&m#+TeM?f=8ktEDL`&1{5W9AOefPra%2QLdLI`8{8RwBcp^J;#5Ymue zNKN1ZkVJ6aw>=r~?V;+0z?wuZHXe0Fw&TuB!L-iap#yrl**RfQ+z8XuaKb;v8K+NI znp!9D^nl^GcX#FR;BTo`ObRs3$v$ORRPG5LdE67Eq! z*29B_g(naVnD%*a&$QBgCgM^ejX>- zP3>?aY1oa=%t@0t&0w3!`QP+Abi?#g95`kHm>)yEm<>+@d>0L*dbGyYfK$8zB1G*z zU$3aS zYZ_v}Z@9gj?R~p<$0;(LyQ(}v>O7+%r*^wK&ofH8e71$Um!5c`M@vCVDl777=~+UY zsdr2^%T7Gxgp-F-oW^pxDC%8Gicmn*Nz%cIB6NhLI-0;fJje=El2nw2JY7y;J>;0! zUIse#;rD``8hBHaP&n>alho%_lx?Rl>U`yv9;&LUPzJ5)f4vpAOH8MvFw+VB(`i5} zQo@vbdKnC^NeBq1Osy&YC1r$_lEKMRpG%VZL1FO2NdExTvN<}Bkv&3BmIa9qH+DF9 z=3Xadbl|s^H0EaFMufbnVv!*>2}xQ*t|dQ*%R*aHPo?Zerez5SOQ^Zz2jn}vuwVco zrLnVJKZnhEu)ojg>%JH{pH}DD(jQ``u}#v{w5DC7r%D=U%TyAQAw@(Kr9iDpAwy9! zCl#x%vRsw~{2)hOO`b_Dw!<4W7POR-$xvdD1b%U}f)COk%(BKaDtek4mcr1zXi`>@ zI<5wwK_01+A_z8%5hduWNr-nz1tj-^@W#?bgW2!|g&{zK%tIGzTGI~B#`5!uiI{Zd zVmg8DpP;95s=0ZRXsGGiK~t|f^Px2Cr7!_24k0O#5pqIqIEvJW%`Y!aE=5fU8>>+T z1*C{6oq;Z67wM?%yYRmcr<0-p(rT;&R-|ewXaMY#xe4_*oG3|BwW|AW z5;q(IY)HETAt9VybK)yKIMVX$w6{^5tt2j0<~2eUKfHbj*74m95@O18(gIZdT7sJ; zELM6J5b{Gz*juI(%w_@|Aw;R7VI!-(w@DAnJ}U)vZAE=U)pc(!qNbr`$6awnN?Mh9 zB~v4a76R4~Fsl-xr591T>(hYD7%+=su}UP8WRhRxP6=4gGrU+Ia(jMT+A$|RW9f)o zlXlqi+qjTNTt0eBuCrd4SY-s(Wr|TQP&~Cl2k}!ZljN)0Nl7!QJ&#K;x?k!|nC;l@ z+R=kks-(C9(|s=U$Tl2Xq&6Xc8Zthe&og#9r>3b}$*MCz_wD*1(vr)Wf)<6hm_kY! zL$zsiq2#iKDfgRtsr4k0sL9h-paSR6>&Ak>(6p!;*LS zoNmsSf}#WGz{eiS`gzK9JRE+5I(DhDiB6KX=~jy<>{f*i#FOuW)TjJ5GL?eh0!Eoh z2dtQOfMm8RkNig>5763JF@i0(%N;rC%-OutDWl9%vPDY`sZ(Vo!ksHjC-EU*@AKy# zX`Y~HS6u=jD^p821Rd__VBVWU*>mL}lMD>W>BE3`hTjaHz0QSAV_9QF6wxF(P-MfE z3s0aEBzjRh_n&-Ncvf7~rmEzB#B`;Ff=BS|L4#zY=O_QkiD6vR9d2_>Xl3433rHjo>TUEHu#C)(*Je!xK+_t;+&3Mz0%!eBuR9znTxv3cF21WH)Jo2WAzZVwH8%YkEwC#MtT zQxiU?R8$Gp00Uw~z$7rX{W$`vr&$faa^h0#{mcIVk%yH! z%1BqMk5CcG8|)zO>^;QRu1f}T7>_`E2mJa(kdm!V`e2SX2HW*NYrH6(3rbu-AYMYZ zokS=PXpy(TV%V;#mL)4^;r3v9{GJQR6NwbNqy{5$Id=ZL_3I#I2nl2_;x3tsk4kon z%o~nv@mS)UGE${!FaUyN5@m>Om>;TT@gZc3j$Ff%SVRU6UuJt3byI+$1y>hWA_PDO zd9d1V$i;0zAwk9NA&eWh1^$zXl)K1ibLn=Mf2qTPm2EM9N~hri(`mNE5>Mx77z&c* zfdSl!7jo<;V9+cvB^ZWgBc|Pq5w{Zu62FI85zTWH*VF`>It8TsBloY!QV<9LDFA@A z4^cXFow3Y&N8&%aWxsbsR<4yK7nCAG)Wuv9k!>Wn#3`hb?&U@-eEZTj?i0!Kn#Ck~*HNe9jhm-uWu8(BLu7r_dO zGT7FMQY|12M0blATQ$5e8HJ)N0~i; zqKrlweO=PMJJ&rgo^*Fr<*a8NHPo4PR#TkiRZSt*D(I@)EiEM~)SodR>TSqMlC*`S zgCy8wvzd<%&QQ+f7Aa8%yGRA7eC9$4l zsA`KfObfdGAPJ^@J;Mk}&XAyDal&}t?B^q#)mOr^RWcO|{{XwzQOsr3PvJl$R0P}| zdO&~qaRKBZ{K68-WRb%uH`o`)QhYS=>%wmqXxMk8x~_@J*Fs!5K4eB;nlhz9^36N? z3YLSa?Q4<9-yTik{>*sqgDpzUWY<$J91PA_nzWPvlC2|BMW0ZDM_e*0B}@;MMaw8% z!Q47e4h)xbIFvJ-j)yg*doIqh+DywVtZhhok29uju94J0AMh#=q!g(H`jRF{jfN?* zncCTUg1%QXR)u;>4N`?ePN0%}%0m|l9}1!gA%(zU??kfF3rr2~&b@SoaWiRAQB z@k%4asU)|)rc*~Y00LODDz(W|DMUl!zPE;Eq+d#eInyn;20LXq<}(` z>D=wSkr?W7`GU9AU^gvk1>LmYV=Tdo;z-4r)xc0(TQT4L3aTB<(SIiM|l4S>%Rz zyNJA(XKQo2-KunyLpcMhL&IEg@?&c*vp`4^soQSn<}JY|y{&CYE~qXV(br~%<^);B zoFo_1c^8A9L(_`DnTR*-~Rxmy-fYDyv+8)i4Y+0-Fx|i z56obbnJ56<0!;0u_vb`|>4FH06Ue~MWsEymw`MdYF(w7rqi- z%0;J8vG{Lqb8&B_zK0p_)C2(J?+@5p`uwocXpbm%k_jW$ARC>Iz>BsKpUN$Dm;+!U zcY_c}Jeao=$k@z~Lxw$e`*k0DIZB_~kJRpeM+6m<0|2MNdyKYNn!vGk zAut=2UQQ<(s_NXu?>@e*`p0CeT|%cU2p33Fsi#rj%n}GQ4tB+rB?VKYlKMbej1rPU$V99L1gs-GQ@m0Wj`PD;w^u=NxtQt;bwZQr6;%*0rCBN>SXCe!>6{ zFuFvAxpQ;Lf6Mw}sLl8P02m;(i;sA}`g8vPTpcMOgX{giSQ%F`3&6N|V>^lO+a5}$ z2e;0CynmO|7^JlI?8CK>>#j5;aUtv&9$BBi%X|)nBz))ckJsuy$l?rmdODmoutqxm6?S^qEzjZAM2X6LVp|z8k0-ounz4G+UdEwlZGB z6@(IZ4E-&|rsDSQ9`bl+)XmW4nY9&5gG~!Yx|J$7QWZMTnKxIRBmrO#0x`(=#!S_% zMQIQ32tw2>AIuC36qa*#Ye^te6p$I++V7>ioyjqMiM(=feS;|-)GuRbCz%^W zPv#=WY7A3gIJa`|FUviiaAY$9!JXZX#l!GV%v%cVHWq?~fV8M6DJRqnf}o;obtN&T zFA+A3FHuD&P!bw{qrWo$0F;mqDN`{p$AE3SN#0`#?@>8S=m9#=xJzaU-*gf-a9RPk zd&Vb8VCpVL_7*1RpkN^KIs>>NoE0QVhX4mQFX+(H<%yB9;pDK(VE`782c;o1F(k>8 zGxH~FL{?SvDP>3EFLr(SW(;oMGb^P!r1sR$@UeL!4#RDsh;Xo=YzaGF#==dEZQO0| zV}zHrz7w(N{7Y|dOcgpq>3xi`=G(VJ+iW^AaHndTWNXl+5<%D?2_(dun*+S^Fpgw| zp-Qo{iE`nEnZbUHK4joTs9yFhV(i?<6F8LVHETp6a*-AZ0HQYA(m{X)ffgzgiVCeI z?|xn9ZTH`HI52?H1&Ha#9+qgdVZlsAkZmLb+QvOMKD7&gZ2*ZTMi8sa#DQ?vZtuR> z*hnnFgEE8qUiSE3w3ow^FQ%xhs;8r;Y`XnJh-tI{NhM^Y6%b%(NY+fiu_kSWD^*1r zYpGE|C_;6UERc{ccX13KREXXSNJu0l$k;u;yKY|Nd|S?&$=k^Cnq0kv$!!5|C<#-q zs0BK;d(40Yh=bldqr~&8&*v*a5veccCABvPovz|9ip}<$ z`#kjD+Ec>p*Pt`zSYtM2r}Hk0&x>hYM^5!CY^>5$A!Q{(j;V1=nA4!?b%mAx0K{zy z$6M^rv{ikb@f7CJRJ^rfiasHixUH85{vesHLG{yB%1Y_kWTnb#RVt~dfX7MH1E?t_ z$w?OEq{}DNRDJ4)-#IZ7$27KaG)>69J{T|Gcgp3zVW zC|DbeeG^OCZvv`{by4D(Q%N=ZBRHDrxPC$qa1W9&0lXsJHFYx~W`$;nMMO`hEgaVQS*@6H;pH8hUZ=y*6 zdb#5YRQAW&+HO_iRE!rWAd=4DIfgN2Xa@las7tblZV6>O5Xwtfmm#J16KA?7?0xo( z$sD9{8D3LLx^)#L<|{O)bn8oEE+7FL-Wg$k6bN8gAGF4b=AORj?5=(60w7aOeNq!fWuChvW54&^k4snNQf0!8YWKvbiJ@U{=0Bm>|cQ!P+e(_X7YwwLfVT z2n(eBP&T+Q<@mG)VE83J0?EUb9t)r9KHUr8bp4Bb9asP}nlo!9HEJm$M+zr^2J^P( z06(=4Xr?Ha-GDx%ByT)k*m)iSlVIvtac+AzMt#eHgGl=oct(&Q=IiV}`gRilTl6+e z00daBuiA%??usL*NIy9I=X@}qXYyj|sIHz~t!az&b&Ofh=0JkloN?ZN!9;r1u+p;t-Hhadat9lzxf z9LTx%oDE;KA02in%a@kYliTpUhQ`=Bd?MBGym$iCvi34j)baG*#jS%Uz_QL7qTVF<8#%h}z#{sZ@SQ5W%J~&(>E0i69zt`zzxWfqW zgeLWuarjeh_?{uT=Lz+n;j!U$LZ*wU`iht+-M39U!6SXj61gTI$*?;K18DuRc(@H) zBbQTuE~X~m3z77@p3Nu20BsdYxYRrCFT1G{&tCs1N~F%~2-5&r<^TYN(uIh$s=e^B*Vpv?0Ozt47$&-;~A^uB2F zwU0B(T6O6vR*w;^UAhoD+W!DQ)z}Juk=ge2=aFrn z39FfqKBL~>*dIO48NiMI08PYn`P8@{{SKO`ujxNd>(=R zH6wrGp#K2tAE&^oIZC)On31IvsINP&lyLC@vq}RJX7k1g%5l zd)p3IBAQfIKze{VR+spkIT!woE=DV#Qkk5cQF2diq3`y+mU4?TVTodbxhqn@B^2*! z0B~U>6p?)-5DnyE4|_b%ANVc;AQA_`d)SWu09-DmAtTCB4oCz6J&Vb9lep|upanS!V-n;;Lq8_v zMliKZtiY&^HAx2l0Pvg}nFmlvJdiISf(5X;%`gI;CC#;J@8u`7!TI3nrbv=3{OC2 zNCp{$ZVj*M9zO3{Uo`wEP!JQOwzGc5Q)>eUXtWRnSJWW8sqRlgHj~Nz;pAziL)geRWP%$k;}9g=bqf0Vp6?-0WI*iPHrwq zktcI6A@s#7iA%L=N|L20p#+1lGNq>5O|?ljKT3S+(g>#FB~tEe$7kQI-vmksQ!xQ7 z-3hddkQ^SRfW9OOG!@V8^>27lCT34$kOXZrdBrtlG^Imma2ch(Q1>_(E<2?+{o3XS#U>_FVDHbo;Tn~Zq=hLXXCy=0je*z>Hy9wKUI8&? zF2kD>En@p(fAGtu9i~an>eB(*@24zwrnys&=}14!%y?oK$5X#7wt42>l~(z@ht z43s|a@mTHYrP44Gl?0MpfxA2J>%cx{IGkHEr+v~6{*rjU-1Zy$Iofm!}V-K z-K$lP5+J?1J9dd9bLf#2T8w%`fGmDP^TNuVQYC<%4899an)M_UEC*AaCyk3X z*go2AvaX_L6mJBR0@sC46FlKnnF1^x+=!n>;`p*nG6$6^X*MURFZDfVd>m<~0T6|l z{6s+B#K_zdEdpWNRiAzO@Qgv5Z=jI zsB}2%N%H_2wP_%jH&w_gABJrm$(%fl`spJ|6m&UlF5p37z(0$5wi`eXF62ARDs+?S zZ?xe;mmy*jpCutdB31{eN#sEQgo6WOEjwXqz9CW6ec@*ZNwI55yPKQt8SrsU*lA*s zB&n`<1we=&CJi9rWt^FWh%7fctgRps5xjy-{ExN}tDdN5-YVbCzoy^}83{|Wl9ts3 z79ed8^XG1=NuWx1NC-$&0loc=!TOl?+#+)dQy23dtsTrZ7#d&?C`d5Q9Q|Ak-_qDF zs%m!1w1k+xk~tg6BJp{d8xgh)DpXTDy_`P$2)sYbj6vz7m;^I`S=>PmRm_)U>6zHF z%5R}IBS|LP?*r5YtVlD+!9X#r$a2DA&)ojF5v-XBO9Cgk;rI+5CEKYbAxhjEY+zjT zHk-_Tcsf+xx4pI-+xmJ5O5mGAMeo6o*x9OOEZ%n~R7`JcjxGeAV#69$PyugH>~GNG z2@XU%bOoS|;qEYGQmiOnc-mlFfHwY8JHR6~Lw{Ctz4|uN-5&*IxrVen4YmP?F4JP| zjm;duAx0+QD)mI)dA86E%1t{1nGgottKFe zo#2Qh*ch~0Mi(kka{Pab0`a)Bz8OlofM(lrc;xVTzBfz)4eV|Ofg5jV1XzAYwg#yN z!N>R?Kk7EYlTbko(~bdtgQnh?9Tfx^F$d!3f(5Vg@45J=0aYMvcZR>tINWr@399{o zYqS=yn{m*%XBZU=LYz#H0Z@=;3Q3a#U?bS}i(G0#l9Fe6fo@Lx$q)6xlCcA30Ld@Q zSW9sjQbN)eB1YiKjDlrEL=h4!Qboau0O4YiL3T65ar0+;^lUN|96=C&tA9%#Uk6%v zpn*I{9FKT{eY*@Ux^5f|=Yo5?b?btKZU~upkeQJQR1hyQeOpbA_uff3QnC~krHgF9m;2h% z#|G3!(Xp9mypOexJ{Gd<(LE)UdHJYmma5)KWydNTLvWVWB&*Z~%4XsL5G-T#lf=EC zMI6%dxm>MW)@qVSS_@L9l?Cb0rG(Y0Y7!2Vri#LVx^8@D!M%#kX7b6-=QDYHj!vS$ zr&2Q&str1df&%GM&;bsm*Gm;PmkI&5nfT9Pg*Vj8zI)1T-(9uXsE-h8VG0|nb zGKxh|m`bTClLu!|x}D0j**9Z5N1l68m|lA*tb*1}T*_3SLuyD8jV+`km5a5Moq#y( z7JJ~=hn_2CnQnL~-^%K98Ww8lGfb7lH0PI8(i|#oS}YvYs#E8C83QELQhNLXlh&q?8scq>!cpbr=%q zj8%;5>_yl4K5LrheJP$~-BClBs+~xtsw&AdR(!M;)EsH$)X=<(2wE#!QjCDbgtM3N z%(uR*y8iN!t)Rd)5(*P-N%I$iJggXFsG;o!UaAE;)YnAQvVj#4LEZpZc!pFo!NM@` zm&7iK%a+Gb^wwiahTU~$p_avM9)%I=`^_SrWdncsg$m@Sz5Z9kvUR`|vozFUl2xHZ zk;0iu^aT8-&W>X*T{@{%N}gHSK-sjPG(j;IafYo^H<*s#*v!eDkG}I`Va1vkzs!BH zC5_lO>-D}8{GcXwz3=q?fAxtiYbM9+e=pJbU_~!;&)=E-bc}A6z_{4_{l|ar`RI~w zjkSSd2l{_Q>1f94NR5T(={^3SPqrcp$Z*H&`uk&eOR8*?tP2=aakxLq{lA_Wrl~>C~d5uyO zEbU?$NTY0k6HHXp1l3Q5R1vHQ>hjpu%Zz`O5EV?)6p&mNB}6-bMY%~k5sT?flCtO_EH|MkDC-;=J>n7l;ouHdQ5oJn& z-|`?@RH>V+2qAS63^uZ5?$B7c?{Ih^RWN0PNDTpviMx;QdBWQ{9$g8V3MCC7>NM>c zN_HAbKS@8X6jpA({{S|qotCdD?g_snY;A(-Kw#-mE=7X?+=mx<+~Ho6Aj+jBS#=DB z!9R3mF*XB8K$+$bx6Nv~%*=sas}S)~MeV;s>f?M6XlG>Hhw5ZW1>n88w6lqfk0?#Q zW#!+5L8D;Bt#qL88}517oL8LIXp(<*tA3;aMDE*0Bs7^&NC|D>%aLH_ZOiOz zq{c;+tKrJ>=mZ%1t2>?(2t^U!56HOt2OO0Pv z2Ieh!ZK5!`)>A=c3My2oQU3sPjf{eR8_W&=0P=x+AiUmU-u|gfznxc}@;W`+oE0fX z$V*%$i2xS^dzYT9&AOX36sb_rPS7WB-Jn2@&;fzLwWGYNQ!`aSlT~Gz-DHA!l3q!X z-I~)#4#5eK*4xp$_xijtWir~5(LzuTz*!3aYT+l4PHwKzSq% zlh+z3L%^N@pXL{^7bl19g?e^d356h$rt%U{LX4hfU{CQ+(BVpz6!4~&8cA?KU<0^s zrYEEZf?JaZok9m!0pJa=riKv-AS4I{FqluJFf2DW^vJon8v>%LD3t%>^%*|gM;0(*Bu8RS6j~g!L^R*}dYO2{=H~Y-Eb`7cvyY15up-|nN{4#_ zp>3d(waJ~&HU{7gG~B+x?FRO8>}(I@TN~7DRKV_kPw9lEtf-T4Njhx=ciLhk{Kg$f zW|sg?@$~QCYynCnlKhw5r;pd6d}^5NWipe0Nf34sCgw<(B%bk!DcaX!B0+I~u;1^2 z>xT(Di^t0MFLpE4gh&<}Tt_z+1pL1|LgSWlW92@i^M3ddQosf5b#1e^GCJR}z`!;L zR44#Npy>uA-{LTRu6?jSF-tf%?sg07bKTyczEA)C@F;~A7Vi& z^;=*7FbVpC4#vYSSQ+R*AAXHI#l{cs6vc=w5b9yim5DAkc$*i%$}j+l?7K)N=611# zT+G3eCd1P2wV>`jALb+r2*lG+umlqF;sgh7kn&r&z)B(sJV_+T5o;bK-@I+KV_Hcd zGaZ}adwR5Ww7g*GsTY3mZ2f;gz`#x{Mg9<|lkkIZ0l6UU?F2~x<6@ZvG`sC_&~IWt zz6>fDE?eo@zonx97Y3h-(*WKC5IEpY@dn8fNDAM&FJsxcbN)C3qlRhJ1*Qwf&d$Q) z*4HBesnmlYjn39L_AnL1+7HVZ5b#{b>5LZI_+pYw~=U( z_(_ib+ha?kOQ;y ziG``|{{XF<SFvF zhD#!8BARMu2l47wEEQ6*1gNQOl@x&CBWWT_pPaHDHJQzLsIO6KPFZK%Qp=>Dbw-78)TwK$=^FQP{{S&s zlov-(eA-lnr~t1lN=Q3@`(A(TMo?1DBQTIO=Ba`}f+|xQR8RcCg5X36oO%BMjpYVk z#T8Wr)0w84p)3FjQ39YMV^EIcVA!~{L*alWQb;=hKNRorg9+kfKoO2QqykIu8vbKG zjRSa>z7(dxNdoG4u!)|G{K>RSm4pR1`^2SbP$Sfkpr9^Ffi@9sFhSk()>54SfQ@8uN?6I%8R;l`h zhUwI|DMACJxZu=k5b8jkLrsnU0E1_INqO2iY8jPiT7#mYE2a{Z>s&07JfQp}5@0>? zVM9BdN4rM7VM+;QfLRZ4#B5oQtHvr5zh|07wNkdajpV6Mp>(>a0+Q1OI{c@{-a&QH zRG;3Up+1sAJz7U%pBX7d57oS{S8im*avyOxb`$L=jliBbIfbW-6 z)Xo?nLpf*#Mm`Xw)hH(1kVXo8SwtN)JxxIy{{Sg78^+Aonra0F84c?8{Z1TIz5sN| zP!&1ObnpDFiZ()^6(~tz(gaBpdqw8}{{U-NoiwQfGIc4M+ol_DlWuJhdxy2G{oC(o z#F^9o0B8RI4C&mat$Kqn%pInAm(rZVy~h}F#1OQl+IA4bPB*DOrqq(!!6{f$NeZpZ zc-M&e(v{PuG^ia3Vm5F|QF0C4!2z1%N~D((NH>Ap@gxcRn_|b)DYOJM+7f^OLQ<4~ zglS9!q*w%{As{3sEgNsoEz7M&^5n@kazJ<8@7%UGETn=NDF8%oIr(p506P@*OYwcu$spPk$__WI5uqRNf7>pyqtaQ4EDH9}A!8iG=l7?MIp z^K+>Bh_Ie*5hGnEEN=lXGJc-CM`8+qBpXW`-)?UY0wM6S)l_K;SU>;|fT|z}Hr%V3 z?oEtgMN=P$U#tFY+Y(JeWES+d>+`~+6(L*_H#)Dd0(Y3$kPMiNF1ljE;fEJ;!){sN z6KoVOR8HsC8ZCEwzW8%A;7;byEgbP3uk`Q65L!;rCA(Yfa8R;Onr?eDnEiU;LAS_- zcQ%V(a7+OvV1hx8WJtn`rU_#$+`_H_HgFiW44TmFZ0*~4EN5-FI9jE7T6Ia(M3}HM z2lTPxPZ1*t)utVxoU_RQN8jm&(6XeSjq^VXcYVWOrWfhnI*N^kkpKbkfI+-W$v5AT zu*GuF0Maf6%fThgJjdu@>G;dIi(UgX@*nDOsN0ZGr4Pk$36MDx$-H(v+C~$ofuxI& z;n)Wtv)Vl{O-!NGpO@+|q{GTdO1>2Wm5AjtH{W;`o^OR!O)86zGEUORr{(v=isg;` zq%hc?{IS~)?7FPF*Z@d6O1Rnp)eLk2GXfQdjz86&>2~kv%5&;e(`|l;l-K;RxC_@O+o&gG!a8@apXC{CprCNJs` zWD*5{Jb@oGaxrIf$CD4Y)NZ_40MtK59Pe_OPnK9y{kafWY5GW zl^YxTZyzIvs?%p61`OSpUf-TD5_&WlE(q(s-`@%?Iix_go#I8wxwKxxyc>)xw7i|{ z?0qHTX3xF~70I=k-TvP{whp1y2s)-_0iT+_a(kba7g7YnGdUkfHjX~nkWm^)Hg*$W zBo{0lrMHoR3zA7uuq$tB1}$Ui6LGP(aHAl=H{K** zE2k`Fk8R`T+aJi_$*5zFW%00iS^!BiKM~xIP>at8`fYQgNxa9T18YL|NWDKd$y^5m;F!CqYQ!#i;F+$zbtO5g=tES%tUP) z#}~AGw!a|=0s5E2N%Dqr2Vj2fgN;2P6q|guzY;hi*b31nlfNUb8$od4z=s@ImM_)E q Date: Sat, 8 Jan 2022 05:36:37 +0000 Subject: [PATCH 27/51] item charges: add ancient brew --- .../runelite/client/plugins/itemcharges/ItemWithCharge.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/itemcharges/ItemWithCharge.java b/runelite-client/src/main/java/net/runelite/client/plugins/itemcharges/ItemWithCharge.java index b9c1124423..65ee2123a1 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/itemcharges/ItemWithCharge.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/itemcharges/ItemWithCharge.java @@ -62,6 +62,10 @@ enum ItemWithCharge ANTIDOTE_PP2(POTION, ANTIDOTE2_5956, 2), ANTIDOTE_PP3(POTION, ANTIDOTE3_5954, 3), ANTIDOTE_PP4(POTION, ANTIDOTE4_5952, 4), + ANCIENT_BR1(POTION, ANCIENT_BREW1, 1), + ANCIENT_BR2(POTION, ANCIENT_BREW2, 2), + ANCIENT_BR3(POTION, ANCIENT_BREW3, 3), + ANCIENT_BR4(POTION, ANCIENT_BREW4, 4), ANTIFIRE1(POTION, ANTIFIRE_POTION1, 1), ANTIFIRE2(POTION, ANTIFIRE_POTION2, 2), ANTIFIRE3(POTION, ANTIFIRE_POTION3, 3), From a0b739f1f48f5cdf6b392d37f7740d129071c984 Mon Sep 17 00:00:00 2001 From: Hydrox6 Date: Sat, 8 Jan 2022 05:39:39 +0000 Subject: [PATCH 28/51] item identification: add ancient brew The pattern for the short names of the other brews isn't being followed here due to the similarities between the Ancient Brew and (Extended) Super Antifire; using `An` could be confusing. --- .../client/plugins/itemidentification/ItemIdentification.java | 1 + 1 file changed, 1 insertion(+) 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 9661c03b61..044aeeca8a 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 @@ -293,6 +293,7 @@ enum ItemIdentification ZAMORAK_BREW(Type.POTION, "ZammyBr", "Za", ItemID.ZAMORAK_BREW4, ItemID.ZAMORAK_BREW3, ItemID.ZAMORAK_BREW2, ItemID.ZAMORAK_BREW1), SARADOMIN_BREW(Type.POTION, "SaraBr", "Sa", ItemID.SARADOMIN_BREW4, ItemID.SARADOMIN_BREW3, ItemID.SARADOMIN_BREW2, ItemID.SARADOMIN_BREW1), + ANCIENT_BREW(Type.POTION, "AncBr", "A.Br", ItemID.ANCIENT_BREW4, ItemID.ANCIENT_BREW3, ItemID.ANCIENT_BREW2, ItemID.ANCIENT_BREW1), ANTIPOISON(Type.POTION, "AntiP", "AP", ItemID.ANTIPOISON4, ItemID.ANTIPOISON3, ItemID.ANTIPOISON2, ItemID.ANTIPOISON1), SUPERANTIPOISON(Type.POTION, "S.AntiP", "S.AP", ItemID.SUPERANTIPOISON4, ItemID.SUPERANTIPOISON3, ItemID.SUPERANTIPOISON2, ItemID.SUPERANTIPOISON1), From 6b1c1283f77479cbab3342d6170b697a95d6cb4d Mon Sep 17 00:00:00 2001 From: Hydrox6 Date: Sat, 8 Jan 2022 05:41:13 +0000 Subject: [PATCH 29/51] skill calc: add ancient brew --- .../client/plugins/skillcalculator/skills/HerbloreAction.java | 1 + 1 file changed, 1 insertion(+) 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 805bea57f0..ad98d978c2 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 @@ -94,6 +94,7 @@ public enum HerbloreAction implements ItemSkillAction WEAPON_POISON_PLUS_PLUS(ItemID.WEAPON_POISON_5940, 82, 190), EXTENDED_ANTIFIRE_3(ItemID.EXTENDED_ANTIFIRE3, 84, 82.5f), EXTENDED_ANTIFIRE_4(ItemID.EXTENDED_ANTIFIRE4, 84, 110), + ANCIENT_BREW_4(ItemID.ANCIENT_BREW4, 85, 190), DIVINE_BASTION_POTION_4(ItemID.DIVINE_BASTION_POTION4, 86, 2), DIVINE_BATTLEMAGE_POTION_4(ItemID.DIVINE_BATTLEMAGE_POTION4, 86, 2), ANTIVENOM_3(ItemID.ANTIVENOM3, 87, 90), From 46545bdecfb5f2145d734f1317fac0dfeb034f23 Mon Sep 17 00:00:00 2001 From: Hydrox6 Date: Sun, 9 Jan 2022 01:42:58 +0000 Subject: [PATCH 30/51] dps counter: add nex --- .../net/runelite/client/plugins/dpscounter/DpsCounterPlugin.java | 1 + 1 file changed, 1 insertion(+) diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/dpscounter/DpsCounterPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/dpscounter/DpsCounterPlugin.java index 54887b7223..6af1e5d578 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/dpscounter/DpsCounterPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/dpscounter/DpsCounterPlugin.java @@ -83,6 +83,7 @@ public class DpsCounterPlugin extends Plugin KREEARRA, KREEARRA_6492, KRIL_TSUTSAROTH, KRIL_TSUTSAROTH_6495, THE_MIMIC, THE_MIMIC_8633, + NEX, NEX_11279, NEX_11280, NEX_11281, NEX_11282, THE_NIGHTMARE, THE_NIGHTMARE_9426, THE_NIGHTMARE_9427, THE_NIGHTMARE_9428, THE_NIGHTMARE_9429, THE_NIGHTMARE_9430, THE_NIGHTMARE_9431, THE_NIGHTMARE_9432, THE_NIGHTMARE_9433, OBOR, SARACHNIS, From 48a6d40418294866ca8fe84072d2291dcfa923f2 Mon Sep 17 00:00:00 2001 From: SirGirion Date: Fri, 7 Jan 2022 22:29:38 -0500 Subject: [PATCH 31/51] itemcharges: Add support for blood essence Co-authored-by: Adam --- .../plugins/itemcharges/ItemChargeConfig.java | 13 +++++++++ .../plugins/itemcharges/ItemChargePlugin.java | 28 ++++++++++++++++++ .../plugins/itemcharges/ItemChargeType.java | 3 +- .../plugins/itemcharges/ItemWithConfig.java | 3 +- .../itemcharges/ItemChargePluginTest.java | 29 +++++++++++++++++++ 5 files changed, 74 insertions(+), 2 deletions(-) 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 82af2d77d3..eb0350e0ad 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 @@ -46,6 +46,7 @@ public interface ItemChargeConfig extends Config String KEY_EXPEDITIOUS_BRACELET = "expeditiousBracelet"; String KEY_EXPLORERS_RING = "explorerRing"; String KEY_RING_OF_FORGING = "ringOfForging"; + String KEY_BLOOD_ESSENCE = "bloodEssence"; @ConfigSection( name = "Charge Settings", @@ -415,4 +416,16 @@ public interface ItemChargeConfig extends Config { return true; } + + @ConfigItem( + keyName = "showBloodEssenceCharges", + name = "Blood Essence Charges", + description = "Show Blood Essence charges", + position = 30, + section = chargesSection + ) + default boolean showBloodEssenceCharges() + { + return true; + } } 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 6dfdb7114b..5ff384a8d0 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 @@ -130,6 +130,13 @@ public class ItemChargePlugin extends Plugin "Your expeditious bracelet has (\\d{1,2}) charges? left\\." ); private static final String EXPEDITIOUS_BRACELET_BREAK_TEXT = "Your Expeditious Bracelet has crumbled to dust."; + private static final Pattern BLOOD_ESSENCE_CHECK_PATTERN = Pattern.compile( + "Your blood essence has (\\d{1,4}) charges? remaining" + ); + private static final Pattern BLOOD_ESSENCE_EXTRACT_PATTERN = Pattern.compile( + "You manage to extract power from the Blood Essence and craft (\\d{1,3}) extra runes?\\." + ); + private static final String BLOOD_ESSENCE_ACTIVATE_TEXT = "You activate the blood essence."; private static final int MAX_DODGY_CHARGES = 10; private static final int MAX_BINDING_CHARGES = 16; @@ -138,6 +145,7 @@ public class ItemChargePlugin extends Plugin private static final int MAX_AMULET_OF_CHEMISTRY_CHARGES = 5; private static final int MAX_AMULET_OF_BOUNTY_CHARGES = 10; private static final int MAX_SLAYER_BRACELET_CHARGES = 30; + private static final int MAX_BLOOD_ESSENCE_CHARGES = 1000; private int lastExplorerRingCharge = -1; @@ -227,6 +235,8 @@ public class ItemChargePlugin extends Plugin Matcher slaughterCheckMatcher = BRACELET_OF_SLAUGHTER_CHECK_PATTERN.matcher(message); Matcher expeditiousActivateMatcher = EXPEDITIOUS_BRACELET_ACTIVATE_PATTERN.matcher(message); Matcher expeditiousCheckMatcher = EXPEDITIOUS_BRACELET_CHECK_PATTERN.matcher(message); + Matcher bloodEssenceCheckMatcher = BLOOD_ESSENCE_CHECK_PATTERN.matcher(message); + Matcher bloodEssenceExtractMatcher = BLOOD_ESSENCE_EXTRACT_PATTERN.matcher(message); if (config.recoilNotification() && message.contains(RING_OF_RECOIL_BREAK_MESSAGE)) { @@ -413,6 +423,18 @@ public class ItemChargePlugin extends Plugin { updateExpeditiousBraceletCharges(Integer.parseInt(expeditiousCheckMatcher.group(1))); } + else if (bloodEssenceCheckMatcher.find()) + { + updateBloodEssenceCharges(Integer.parseInt(bloodEssenceCheckMatcher.group(1))); + } + else if (bloodEssenceExtractMatcher.find()) + { + updateBloodEssenceCharges(getItemCharges(ItemChargeConfig.KEY_BLOOD_ESSENCE) - Integer.parseInt(bloodEssenceExtractMatcher.group(1))); + } + else if (message.contains(BLOOD_ESSENCE_ACTIVATE_TEXT)) + { + updateBloodEssenceCharges(MAX_BLOOD_ESSENCE_CHARGES); + } } } @@ -540,6 +562,12 @@ public class ItemChargePlugin extends Plugin updateInfoboxes(); } + private void updateBloodEssenceCharges(final int value) + { + setItemCharges(ItemChargeConfig.KEY_BLOOD_ESSENCE, value); + updateInfoboxes(); + } + private void checkDestroyWidget() { final int currentTick = client.getTickCount(); diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/itemcharges/ItemChargeType.java b/runelite-client/src/main/java/net/runelite/client/plugins/itemcharges/ItemChargeType.java index 294a865c1f..3178fa9953 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/itemcharges/ItemChargeType.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/itemcharges/ItemChargeType.java @@ -51,7 +51,8 @@ enum ItemChargeType SACK(ItemChargeConfig::showSackCharges), RING_OF_FORGING(ItemChargeConfig::showRingOfForgingCount), POTION(ItemChargeConfig::showPotionDoseCount), - GUTHIX_REST(ItemChargeConfig::showGuthixRestDoses); + GUTHIX_REST(ItemChargeConfig::showGuthixRestDoses), + BLOOD_ESSENCE(ItemChargeConfig::showBloodEssenceCharges); private final Predicate enabled; } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/itemcharges/ItemWithConfig.java b/runelite-client/src/main/java/net/runelite/client/plugins/itemcharges/ItemWithConfig.java index ca77f40d15..581410c1f9 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/itemcharges/ItemWithConfig.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/itemcharges/ItemWithConfig.java @@ -46,7 +46,8 @@ enum ItemWithConfig AMULET_OF_BOUNTY(ItemID.AMULET_OF_BOUNTY, ItemChargeConfig.KEY_AMULET_OF_BOUNTY, ItemChargeType.AMULET_OF_BOUNTY), BRACELET_OF_SLAUGHTER(ItemID.BRACELET_OF_SLAUGHTER, ItemChargeConfig.KEY_BRACELET_OF_SLAUGHTER, ItemChargeType.BRACELET_OF_SLAUGHTER), EXPEDITIOUS_BRACELET(ItemID.EXPEDITIOUS_BRACELET, ItemChargeConfig.KEY_EXPEDITIOUS_BRACELET, ItemChargeType.EXPEDITIOUS_BRACELET), - CHRONICLE(ItemID.CHRONICLE, ItemChargeConfig.KEY_CHRONICLE, ItemChargeType.TELEPORT); + CHRONICLE(ItemID.CHRONICLE, ItemChargeConfig.KEY_CHRONICLE, ItemChargeType.TELEPORT), + BLOOD_ESSENCE(ItemID.BLOOD_ESSENCE_ACTIVE, ItemChargeConfig.KEY_BLOOD_ESSENCE, ItemChargeType.BLOOD_ESSENCE); private final int itemId; private final String configKey; diff --git a/runelite-client/src/test/java/net/runelite/client/plugins/itemcharges/ItemChargePluginTest.java b/runelite-client/src/test/java/net/runelite/client/plugins/itemcharges/ItemChargePluginTest.java index f1e9c50edd..464ec09bad 100644 --- a/runelite-client/src/test/java/net/runelite/client/plugins/itemcharges/ItemChargePluginTest.java +++ b/runelite-client/src/test/java/net/runelite/client/plugins/itemcharges/ItemChargePluginTest.java @@ -93,6 +93,10 @@ public class ItemChargePluginTest private static final String ACTIVATE_EXPEDITIOUS_BRACELET = "Your expeditious bracelet helps you progress your slayer task faster. It has 11 charges left."; private static final String BREAK_EXPEDITIOUS_BRACELET = "Your expeditious bracelet helps you progress your slayer task faster. It then crumbles to dust."; + private static final String ACTIVATE_BLOOD_ESSENCE = "You activate the blood essence."; + private static final String EXTRACT_BLOOD_ESSENCE = "You manage to extract power from the Blood Essence and craft 67 extra runes."; + private static final String CHECK_BLOOD_ESSENCE = "Your blood essence has 56 charges remaining"; + @Mock @Bind private Client client; @@ -421,4 +425,29 @@ public class ItemChargePluginTest itemChargePlugin.onChatMessage(chatMessage); verify(configManager).setRSProfileConfiguration(ItemChargeConfig.GROUP, ItemChargeConfig.KEY_EXPEDITIOUS_BRACELET, 30); } + + @Test + public void testBloodEssenceActivate() + { + ChatMessage chatMessage = new ChatMessage(null, ChatMessageType.GAMEMESSAGE, "", ACTIVATE_BLOOD_ESSENCE, "", 0); + itemChargePlugin.onChatMessage(chatMessage); + verify(configManager).setRSProfileConfiguration(ItemChargeConfig.GROUP, ItemChargeConfig.KEY_BLOOD_ESSENCE, 1000); + } + + @Test + public void testBloodEssenceExtract() + { + ChatMessage chatMessage = new ChatMessage(null, ChatMessageType.GAMEMESSAGE, "", EXTRACT_BLOOD_ESSENCE, "", 0); + when(configManager.getConfiguration(ItemChargeConfig.GROUP, ItemChargeConfig.KEY_BLOOD_ESSENCE, Integer.class)).thenReturn(1000); + itemChargePlugin.onChatMessage(chatMessage); + verify(configManager).setRSProfileConfiguration(ItemChargeConfig.GROUP, ItemChargeConfig.KEY_BLOOD_ESSENCE, 933); + } + + @Test + public void testBloodEssenceCheck() + { + ChatMessage chatMessage = new ChatMessage(null, ChatMessageType.GAMEMESSAGE, "", CHECK_BLOOD_ESSENCE, "", 0); + itemChargePlugin.onChatMessage(chatMessage); + verify(configManager).setRSProfileConfiguration(ItemChargeConfig.GROUP, ItemChargeConfig.KEY_BLOOD_ESSENCE, 56); + } } \ No newline at end of file From b3e87ee875b08ba977751d815bc54a9a23733fde Mon Sep 17 00:00:00 2001 From: geheur <41499327+geheur@users.noreply.github.com> Date: Tue, 18 Jan 2022 12:55:32 -0800 Subject: [PATCH 32/51] menu swapper: add climb-up and climb-down swaps --- .../MenuEntrySwapperConfig.java | 29 +++++++++++++++++++ .../MenuEntrySwapperPlugin.java | 3 ++ 2 files changed, 32 insertions(+) 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 98c2302fcd..82b89bea25 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 @@ -787,6 +787,35 @@ public interface MenuEntrySwapperConfig extends Config return false; } + enum StairsMode + { + CLIMB, + CLIMB_UP, + CLIMB_DOWN, + } + + @ConfigItem( + keyName = "swapStairsLeftClick", + name = "Stairs left-click", + description = "Swap this option when left-clicking stairs. Also works on ladders.", + section = objectSection + ) + default StairsMode swapStairsLeftClick() + { + return StairsMode.CLIMB; + } + + @ConfigItem( + keyName = "swapStairsShiftClick", + name = "Stairs shift-click", + description = "Swap this option when shift-clicking stairs. Also works on ladders.", + section = objectSection + ) + default StairsMode swapStairsShiftClick() + { + return StairsMode.CLIMB; + } + @ConfigItem( keyName = "swapTemporossLeave", name = "Tempoross Leave", 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 9366edb8e0..2581d95859 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 @@ -415,6 +415,9 @@ public class MenuEntrySwapperPlugin extends Plugin swap("eat", "guzzle", config::swapRockCake); swap("travel", "dive", config::swapRowboatDive); + + swap("climb", "climb-up", () -> (shiftModifier() ? config.swapStairsShiftClick() : config.swapStairsLeftClick()) == MenuEntrySwapperConfig.StairsMode.CLIMB_UP); + swap("climb", "climb-down", () -> (shiftModifier() ? config.swapStairsShiftClick() : config.swapStairsLeftClick()) == MenuEntrySwapperConfig.StairsMode.CLIMB_DOWN); } private void swap(String option, String swappedOption, Supplier enabled) From b53dc9ee8fe769f187e13668c9668838d6083592 Mon Sep 17 00:00:00 2001 From: Adam Date: Tue, 18 Jan 2022 16:58:51 -0500 Subject: [PATCH 33/51] cache: remove netty-buffer dependency --- cache/pom.xml | 5 ---- .../java/net/runelite/cache/util/Xtea.java | 28 +++++++++---------- 2 files changed, 14 insertions(+), 19 deletions(-) diff --git a/cache/pom.xml b/cache/pom.xml index 999d5a0a5c..74e2ea5128 100644 --- a/cache/pom.xml +++ b/cache/pom.xml @@ -59,11 +59,6 @@ com.google.code.gson gson - - io.netty - netty-buffer - 4.1.0.Final - org.antlr antlr4-runtime diff --git a/cache/src/main/java/net/runelite/cache/util/Xtea.java b/cache/src/main/java/net/runelite/cache/util/Xtea.java index c79dc5a511..d970979e50 100644 --- a/cache/src/main/java/net/runelite/cache/util/Xtea.java +++ b/cache/src/main/java/net/runelite/cache/util/Xtea.java @@ -24,8 +24,8 @@ */ package net.runelite.cache.util; -import io.netty.buffer.ByteBuf; -import io.netty.buffer.Unpooled; +import net.runelite.cache.io.InputStream; +import net.runelite.cache.io.OutputStream; public class Xtea { @@ -42,13 +42,13 @@ public class Xtea public byte[] encrypt(byte[] data, int len) { - ByteBuf buf = Unpooled.wrappedBuffer(data, 0, len); - ByteBuf out = Unpooled.buffer(len); + InputStream in = new InputStream(data); + OutputStream out = new OutputStream(len); int numBlocks = len / 8; for (int block = 0; block < numBlocks; ++block) { - int v0 = buf.readInt(); - int v1 = buf.readInt(); + int v0 = in.readInt(); + int v1 = in.readInt(); int sum = 0; for (int i = 0; i < ROUNDS; ++i) { @@ -59,19 +59,19 @@ public class Xtea out.writeInt(v0); out.writeInt(v1); } - out.writeBytes(buf); - return out.array(); + out.writeBytes(in.getRemaining()); + return out.flip(); } public byte[] decrypt(byte[] data, int len) { - ByteBuf buf = Unpooled.wrappedBuffer(data, 0, len); - ByteBuf out = Unpooled.buffer(len); + InputStream in = new InputStream(data); + OutputStream out = new OutputStream(len); int numBlocks = len / 8; for (int block = 0; block < numBlocks; ++block) { - int v0 = buf.readInt(); - int v1 = buf.readInt(); + int v0 = in.readInt(); + int v1 = in.readInt(); int sum = GOLDEN_RATIO * ROUNDS; for (int i = 0; i < ROUNDS; ++i) { @@ -82,7 +82,7 @@ public class Xtea out.writeInt(v0); out.writeInt(v1); } - out.writeBytes(buf); - return out.array(); + out.writeBytes(in.getRemaining()); + return out.flip(); } } From 85b15156fc25f138fe1f11db2fb5a5b96652ccca Mon Sep 17 00:00:00 2001 From: Adam Keenan Date: Tue, 18 Jan 2022 21:28:02 -0500 Subject: [PATCH 34/51] menu swapper: add group storage shift deposit swap --- .../java/net/runelite/api/widgets/WidgetID.java | 1 + .../menuentryswapper/MenuEntrySwapperPlugin.java | 4 +++- .../menuentryswapper/ShiftDepositMode.java | 15 ++++++++------- 3 files changed, 12 insertions(+), 8 deletions(-) diff --git a/runelite-api/src/main/java/net/runelite/api/widgets/WidgetID.java b/runelite-api/src/main/java/net/runelite/api/widgets/WidgetID.java index fbac727d36..ec3b04348b 100644 --- a/runelite-api/src/main/java/net/runelite/api/widgets/WidgetID.java +++ b/runelite-api/src/main/java/net/runelite/api/widgets/WidgetID.java @@ -171,6 +171,7 @@ public final class WidgetID public static final int GRAVESTONE_GROUP_ID = 672; public static final int POH_TREASURE_CHEST_INVENTORY_GROUP_ID = 674; public static final int GROUP_IRON_GROUP_ID = 726; + public static final int GROUP_STORAGE_INVENTORY_GROUP_ID = 725; public static final int GROUP_STORAGE_GROUP_ID = 724; static class WorldMap 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 2581d95859..4ba94cfd72 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 @@ -607,17 +607,19 @@ public class MenuEntrySwapperPlugin extends Plugin final boolean isDepositBoxPlayerInventory = widgetGroupId == WidgetID.DEPOSIT_BOX_GROUP_ID; final boolean isChambersOfXericStorageUnitPlayerInventory = widgetGroupId == WidgetID.CHAMBERS_OF_XERIC_STORAGE_UNIT_INVENTORY_GROUP_ID; + final boolean isGroupStoragePlayerInventory = widgetGroupId == WidgetID.GROUP_STORAGE_INVENTORY_GROUP_ID; // Swap to shift-click deposit behavior // Deposit- op 1 is the current withdraw amount 1/5/10/x for deposit box interface and chambers of xeric storage unit. // Deposit- op 2 is the current withdraw amount 1/5/10/x for bank interface if (shiftModifier() && config.bankDepositShiftClick() != ShiftDepositMode.OFF && menuEntryAdded.getType() == MenuAction.CC_OP.getId() - && menuEntryAdded.getIdentifier() == (isDepositBoxPlayerInventory || isChambersOfXericStorageUnitPlayerInventory ? 1 : 2) + && menuEntryAdded.getIdentifier() == (isDepositBoxPlayerInventory || isGroupStoragePlayerInventory || isChambersOfXericStorageUnitPlayerInventory ? 1 : 2) && (menuEntryAdded.getOption().startsWith("Deposit-") || menuEntryAdded.getOption().startsWith("Store") || menuEntryAdded.getOption().startsWith("Donate"))) { ShiftDepositMode shiftDepositMode = config.bankDepositShiftClick(); final int opId = isDepositBoxPlayerInventory ? shiftDepositMode.getIdentifierDepositBox() : isChambersOfXericStorageUnitPlayerInventory ? shiftDepositMode.getIdentifierChambersStorageUnit() + : isGroupStoragePlayerInventory ? shiftDepositMode.getIdentifierGroupStorage() : shiftDepositMode.getIdentifier(); final MenuAction action = opId >= 6 ? MenuAction.CC_OP_LOW_PRIORITY : MenuAction.CC_OP; bankModeSwap(action, opId); diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/menuentryswapper/ShiftDepositMode.java b/runelite-client/src/main/java/net/runelite/client/plugins/menuentryswapper/ShiftDepositMode.java index 6c7deb9149..1c8351f217 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/menuentryswapper/ShiftDepositMode.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/menuentryswapper/ShiftDepositMode.java @@ -31,17 +31,18 @@ import lombok.RequiredArgsConstructor; @RequiredArgsConstructor public enum ShiftDepositMode { - DEPOSIT_1("Deposit-1", 3, 2, 1), - DEPOSIT_5("Deposit-5", 4, 3, 2), - DEPOSIT_10("Deposit-10", 5, 4, 3), - DEPOSIT_X("Deposit-X", 6, 6, 5), - DEPOSIT_ALL("Deposit-All", 8, 5, 4), - EXTRA_OP("Eat/Wield/Etc.", 9, 9, 0), - OFF("Off", 0, 0, 0); + DEPOSIT_1("Deposit-1", 3, 2, 1, 1), + DEPOSIT_5("Deposit-5", 4, 3, 3, 2), + DEPOSIT_10("Deposit-10", 5, 4, 4, 3), + DEPOSIT_X("Deposit-X", 6, 6, 5, 5), + DEPOSIT_ALL("Deposit-All", 8, 5, 7, 4), + EXTRA_OP("Eat/Wield/Etc.", 9, 9, 0, 0), + OFF("Off", 0, 0, 0, 0); private final String name; private final int identifier; private final int identifierDepositBox; + private final int identifierGroupStorage; private final int identifierChambersStorageUnit; @Override From 6555643e11b05c89bc0a08639dcf2b705707e317 Mon Sep 17 00:00:00 2001 From: Max Weber Date: Tue, 18 Jan 2022 14:46:54 -0700 Subject: [PATCH 35/51] rl-api: expose ModelData & model transformation methods --- .../main/java/net/runelite/api/Client.java | 21 +++- .../src/main/java/net/runelite/api/Mesh.java | 73 ++++++++++++++ .../src/main/java/net/runelite/api/Model.java | 22 +---- .../main/java/net/runelite/api/ModelData.java | 98 +++++++++++++++++++ 4 files changed, 192 insertions(+), 22 deletions(-) create mode 100644 runelite-api/src/main/java/net/runelite/api/Mesh.java create mode 100644 runelite-api/src/main/java/net/runelite/api/ModelData.java 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 e354a3e5d6..f4b9172dd8 100644 --- a/runelite-api/src/main/java/net/runelite/api/Client.java +++ b/runelite-api/src/main/java/net/runelite/api/Client.java @@ -1074,7 +1074,26 @@ public interface Client extends GameEngine RuneLiteObject createRuneLiteObject(); /** - * Loads a model from the cache + * Loads an unlit model from the cache. The returned model shares + * data such as faces, face colors, face transparencies, and vertex points with + * other models. If you want to mutate these you MUST call the relevant {@code cloneX} + * method. + * + * @see ModelData#cloneColors() + * + * @param id the ID of the model + * @return the model or null if it is loading or nonexistent + */ + @Nullable + ModelData loadModelData(int id); + + ModelData mergeModels(ModelData[] models, int length); + ModelData mergeModels(ModelData ...models); + + /** + * Loads and lights a model from the cache + * + * This is equivalent to {@code loadModelData(id).light()} * * @param id the ID of the model * @return the model or null if it is loading or nonexistent diff --git a/runelite-api/src/main/java/net/runelite/api/Mesh.java b/runelite-api/src/main/java/net/runelite/api/Mesh.java new file mode 100644 index 0000000000..33241b4357 --- /dev/null +++ b/runelite-api/src/main/java/net/runelite/api/Mesh.java @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2022 Abex + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package net.runelite.api; + +/** + * A {@link Model} or {@link ModelData} + */ +public interface Mesh> +{ + int getVerticesCount(); + int[] getVerticesX(); + int[] getVerticesY(); + int[] getVerticesZ(); + + int getFaceCount(); + int[] getFaceIndices1(); + int[] getFaceIndices2(); + int[] getFaceIndices3(); + byte[] getFaceTransparencies(); + short[] getFaceTextures(); + + /** + * Rotates this model 90 degrees around the vertical axis. + * {@link ModelData#cloneVertices()} should be called before calling this method + */ + T rotateY90Ccw(); + + /** + * Rotates this model 180 degrees around the vertical axis. + * {@link ModelData#cloneVertices()} should be called before calling this method + */ + T rotateY180Ccw(); + + /** + * Rotates this model 270 degrees around the vertical axis. + * {@link ModelData#cloneVertices()} should be called before calling this method + */ + T rotateY270Ccw(); + + /** + * Offsets this model by the passed amount (1/128ths of a tile). + * {@link ModelData#cloneVertices()} should be called before calling this method + */ + T translate(int x, int y, int z); + + /** + * Resizes this model by the passed amount (1/128ths). + * {@link ModelData#cloneVertices()} should be called before calling this method + */ + T scale(int x, int y, int z); +} diff --git a/runelite-api/src/main/java/net/runelite/api/Model.java b/runelite-api/src/main/java/net/runelite/api/Model.java index 03045dac2c..1316d31055 100644 --- a/runelite-api/src/main/java/net/runelite/api/Model.java +++ b/runelite-api/src/main/java/net/runelite/api/Model.java @@ -27,32 +27,14 @@ package net.runelite.api; /** * Represents the model of an object. */ -public interface Model extends Renderable +public interface Model extends Mesh, Renderable { - int getVerticesCount(); - - int[] getVerticesX(); - - int[] getVerticesY(); - - int[] getVerticesZ(); - - int getFaceCount(); - - int[] getFaceIndices1(); - - int[] getFaceIndices2(); - - int[] getFaceIndices3(); - int[] getFaceColors1(); int[] getFaceColors2(); int[] getFaceColors3(); - byte[] getFaceTransparencies(); - int getSceneId(); void setSceneId(int sceneId); @@ -70,8 +52,6 @@ public interface Model extends Renderable int getRadius(); - short[] getFaceTextures(); - float[] getFaceTextureUVCoordinates(); void calculateExtreme(int orientation); diff --git a/runelite-api/src/main/java/net/runelite/api/ModelData.java b/runelite-api/src/main/java/net/runelite/api/ModelData.java new file mode 100644 index 0000000000..f98da89ca8 --- /dev/null +++ b/runelite-api/src/main/java/net/runelite/api/ModelData.java @@ -0,0 +1,98 @@ +/* + * Copyright (c) 2022 Abex + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package net.runelite.api; + +/** + * An unlit model + */ +public interface ModelData extends Mesh, Renderable +{ + int DEFAULT_AMBIENT = 64; + int DEFAULT_CONTRAST = 768; + int DEFAULT_X = -50; + int DEFAULT_Y = -10; + int DEFAULT_Z = -50; + + /** + * Gets colors as Jagex HSL + * + * @see JagexColor + */ + short[] getFaceColors(); + + /** + * Lights a model. + * + * The produced model shares verticies, face transparencies, face indicies, and textures with + * the underlying ModelData. If any of these may be mutated the corresponding {@code cloneX} + * method should be called before {@code light}ing + */ + Model light(int ambient, int contrast, int x, int y, int z); + + /** + * Lights a model with default values + * + * @see #light(int, int, int, int, int) + */ + Model light(); + + /** + * Applies a recolor using Jagex's HSL format. You should call {@link #cloneColors()} ()} before calling + * this method + */ + ModelData recolor(short colorToReplace, short colorToReplaceWith); + + /** + * Applies a retexture, changing texture ids. You should call {@link #cloneTextures()} before calling + * this method + */ + ModelData retexture(short find, short replace); + + /** + * Shallow-copies a model. Does not copy any arrays, which are still shared with this object. + */ + ModelData shallowCopy(); + + /** + * Clones {@link #getVerticesX()}, {@link #getVerticesY()}, and {@link #getVerticesZ()} so + * they can be safely mutated + */ + ModelData cloneVertices(); + + /** + * Clones {@link #getFaceColors()} so they can be safely mutated + */ + ModelData cloneColors(); + + /** + * Clones {@link #getFaceTextures()} so they can be safely mutated + */ + ModelData cloneTextures(); + + /** + * Clones {@link #getFaceTransparencies()} so they can be safely mutated + */ + ModelData cloneTransparencies(); +} From f1fb26eb3d1cd52087cbdcbddf4fe0877f3c3cdf Mon Sep 17 00:00:00 2001 From: Max Weber Date: Tue, 18 Jan 2022 16:30:06 -0700 Subject: [PATCH 36/51] rl-api: expose cache getters --- runelite-api/src/main/java/net/runelite/api/Client.java | 5 +++++ .../src/main/java/net/runelite/api/IndexDataBase.java | 2 ++ 2 files changed, 7 insertions(+) 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 f4b9172dd8..acdd728a99 100644 --- a/runelite-api/src/main/java/net/runelite/api/Client.java +++ b/runelite-api/src/main/java/net/runelite/api/Client.java @@ -420,6 +420,11 @@ public interface Client extends GameEngine */ IndexDataBase getIndexConfig(); + /** + * Gets an index by id + */ + IndexDataBase getIndex(int id); + /** * Returns the x-axis base coordinate. *

diff --git a/runelite-api/src/main/java/net/runelite/api/IndexDataBase.java b/runelite-api/src/main/java/net/runelite/api/IndexDataBase.java index ba8042c480..5bb100e244 100644 --- a/runelite-api/src/main/java/net/runelite/api/IndexDataBase.java +++ b/runelite-api/src/main/java/net/runelite/api/IndexDataBase.java @@ -40,4 +40,6 @@ public interface IndexDataBase * @return */ int[] getFileIds(int archiveId); + + byte[] loadData(int archiveID, int fileID); } From 25cc99e4fc3d93e99302b514ca620f953ffd7424 Mon Sep 17 00:00:00 2001 From: RuneLite Cache-Code Autoupdater Date: Tue, 18 Jan 2022 09:35:56 -0700 Subject: [PATCH 37/51] Update Scripts to 2022-1-19 --- .../src/main/scripts/FakeXpDrop.hash | 2 +- .../src/main/scripts/FakeXpDrop.rs2asm | 299 ++++++++---------- 2 files changed, 133 insertions(+), 168 deletions(-) diff --git a/runelite-client/src/main/scripts/FakeXpDrop.hash b/runelite-client/src/main/scripts/FakeXpDrop.hash index 9eba813f20..f39e7684ca 100644 --- a/runelite-client/src/main/scripts/FakeXpDrop.hash +++ b/runelite-client/src/main/scripts/FakeXpDrop.hash @@ -1 +1 @@ -C85469C2529D794C523505679F14AA20E988513E8FBAF249E41F4760382B4BBB \ No newline at end of file +49856301491D162091426F3F788EA13FDBE3E5BE758471537F5E7AB7A588066B \ No newline at end of file diff --git a/runelite-client/src/main/scripts/FakeXpDrop.rs2asm b/runelite-client/src/main/scripts/FakeXpDrop.rs2asm index 0f5b817d85..c0040afc32 100644 --- a/runelite-client/src/main/scripts/FakeXpDrop.rs2asm +++ b/runelite-client/src/main/scripts/FakeXpDrop.rs2asm @@ -12,259 +12,224 @@ iconst 105 iconst 83 iconst 681 - get_varc_int 207 - coordx + get_varc_int 953 enum iload 0 - if_icmpeq LABEL9 - jump LABEL16 -LABEL9: - get_varc_int 207 - iconst 0 - iconst 0 + if_icmpeq LABEL8 + jump LABEL13 +LABEL8: + get_varc_int 960 iload 1 - movecoord - set_varc_int 207 - jump LABEL227 -LABEL16: + add + set_varc_int 960 + jump LABEL192 +LABEL13: iconst 105 iconst 83 iconst 681 - get_varc_int 208 - coordx + get_varc_int 954 enum iload 0 - if_icmpeq LABEL25 - jump LABEL32 -LABEL25: - get_varc_int 208 - iconst 0 - iconst 0 + if_icmpeq LABEL21 + jump LABEL26 +LABEL21: + get_varc_int 961 iload 1 - movecoord - set_varc_int 208 - jump LABEL227 -LABEL32: + add + set_varc_int 961 + jump LABEL192 +LABEL26: iconst 105 iconst 83 iconst 681 - get_varc_int 209 - coordx + get_varc_int 955 enum iload 0 - if_icmpeq LABEL41 - jump LABEL48 -LABEL41: - get_varc_int 209 - iconst 0 - iconst 0 + if_icmpeq LABEL34 + jump LABEL39 +LABEL34: + get_varc_int 962 iload 1 - movecoord - set_varc_int 209 - jump LABEL227 -LABEL48: + add + set_varc_int 962 + jump LABEL192 +LABEL39: iconst 105 iconst 83 iconst 681 - get_varc_int 210 - coordx + get_varc_int 956 enum iload 0 - if_icmpeq LABEL57 - jump LABEL64 -LABEL57: - get_varc_int 210 - iconst 0 - iconst 0 + if_icmpeq LABEL47 + jump LABEL52 +LABEL47: + get_varc_int 963 iload 1 - movecoord - set_varc_int 210 - jump LABEL227 -LABEL64: + add + set_varc_int 963 + jump LABEL192 +LABEL52: iconst 105 iconst 83 iconst 681 - get_varc_int 211 - coordx + get_varc_int 957 + enum + iload 0 + if_icmpeq LABEL60 + jump LABEL65 +LABEL60: + get_varc_int 964 + iload 1 + add + set_varc_int 964 + jump LABEL192 +LABEL65: + iconst 105 + iconst 83 + iconst 681 + get_varc_int 958 enum iload 0 if_icmpeq LABEL73 - jump LABEL80 + jump LABEL78 LABEL73: - get_varc_int 211 - iconst 0 - iconst 0 + get_varc_int 965 iload 1 - movecoord - set_varc_int 211 - jump LABEL227 -LABEL80: + add + set_varc_int 965 + jump LABEL192 +LABEL78: iconst 105 iconst 83 iconst 681 - get_varc_int 212 - coordx + get_varc_int 959 enum iload 0 - if_icmpeq LABEL89 - jump LABEL96 -LABEL89: - get_varc_int 212 - iconst 0 - iconst 0 + if_icmpeq LABEL86 + jump LABEL91 +LABEL86: + get_varc_int 966 iload 1 - movecoord - set_varc_int 212 - jump LABEL227 -LABEL96: - iconst 105 - iconst 83 - iconst 681 - get_varc_int 213 - coordx - enum - iload 0 - if_icmpeq LABEL105 - jump LABEL112 -LABEL105: - get_varc_int 213 - iconst 0 - iconst 0 - iload 1 - movecoord - set_varc_int 213 - jump LABEL227 -LABEL112: + add + set_varc_int 966 + jump LABEL192 +LABEL91: iload 0 iconst 3 - if_icmpeq LABEL116 - jump LABEL123 -LABEL116: + if_icmpeq LABEL95 + jump LABEL102 +LABEL95: iload 1 iconst 20000001 - if_icmpeq LABEL120 - jump LABEL123 -LABEL120: - iconst 269500481 - set_varc_int 207 - jump LABEL227 -LABEL123: - get_varc_int 207 + if_icmpeq LABEL99 + jump LABEL102 +LABEL99: + iconst -10 + set_varc_int 960 + jump LABEL192 +LABEL102: + get_varc_int 953 iconst -1 - if_icmpeq LABEL127 - jump LABEL138 -LABEL127: - iconst 0 + if_icmpeq LABEL106 + jump LABEL115 +LABEL106: iconst 83 iconst 105 iconst 81 iload 0 enum - iconst 0 + set_varc_int 953 iload 1 - movecoord - set_varc_int 207 - jump LABEL227 -LABEL138: - get_varc_int 208 + set_varc_int 960 + jump LABEL192 +LABEL115: + get_varc_int 954 iconst -1 - if_icmpeq LABEL142 - jump LABEL153 -LABEL142: - iconst 0 + if_icmpeq LABEL119 + jump LABEL128 +LABEL119: iconst 83 iconst 105 iconst 81 iload 0 enum - iconst 0 + set_varc_int 954 iload 1 - movecoord - set_varc_int 208 - jump LABEL227 -LABEL153: - get_varc_int 209 + set_varc_int 961 + jump LABEL192 +LABEL128: + get_varc_int 955 iconst -1 - if_icmpeq LABEL157 - jump LABEL168 -LABEL157: - iconst 0 + if_icmpeq LABEL132 + jump LABEL141 +LABEL132: iconst 83 iconst 105 iconst 81 iload 0 enum - iconst 0 + set_varc_int 955 iload 1 - movecoord - set_varc_int 209 - jump LABEL227 -LABEL168: - get_varc_int 210 + set_varc_int 962 + jump LABEL192 +LABEL141: + get_varc_int 956 iconst -1 - if_icmpeq LABEL172 - jump LABEL183 -LABEL172: - iconst 0 + if_icmpeq LABEL145 + jump LABEL154 +LABEL145: iconst 83 iconst 105 iconst 81 iload 0 enum - iconst 0 + set_varc_int 956 iload 1 - movecoord - set_varc_int 210 - jump LABEL227 -LABEL183: - get_varc_int 211 + set_varc_int 963 + jump LABEL192 +LABEL154: + get_varc_int 957 iconst -1 - if_icmpeq LABEL187 - jump LABEL198 -LABEL187: - iconst 0 + if_icmpeq LABEL158 + jump LABEL167 +LABEL158: iconst 83 iconst 105 iconst 81 iload 0 enum - iconst 0 + set_varc_int 957 iload 1 - movecoord - set_varc_int 211 - jump LABEL227 -LABEL198: - get_varc_int 212 + set_varc_int 964 + jump LABEL192 +LABEL167: + get_varc_int 958 iconst -1 - if_icmpeq LABEL202 - jump LABEL213 -LABEL202: - iconst 0 + if_icmpeq LABEL171 + jump LABEL180 +LABEL171: iconst 83 iconst 105 iconst 81 iload 0 enum - iconst 0 + set_varc_int 958 iload 1 - movecoord - set_varc_int 212 - jump LABEL227 -LABEL213: - get_varc_int 213 + set_varc_int 965 + jump LABEL192 +LABEL180: + get_varc_int 959 iconst -1 - if_icmpeq LABEL217 - jump LABEL227 -LABEL217: - iconst 0 + if_icmpeq LABEL184 + jump LABEL192 +LABEL184: iconst 83 iconst 105 iconst 81 iload 0 enum - iconst 0 + set_varc_int 959 iload 1 - movecoord - set_varc_int 213 -LABEL227: + set_varc_int 966 +LABEL192: return From 694fff9bf0f9bb2e53c7d06bee2c5f6efa8d3641 Mon Sep 17 00:00:00 2001 From: RuneLite Cache-Code Autoupdater Date: Tue, 18 Jan 2022 09:35:56 -0700 Subject: [PATCH 38/51] Update Item IDs to 2022-1-19 --- .../main/java/net/runelite/api/ItemID.java | 64 +++++++++++ .../java/net/runelite/api/NullItemID.java | 103 ++++++++++++++++++ 2 files changed, 167 insertions(+) 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 45e0f6ae2f..da1a5d901d 100644 --- a/runelite-api/src/main/java/net/runelite/api/ItemID.java +++ b/runelite-api/src/main/java/net/runelite/api/ItemID.java @@ -12284,5 +12284,69 @@ public final class ItemID public static final int BLOOD_ESSENCE = 26390; public static final int BLOOD_ESSENCE_ACTIVE = 26392; public static final int BANDOSIAN_COMPONENTS = 26394; + public static final int CABBAGE_26417 = 26417; + public static final int CABBAGE_26419 = 26419; + public static final int SHATTERED_RELICS_VARIETY_ORNAMENT_KIT = 26421; + public static final int SHATTERED_BANNER = 26424; + public static final int SHATTERED_HOOD_T1 = 26427; + public static final int SHATTERED_TOP_T1 = 26430; + public static final int SHATTERED_TROUSERS_T1 = 26433; + public static final int SHATTERED_BOOTS_T1 = 26436; + public static final int SHATTERED_HOOD_T2 = 26439; + public static final int SHATTERED_TOP_T2 = 26442; + public static final int SHATTERED_TROUSERS_T2 = 26445; + public static final int SHATTERED_BOOTS_T2 = 26448; + public static final int SHATTERED_HOOD_T3 = 26451; + public static final int SHATTERED_TOP_T3 = 26454; + public static final int SHATTERED_TROUSERS_T3 = 26457; + public static final int SHATTERED_BOOTS_T3 = 26460; + public static final int VOID_KNIGHT_TOP_OR = 26463; + public static final int VOID_KNIGHT_ROBE_OR = 26465; + public static final int VOID_KNIGHT_GLOVES_OR = 26467; + public static final int ELITE_VOID_TOP_OR = 26469; + public static final int ELITE_VOID_ROBE_OR = 26471; + public static final int VOID_MAGE_HELM_OR = 26473; + public static final int VOID_RANGER_HELM_OR = 26475; + public static final int VOID_MELEE_HELM_OR = 26477; + public static final int SHATTERED_RELICS_VOID_ORNAMENT_KIT = 26479; + public static final int ABYSSAL_WHIP_OR = 26482; + public static final int ABYSSAL_TENTACLE_OR = 26484; + public static final int RUNE_CROSSBOW_OR = 26486; + public static final int BOOK_OF_BALANCE_OR = 26488; + public static final int BOOK_OF_DARKNESS_OR = 26490; + public static final int BOOK_OF_LAW_OR = 26492; + public static final int BOOK_OF_WAR_OR = 26494; + public static final int HOLY_BOOK_OR = 26496; + public static final int UNHOLY_BOOK_OR = 26498; + public static final int SHATTERED_TELEPORT_SCROLL = 26500; + public static final int SHATTERED_RELICS_BRONZE_TROPHY = 26503; + public static final int SHATTERED_RELICS_IRON_TROPHY = 26505; + public static final int SHATTERED_RELICS_STEEL_TROPHY = 26507; + public static final int SHATTERED_RELICS_MITHRIL_TROPHY = 26509; + public static final int SHATTERED_RELICS_ADAMANT_TROPHY = 26511; + public static final int SHATTERED_RELICS_RUNE_TROPHY = 26513; + public static final int SHATTERED_RELICS_DRAGON_TROPHY = 26515; + public static final int SHATTERED_CANE = 26517; + public static final int CANNON_BASE_OR = 26520; + public static final int CANNON_STAND_OR = 26522; + public static final int CANNON_BARRELS_OR = 26524; + public static final int CANNON_FURNACE_OR = 26526; + public static final int SHATTERED_CANNON_ORNAMENT_KIT = 26528; + public static final int MYSTIC_HAT_OR = 26531; + public static final int MYSTIC_ROBE_TOP_OR = 26533; + public static final int MYSTIC_ROBE_BOTTOM_OR = 26535; + public static final int MYSTIC_GLOVES_OR = 26537; + public static final int MYSTIC_BOOTS_OR = 26539; + public static final int SHATTERED_RELICS_MYSTIC_ORNAMENT_KIT = 26541; + public static final int UNIDENTIFIED_FRAGMENT_HARVESTING = 26544; + public static final int UNIDENTIFIED_FRAGMENT_PRODUCTION = 26545; + public static final int UNIDENTIFIED_FRAGMENT_SKILLING = 26546; + public static final int UNIDENTIFIED_FRAGMENT_COMBAT = 26547; + public static final int UNIDENTIFIED_FRAGMENT_MISC = 26548; + public static final int PORTABLE_WAYSTONE = 26549; + public static final int ARCANE_GRIMOIRE = 26551; + public static final int SHATTERED_RELIC_HUNTER_T1_ARMOUR_SET = 26554; + public static final int SHATTERED_RELIC_HUNTER_T2_ARMOUR_SET = 26557; + public static final int SHATTERED_RELIC_HUNTER_T3_ARMOUR_SET = 26560; /* 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 3adbbe4a12..bb4bda7a6b 100644 --- a/runelite-api/src/main/java/net/runelite/api/NullItemID.java +++ b/runelite-api/src/main/java/net/runelite/api/NullItemID.java @@ -13901,5 +13901,108 @@ public final class NullItemID public static final int NULL_26391 = 26391; public static final int NULL_26393 = 26393; public static final int NULL_26395 = 26395; + public static final int NULL_26396 = 26396; + public static final int NULL_26397 = 26397; + public static final int NULL_26398 = 26398; + public static final int NULL_26399 = 26399; + public static final int NULL_26400 = 26400; + public static final int NULL_26401 = 26401; + public static final int NULL_26402 = 26402; + public static final int NULL_26403 = 26403; + public static final int NULL_26404 = 26404; + public static final int NULL_26405 = 26405; + public static final int NULL_26406 = 26406; + public static final int NULL_26407 = 26407; + public static final int NULL_26408 = 26408; + public static final int NULL_26409 = 26409; + public static final int NULL_26410 = 26410; + public static final int NULL_26411 = 26411; + public static final int NULL_26412 = 26412; + public static final int NULL_26413 = 26413; + public static final int NULL_26414 = 26414; + public static final int NULL_26415 = 26415; + public static final int NULL_26416 = 26416; + public static final int NULL_26418 = 26418; + public static final int NULL_26420 = 26420; + public static final int NULL_26422 = 26422; + public static final int NULL_26423 = 26423; + public static final int NULL_26425 = 26425; + public static final int NULL_26426 = 26426; + public static final int NULL_26428 = 26428; + public static final int NULL_26429 = 26429; + public static final int NULL_26431 = 26431; + public static final int NULL_26432 = 26432; + public static final int NULL_26434 = 26434; + public static final int NULL_26435 = 26435; + public static final int NULL_26437 = 26437; + public static final int NULL_26438 = 26438; + public static final int NULL_26440 = 26440; + public static final int NULL_26441 = 26441; + public static final int NULL_26443 = 26443; + public static final int NULL_26444 = 26444; + public static final int NULL_26446 = 26446; + public static final int NULL_26447 = 26447; + public static final int NULL_26449 = 26449; + public static final int NULL_26450 = 26450; + public static final int NULL_26452 = 26452; + public static final int NULL_26453 = 26453; + public static final int NULL_26455 = 26455; + public static final int NULL_26456 = 26456; + public static final int NULL_26458 = 26458; + public static final int NULL_26459 = 26459; + public static final int NULL_26461 = 26461; + public static final int NULL_26462 = 26462; + public static final int NULL_26464 = 26464; + public static final int NULL_26466 = 26466; + public static final int NULL_26468 = 26468; + public static final int NULL_26470 = 26470; + public static final int NULL_26472 = 26472; + public static final int NULL_26474 = 26474; + public static final int NULL_26476 = 26476; + public static final int NULL_26478 = 26478; + public static final int NULL_26480 = 26480; + public static final int NULL_26481 = 26481; + public static final int NULL_26483 = 26483; + public static final int NULL_26485 = 26485; + public static final int NULL_26487 = 26487; + public static final int NULL_26489 = 26489; + public static final int NULL_26491 = 26491; + public static final int NULL_26493 = 26493; + public static final int NULL_26495 = 26495; + public static final int NULL_26497 = 26497; + public static final int NULL_26499 = 26499; + public static final int NULL_26501 = 26501; + public static final int NULL_26502 = 26502; + public static final int NULL_26504 = 26504; + public static final int NULL_26506 = 26506; + public static final int NULL_26508 = 26508; + public static final int NULL_26510 = 26510; + public static final int NULL_26512 = 26512; + public static final int NULL_26514 = 26514; + public static final int NULL_26516 = 26516; + public static final int NULL_26518 = 26518; + public static final int NULL_26519 = 26519; + public static final int NULL_26521 = 26521; + public static final int NULL_26523 = 26523; + public static final int NULL_26525 = 26525; + public static final int NULL_26527 = 26527; + public static final int NULL_26529 = 26529; + public static final int NULL_26530 = 26530; + public static final int NULL_26532 = 26532; + public static final int NULL_26534 = 26534; + public static final int NULL_26536 = 26536; + public static final int NULL_26538 = 26538; + public static final int NULL_26540 = 26540; + public static final int NULL_26542 = 26542; + public static final int NULL_26543 = 26543; + public static final int NULL_26550 = 26550; + public static final int NULL_26552 = 26552; + public static final int NULL_26553 = 26553; + public static final int NULL_26555 = 26555; + public static final int NULL_26556 = 26556; + public static final int NULL_26558 = 26558; + public static final int NULL_26559 = 26559; + public static final int NULL_26561 = 26561; + public static final int NULL_26562 = 26562; /* This file is automatically generated. Do not edit. */ } From 59df0792633be37dbbd85dded53285d244fcb082 Mon Sep 17 00:00:00 2001 From: RuneLite Cache-Code Autoupdater Date: Tue, 18 Jan 2022 09:35:56 -0700 Subject: [PATCH 39/51] Update Item variations to 2022-1-19 --- .../src/main/resources/item_variations.json | 125 +++++++++++++++--- 1 file changed, 109 insertions(+), 16 deletions(-) diff --git a/runelite-client/src/main/resources/item_variations.json b/runelite-client/src/main/resources/item_variations.json index 6a56701fb7..8bd791dfd0 100644 --- a/runelite-client/src/main/resources/item_variations.json +++ b/runelite-client/src/main/resources/item_variations.json @@ -3,6 +3,22 @@ 1, 4051 ], + "cannon base": [ + 6, + 26520 + ], + "cannon stand": [ + 8, + 26522 + ], + "cannon barrels": [ + 10, + 26524 + ], + "cannon furnace": [ + 12, + 26526 + ], "excalibur": [ 35, 8280 @@ -2483,7 +2499,9 @@ 24971, 24973, 24994, - 24996 + 24996, + 26417, + 26419 ], "empty cup": [ 1980, @@ -3297,6 +3315,18 @@ 12609, 12611 ], + "holy book": [ + 3840, + 26496 + ], + "unholy book": [ + 3842, + 26498 + ], + "book of balance": [ + 3844, + 26488 + ], "games necklace": [ 3853, 3855, @@ -3499,34 +3529,39 @@ 4099, 4109, 20562, - 23047 + 23047, + 26531 ], "mystic robe top": [ 4091, 4101, 4111, 20425, - 23050 + 23050, + 26533 ], "mystic robe bottom": [ 4093, 4103, 4113, 20426, - 23053 + 23053, + 26535 ], "mystic gloves": [ 4095, 4105, 4115, - 23056 + 23056, + 26537 ], "mystic boots": [ 4097, 4107, 4117, 20579, - 23059 + 23059, + 26539 ], "crawling hand": [ 4133, @@ -3542,7 +3577,8 @@ 4178, 12773, 12774, - 20405 + 20405, + 26482 ], "granite maul": [ 4153, @@ -6124,12 +6160,14 @@ "void knight top": [ 8839, 20465, - 24177 + 24177, + 26463 ], "void knight robe": [ 8840, 20469, - 24179 + 24179, + 26465 ], "void knight mace": [ 8841, @@ -6139,7 +6177,8 @@ "void knight gloves": [ 8842, 20475, - 24182 + 24182, + 26467 ], "bronze defender": [ 8844, @@ -6359,7 +6398,8 @@ ], "rune crossbow": [ 9185, - 23601 + 23601, + 26486 ], "jade bolts": [ 9237, @@ -7260,17 +7300,20 @@ "void mage helm": [ 11663, 20477, - 24183 + 24183, + 26473 ], "void ranger helm": [ 11664, 20479, - 24184 + 24184, + 26475 ], "void melee helm": [ 11665, 20481, - 24185 + 24185, + 26477 ], "void seal": [ 11666, @@ -7620,6 +7663,10 @@ 19720, 23654 ], + "abyssal tentacle": [ + 12006, + 26484 + ], "soft clay pack": [ 12009, 12010, @@ -7649,6 +7696,18 @@ 12692, 25256 ], + "book of war": [ + 12608, + 26494 + ], + "book of law": [ + 12610, + 26492 + ], + "book of darkness": [ + 12612, + 26490 + ], "bandos page": [ 12613, 12614, @@ -7999,12 +8058,14 @@ "elite void top": [ 13072, 20467, - 24178 + 24178, + 26469 ], "elite void robe": [ 13073, 20471, - 24180 + 24180, + 26471 ], "crystal halberd": [ 13080, @@ -10240,5 +10301,37 @@ "blood essence": [ 26390, 26392 + ], + "shattered hood": [ + 26427, + 26439, + 26451 + ], + "shattered top": [ + 26430, + 26442, + 26454 + ], + "shattered trousers": [ + 26433, + 26445, + 26457 + ], + "shattered boots": [ + 26436, + 26448, + 26460 + ], + "unidentified fragment": [ + 26544, + 26545, + 26546, + 26547, + 26548 + ], + "shattered relic hunter armour set": [ + 26554, + 26557, + 26560 ] } \ No newline at end of file From 39b6fd11813e2cdb52c82d54e5fc2986d172c193 Mon Sep 17 00:00:00 2001 From: RuneLite Cache-Code Autoupdater Date: Tue, 18 Jan 2022 09:35:56 -0700 Subject: [PATCH 40/51] Update Object IDs to 2022-1-19 --- .../java/net/runelite/api/NullObjectID.java | 74 ++++++--- .../main/java/net/runelite/api/ObjectID.java | 153 +++++++++++++----- 2 files changed, 171 insertions(+), 56 deletions(-) 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 ae2f7ee931..d65f6bb4c6 100644 --- a/runelite-api/src/main/java/net/runelite/api/NullObjectID.java +++ b/runelite-api/src/main/java/net/runelite/api/NullObjectID.java @@ -21006,18 +21006,7 @@ public final class NullObjectID public static final int NULL_42849 = 42849; public static final int NULL_42850 = 42850; public static final int NULL_42851 = 42851; - public static final int NULL_42873 = 42873; - public static final int NULL_42874 = 42874; - public static final int NULL_42875 = 42875; - public static final int NULL_42876 = 42876; - public static final int NULL_42877 = 42877; - public static final int NULL_42882 = 42882; - public static final int NULL_42883 = 42883; - public static final int NULL_42884 = 42884; - public static final int NULL_42893 = 42893; - public static final int NULL_42894 = 42894; - public static final int NULL_42896 = 42896; - public static final int NULL_42897 = 42897; + public static final int NULL_42853 = 42853; public static final int NULL_42898 = 42898; public static final int NULL_42899 = 42899; public static final int NULL_42900 = 42900; @@ -21040,12 +21029,6 @@ public final class NullObjectID public static final int NULL_42919 = 42919; public static final int NULL_42920 = 42920; public static final int NULL_42921 = 42921; - public static final int NULL_42922 = 42922; - public static final int NULL_42923 = 42923; - public static final int NULL_42924 = 42924; - public static final int NULL_42925 = 42925; - public static final int NULL_42926 = 42926; - public static final int NULL_42927 = 42927; public static final int NULL_42945 = 42945; public static final int NULL_42946 = 42946; public static final int NULL_42947 = 42947; @@ -21068,5 +21051,60 @@ public final class NullObjectID public static final int NULL_42964 = 42964; public static final int NULL_42967 = 42967; public static final int NULL_42968 = 42968; + public static final int NULL_42991 = 42991; + public static final int NULL_43000 = 43000; + public static final int NULL_43001 = 43001; + public static final int NULL_43002 = 43002; + public static final int NULL_43032 = 43032; + public static final int NULL_43033 = 43033; + public static final int NULL_43034 = 43034; + public static final int NULL_43035 = 43035; + public static final int NULL_43036 = 43036; + public static final int NULL_43037 = 43037; + public static final int NULL_43038 = 43038; + public static final int NULL_43039 = 43039; + public static final int NULL_43040 = 43040; + public static final int NULL_43041 = 43041; + public static final int NULL_43042 = 43042; + public static final int NULL_43043 = 43043; + public static final int NULL_43044 = 43044; + public static final int NULL_43045 = 43045; + public static final int NULL_43046 = 43046; + public static final int NULL_43047 = 43047; + public static final int NULL_43048 = 43048; + public static final int NULL_43049 = 43049; + public static final int NULL_43050 = 43050; + public static final int NULL_43051 = 43051; + public static final int NULL_43052 = 43052; + public static final int NULL_43053 = 43053; + public static final int NULL_43054 = 43054; + public static final int NULL_43055 = 43055; + public static final int NULL_43056 = 43056; + public static final int NULL_43057 = 43057; + public static final int NULL_43058 = 43058; + public static final int NULL_43059 = 43059; + public static final int NULL_43060 = 43060; + public static final int NULL_43061 = 43061; + public static final int NULL_43062 = 43062; + public static final int NULL_43063 = 43063; + public static final int NULL_43064 = 43064; + public static final int NULL_43065 = 43065; + public static final int NULL_43066 = 43066; + public static final int NULL_43067 = 43067; + public static final int NULL_43068 = 43068; + public static final int NULL_43069 = 43069; + public static final int NULL_43070 = 43070; + public static final int NULL_43071 = 43071; + public static final int NULL_43072 = 43072; + public static final int NULL_43073 = 43073; + public static final int NULL_43074 = 43074; + public static final int NULL_43075 = 43075; + public static final int NULL_43076 = 43076; + public static final int NULL_43077 = 43077; + public static final int NULL_43078 = 43078; + public static final int NULL_43079 = 43079; + public static final int NULL_43082 = 43082; + public static final int NULL_43083 = 43083; + public static final int NULL_43084 = 43084; /* 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 016f9487e5..36497059d5 100644 --- a/runelite-api/src/main/java/net/runelite/api/ObjectID.java +++ b/runelite-api/src/main/java/net/runelite/api/ObjectID.java @@ -21832,49 +21832,66 @@ public final class ObjectID public static final int FROZEN_DOOR = 42840; public static final int FROZEN_DOOR_42841 = 42841; public static final int GOLD_SINK_42852 = 42852; - public static final int SIGN_42853 = 42853; - public static final int SCUFFED_SNOW = 42854; - public static final int SNOWMAN = 42855; - public static final int SNOWMAN_42856 = 42856; - public static final int SNOWMAN_42857 = 42857; - public static final int SNOWMAN_42858 = 42858; - public static final int SNOWMAN_42859 = 42859; - public static final int SNOWMAN_42860 = 42860; - public static final int SNOWMAN_42861 = 42861; - public static final int SNOWMAN_42862 = 42862; - public static final int SNOWMAN_42863 = 42863; - public static final int SNOWMAN_42864 = 42864; - public static final int SPADE_42865 = 42865; - public static final int PILE_OF_SNOW = 42866; - public static final int BUSH_42867 = 42867; - public static final int PILE_OF_SNOW_42868 = 42868; - public static final int PILE_OF_SNOW_42869 = 42869; - public static final int CHRISTMAS_TREE = 42870; - public static final int CHRISTMAS_TREE_42871 = 42871; - public static final int CHRISTMAS_TREE_42872 = 42872; - public static final int PRESENTS = 42878; - public static final int PRESENTS_42879 = 42879; - public static final int PRESENTS_42880 = 42880; - public static final int PRESENTS_42881 = 42881; - public static final int POTTED_TREE = 42885; - public static final int POTTED_TREE_42886 = 42886; - public static final int MARKET_STALL_42887 = 42887; - public static final int MARKET_STALL_42888 = 42888; - public static final int MARKET_STALL_42889 = 42889; - public static final int MARKET_STALL_42890 = 42890; - public static final int MARKET_STALL_42891 = 42891; - public static final int MARKET_STALL_42892 = 42892; - public static final int ROBIN = 42895; + public static final int CHEST_42854 = 42854; + public static final int DOOR_42855 = 42855; + public static final int ANCIENT_PLAQUE = 42856; + public static final int SCOREBOARD_42857 = 42857; + public static final int CHEST_42858 = 42858; + public static final int ANCIENT_FORGE = 42859; + public static final int ANVIL_42860 = 42860; + public static final int TROPHY_PEDESTAL_42861 = 42861; + public static final int TROPHY_PEDESTAL_42862 = 42862; + public static final int TROPHY_PEDESTAL_42863 = 42863; + public static final int TROPHY_PEDESTAL_42864 = 42864; + public static final int TROPHY_PEDESTAL_42865 = 42865; + public static final int TROPHY_PEDESTAL_42866 = 42866; + public static final int TROPHY_PEDESTAL_42867 = 42867; + public static final int ORNATE_TROPHY_PEDESTAL_42868 = 42868; + public static final int ORNATE_TROPHY_PEDESTAL_42869 = 42869; + public static final int ORNATE_TROPHY_PEDESTAL_42870 = 42870; + public static final int ORNATE_TROPHY_PEDESTAL_42871 = 42871; + public static final int ORNATE_TROPHY_PEDESTAL_42872 = 42872; + public static final int ORNATE_TROPHY_PEDESTAL_42873 = 42873; + public static final int ORNATE_TROPHY_PEDESTAL_42874 = 42874; + public static final int TROPHY_PEDESTAL_42875 = 42875; + public static final int TROPHY_PEDESTAL_42876 = 42876; + public static final int TROPHY_PEDESTAL_42877 = 42877; + public static final int TROPHY_PEDESTAL_42878 = 42878; + public static final int TROPHY_PEDESTAL_42879 = 42879; + public static final int TROPHY_PEDESTAL_42880 = 42880; + public static final int TROPHY_PEDESTAL_42881 = 42881; + public static final int ORNATE_TROPHY_PEDESTAL_42882 = 42882; + public static final int ORNATE_TROPHY_PEDESTAL_42883 = 42883; + public static final int ORNATE_TROPHY_PEDESTAL_42884 = 42884; + public static final int ORNATE_TROPHY_PEDESTAL_42885 = 42885; + public static final int ORNATE_TROPHY_PEDESTAL_42886 = 42886; + public static final int ORNATE_TROPHY_PEDESTAL_42887 = 42887; + public static final int ORNATE_TROPHY_PEDESTAL_42888 = 42888; + public static final int TROPHY_PEDESTAL_42889 = 42889; + public static final int TROPHY_PEDESTAL_42890 = 42890; + public static final int TROPHY_PEDESTAL_42891 = 42891; + public static final int TROPHY_PEDESTAL_42892 = 42892; + public static final int TROPHY_PEDESTAL_42893 = 42893; + public static final int TROPHY_PEDESTAL_42894 = 42894; + public static final int TROPHY_PEDESTAL_42895 = 42895; + public static final int ORNATE_TROPHY_PEDESTAL_42896 = 42896; + public static final int ORNATE_TROPHY_PEDESTAL_42897 = 42897; public static final int DEAD_TREE_42907 = 42907; public static final int DEAD_OAK_42908 = 42908; - public static final int SANTAS_SLEIGH = 42928; - public static final int SANTAS_THRONE = 42929; - public static final int SANTAS_SACK = 42930; + public static final int ORNATE_TROPHY_PEDESTAL_42922 = 42922; + public static final int ORNATE_TROPHY_PEDESTAL_42923 = 42923; + public static final int ORNATE_TROPHY_PEDESTAL_42924 = 42924; + public static final int ORNATE_TROPHY_PEDESTAL_42925 = 42925; + public static final int ORNATE_TROPHY_PEDESTAL_42926 = 42926; + public static final int BANNER_STAND_42927 = 42927; + public static final int ORNATE_BANNER_STAND_42928 = 42928; + public static final int OAK_OUTFIT_STAND_42929 = 42929; + public static final int OAK_OUTFIT_STAND_42930 = 42930; public static final int FROZEN_DOOR_42931 = 42931; public static final int FROZEN_DOOR_42932 = 42932; public static final int DOOR_42933 = 42933; public static final int DOOR_42934 = 42934; - public static final int ANCIENT_PLAQUE = 42935; + public static final int ANCIENT_PLAQUE_42935 = 42935; public static final int SCOREBOARD_42936 = 42936; public static final int ANCIENT_BARRIER = 42937; public static final int ANCIENT_BARRIER_42938 = 42938; @@ -21885,7 +21902,67 @@ public final class ObjectID public static final int STALAGMITE_42943 = 42943; public static final int STALAGMITE_42944 = 42944; public static final int ALTAR_42965 = 42965; - public static final int ANCIENT_FORGE = 42966; + public static final int ANCIENT_FORGE_42966 = 42966; public static final int BROKEN_CROSSBOW_42969 = 42969; + public static final int OAK_OUTFIT_STAND_42970 = 42970; + public static final int MAHOGANY_OUTFIT_STAND_42971 = 42971; + public static final int MAHOGANY_OUTFIT_STAND_42972 = 42972; + public static final int MAHOGANY_OUTFIT_STAND_42973 = 42973; + public static final int LOCK_42974 = 42974; + public static final int LOCK_42975 = 42975; + public static final int LOCK_42976 = 42976; + public static final int LOCK_42977 = 42977; + public static final int LOCK_42978 = 42978; + public static final int LOCK_42979 = 42979; + public static final int LOCK_42980 = 42980; + public static final int LOCK_42981 = 42981; + public static final int LOCK_42982 = 42982; + public static final int LOCK_42983 = 42983; + public static final int LOCK_42984 = 42984; + public static final int LOCK_42985 = 42985; + public static final int LOCK_42986 = 42986; + public static final int LOCK_42987 = 42987; + public static final int REPLACE_ME = 42988; + public static final int REPLACE_ME_42989 = 42989; + public static final int REPLACE_ME_42990 = 42990; + public static final int RUNESTONE_BASALT = 42992; + public static final int RUNESTONE_BASALT_42993 = 42993; + public static final int RUNESTONE_BASALT_42994 = 42994; + public static final int RUNESTONE_BASALT_42995 = 42995; + public static final int RUNESTONE_BASALT_42996 = 42996; + public static final int RUNESTONE_BASALT_42997 = 42997; + public static final int RUNESTONE_BASALT_42998 = 42998; + public static final int BOAT_42999 = 42999; + public static final int LUMBRIDGE_WAYSTONE = 43003; + public static final int LUMBRIDGE_WAYSTONE_43004 = 43004; + public static final int FALADOR_WAYSTONE = 43005; + public static final int FALADOR_WAYSTONE_43006 = 43006; + public static final int VARROCK_WAYSTONE = 43007; + public static final int VARROCK_WAYSTONE_43008 = 43008; + public static final int AL_KHARID_WAYSTONE = 43009; + public static final int AL_KHARID_WAYSTONE_43010 = 43010; + public static final int CATHERBY_WAYSTONE = 43011; + public static final int CATHERBY_WAYSTONE_43012 = 43012; + public static final int ARDOUGNE_WAYSTONE = 43013; + public static final int ARDOUGNE_WAYSTONE_43014 = 43014; + public static final int BRIMHAVEN_WAYSTONE = 43015; + public static final int BRIMHAVEN_WAYSTONE_43016 = 43016; + public static final int RELLEKKA_WAYSTONE = 43017; + public static final int RELLEKKA_WAYSTONE_43018 = 43018; + public static final int FEROX_ENCLAVE_WAYSTONE = 43019; + public static final int FEROX_ENCLAVE_WAYSTONE_43020 = 43020; + public static final int CANIFIS_WAYSTONE = 43021; + public static final int CANIFIS_WAYSTONE_43022 = 43022; + public static final int PRIFDDINAS_WAYSTONE = 43023; + public static final int PRIFDDINAS_WAYSTONE_43024 = 43024; + public static final int KOUREND_WAYSTONE = 43025; + public static final int KOUREND_WAYSTONE_43026 = 43026; + public static final int DWARF_MULTICANNON_43027 = 43027; + public static final int BROKEN_MULTICANNON_43028 = 43028; + public static final int CANNON_BASE_43029 = 43029; + public static final int CANNON_STAND_43030 = 43030; + public static final int CANNON_BARRELS_43031 = 43031; + public static final int RUNESTONE_BASALT_43080 = 43080; + public static final int RUNESTONE_BASALT_43081 = 43081; /* This file is automatically generated. Do not edit. */ } From 08cc8caa708d7f50e65a4acb1db8631893dd3cdf Mon Sep 17 00:00:00 2001 From: RuneLite Cache-Code Autoupdater Date: Tue, 18 Jan 2022 09:35:56 -0700 Subject: [PATCH 41/51] Update NPC IDs to 2022-1-19 --- .../src/main/java/net/runelite/api/NpcID.java | 29 +++---------------- .../main/java/net/runelite/api/NullNpcID.java | 17 ++--------- 2 files changed, 6 insertions(+), 40 deletions(-) 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 cd8c383e63..cfd04862de 100644 --- a/runelite-api/src/main/java/net/runelite/api/NpcID.java +++ b/runelite-api/src/main/java/net/runelite/api/NpcID.java @@ -9477,31 +9477,9 @@ public final class NpcID public static final int REGENT = 11229; public static final int GROUP_STORAGE_TUTOR = 11230; public static final int GROUP_IRON_TUTOR = 11231; - public static final int TINY_SNOWBALL = 11232; - public static final int MINI_SNOWBALL = 11233; - public static final int LITTLE_SNOWBALL = 11234; - public static final int SMALL_SNOWBALL = 11235; - public static final int NORMAL_SNOWBALL = 11236; - public static final int BIG_SNOWBALL = 11237; - public static final int LARGE_SNOWBALL = 11238; - public static final int HUGE_SNOWBALL = 11239; - public static final int HUMONGOUS_SNOWBALL = 11240; - public static final int BUOY = 11241; - public static final int GURL = 11242; - public static final int BUOY_11243 = 11243; - public static final int GURL_11244 = 11244; - public static final int HERQUIN_11245 = 11245; - public static final int CECILIA_11247 = 11247; - public static final int LARRY_11248 = 11248; - public static final int SANTAS_THRONE = 11249; - public static final int SANTA = 11250; - public static final int WAYNE_11251 = 11251; - public static final int WYSON_THE_GARDENER_11252 = 11252; - public static final int HAIRDRESSER_11254 = 11254; - public static final int SIR_VYVIN_11255 = 11255; - public static final int XI_PLZPETDOGZ_XIX = 11259; - public static final int DRAKE_11260 = 11260; - public static final int DUCK_11261 = 11261; + public static final int THE_SAGE = 11232; + public static final int LEAGUE_TUTOR = 11233; + public static final int LEAGUES_ASSISTANT_11234 = 11234; public static final int NEXLING = 11276; public static final int NEXLING_11277 = 11277; public static final int NEX = 11278; @@ -9521,5 +9499,6 @@ public final class NpcID public static final int SPIRITUAL_MAGE_11292 = 11292; public static final int BLOOD_REAVER = 11293; public static final int BLOOD_REAVER_11294 = 11294; + public static final int GULL_11297 = 11297; /* 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 73396db288..9e9d6158d6 100644 --- a/runelite-api/src/main/java/net/runelite/api/NullNpcID.java +++ b/runelite-api/src/main/java/net/runelite/api/NullNpcID.java @@ -1738,25 +1738,12 @@ public final class NullNpcID public static final int NULL_11222 = 11222; public static final int NULL_11223 = 11223; public static final int NULL_11224 = 11224; - public static final int NULL_11246 = 11246; + public static final int NULL_11235 = 11235; + public static final int NULL_11236 = 11236; public static final int NULL_11253 = 11253; public static final int NULL_11256 = 11256; public static final int NULL_11257 = 11257; public static final int NULL_11258 = 11258; - public static final int NULL_11262 = 11262; - public static final int NULL_11263 = 11263; - public static final int NULL_11264 = 11264; - public static final int NULL_11265 = 11265; - public static final int NULL_11266 = 11266; - public static final int NULL_11267 = 11267; - public static final int NULL_11268 = 11268; - public static final int NULL_11269 = 11269; - public static final int NULL_11270 = 11270; - public static final int NULL_11271 = 11271; - public static final int NULL_11272 = 11272; - public static final int NULL_11273 = 11273; - public static final int NULL_11274 = 11274; - public static final int NULL_11275 = 11275; public static final int NULL_11295 = 11295; public static final int NULL_11296 = 11296; /* This file is automatically generated. Do not edit. */ From c7694d21adba9c86fa3a0b287e4eb72689c9429c Mon Sep 17 00:00:00 2001 From: RuneLite Cache-Code Autoupdater Date: Tue, 18 Jan 2022 09:35:56 -0700 Subject: [PATCH 42/51] Update Widget IDs to 2022-1-19 --- .../src/main/java/net/runelite/api/widgets/WidgetID.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/runelite-api/src/main/java/net/runelite/api/widgets/WidgetID.java b/runelite-api/src/main/java/net/runelite/api/widgets/WidgetID.java index ec3b04348b..74ebdc5ca5 100644 --- a/runelite-api/src/main/java/net/runelite/api/widgets/WidgetID.java +++ b/runelite-api/src/main/java/net/runelite/api/widgets/WidgetID.java @@ -759,23 +759,23 @@ public final class WidgetID static class StandardSpellBook { - static final int LUMBRIDGE_HOME_TELEPORT = 5; + static final int LUMBRIDGE_HOME_TELEPORT = 6; static final int KOUREND_HOME_TELEPORT = 4; } static class AncientSpellBook { - static final int EDGEVILLE_HOME_TELEPORT = 99; + static final int EDGEVILLE_HOME_TELEPORT = 100; } static class LunarSpellBook { - static final int LUNAR_HOME_TELEPORT = 100; + static final int LUNAR_HOME_TELEPORT = 101; } static class ArceuusSpellBook { - static final int ARCEUUS_HOME_TELEPORT = 144; + static final int ARCEUUS_HOME_TELEPORT = 145; } static class Pvp From b0a10a9c14686f4012eb30865261bbeb3d55af4b Mon Sep 17 00:00:00 2001 From: Max Weber Date: Tue, 18 Jan 2022 14:54:36 -0700 Subject: [PATCH 43/51] grounditems: Add Modern style loot beam --- .../java/net/runelite/api/AnimationID.java | 1 + .../java/net/runelite/api/JagexColor.java | 30 ++++++- .../grounditems/GroundItemsConfig.java | 11 +++ .../grounditems/GroundItemsPlugin.java | 5 +- .../client/plugins/grounditems/Lootbeam.java | 81 ++++++++++++++++--- 5 files changed, 110 insertions(+), 18 deletions(-) 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 0d4350fbcf..59c61ab497 100644 --- a/runelite-api/src/main/java/net/runelite/api/AnimationID.java +++ b/runelite-api/src/main/java/net/runelite/api/AnimationID.java @@ -205,6 +205,7 @@ public final class AnimationID public static final int LEAGUE_HOME_TELEPORT_5 = 8805; public static final int LEAGUE_HOME_TELEPORT_6 = 8807; public static final int RAID_LIGHT_ANIMATION = 3101; + public static final int LOOTBEAM_ANIMATION = 9260; public static final int CONSTRUCTION = 3676; public static final int CONSTRUCTION_IMCANDO = 8912; diff --git a/runelite-api/src/main/java/net/runelite/api/JagexColor.java b/runelite-api/src/main/java/net/runelite/api/JagexColor.java index 618ed002fa..1175f194e7 100644 --- a/runelite-api/src/main/java/net/runelite/api/JagexColor.java +++ b/runelite-api/src/main/java/net/runelite/api/JagexColor.java @@ -28,11 +28,35 @@ import java.awt.Color; public final class JagexColor { + public static final int HUE_MAX = 63; + public static final int SATURATION_MAX = 7; + public static final int LUMINANCE_MAX = 127; + public static short packHSL(int hue, int saturation, int luminance) { - return (short) ((short) (hue & 63) << 10 - | (short) (saturation & 7) << 7 - | (short) (luminance & 127)); + return (short) ((short) (hue & HUE_MAX) << 10 + | (short) (saturation & SATURATION_MAX) << 7 + | (short) (luminance & LUMINANCE_MAX)); + } + + public static int unpackHue(short hsl) + { + return hsl >> 10 & HUE_MAX; + } + + public static int unpackSaturation(short hsl) + { + return hsl >> 7 & SATURATION_MAX; + } + + public static int unpackLuminance(short hsl) + { + return hsl & LUMINANCE_MAX; + } + + public static String formatHSL(short hsl) + { + return String.format("%02Xh%Xs%02Xl", unpackHue(hsl), unpackSaturation(hsl), unpackLuminance(hsl)); } public static short rgbToHSL(int rgb, double brightness) diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/grounditems/GroundItemsConfig.java b/runelite-client/src/main/java/net/runelite/client/plugins/grounditems/GroundItemsConfig.java index 2e32a8e336..5869c07208 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/grounditems/GroundItemsConfig.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/grounditems/GroundItemsConfig.java @@ -436,4 +436,15 @@ public interface GroundItemsConfig extends Config { return HighlightTier.HIGH; } + + @ConfigItem( + keyName = "lootbeamStyle", + name = "Lootbeam Style", + description = "Style of lootbeam to use", + position = 32 + ) + default Lootbeam.Style lootbeamStyle() + { + return Lootbeam.Style.MODERN; + } } 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 773fd8b044..af5282db14 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 @@ -99,7 +99,7 @@ import net.runelite.client.util.Text; @PluginDescriptor( name = "Ground Items", description = "Highlight ground items and/or show price information", - tags = {"grand", "exchange", "high", "alchemy", "prices", "highlight", "overlay"} + tags = {"grand", "exchange", "high", "alchemy", "prices", "highlight", "overlay", "lootbeam"} ) public class GroundItemsPlugin extends Plugin { @@ -791,12 +791,13 @@ public class GroundItemsPlugin extends Plugin Lootbeam lootbeam = lootbeams.get(worldPoint); if (lootbeam == null) { - lootbeam = new Lootbeam(client, clientThread, worldPoint, color); + lootbeam = new Lootbeam(client, clientThread, worldPoint, color, config.lootbeamStyle()); lootbeams.put(worldPoint, lootbeam); } else { lootbeam.setColor(color); + lootbeam.setStyle(config.lootbeamStyle()); } } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/grounditems/Lootbeam.java b/runelite-client/src/main/java/net/runelite/client/plugins/grounditems/Lootbeam.java index 9e8761a93f..96d7d34409 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/grounditems/Lootbeam.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/grounditems/Lootbeam.java @@ -24,10 +24,14 @@ */ package net.runelite.client.plugins.grounditems; +import java.util.function.Function; +import lombok.RequiredArgsConstructor; +import net.runelite.api.Animation; import net.runelite.api.AnimationID; import net.runelite.api.Client; import net.runelite.api.JagexColor; import net.runelite.api.Model; +import net.runelite.api.ModelData; import net.runelite.api.RuneLiteObject; import net.runelite.api.coords.LocalPoint; import net.runelite.api.coords.WorldPoint; @@ -36,22 +40,58 @@ import net.runelite.client.callback.ClientThread; class Lootbeam { - private static final int RAID_LIGHT_MODEL = 5809; - private static final short RAID_LIGHT_FIND_COLOR = 6371; - private final RuneLiteObject runeLiteObject; private final Client client; private final ClientThread clientThread; private Color color; + private Style style; - public Lootbeam(Client client, ClientThread clientThread, WorldPoint worldPoint, Color color) + @RequiredArgsConstructor + public enum Style + { + LIGHT(l -> l.client.loadModel( + 5809, + new short[]{6371}, + new short[]{JagexColor.rgbToHSL(l.color.getRGB(), 1.0d)} + ), anim(AnimationID.RAID_LIGHT_ANIMATION)), + MODERN(l -> + { + ModelData md = l.client.loadModelData(43330); + if (md == null) + { + return null; + } + + short hsl = JagexColor.rgbToHSL(l.color.getRGB(), 1.0d); + int hue = JagexColor.unpackHue(hsl); + int sat = Math.min(JagexColor.unpackSaturation(hsl) + 1, JagexColor.SATURATION_MAX); + int lum = JagexColor.unpackLuminance(hsl); + + return md.cloneColors() + .recolor((short) 26432, JagexColor.packHSL(hue, sat, Math.min(lum + 12, JagexColor.LUMINANCE_MAX))) + .recolor((short) 26584, JagexColor.packHSL(hue, sat - 1, Math.max(lum - 12, 0))) + .light(75, 1875, ModelData.DEFAULT_X, ModelData.DEFAULT_Y, ModelData.DEFAULT_Z); + }, anim(AnimationID.LOOTBEAM_ANIMATION)), + ; + + private final Function modelSupplier; + private final Function animationSupplier; + } + + private static Function anim(int id) + { + return b -> b.client.loadAnimation(id); + } + + public Lootbeam(Client client, ClientThread clientThread, WorldPoint worldPoint, Color color, Style style) { this.client = client; this.clientThread = clientThread; runeLiteObject = client.createRuneLiteObject(); - setColor(color); - runeLiteObject.setAnimation(client.loadAnimation(AnimationID.RAID_LIGHT_ANIMATION)); + this.color = color; + this.style = style; + update(); runeLiteObject.setShouldLoop(true); LocalPoint lp = LocalPoint.fromWorld(client, worldPoint); @@ -68,19 +108,34 @@ class Lootbeam } this.color = color; + update(); + } + + public void setStyle(Style style) + { + if (this.style == style) + { + return; + } + + this.style = style; + update(); + } + + private void update() + { clientThread.invoke(() -> { - Model m = client.loadModel( - RAID_LIGHT_MODEL, - new short[]{RAID_LIGHT_FIND_COLOR}, - new short[]{JagexColor.rgbToHSL(color.getRGB(), 1.0d)} - ); - if (m == null) + Model model = style.modelSupplier.apply(this); + if (model == null) { return false; } - runeLiteObject.setModel(m); + Animation anim = style.animationSupplier.apply(this); + + runeLiteObject.setAnimation(anim); + runeLiteObject.setModel(model); return true; }); } From 80e98abd51015ec752e267c8b7c05aa1d879ea21 Mon Sep 17 00:00:00 2001 From: Runelite auto updater Date: Wed, 19 Jan 2022 12:31:20 +0000 Subject: [PATCH 44/51] Release 1.8.10 --- cache-client/pom.xml | 2 +- cache-updater/pom.xml | 2 +- cache/pom.xml | 2 +- pom.xml | 4 ++-- runelite-api/pom.xml | 2 +- runelite-client/pom.xml | 2 +- runelite-jshell/pom.xml | 2 +- runelite-script-assembler-plugin/pom.xml | 2 +- 8 files changed, 9 insertions(+), 9 deletions(-) diff --git a/cache-client/pom.xml b/cache-client/pom.xml index a1316deb29..7b3caf5e7b 100644 --- a/cache-client/pom.xml +++ b/cache-client/pom.xml @@ -29,7 +29,7 @@ net.runelite runelite-parent - 1.8.10-SNAPSHOT + 1.8.10 cache-client diff --git a/cache-updater/pom.xml b/cache-updater/pom.xml index 0d9dd92647..0bc5d81c4f 100644 --- a/cache-updater/pom.xml +++ b/cache-updater/pom.xml @@ -28,7 +28,7 @@ net.runelite runelite-parent - 1.8.10-SNAPSHOT + 1.8.10 Cache Updater diff --git a/cache/pom.xml b/cache/pom.xml index 74e2ea5128..bcf61e77ef 100644 --- a/cache/pom.xml +++ b/cache/pom.xml @@ -29,7 +29,7 @@ net.runelite runelite-parent - 1.8.10-SNAPSHOT + 1.8.10 cache diff --git a/pom.xml b/pom.xml index 0bd2938b26..60253e9909 100644 --- a/pom.xml +++ b/pom.xml @@ -28,7 +28,7 @@ net.runelite runelite-parent - 1.8.10-SNAPSHOT + 1.8.10 pom RuneLite @@ -63,7 +63,7 @@ https://github.com/runelite/runelite scm:git:git://github.com/runelite/runelite scm:git:git@github.com:runelite/runelite - HEAD + runelite-parent-1.8.10 diff --git a/runelite-api/pom.xml b/runelite-api/pom.xml index 3a6481dfca..a8538ef719 100644 --- a/runelite-api/pom.xml +++ b/runelite-api/pom.xml @@ -29,7 +29,7 @@ net.runelite runelite-parent - 1.8.10-SNAPSHOT + 1.8.10 runelite-api diff --git a/runelite-client/pom.xml b/runelite-client/pom.xml index f4fd5bd7ea..49b1fdcf03 100644 --- a/runelite-client/pom.xml +++ b/runelite-client/pom.xml @@ -29,7 +29,7 @@ net.runelite runelite-parent - 1.8.10-SNAPSHOT + 1.8.10 client diff --git a/runelite-jshell/pom.xml b/runelite-jshell/pom.xml index e502e4ac61..9bc7c85b4a 100644 --- a/runelite-jshell/pom.xml +++ b/runelite-jshell/pom.xml @@ -30,7 +30,7 @@ net.runelite runelite-parent - 1.8.10-SNAPSHOT + 1.8.10 jshell diff --git a/runelite-script-assembler-plugin/pom.xml b/runelite-script-assembler-plugin/pom.xml index 232d065b8b..08cf1a22eb 100644 --- a/runelite-script-assembler-plugin/pom.xml +++ b/runelite-script-assembler-plugin/pom.xml @@ -29,7 +29,7 @@ net.runelite runelite-parent - 1.8.10-SNAPSHOT + 1.8.10 script-assembler-plugin From 86b15a31bb695d2d1a250863520665595739fb06 Mon Sep 17 00:00:00 2001 From: Runelite auto updater Date: Wed, 19 Jan 2022 12:31:24 +0000 Subject: [PATCH 45/51] Bump for 1.8.11-SNAPSHOT --- cache-client/pom.xml | 2 +- cache-updater/pom.xml | 2 +- cache/pom.xml | 2 +- pom.xml | 4 ++-- runelite-api/pom.xml | 2 +- runelite-client/pom.xml | 2 +- runelite-jshell/pom.xml | 2 +- runelite-script-assembler-plugin/pom.xml | 2 +- 8 files changed, 9 insertions(+), 9 deletions(-) diff --git a/cache-client/pom.xml b/cache-client/pom.xml index 7b3caf5e7b..0bb84581f7 100644 --- a/cache-client/pom.xml +++ b/cache-client/pom.xml @@ -29,7 +29,7 @@ net.runelite runelite-parent - 1.8.10 + 1.8.11-SNAPSHOT cache-client diff --git a/cache-updater/pom.xml b/cache-updater/pom.xml index 0bc5d81c4f..546de93683 100644 --- a/cache-updater/pom.xml +++ b/cache-updater/pom.xml @@ -28,7 +28,7 @@ net.runelite runelite-parent - 1.8.10 + 1.8.11-SNAPSHOT Cache Updater diff --git a/cache/pom.xml b/cache/pom.xml index bcf61e77ef..2c40ed225f 100644 --- a/cache/pom.xml +++ b/cache/pom.xml @@ -29,7 +29,7 @@ net.runelite runelite-parent - 1.8.10 + 1.8.11-SNAPSHOT cache diff --git a/pom.xml b/pom.xml index 60253e9909..21b6a8570f 100644 --- a/pom.xml +++ b/pom.xml @@ -28,7 +28,7 @@ net.runelite runelite-parent - 1.8.10 + 1.8.11-SNAPSHOT pom RuneLite @@ -63,7 +63,7 @@ https://github.com/runelite/runelite scm:git:git://github.com/runelite/runelite scm:git:git@github.com:runelite/runelite - runelite-parent-1.8.10 + HEAD diff --git a/runelite-api/pom.xml b/runelite-api/pom.xml index a8538ef719..5c263c72f3 100644 --- a/runelite-api/pom.xml +++ b/runelite-api/pom.xml @@ -29,7 +29,7 @@ net.runelite runelite-parent - 1.8.10 + 1.8.11-SNAPSHOT runelite-api diff --git a/runelite-client/pom.xml b/runelite-client/pom.xml index 49b1fdcf03..591955b1e2 100644 --- a/runelite-client/pom.xml +++ b/runelite-client/pom.xml @@ -29,7 +29,7 @@ net.runelite runelite-parent - 1.8.10 + 1.8.11-SNAPSHOT client diff --git a/runelite-jshell/pom.xml b/runelite-jshell/pom.xml index 9bc7c85b4a..353e2ec271 100644 --- a/runelite-jshell/pom.xml +++ b/runelite-jshell/pom.xml @@ -30,7 +30,7 @@ net.runelite runelite-parent - 1.8.10 + 1.8.11-SNAPSHOT jshell diff --git a/runelite-script-assembler-plugin/pom.xml b/runelite-script-assembler-plugin/pom.xml index 08cf1a22eb..3f3edaeeea 100644 --- a/runelite-script-assembler-plugin/pom.xml +++ b/runelite-script-assembler-plugin/pom.xml @@ -29,7 +29,7 @@ net.runelite runelite-parent - 1.8.10 + 1.8.11-SNAPSHOT script-assembler-plugin From adf224c0ccea9452b2a09a8dd4df259003bc7446 Mon Sep 17 00:00:00 2001 From: Sundar-Gandu <86447677+Sundar-Gandu@users.noreply.github.com> Date: Wed, 19 Jan 2022 11:56:11 -0500 Subject: [PATCH 46/51] update spell widget ids --- .../net/runelite/api/widgets/WidgetID.java | 368 +++++++++--------- 1 file changed, 184 insertions(+), 184 deletions(-) diff --git a/runelite-api/src/main/java/net/runelite/api/widgets/WidgetID.java b/runelite-api/src/main/java/net/runelite/api/widgets/WidgetID.java index 1114c99147..fc17cee9b3 100644 --- a/runelite-api/src/main/java/net/runelite/api/widgets/WidgetID.java +++ b/runelite-api/src/main/java/net/runelite/api/widgets/WidgetID.java @@ -1093,198 +1093,198 @@ public final class WidgetID static class SpellBook { static final int FILTERED_SPELLS_BOUNDS = 3; - static final int TOOLTIP = 189; + static final int TOOLTIP = 190; // NORMAL SPELLS - static final int LUMBRIDGE_HOME_TELEPORT = 5; - static final int WIND_STRIKE = 6; - static final int CONFUSE = 7; - static final int ENCHANT_CROSSBOW_BOLT = 8; - static final int WATER_STRIKE = 9; - static final int LVL_1_ENCHANT = 10; - static final int EARTH_STRIKE = 11; - static final int WEAKEN = 12; - static final int FIRE_STRIKE = 13; - static final int BONES_TO_BANANAS = 14; - static final int WIND_BOLT = 15; - static final int CURSE = 16; - static final int BIND = 17; - static final int LOW_LEVEL_ALCHEMY = 18; - static final int WATER_BOLT = 19; - static final int VARROCK_TELEPORT = 20; - static final int LVL_2_ENCHANT = 21; - static final int EARTH_BOLT = 22; - static final int LUMBRIDGE_TELEPORT = 23; - static final int TELEKINETIC_GRAB = 24; - static final int FIRE_BOLT = 25; - static final int FALADOR_TELEPORT = 26; - static final int CRUMBLE_UNDEAD = 27; - static final int TELEPORT_TO_HOUSE = 28; - static final int WIND_BLAST = 29; - static final int SUPERHEAT_ITEM = 30; - static final int CAMELOT_TELEPORT = 31; - static final int WATER_BLAST = 32; - static final int LVL_3_ENCHANT = 33; - static final int IBAN_BLAST = 34; - static final int SNARE = 35; - static final int MAGIC_DART = 36; - static final int ARDOUGNE_TELEPORT = 37; - static final int EARTH_BLAST = 38; - static final int HIGH_LEVEL_ALCHEMY = 39; - static final int CHARGE_WATER_ORB = 40; - static final int LVL_4_ENCHANT = 41; - static final int WATCHTOWER_TELEPORT = 42; - static final int FIRE_BLAST = 43; - static final int CHARGE_EARTH_ORB = 44; - static final int BONES_TO_PEACHES = 45; - static final int SARADOMIN_STRIKE = 46; - static final int CLAWS_OF_GUTHIX = 47; - static final int FLAMES_OF_ZAMORAK = 48; - static final int TROLLHEIM_TELEPORT = 49; - static final int WIND_WAVE = 50; - static final int CHARGE_FIRE_ORB = 51; - static final int TELEPORT_TO_APE_ATOLL = 52; - static final int WATER_WAVE = 53; - static final int CHARGE_AIR_ORB = 54; - static final int VULNERABILITY = 55; - static final int LVL_5_ENCHANT = 56; - static final int TELEPORT_TO_KOUREND = 57; - static final int EARTH_WAVE = 58; - static final int ENFEEBLE = 59; - static final int TELEOTHER_LUMBRIDGE = 60; - static final int FIRE_WAVE = 61; - static final int ENTANGLE = 62; - static final int STUN = 63; - static final int CHARGE = 64; - static final int WIND_SURGE = 65; - static final int TELEOTHER_FALADOR = 66; - static final int WATER_SURGE = 67; - static final int TELE_BLOCK = 68; - static final int BOUNTY_TARGET_TELEPORT = 69; - static final int LVL_6_ENCHANT = 70; - static final int TELEOTHER_CAMELOT = 71; - static final int EARTH_SURGE = 72; - static final int LVL_7_ENCHANT = 73; - static final int FIRE_SURGE = 74; + static final int LUMBRIDGE_HOME_TELEPORT = 6; + static final int WIND_STRIKE = 7; + static final int CONFUSE = 8; + static final int ENCHANT_CROSSBOW_BOLT = 9; + static final int WATER_STRIKE = 10; + static final int LVL_1_ENCHANT = 11; + static final int EARTH_STRIKE = 12; + static final int WEAKEN = 13; + static final int FIRE_STRIKE = 14; + static final int BONES_TO_BANANAS = 15; + static final int WIND_BOLT = 16; + static final int CURSE = 17; + static final int BIND = 18; + static final int LOW_LEVEL_ALCHEMY = 19; + static final int WATER_BOLT = 20; + static final int VARROCK_TELEPORT = 21; + static final int LVL_2_ENCHANT = 22; + static final int EARTH_BOLT = 23; + static final int LUMBRIDGE_TELEPORT = 24; + static final int TELEKINETIC_GRAB = 25; + static final int FIRE_BOLT = 26; + static final int FALADOR_TELEPORT = 27; + static final int CRUMBLE_UNDEAD = 28; + static final int TELEPORT_TO_HOUSE = 29; + static final int WIND_BLAST = 30; + static final int SUPERHEAT_ITEM = 31; + static final int CAMELOT_TELEPORT = 32; + static final int WATER_BLAST = 33; + static final int LVL_3_ENCHANT = 34; + static final int IBAN_BLAST = 35; + static final int SNARE = 36; + static final int MAGIC_DART = 37; + static final int ARDOUGNE_TELEPORT = 38; + static final int EARTH_BLAST = 39; + static final int HIGH_LEVEL_ALCHEMY = 40; + static final int CHARGE_WATER_ORB = 41; + static final int LVL_4_ENCHANT = 42; + static final int WATCHTOWER_TELEPORT = 43; + static final int FIRE_BLAST = 44; + static final int CHARGE_EARTH_ORB = 45; + static final int BONES_TO_PEACHES = 46; + static final int SARADOMIN_STRIKE = 47; + static final int CLAWS_OF_GUTHIX = 48; + static final int FLAMES_OF_ZAMORAK = 49; + static final int TROLLHEIM_TELEPORT = 50; + static final int WIND_WAVE = 51; + static final int CHARGE_FIRE_ORB = 52; + static final int TELEPORT_TO_APE_ATOLL = 53; + static final int WATER_WAVE = 54; + static final int CHARGE_AIR_ORB = 55; + static final int VULNERABILITY = 56; + static final int LVL_5_ENCHANT = 57; + static final int TELEPORT_TO_KOUREND = 58; + static final int EARTH_WAVE = 59; + static final int ENFEEBLE = 60; + static final int TELEOTHER_LUMBRIDGE = 61; + static final int FIRE_WAVE = 62; + static final int ENTANGLE = 63; + static final int STUN = 64; + static final int CHARGE = 65; + static final int WIND_SURGE = 66; + static final int TELEOTHER_FALADOR = 67; + static final int WATER_SURGE = 68; + static final int TELE_BLOCK = 69; + static final int BOUNTY_TARGET_TELEPORT = 70; + static final int LVL_6_ENCHANT = 71; + static final int TELEOTHER_CAMELOT = 72; + static final int EARTH_SURGE = 73; + static final int LVL_7_ENCHANT = 74; + static final int FIRE_SURGE = 75; // ANCIENT SPELLS - static final int ICE_RUSH = 75; - static final int ICE_BLITZ = 76; - static final int ICE_BURST = 77; - static final int ICE_BARRAGE = 78; - static final int BLOOD_RUSH = 79; - static final int BLOOD_BLITZ = 80; - static final int BLOOD_BURST = 81; - static final int BLOOD_BARRAGE = 82; - static final int SMOKE_RUSH = 83; - static final int SMOKE_BLITZ = 84; - static final int SMOKE_BURST = 85; - static final int SMOKE_BARRAGE = 86; - static final int SHADOW_RUSH = 87; - static final int SHADOW_BLITZ = 88; - static final int SHADOW_BURST = 89; - static final int SHADOW_BARRAGE = 90; - static final int PADDEWWA_TELEPORT = 91; - static final int SENNTISTEN_TELEPORT = 92; - static final int KHARYRLL_TELEPORT = 93; - static final int LASSAR_TELEPORT = 94; - static final int DAREEYAK_TELEPORT = 95; - static final int CARRALLANGER_TELEPORT = 96; - static final int ANNAKARL_TELEPORT = 97; - static final int GHORROCK_TELEPORT = 98; - static final int EDGEVILLE_HOME_TELEPORT = 99; + static final int ICE_RUSH = 76; + static final int ICE_BLITZ = 77; + static final int ICE_BURST = 78; + static final int ICE_BARRAGE = 79; + static final int BLOOD_RUSH = 80; + static final int BLOOD_BLITZ = 81; + static final int BLOOD_BURST = 82; + static final int BLOOD_BARRAGE = 83; + static final int SMOKE_RUSH = 84; + static final int SMOKE_BLITZ = 85; + static final int SMOKE_BURST = 86; + static final int SMOKE_BARRAGE = 87; + static final int SHADOW_RUSH = 88; + static final int SHADOW_BLITZ = 89; + static final int SHADOW_BURST = 90; + static final int SHADOW_BARRAGE = 91; + static final int PADDEWWA_TELEPORT = 92; + static final int SENNTISTEN_TELEPORT = 93; + static final int KHARYRLL_TELEPORT = 94; + static final int LASSAR_TELEPORT = 95; + static final int DAREEYAK_TELEPORT = 96; + static final int CARRALLANGER_TELEPORT = 97; + static final int ANNAKARL_TELEPORT = 98; + static final int GHORROCK_TELEPORT = 99; + static final int EDGEVILLE_HOME_TELEPORT = 100; // LUNAR SPELLS - static final int LUNAR_HOME_TELEPORT = 100; - static final int BAKE_PIE = 101; - static final int CURE_PLANT = 102; - static final int MONSTER_EXAMINE = 103; - static final int NPC_CONTACT = 104; - static final int CURE_OTHER = 105; - static final int HUMIDIFY = 106; - static final int MOONCLAN_TELEPORT = 107; - static final int TELE_GROUP_MOONCLAN = 108; - static final int CURE_ME = 109; - static final int HUNTER_KIT = 110; - static final int WATERBIRTH_TELEPORT = 111; - static final int TELE_GROUP_WATERBIRTH = 112; - static final int CURE_GROUP = 113; - static final int STAT_SPY = 114; - static final int BARBARIAN_TELEPORT = 115; - static final int TELE_GROUP_BARBARIAN = 116; - static final int SUPERGLASS_MAKE = 117; - static final int TAN_LEATHER = 118; - static final int KHAZARD_TELEPORT = 119; - static final int TELE_GROUP_KHAZARD = 120; - static final int DREAM = 121; - static final int STRING_JEWELLERY = 122; - static final int STAT_RESTORE_POT_SHARE = 123; - static final int MAGIC_IMBUE = 124; - static final int FERTILE_SOIL = 125; - static final int BOOST_POTION_SHARE = 126; - static final int FISHING_GUILD_TELEPORT = 127; - static final int TELE_GROUP_FISHING_GUILD = 128; - static final int PLANK_MAKE = 129; - static final int CATHERBY_TELEPORT = 130; - static final int TELE_GROUP_CATHERBY = 131; - static final int RECHARGE_DRAGONSTONE = 132; - static final int ICE_PLATEAU_TELEPORT = 133; - static final int TELE_GROUP_ICE_PLATEAU = 134; - static final int ENERGY_TRANSFER = 135; - static final int HEAL_OTHER = 136; - static final int VENGEANCE_OTHER = 137; - static final int VENGEANCE = 138; - static final int HEAL_GROUP = 139; - static final int SPELLBOOK_SWAP = 140; - static final int GEOMANCY = 141; - static final int SPIN_FLAX = 142; - static final int OURANIA_TELEPORT = 143; + static final int LUNAR_HOME_TELEPORT = 101; + static final int BAKE_PIE = 102; + static final int CURE_PLANT = 103; + static final int MONSTER_EXAMINE = 104; + static final int NPC_CONTACT = 105; + static final int CURE_OTHER = 106; + static final int HUMIDIFY = 107; + static final int MOONCLAN_TELEPORT = 108; + static final int TELE_GROUP_MOONCLAN = 109; + static final int CURE_ME = 110; + static final int HUNTER_KIT = 111; + static final int WATERBIRTH_TELEPORT = 112; + static final int TELE_GROUP_WATERBIRTH = 113; + static final int CURE_GROUP = 114; + static final int STAT_SPY = 115; + static final int BARBARIAN_TELEPORT = 116; + static final int TELE_GROUP_BARBARIAN = 117; + static final int SUPERGLASS_MAKE = 118; + static final int TAN_LEATHER = 119; + static final int KHAZARD_TELEPORT = 120; + static final int TELE_GROUP_KHAZARD = 121; + static final int DREAM = 122; + static final int STRING_JEWELLERY = 123; + static final int STAT_RESTORE_POT_SHARE = 124; + static final int MAGIC_IMBUE = 125; + static final int FERTILE_SOIL = 126; + static final int BOOST_POTION_SHARE = 127; + static final int FISHING_GUILD_TELEPORT = 128; + static final int TELE_GROUP_FISHING_GUILD = 129; + static final int PLANK_MAKE = 130; + static final int CATHERBY_TELEPORT = 131; + static final int TELE_GROUP_CATHERBY = 132; + static final int RECHARGE_DRAGONSTONE = 133; + static final int ICE_PLATEAU_TELEPORT = 134; + static final int TELE_GROUP_ICE_PLATEAU = 135; + static final int ENERGY_TRANSFER = 136; + static final int HEAL_OTHER = 137; + static final int VENGEANCE_OTHER = 138; + static final int VENGEANCE = 139; + static final int HEAL_GROUP = 140; + static final int SPELLBOOK_SWAP = 141; + static final int GEOMANCY = 142; + static final int SPIN_FLAX = 143; + static final int OURANIA_TELEPORT = 144; // ARCEUUS SPELLS - static final int ARCEUUS_HOME_TELEPORT = 144; - static final int BASIC_REANIMATION = 145; - static final int ARCEUUS_LIBRARY_TELEPORT = 146; - static final int ADEPT_REANIMATION = 147; - static final int EXPERT_REANIMATION = 148; - static final int MASTER_REANIMATION = 149; - static final int DRAYNOR_MANOR_TELEPORT = 150; - static final int MIND_ALTAR_TELEPORT = 152; - static final int RESPAWN_TELEPORT = 153; - static final int SALVE_GRAVEYARD_TELEPORT = 154; - static final int FENKENSTRAINS_CASTLE_TELEPORT = 155; - static final int WEST_ARDOUGNE_TELEPORT = 156; - static final int HARMONY_ISLAND_TELEPORT = 157; - static final int CEMETERY_TELEPORT = 158; - static final int RESURRECT_CROPS = 159; - static final int BARROWS_TELEPORT = 160; - static final int APE_ATOLL_TELEPORT = 161; - static final int BATTLEFRONT_TELEPORT = 162; - static final int INFERIOR_DEMONBANE = 163; - static final int SUPERIOR_DEMONBANE = 164; - static final int DARK_DEMONBANE = 165; - static final int MARK_OF_DARKNESS = 166; - static final int GHOSTLY_GRASP = 167; - static final int SKELETAL_GRASP = 168; - static final int UNDEAD_GRASP = 169; - static final int WARD_OF_ARCEUUS = 170; - static final int LESSER_CORRUPTION = 171; - static final int GREATER_CORRUPTION = 172; - static final int DEMONIC_OFFERING = 173; - static final int SINISTER_OFFERING = 174; - static final int DEGRIME = 175; - static final int SHADOW_VEIL = 176; - static final int VILE_VIGOUR = 177; - static final int DARK_LURE = 178; - static final int DEATH_CHARGE = 179; - static final int RESURRECT_LESSER_GHOST = 180; - static final int RESURRECT_LESSER_SKELETON = 181; - static final int RESURRECT_LESSER_ZOMBIE = 182; - static final int RESURRECT_SUPERIOR_GHOST = 183; - static final int RESURRECT_SUPERIOR_SKELETON = 184; - static final int RESURRECT_SUPERIOR_ZOMBIE = 185; - static final int RESURRECT_GREATER_GHOST = 186; - static final int RESURRECT_GREATER_SKELETON = 187; - static final int RESURRECT_GREATER_ZOMBIE = 188; + static final int ARCEUUS_HOME_TELEPORT = 145; + static final int BASIC_REANIMATION = 146; + static final int ARCEUUS_LIBRARY_TELEPORT = 147; + static final int ADEPT_REANIMATION = 148; + static final int EXPERT_REANIMATION = 149; + static final int MASTER_REANIMATION = 150; + static final int DRAYNOR_MANOR_TELEPORT = 152; + static final int MIND_ALTAR_TELEPORT = 153; + static final int RESPAWN_TELEPORT = 154; + static final int SALVE_GRAVEYARD_TELEPORT = 155; + static final int FENKENSTRAINS_CASTLE_TELEPORT = 156; + static final int WEST_ARDOUGNE_TELEPORT = 157; + static final int HARMONY_ISLAND_TELEPORT = 158; + static final int CEMETERY_TELEPORT = 159; + static final int RESURRECT_CROPS = 160; + static final int BARROWS_TELEPORT = 161; + static final int APE_ATOLL_TELEPORT = 162; + static final int BATTLEFRONT_TELEPORT = 163; + static final int INFERIOR_DEMONBANE = 164; + static final int SUPERIOR_DEMONBANE = 165; + static final int DARK_DEMONBANE = 166; + static final int MARK_OF_DARKNESS = 167; + static final int GHOSTLY_GRASP = 168; + static final int SKELETAL_GRASP = 169; + static final int UNDEAD_GRASP = 170; + static final int WARD_OF_ARCEUUS = 171; + static final int LESSER_CORRUPTION = 172; + static final int GREATER_CORRUPTION = 173; + static final int DEMONIC_OFFERING = 174; + static final int SINISTER_OFFERING = 175; + static final int DEGRIME = 176; + static final int SHADOW_VEIL = 177; + static final int VILE_VIGOUR = 178; + static final int DARK_LURE = 179; + static final int DEATH_CHARGE = 180; + static final int RESURRECT_LESSER_GHOST = 181; + static final int RESURRECT_LESSER_SKELETON = 182; + static final int RESURRECT_LESSER_ZOMBIE = 183; + static final int RESURRECT_SUPERIOR_GHOST = 184; + static final int RESURRECT_SUPERIOR_SKELETON = 185; + static final int RESURRECT_SUPERIOR_ZOMBIE = 186; + static final int RESURRECT_GREATER_GHOST = 187; + static final int RESURRECT_GREATER_SKELETON = 188; + static final int RESURRECT_GREATER_ZOMBIE = 189; } static class DialogSprite2 From 6fc8bcbe578257203e4ecc305d1a8c2c93f34568 Mon Sep 17 00:00:00 2001 From: Sundar-Gandu <86447677+Sundar-Gandu@users.noreply.github.com> Date: Wed, 19 Jan 2022 12:24:55 -0500 Subject: [PATCH 47/51] fix draynor manor teleport id --- .../src/main/java/net/runelite/api/widgets/WidgetID.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/runelite-api/src/main/java/net/runelite/api/widgets/WidgetID.java b/runelite-api/src/main/java/net/runelite/api/widgets/WidgetID.java index fc17cee9b3..f80da8c173 100644 --- a/runelite-api/src/main/java/net/runelite/api/widgets/WidgetID.java +++ b/runelite-api/src/main/java/net/runelite/api/widgets/WidgetID.java @@ -1247,7 +1247,7 @@ public final class WidgetID static final int ADEPT_REANIMATION = 148; static final int EXPERT_REANIMATION = 149; static final int MASTER_REANIMATION = 150; - static final int DRAYNOR_MANOR_TELEPORT = 152; + static final int DRAYNOR_MANOR_TELEPORT = 151; static final int MIND_ALTAR_TELEPORT = 153; static final int RESPAWN_TELEPORT = 154; static final int SALVE_GRAVEYARD_TELEPORT = 155; From 69f1bd5cceae66a1b2682269086f0d8198761c4e Mon Sep 17 00:00:00 2001 From: Owain van Brakel Date: Wed, 19 Jan 2022 19:58:57 +0100 Subject: [PATCH 48/51] project: Mixins --- .../java/net/runelite/api/IndexDataBase.java | 2 - .../src/main/java/net/runelite/api/Model.java | 4 - .../net/runelite/mixins/RSClientMixin.java | 51 +++- .../net/runelite/mixins/RSModelDataMixin.java | 231 +++++++++++++++++- .../net/runelite/mixins/RSModelMixin.java | 45 ++++ .../mixins/RSSequenceDefinitionMixin.java | 12 +- .../runelite/rs/api/RSAbstractArchive.java | 8 +- .../java/net/runelite/rs/api/RSClient.java | 7 + .../rs/api/RSEvictingDualNodeHashTable.java | 3 + .../java/net/runelite/rs/api/RSModel.java | 12 +- .../java/net/runelite/rs/api/RSModelData.java | 56 ++++- runescape-client/src/main/java/ModelData.java | 3 +- .../src/main/java/ObjectComposition.java | 2 +- 13 files changed, 396 insertions(+), 40 deletions(-) diff --git a/runelite-api/src/main/java/net/runelite/api/IndexDataBase.java b/runelite-api/src/main/java/net/runelite/api/IndexDataBase.java index 8ffba7c9ef..2c25d61ee4 100644 --- a/runelite-api/src/main/java/net/runelite/api/IndexDataBase.java +++ b/runelite-api/src/main/java/net/runelite/api/IndexDataBase.java @@ -49,8 +49,6 @@ public interface IndexDataBase int[][] getFileIds(); - byte[] getFile(int groupId, int fileId); - int getGroupFileCount(int groupId); int[] getFileCounts(); diff --git a/runelite-api/src/main/java/net/runelite/api/Model.java b/runelite-api/src/main/java/net/runelite/api/Model.java index 0b38bcf3af..fdff0fcd11 100644 --- a/runelite-api/src/main/java/net/runelite/api/Model.java +++ b/runelite-api/src/main/java/net/runelite/api/Model.java @@ -24,10 +24,6 @@ */ package net.runelite.api; -import net.runelite.api.model.Triangle; -import net.runelite.api.model.Vertex; -import java.util.List; - /** * Represents the model of an object. */ diff --git a/runelite-mixins/src/main/java/net/runelite/mixins/RSClientMixin.java b/runelite-mixins/src/main/java/net/runelite/mixins/RSClientMixin.java index ceadb07016..646bca55bf 100644 --- a/runelite-mixins/src/main/java/net/runelite/mixins/RSClientMixin.java +++ b/runelite-mixins/src/main/java/net/runelite/mixins/RSClientMixin.java @@ -69,6 +69,7 @@ import static net.runelite.api.MenuAction.UNKNOWN; import net.runelite.api.MenuEntry; import net.runelite.api.MessageNode; import net.runelite.api.Model; +import net.runelite.api.ModelData; import net.runelite.api.NPC; import net.runelite.api.NPCComposition; import net.runelite.api.NameableContainer; @@ -145,6 +146,7 @@ import net.runelite.rs.api.RSArchive; import net.runelite.rs.api.RSChatChannel; import net.runelite.rs.api.RSClanChannel; import net.runelite.rs.api.RSClient; +import net.runelite.rs.api.RSDualNode; import net.runelite.rs.api.RSEnumComposition; import net.runelite.rs.api.RSEvictingDualNodeHashTable; import net.runelite.rs.api.RSFriendSystem; @@ -292,6 +294,9 @@ public abstract class RSClientMixin implements RSClient @Inject public long delayNanoTime; + @Inject + public RSEvictingDualNodeHashTable tmpModelDataCache = newEvictingDualNodeHashTable(16); + @Inject private List outdatedScripts = new ArrayList<>(); @@ -1054,11 +1059,11 @@ public abstract class RSClientMixin implements RSClient int targetIndex = 0; if (target instanceof NPC) { - targetIndex = ((NPC)target).getIndex() + 1; + targetIndex = ((NPC) target).getIndex() + 1; } else if (target instanceof Player) { - targetIndex = -(((Player)target).getPlayerId() + 1); + targetIndex = -(((Player) target).getPlayerId() + 1); } RSProjectile projectile = client.newProjectile(id, plane, startX, startY, startZ, startCycle, endCycle, slope, startHeight, targetIndex, endHeight); @@ -2611,7 +2616,7 @@ public abstract class RSClientMixin implements RSClient { for (int i = 0; i < colorToFind.length; ++i) { - modeldata.recolor(colorToFind[i], colorToReplace[i]); + modeldata.rs$recolor(colorToFind[i], colorToReplace[i]); } } @@ -2791,5 +2796,45 @@ public abstract class RSClientMixin implements RSClient check("Widget_cachedSpriteMasks", client.getSpriteMasksCache()); check("WorldMapElement_cachedSprites", client.getSpritesCache()); } + + @Inject + @Override + public RSModelData mergeModels(ModelData[] var0, int var1) + { + return newModelData(var0, var1); + } + + @Inject + @Override + public RSModelData mergeModels(ModelData... var0) + { + return newModelData(var0, var0.length); + } + + @Inject + public IndexDataBase getIndex(int id) + { + return RSClientMixin.archives[id]; + } + + @Inject + @Override + public RSModelData loadModelData(int var0) + { + RSModelData modelData = (RSModelData) this.tmpModelDataCache.get(var0); + + if (modelData == null) + { + modelData = getModelData(RSClientMixin.archives[7], var0, 0); + if (modelData == null) + { + return null; + } + + this.tmpModelDataCache.put((RSDualNode) modelData, (long) var0); + } + + return modelData.newModelData(modelData, true, true, true, true); + } } diff --git a/runelite-mixins/src/main/java/net/runelite/mixins/RSModelDataMixin.java b/runelite-mixins/src/main/java/net/runelite/mixins/RSModelDataMixin.java index 15b1e4223f..af852eebc5 100644 --- a/runelite-mixins/src/main/java/net/runelite/mixins/RSModelDataMixin.java +++ b/runelite-mixins/src/main/java/net/runelite/mixins/RSModelDataMixin.java @@ -24,12 +24,18 @@ */ package net.runelite.mixins; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; import net.runelite.api.Model; +import net.runelite.api.ModelData; import net.runelite.api.mixins.Copy; import net.runelite.api.mixins.Inject; import net.runelite.api.mixins.Mixin; import net.runelite.api.mixins.Replace; import net.runelite.api.mixins.Shadow; +import net.runelite.api.model.Triangle; +import net.runelite.api.model.Vertex; import net.runelite.rs.api.RSClient; import net.runelite.rs.api.RSModel; import net.runelite.rs.api.RSModelData; @@ -124,13 +130,13 @@ public abstract class RSModelDataMixin implements RSModelData return; } - final int[] vertexPositionsX = getVertexX(); - final int[] vertexPositionsY = getVertexY(); - final int[] vertexPositionsZ = getVertexZ(); + final int[] vertexPositionsX = getVerticesX(); + final int[] vertexPositionsY = getVerticesY(); + final int[] vertexPositionsZ = getVerticesZ(); - final int[] trianglePointsX = getTrianglePointsX(); - final int[] trianglePointsY = getTrianglePointsY(); - final int[] trianglePointsZ = getTrianglePointsZ(); + final int[] trianglePointsX = getFaceIndices1(); + final int[] trianglePointsY = getFaceIndices2(); + final int[] trianglePointsZ = getFaceIndices3(); final short[] texTriangleX = getTexTriangleX(); final short[] texTriangleY = getTexTriangleY(); @@ -138,7 +144,7 @@ public abstract class RSModelDataMixin implements RSModelData final byte[] textureCoords = getTextureCoords(); - int faceCount = getTriangleFaceCount(); + int faceCount = getFaceCount(); float[] faceTextureUCoordinates = new float[faceCount * 6]; for (int i = 0; i < faceCount; i++) @@ -222,4 +228,215 @@ public abstract class RSModelDataMixin implements RSModelData faceTextureUVCoordinates = faceTextureUCoordinates; } + + @Override + @Inject + public List getVertices() + { + int[] verticesX = getVerticesX(); + int[] verticesY = getVerticesY(); + int[] verticesZ = getVerticesZ(); + + List vertices = new ArrayList(getVerticesCount()); + + for (int i = 0; i < getVerticesCount(); ++i) + { + Vertex v = new Vertex( + verticesX[i], + verticesY[i], + verticesZ[i] + ); + vertices.add(v); + } + + return vertices; + } + + @Override + @Inject + public List getTriangles() + { + int[] trianglesX = getFaceIndices1(); + int[] trianglesY = getFaceIndices2(); + int[] trianglesZ = getFaceIndices3(); + + List vertices = getVertices(); + List triangles = new ArrayList<>(getFaceCount()); + + for (int i = 0; i < getFaceCount(); ++i) + { + int triangleX = trianglesX[i]; + int triangleY = trianglesY[i]; + int triangleZ = trianglesZ[i]; + + Triangle triangle = new Triangle( + vertices.get(triangleX), + vertices.get(triangleY), + vertices.get(triangleZ) + ); + triangles.add(triangle); + } + + return triangles; + } + + @Inject + @Override + public RSModel light() + { + return this.toModel(ModelData.DEFAULT_AMBIENT, ModelData.DEFAULT_CONTRAST, ModelData.DEFAULT_X, ModelData.DEFAULT_Y, ModelData.DEFAULT_Z); + } + + @Inject + @Override + public RSModel light(int var1, int var2, int var3, int var4, int var5) + { + return this.toModel(var1, var2, var3, var4, var5); + } + + @Inject + @Override + public RSModelData recolor(short colorToReplace, short colorToReplaceWith) + { + this.rs$recolor(colorToReplace, colorToReplaceWith); + + return this; + } + + @Inject + @Override + public RSModelData retexture(short find, short replace) + { + this.rs$retexture(find, replace); + + return this; + } + + @Inject + @Override + public RSModelData cloneVertices() + { + int[] newVericesX = Arrays.copyOf(this.getVerticesX(), this.getVerticesX().length); + int[] newVericesY = Arrays.copyOf(this.getVerticesY(), this.getVerticesX().length); + int[] newVericesZ = Arrays.copyOf(this.getVerticesZ(), this.getVerticesX().length); + + this.setVerticesX(newVericesX); + this.setVerticesY(newVericesY); + this.setVerticesZ(newVericesZ); + + return this; + } + + @Inject + @Override + public RSModelData cloneColors() + { + short[] newFaceColor = Arrays.copyOf(this.getFaceColors(), this.getFaceColors().length); + this.setFaceColors(newFaceColor); + + return this; + } + + @Inject + @Override + public RSModelData cloneTextures() + { + short[] newFaceColor = Arrays.copyOf(this.getFaceTextures(), this.getFaceTextures().length); + this.setFaceTextures(newFaceColor); + + return this; + } + + @Inject + @Override + public RSModelData cloneTransparencies() + { + byte[] newFaceColor = Arrays.copyOf(this.getFaceTransparencies(), this.getFaceTransparencies().length); + this.setFaceTransparencies(newFaceColor); + + return this; + } + + @Inject + @Override + public RSModelData rotateY90Ccw() + { + for (int var1 = 0; var1 < this.getVerticesCount(); ++var1) + { + int var2 = this.getVerticesX()[var1]; + this.getVerticesX()[var1] = this.getVerticesZ()[var1]; + this.getVerticesZ()[var1] = -var2; + } + + this.invalidate(); + + return this; + } + + @Inject + @Override + public RSModelData rotateY180Ccw() + { + for (int var1 = 0; var1 < this.getVerticesCount(); ++var1) + { + this.getVerticesX()[var1] = -this.getVerticesX()[var1]; + this.getVerticesZ()[var1] = -this.getVerticesZ()[var1]; + } + + this.invalidate(); + + return this; + } + + @Inject + @Override + public RSModelData rotateY270Ccw() + { + for (int var1 = 0; var1 < this.getVerticesCount(); ++var1) + { + int var2 = this.getVerticesZ()[var1]; + this.getVerticesZ()[var1] = this.getVerticesX()[var1]; + this.getVerticesX()[var1] = -var2; + } + + this.invalidate(); + + return this; + } + + @Inject + @Override + public RSModelData scale(int var1, int var2, int var3) + { + for (int i = 0; i < this.getVerticesCount(); ++i) + { + this.getVerticesX()[i] = this.getVerticesX()[i] * var1 / 128; + this.getVerticesY()[i] = this.getVerticesY()[i] * var2 / 128; + this.getVerticesZ()[i] = this.getVerticesZ()[i] * var3 / 128; + } + + this.invalidate(); + + return this; + } + + @Inject + @Override + public RSModelData translate(int var1, int var2, int var3) + { + for (int i = 0; i < this.getVerticesCount(); ++i) + { + int[] vertexX = this.getVerticesX(); + int[] vertexY = this.getVerticesY(); + int[] vertexZ = this.getVerticesZ(); + + vertexX[i] += var1; + vertexY[i] += var2; + vertexZ[i] += var3; + } + + this.invalidate(); + + return this; + } } \ No newline at end of file diff --git a/runelite-mixins/src/main/java/net/runelite/mixins/RSModelMixin.java b/runelite-mixins/src/main/java/net/runelite/mixins/RSModelMixin.java index c18e32c59d..ad4bdb45e2 100644 --- a/runelite-mixins/src/main/java/net/runelite/mixins/RSModelMixin.java +++ b/runelite-mixins/src/main/java/net/runelite/mixins/RSModelMixin.java @@ -196,6 +196,51 @@ public abstract class RSModelMixin implements RSModel rsModel.setFaceTextureUVCoordinates(rl$faceTextureUVCoordinates); } + @Inject + @Override + public RSModel rotateY90Ccw() + { + this.rs$rotateY90Ccw(); + + return this; + } + + @Inject + @Override + public RSModel rotateY180Ccw() + { + this.rs$rotateY180Ccw(); + + return this; + } + + @Inject + @Override + public RSModel rotateY270Ccw() + { + this.rs$rotateY270Ccw(); + + return this; + } + + @Inject + @Override + public RSModel scale(int var1, int var2, int var3) + { + this.rs$scale(var1, var2, var3); + + return this; + } + + @Inject + @Override + public RSModel translate(int var1, int var2, int var3) + { + this.rs$translate(var1, var2, var3); + + return this; + } + @Inject public void interpolateFrames(RSFrames frames, int frameId, RSFrames nextFrames, int nextFrameId, int interval, int intervalCount) { diff --git a/runelite-mixins/src/main/java/net/runelite/mixins/RSSequenceDefinitionMixin.java b/runelite-mixins/src/main/java/net/runelite/mixins/RSSequenceDefinitionMixin.java index 579835ce2d..69da68972d 100644 --- a/runelite-mixins/src/main/java/net/runelite/mixins/RSSequenceDefinitionMixin.java +++ b/runelite-mixins/src/main/java/net/runelite/mixins/RSSequenceDefinitionMixin.java @@ -125,30 +125,30 @@ public abstract class RSSequenceDefinitionMixin implements RSSequenceDefinition rotation &= 3; if (rotation == 1) { - animatedModel.rotateY270Ccw(); + animatedModel.rs$rotateY270Ccw(); } else if (rotation == 2) { - animatedModel.rotateY180Ccw(); + animatedModel.rs$rotateY180Ccw(); } else if (rotation == 3) { - animatedModel.rotateY90Ccw(); + animatedModel.rs$rotateY90Ccw(); } animatedModel.interpolateFrames(frames, frameIdx, nextFrames, nextFrameIdx, interval, getFrameLengths()[frame]); // reapply rotation after animating if (rotation == 1) { - animatedModel.rotateY90Ccw(); + animatedModel.rs$rotateY90Ccw(); } else if (rotation == 2) { - animatedModel.rotateY180Ccw(); + animatedModel.rs$rotateY180Ccw(); } else if (rotation == 3) { - animatedModel.rotateY270Ccw(); + animatedModel.rs$rotateY270Ccw(); } return animatedModel; } diff --git a/runescape-api/src/main/java/net/runelite/rs/api/RSAbstractArchive.java b/runescape-api/src/main/java/net/runelite/rs/api/RSAbstractArchive.java index 1a0c8d2b68..ac7dd9c82e 100644 --- a/runescape-api/src/main/java/net/runelite/rs/api/RSAbstractArchive.java +++ b/runescape-api/src/main/java/net/runelite/rs/api/RSAbstractArchive.java @@ -21,10 +21,6 @@ public interface RSAbstractArchive extends IndexDataBase @Override int[][] getFileIds(); - @Import("getFile") - @Override - byte[] getFile(int groupId, int fileId); - @Import("getGroupFileCount") @Override int getGroupFileCount(int groupId); @@ -32,4 +28,8 @@ public interface RSAbstractArchive extends IndexDataBase @Import("fileCounts") @Override int[] getFileCounts(); + + @Import("getFile") + @Override + byte[] loadData(int groupId, int fileId); } diff --git a/runescape-api/src/main/java/net/runelite/rs/api/RSClient.java b/runescape-api/src/main/java/net/runelite/rs/api/RSClient.java index 1e662044d5..8384c55b49 100644 --- a/runescape-api/src/main/java/net/runelite/rs/api/RSClient.java +++ b/runescape-api/src/main/java/net/runelite/rs/api/RSClient.java @@ -29,6 +29,7 @@ import java.util.Map; import net.runelite.api.AmbientSoundEffect; import net.runelite.api.Client; import net.runelite.api.Deque; +import net.runelite.api.ModelData; import net.runelite.api.SpritePixels; import net.runelite.api.World; import net.runelite.api.clan.ClanRank; @@ -1569,4 +1570,10 @@ public interface RSClient extends RSGameEngine, Client @Construct RSProjectile newProjectile(int var1, int var2, int var3, int var4, int var5, int var6, int var7, int var8, int var9, int var10, int var11); + + @Construct + RSModelData newModelData(ModelData[] var1, int var2); + + @Construct + RSEvictingDualNodeHashTable newEvictingDualNodeHashTable(int var1); } diff --git a/runescape-api/src/main/java/net/runelite/rs/api/RSEvictingDualNodeHashTable.java b/runescape-api/src/main/java/net/runelite/rs/api/RSEvictingDualNodeHashTable.java index f4bf30fbc3..56b7084799 100644 --- a/runescape-api/src/main/java/net/runelite/rs/api/RSEvictingDualNodeHashTable.java +++ b/runescape-api/src/main/java/net/runelite/rs/api/RSEvictingDualNodeHashTable.java @@ -8,6 +8,9 @@ public interface RSEvictingDualNodeHashTable extends NodeCache @Import("get") RSDualNode get(long id); + @Import("put") + void put(RSDualNode var1, long var2); + @Import("dualNode") RSDualNode getDualNode(); diff --git a/runescape-api/src/main/java/net/runelite/rs/api/RSModel.java b/runescape-api/src/main/java/net/runelite/rs/api/RSModel.java index afeacaabe9..4a4754f36b 100644 --- a/runescape-api/src/main/java/net/runelite/rs/api/RSModel.java +++ b/runescape-api/src/main/java/net/runelite/rs/api/RSModel.java @@ -110,13 +110,19 @@ public interface RSModel extends RSRenderable, Model RSModel toSharedSpotAnimModel(boolean b); @Import("rotateY90Ccw") - void rotateY90Ccw(); + void rs$rotateY90Ccw(); @Import("rotateY180") - void rotateY180Ccw(); + void rs$rotateY180Ccw(); @Import("rotateY270Ccw") - void rotateY270Ccw(); + void rs$rotateY270Ccw(); + + @Import("scale") + void rs$scale(int var1, int var2, int var3); + + @Import("offsetBy") + void rs$translate(int var1, int var2, int var3); @Import("radius") @Override diff --git a/runescape-api/src/main/java/net/runelite/rs/api/RSModelData.java b/runescape-api/src/main/java/net/runelite/rs/api/RSModelData.java index 3d8cb0e9c0..2e85e438df 100644 --- a/runescape-api/src/main/java/net/runelite/rs/api/RSModelData.java +++ b/runescape-api/src/main/java/net/runelite/rs/api/RSModelData.java @@ -1,29 +1,40 @@ package net.runelite.rs.api; +import net.runelite.api.ModelData; +import net.runelite.mapping.Construct; import net.runelite.mapping.Import; -public interface RSModelData extends RSRenderable +public interface RSModelData extends RSRenderable, ModelData { @Import("faceCount") - int getTriangleFaceCount(); + int getFaceCount(); @Import("indices1") - int[] getTrianglePointsX(); + int[] getFaceIndices1(); @Import("indices2") - int[] getTrianglePointsY(); + int[] getFaceIndices2(); @Import("indices3") - int[] getTrianglePointsZ(); + int[] getFaceIndices3(); @Import("verticesX") - int[] getVertexX(); + int[] getVerticesX(); + + @Import("verticesX") + void setVerticesX(int[] var1); @Import("verticesY") - int[] getVertexY(); + int[] getVerticesY(); + + @Import("verticesY") + void setVerticesY(int[] var1); @Import("verticesZ") - int[] getVertexZ(); + int[] getVerticesZ(); + + @Import("verticesZ") + void setVerticesZ(int[] var1); @Import("texTriangleX") short[] getTexTriangleX(); @@ -37,6 +48,21 @@ public interface RSModelData extends RSRenderable @Import("faceTextures") short[] getFaceTextures(); + @Import("faceTextures") + void setFaceTextures(short[] var1); + + @Import("faceAlphas") + byte[] getFaceTransparencies(); + + @Import("faceAlphas") + void setFaceTransparencies(byte[] var1); + + @Import("faceColors") + short[] getFaceColors(); + + @Import("faceColors") + void setFaceColors(short[] var1); + @Import("textureCoords") byte[] getTextureCoords(); @@ -53,7 +79,10 @@ public interface RSModelData extends RSRenderable RSVertexNormal[] getVertexVertices(); @Import("recolor") - void recolor(short var1, short var2); + void rs$recolor(short var1, short var2); + + @Import("retexture") + void rs$retexture(short var1, short var2); @Import("toModel") RSModel toModel(int var1, int var2, int var3, int var4, int var5); @@ -63,4 +92,13 @@ public interface RSModelData extends RSRenderable @Import("contrast") short getContrast(); + + @Import("invalidate") + void invalidate(); + + @Import("copyModelData") + RSModelData shallowCopy(); + + @Construct + RSModelData newModelData(ModelData var1, boolean var2, boolean var3, boolean var4, boolean var5); } diff --git a/runescape-client/src/main/java/ModelData.java b/runescape-client/src/main/java/ModelData.java index 0278204c71..42140520b6 100644 --- a/runescape-client/src/main/java/ModelData.java +++ b/runescape-client/src/main/java/ModelData.java @@ -1640,7 +1640,8 @@ public class ModelData extends Renderable { @ObfuscatedSignature( descriptor = "()Lge;" ) - public ModelData method3751() { + @Export("copyModelData") + public ModelData copyModelData() { ModelData var1 = new ModelData(); if (this.faceRenderTypes != null) { var1.faceRenderTypes = new byte[this.faceCount]; diff --git a/runescape-client/src/main/java/ObjectComposition.java b/runescape-client/src/main/java/ObjectComposition.java index 7ec9123cdf..f1c597c82b 100644 --- a/runescape-client/src/main/java/ObjectComposition.java +++ b/runescape-client/src/main/java/ObjectComposition.java @@ -612,7 +612,7 @@ public class ObjectComposition extends DualNode { } if (this.nonFlatShading) { - var9 = ((ModelData)var9).method3751(); + var9 = ((ModelData)var9).copyModelData(); } if (this.clipType >= 0) { From 0fbf3b733a28150b995088b669c49007a5f7d1cd Mon Sep 17 00:00:00 2001 From: Owain van Brakel Date: Thu, 20 Jan 2022 00:10:33 +0100 Subject: [PATCH 49/51] project: Bump RL version --- buildSrc/src/main/kotlin/Dependencies.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/buildSrc/src/main/kotlin/Dependencies.kt b/buildSrc/src/main/kotlin/Dependencies.kt index da3d1e75de..a70b753a6c 100644 --- a/buildSrc/src/main/kotlin/Dependencies.kt +++ b/buildSrc/src/main/kotlin/Dependencies.kt @@ -25,7 +25,7 @@ object ProjectVersions { const val launcherVersion = "2.2.0" - const val rlVersion = "1.8.9" + const val rlVersion = "1.8.10" const val openosrsVersion = "4.18.1" From a8671b6b41cca7c74d9058999e99e6d5c2633450 Mon Sep 17 00:00:00 2001 From: Owain van Brakel Date: Thu, 20 Jan 2022 00:10:47 +0100 Subject: [PATCH 50/51] project: Bump OpenOSRS version --- buildSrc/src/main/kotlin/Dependencies.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/buildSrc/src/main/kotlin/Dependencies.kt b/buildSrc/src/main/kotlin/Dependencies.kt index a70b753a6c..88070fdb18 100644 --- a/buildSrc/src/main/kotlin/Dependencies.kt +++ b/buildSrc/src/main/kotlin/Dependencies.kt @@ -27,7 +27,7 @@ object ProjectVersions { const val launcherVersion = "2.2.0" const val rlVersion = "1.8.10" - const val openosrsVersion = "4.18.1" + const val openosrsVersion = "4.19.0" const val rsversion = 202 const val cacheversion = 165 From 6a9d8d643ab54b851a7c709707b4c41846fb8bd7 Mon Sep 17 00:00:00 2001 From: Owain van Brakel Date: Thu, 20 Jan 2022 00:30:33 +0100 Subject: [PATCH 51/51] project: Update xp drop script --- .../src/main/scripts/XpDropChanged.hash | 2 +- .../src/main/scripts/XpDropChanged.rs2asm | 710 +++++++++--------- 2 files changed, 362 insertions(+), 350 deletions(-) diff --git a/runelite-client/src/main/scripts/XpDropChanged.hash b/runelite-client/src/main/scripts/XpDropChanged.hash index a1f5ae3d57..c6f00b8adc 100644 --- a/runelite-client/src/main/scripts/XpDropChanged.hash +++ b/runelite-client/src/main/scripts/XpDropChanged.hash @@ -1 +1 @@ -A4641387DC1A542BDEB6F3728D23944F968EF2FD3EA2868B5B6AAF6961D0C6E0 \ No newline at end of file +6D7631FB41674C37039A83E08EF9D82B807CC0438AC68FDF5600B3547140298C \ No newline at end of file diff --git a/runelite-client/src/main/scripts/XpDropChanged.rs2asm b/runelite-client/src/main/scripts/XpDropChanged.rs2asm index 401c12d4de..9d517beef1 100644 --- a/runelite-client/src/main/scripts/XpDropChanged.rs2asm +++ b/runelite-client/src/main/scripts/XpDropChanged.rs2asm @@ -8,7 +8,7 @@ if_icmpeq LABEL4 jump LABEL9 LABEL4: - get_varc_int 207 + get_varc_int 953 iconst -1 if_icmpeq LABEL8 jump LABEL9 @@ -30,15 +30,15 @@ LABEL9: iload 0 iconst 1 if_icmpeq LABEL25 - jump LABEL81 + jump LABEL93 LABEL25: - get_varc_int 207 + get_varc_int 953 iconst -1 if_icmpne LABEL29 - jump LABEL80 + jump LABEL92 LABEL29: - get_varc_int 207 - iconst 269500481 + get_varc_int 960 + iconst -10 if_icmpeq LABEL33 jump LABEL39 LABEL33: @@ -47,196 +47,208 @@ LABEL33: iload 8 iload 9 invoke 997 - jump LABEL65 + jump LABEL63 LABEL39: iload 35 iconst 105 iconst 83 iconst 681 - get_varc_int 207 - coordx - enum - set_array_int + get_varc_int 953 + enum + set_array_int iload 35 - get_varc_int 207 - coordy + get_varc_int 960 set_array_int 1 iload 35 - get_array_int + get_array_int iconst -1 - if_icmpne LABEL56 - jump LABEL65 -LABEL56: + if_icmpne LABEL54 + jump LABEL63 +LABEL54: iload 35 get_array_int 1 iconst 0 - if_icmpgt LABEL61 - jump LABEL65 -LABEL61: + if_icmpgt LABEL59 + jump LABEL63 +LABEL59: iload 35 iconst 1 - add + add istore 35 -LABEL65: - get_varc_int 208 - get_varc_int 209 - get_varc_int 210 - get_varc_int 211 - get_varc_int 212 - get_varc_int 213 +LABEL63: + get_varc_int 954 + get_varc_int 955 + get_varc_int 956 + get_varc_int 957 + get_varc_int 958 + get_varc_int 959 iconst -1 - set_varc_int 213 - set_varc_int 212 - set_varc_int 211 - set_varc_int 210 - set_varc_int 209 - set_varc_int 208 - set_varc_int 207 + set_varc_int 959 + set_varc_int 958 + set_varc_int 957 + set_varc_int 956 + set_varc_int 955 + set_varc_int 954 + set_varc_int 953 + get_varc_int 961 + get_varc_int 962 + get_varc_int 963 + get_varc_int 964 + get_varc_int 965 + get_varc_int 966 + iconst -1 + set_varc_int 966 + set_varc_int 965 + set_varc_int 964 + set_varc_int 963 + set_varc_int 962 + set_varc_int 961 + set_varc_int 960 jump LABEL25 -LABEL80: - jump LABEL518 -LABEL81: +LABEL92: + jump LABEL530 +LABEL93: sconst "newXpDrop" runelite_callback iconst 10 - stat_xp + stat_xp iload 25 - sub + sub istore 36 iload 36 iconst 0 - if_icmpgt LABEL90 - jump LABEL100 -LABEL90: + if_icmpgt LABEL102 + jump LABEL112 +LABEL102: iload 35 iconst 10 - set_array_int + set_array_int iload 35 iload 36 set_array_int 1 iload 35 iconst 1 - add + add istore 35 -LABEL100: +LABEL112: iconst 0 - stat_xp + stat_xp iload 11 - sub + sub istore 36 iload 36 iconst 0 - if_icmpgt LABEL109 - jump LABEL119 -LABEL109: + if_icmpgt LABEL121 + jump LABEL131 +LABEL121: iload 35 iconst 0 - set_array_int + set_array_int iload 35 iload 36 set_array_int 1 iload 35 iconst 1 - add + add istore 35 -LABEL119: +LABEL131: iconst 2 - stat_xp + stat_xp iload 12 - sub + sub istore 36 iload 36 iconst 0 - if_icmpgt LABEL128 - jump LABEL138 -LABEL128: + if_icmpgt LABEL140 + jump LABEL150 +LABEL140: iload 35 iconst 2 - set_array_int + set_array_int iload 35 iload 36 set_array_int 1 iload 35 iconst 1 - add + add istore 35 -LABEL138: +LABEL150: iconst 4 - stat_xp + stat_xp iload 13 - sub + sub istore 36 iload 36 iconst 0 - if_icmpgt LABEL147 - jump LABEL157 -LABEL147: + if_icmpgt LABEL159 + jump LABEL169 +LABEL159: iload 35 iconst 4 - set_array_int + set_array_int iload 35 iload 36 set_array_int 1 iload 35 iconst 1 - add + add istore 35 -LABEL157: +LABEL169: iconst 6 - stat_xp + stat_xp iload 14 - sub + sub istore 36 iload 36 iconst 0 - if_icmpgt LABEL166 - jump LABEL176 -LABEL166: + if_icmpgt LABEL178 + jump LABEL188 +LABEL178: iload 35 iconst 6 - set_array_int + set_array_int iload 35 iload 36 set_array_int 1 iload 35 iconst 1 - add + add istore 35 -LABEL176: +LABEL188: iconst 1 - stat_xp + stat_xp iload 15 - sub + sub istore 36 iload 36 iconst 0 - if_icmpgt LABEL185 - jump LABEL195 -LABEL185: + if_icmpgt LABEL197 + jump LABEL207 +LABEL197: iload 35 iconst 1 - set_array_int + set_array_int iload 35 iload 36 set_array_int 1 iload 35 iconst 1 - add + add istore 35 -LABEL195: +LABEL207: iconst 3 - stat_xp + stat_xp iload 16 - sub + sub istore 36 iload 36 iconst 0 if_icmpgt HP_XP_GAINED - jump LABEL214 + jump LABEL226 HP_XP_GAINED: iload 35 iconst 3 - set_array_int + set_array_int iload 35 iload 36 sconst "hpXpGained" @@ -244,345 +256,345 @@ HP_XP_GAINED: set_array_int 1 iload 35 iconst 1 - add + add istore 35 -LABEL214: +LABEL226: iconst 5 - stat_xp + stat_xp iload 17 - sub + sub istore 36 iload 36 iconst 0 - if_icmpgt LABEL223 - jump LABEL233 -LABEL223: + if_icmpgt LABEL235 + jump LABEL245 +LABEL235: iload 35 iconst 5 - set_array_int + set_array_int iload 35 iload 36 set_array_int 1 iload 35 iconst 1 - add + add istore 35 -LABEL233: +LABEL245: iconst 16 - stat_xp + stat_xp iload 18 - sub + sub istore 36 iload 36 iconst 0 - if_icmpgt LABEL242 - jump LABEL252 -LABEL242: + if_icmpgt LABEL254 + jump LABEL264 +LABEL254: iload 35 iconst 16 - set_array_int + set_array_int iload 35 iload 36 set_array_int 1 iload 35 iconst 1 - add + add istore 35 -LABEL252: +LABEL264: iconst 15 - stat_xp + stat_xp iload 19 - sub + sub istore 36 iload 36 iconst 0 - if_icmpgt LABEL261 - jump LABEL271 -LABEL261: + if_icmpgt LABEL273 + jump LABEL283 +LABEL273: iload 35 iconst 15 - set_array_int + set_array_int iload 35 iload 36 set_array_int 1 iload 35 iconst 1 - add + add istore 35 -LABEL271: +LABEL283: iconst 17 - stat_xp + stat_xp iload 20 - sub + sub istore 36 iload 36 iconst 0 - if_icmpgt LABEL280 - jump LABEL290 -LABEL280: + if_icmpgt LABEL292 + jump LABEL302 +LABEL292: iload 35 iconst 17 - set_array_int + set_array_int iload 35 iload 36 set_array_int 1 iload 35 iconst 1 - add + add istore 35 -LABEL290: +LABEL302: iconst 12 - stat_xp + stat_xp iload 21 - sub + sub istore 36 iload 36 iconst 0 - if_icmpgt LABEL299 - jump LABEL309 -LABEL299: + if_icmpgt LABEL311 + jump LABEL321 +LABEL311: iload 35 iconst 12 - set_array_int + set_array_int iload 35 iload 36 set_array_int 1 iload 35 iconst 1 - add + add istore 35 -LABEL309: +LABEL321: iconst 20 - stat_xp + stat_xp iload 22 - sub + sub istore 36 iload 36 iconst 0 - if_icmpgt LABEL318 - jump LABEL328 -LABEL318: + if_icmpgt LABEL330 + jump LABEL340 +LABEL330: iload 35 iconst 20 - set_array_int + set_array_int iload 35 iload 36 set_array_int 1 iload 35 iconst 1 - add + add istore 35 -LABEL328: +LABEL340: iconst 14 - stat_xp + stat_xp iload 23 - sub + sub istore 36 iload 36 iconst 0 - if_icmpgt LABEL337 - jump LABEL347 -LABEL337: + if_icmpgt LABEL349 + jump LABEL359 +LABEL349: iload 35 iconst 14 - set_array_int + set_array_int iload 35 iload 36 set_array_int 1 iload 35 iconst 1 - add + add istore 35 -LABEL347: +LABEL359: iconst 13 - stat_xp + stat_xp iload 24 - sub + sub istore 36 iload 36 iconst 0 - if_icmpgt LABEL356 - jump LABEL366 -LABEL356: + if_icmpgt LABEL368 + jump LABEL378 +LABEL368: iload 35 iconst 13 - set_array_int + set_array_int iload 35 iload 36 set_array_int 1 iload 35 iconst 1 - add + add istore 35 -LABEL366: +LABEL378: iconst 7 - stat_xp + stat_xp iload 26 - sub + sub istore 36 iload 36 iconst 0 - if_icmpgt LABEL375 - jump LABEL385 -LABEL375: + if_icmpgt LABEL387 + jump LABEL397 +LABEL387: iload 35 iconst 7 - set_array_int + set_array_int iload 35 iload 36 set_array_int 1 iload 35 iconst 1 - add + add istore 35 -LABEL385: +LABEL397: iconst 11 - stat_xp + stat_xp iload 27 - sub + sub istore 36 iload 36 iconst 0 - if_icmpgt LABEL394 - jump LABEL404 -LABEL394: + if_icmpgt LABEL406 + jump LABEL416 +LABEL406: iload 35 iconst 11 - set_array_int + set_array_int iload 35 iload 36 set_array_int 1 iload 35 iconst 1 - add + add istore 35 -LABEL404: +LABEL416: iconst 8 - stat_xp + stat_xp iload 28 - sub + sub istore 36 iload 36 iconst 0 - if_icmpgt LABEL413 - jump LABEL423 -LABEL413: + if_icmpgt LABEL425 + jump LABEL435 +LABEL425: iload 35 iconst 8 - set_array_int + set_array_int iload 35 iload 36 set_array_int 1 iload 35 iconst 1 - add + add istore 35 -LABEL423: +LABEL435: iconst 9 - stat_xp + stat_xp iload 29 - sub + sub istore 36 iload 36 iconst 0 - if_icmpgt LABEL432 - jump LABEL442 -LABEL432: + if_icmpgt LABEL444 + jump LABEL454 +LABEL444: iload 35 iconst 9 - set_array_int + set_array_int iload 35 iload 36 set_array_int 1 iload 35 iconst 1 - add + add istore 35 -LABEL442: +LABEL454: iconst 18 - stat_xp + stat_xp iload 30 - sub + sub istore 36 iload 36 iconst 0 - if_icmpgt LABEL451 - jump LABEL461 -LABEL451: + if_icmpgt LABEL463 + jump LABEL473 +LABEL463: iload 35 iconst 18 - set_array_int + set_array_int iload 35 iload 36 set_array_int 1 iload 35 iconst 1 - add + add istore 35 -LABEL461: +LABEL473: iconst 19 - stat_xp + stat_xp iload 31 - sub + sub istore 36 iload 36 iconst 0 - if_icmpgt LABEL470 - jump LABEL480 -LABEL470: + if_icmpgt LABEL482 + jump LABEL492 +LABEL482: iload 35 iconst 19 - set_array_int + set_array_int iload 35 iload 36 set_array_int 1 iload 35 iconst 1 - add + add istore 35 -LABEL480: +LABEL492: iconst 22 - stat_xp + stat_xp iload 32 - sub + sub istore 36 iload 36 iconst 0 - if_icmpgt LABEL489 - jump LABEL499 -LABEL489: + if_icmpgt LABEL501 + jump LABEL511 +LABEL501: iload 35 iconst 22 - set_array_int + set_array_int iload 35 iload 36 set_array_int 1 iload 35 iconst 1 - add + add istore 35 -LABEL499: +LABEL511: iconst 21 - stat_xp + stat_xp iload 33 - sub + sub istore 36 iload 36 iconst 0 - if_icmpgt LABEL508 - jump LABEL518 -LABEL508: + if_icmpgt LABEL520 + jump LABEL530 +LABEL520: iload 35 iconst 21 - set_array_int + set_array_int iload 35 iload 36 set_array_int 1 iload 35 iconst 1 - add + add istore 35 -LABEL518: +LABEL530: iconst 0 istore 37 iconst 0 @@ -609,221 +621,221 @@ LABEL518: sstore 0 iload 35 iconst 0 - if_icmpgt LABEL546 - jump LABEL789 -LABEL546: + if_icmpgt LABEL558 + jump LABEL801 +LABEL558: iload 16 iconst 0 - if_icmpgt LABEL550 - jump LABEL789 -LABEL550: - clientclock + if_icmpgt LABEL562 + jump LABEL801 +LABEL562: + clientclock get_varc_int 76 - sub + sub iconst 10 - if_icmpgt LABEL556 - jump LABEL789 -LABEL556: + if_icmpgt LABEL568 + jump LABEL801 +LABEL568: get_varbit 4693 iconst 1 - if_icmpeq LABEL560 - jump LABEL571 -LABEL560: + if_icmpeq LABEL572 + jump LABEL583 +LABEL572: invoke 1972 iconst 0 - if_icmpeq LABEL564 - jump LABEL571 -LABEL564: + if_icmpeq LABEL576 + jump LABEL583 +LABEL576: iconst 495 iconst 495 iconst 25 istore 41 istore 40 istore 39 - jump LABEL585 -LABEL571: + jump LABEL597 +LABEL583: get_varbit 4693 iconst 2 - if_icmpeq LABEL575 - jump LABEL585 -LABEL575: + if_icmpeq LABEL587 + jump LABEL597 +LABEL587: invoke 1972 iconst 0 - if_icmpeq LABEL579 - jump LABEL585 -LABEL579: + if_icmpeq LABEL591 + jump LABEL597 +LABEL591: iconst 496 iconst 496 iconst 25 istore 41 istore 40 istore 39 -LABEL585: +LABEL597: iload 8 - if_getheight + if_getheight istore 42 iload 42 iconst 100 - if_icmplt LABEL592 - jump LABEL594 -LABEL592: + if_icmplt LABEL604 + jump LABEL606 +LABEL604: iconst 100 istore 42 -LABEL594: +LABEL606: iload 41 iconst 105 iconst 105 iconst 1171 get_varbit 4722 - enum - multiply + enum + multiply iload 42 - div + div iconst 1 - add + add istore 43 -LABEL606: - iload 37 - iload 35 - if_icmplt LABEL610 - jump LABEL784 -LABEL610: - iload 38 - iconst 0 - if_icmpeq LABEL614 - jump LABEL623 -LABEL614: - iload 0 - iconst 0 - if_icmpeq LABEL618 - jump LABEL623 LABEL618: iload 37 - get_array_int + iload 35 + if_icmplt LABEL622 + jump LABEL796 +LABEL622: + iload 38 + iconst 0 + if_icmpeq LABEL626 + jump LABEL635 +LABEL626: + iload 0 + iconst 0 + if_icmpeq LABEL630 + jump LABEL635 +LABEL630: + iload 37 + get_array_int set_varc_int 72 iconst 1 istore 38 -LABEL623: +LABEL635: get_varc_int 71 iconst 0 - if_icmpgt LABEL627 - jump LABEL638 -LABEL627: + if_icmpgt LABEL639 + jump LABEL650 +LABEL639: get_varc_int 71 - clientclock + clientclock iload 43 - sub - if_icmpgt LABEL633 - jump LABEL638 -LABEL633: + sub + if_icmpgt LABEL645 + jump LABEL650 +LABEL645: get_varc_int 71 iload 43 - add + add istore 44 - jump LABEL640 -LABEL638: - clientclock + jump LABEL652 +LABEL650: + clientclock istore 44 -LABEL640: +LABEL652: iload 44 - clientclock + clientclock iload 43 iload 10 - multiply - add - if_icmplt LABEL648 - jump LABEL781 -LABEL648: + multiply + add + if_icmplt LABEL660 + jump LABEL793 +LABEL660: iconst 105 iconst 73 iconst 1163 get_varc_int 70 - enum + enum istore 47 iconst 0 iload 47 - if_sethide + if_sethide iload 37 get_array_int 1 istore 46 iload 47 iconst 5 iconst 1 - cc_create + cc_create iconst 83 iconst 100 iconst 255 iload 37 - get_array_int - enum - cc_setgraphic + get_array_int + enum + cc_setgraphic iconst 0 iconst 0 iconst 0 iconst 5 - cc_setposition + cc_setposition iconst 1 - cc_sethide + cc_sethide iconst 1 istore 45 iload 37 iconst 1 - add + add istore 37 -LABEL684: +LABEL696: get_varbit 4696 iconst 1 - if_icmpeq LABEL688 - jump LABEL732 -LABEL688: + if_icmpeq LABEL700 + jump LABEL744 +LABEL700: iload 37 iload 35 - if_icmplt LABEL692 - jump LABEL732 -LABEL692: + if_icmplt LABEL704 + jump LABEL744 +LABEL704: iload 45 iconst 5 - if_icmplt LABEL696 - jump LABEL732 -LABEL696: + if_icmplt LABEL708 + jump LABEL744 +LABEL708: iload 46 iconst 1000000 - if_icmplt LABEL700 - jump LABEL732 -LABEL700: + if_icmplt LABEL712 + jump LABEL744 +LABEL712: iload 46 iload 37 get_array_int 1 - add + add istore 46 iload 45 iconst 1 - add + add istore 45 iload 47 iconst 5 iload 45 - cc_create + cc_create iconst 83 iconst 100 iconst 255 iload 37 - get_array_int - enum - cc_setgraphic + get_array_int + enum + cc_setgraphic iconst 0 iconst 0 iconst 0 iconst 5 - cc_setposition + cc_setposition iconst 1 - cc_sethide + cc_sethide iload 37 iconst 1 - add + add istore 37 - jump LABEL684 -LABEL732: + jump LABEL696 +LABEL744: iload 46 sconst "," invoke 46 @@ -832,70 +844,70 @@ LABEL732: sstore 0 iload 0 iconst 1 - if_icmpeq LABEL740 - jump LABEL745 -LABEL740: + if_icmpeq LABEL752 + jump LABEL757 +LABEL752: sconst "" sconst " " sload 0 join_string 3 sstore 0 -LABEL745: +LABEL757: iload 47 iconst 0 - cc_find + cc_find iconst 1 - if_icmpeq LABEL751 - jump LABEL766 -LABEL751: + if_icmpeq LABEL763 + jump LABEL778 +LABEL763: sload 0 - cc_settext + cc_settext iconst 0 iconst 0 iconst 0 iconst 5 - cc_setposition + cc_setposition iconst 1 - cc_sethide + cc_sethide iload 47 iload 41 iload 39 iload 40 sload 0 invoke 996 -LABEL766: +LABEL778: iconst 1005 iload 47 iload 44 sconst "Ii" iload 47 - if_setontimer + if_setontimer iload 44 set_varc_int 71 get_varc_int 70 iconst 1 - add + add iload 10 - mod + mod set_varc_int 70 - jump LABEL783 -LABEL781: + jump LABEL795 +LABEL793: iload 35 istore 37 -LABEL783: - jump LABEL606 -LABEL784: +LABEL795: + jump LABEL618 +LABEL796: iload 1 iload 3 iload 8 iload 9 invoke 997 -LABEL789: +LABEL801: iload 0 iconst 0 - if_icmpeq LABEL793 - jump LABEL812 -LABEL793: + if_icmpeq LABEL805 + jump LABEL824 +LABEL805: iload 3 iload 4 iload 5 @@ -915,5 +927,5 @@ LABEL793: iload 9 iload 10 invoke 1003 -LABEL812: +LABEL824: return