From 3a18fb16c2090f29c40ed7ab2b49b016efe024fc Mon Sep 17 00:00:00 2001 From: Bishop Date: Tue, 28 Jul 2026 17:17:06 -0500 Subject: [PATCH] Then you commit the rest of the Waterfall Quest --- Server/data/configs/ground_spawns.json | 6 +- .../quest/waterfall/AlmeraDialogue.java | 150 ------- .../quest/waterfall/AlmeraDialogue.kt | 84 ++++ .../kandarin/quest/waterfall/BaxtorianBook.kt | 281 +++++++----- .../quest/waterfall/GolrieDialogue.java | 108 ----- .../quest/waterfall/GolrieDialogue.kt | 107 +++++ .../quest/waterfall/HadleyDialogue.java | 80 ---- .../quest/waterfall/HadleyDialogue.kt | 96 +++++ .../quest/waterfall/HudonDialogue.java | 123 ------ .../quest/waterfall/HudonDialogueFile.kt | 54 +++ .../quest/waterfall/MithrilSeedsDialogue.java | 96 ----- .../quest/waterfall/MithrilSeedsListener.kt | 107 +++++ .../quest/waterfall/MithrilSeedsPlugin.java | 92 ---- .../kandarin/quest/waterfall/WaterFall.java | 85 ---- .../quest/waterfall/WaterfallListeners.kt | 403 ++++++++++-------- .../quest/waterfall/WaterfallQuest.kt | 123 ++++++ .../waterfall/WaterfallTreeDialogue.java | 80 ---- .../waterfall/WaterfallTreeDialogueFile.kt | 39 ++ .../core/game/dialogue/DialogueLabeller.kt | 1 + .../core/game/dialogue/FacialExpression.java | 1 + 20 files changed, 1025 insertions(+), 1091 deletions(-) delete mode 100644 Server/src/main/content/region/kandarin/quest/waterfall/AlmeraDialogue.java create mode 100644 Server/src/main/content/region/kandarin/quest/waterfall/AlmeraDialogue.kt delete mode 100644 Server/src/main/content/region/kandarin/quest/waterfall/GolrieDialogue.java create mode 100644 Server/src/main/content/region/kandarin/quest/waterfall/GolrieDialogue.kt delete mode 100644 Server/src/main/content/region/kandarin/quest/waterfall/HadleyDialogue.java create mode 100644 Server/src/main/content/region/kandarin/quest/waterfall/HadleyDialogue.kt delete mode 100644 Server/src/main/content/region/kandarin/quest/waterfall/HudonDialogue.java create mode 100644 Server/src/main/content/region/kandarin/quest/waterfall/HudonDialogueFile.kt delete mode 100644 Server/src/main/content/region/kandarin/quest/waterfall/MithrilSeedsDialogue.java create mode 100644 Server/src/main/content/region/kandarin/quest/waterfall/MithrilSeedsListener.kt delete mode 100644 Server/src/main/content/region/kandarin/quest/waterfall/MithrilSeedsPlugin.java delete mode 100644 Server/src/main/content/region/kandarin/quest/waterfall/WaterFall.java create mode 100644 Server/src/main/content/region/kandarin/quest/waterfall/WaterfallQuest.kt delete mode 100644 Server/src/main/content/region/kandarin/quest/waterfall/WaterfallTreeDialogue.java create mode 100644 Server/src/main/content/region/kandarin/quest/waterfall/WaterfallTreeDialogueFile.kt diff --git a/Server/data/configs/ground_spawns.json b/Server/data/configs/ground_spawns.json index 1893b6df3..a953bb958 100644 --- a/Server/data/configs/ground_spawns.json +++ b/Server/data/configs/ground_spawns.json @@ -111,6 +111,10 @@ "item_id": "278", "loc_data": "{1,2604,3358,0,50}-" }, + { + "item_id": "298", + "loc_data": "{1,2569,9897,0,50}-" + }, { "item_id": "301", "loc_data": "{1,2608,3397,0,90}-" @@ -145,7 +149,7 @@ }, { "item_id": "444", - "loc_data": "{1,3231,3739,0,250}-{1,3236,3741,0,250}-{1,3195,9821,0,150}-{1,2732,3224,0,250}-" + "loc_data": "{1,2732,3224,0,250}-{1,3231,3739,0,250}-{1,3236,3741,0,250}-{1,3195,9821,0,150}-" }, { "item_id": "480", diff --git a/Server/src/main/content/region/kandarin/quest/waterfall/AlmeraDialogue.java b/Server/src/main/content/region/kandarin/quest/waterfall/AlmeraDialogue.java deleted file mode 100644 index 6d3f2bee6..000000000 --- a/Server/src/main/content/region/kandarin/quest/waterfall/AlmeraDialogue.java +++ /dev/null @@ -1,150 +0,0 @@ -package content.region.kandarin.quest.waterfall; - -import content.data.Quests; -import core.game.dialogue.DialogueInterpreter; -import core.game.dialogue.DialoguePlugin; -import core.game.dialogue.FacialExpression; -import core.game.node.entity.player.Player; -import core.game.node.entity.player.link.quest.Quest; - -/** - * Handles Almera's Dialogue for the Waterfall Quest. - * @author Splinter - */ -public class AlmeraDialogue extends DialoguePlugin { - - public AlmeraDialogue() { - - } - - public AlmeraDialogue(Player player) { - super(player); - } - - @Override - public int[] getIds() { - return new int[] { DialogueInterpreter.getDialogueKey("almera_dialogue"), 304 }; - } - - @Override - public boolean handle(int interfaceId, int buttonId) { - final Quest quest = player.getQuestRepository().getQuest(Quests.WATERFALL_QUEST); - switch (stage) { - /* Main dialogue sequence */ - case 0: - if (quest.getStage(player) == 0) { - interpreter.sendDialogues(304, FacialExpression.ASKING, "Ah, hello there. Nice to see an outsider for a change,", "are you busy? I have a problem."); - stage = 1; - } else if (quest.getStage(player) == 10) { - interpreter.sendDialogues(304, FacialExpression.JOLLY, "Hello brave adventurer, have you seen my boy yet?"); - stage = 200; - } else if (quest.getStage(player) >= 20) { - interpreter.sendDialogues(304, FacialExpression.JOLLY, "Well hello, you're still around then."); - stage = 202; - } else { - - } - break; - case 1: - interpreter.sendOptions("Select an Option", "I'm afraid I'm in a rush.", "How can I help?"); - stage = 2; - break; - case 2: - switch (buttonId) { - case 1: - interpreter.sendDialogues(player, FacialExpression.HALF_GUILTY, "I'm afraid I am in a rush."); - stage = 99; - break; - case 2: - interpreter.sendDialogues(player, FacialExpression.HALF_GUILTY, "How can I help?"); - stage = 3; - break; - } - break; - case 3: - interpreter.sendDialogues(304, FacialExpression.DISGUSTED, "It's my son Hudon, he's always getting into trouble, the", "boy's convinced there's hidden treasure in the river and", "I'm a bit worried about his safety, the poor lad can't", "even swim."); - stage = 4; - break; - case 4: - interpreter.sendDialogues(player, FacialExpression.HALF_GUILTY, "I could go and take a look for you if you like?"); - stage = 5; - break; - case 5: - interpreter.sendDialogues(304, FacialExpression.DISGUSTED, "Would you? You are kind. You can use the small raft", "out back if you wish, do be careful, the current down", "stream is very strong."); - quest.start(player); - stage = 100; - break; - case 6: - interpreter.sendDialogues(304, FacialExpression.HALF_GUILTY, "Perhaps you can speak to Hadley a further bit down", "south for more information on how to find the treasure."); - stage = 100; - break; - case 7: - interpreter.sendDialogues(player, FacialExpression.HALF_GUILTY, "I did it, I found the treasure under the waterfall!"); - stage = 8; - break; - case 8: - interpreter.sendDialogues(304, FacialExpression.HALF_GUILTY, "Ah, very well done, adventurer!", "My boy Hudon was searching for that treasure too."); - stage = 9; - break; - case 9: - interpreter.sendDialogues(304, FacialExpression.HALF_GUILTY, "Maybe you could share it with him, he's just a boy."); - stage = 10; - break; - case 10: - interpreter.sendDialogues(player, FacialExpression.HALF_GUILTY, "On second thought, I really have to go."); - stage = 100; - break; - - case 99: - interpreter.sendDialogues(304, FacialExpression.HALF_GUILTY, "Oh okay, never mind."); - stage = 100; - break; - case 100: - end(); - break; - case 200: - interpreter.sendDialogues(player, FacialExpression.HALF_GUILTY, "I'm afraid not, but I'm sure he hasn't gone far."); - stage = 201; - break; - case 201: - interpreter.sendDialogues(304, FacialExpression.HALF_GUILTY, "I do hope so, you can't be too careful these days."); - stage = 100; - break; - case 202: - interpreter.sendDialogues(player, FacialExpression.HALF_GUILTY, "I saw Hudon by the river but he refused to come back", "with me."); - stage = 203; - break; - case 203: - interpreter.sendDialogues(304, FacialExpression.HALF_GUILTY, "Yes he told me, the foolish lad came in drenched to the", "bone, he had fallen into the waterfall, lucky he wasn't", "killed! Now he can spend the rest of the summer in his", "room."); - stage = 204; - break; - case 204: - interpreter.sendDialogues(player, FacialExpression.HALF_GUILTY, "Any ideas on what I could do while I'm here?"); - stage = 205; - break; - case 205: - interpreter.sendDialogues(304, FacialExpression.HALF_GUILTY, "Why don't you visit the tourist centre south of the", "waterfall?"); - stage = 100; - break; - } - return true; - } - - @Override - public DialoguePlugin newInstance(Player player) { - return new AlmeraDialogue(player); - } - - @Override - public boolean open(Object... args) { - final Quest quest = player.getQuestRepository().getQuest(Quests.WATERFALL_QUEST); - if (quest.getStage(player) == 100) { - interpreter.sendDialogues(player, FacialExpression.HALF_GUILTY, "Hello Almera."); - stage = 7; - } else { - interpreter.sendDialogues(player, FacialExpression.NEUTRAL, "Hello."); - stage = 0; - } - return true; - } -} diff --git a/Server/src/main/content/region/kandarin/quest/waterfall/AlmeraDialogue.kt b/Server/src/main/content/region/kandarin/quest/waterfall/AlmeraDialogue.kt new file mode 100644 index 000000000..4da028e98 --- /dev/null +++ b/Server/src/main/content/region/kandarin/quest/waterfall/AlmeraDialogue.kt @@ -0,0 +1,84 @@ +package content.region.kandarin.quest.waterfall + +import content.data.Quests +import core.api.* +import core.game.dialogue.ChatAnim +import core.game.dialogue.DialogueLabeller +import core.game.dialogue.DialogueOption +import core.game.interaction.IntType +import core.game.interaction.InteractionListener +import core.game.node.entity.npc.NPC +import org.rs09.consts.NPCs + +class AlmeraDialogue : InteractionListener { + override fun defineListeners() { + on(NPCs.ALMERA_304, IntType.NPC, "talk-to") { player, node -> + DialogueLabeller.open(player, AlmeraDialogueFile(), node as NPC) + return@on true + } + } +} + +class AlmeraDialogueFile : DialogueLabeller() { + override fun addConversation() { + exec { player, _ -> + when (getQuestStage(player, Quests.WATERFALL_QUEST)) { + 0 -> loadLabel(player, "quest_not_started") + 10 -> loadLabel(player, "quest_stage_10") + 20 -> loadLabel(player, "quest_stage_20") + 30 -> loadLabel(player, "quest_stage_30") + 100 -> loadLabel(player, "quest_complete") + } + } + + label("quest_not_started") + player(ChatAnim.NEUTRAL, "Hello.") + npc(ChatAnim.NEUTRAL, "Ah, hello there. Nice to see an outsider for a change,", "are you busy? I have a problem.") + options( + DialogueOption("rush", "I'm afraid I'm in a rush.", expression = ChatAnim.NEUTRAL), + DialogueOption("help", "How can I help?", expression = ChatAnim.NEUTRAL) + ) + + label("rush") + npc(ChatAnim.HALF_GUILTY, "Oh okay, never mind.") + + label("help") + npc(ChatAnim.THINKING, "It's my son Hudon, he's always getting into trouble, the", "boy's convinced there's hidden treasure in the river and", + "I'm a bit worried about his safety, the poor lad can't", "even swim.") + player(ChatAnim.THINKING, "I could go and take a look for you if you like?") + exec { player, _ -> + startQuest(player, Quests.WATERFALL_QUEST) + } + npc(ChatAnim.HAPPY, "Would you? You are kind. You can use the small raft", "out back if you wish, do be careful, the current down", + "stream is very strong.") + + label("quest_stage_10") + npc(ChatAnim.NEUTRAL, "Hello brave adventurer, have you seen my boy yet?") + player(ChatAnim.NEUTRAL, "I'm afraid not, but I'm sure he hasn't gone far.") + npc(ChatAnim.NEUTRAL, "I do hope so, you can't be too careful these days.") + + label("quest_stage_20") + player(ChatAnim.NEUTRAL, "Hello again.") + npc(ChatAnim.NEUTRAL, "Well hello, you're still around then.") + player(ChatAnim.NEUTRAL, "I saw Hudon by the river but he refused to come back", "with me.") + npc(ChatAnim.NEUTRAL, "Yes he told me, the foolish lad came in drenched to the", "bone, he had fallen into the waterfall, lucky he wasn't", + "killed! Now he can spend the rest of the summer in his", "room.") + player(ChatAnim.NEUTRAL, "Any ideas on what I could do while I'm here?") + npc(ChatAnim.NEUTRAL, "Why don't you visit the tourist centre south of the", "waterfall?") + + label("quest_stage_30") + player(ChatAnim.NEUTRAL, "Hello Almera.") + npc(ChatAnim.NEUTRAL, "Hello adventurer, how's your treasure hunt going?") + player(ChatAnim.NEUTRAL, "Oh, I'm just sight seeing.") + npc(ChatAnim.NEUTRAL, "No adventurer stays this long just to sight see. But", "your business is yours alone, if you need to use the", + "raft go ahead. But please try not to crash it this time!") + player(ChatAnim.NEUTRAL, "Thanks Almera.") + + label("quest_complete") + player(ChatAnim.NEUTRAL, "Hello Almera.") + player(ChatAnim.NEUTRAL, "I did it, I found the treasure under the waterfall!") + npc(ChatAnim.NEUTRAL, "Ah, very well done, adventurer!", "My boy Hudon was searching for that treasure too.") + npc(ChatAnim.NEUTRAL, "Maybe you could share it with him, he's just a boy.") + player(ChatAnim.NEUTRAL, "On second thought, I really have to go.") + } +} \ No newline at end of file diff --git a/Server/src/main/content/region/kandarin/quest/waterfall/BaxtorianBook.kt b/Server/src/main/content/region/kandarin/quest/waterfall/BaxtorianBook.kt index c4c0d1ef0..bb35340b0 100644 --- a/Server/src/main/content/region/kandarin/quest/waterfall/BaxtorianBook.kt +++ b/Server/src/main/content/region/kandarin/quest/waterfall/BaxtorianBook.kt @@ -5,148 +5,205 @@ import content.global.handlers.iface.BookInterface import content.global.handlers.iface.BookLine import content.global.handlers.iface.Page import content.global.handlers.iface.PageSet -import core.api.setAttribute +import core.api.getQuestStage +import core.api.lock +import core.api.queueScript +import core.api.sendMessage +import core.api.setQuestStage +import core.api.stopExecuting import core.api.storeBookInHouse import core.game.interaction.IntType import core.game.interaction.InteractionListener +import core.game.interaction.QueueStrength import core.game.node.entity.player.Player import org.rs09.consts.Items /** - * Baxtorian Book + * The Book on Baxtorian * @author ovenbreado - * @author Splinter + * @author Bishop */ + class BaxtorianBook : InteractionListener { companion object { + private const val RED = "" + private val TITLE = "Book on Baxtorian" private val CONTENTS = arrayOf( PageSet( Page( - BookLine("The missing relics", 55), + BookLine(RED + "The missing relics", 55), BookLine("", 56), - BookLine(" Many artefacts of", 57), - BookLine("elven history were lost", 58), - BookLine("after the fourth age. The", 59), - BookLine("greatest loss to our", 60), - BookLine("collections of elf history", 61), - BookLine("were the hidden treasures", 62), - BookLine("of Baxtorian.", 63), - BookLine(" Some believe these", 64), - BookLine("treasures are still", 65) + BookLine("Many artefacts of elven", 57), + BookLine("history were lost after the", 58), + BookLine("fourth age, following the", 59), + BookLine("departure of the elven", 60), + BookLine("colonies from these lands.", 61), + BookLine("The greatest loss to our", 62), + BookLine("collections of elf history", 63), + BookLine("were the hidden treasures", 64), + BookLine("of Baxtorian. Some", 65) ), Page( - BookLine("unclaimed, but it is more", 66), - BookLine("commonly believed that", 67), - BookLine("dwarf miners recovered", 68), - BookLine("the treasure at the", 69), - BookLine("beginning of the third", 70), - BookLine("age. Another great loss", 71), - BookLine("was Glarial's pebble, a key", 72), - BookLine("which allowed her family", 73), - BookLine("to visit her tomb.", 74), - BookLine(" The stone was taken", 75), - BookLine("by a gnome family over a", 76) - ) - ), - PageSet( - Page( - BookLine("century ago. It is", 55), - BookLine("believed that the gnomes'", 56), - BookLine("descendant Golrie still has", 57), - BookLine("the stone hidden in the", 58), - BookLine("caves under the gnome", 59), - BookLine("tree village.", 60), - BookLine("", 61), - BookLine("The sonnet of Baxtorian", 62), - BookLine("", 63), - BookLine("The love between", 64), - BookLine("Baxtorian and Glarial was", 65) - ), Page( - BookLine("said to have lasted over a", 66), - BookLine("century. They lived a", 67), - BookLine("peaceful life learning and", 68), - BookLine("teaching the laws of", 69), - BookLine("nature. When Baxtorian's", 70), - BookLine("kingdom was invaded by", 71), - BookLine("the dark forces he left on", 72), - BookLine("a five year campaign. He", 73), - BookLine("returned to find his", 74), - BookLine("people slaughtered and his", 75), - BookLine("wife taken by the enemy.", 76) - ) - ), - PageSet( - Page( - BookLine(" After years of", 55), - BookLine("searching for his love he", 56), - BookLine("finally gave up and", 57), - BookLine("returned to the home he", 58), - BookLine("made for Glarial under", 59), - BookLine("the Baxtorian Waterfall.", 60), - BookLine("Once he entered he", 61), - BookLine("never returned. Only", 62), - BookLine("Glarial had the power to", 63), - BookLine("also enter the waterfall.", 64), - BookLine(" Since Baxtorian", 65) - ), - Page( - BookLine("entered no one but her", 66), - BookLine("can follow him in, it's as if", 67), - BookLine("the powers of nature still", 68), - BookLine("work to protect him.", 69), - BookLine("", 70), - BookLine("The power of nature", 71), + BookLine("believe these treasures", 66), + BookLine("are still unclaimed, but it", 67), + BookLine("is more commonly", 68), + BookLine("believed that dwarf miners", 69), + BookLine("recovered the treasure", 70), + BookLine("early in the 5th Age.", 71), BookLine("", 72), - BookLine(" Glarial and Baxtorian", 73), - BookLine("were masters of nature.", 74), - BookLine("Trees would grow, hills", 75), - BookLine("form and rivers flood on", 76) + BookLine("Another great loss was", 73), + BookLine("Glarial's pebble, a key", 74), + BookLine("which allowed her family", 75), + BookLine("to visit her tomb.", 76) ) ), PageSet( Page( - BookLine("their command. Baxtorian", 55), - BookLine("in particular had", 56), - BookLine("perfected rune lore. It", 57), - BookLine("was said that he could", 58), - BookLine("uses the stones to control", 59), - BookLine("water, earth, and air.", 60), - BookLine("", 61), - BookLine("Ode to eternity", 62), + BookLine("The pebble was taken by", 55), + BookLine("a gnome many years", 56), + BookLine("ago. It is hoped that", 57), + BookLine("descendents " /*sic*/+ "of that", 58), + BookLine("gnome may still have the", 59), + BookLine("pebble hidden in their", 60), + BookLine("cave under the Tree", 61), + BookLine("Gnome Village.", 62), BookLine("", 63), - BookLine("A short piece written by", 64), - BookLine("Baxtorian himself.", 65) + BookLine("Unfortunately the maze", 64), + BookLine("around that village makes", 65) ), Page( - BookLine("", 66), - BookLine("What care I for this", 67), - BookLine("mortal coil,", 68), - BookLine("where treasures are yet", 69), - BookLine("so frail,", 70), - BookLine("for it is you that is my", 71), - BookLine("life blood,", 72), - BookLine("the wine to my holy grail", 73), - BookLine("and if I see the", 74), - BookLine("judgement day,", 75), - BookLine("when the gods fill the air", 76) + BookLine("it difficult to contact the", 66), + BookLine("gnomes to investigate this", 67), + BookLine("matter.", 68), + BookLine("", 69), + BookLine("", 70), + BookLine("", 71), + BookLine("", 72), + BookLine("", 73), + BookLine("", 74), + BookLine("", 75), + BookLine("", 76) ) ), PageSet( Page( - BookLine("with dust,", 55), - BookLine("I'll happily choke on your", 56), - BookLine("memory,", 57), - BookLine("as my kingdom turns to", 58), - BookLine("rust", 59) + BookLine(RED + "The fall of Baxtorian", 55), + BookLine("", 56), + BookLine("The love between", 57), + BookLine("Baxtorian and Glarial was", 58), + BookLine("said to have lasted over a", 59), + BookLine("century. They lived a", 60), + BookLine("peaceful life learning and", 61), + BookLine("teaching the laws of", 62), + BookLine("nature.", 63), + BookLine("", 64), + BookLine("When their homeland in", 65) + ), + Page( + BookLine("the far west was plunged", 66), + BookLine("into chaos by dark forces,", 67), + BookLine("Baxtorian left on a", 68), + BookLine("dangerous campaign that", 69), + BookLine("lasted for five years. He", 70), + BookLine("survived to return to this", 71), + BookLine("land, but found his people", 72), + BookLine("slaughtered and his wife", 73), + BookLine("taken by the enemy.", 74), + BookLine("", 75), + BookLine("After years of searching", 76) ) - ) + ), + PageSet( + Page( + BookLine("for his love he finally", 55), + BookLine("gave up and returned to", 56), + BookLine("the home he made for", 57), + BookLine("Glarial under the", 58), + BookLine("Baxtorian Waterfall.", 59), + BookLine("Once he entered he", 60), + BookLine("never returned.", 61), + BookLine("", 62), + BookLine("Only he and Glarial had", 63), + BookLine("the power to enter the", 64), + BookLine("waterfall. Since Baxtorian", 65) + ), + Page( + BookLine("entered, no-one else can", 66), + BookLine("follow him in, it's as if the", 67), + BookLine("powers of nature still", 68), + BookLine("work to protect his peace.", 69), + BookLine("", 70), + BookLine("", 71), + BookLine("", 72), + BookLine("", 73), + BookLine("", 74), + BookLine("", 75), + BookLine("", 76) + ) + ), + PageSet( + Page( + BookLine(RED + "The power of nature", 55), + BookLine("", 56), + BookLine("Glarial and Baxtorian", 57), + BookLine("were masters of nature.", 58), + BookLine("Trees and flowers would", 59), + BookLine("grow, hills form and", 60), + BookLine("rivers flood on their", 61), + BookLine("command.", 62), + BookLine("", 63), + BookLine("Baxtorian in particular", 64), + BookLine("had perfected rune lore.", 65) + ), + Page( + BookLine("It was said that he could", 66), + BookLine("use the stones to control", 67), + BookLine("water, earth and air.", 68), + BookLine("", 69), + BookLine("", 70), + BookLine("", 71), + BookLine("", 72), + BookLine("", 73), + BookLine("", 74), + BookLine("", 75), + BookLine("", 76) + ) + ), + PageSet( + Page( + BookLine(RED + "Ode to eternity", 55), + BookLine("", 56), + BookLine("(A short piece written by", 57), + BookLine("Baxtorian himself.)", 58), + BookLine("", 59), + BookLine("What care I for this", 60), + BookLine("mortal coil,", 61), + BookLine("where treasures are yet", 62), + BookLine("so frail,", 63), + BookLine("for it is you that is my", 64), + BookLine("life blood,", 65) + ), + Page( + BookLine("the wine to my holy grail", 66), + BookLine("and if I see the", 67), + BookLine("judgement day,", 68), + BookLine("when the gods fill the air", 69), + BookLine("with dust,", 70), + BookLine("I'll happily choke on your", 71), + BookLine("memory,", 72), + BookLine("as my kingdom turns to", 73), + BookLine("rust.", 74), + BookLine("", 75), + BookLine("", 76) + ) + ), ) private fun display(player: Player, pageNum: Int, buttonID: Int) : Boolean { BookInterface.pageSetup(player, BookInterface.FANCY_BOOK_3_49, TITLE, CONTENTS) - if (player.questRepository.getQuest(Quests.WATERFALL_QUEST).getStage(player) == 20) { - player.questRepository.getQuest(Quests.WATERFALL_QUEST).setStage(player, 30) + if (getQuestStage(player, Quests.WATERFALL_QUEST) == 20) { + setQuestStage(player, Quests.WATERFALL_QUEST, 30) } return true } @@ -154,8 +211,14 @@ class BaxtorianBook : InteractionListener { override fun defineListeners() { on(Items.BOOK_ON_BAXTORIAN_292, IntType.ITEM, "read") { player, node -> - BookInterface.openBook(player, BookInterface.FANCY_BOOK_3_49, ::display) - storeBookInHouse(player, node) + sendMessage(player, "The book is old with many pages missing.") + sendMessage(player, "A few are translated from elven into common tongue.") + lock(player, 2) + queueScript(player, 2, QueueStrength.STRONG) { + BookInterface.openBook(player, BookInterface.FANCY_BOOK_3_49, ::display) + storeBookInHouse(player, node) + return@queueScript stopExecuting(player) + } return@on true } } diff --git a/Server/src/main/content/region/kandarin/quest/waterfall/GolrieDialogue.java b/Server/src/main/content/region/kandarin/quest/waterfall/GolrieDialogue.java deleted file mode 100644 index f16af0ea8..000000000 --- a/Server/src/main/content/region/kandarin/quest/waterfall/GolrieDialogue.java +++ /dev/null @@ -1,108 +0,0 @@ -package content.region.kandarin.quest.waterfall; - -import core.game.dialogue.DialogueInterpreter; -import core.game.dialogue.DialoguePlugin; -import core.game.dialogue.FacialExpression; -import core.game.node.entity.player.Player; -import core.game.node.item.Item; - -import static core.api.ContentAPIKt.*; - -/** - * Handles Golrie's Dialogue for the Waterfall quest - * @author Splinter - */ -public class GolrieDialogue extends DialoguePlugin { - - public GolrieDialogue() { - - } - - public GolrieDialogue(Player player) { - super(player); - } - - @Override - public int[] getIds() { - return new int[] { DialogueInterpreter.getDialogueKey("golrie_dialogue"), 306 }; - } - - @Override - public boolean handle(int interfaceId, int buttonId) { - switch (stage) { - case 100: - end(); - break; - - /* Main dialogue sequence */ - case 0: - interpreter.sendDialogues(306, FacialExpression.OLD_NORMAL, "That's me. I've been stuck in here for weeks, those", "goblins are trying to steal my family's heirlooms. My", "grandad gave me all sorts of old junk."); - stage = 1; - break; - case 1: - interpreter.sendDialogues(player, FacialExpression.ASKING, "Do you mind if I have a look?"); - stage = 2; - break; - case 2: - interpreter.sendDialogues(306, FacialExpression.OLD_HAPPY, "No, of course not."); - stage = 3; - break; - case 3: - //TODO: Possibly change this to chat message - interpreter.sendDialogue("You look amongst the junk on the floor."); - if (hasAnItem(player, 294).getContainer() != null) { - stage = 50; - } else { - stage = 4; - } - break; - case 4: - //TODO: Possibly change this to chat message - interpreter.sendDialogue("Mixed with the junk on the floor you find Glarial's pebble."); - stage = 5; - break; - case 5: - //TODO: Possibly change to HAPPY - interpreter.sendDialogues(player, FacialExpression.ASKING, "Could I take this old pebble?"); - stage = 6; - break; - case 6: - interpreter.sendDialogues(306, FacialExpression.OLD_NORMAL, "Oh that, yes have it, it's just some old elven junk I", "believe."); - player.getInventory().add(new Item(294, 1)); - stage = 7; - break; - case 7: - //TODO: Possibly change this to chat message - interpreter.sendDialogue("You give the key to Golrie."); - stage = 8; - break; - case 8: - interpreter.sendDialogues(306, FacialExpression.OLD_HAPPY, "Thanks a lot for the key traveller. I think I'll wait in", "here until those goblins get bored and leave."); - player.getInventory().remove(new Item(293, 1)); - stage = 9; - break; - case 9: - interpreter.sendDialogues(player, FacialExpression.NEUTRAL, "OK... Take care Golrie."); - stage = 100; - break; - case 50: - //TODO: Possibly change this to chat message - interpreter.sendDialogue("You find nothing of interest."); - stage = 100; - break; - } - return true; - } - - @Override - public DialoguePlugin newInstance(Player player) { - return new GolrieDialogue(player); - } - - @Override - public boolean open(Object... args) { - interpreter.sendDialogues(player, FacialExpression.NEUTRAL, "Hello, is your name Golrie?"); - stage = 0; - return true; - } -} \ No newline at end of file diff --git a/Server/src/main/content/region/kandarin/quest/waterfall/GolrieDialogue.kt b/Server/src/main/content/region/kandarin/quest/waterfall/GolrieDialogue.kt new file mode 100644 index 000000000..2417f89b3 --- /dev/null +++ b/Server/src/main/content/region/kandarin/quest/waterfall/GolrieDialogue.kt @@ -0,0 +1,107 @@ +package content.region.kandarin.quest.waterfall + +import core.api.* +import core.game.dialogue.ChatAnim +import core.game.dialogue.DialogueLabeller +import core.game.interaction.IntType +import core.game.interaction.InteractionListener +import core.game.interaction.QueueStrength +import core.game.node.entity.npc.NPC +import org.rs09.consts.Items +import org.rs09.consts.NPCs + +class GolrieDialogue : InteractionListener { + override fun defineListeners() { + on(NPCs.GOLRIE_306, IntType.NPC, "talk-to") { player, node -> + DialogueLabeller.open(player, GolrieDialogueFile(null), node as NPC) + return@on true + } + } +} + +class GolrieDialogueFile(val startLabel: String?) : DialogueLabeller() { + override fun addConversation() { + exec { player, _ -> + loadLabel(player, startLabel?: "init") + return@exec + } + + label("init") + player(ChatAnim.NEUTRAL, "Hello, is your name Golrie?") + npc(ChatAnim.OLD_CALM_TALK2, "That's me. I've been stuck in here for weeks, those", "goblins are trying to steal my family's heirlooms. My", + "grandad gave me all sorts of old junk.") + player(ChatAnim.NEUTRAL, "Do you mind if I have a look?") + afterClose { player -> + queueScript(player, 0, QueueStrength.NORMAL) { stage -> + when (stage) { + 0 -> { + lock(player, 4) + sendMessage(player, "You look amongst the junk on the floor") + return@queueScript delayScript(player, 2) + } + 1 -> { + if (hasAnItem(player, Items.GLARIALS_PEBBLE_294).exists()) { + sendMessage(player, "You find nothing of interest.") + return@queueScript stopExecuting(player) + } else { + sendMessage(player, "Mixed with the junk on the floor you find Glarial's pebble.") + return@queueScript delayScript(player, 2) + } + } + 2 -> { + DialogueLabeller.open(player, GolrieDialogueFile("got_pebble"), + findLocalNPC(player, NPCs.GOLRIE_306)?: return@queueScript stopExecuting(player)) + return@queueScript stopExecuting(player) + } + else -> return@queueScript stopExecuting(player) + } + } + return@afterClose + } + npc(ChatAnim.OLD_HAPPY, "No, of course not.") + + label("got_pebble") + player(ChatAnim.NEUTRAL, "Could I take this old pebble?") + afterClose { player -> + addItemOrDrop(player, Items.GLARIALS_PEBBLE_294) + if (removeItem(player, Items.A_KEY_293)) { + sendMessage(player, "You give Golrie the key.") + queueScript(player, 2, QueueStrength.NORMAL) { + DialogueLabeller.open(player, GolrieDialogueFile("thanks"), + findLocalNPC(player, NPCs.GOLRIE_306)?: return@queueScript stopExecuting(player)) + return@queueScript stopExecuting(player) + } + } + return@afterClose + } + npc(ChatAnim.OLD_CALM_TALK1, "Oh that, yes have it, it's just some old elven junk I", "believe.") + + label("thanks") + npc(ChatAnim.OLD_CALM_TALK1, "Thanks a lot for the key traveller. I think I'll wait in", "here until those goblins get bored and leave.") + player(ChatAnim.NEUTRAL, "OK... Take care Golrie.") + + label("door_no_business_here") + npc(ChatAnim.OLD_CALM_TALK1, "What are you doing down here?", "Leave before you get yourself into trouble.") + + label("door_on_quest") + player(ChatAnim.NEUTRAL, "Hello, are you ok?") + npc(ChatAnim.OLD_CALM_TALK1, "It's just those blasted hobgoblins. I locked myself in here for protection. But I've left the key somewhere and now I'm stuck.") + exec { player, _ -> + if (inInventory(player, Items.A_KEY_293)) { + loadLabel(player, "door_yes_key") + } else { + loadLabel(player, "door_no_key") + } + return@exec + } + + label("door_no_key") + player(ChatAnim.NEUTRAL, "OK... I'll have a look for a key.") + + label("door_yes_key") + player(ChatAnim.NEUTRAL, "I found a key.") + npc(ChatAnim.OLD_CALM_TALK2, "Well don't wait all day, give it a try!") + player(ChatAnim.NEUTRAL, "OK...") + + } +} \ No newline at end of file diff --git a/Server/src/main/content/region/kandarin/quest/waterfall/HadleyDialogue.java b/Server/src/main/content/region/kandarin/quest/waterfall/HadleyDialogue.java deleted file mode 100644 index 6ac9e47f9..000000000 --- a/Server/src/main/content/region/kandarin/quest/waterfall/HadleyDialogue.java +++ /dev/null @@ -1,80 +0,0 @@ -package content.region.kandarin.quest.waterfall; - -import core.game.dialogue.DialogueInterpreter; -import core.game.dialogue.DialoguePlugin; -import core.game.dialogue.FacialExpression; -import core.game.node.entity.player.Player; -import core.game.world.GameWorld; - -/** - * Handles Almera's Dialogue for the Waterfall Quest. - * @author Splinter - */ -public class HadleyDialogue extends DialoguePlugin { - - public HadleyDialogue() { - - } - - public HadleyDialogue(Player player) { - super(player); - } - - @Override - public int[] getIds() { - return new int[] { DialogueInterpreter.getDialogueKey("hadley_dialogue"), 302 }; - } - - @Override - public boolean handle(int interfaceId, int buttonId) { - switch (stage) { - case 100: - end(); - break; - - /* Main dialogue sequence */ - case 0: - if (player.getInventory().contains(292, 1)) { - interpreter.sendDialogues(302, FacialExpression.HALF_GUILTY, "I hope you're enjoying your stay, there should be lots", "of useful information in that book: places to go, people to", "see."); - stage = 100; - } else { - interpreter.sendDialogues(302, FacialExpression.HALF_GUILTY, "Are you on holiday? If so you've come to the right", "place. I'm Hadley the tourist guide, anything you need", "to know just ask me. We have some of the most unspoilt", "wildlife and scenery in " + GameWorld.getSettings().getName() + "."); - stage = 1; - } - break; - case 1: - interpreter.sendDialogues(302, FacialExpression.HALF_GUILTY, "People come from miles around to fish in the clear lakes", "or to wander the beautiful hill sides."); - stage = 2; - break; - case 2: - interpreter.sendDialogues(player, FacialExpression.HALF_GUILTY, "It is quite pretty."); - stage = 3; - break; - case 3: - interpreter.sendDialogues(302, FacialExpression.HALF_GUILTY, "Surely pretty is an understatement kind " + (player.isMale() ? "Sir. " : "Lady. ") + "Beautiful,", "amazing or possibly life-changing would be more suitable", "wording. Have you seen the Baxtorian waterfall?", "Named after the elf king who was buried underneath."); - stage = 4; - break; - case 4: - interpreter.sendDialogues(player, FacialExpression.HALF_GUILTY, "Thanks then, goodbye."); - stage = 5; - break; - case 5: - interpreter.sendDialogues(302, FacialExpression.HALF_GUILTY, "Enjoy your visit."); - stage = 100; - break; - } - return true; - } - - @Override - public DialoguePlugin newInstance(Player player) { - return new HadleyDialogue(player); - } - - @Override - public boolean open(Object... args) { - interpreter.sendDialogues(player, FacialExpression.HALF_GUILTY, "Hello there."); - stage = 0; - return true; - } -} \ No newline at end of file diff --git a/Server/src/main/content/region/kandarin/quest/waterfall/HadleyDialogue.kt b/Server/src/main/content/region/kandarin/quest/waterfall/HadleyDialogue.kt new file mode 100644 index 000000000..90f5eeba9 --- /dev/null +++ b/Server/src/main/content/region/kandarin/quest/waterfall/HadleyDialogue.kt @@ -0,0 +1,96 @@ +package content.region.kandarin.quest.waterfall + +import core.ServerConstants +import core.api.* +import core.game.dialogue.ChatAnim +import core.game.dialogue.DialogueLabeller +import core.game.dialogue.DialogueOption +import core.game.interaction.IntType +import core.game.interaction.InteractionListener +import core.game.node.entity.npc.NPC +import org.rs09.consts.Items +import org.rs09.consts.NPCs + +class HadleyDialogue : InteractionListener { + override fun defineListeners() { + on(NPCs.HADLEY_302, IntType.NPC, "talk-to") { player, node -> + DialogueLabeller.open(player, HadleyDialogueFile(), node as NPC) + return@on true + } + } +} + +class HadleyDialogueFile : DialogueLabeller() { + override fun addConversation() { + val gender = if (player!!.isMale) "Sir" else "Lady" + + player(ChatAnim.NEUTRAL, "Hello there.") + exec { player, _ -> + if (inInventory(player, Items.BOOK_ON_BAXTORIAN_292)) { + loadLabel(player, "book") + } else { + loadLabel(player, "no_book") + } + } + + label("book") + npc(ChatAnim.HALF_GUILTY, "I hope you're enjoying your stay, there should be lots", "of useful information in that book: places to go, people to", "see.") + + label("no_book") + npc(ChatAnim.NEUTRAL_FAST, "Are you on holiday? If so you've come to the right", "place. I'm Hadley the tourist guide, anything you need", + "to know just ask me " /*sic*/+ "we have some of the most unspoilt", "wildlife and scenery in ${ServerConstants.SERVER_NAME}.") + npc(ChatAnim.NEUTRAL, "People come from miles around to fish in the clear lakes", "or to wander the beautiful hillsides") + player(ChatAnim.NEUTRAL, "It is quite pretty.") + npc(ChatAnim.NEUTRAL_FAST, "Surely pretty is an understatement kind $gender.", "Beautiful, amazing or possibly life-changing would be", + "more suitable wording. Have you seen the Baxtorian", "waterfall? Named after the elf king who was buried") + npc(ChatAnim.NEUTRAL, "beneath.") + options( + DialogueOption("elf_king", "Can you tell me what happened to the elf king?", expression = ChatAnim.NEUTRAL), + DialogueOption("visiting", "Where else is worth visiting around here?", expression = ChatAnim.NEUTRAL), + DialogueOption("treasure", "Is there treasure under the waterfall?", expression = ChatAnim.NEUTRAL), + DialogueOption("bye", "Thanks then, goodbye.", expression = ChatAnim.NEUTRAL), + ) + + label("elf_king") + npc(ChatAnim.NEUTRAL_FAST, "There are many myths about Baxtorian. One popular", "story is that after defending his kingdom against the", + "invading dark forces from the west, Baxtorian returned", "to find his wife Glarial had been captured by the") + npc(ChatAnim.NEUTRAL, "enemy!") + npc(ChatAnim.NEUTRAL_FAST, "This destroyed Baxtorian, after years of searching he", "became a recluse. In the secret home he had made for", + "Glarial under the waterfall, he never came out and it is", "told that only Glarial could enter.") + player(ChatAnim.NEUTRAL, "What happened to him?") + npc(ChatAnim.NEUTRAL, "Oh, I don't know. I believe we have some pages on him", "upstairs in our archives. If you wish to look at them", + "please be careful, they're all pretty delicate.") + options( + DialogueOption("visiting", "Where else is worth visiting around here?", expression = ChatAnim.NEUTRAL), + DialogueOption("treasure", "Is there treasure under the waterfall?", expression = ChatAnim.NEUTRAL), + DialogueOption("bye", "Thanks then, goodbye.", expression = ChatAnim.NEUTRAL), + ) + + label("visiting") + npc(ChatAnim.NEUTRAL, "There is a lovely spot for a picnic on the hill to the", "north east, there lies a monument to the deceased elven", + "queen Glarial. It really is quite pretty.") + player(ChatAnim.NEUTRAL, "Who was queen Glarial?") + npc(ChatAnim.NEUTRAL, "Baxtorian's wife, the only person who could also enter", "the waterfall. She was queen when this land was", + "inhabited by elven kind. Glarial was kidnapped while") + npc(ChatAnim.NEUTRAL, "Baxtorian was away, but they eventually recovered her", "body and brought her home to rest.") + player(ChatAnim.SAD, "That's sad.") + npc(ChatAnim.NEUTRAL, "True, I believe there's some information about her", "upstairs, if you look at them please be careful.") + options( + DialogueOption("elf_king", "Can you tell me what happened to the elf king?", expression = ChatAnim.NEUTRAL), + DialogueOption("treasure", "Is there treasure under the waterfall?", expression = ChatAnim.NEUTRAL), + DialogueOption("bye", "Thanks then, goodbye.", expression = ChatAnim.NEUTRAL), + ) + + label("treasure") + npc(ChatAnim.NEUTRAL, "Ha ha... another treasure hunter. Well if there is " /*sic*/+ "no", "one's been able to get to it. They've been searching that", + "river for decades, all to no avail.") + options( + DialogueOption("elf_king", "Can you tell me what happened to the elf king?", expression = ChatAnim.NEUTRAL), + DialogueOption("visiting", "Where else is worth visiting around here?", expression = ChatAnim.NEUTRAL), + DialogueOption("bye", "Thanks then, goodbye.", expression = ChatAnim.NEUTRAL), + ) + + label("bye") + npc(ChatAnim.NEUTRAL, "Enjoy your visit.") + } +} \ No newline at end of file diff --git a/Server/src/main/content/region/kandarin/quest/waterfall/HudonDialogue.java b/Server/src/main/content/region/kandarin/quest/waterfall/HudonDialogue.java deleted file mode 100644 index e8c3262ad..000000000 --- a/Server/src/main/content/region/kandarin/quest/waterfall/HudonDialogue.java +++ /dev/null @@ -1,123 +0,0 @@ -package content.region.kandarin.quest.waterfall; - -import content.data.Quests; -import core.game.dialogue.DialogueInterpreter; -import core.game.dialogue.DialoguePlugin; -import core.game.dialogue.FacialExpression; -import core.game.node.entity.player.Player; -import core.game.node.entity.player.link.quest.Quest; - -/** - * Handles Hudon's Dialogue for the Waterfall Quest. - * @author Splinter - */ -public class HudonDialogue extends DialoguePlugin { - - public HudonDialogue() { - - } - - public HudonDialogue(Player player) { - super(player); - } - - @Override - public int[] getIds() { - return new int[] { DialogueInterpreter.getDialogueKey("hudon_dialogue"), 305 }; - } - - @Override - public boolean handle(int interfaceId, int buttonId) { - final Quest quest = player.getQuestRepository().getQuest(Quests.WATERFALL_QUEST); - switch (stage) { - - case 100: // Generic end to the dlg - end(); - break; - case 101: // Generic end to the dlg - player.getPacketDispatch().sendMessage("Hudon is refusing to leave the waterfall."); - end(); - break; - - /* Main dialogue sequence */ - case 0: - if (quest.getStage(player) == 10) { - interpreter.sendDialogues(305, FacialExpression.CHILD_NORMAL, "It looks like you need the help."); - stage = 1; - } - break; - case 1: - interpreter.sendDialogues(player, FacialExpression.HALF_GUILTY, "Your mum sent me to find you."); - stage = 2; - break; - case 2: - interpreter.sendDialogues(305, FacialExpression.CHILD_NORMAL, "Don't play nice with me, I know you're looking for the", "treasure too."); - stage = 3; - break; - case 3: - interpreter.sendDialogues(player, FacialExpression.HALF_GUILTY, "Where is this treasure you talk of?"); - stage = 4; - break; - case 4: - interpreter.sendDialogues(305, FacialExpression.CHILD_SUSPICIOUS, "Just because I'm small doesn't mean I'm dumb! If I", "told you, you would take it all for yourself."); - stage = 5; - break; - case 5: - interpreter.sendDialogues(player, FacialExpression.HALF_GUILTY, "Maybe I could help."); - stage = 6; - break; - case 6: - interpreter.sendDialogues(305, FacialExpression.CHILD_NORMAL, "I'm fine alone."); - quest.setStage(player, 20); - stage = 101; - break; - case 20: - interpreter.sendDialogues(305, FacialExpression.CHILD_NORMAL, "I'll find that treasure soon, just you wait and see."); - if (quest.getStage(player) == 100) { - stage = 21; - } else { - stage = 100; - } - break; - case 21: - interpreter.sendDialogues(player, FacialExpression.HALF_GUILTY, "I hate to break it to you kid, but I found the treasure."); - stage = 22; - break; - case 22: - interpreter.sendDialogues(305, FacialExpression.CHILD_NORMAL, "Wha- are you serious? Are you going to at least share?"); - stage = 23; - break; - case 23: - interpreter.sendDialogues(player, FacialExpression.HALF_GUILTY, "No."); - stage = 24; - break; - case 24: - interpreter.sendDialogues(305, FacialExpression.CHILD_NORMAL, "Aww, come on... I helped you find it.", "This isn't fair!"); - stage = 25; - break; - case 25: - interpreter.sendDialogues(player, FacialExpression.HALF_GUILTY, "Life ain't fair kid."); - stage = 100; - break; - } - return true; - } - - @Override - public DialoguePlugin newInstance(Player player) { - return new HudonDialogue(player); - } - - @Override - public boolean open(Object... args) { - final Quest quest = player.getQuestRepository().getQuest(Quests.WATERFALL_QUEST); - if (quest.getStage(player) >= 20) { - interpreter.sendDialogues(player, FacialExpression.HALF_GUILTY, "So you're still here."); - stage = 20; - } else { - interpreter.sendDialogues(player, FacialExpression.HALF_GUILTY, "Hello son, are you okay? You need help?"); - stage = 0; - } - return true; - } -} diff --git a/Server/src/main/content/region/kandarin/quest/waterfall/HudonDialogueFile.kt b/Server/src/main/content/region/kandarin/quest/waterfall/HudonDialogueFile.kt new file mode 100644 index 000000000..cbfd042c8 --- /dev/null +++ b/Server/src/main/content/region/kandarin/quest/waterfall/HudonDialogueFile.kt @@ -0,0 +1,54 @@ +package content.region.kandarin.quest.waterfall + +import content.data.Quests +import core.api.* +import core.game.dialogue.ChatAnim +import core.game.dialogue.DialogueLabeller + +class HudonDialogueFile : DialogueLabeller() { + override fun addConversation() { + exec { player, _ -> + when (getQuestStage(player, Quests.WATERFALL_QUEST)) { + 10 -> loadLabel(player, "quest_stage_10") + 20 -> loadLabel(player, "quest_stage_20") + 30 -> loadLabel(player, "quest_stage_30") + 100 -> loadLabel(player, "quest_complete") + } + } + + label("quest_stage_10") + player(ChatAnim.NEUTRAL, "Hello son, are you okay? You need help?") + npc(ChatAnim.CHILD_NORMAL, "It looks like you need the help.") + player(ChatAnim.NEUTRAL, "Your mum sent me to find you.") + npc(ChatAnim.CHILD_NORMAL, "Don't play nice with me, I know you're looking for the", "treasure too.") + player(ChatAnim.NEUTRAL, "Where is this treasure you talk of?") + npc(ChatAnim.CHILD_NORMAL, "Just because I'm small doesn't mean I'm dumb! If I", "told you, you would take it all for yourself.") + player(ChatAnim.NEUTRAL, "Maybe I could help.") + exec { player, _ -> + setQuestStage(player, Quests.WATERFALL_QUEST, 20) + sendMessage(player, "Hudon is refusing to leave the waterfall") /*sic*/ + } + npc(ChatAnim.CHILD_NORMAL, "I'm fine alone.") + + label("quest_stage_20") + player(ChatAnim.NEUTRAL, "So you're still here.") + npc(ChatAnim.CHILD_NORMAL, "I'll find that treasure soon, just you wait and see.") + + label("quest_stage_30") + player(ChatAnim.NEUTRAL, "Hello again.") + npc(ChatAnim.CHILD_NORMAL, "Not you still, why don't you give up?") + player(ChatAnim.NEUTRAL, "And miss all the fun!") + npc(ChatAnim.CHILD_NORMAL, "You do understand that anything you find you have to share with me.") + player(ChatAnim.NEUTRAL, "Why's that?") + npc(ChatAnim.CHILD_NORMAL, "Because I told you about the treasure.") + player(ChatAnim.NEUTRAL, "Well, I wouldn't count on it.") + npc(ChatAnim.CHILD_NORMAL, "That's not fair.") + player(ChatAnim.NEUTRAL, "Neither is life, kid.") + + label("quest_complete") + player(ChatAnim.NEUTRAL, "Hello again.") + npc(ChatAnim.CHILD_NORMAL, "You stole my treasure. I saw you!") + player(ChatAnim.NEUTRAL, "I'll make sure it goes to a good cause.") + npc(ChatAnim.CHILD_NORMAL, "Hmmmm!") + } +} \ No newline at end of file diff --git a/Server/src/main/content/region/kandarin/quest/waterfall/MithrilSeedsDialogue.java b/Server/src/main/content/region/kandarin/quest/waterfall/MithrilSeedsDialogue.java deleted file mode 100644 index 4a6c28e70..000000000 --- a/Server/src/main/content/region/kandarin/quest/waterfall/MithrilSeedsDialogue.java +++ /dev/null @@ -1,96 +0,0 @@ -package content.region.kandarin.quest.waterfall; - -import core.game.dialogue.DialoguePlugin; -import core.game.node.entity.player.Player; -import core.game.node.item.Item; -import core.game.node.scenery.Scenery; -import core.game.node.scenery.SceneryBuilder; -import core.game.system.task.Pulse; -import core.game.world.GameWorld; -import core.game.world.update.flag.context.Animation; -import core.plugin.Initializable; - -/** - * Represents the dialogue plugin used for mithril seeds. - * @author 'Vexia - * @version 1.0 - */ -@Initializable -public final class MithrilSeedsDialogue extends DialoguePlugin { - - /** - * Represents the animation to use. - */ - private static final Animation ANIMATION = new Animation(827); - - /** - * Represents the flower object. - */ - private Scenery flower; - - /** - * Constructs a new {@code MithrilSeedPluginDialogue}. - */ - public MithrilSeedsDialogue() { - /** - * empty. - */ - } - - /** - * Constructs a new {@code MithrilSeedPluginDialogue}. - */ - public MithrilSeedsDialogue(Player player) { - super(player); - } - - @Override - public DialoguePlugin newInstance(Player player) { - return new MithrilSeedsDialogue(player); - } - - @Override - public boolean open(Object... args) { - flower = (Scenery) args[0]; - player.getDialogueInterpreter().sendOptions("Select an Option", "Pick the flowers.", "Leave the flowers."); - return true; - } - - @Override - public boolean handle(int interfaceId, int buttonId) { - switch (interfaceId) { - case 228: // Options chatbox interface id. - switch (buttonId) { - case 1: // First option - player.lock(2); - player.faceLocation(flower.getFaceLocation(player.getLocation())); - player.animate(ANIMATION); - GameWorld.getPulser().submit(new Pulse(2, player, flower) { - @Override - public boolean pulse() { - Item reward = new Item(2460 + ((flower.getId() - 2980) << 1)); - if (reward == null || !player.getInventory().hasSpaceFor(reward)) { - player.getPacketDispatch().sendMessage("Not enough space in your inventory!"); - return true; - } - if (SceneryBuilder.remove(flower)) { - player.getInventory().add(reward); - player.getPacketDispatch().sendMessage("You pick the flowers."); - } - return true; - } - }); - break; - } - break; - } - end(); - return true; - } - - @Override - public int[] getIds() { - return new int[] { 1 << 16 | 1 }; - } - -} diff --git a/Server/src/main/content/region/kandarin/quest/waterfall/MithrilSeedsListener.kt b/Server/src/main/content/region/kandarin/quest/waterfall/MithrilSeedsListener.kt new file mode 100644 index 000000000..b0b194769 --- /dev/null +++ b/Server/src/main/content/region/kandarin/quest/waterfall/MithrilSeedsListener.kt @@ -0,0 +1,107 @@ +package content.region.kandarin.quest.waterfall + +import core.api.* +import core.game.dialogue.DialogueFile +import core.game.interaction.IntType +import core.game.interaction.InteractionListener +import core.game.interaction.QueueStrength +import core.game.node.scenery.Scenery +import core.game.world.GameWorld.ticks +import core.game.world.map.RegionManager.getObject +import core.game.world.update.flag.context.Animation +import core.tools.RandomFunction +import org.rs09.consts.Animations +import org.rs09.consts.Items +import org.rs09.consts.Scenery as SceneryObj + +/** + * Handles planting flowers with mithril seeds. + * @author Bishop + */ + +class MithrilSeedsListener : InteractionListener { + + companion object { + private val attributeDelay = "mithril-flowers:delay" + private val flowersToItems = mapOf( + SceneryObj.FLOWERS_2980 to Items.FLOWERS_2460, // multicolored pastels + SceneryObj.FLOWERS_2981 to Items.FLOWERS_2462, // red + SceneryObj.FLOWERS_2982 to Items.FLOWERS_2464, // blue + SceneryObj.FLOWERS_2983 to Items.FLOWERS_2466, // yellow + SceneryObj.FLOWERS_2984 to Items.FLOWERS_2468, // magenta + SceneryObj.FLOWERS_2985 to Items.FLOWERS_2470, // orange + SceneryObj.FLOWERS_2986 to Items.FLOWERS_2472, // multicolored primaries + SceneryObj.FLOWERS_2987 to Items.FLOWERS_2474, // white + SceneryObj.FLOWERS_2988 to Items.FLOWERS_2476, // black + ) + } + + override fun defineListeners() { + on(Items.MITHRIL_SEEDS_299, IntType.ITEM, "plant") { player, _ -> + closeAllInterfaces(player) + val flowerLoc = player.location + if (getAttribute(player, attributeDelay, -1) > ticks) { + return@on false + } + if (getObject(flowerLoc) != null) { + sendMessage(player, "You can't plant a flower here.") + return@on true + } + if (removeItem(player, Items.MITHRIL_SEEDS_299)) { + // Source: Mod Ash https://reldo.runescape.wiki/i/106311 + val flowerObj = when (RandomFunction.random(1001)) { + in 0..897 -> RandomFunction.random(SceneryObj.FLOWERS_2981, SceneryObj.FLOWERS_2986 + 1) // normal flowers + in 898..997 -> SceneryObj.FLOWERS_2980 // multicolored pastels, 100/1001 + in 998..999 -> SceneryObj.FLOWERS_2988 // black flowers, 2/1001 + else -> SceneryObj.FLOWERS_2987 // white flowers, 1/1001 + } + val thisFlower = addScenery(flowerObj, flowerLoc, 0, 10) + sendMessage(player, "You open the small mithril case and drop a seed by your feet.") + setAttribute(player, attributeDelay, ticks + 3) + animate(player, Animations.HUMAN_BURYING_BONES_827) + stopWalk(player) + player.moveStep() + lock(player, 1) + queueScript(player, 1, QueueStrength.SOFT) { + face(player, flowerLoc) + openDialogue(player, MithrilSeedsDialogue(thisFlower, flowersToItems[thisFlower.id]!!)) + return@queueScript stopExecuting(player) + } + queueScript(player, 100, QueueStrength.SOFT) { + removeScenery(thisFlower) + return@queueScript stopExecuting(player) + } + } + return@on true + } + } + +} + +private class MithrilSeedsDialogue(val flower: Scenery, val flowerItem: Int) : DialogueFile() { + + override fun handle(componentID: Int, buttonID: Int) { + when (stage) { + 0 -> sendDialogueOptions(player!!, "Select an Option", "Pick the flowers.", "Leave the flowers.").also { stage++ } + 1 -> { + when (buttonID) { + 1 -> { + animate(player!!, Animations.HUMAN_BURYING_BONES_827) + lock(player!!, 2) + queueScript(player!!, 2, QueueStrength.SOFT) { + if (getScenery(flower.location) == flower) { + sendMessage(player!!, "You pick the flowers.") + removeScenery(flower) + addItemOrDrop(player!!, flowerItem) + } + return@queueScript stopExecuting(player!!) + } + end() + } + else -> end() + } + } + } + } + +} \ No newline at end of file diff --git a/Server/src/main/content/region/kandarin/quest/waterfall/MithrilSeedsPlugin.java b/Server/src/main/content/region/kandarin/quest/waterfall/MithrilSeedsPlugin.java deleted file mode 100644 index b085e42e2..000000000 --- a/Server/src/main/content/region/kandarin/quest/waterfall/MithrilSeedsPlugin.java +++ /dev/null @@ -1,92 +0,0 @@ -package content.region.kandarin.quest.waterfall; - -import core.cache.def.impl.ItemDefinition; -import core.game.interaction.OptionHandler; -import core.game.node.Node; -import core.game.node.entity.player.Player; -import core.game.node.item.Item; -import core.game.node.scenery.Scenery; -import core.game.node.scenery.SceneryBuilder; -import core.game.system.task.Pulse; -import core.game.world.GameWorld; -import core.game.world.map.RegionManager; -import core.game.world.update.flag.context.Animation; -import core.plugin.Initializable; -import core.plugin.Plugin; -import core.tools.RandomFunction; - -/** - * Represents the plugin used for mithril seeds. - * @author 'Vexia - * @version 1.2 - */ -@Initializable -public final class MithrilSeedsPlugin extends OptionHandler { - - /** - * Represents the item to use. - */ - private static final Item ITEM = new Item(299, 1); - - /** - * Represents the common flower ids. - */ - private static final int FLOWERS[] = { 2980, 2981, 2982, 2983, 2984, 2985, 2986 }; - - /** - * Represents the rare flower ids. - */ - private static final int RARE[] = new int[] { 2987, 2988 }; - - /** - * Represents the animation. - */ - private static final Animation ANIMATION = new Animation(827); - - @Override - public Plugin newInstance(Object arg) throws Throwable { - ItemDefinition.forId(299).getHandlers().put("option:plant", this); - return this; - } - - @Override - public boolean handle(final Player player, Node node, String option) { - if (player.getAttribute("delay:plant", -1) > GameWorld.getTicks()) { - return true; - } - if (RegionManager.getObject(player.getLocation()) != null) { - player.getPacketDispatch().sendMessage("You can't plant a flower here."); - return true; - } - player.animate(ANIMATION); - player.getInventory().remove(ITEM); - final Scenery object = SceneryBuilder.add(new Scenery(getFlower(RandomFunction.random(100) == 1 ? RARE : FLOWERS), player.getLocation()), 100); - player.moveStep(); - player.lock(3); - player.getPulseManager().run(new Pulse(1, player) { - @Override - public boolean pulse() { - player.faceLocation(object.getFaceLocation(player.getLocation())); - player.getDialogueInterpreter().open(1 << 16 | 1, object); - return true; - } - }); - player.setAttribute("delay:plant", GameWorld.getTicks() + 3); - player.getPacketDispatch().sendMessage("You open the small mithril case and drop a seed by your feet."); - return true; - } - - @Override - public boolean isWalk() { - return false; - } - - /** - * Gets a random flower from an array. - * @return the flower. - */ - public static int getFlower(int[] array) { - return array[RandomFunction.random(array.length)]; - } - -} diff --git a/Server/src/main/content/region/kandarin/quest/waterfall/WaterFall.java b/Server/src/main/content/region/kandarin/quest/waterfall/WaterFall.java deleted file mode 100644 index 33030e29a..000000000 --- a/Server/src/main/content/region/kandarin/quest/waterfall/WaterFall.java +++ /dev/null @@ -1,85 +0,0 @@ -package content.region.kandarin.quest.waterfall; - -import content.data.Quests; -import core.plugin.Initializable; -import core.game.node.entity.skill.Skills; -import core.game.node.entity.player.Player; -import core.game.node.entity.player.link.quest.Quest; -import core.game.node.item.Item; -import core.plugin.ClassScanner; - -/** - * The main type for the waterfall quest. - * @author Splinter - */ -@Initializable -public class WaterFall extends Quest { - /** - * Constructs a new {@code WaterFall} {@code Object}. - */ - public WaterFall() { - super(Quests.WATERFALL_QUEST, 65, 64, 1, 65, 0, 1, 10); - } - - @Override - public void drawJournal(Player player, int stage) { - super.drawJournal(player, stage); - switch (stage) { - case 0: - line(player, "I can start this quest by speaking to Almera in her house next to the Baxtorian Falls.I need to be able to fight Level 84 Giants.", 12); - break; - case 10: - line(player, "I spoke to Almera in a house close to the Baxtorianwaterfall. Her son was missing so I offered to help findhim. The boy, Hudon's looking for treasure in the waterfall.", 12); - break; - case 20: - line(player, "I spoke to Almera in a house close to the Baxtorianwaterfall. Her son was missing so I offered to help findhim. The boy, Hudon's looking for treasure in the waterfall.I found Hudon a short raft ride down the river. He isconvinced there is treasure here somewhere. Maybe Ineed to do a little research.", 12); - break; - case 30: - if (player.getInventory().containsItem(new Item(294, 1))) { - line(player, "I spoke to Almera in a house close to the Baxtorianwaterfall. Her son was missing so I offered to help findhim. The boy, Hudon's looking for treasure in the waterfall.I found Hudon a short raft ride down the river. He isconvinced there is treasure here somewhere. Maybe Ineed to do a little research.I found a book in the tourist office about Baxtorian. Thebook tells of a sad love story about 2 elf lovers. It endswith Baxtorian withdrawing to his home under the waterfallafter his wife dies. It is told that only Glarial could entertheir home.The book also mentions Glarial's tomb and a pebble, itappears that the pebble is used to enter the tomb.From what I understand Glarial's pebble was hidden in a cave under the Tree Gnome Village by Golrie's ancestors.", 12); - } else { - line(player, "I spoke to Almera in a house close to the Baxtorianwaterfall. Her son was missing so I offered to help findhim. The boy, Hudon's looking for treasure in the waterfall.I found Hudon a short raft ride down the river. He isconvinced there is treasure here somewhere. Maybe Ineed to do a little research.I found a book in the tourist office about Baxtorian. Thebook tells of a sad love story about 2 elf lovers. It endswith Baxtorian withdrawing to his home under the waterfallafter his wife dies. It is told that only Glarial could entertheir home.The book also mentions Glarial's tomb and a pebble, itappears that the pebble is used to enter the tomb.From what I understand Glarial's pebble was hidden in a cave under the Tree Gnome Village by Golrie's ancestors.", 12); - } - if (player.getInventory().containsItem(new Item(295, 1)) || player.getEquipment().containsAtLeastOneItem(295)) { - line(player, "I spoke to Almera in a house close to the Baxtorianwaterfall. Her son was missing so I offered to help findhim. The boy, Hudon's looking for treasure in the waterfall.I found Hudon a short raft ride down the river. He isconvinced there is treasure here somewhere. Maybe Ineed to do a little research.I found a book in the tourist office about Baxtorian. Thebook tells of a sad love story about 2 elf lovers. It endswith Baxtorian withdrawing to his home under the waterfallafter his wife dies. It is told that only Glarial could entertheir home.The book also mentions Glarial's tomb and a pebble, itappears that the pebble is used to enter the tomb.From what I understand Glarial's pebble was hidden in a cave under the Tree Gnome Village by Golrie's ancestors.Inside the tomb I found Glarial's amulet and ashes.", 12); - } - if (player.getLocation().getY() >= 9902) { - line(player, "I spoke to Almera in a house close to the Baxtorianwaterfall. Her son was missing so I offered to help findhim. The boy, Hudon's looking for treasure in the waterfall.I found Hudon a short raft ride down the river. He isconvinced there is treasure here somewhere. Maybe Ineed to do a little research.I found a book in the tourist office about Baxtorian. Thebook tells of a sad love story about 2 elf lovers. It endswith Baxtorian withdrawing to his home under the waterfallafter his wife dies. It is told that only Glarial could entertheir home.The book also mentions Glarial's tomb and a pebble, itappears that the pebble is used to enter the tomb.From what I understand Glarial's pebble was hidden in a cave under the Tree Gnome Village by Golrie's ancestors.Inside the tomb I found Glarial's amulet and ashes.I finally got access to the derelict home of Baxtorian. Thedoor must have been keyed to Glarial's amulet.I have found a room containing the Chalice of Eternity. Thechalice is suspended in midair just out of reach.", 12); - } - break; - case 100: - line(player, "I spoke to Almera in a house close to the Baxtorianwaterfall. Her son was missing so I offered to help findhim. The boy, Hudon's looking for treasure in the waterfall.I found Hudon a short raft ride down the river. He isconvinced there is treasure here somewhere. Maybe Ineed to do a little research.I found a book in the tourist office about Baxtorian. Thebook tells of a sad love story about 2 elf lovers. It endswith Baxtorian withdrawing to his home under the waterfallafter his wife dies. It is told that only Glarial could entertheir home.The book also mentions Glarial's tomb and a pebble, itappears that the pebble is used to enter the tomb.From what I understand Glarial's pebble was hidden in a cave under the Tree Gnome Village by Golrie's ancestors.Inside the tomb I found Glarial's amulet and ashes.I finally got access to the derelict home of Baxtorian. Thedoor must have been keyed to Glarial's amulet.I have found a room containing the Chalice of Eternity. Thechalice is suspended in midair just out of reach. Using Glarial's ashes as a counterweight, I was able toremove the treasure that had been left in the chalice.QUEST COMPLETE!", 12); - break; - } - } - - @Override - public void finish(Player player) { - super.finish(player); - player.getQuestRepository().syncronizeTab(player); - - player.getPacketDispatch().sendString("1 Quest Point", 277, 8+ 2); - player.getPacketDispatch().sendString("13,750 Strength XP", 277, 9+ 2); - player.getPacketDispatch().sendString("13,750 Attack XP", 277, 10+ 2); - player.getPacketDispatch().sendString("2 diamonds", 277, 11+ 2); - player.getPacketDispatch().sendString("2 gold bars", 277, 12+ 2); - player.getPacketDispatch().sendString("40 Mithril seeds", 277, 13+ 2); - player.getPacketDispatch().sendString("You have completed the Waterfall Quest!", 277, 2+ 2); - player.getPacketDispatch().sendItemZoomOnInterface(1601, 230, 277, 3+ 2); - player.getSkills().addExperience(Skills.STRENGTH, 13750); - player.getSkills().addExperience(Skills.ATTACK, 13750); - player.getInventory().add(new Item(1601, 2));// diamonds - player.getInventory().add(new Item(2357, 2));// gold bars - player.getInventory().add(new Item(299, 40));// seeds - - setStage(player, 100); - player.getQuestRepository().syncronizeTab(player); - } - - @Override - public Quest newInstance(Object object) { - ClassScanner.definePlugins(new AlmeraDialogue(), new GolrieDialogue(), new HadleyDialogue(), new HudonDialogue(), new WaterfallPlugin(), new WaterfallTreeDialogue()); - return this; - } - -} diff --git a/Server/src/main/content/region/kandarin/quest/waterfall/WaterfallListeners.kt b/Server/src/main/content/region/kandarin/quest/waterfall/WaterfallListeners.kt index 8358b1a5a..3d6d107cb 100644 --- a/Server/src/main/content/region/kandarin/quest/waterfall/WaterfallListeners.kt +++ b/Server/src/main/content/region/kandarin/quest/waterfall/WaterfallListeners.kt @@ -4,20 +4,22 @@ import content.data.Quests import content.global.skill.agility.AgilityHandler import core.api.* import core.cache.def.impl.ItemDefinition -import core.game.dialogue.ChatAnim +import core.game.dialogue.DialogueLabeller import core.game.global.action.DoorActionHandler import core.game.interaction.InteractionListener import core.game.interaction.IntType import core.game.interaction.QueueStrength import core.game.node.entity.combat.ImpactHandler.HitsplatType import core.game.node.entity.npc.NPC -import core.game.node.entity.player.Player import core.game.node.scenery.Scenery import core.game.world.map.Location import core.game.world.update.flag.context.Animation import core.game.world.update.flag.context.Graphics +import core.tools.ticksToCycles +import org.rs09.consts.Animations import org.rs09.consts.Items import org.rs09.consts.NPCs +import java.util.concurrent.atomic.AtomicBoolean import org.rs09.consts.Scenery as SceneryObj /** @@ -31,50 +33,59 @@ class WaterfallListeners : InteractionListener { companion object { // Animations - private val animationSwim = Animation(164) - private val animationRopeToss = Animation(774) - private val animationRopeWalk = Animation(273) - private val animationRopeDone = Animation(780) + private val animationSwim = Animation(164) + private val animationRopeToss = Animation(774) + private val animationRopeWalk = Animation(776) + private val animationDrowning = Animation(765) + private val animationWhirlpool = Animation(528) + private val animationRenderRopeWalk = Animation(273) + private val animationRenderDrowning = Animation(163) + private val animationRenderWhirlpool = Animation(847) // Attributes - private const val attributeRunes = "waterfall:runes-placed" + private const val attributeRunes = "waterfall:runes-placed" // Graphics - private val graphicsSplash = Graphics(68) - private val graphicsRunePoof = Graphics(580) - private val graphicsRocksFall = Graphics(74) - // Lists - private val listOfSwimmers : MutableList = ArrayList(20) + private val graphicRopeToss = Graphics(67) + private val graphicsSplash = Graphics(68) + private val graphicsRunePoof = Graphics(580, 250) + private val graphicsRocksFall = Graphics(74) + // Flags + private val someoneIsSwimming = AtomicBoolean(false) // Locations - private val locHudonTalk = Location(2512, 3481) - private val locIslandAfterRaft = Location(2512, 3481) - private val locIslandBeforeRock = Location(2512, 3476) - private val locSwimmingGoal = Location(2512, 3471) - private val locInFrontOfRock = Location(2512, 3469) - private val locRock = Location(2512, 3468) - private val locIslandAfterRock = Location(2513, 3468) - private val locWaterfallLedge = Location(2511, 3463) - private val locDownstream = Location(2527, 3413) - private val locInsideTomb = Location(2555, 9844) - private val locInWaterfallCave = Location(2575, 9861) - private val locWaterfallDoorSouth = Location(2568, 9893) - private val locWaterfallDoorNorth = Location(2566, 9901) - private val locWaterfallDoorChamber = Location(2604, 9900) - private val locBeforeFinalStatue = Location(2603, 9914) + private val locIslandAfterRaft = Location(2512, 3481) + private val locIslandBeforeRock = Location(2512, 3476) + private val locSwimmingGoal = Location(2512, 3471) + private val locInFrontOfRock = Location(2512, 3470) + private val locRock = Location(2512, 3468) + private val locWaterfallLedge = Location(2511, 3463) + private val locDownstream = Location(2527, 3413) + private val locInsideTomb = Location(2555, 9844) + private val locInWaterfallCave = Location(2575, 9861) + private val locWaterfallDoorSouth = Location(2568, 9893) + private val locWaterfallDoorNorth = Location(2566, 9901) + private val locWaterfallDoorChamber = Location(2604, 9900) + private val locBeforeFloodedStatue = Location(2539, 9914) + private val locBeforeFinalStatue = Location(2603, 9914) // Misc data - private val ropeYSpan = intArrayOf(3469, 3475) - private const val locGnomeCaveDoorY = 9576 - private val pedestalLocations = arrayOf( + private val ropeYSpan = intArrayOf(3469, 3470, 3471, 3472, 3473, 3474, 3475) + private val pedestalLocations = arrayOf( Location(2562, 9914), Location(2562, 9912), Location(2562, 9910), Location(2569, 9914), Location(2569, 9912), Location(2569, 9910), ) private val runes = intArrayOf( Items.WATER_RUNE_555, Items.AIR_RUNE_556, Items.EARTH_RUNE_557, ) + private val anyRunes = intArrayOf( + Items.FIRE_RUNE_554, Items.WATER_RUNE_555, Items.AIR_RUNE_556, Items.EARTH_RUNE_557, Items.MIND_RUNE_558, + Items.BODY_RUNE_559, Items.DEATH_RUNE_560, Items.NATURE_RUNE_561, Items.CHAOS_RUNE_562, Items.LAW_RUNE_563, + Items.COSMIC_RUNE_564, Items.BLOOD_RUNE_565, Items.SOUL_RUNE_566, Items.ASTRAL_RUNE_9075, Items.STEAM_RUNE_4694, + Items.MIST_RUNE_4695, Items.DUST_RUNE_4696, Items.SMOKE_RUNE_4697, Items.MUD_RUNE_4698, Items.LAVA_RUNE_4699 + ) } override fun defineListeners() { // Speak to Hudon on(NPCs.HUDON_305, IntType.NPC, "talk-to") { player, node -> - openDialogue(player, node as NPC) + DialogueLabeller.open(player, HudonDialogueFile(), node as NPC) return@on true } @@ -82,7 +93,7 @@ class WaterfallListeners : InteractionListener { on(SceneryObj.LOG_RAFT_1987, IntType.SCENERY, "board") { player, _ -> if (getQuestStage(player, Quests.WATERFALL_QUEST) >= 10) { lock(player, 13) - queueScript(player, 2, QueueStrength.SOFT) { stage -> + queueScript(player, 2, QueueStrength.STRONG) { stage -> when (stage) { 0 -> { sendMessage(player, "You board the small raft") @@ -112,9 +123,6 @@ class WaterfallListeners : InteractionListener { // Try to swim to the rock at the waterfall, or just swim in general on(intArrayOf(SceneryObj.ROCK_1996, SceneryObj.ROCK_1997, SceneryObj.RIVER_10283), IntType.SCENERY, "swim to", "swim") { player, _ -> - registerLogoutListener(player, "waterfall") { player: Player -> - teleport(player, locIslandBeforeRock) - } sendMessage(player, "It looks like a long distance, but you swim out into the water.") sendGraphics(graphicsSplash, player.location) AgilityHandler.walk( @@ -130,7 +138,6 @@ class WaterfallListeners : InteractionListener { 1 -> { sendMessage(player, "You are washed downstream but feel lucky to be alive.") teleport(player, locDownstream) - clearLogoutListener(player, "waterfall") return@queueScript stopExecuting(player) } else -> return@queueScript stopExecuting(player) @@ -141,44 +148,50 @@ class WaterfallListeners : InteractionListener { // Correctly use a rope on the rock at the waterfall onUseWith(IntType.SCENERY, Items.ROPE_954, SceneryObj.ROCK_1996, SceneryObj.ROCK_1997) { player, _, _ -> - registerLogoutListener(player, "waterfall") { player: Player -> - teleport(player, locIslandBeforeRock) + if (someoneIsSwimming.get()) { + sendMessage(player, "Someone else is already doing that.") // Assumed, copied from blast furnace + return@onUseWith true } - lock(player, 8) + someoneIsSwimming.set(true) animate(player, animationRopeToss) - if (listOfSwimmers.isEmpty()) { - listOfSwimmers.add(player) - replaceScenery(getScenery(locRock)!!, SceneryObj.ROCK_1997, -1) - for (y in ropeYSpan[0]..ropeYSpan[1]) { - addScenery(Scenery(SceneryObj.ROPE_1998, Location(locRock.x, y), 10, 0)) - } - } - queueScript(player, 2, QueueStrength.SOFT) { stage -> + sendGraphics(graphicRopeToss, Location(locRock.x, ropeYSpan[3])) + lock(player, 9) + queueScript(player, 1, QueueStrength.SOFT) { stage -> when (stage) { 0 -> { - face(player, locRock) - AgilityHandler.walk( - player, -1, player.location, locInFrontOfRock, animationRopeWalk, 0.0, null - ) - return@queueScript delayScript(player, 8) - } - 1 -> { - teleport(player, locIslandAfterRock) - return@queueScript keepRunning(player) - } - 2 -> { - face(player, locRock) - animate(player, animationRopeDone) - return@queueScript animationFinished(player) - } - 3 -> { - clearLogoutListener(player, "waterfall") - if (listOfSwimmers.remove(player) && listOfSwimmers.isEmpty()) { - replaceScenery(getScenery(locRock)!!, SceneryObj.ROCK_1996, -1) - for (y in ropeYSpan[0]..ropeYSpan[1]) { - removeScenery(Scenery(SceneryObj.ROPE_1998, Location(locRock.x, y), 10, 0)) - } + replaceScenery(getScenery(locRock)!!, SceneryObj.ROCK_1997, -1) + for (y in ropeYSpan[0]..ropeYSpan[6]) { + addScenery(Scenery(SceneryObj.ROPE_1998, Location(locRock.x, y), 10, 0)) } + face(player, locRock) + player.appearance.setAnimations(animationRenderRopeWalk) + player.appearance.sync() + AgilityHandler.walk( + player, -1, player.location, locInFrontOfRock, null, 0.0, null + ) + return@queueScript delayScript(player, 1) + } + in 1..6 -> { + removeScenery(Scenery(SceneryObj.ROPE_1998, Location(locRock.x, ropeYSpan[7 - stage]), 10, 0)) + if (stage == 1 && getScenery(locRock.x, ropeYSpan[6], 0) == null) { + addScenery(SceneryObj.RIVER_10283, Location(locRock.x, ropeYSpan[6])) + } + return@queueScript delayScript(player, 1) + } + 7 -> { + AgilityHandler.walk( + player, -1, player.location, locInFrontOfRock.transform(1, -1, 0), null, 0.0, null + ) + replaceScenery(getScenery(locRock)!!, SceneryObj.ROCK_1996, -1) + removeScenery(Scenery(SceneryObj.ROPE_1998, Location(locRock.x, ropeYSpan[0]), 10, 0)) + return@queueScript delayScript(player, 1) + } + 8 -> { + player.appearance.setDefaultAnimations() + player.appearance.setAnimations() + player.appearance.sync() + forceMove(player, player.location, locInFrontOfRock.transform(1, -2, 0), 0, ticksToCycles(1)) + someoneIsSwimming.set(false) return@queueScript stopExecuting(player) } else -> return@queueScript stopExecuting(player) @@ -189,22 +202,29 @@ class WaterfallListeners : InteractionListener { // Try to climb down the tree at the waterfall barehanded on(SceneryObj.DEAD_TREE_2020, IntType.SCENERY, "climb") { player, _ -> - player.dialogueInterpreter.open("waterfall_tree_dialogue", 0) + openDialogue(player, WaterfallTreeDialogueFile()) return@on true } // Correctly use a rope on the tree at the waterfall onUseWith(IntType.SCENERY, Items.ROPE_954, SceneryObj.DEAD_TREE_2020) { player, _, _ -> - sendMessage(player, "You tie the rope to the tree and let yourself down on the ledge.") - teleport(player, locWaterfallLedge) + sendMessage(player, "You tie the rope to the tree") + queueScript(player, 1, QueueStrength.STRONG) { + sendMessage(player, "and let your self down on to the ledge.") + teleport(player, locWaterfallLedge) + return@queueScript stopExecuting(player) + } return@onUseWith true } // Get in the barrel on the waterfall's ledge on(SceneryObj.BARREL_2022, IntType.SCENERY, "get in") { player, _ -> sendMessage(player, "You get in the barrel and start rocking.") - sendMessage(player, "The barrel falls off the ledge.") - teleport(player, locDownstream) + queueScript(player, 1, QueueStrength.STRONG) { + sendMessage(player, "The barrel falls off the ledge.") + teleport(player, locDownstream) + return@queueScript stopExecuting(player) + } return@on true } @@ -213,7 +233,8 @@ class WaterfallListeners : InteractionListener { if (inInventory(player, Items.BOOK_ON_BAXTORIAN_292) || getQuestStage(player, Quests.WATERFALL_QUEST) != 20) { sendMessage(player, "You search the bookcase and find nothing of interest.") } else { - sendMessage(player, "You search the bookcase and find a book named 'Book on Baxtorian'") + sendMessage(player, "You search the bookcase...") + sendMessage(player, "You find a book named 'Book on Baxtorian'") addItemOrDrop(player, Items.BOOK_ON_BAXTORIAN_292) } return@on true @@ -224,58 +245,40 @@ class WaterfallListeners : InteractionListener { if (inInventory(player, Items.A_KEY_293) || getQuestStage(player, Quests.WATERFALL_QUEST) < 30) { sendMessage(player, "You search the crate and find nothing.") } else { - sendMessage(player, "You find a large key.") - addItemOrDrop(player, Items.A_KEY_293) + sendMessage(player, "You search the crate...") + queueScript(player, 2, QueueStrength.WEAK) { // Weak so you can most easily be harangued by enemies + sendMessage(player, "and find a large key.") + addItemOrDrop(player, Items.A_KEY_293) + return@queueScript stopExecuting(player) + } } return@on true } // Access the door in the gnome cave on(SceneryObj.DOOR_1991, IntType.SCENERY, "open") { player, node -> - if (player.getLocation().y >= locGnomeCaveDoorY) { + if (player.location.y > node.location.y) { sendMessage(player, "You open the gate and walk through.") DoorActionHandler.handleAutowalkDoor(player, node as Scenery) - } else if (inInventory(player, Items.A_KEY_293)) { - sendMessage(player, "The gate is locked. You need to use the key on the door to enter.") + return@on true } else { - sendNPCDialogueLines( - player, NPCs.GOLRIE_306, ChatAnim.HALF_GUILTY, false, - "Hello? Ah yes, the door is still locked.", - "If you want to get in here, you'll need to find the key", - "that I hid in some crates in the eastern room." - ) + sendMessage(player, "The gate is locked.") } + val startLabel = if (getQuestStage(player, Quests.WATERFALL_QUEST) >= 30) { "door_on_quest" } else { "door_no_business_here" } + DialogueLabeller.open(player, GolrieDialogueFile(startLabel), findLocalNPC(player, NPCs.GOLRIE_306)?: return@on true) return@on true } // Use the key on the door in the gnome cave onUseWith(IntType.SCENERY, Items.A_KEY_293, SceneryObj.DOOR_1991) { player, _, with -> sendMessage(player, "The key fits the gate.") - sendMessage(player, "You open the gate and walk through.") - DoorActionHandler.handleAutowalkDoor(player, with as Scenery) - return@onUseWith true - } - - // Enter the waterfall cave - on(SceneryObj.LEDGE_37247, IntType.SCENERY, "open") { player, _ -> - sendMessage(player, "The door opens...") - queueScript(player, 2, QueueStrength.SOFT) { - if ((inInventory(player, Items.GLARIALS_AMULET_295) || inEquipment(player, Items.GLARIALS_AMULET_295)) || isQuestComplete(player, Quests.WATERFALL_QUEST)) { - sendMessage(player, "You walk through the door.") - teleport(player, locInWaterfallCave) - } else { - sendMessage(player, "The cave floods and washes you away!") - teleport(player, locDownstream) - } + lock(player, 3) + queueScript(player, 3, QueueStrength.STRONG) { + sendMessage(player, "You open the gate and walk through.") + DoorActionHandler.handleAutowalkDoor(player, with as Scenery) return@queueScript stopExecuting(player) } - return@on true - } - - // Exit the waterfall cave through the entrance - on(SceneryObj.DOOR_32711, IntType.SCENERY, "open") { player, _ -> - teleport(player, locWaterfallLedge) - return@on true + return@onUseWith true } // Read Glarial's tombstone @@ -315,15 +318,20 @@ class WaterfallListeners : InteractionListener { // Enter Glarial's tomb with the pebble onUseWith(IntType.SCENERY, Items.GLARIALS_PEBBLE_294, SceneryObj.GLARIAL_S_TOMBSTONE_1992) { player, _, _ -> - if (ItemDefinition.canEnterEntrana(player)) { - if (player.familiarManager.hasFamiliar()) { - sendMessage(player, "You can't take a follower into the tomb.") - return@onUseWith true - } + // A more strict frisk than Entrana + if (!ItemDefinition.canEnterEntrana(player) || anyInInventory(player, *anyRunes)) { sendMessage(player, "You place the pebble in the gravestone's small indent.") sendMessage(player, "It fits perfectly.") - lock(player, 13) - queueScript(player, 4, QueueStrength.SOFT) { stage -> + lock(player, 3) + queueScript(player, 3, QueueStrength.SOFT) { + sendMessage(player, "But nothing happens.") + return@queueScript stopExecuting(player) + } + } else { + sendMessage(player, "You place the pebble in the gravestone's small indent.") + sendMessage(player, "It fits perfectly.") + lock(player, 10) + queueScript(player, 3, QueueStrength.SOFT) { stage -> when (stage) { 0 -> { sendMessage(player, "You hear a loud creak.") @@ -331,13 +339,10 @@ class WaterfallListeners : InteractionListener { } 1 -> { sendMessage(player, "The stone slab slides back revealing a ladder down.") - return@queueScript delayScript(player, 5) + return@queueScript delayScript(player, 4) } 2 -> { sendMessage(player, "You climb down to an underground passage.") - return@queueScript delayScript(player, 1) - } - 3 -> { player.skills.setPrayerPoints(0.0) teleport(player, locInsideTomb) return@queueScript stopExecuting(player) @@ -345,19 +350,13 @@ class WaterfallListeners : InteractionListener { else -> return@queueScript stopExecuting(player) } } - } else { - sendMessage(player, "You place the pebble in the gravestone's small indent.") - sendMessage(player, "It fits perfectly.") - queueScript(player, 4, QueueStrength.SOFT) { - sendMessage(player, "But nothing happens.") - return@queueScript stopExecuting(player) - } } return@onUseWith true } // Open the treasure chest in Glarial's tomb - on(SceneryObj.CLOSED_CHEST_33046, IntType.SCENERY, "open") { _, node -> + on(SceneryObj.CLOSED_CHEST_33046, IntType.SCENERY, "open") { player, node -> + animate(player, Animations.HUMAN_OPEN_CHEST_536) replaceScenery(node as Scenery, SceneryObj.OPEN_CHEST_33047, -1) return@on true } @@ -376,7 +375,8 @@ class WaterfallListeners : InteractionListener { } // Close the treasure chest in Glarial's tomb - on(SceneryObj.OPEN_CHEST_33047, IntType.SCENERY, "close") { _, node -> + on(SceneryObj.OPEN_CHEST_33047, IntType.SCENERY, "close") { player, node -> + animate(player, Animations.HUMAN_CLOSE_CHEST_535) replaceScenery(node as Scenery, SceneryObj.CLOSED_CHEST_33046, -1) return@on true } @@ -387,41 +387,76 @@ class WaterfallListeners : InteractionListener { if (inInventory(player, Items.GLARIALS_URN_296)) { sendMessage(player, "You search the coffin and find nothing.") } else { - sendMessage(player, "You search the coffin and inside you find an urn full of ashes.") - addItemOrDrop(player, Items.GLARIALS_URN_296) + sendMessage(player, "You search the coffin") + queueScript(player, 2, QueueStrength.WEAK) { stage -> // Weak so you can most easily be harangued by enemies + when (stage) { + 0 -> { + sendMessage(player, "Inside you find an urn full of ashes.") + return@queueScript delayScript(player, 2) + } + 1 -> { + sendMessage(player, "You take the urn and close the coffin.") + addItemOrDrop(player, Items.GLARIALS_URN_296) + return@queueScript stopExecuting(player) + } + else -> return@queueScript stopExecuting(player) + } + } } } return@on true } + // Enter the waterfall cave + on(SceneryObj.LEDGE_37247, IntType.SCENERY, "open") { player, _ -> + sendMessage(player, "The door begins to open.") + queueScript(player, 2, QueueStrength.STRONG) { + if ((inInventory(player, Items.GLARIALS_AMULET_295) || inEquipment(player, Items.GLARIALS_AMULET_295)) || isQuestComplete(player, Quests.WATERFALL_QUEST)) { + queueScript(player, 2, QueueStrength.STRONG) { + sendMessage(player, "You walk through the door.") + teleport(player, locInWaterfallCave) + } + } else { + sendMessage(player, "The cave floods and washes you away!") + teleport(player, locDownstream) + } + return@queueScript stopExecuting(player) + } + return@on true + } + + // Exit the waterfall cave through the entrance + on(SceneryObj.DOOR_32711, IntType.SCENERY, "open") { player, _ -> + teleport(player, locWaterfallLedge) + return@on true + } + // Search the crate in the waterfall cave on(SceneryObj.CRATE_1999, IntType.SCENERY, "search") { player, _ -> if (inInventory(player, Items.A_KEY_298, 1) || getQuestStage(player, Quests.WATERFALL_QUEST) < 30) { sendMessage(player, "You search the crate and find nothing.") } else { - sendMessage(player, "You find a large key.") - addItemOrDrop(player, Items.A_KEY_298, 1) + sendMessage(player, "You search the crate") + queueScript(player, 2, QueueStrength.WEAK) { // Weak so you can most easily be harangued by enemies + sendMessage(player, "and find a large key") + addItemOrDrop(player, Items.A_KEY_298) + return@queueScript stopExecuting(player) + } } return@on true } // Interact with the doors directly ahead of the waterfall cave's inner chamber on(SceneryObj.DOOR_2002, IntType.SCENERY, "open") { player, node -> - when (player.location) { - locWaterfallDoorSouth -> { - sendMessage(player, "The door is locked.") - } - locWaterfallDoorSouth.transform(0, 1, 0) -> { - DoorActionHandler.handleAutowalkDoor(player, node as Scenery) - } - locWaterfallDoorNorth -> { - if (isQuestComplete(player, Quests.WATERFALL_QUEST)) { - teleport(player, locWaterfallDoorChamber.transform(0, 1, 0)) + when (node.location) { + locWaterfallDoorSouth, locWaterfallDoorNorth -> { + if (player.location != locWaterfallDoorNorth.transform(0, 1, 0)) { + sendMessage(player, "The door is locked.") } else { DoorActionHandler.handleAutowalkDoor(player, node as Scenery) } } - locWaterfallDoorChamber.transform(0, 1, 0) -> { + locWaterfallDoorChamber -> { teleport(player, locWaterfallDoorNorth) removeAttribute(player, attributeRunes) } @@ -432,12 +467,19 @@ class WaterfallListeners : InteractionListener { // Use the key on the door to the waterfall cave's inner chamber onUseWith(IntType.SCENERY, Items.A_KEY_298, SceneryObj.DOOR_2002) { player, _, with -> - if (player.location == locWaterfallDoorSouth) { - sendMessage(player, "You open the door and walk through.") - DoorActionHandler.handleAutowalkDoor(player, with as Scenery) + val locInChamber = locWaterfallDoorChamber.transform(0, 1, 0) + sendMessage(player, "You open the door and walk through.") + if (player.location == locInChamber) { + teleport(player, locWaterfallDoorNorth) + removeAttribute(player, attributeRunes) return@onUseWith true } - return@onUseWith false + if (isQuestComplete(player, Quests.WATERFALL_QUEST)) { + teleport(player, locInChamber) + } else { + DoorActionHandler.handleAutowalkDoor(player, with as Scenery) + } + return@onUseWith true } // Use runes on the pedestals @@ -448,7 +490,7 @@ class WaterfallListeners : InteractionListener { var activeState = getAttribute(player, attributeRunes, 0) if (pIndex == -1) return@onUseWith false if (activeState and (1 shl activeIndex) == 0) { - if (removeItem(player, used)) { + if (removeItem(player, used.id)) { sendMessage(player, "You place the rune on the stand.") lock(player, 1) queueScript(player, 1, QueueStrength.SOFT) { @@ -482,18 +524,15 @@ class WaterfallListeners : InteractionListener { return@onUseWith true } else if (removeItem(player, used)) { sendMessage(player, "You place the amulet around the neck of the statue.") - lock(player, 7) - queueScript(player, 3, QueueStrength.SOFT) { stage -> + lock(player, 5) + queueScript(player, 2, QueueStrength.SOFT) { stage -> when (stage) { 0 -> { sendMessage(player, "You hear a loud rumble from beneath...") - return@queueScript delayScript(player, 3) + return@queueScript delayScript(player, 2) } 1 -> { sendMessage(player, "The ground raises up before you!") - return@queueScript delayScript(player, 6) - } - 2 -> { teleport(player, locBeforeFinalStatue) return@queueScript stopExecuting(player) } @@ -508,16 +547,45 @@ class WaterfallListeners : InteractionListener { // Try to loot the chalice on(SceneryObj.CHALICE_OF_ETERNITY_2014, IntType.SCENERY, "take treasure") { player, _ -> if (!isQuestComplete(player, Quests.WATERFALL_QUEST)) { - sendMessage(player, "The cavern floods!") - lock(player, 6) - queueScript(player, 5, QueueStrength.SOFT) { - sendMessage(player, "You are washed out of the chalice room.") - teleport(player, locWaterfallDoorNorth) - removeAttribute(player, attributeRunes) - return@queueScript stopExecuting(player) + sendMessage(player, "You hear the gushing of water.") + removeAttribute(player, attributeRunes) + lock(player, 18) + queueScript(player, 2, QueueStrength.SOFT) { stage -> + when (stage) { + 0 -> { + sendMessage(player, "Water floods into the cavern.") + animate(player, animationDrowning) + teleport(player, locBeforeFloodedStatue) + return@queueScript keepRunning(player) + } + 1 -> { + player.appearance.setAnimations(animationRenderDrowning) + player.appearance.sync() + AgilityHandler.walk(player, -1, player.location, player.location.transform(0, -2, 0), null, 0.0, null) + return@queueScript delayScript(player, 2) + } + 2 -> { + AgilityHandler.walk(player, -1, player.location, player.location.transform(1, -1, 0), null, 0.0, null) + return@queueScript keepRunning(player) + } + 3 -> { + player.appearance.setAnimations(animationRenderWhirlpool) + player.appearance.sync() + return@queueScript delayScript(player, 12) + } + 4 -> { + sendMessage(player, "You are washed downstream, but feel lucky to be alive.") + player.appearance.setDefaultAnimations() + player.appearance.setAnimations() + player.appearance.sync() + teleport(player, locDownstream) + return@queueScript stopExecuting(player) + } + else -> return@queueScript stopExecuting(player) + } } } else { - sendMessage(player, "You have already looted the treasure.") + sendMessage(player, "The chalice only contains some old ashes.") } return@on true } @@ -525,10 +593,11 @@ class WaterfallListeners : InteractionListener { // Use the urn on the chalice onUseWith(IntType.SCENERY, Items.GLARIALS_URN_296, SceneryObj.CHALICE_OF_ETERNITY_2014) { player, used, _ -> if (isQuestComplete(player, Quests.WATERFALL_QUEST)) { - return@onUseWith false + sendMessage(player, "The chalice only contains some old ashes.") + return@onUseWith true } if (freeSlots(player) < 5) { - sendMessage(player, "You'll need 5 free inventory slots to take Glarial's treasure.") + sendMessage(player, "You do not have enough space for the reward, you will need 5 free slots to accept it.") return@onUseWith true } if (removeItem(player, used)) { @@ -562,10 +631,10 @@ class WaterfallListeners : InteractionListener { override fun defineDestinationOverrides() { setDest(IntType.NPC, NPCs.HUDON_305) { _, _ -> - return@setDest locHudonTalk + return@setDest locIslandAfterRaft } - setDest(IntType.SCENERY, intArrayOf(SceneryObj.ROCK_1996, SceneryObj.ROCK_1997)) { _, _ -> + setDest(IntType.SCENERY, intArrayOf(SceneryObj.ROCK_1996, SceneryObj.ROCK_1997), "swim to", "use") { _, _ -> return@setDest locIslandBeforeRock } } diff --git a/Server/src/main/content/region/kandarin/quest/waterfall/WaterfallQuest.kt b/Server/src/main/content/region/kandarin/quest/waterfall/WaterfallQuest.kt new file mode 100644 index 000000000..5b2eea352 --- /dev/null +++ b/Server/src/main/content/region/kandarin/quest/waterfall/WaterfallQuest.kt @@ -0,0 +1,123 @@ +package content.region.kandarin.quest.waterfall + +import content.data.Quests +import core.api.* +import core.game.node.entity.player.Player +import core.game.node.entity.player.link.quest.Quest +import core.game.node.entity.skill.Skills +import core.plugin.Initializable +import org.rs09.consts.Components +import org.rs09.consts.Items + +/** + * Waterfall Quest + * @author Splinter - original + * @author Bishop - refactor + */ + +@Initializable +class WaterfallQuest : Quest(Quests.WATERFALL_QUEST, 65, 64, 1, 65, 0, 1, 10) { + + private val questVarp = 65 + + override fun drawJournal(player: Player, stage: Int) { + super.drawJournal(player, stage) + + var ln = 11 + var stage = getStage(player) + var started = getQuestStage(player, Quests.WATERFALL_QUEST) > 0 + + val hasPebble = (inInventory(player, Items.GLARIALS_PEBBLE_294)) + val hasAmulet = (inInventory(player, Items.GLARIALS_AMULET_295) || inEquipment(player, Items.GLARIALS_AMULET_295)) + val inChamber = ((player.location.x in 2561..2570 && player.location.y in 9902..9917) || (player.location.x in 2599..2608 && player.location.y in 9901..9916)) + + if (!started) { + line(player, "I can start this quest by speaking to !!Almera?? in her house", ln++) + line(player, "next to the !!Baxtorian Falls.", ln++) + line(player, "", ln++) + line(player, "I need to be able to fight !!Level 84 Giants.", ln++) + limitScrolling(player, ln + 6, true) + } else { + if (stage >= 10) { + line(player, "I spoke to !!Almera?? in a house close to the Baxtorian", ln++, stage >= 20) + line(player, "waterfall. Her son was missing so I offered to help find", ln++, stage >= 20) + line(player, "him. The boy, !!Hudon's?? looking for treasure in the waterfall.", ln++, stage >= 20) + ln++ + } + if (stage >= 20) { + line(player, "I found Hudon a short raft ride down the river. He is", ln++, stage >= 30) + line(player, "convinced there is treasure here somewhere. Maybe I", ln++, stage >= 30) + line(player, "need to do a little research.", ln++, stage >= 30) + ln++ + } + if (stage >= 30) { + line(player, "I found a book in the tourist office about Baxtorian. The", ln++, true) + line(player, "book tells of a sad love story about 2 elf lovers. It ends", ln++, true) + line(player, "with Baxtorian withdrawing to his home under the waterfall", ln++, true) + line(player, "after his wife dies. It is told that only Glarial could enter", ln++, true) + line(player, "their home.", ln++, true) + ln++ + line(player, "The book also mentions !!Glarial's tomb?? and a pebble, it", ln++, stage == 100 || hasAmulet || inChamber) + line(player, "appears that the pebble is used to enter the tomb.", ln++, stage == 100 || hasAmulet || inChamber) + line(player, "From what I understand Glarial's pebble was hidden in a", ln++, stage == 100 || hasPebble || hasAmulet || inChamber) + line(player, "cave under the Tree Gnome Village by Golrie's ancestors.", ln++, stage == 100 || hasPebble || hasAmulet || inChamber) + ln++ + } + if (stage >= 30 && (stage == 100 || hasAmulet || inChamber)) { + line(player, "Inside the tomb I found Glarial's amulet and ashes.", ln++, stage == 100 || inChamber) + ln++ + } + if (stage >= 30 && (stage == 100 || inChamber)) { + line(player, "I finally got access to the derelict home of Baxtorian. The", ln++, true) + line(player, "door must have been keyed to Glarial's amulet.", ln++, true) + line(player, "", ln++) + line(player, "I have found a room containing the !!Chalice of Eternity.?? The", ln++, stage == 100) + line(player, "chalice is suspended in midair just out of reach.", ln++, stage == 100) + ln++ + } + if (stage == 100) { + line(player, "Using Glarial's ashes as a counterweight, I was able to", ln++, true) + line(player, "remove the treasure that had been left in the chalice.", ln++, true) + ln++ + line(player, "!!QUEST COMPLETE!", ln++) + } + limitScrolling(player, ln, false) + } + } + + override fun finish(player: Player) { + var ln = 10 + super.finish(player) + + setInterfaceText(player, "You have completed the Waterfall Quest!", Components.QUEST_COMPLETE_SCROLL_277, 4) + sendItemZoomOnInterface(player,Components.QUEST_COMPLETE_SCROLL_277, 5, Items.DIAMOND_1601, 230) + + drawReward(player, "1 Quest Point", ln++) + drawReward(player, "13,750 Strength XP", ln++) + drawReward(player, "13,750 Attack XP", ln++) + drawReward(player, "2 diamonds", ln++) + drawReward(player, "2 gold bars", ln++) + drawReward(player, "40 Mithril seeds", ln++) + + rewardXP(player, Skills.STRENGTH, 13750.0) + rewardXP(player, Skills.ATTACK, 13750.0) + + addItemOrDrop(player, Items.DIAMOND_1601, 2) + addItemOrDrop(player, Items.GOLD_BAR_2357, 2) + addItemOrDrop(player, Items.MITHRIL_SEEDS_299, 40) + } + + override fun setStage(player: Player, stage: Int) { + super.setStage(player, stage) + this.updateVarps(player) + } + + override fun updateVarps(player: Player) { + setVarp(player, questVarp, (getQuestStage(player, Quests.WATERFALL_QUEST) / 10), true) + } + + override fun newInstance(`object`: Any?): Quest { + return this + } + +} \ No newline at end of file diff --git a/Server/src/main/content/region/kandarin/quest/waterfall/WaterfallTreeDialogue.java b/Server/src/main/content/region/kandarin/quest/waterfall/WaterfallTreeDialogue.java deleted file mode 100644 index 54b39a043..000000000 --- a/Server/src/main/content/region/kandarin/quest/waterfall/WaterfallTreeDialogue.java +++ /dev/null @@ -1,80 +0,0 @@ -package content.region.kandarin.quest.waterfall; - -import core.game.dialogue.DialogueInterpreter; -import core.game.dialogue.DialoguePlugin; -import core.game.node.entity.combat.ImpactHandler.HitsplatType; -import core.game.node.entity.player.Player; -import core.game.system.task.Pulse; -import core.game.world.map.Location; -import core.game.world.update.flag.context.Animation; - -/** - * Handles the dialogue for the tree on the edge of the Waterfall. - * @author Splinter - */ -public class WaterfallTreeDialogue extends DialoguePlugin { - - public WaterfallTreeDialogue() { - - } - - public WaterfallTreeDialogue(Player player) { - super(player); - } - - @Override - public int[] getIds() { - return new int[] { DialogueInterpreter.getDialogueKey("waterfall_tree_dialogue") }; - } - - @Override - public boolean handle(int interfaceId, int buttonId) { - switch (stage) { - - case 100: // Generic end to the dlg - end(); - break; - - /* Main dialogue sequence */ - case 0: - player.getDialogueInterpreter().sendOptions("Select an Option", "Climb down anyway", "Back away"); - stage = 1; - break; - case 1: - switch (buttonId) { - case 1: - end(); - player.getPacketDispatch().sendMessage("You climb down the tree"); - player.animate(new Animation(828)); - player.getPulseManager().run(new Pulse(4, player) { - @Override - public boolean pulse() { - player.getPacketDispatch().sendMessage("and lose your grip."); - player.getPacketDispatch().sendMessage("You get washed away in the current."); - player.teleport(new Location(2527, 3413)); - player.getImpactHandler().manualHit(player, 8, HitsplatType.NORMAL); - return true; - } - }); - break; - case 2: - player.getDialogueInterpreter().sendDialogue("You leave the tree alone."); - stage = 100; - break; - } - } - return true; - } - - @Override - public DialoguePlugin newInstance(Player player) { - return new WaterfallTreeDialogue(player); - } - - @Override - public boolean open(Object... args) { - player.getDialogueInterpreter().sendDialogue("It would be difficult to get down this tree without using a rope", "on it first."); - stage = 0; - return true; - } -} \ No newline at end of file diff --git a/Server/src/main/content/region/kandarin/quest/waterfall/WaterfallTreeDialogueFile.kt b/Server/src/main/content/region/kandarin/quest/waterfall/WaterfallTreeDialogueFile.kt new file mode 100644 index 000000000..af0516f22 --- /dev/null +++ b/Server/src/main/content/region/kandarin/quest/waterfall/WaterfallTreeDialogueFile.kt @@ -0,0 +1,39 @@ +package content.region.kandarin.quest.waterfall + +import core.api.* +import core.game.dialogue.DialogueFile +import core.game.interaction.QueueStrength +import core.game.node.entity.combat.ImpactHandler.HitsplatType +import core.game.world.map.Location +import core.game.world.update.flag.context.Animation + +class WaterfallTreeDialogueFile : DialogueFile() { + + private val animationClimb = Animation(828) + private val locDownstream = Location(2527, 3413) + + override fun handle(componentID: Int, buttonID: Int) { + when (stage) { + 0 -> sendDialogueLines(player!!, "It would be difficult to get down this tree without using a rope", "on it first.").also { stage++ } + 1 -> sendDialogueOptions(player!!, "Select an Option", "Climb down anyway", "Back away").also { stage++ } + 2 -> { + when (buttonID) { + 1 -> { + sendMessage(player!!, "You climb down the tree") + animate(player!!, animationClimb) + queueScript(player!!, 4, QueueStrength.SOFT) { + sendMessage(player!!, "and lose your grip.") + sendMessage(player!!, "You get washed away in the current.") + teleport(player!!, locDownstream) + impact(player!!, 8, HitsplatType.NORMAL) + return@queueScript stopExecuting(player!!) + } + end() + } + 2 -> sendDialogue(player!!, "You leave the tree alone.").also { stage++ } + } + } + 3 -> end() + } + } +} \ No newline at end of file diff --git a/Server/src/main/core/game/dialogue/DialogueLabeller.kt b/Server/src/main/core/game/dialogue/DialogueLabeller.kt index 1d39ce22b..2d27bed68 100644 --- a/Server/src/main/core/game/dialogue/DialogueLabeller.kt +++ b/Server/src/main/core/game/dialogue/DialogueLabeller.kt @@ -257,6 +257,7 @@ abstract class DialogueLabeller : DialogueFile() { /** Runs arbitrary code when the dialogue closes, once. **/ fun afterClose(callback: (player: Player) -> Unit) { + if (!stageHit || super.stage != dialogueCounter || jumpTo != null) return val hook = object : EventHook { override fun process(entity: Entity, event: DialogueCloseEvent) { val you = entity as Player diff --git a/Server/src/main/core/game/dialogue/FacialExpression.java b/Server/src/main/core/game/dialogue/FacialExpression.java index 8b4f2eb8c..ff596dee3 100644 --- a/Server/src/main/core/game/dialogue/FacialExpression.java +++ b/Server/src/main/core/game/dialogue/FacialExpression.java @@ -70,6 +70,7 @@ public enum FacialExpression { SLEEPING(9802), SILENT(9804), NEUTRAL(9808), + NEUTRAL_FAST(9810), // Like neutral but mouth starts moving immediately THINKING(9812), HALF_THINKING(9814), DISGUSTED(9816),