Then you commit the rest of the Waterfall Quest

This commit is contained in:
Bishop 2026-07-28 17:17:06 -05:00
parent 10dadd0949
commit 3a18fb16c2
20 changed files with 1025 additions and 1091 deletions

View file

@ -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",

View file

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

View file

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

View file

@ -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 = "<col=8A0808>"
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 ->
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
}
}

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -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!")
}
}

View file

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

View file

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

View file

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

View file

@ -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, "<blue>I can start this quest by speaking to <red>Almera<blue> in her house<n><blue> next to the <red>Baxtorian Falls.<n><n><blue>I need to be able to fight <red>Level 84 Giants.", 12);
break;
case 10:
line(player, "<blue>I spoke to <red>Almera<blue> in a house close to the Baxtorian<n><blue>waterfall. Her son was missing so I offered to help find<n><blue>him. The boy, <red>Hudon's<blue> looking for treasure in the waterfall.", 12);
break;
case 20:
line(player, "<str>I spoke to Almera in a house close to the Baxtorian<n><str>waterfall. Her son was missing so I offered to help find<n><str>him. The boy, Hudon's looking for treasure in the waterfall.<n><n><blue>I found Hudon a short raft ride down the river. He is<n><blue>convinced there is treasure here somewhere. Maybe I<n><blue>need to do a little research.", 12);
break;
case 30:
if (player.getInventory().containsItem(new Item(294, 1))) {
line(player, "<str>I spoke to Almera in a house close to the Baxtorian<n><str>waterfall. Her son was missing so I offered to help find<n><str>him. The boy, Hudon's looking for treasure in the waterfall.<n><n><str>I found Hudon a short raft ride down the river. He is<n><str>convinced there is treasure here somewhere. Maybe I<n><str>need to do a little research.<n><n><str>I found a book in the tourist office about Baxtorian. The<n><str>book tells of a sad love story about 2 elf lovers. It ends<n><str>with Baxtorian withdrawing to his home under the waterfall<n><str>after his wife dies. It is told that only Glarial could enter<n><str>their home.<n><n><blue>The book also mentions <red>Glarial's tomb<blue> and a pebble, it<n><blue>appears that the pebble is used to enter the tomb.<n><str>From what I understand Glarial's pebble was hidden in a <n><str> cave under the Tree Gnome Village by Golrie's ancestors.", 12);
} else {
line(player, "<str>I spoke to Almera in a house close to the Baxtorian<n><str>waterfall. Her son was missing so I offered to help find<n><str>him. The boy, Hudon's looking for treasure in the waterfall.<n><n><str>I found Hudon a short raft ride down the river. He is<n><str>convinced there is treasure here somewhere. Maybe I<n><str>need to do a little research.<n><n><str>I found a book in the tourist office about Baxtorian. The<n><str>book tells of a sad love story about 2 elf lovers. It ends<n><str>with Baxtorian withdrawing to his home under the waterfall<n><str>after his wife dies. It is told that only Glarial could enter<n><str>their home.<n><n><blue>The book also mentions <red>Glarial's tomb<blue> and a pebble, it<n><blue>appears that the pebble is used to enter the tomb.<n><blue>From what I understand <red>Glarial's pebble<blue> was hidden in a <n><blue> cave under the <red>Tree Gnome Village<blue> by<red> Golrie's<blue> ancestors.", 12);
}
if (player.getInventory().containsItem(new Item(295, 1)) || player.getEquipment().containsAtLeastOneItem(295)) {
line(player, "<str>I spoke to Almera in a house close to the Baxtorian<n><str>waterfall. Her son was missing so I offered to help find<n><str>him. The boy, Hudon's looking for treasure in the waterfall.<n><n><str>I found Hudon a short raft ride down the river. He is<n><str>convinced there is treasure here somewhere. Maybe I<n><str>need to do a little research.<n><n><str>I found a book in the tourist office about Baxtorian. The<n><str>book tells of a sad love story about 2 elf lovers. It ends<n><str>with Baxtorian withdrawing to his home under the waterfall<n><str>after his wife dies. It is told that only Glarial could enter<n><str>their home.<n><n><str>The book also mentions Glarial's tomb and a pebble, it<n><str>appears that the pebble is used to enter the tomb.<n><str>From what I understand Glarial's pebble was hidden in a <n><str> cave under the Tree Gnome Village by Golrie's ancestors.<n><n><blue>Inside the tomb I found Glarial's amulet and ashes.", 12);
}
if (player.getLocation().getY() >= 9902) {
line(player, "<str>I spoke to Almera in a house close to the Baxtorian<n><str>waterfall. Her son was missing so I offered to help find<n><str>him. The boy, Hudon's looking for treasure in the waterfall.<n><n><str>I found Hudon a short raft ride down the river. He is<n><str>convinced there is treasure here somewhere. Maybe I<n><str>need to do a little research.<n><n><str>I found a book in the tourist office about Baxtorian. The<n><str>book tells of a sad love story about 2 elf lovers. It ends<n><str>with Baxtorian withdrawing to his home under the waterfall<n><str>after his wife dies. It is told that only Glarial could enter<n><str>their home.<n><n><str>The book also mentions Glarial's tomb and a pebble, it<n><str>appears that the pebble is used to enter the tomb.<n><str>From what I understand Glarial's pebble was hidden in a <n><str> cave under the Tree Gnome Village by Golrie's ancestors.<n><n><str>Inside the tomb I found Glarial's amulet and ashes.<n><n><str>I finally got access to the derelict home of Baxtorian. The<n><str>door must have been keyed to Glarial's amulet.<n><n><blue>I have found a room containing the <red>Chalice of Eternity.<blue> The<n><blue>chalice is suspended in midair just out of reach.", 12);
}
break;
case 100:
line(player, "<str>I spoke to Almera in a house close to the Baxtorian<n><str>waterfall. Her son was missing so I offered to help find<n><str>him. The boy, Hudon's looking for treasure in the waterfall.<n><n><str>I found Hudon a short raft ride down the river. He is<n><str>convinced there is treasure here somewhere. Maybe I<n><str>need to do a little research.<n><n><str>I found a book in the tourist office about Baxtorian. The<n><str>book tells of a sad love story about 2 elf lovers. It ends<n><str>with Baxtorian withdrawing to his home under the waterfall<n><str>after his wife dies. It is told that only Glarial could enter<n><str>their home.<n><n><str>The book also mentions Glarial's tomb and a pebble, it<n><str>appears that the pebble is used to enter the tomb.<n><str>From what I understand Glarial's pebble was hidden in a <n><str> cave under the Tree Gnome Village by Golrie's ancestors.<n><n><str>Inside the tomb I found Glarial's amulet and ashes.<n><n><str>I finally got access to the derelict home of Baxtorian. The<n><str>door must have been keyed to Glarial's amulet.<n><n><str>I have found a room containing the Chalice of Eternity. The<n><str>chalice is suspended in midair just out of reach. <n><n><str>Using Glarial's ashes as a counterweight, I was able to<n><str>remove the treasure that had been left in the chalice.<n><n><col=FF0000>QUEST COMPLETE!</col>", 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;
}
}

