From 702e3f11134e242f0664109ad2a111c23ebd2288 Mon Sep 17 00:00:00 2001 From: Vantha Date: Wed, 25 Feb 2026 17:17:49 +0100 Subject: [PATCH] Revise tutorial step handling - Remove the delay functionality from the tutorial. It was unused and that for a reason. Switching to the next step after a fixed amount of time is never wanted. It was only used to force-show the ready button in one case, but a designated bool communicates the purpose better. - Rename the "ready" button to "continue" as it fits better. - Rename "leave" to "isLast" as it's more descriptive. - Rename the "warning" object of the instruction panel to "hint" as it's not always display warnings, and move its captions to the class prototype like the coding conventions state. - Simplify the logic in NextStep a bit to make it more readable. --- .../gui/session/tutorial/InstructionPanel.js | 34 ++++++++------- .../gui/session/tutorial/InstructionPanel.xml | 6 +-- .../data/mods/public/maps/scripts/Tutorial.js | 42 +++++++------------ .../tutorials/starting_economy_walkthrough.js | 4 +- 4 files changed, 41 insertions(+), 45 deletions(-) diff --git a/binaries/data/mods/public/gui/session/tutorial/InstructionPanel.js b/binaries/data/mods/public/gui/session/tutorial/InstructionPanel.js index b3b6b6d011..91bad4f5ac 100644 --- a/binaries/data/mods/public/gui/session/tutorial/InstructionPanel.js +++ b/binaries/data/mods/public/gui/session/tutorial/InstructionPanel.js @@ -6,17 +6,17 @@ class InstructionPanel { panel = Engine.GetGUIObjectByName("instructionPanel"); text = Engine.GetGUIObjectByName("instructionPanelText"); - warning = Engine.GetGUIObjectByName("instructionPanelWarning"); - readyButton = Engine.GetGUIObjectByName("instructionPanelReady"); + hint = Engine.GetGUIObjectByName("instructionPanelHint"); + continueButton = Engine.GetGUIObjectByName("instructionPanelContinueButton"); instructions = []; closePage; constructor(closePage) { this.closePage = closePage; - this.readyButton.onPress = () => + this.continueButton.onPress = () => { - Engine.PostNetworkCommand({ "type": "dialog-answer", "tutorial": "ready" }); + Engine.PostNetworkCommand({ "type": "dialog-answer", "tutorial": "continue" }); }; } @@ -27,7 +27,7 @@ class InstructionPanel displayWarning(warning) { - this.warning.caption = setStringTags(warning, this.WarningTags); + this.hint.caption = setStringTags(warning, this.WarningTags); } displayStep(panelData) @@ -35,22 +35,22 @@ class InstructionPanel this.text.caption = this.instructions.concat(setStringTags(panelData.text, this.NewInstructionTags)).join("\n"); this.instructions.push(panelData.text); - if (panelData.readyButton) + if (panelData.showContinueButton) { - this.readyButton.hidden = false; - if (panelData.leave) + this.continueButton.hidden = false; + if (panelData.isLast) { - this.warning.caption = translate("Click to quit this tutorial."); - this.readyButton.caption = translate("Quit"); - this.readyButton.onPress = this.closePage; + this.hint.caption = translate("Click to quit this tutorial."); + this.continueButton.caption = translate("Quit"); + this.continueButton.onPress = this.closePage; } else - this.warning.caption = translate("Click when ready."); + this.hint.caption = this.HintCaptions.Continue; } else { - this.warning.caption = translate("Follow the instructions."); - this.readyButton.hidden = true; + this.hint.caption = this.HintCaptions.Instruction; + this.continueButton.hidden = true; } } } @@ -64,3 +64,9 @@ InstructionPanel.prototype.NewInstructionTags = { "color": "255 226 149" }; * Tags applied to warning messages. */ InstructionPanel.prototype.WarningTags = { "color": "orange" }; + +InstructionPanel.prototype.HintCaptions = { + "Continue": translate("Click when continue."), + "Instruction": translate("Follow the instructions."), + "Quit": translate("Click to quit this tutorial.") +}; diff --git a/binaries/data/mods/public/gui/session/tutorial/InstructionPanel.xml b/binaries/data/mods/public/gui/session/tutorial/InstructionPanel.xml index 437db1e460..a639c30746 100644 --- a/binaries/data/mods/public/gui/session/tutorial/InstructionPanel.xml +++ b/binaries/data/mods/public/gui/session/tutorial/InstructionPanel.xml @@ -3,8 +3,8 @@ - - - Ready + + + Continue diff --git a/binaries/data/mods/public/maps/scripts/Tutorial.js b/binaries/data/mods/public/maps/scripts/Tutorial.js index 410911fc29..fa75077110 100644 --- a/binaries/data/mods/public/maps/scripts/Tutorial.js +++ b/binaries/data/mods/public/maps/scripts/Tutorial.js @@ -39,16 +39,11 @@ Trigger.prototype.NextStep = function(deserializing = false) if (this.index > this.tutorialSteps.length) return; const step = this.tutorialSteps[this.index]; - let needDelay = true; - let readyButton = false; Trigger.prototype.Init = step.Init || null; if (!deserializing && this.Init) this.Init(); - Trigger.prototype.IsDone = step.IsDone || (() => false); - const stepAlreadyDone = this.IsDone(); - for (const event of this.tutorialEvents) { const action = event + "Trigger"; @@ -56,36 +51,31 @@ Trigger.prototype.NextStep = function(deserializing = false) { Trigger.prototype[action] = step[event]; this.EnableTrigger(event, action); - if (!stepAlreadyDone) - needDelay = false; } else this.DisableTrigger(event, action); } - // Steps without actions to be performed by the player must have - // - either the property delay (a value > 0 to wait for a given time, and -1 to display the Ready button) - // - or no trigger functions (needDelay will be set automatically to true and the Ready button displayed) - if (step.delay || needDelay) + Trigger.prototype.IsDone = step.IsDone || (() => false); + const showContinueButton = + step.panelData.showContinueButton === undefined ? + this.IsDone() || this.tutorialEvents.every(event => !step[event]) : + step.panelData.showContinueButton; + + if (showContinueButton) { - if (step.delay && step.delay > 0) - this.DoAfterDelay(+step.delay, "NextStep", {}); - else + this.EnableTrigger("OnPlayerCommand", "OnPlayerCommandTrigger"); + Trigger.prototype.OnPlayerCommandTrigger = function(msg) { - this.EnableTrigger("OnPlayerCommand", "OnPlayerCommandTrigger"); - Trigger.prototype.OnPlayerCommandTrigger = function(msg) - { - if (msg.cmd.type == "dialog-answer" && msg.cmd.tutorial && msg.cmd.tutorial == "ready") - this.NextStep(); - }; - readyButton = true; - } + if (msg.cmd.type == "dialog-answer" && msg.cmd.tutorial && msg.cmd.tutorial == "continue") + this.NextStep(); + }; } - this.DisplayStep(step, readyButton, ++this.index == this.tutorialSteps.length); + this.DisplayStep(step, showContinueButton, ++this.index == this.tutorialSteps.length); }; -Trigger.prototype.DisplayStep = function(step, readyButton = false, leave = false) +Trigger.prototype.DisplayStep = function(step, showContinueButton = false, isLast = false) { const cmpGUIInterface = Engine.QueryInterface(SYSTEM_ENTITY, IID_GuiInterface); cmpGUIInterface.PushNotification({ @@ -95,8 +85,8 @@ Trigger.prototype.DisplayStep = function(step, readyButton = false, leave = fals "type": step.type, "panelData": { ...step.panelData, - "readyButton": readyButton, - "leave": leave + "showContinueButton": showContinueButton, + "isLast": isLast } } }); diff --git a/binaries/data/mods/public/maps/tutorials/starting_economy_walkthrough.js b/binaries/data/mods/public/maps/tutorials/starting_economy_walkthrough.js index 1cb01739e8..0f1dfa984d 100644 --- a/binaries/data/mods/public/maps/tutorials/starting_economy_walkthrough.js +++ b/binaries/data/mods/public/maps/tutorials/starting_economy_walkthrough.js @@ -274,9 +274,9 @@ Trigger.prototype.tutorialSteps = [ "panelData": { "text": markForTranslation("You may notice that berries are a finite supply of food. We will need a more lasting food source. Fields produce an unlimited food resource, but are slower to gather than forageable fruits.\n") + - markForTranslation("But to minimize the distance between a farm and its corresponding food dropsite, we will first build a Farmstead.") + markForTranslation("But to minimize the distance between a farm and its corresponding food dropsite, we will first build a Farmstead."), + "showContinueButton": true }, - "delay": -1, "OnOwnershipChanged": function(msg) { if (this.houseGoal.has(+msg.entity))