Added additional dialogue helpers
This commit is contained in:
@@ -30,7 +30,7 @@ class DonieDialogueFile : DialogueLabeller() {
|
||||
options(
|
||||
DialogueOption("whereami", "Where am I?", expression = ChatAnim.THINKING),
|
||||
DialogueOption("howareyou", "How are you today?"),
|
||||
DialogueOption("shoelace", "Your shoe lace is untied."),
|
||||
DialogueOption("shoelace", "Your shoe lace is untied.", skipPlayer=true),
|
||||
)
|
||||
|
||||
label("whereami")
|
||||
@@ -45,9 +45,15 @@ class DonieDialogueFile : DialogueLabeller() {
|
||||
npc("Not just a pretty face eh? Ha ha ha.")
|
||||
|
||||
label("shoelace")
|
||||
open(player!!, DonieDialogueShoelaceFile(), npc!!)
|
||||
|
||||
}
|
||||
}
|
||||
class DonieDialogueShoelaceFile : DialogueLabeller() {
|
||||
override fun addConversation() {
|
||||
player("Your shoe lace is untied.")
|
||||
npc(ChatAnim.ANGRY, "No it's not!")
|
||||
player("No you're right. I have nothing to back that up.")
|
||||
npc(ChatAnim.ANGRY, "Fool! Leave me alone!")
|
||||
|
||||
}
|
||||
}
|
||||
@@ -2,6 +2,7 @@ package core.game.dialogue
|
||||
|
||||
import core.api.InputType
|
||||
import core.api.face
|
||||
import core.api.openDialogue
|
||||
import core.api.splitLines
|
||||
import core.game.node.entity.npc.NPC
|
||||
import core.game.node.entity.player.Player
|
||||
@@ -13,12 +14,12 @@ typealias ChatAnim = FacialExpression
|
||||
typealias InputType = InputType
|
||||
/** Create container class DialogueOption for [DialogueLabeller.options] */
|
||||
class DialogueOption(
|
||||
val goto: String,
|
||||
val option: String,
|
||||
val spokenText: String = option,
|
||||
val expression: ChatAnim = ChatAnim.NEUTRAL,
|
||||
val skipPlayer: Boolean = false,
|
||||
val callback: ((player: Player, npc: NPC) -> Boolean)? = null
|
||||
val goto: String, // Required: Label to go to if player selects option.
|
||||
val option: String, // Required: Printed text on the option list.
|
||||
val spokenText: String = option, // Optional: Option selected will be spoken text unless provided here.
|
||||
val expression: ChatAnim = ChatAnim.NEUTRAL, // Optional: Player expression to show.
|
||||
val skipPlayer: Boolean = false, // Optional: Skips the player spoken text (if wildly different)
|
||||
val optionIf: ((player: Player, npc: NPC) -> Boolean)? = null // Optional: Function to show/not show option.
|
||||
)
|
||||
|
||||
/**
|
||||
@@ -32,7 +33,7 @@ class DialogueOption(
|
||||
*
|
||||
* ! WARNING: DO NOT use functions in DialogueFile as it will cause unexpected behavior.
|
||||
*
|
||||
* Example: [content.region.misthalin.lumbridge.dialogue.RangedTutorDialogue]
|
||||
* ! HELP: There are snippets below that you can copy and modify to use as part of your code.
|
||||
*/
|
||||
abstract class DialogueLabeller : DialogueFile() {
|
||||
|
||||
@@ -41,11 +42,12 @@ abstract class DialogueLabeller : DialogueFile() {
|
||||
* Makes NPC stop in its tracks and look at player.
|
||||
* An alternative to setting up DialoguePlugin(player) to be used in InteractionListener.
|
||||
*/
|
||||
fun captureNPC(player: Player, npc: NPC) {
|
||||
fun open(player: Player, dialogue: Any, npc: NPC) {
|
||||
face(npc, player.location)
|
||||
npc.setDialoguePlayer(player) // This prevents random walking in [NPC.java handleTickActions()]
|
||||
npc.getWalkingQueue().reset()
|
||||
npc.getPulseManager().clear()
|
||||
openDialogue(player, dialogue, npc)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -74,7 +76,7 @@ abstract class DialogueLabeller : DialogueFile() {
|
||||
/** Helper function to create an individual stage for each of the dialogue stages. */
|
||||
private fun assignIndividualStage(callback: () -> Unit) {
|
||||
if (startingStage == null) { startingStage = 0 }
|
||||
if (stage == dialogueCounter) { // Run this stage when the stage equals to the dialogueCounter of this dialogue
|
||||
if (stage == dialogueCounter && jumpTo == null) { // Run this stage when the stage equals to the dialogueCounter of this dialogue
|
||||
callback() // CALLBACK FUNCTION
|
||||
super.stage++ // Increment the stage to the next stage (only applies after a pass)
|
||||
stageHit = true // Flag that the stage was hit, so that it doesn't close the dialogue
|
||||
@@ -97,15 +99,16 @@ abstract class DialogueLabeller : DialogueFile() {
|
||||
fun assignToIds(npcid: Int) { /* super.npc = NPC(npcid) */ }
|
||||
|
||||
/** Marks the start of a series of dialogue that can be jumped to using a [goto]. */
|
||||
fun label(label: String) {
|
||||
fun label(label: String, nesting: () -> Unit = {}) {
|
||||
if (startingStage == null) { startingStage = 1 }
|
||||
dialogueCounter++
|
||||
labelStageMap[label] = dialogueCounter
|
||||
nesting()
|
||||
}
|
||||
|
||||
/** Jumps to a [label] after a series of dialogue. */
|
||||
fun goto(label: String) {
|
||||
if (stage == dialogueCounter) {
|
||||
if (stage == dialogueCounter && jumpTo == null) {
|
||||
jumpTo = labelStageMap[label]
|
||||
}
|
||||
}
|
||||
@@ -122,11 +125,16 @@ abstract class DialogueLabeller : DialogueFile() {
|
||||
*/
|
||||
fun exec(callback: (player: Player, npc: NPC) -> Unit) {
|
||||
if (startingStage == null) { startingStage = 0 }
|
||||
if (stage == dialogueCounter) {
|
||||
if (stage == dialogueCounter && jumpTo == null) {
|
||||
callback(player!!, npc!!)
|
||||
}
|
||||
}
|
||||
|
||||
/** Manual stage. For custom creation of an individual stage. Must call interpreter in some form. **/
|
||||
fun manual(callback: (player: Player, npc: NPC) -> Unit) {
|
||||
assignIndividualStage { callback(player!!, npc!!) }
|
||||
}
|
||||
|
||||
/** Dialogue player/playerl. Shows player chathead with text. **/
|
||||
fun player(chatAnim: ChatAnim = ChatAnim.NEUTRAL, vararg messages: String) {
|
||||
assignIndividualStage { interpreter!!.sendDialogues(player, chatAnim, *formatMessages(messages)) }
|
||||
@@ -143,9 +151,13 @@ abstract class DialogueLabeller : DialogueFile() {
|
||||
assignIndividualStage { interpreter!!.sendDialogues(npc, chatAnim, *formatMessages(messages)) }
|
||||
}
|
||||
/** Dialogue npc/npcl. Shows npcId chathead with text. **/
|
||||
fun npc(chatAnim: ChatAnim = ChatAnim.NEUTRAL, npcId: Int, vararg messages: String) {
|
||||
fun npc(chatAnim: ChatAnim = ChatAnim.NEUTRAL, npcId: Int = npc!!.id, vararg messages: String) {
|
||||
assignIndividualStage { interpreter!!.sendDialogues(NPC(npcId), chatAnim, *formatMessages(messages)) }
|
||||
}
|
||||
/** Dialogue npc/npcl. Shows npcId chathead with text. **/
|
||||
fun npc(npcId: Int = npc!!.id, vararg messages: String) {
|
||||
assignIndividualStage { interpreter!!.sendDialogues(NPC(npcId), ChatAnim.NEUTRAL, *formatMessages(messages)) }
|
||||
}
|
||||
/** Dialogue npc/npcl. Shows npc chathead with text. **/
|
||||
fun npc(vararg messages: String) { npc(ChatAnim.NEUTRAL, *messages) }
|
||||
@Deprecated("Use npc() instead.", ReplaceWith("npc(chatAnim, *messages)"))
|
||||
@@ -175,7 +187,7 @@ abstract class DialogueLabeller : DialogueFile() {
|
||||
/** Dialogue option. Shows the option dialogue with choices for the user to select. **/
|
||||
fun options(vararg options: DialogueOption, title: String = "Select an Option") {
|
||||
// Filter out options that aren't shown.
|
||||
val filteredOptions = options.filter{ if (it.callback != null) { it.callback.invoke(player!!, npc!!) } else { true } }
|
||||
val filteredOptions = options.filter{ if (it.optionIf != null) { it.optionIf.invoke(player!!, npc!!) } else { true } }
|
||||
// Stage Part 1: Options List Dialogue
|
||||
assignIndividualStage { interpreter!!.sendOptions(title, *filteredOptions.map{ it.option }.toTypedArray()) }
|
||||
// Stage Part 2: Show spoken text.
|
||||
@@ -211,9 +223,10 @@ abstract class DialogueLabeller : DialogueFile() {
|
||||
if (type == InputType.AMOUNT) {
|
||||
player!!.setAttribute("parseamount", true)
|
||||
}
|
||||
// This runscript is the same runscript as the one in ContentAPI sendInputDialogue
|
||||
player!!.setAttribute("runscript") { value: Any ->
|
||||
optInput = value
|
||||
// The next line is a hack. Because this prompt is overlays the actual chatbox, we trigger the next dialogue with a call to handle.
|
||||
// The next line is a hack. Because this prompt overlays the actual chat box, we trigger the next dialogue with a call to handle.
|
||||
interpreter!!.handle(player!!.interfaceManager.chatbox.id, 2)
|
||||
}
|
||||
player!!.setAttribute("input-type", type)
|
||||
@@ -222,6 +235,16 @@ abstract class DialogueLabeller : DialogueFile() {
|
||||
/** Dialogue input. Shows the input dialogue with an input box for the user to type in. Read [optInput] in an [exec] function for the value. **/
|
||||
fun input(numeric: Boolean, prompt: String = "Enter the amount") { input( if (numeric) { InputType.NUMERIC } else { InputType.STRING_SHORT }, prompt) }
|
||||
|
||||
/** Calls another dialogue file. Always use this to open another dialogue file instead of calling openDialogue() in exec{} due to interfaces clashing. **/
|
||||
fun open(player: Player, dialogue: Any, vararg args: Any) {
|
||||
assignIndividualStage { core.api.openDialogue(player, dialogue, *args) }
|
||||
}
|
||||
|
||||
/** WARNING: DIALOGUE LABELLER WILL BREAK IN CERTAIN FUNCTIONS. USE open() instead. */
|
||||
fun openDialogue(player: Player, dialogue: Any, vararg args: Any) {
|
||||
core.api.openDialogue(player, dialogue, *args)
|
||||
}
|
||||
|
||||
/** Hook onto the handle function of DialogueFile. This function gets called every loop with a super.stage. */
|
||||
override fun handle(componentID: Int, buttonID: Int) {
|
||||
this.buttonID = buttonID
|
||||
@@ -248,4 +271,90 @@ abstract class DialogueLabeller : DialogueFile() {
|
||||
}
|
||||
if (!stageHit) { end() } // If a dialogue stage is not hit, end the dialogues.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
// COPY PASTA SNIPPETS SECTION FOR QUICK BOILERPLATES
|
||||
|
||||
// STANDARD: Initializing with DialoguePlugin.
|
||||
@Initializable
|
||||
class DonieDialogue (player: Player? = null) : DialoguePlugin(player) {
|
||||
override fun newInstance(player: Player): DialoguePlugin {
|
||||
return DonieDialogue(player)
|
||||
}
|
||||
override fun handle(interfaceId: Int, buttonId: Int): Boolean {
|
||||
openDialogue(player, DonieDialogueFile(), npc)
|
||||
return false
|
||||
}
|
||||
override fun getIds(): IntArray {
|
||||
return intArrayOf(NPCs.DONIE_2238)
|
||||
}
|
||||
}
|
||||
class DonieDialogueFile : DialogueLabeller() {
|
||||
override fun addConversation() {
|
||||
assignToIds(NPCs.DONIE_2238)
|
||||
|
||||
npc(ChatAnim.FRIENDLY, "Hello there, can I help you?")
|
||||
goto("nowhere")
|
||||
}
|
||||
}
|
||||
|
||||
// NEW! (EXPERIMENTAL): Initializing with InteractionListener.
|
||||
class SomeDudeDialogue : InteractionListener {
|
||||
override fun defineListeners() {
|
||||
on(NPCs.PRIEST_OF_GUTHIX_8555, IntType.NPC, "talk-to") { player, node ->
|
||||
DialogueLabeller.open(player, SomeDudeDialogueLabellerFile(), node as NPC)
|
||||
return@on true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Exec with quest stage branches.
|
||||
exec { player, npc ->
|
||||
when(getQuestStage(player, SomeQuest.questName)) {
|
||||
100 -> loadLabel(player, "SomeQuestStage100")
|
||||
10, 20 -> loadLabel(player, "SomeQuestStage10")
|
||||
else -> {
|
||||
loadLabel(player, "SomeQuestStage0")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Exec to move quest stage up.
|
||||
exec { player, npc ->
|
||||
if (getQuestStage(player, SomeQuest.questName) == 0) {
|
||||
setQuestStage(player, SomeQuest.questName, 10)
|
||||
}
|
||||
}
|
||||
|
||||
// Exec to add item, set attribute.
|
||||
exec { player, npc ->
|
||||
if (removeItem(player, Items.ITEM_1)) {
|
||||
addItemOrDrop(player, Items.ITEM_2)
|
||||
}
|
||||
if (getAttribute(player, attributeSomething, null) == null) {
|
||||
setAttribute(player, attributeSomething, player.location)
|
||||
}
|
||||
}
|
||||
|
||||
// Open to another dialogue file.
|
||||
npc("I'm going to another file.")
|
||||
open(player!!, SomeDialogueFile2(), npc!!)
|
||||
...
|
||||
class SomeDialogueFile2 : DialogueLabeller() {
|
||||
override fun addConversation() {
|
||||
npc("This is another file.")
|
||||
}
|
||||
}
|
||||
|
||||
// Options with all the different controls.
|
||||
options(
|
||||
DialogueOption("Label1", "Line 1 Say", expression=ChatAnim.THINKING),
|
||||
DialogueOption("Label2", "Line 2 Huh", skipPlayer=true),
|
||||
DialogueOption("Label3", "Line 3 Blah", spokenText="I say something else", expression=ChatAnim.FRIENDLY),
|
||||
DialogueOption("Label4", "Line 4 What") { player, npc ->
|
||||
return@DialogueOption false // Don't show
|
||||
}
|
||||
)
|
||||
|
||||
*/
|
||||
Reference in New Issue
Block a user