View file

@ -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
/**
@ -33,24 +35,27 @@ class WaterfallListeners : InteractionListener {
// Animations
private val animationSwim = Animation(164)
private val animationRopeToss = Animation(774)
private val animationRopeWalk = Animation(273)
private val animationRopeDone = Animation(780)
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"
// Graphics
private val graphicRopeToss = Graphics(67)
private val graphicsSplash = Graphics(68)
private val graphicsRunePoof = Graphics(580)
private val graphicsRunePoof = Graphics(580, 250)
private val graphicsRocksFall = Graphics(74)
// Lists
private val listOfSwimmers : MutableList<Player?> = ArrayList(20)
// 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 locInFrontOfRock = Location(2512, 3470)
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)
@ -58,10 +63,10 @@ class WaterfallListeners : InteractionListener {
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 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),
@ -69,12 +74,18 @@ class WaterfallListeners : InteractionListener {
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 -> {
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, animationRopeWalk, 0.0, null
player, -1, player.location, locInFrontOfRock, null, 0.0, null
)
return@queueScript delayScript(player, 8)
return@queueScript delayScript(player, 1)
}
1 -> {
teleport(player, locIslandAfterRock)
return@queueScript keepRunning(player)
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]))
}
2 -> {
face(player, locRock)
animate(player, animationRopeDone)
return@queueScript animationFinished(player)
return@queueScript delayScript(player, 1)
}
3 -> {
clearLogoutListener(player, "waterfall")
if (listOfSwimmers.remove(player) && listOfSwimmers.isEmpty()) {
7 -> {
AgilityHandler.walk(
player, -1, player.location, locInFrontOfRock.transform(1, -1, 0), null, 0.0, null
)
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))
}
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.")
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.")
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.")
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.")
lock(player, 3)
queueScript(player, 3, QueueStrength.STRONG) {
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)
}
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,10 +387,47 @@ 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.")
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
}
@ -399,29 +436,27 @@ class WaterfallListeners : InteractionListener {
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 -> {
when (node.location) {
locWaterfallDoorSouth, locWaterfallDoorNorth -> {
if (player.location != locWaterfallDoorNorth.transform(0, 1, 0)) {
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))
} 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) {
val locInChamber = locWaterfallDoorChamber.transform(0, 1, 0)
sendMessage(player, "You open the door and walk through.")
DoorActionHandler.handleAutowalkDoor(player, with as Scenery)
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)
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
}
}

View file

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

View file

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

View file

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

View file

@ -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<DialogueCloseEvent> {
override fun process(entity: Entity, event: DialogueCloseEvent) {
val you = entity as Player

View file

@ -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),