mirror of
https://gitea.wildfiregames.com/0ad/0ad
synced 2026-06-16 05:13:58 -07:00
Add a tutorial panel for explaining the GUI
This patch adds a new type of tutorial steps called "GUI explanation", with a corresponding GUI panel. The purpose of it is to explain what a certain GUI element does. To make use of it the trigger script has to specify the target GUI object's name as well as the side on which to place the explanation panel relative to the target itself. The panel then highlights the target object by fading everything else out with black and also uses an arrow to point to it. Whilever the target GUI object is hidden, the panel hides the background fade too and shows a warning message. Unlike for the other steps, the TutorialManager does not hide the previously active panel when showing a GUI explanation, but instead only disables it, since it could contain relevant information and the GUI explanation panel is visibly placed "above" all other panels (in the Z axis).
This commit is contained in:
parent
9a867d4e81
commit
9d4055364d
15 changed files with 378 additions and 20 deletions
|
|
@ -0,0 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:3d1a87bfd33e5c55c8bc28eac1985f17fe5d4c51d853b4984f85051ce96a62d8
|
||||
size 2598
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:5ca1fbd89c75157abb88e88d047273c93a61ff085c1eb5311a36ce07b4133590
|
||||
size 2611
|
||||
|
|
@ -18,7 +18,7 @@
|
|||
<object name="gameStateNotifications"
|
||||
type="text"
|
||||
ghost="true"
|
||||
z="199"
|
||||
z="200"
|
||||
size="100%-110 40 100%-110 40"
|
||||
font="mono-stroke-10"
|
||||
textcolor="255 219 77"
|
||||
|
|
@ -36,7 +36,7 @@
|
|||
<object name="dataCounter"
|
||||
type="text"
|
||||
ghost="true"
|
||||
z="199"
|
||||
z="200"
|
||||
size="100%-100 40 100%-5 54"
|
||||
font="mono-10"
|
||||
textcolor="white"
|
||||
|
|
@ -58,7 +58,7 @@
|
|||
<object name="glbWaterMark"
|
||||
hidden="true"
|
||||
hotkey="screenshot.watermark"
|
||||
z="200"
|
||||
z="300"
|
||||
>
|
||||
<action on="Press">
|
||||
this.hidden = !this.hidden;
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
type="text"
|
||||
hidden="true"
|
||||
ghost="true"
|
||||
z="199"
|
||||
z="160"
|
||||
size="100%-300 60 100%-110 80"
|
||||
font="mono-10"
|
||||
textcolor="white"
|
||||
|
|
|
|||
|
|
@ -112,7 +112,7 @@
|
|||
<!-- Status Effects icons -->
|
||||
<object name="statusEffectsIcons" size="100%-20 4 100%-4 100%">
|
||||
<repeat count="5">
|
||||
<object type="image" size="0 0 16 16" z="200" tooltip_style="sessionToolTip"/>
|
||||
<object type="image" size="0 0 16 16" z="100" tooltip_style="sessionToolTip"/>
|
||||
</repeat>
|
||||
</object>
|
||||
</object>
|
||||
|
|
|
|||
|
|
@ -532,6 +532,49 @@
|
|||
<image backcolor="red" size="100%-1 0 100% 100%"/>
|
||||
</sprite>
|
||||
|
||||
<!-- ================================ ================================ -->
|
||||
<!-- Tutorial -->
|
||||
<!-- ================================ ================================ -->
|
||||
<sprite name="GuiExplanationPanel">
|
||||
<image texture="session/hud_panels.png"/>
|
||||
|
||||
<!-- top edge -->
|
||||
<image backcolor="41 32 11" size="0 0 100% 4"/>
|
||||
<image backcolor="164 133 57" size="2 2 100%-2 3"/>
|
||||
<image backcolor="221 180 87" size="1 1 100%-1 2"/>
|
||||
|
||||
<!-- bottom edge -->
|
||||
<image backcolor="41 32 11" size="0 100%-4 100% 100%"/>
|
||||
<image backcolor="164 133 57" size="2 100%-3 100%-2 100%-2"/>
|
||||
<image backcolor="221 180 87" size="1 100%-2 100%-1 100%-1"/>
|
||||
|
||||
<!-- left edge -->
|
||||
<image backcolor="41 32 11" size="0 4 4 100%-4"/>
|
||||
<image backcolor="164 133 57" size="2 3 3 100%-3"/>
|
||||
<image backcolor="221 180 87" size="1 2 2 100%-2"/>
|
||||
|
||||
<!-- right edge -->
|
||||
<image backcolor="41 32 11" size="100%-4 4 100% 100%-4"/>
|
||||
<image backcolor="164 133 57" size="100%-3 3 100%-2 100%-3"/>
|
||||
<image backcolor="221 180 87" size="100%-2 2 100%-1 100%-2"/>
|
||||
</sprite>
|
||||
|
||||
<sprite name="GoldenArrowDown">
|
||||
<image texture="session/golden-arrow_down.png"/>
|
||||
</sprite>
|
||||
|
||||
<sprite name="GoldenArrowUp">
|
||||
<image texture="session/golden-arrow_down.png" texture_size="0 100% 100% 0"/>
|
||||
</sprite>
|
||||
|
||||
<sprite name="GoldenArrowLeft">
|
||||
<image texture="session/golden-arrow_left.png"/>
|
||||
</sprite>
|
||||
|
||||
<sprite name="GoldernArrowRight">
|
||||
<image texture="session/golden-arrow_left.png" texture_size="100% 0 0 100%"/>
|
||||
</sprite>
|
||||
|
||||
<!-- ================================ ================================ -->
|
||||
<!-- Misc -->
|
||||
<!-- ================================ ================================ -->
|
||||
|
|
|
|||
|
|
@ -254,6 +254,25 @@
|
|||
text_valign="center"
|
||||
/>
|
||||
|
||||
<style name="TutorialExplanationTitle"
|
||||
buffer_zone="10"
|
||||
font="sans-bold-18"
|
||||
textcolor="gold"
|
||||
text_align="center"
|
||||
text_valign="top"
|
||||
/>
|
||||
|
||||
<style name="TutorialExplanationText"
|
||||
buffer_zone="10"
|
||||
font="sans-16"
|
||||
sprite="ModernFade"
|
||||
textcolor="white"
|
||||
scrollbar="true"
|
||||
scrollbar_style="ModernScrollBar"
|
||||
text_align="center"
|
||||
text_valign="top"
|
||||
/>
|
||||
|
||||
<!-- ================================ ================================ -->
|
||||
<!-- Icon Styles -->
|
||||
<!-- ================================ ================================ -->
|
||||
|
|
|
|||
|
|
@ -1,7 +1,8 @@
|
|||
// Needs to be kept in sync with the one in maps/scripts/Tutorial.js
|
||||
const TUTORIAL_STEP_TYPE = deepfreeze({
|
||||
"INSTRUCTION": 1,
|
||||
"INFO": 2
|
||||
"INFO": 2,
|
||||
"GUI_EXPLANATION": 3
|
||||
});
|
||||
|
||||
/**
|
||||
|
|
@ -15,7 +16,8 @@ class TutorialManager
|
|||
|
||||
panels = new Map([
|
||||
[TUTORIAL_STEP_TYPE.INSTRUCTION, new InstructionPanel(this)],
|
||||
[TUTORIAL_STEP_TYPE.INFO, new InfoPanel(this)]
|
||||
[TUTORIAL_STEP_TYPE.INFO, new InfoPanel(this)],
|
||||
[TUTORIAL_STEP_TYPE.GUI_EXPLANATION, new GuiExplanationPanel(this)]
|
||||
]);
|
||||
|
||||
displayedSteps = []; // All steps that have already been displayed, in the form of [stepType, panelData]
|
||||
|
|
@ -117,8 +119,18 @@ class TutorialManager
|
|||
if (!this.panels.has(stepType))
|
||||
throw new Error("Failed to display tutorial step: Unkown step type: " + stepType);
|
||||
|
||||
this.panels.forEach((panel, type) => panel.setVisible(type == stepType));
|
||||
// Explicitly don't hide the previously active panel if the new step is a GUI explanation. It's displayed
|
||||
// "on top" of everything else.
|
||||
if (stepType == TUTORIAL_STEP_TYPE.GUI_EXPLANATION)
|
||||
{
|
||||
this.panels.get(TUTORIAL_STEP_TYPE.GUI_EXPLANATION).setVisible(true);
|
||||
this.activePanel.setEnabled(false);
|
||||
}
|
||||
else
|
||||
this.panels.forEach((panel, type) => panel.setVisible(type == stepType));
|
||||
|
||||
this.activePanel = this.panels.get(stepType);
|
||||
this.activePanel.setEnabled(true);
|
||||
this.activePanel.displayStep(panelData);
|
||||
|
||||
this.displayedSteps.push([stepType, panelData]);
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ class TutorialPanel
|
|||
hint;
|
||||
button;
|
||||
|
||||
constructor(name, manager)
|
||||
constructor(name, continueAction)
|
||||
{
|
||||
this.panel = Engine.GetGUIObjectByName(name);
|
||||
this.text = Engine.GetGUIObjectByName(name + "Text");
|
||||
|
|
@ -19,7 +19,7 @@ class TutorialPanel
|
|||
this.button = Engine.GetGUIObjectByName(name + "Button");
|
||||
|
||||
this.button.caption = this.ButtonCaptions.Continue;
|
||||
this.button.onPress = manager.continue.bind(manager);
|
||||
this.button.onPress = continueAction;
|
||||
}
|
||||
|
||||
setVisible(visible)
|
||||
|
|
@ -27,6 +27,11 @@ class TutorialPanel
|
|||
this.panel.hidden = !visible;
|
||||
}
|
||||
|
||||
setEnabled(enabled)
|
||||
{
|
||||
this.button.enabled = enabled;
|
||||
}
|
||||
|
||||
displayWarning(warning)
|
||||
{
|
||||
this.hint.caption = coloredText(warning, this.WarningColor);
|
||||
|
|
|
|||
|
|
@ -0,0 +1,249 @@
|
|||
/**
|
||||
* This class manages a tutorial panel meant to explain GUI elements (what they show or do) to the player, like
|
||||
* "The resource counters at the top show how many resources you have ...".
|
||||
* The explanations consist of a title and text. It also highlights the target GUI objects by fading out everything else
|
||||
* with black and uses an arrow to point to them directly.
|
||||
* If the target object is hidden the panel is still shown (pointing to nothing), but a warning displayed.
|
||||
*/
|
||||
class GuiExplanationPanel extends TutorialPanel
|
||||
{
|
||||
panel = Engine.GetGUIObjectByName("guiExplanationPanel");
|
||||
backgroundFade = Engine.GetGUIObjectByName("guiExplanationPanelFade");
|
||||
arrow = Engine.GetGUIObjectByName("guiExplanationPanelArrow");
|
||||
|
||||
currentStep;
|
||||
targetObject;
|
||||
wasTargetHidden = false;
|
||||
|
||||
constructor(manager)
|
||||
{
|
||||
super("guiExplanationPanel", () =>
|
||||
{
|
||||
this.resetTargetObjectZ();
|
||||
this.targetObject = null;
|
||||
manager.continue();
|
||||
});
|
||||
|
||||
// Place the panel in front of all other session objects.
|
||||
this.panel.z = this.OverlayZValue + 10;
|
||||
// Place the black overlay behind the panel.
|
||||
this.backgroundFade.z = this.OverlayZValue - 10;
|
||||
|
||||
// We need to set the arrow's Z value explicitly since it has 'absolute' set to true, which makes it not inherit
|
||||
// the parent's value by default.
|
||||
this.arrow.z = this.OverlayZValue;
|
||||
|
||||
// Initialize the size to a default, with all relative values set to 0.
|
||||
// This is necessary for the custom sizing later.
|
||||
this.panel.size = { "right": this.PanelWidth, "bottom": this.MaxPanelHeight };
|
||||
this.arrow.size = { "right": this.ArrowScale * 2, "bottom": this.ArrowScale };
|
||||
|
||||
this.panel.onWindowResized = this.updatePanelSize.bind(this);
|
||||
this.panel.onTick = this.updateContent.bind(this);
|
||||
}
|
||||
|
||||
setVisible(visible)
|
||||
{
|
||||
super.setVisible(visible);
|
||||
if (!visible)
|
||||
this.resetTargetObjectZ();
|
||||
}
|
||||
|
||||
resetTargetObjectZ()
|
||||
{
|
||||
if (this.targetObject)
|
||||
this.targetObject.z = this.targetOriginalZ;
|
||||
}
|
||||
|
||||
displayStep(step)
|
||||
{
|
||||
super.displayStep(step);
|
||||
|
||||
this.resetTargetObjectZ();
|
||||
|
||||
if (!["left", "top", "right", "bottom"].includes(step.side))
|
||||
throw new Error("GuiExplanationPanel: Invalid or no side specified:" + step.side + ". It must be 'left', 'top', 'right', or 'bottom'.");
|
||||
|
||||
this.targetObject = Engine.TryGetGUIObjectByName(step.targetObject);
|
||||
if (!this.targetObject)
|
||||
throw new Error("GuiExplanationPanel: Non-existing target GUI object specified: '" + step.targetObject + "'.");
|
||||
|
||||
this.currentStep = step;
|
||||
|
||||
// This results in the target's grandchildren taking higher Z values than this panel (since they get their parent's value + 10).
|
||||
// But that's ok, since they should never overlap anyway.
|
||||
this.targetOriginalZ = this.targetObject.z;
|
||||
this.targetObject.z = this.OverlayZValue;
|
||||
|
||||
this.arrow.sprite = this.ArrowSprites[step.side];
|
||||
|
||||
this.wasTargetHidden = undefined;
|
||||
this.updateContent();
|
||||
}
|
||||
|
||||
/**
|
||||
* Check the visibility of the target object and update the text and background fade accordingly, if necessary.
|
||||
*/
|
||||
updateContent()
|
||||
{
|
||||
if (!this.targetObject)
|
||||
return;
|
||||
|
||||
const displayTextAndTitle = (title, text) =>
|
||||
{
|
||||
this.text.caption = (title ? setStringTags(title, this.TitleTags) + setStringTags("\n\n", { "font": "sans-3" }) : "") + text;
|
||||
this.updatePanelSize();
|
||||
};
|
||||
|
||||
if (this.targetObject.hidden && !this.wasTargetHidden)
|
||||
{
|
||||
this.backgroundFade.hidden = true;
|
||||
displayTextAndTitle(this.currentStep.title, this.HiddenWarning);
|
||||
this.wasTargetHidden = true;
|
||||
}
|
||||
else if (!this.targetObject.hidden && (this.wasTargetHidden == undefined || this.wasTargetHidden))
|
||||
{
|
||||
this.backgroundFade.hidden = false;
|
||||
displayTextAndTitle(this.currentStep.title, this.currentStep.text);
|
||||
this.wasTargetHidden = false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Place the panel next to the target object on the desired side relative to it.
|
||||
*/
|
||||
updatePanelSize()
|
||||
{
|
||||
if (!this.targetObject)
|
||||
return;
|
||||
|
||||
const panelHeight = Math.min(this.MaxPanelHeight, this.text.size.top + this.text.getTextSize().height - this.text.size.bottom);
|
||||
const targetComputedSize = this.targetObject.getComputedSize();
|
||||
const targetHorizontalCenter = (targetComputedSize.left + targetComputedSize.right) / 2;
|
||||
const targetVerticalCenter = (targetComputedSize.top + targetComputedSize.bottom) / 2;
|
||||
|
||||
// Don't perfectly center the panel on the target object, instead shift it to one side a bit.
|
||||
// That looks better.
|
||||
const panelPlacementRatio = 0.3;
|
||||
|
||||
if (this.currentStep.side == "top" || this.currentStep.side == "bottom")
|
||||
{
|
||||
this.panel.size.left = targetHorizontalCenter - panelPlacementRatio * this.PanelWidth;
|
||||
this.panel.size.right = targetHorizontalCenter + (1 - panelPlacementRatio) * this.PanelWidth;
|
||||
this.arrow.size.left = targetHorizontalCenter - this.ArrowScale;
|
||||
this.arrow.size.right = targetHorizontalCenter + this.ArrowScale;
|
||||
|
||||
if (this.currentStep.side == "top")
|
||||
{
|
||||
this.panel.size.bottom = targetComputedSize.top - this.PanelDistanceFromTarget;
|
||||
this.panel.size.top = this.panel.size.bottom - panelHeight;
|
||||
this.arrow.size.bottom = targetComputedSize.top - this.ArrowDistanceFromTarget;
|
||||
this.arrow.size.top = this.arrow.size.bottom - this.ArrowScale;
|
||||
}
|
||||
else
|
||||
{
|
||||
this.panel.size.top = targetComputedSize.bottom + this.PanelDistanceFromTarget;
|
||||
this.panel.size.bottom = this.panel.size.top + panelHeight;
|
||||
this.arrow.size.top = targetComputedSize.bottom + this.ArrowDistanceFromTarget;
|
||||
this.arrow.size.bottom = this.arrow.size.top + this.ArrowScale;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
this.panel.size.top = targetVerticalCenter - panelPlacementRatio * panelHeight;
|
||||
this.panel.size.bottom = targetVerticalCenter + (1 - panelPlacementRatio) * panelHeight;
|
||||
this.arrow.size.top = targetVerticalCenter - this.ArrowScale;
|
||||
this.arrow.size.bottom = targetVerticalCenter + this.ArrowScale;
|
||||
|
||||
if (this.currentStep.side == "left")
|
||||
{
|
||||
this.panel.size.right = targetComputedSize.left - this.PanelDistanceFromTarget;
|
||||
this.panel.size.left = this.panel.size.right - this.PanelWidth;
|
||||
this.arrow.size.right = targetComputedSize.left - this.ArrowDistanceFromTarget;
|
||||
this.arrow.size.left = this.arrow.size.right - this.ArrowScale;
|
||||
}
|
||||
else
|
||||
{
|
||||
this.panel.size.left = targetComputedSize.right + this.PanelDistanceFromTarget;
|
||||
this.panel.size.right = this.panel.size.left + this.PanelWidth;
|
||||
this.arrow.size.left = targetComputedSize.right + this.ArrowDistanceFromTarget;
|
||||
this.arrow.size.right = this.arrow.size.left + this.ArrowScale;
|
||||
}
|
||||
}
|
||||
|
||||
let root = this.panel;
|
||||
while (root.parent) root = root.parent;
|
||||
const screenSize = root.getComputedSize();
|
||||
|
||||
// Perform some clamping to ensure the panel is always fully visible on the screen.
|
||||
if (this.panel.size.left < 0)
|
||||
{
|
||||
this.panel.size.right -= this.panel.size.left;
|
||||
this.panel.size.left = 0;
|
||||
}
|
||||
else if (this.panel.size.right > screenSize.right)
|
||||
{
|
||||
this.panel.size.left -= this.panel.size.right - screenSize.right;
|
||||
this.panel.size.right = screenSize.right;
|
||||
}
|
||||
if (this.panel.size.top < 0)
|
||||
{
|
||||
this.panel.size.bottom -= this.panel.size.top;
|
||||
this.panel.size.top = 0;
|
||||
}
|
||||
else if (this.panel.size.bottom > screenSize.bottom)
|
||||
{
|
||||
this.panel.size.top -= this.panel.size.bottom - screenSize.bottom;
|
||||
this.panel.size.bottom = screenSize.bottom;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Warning shown whilever the target objects is hidden.
|
||||
*/
|
||||
GuiExplanationPanel.prototype.HiddenWarning = coloredText(
|
||||
translate("It is currently hidden. Follow the previous instructions for it to be shown again."),
|
||||
"orange"
|
||||
);
|
||||
|
||||
/**
|
||||
* GUI tags applied to the shown title.
|
||||
*/
|
||||
GuiExplanationPanel.prototype.TitleTags = { "color": "gold", "font": "sans-bold-18" };
|
||||
|
||||
/**
|
||||
* Which sprite to use depending on the side that the description panel is placed on. The sprites only differ in rotation.
|
||||
* E.g. if the panel is placed to the left of the target object, the arrow has to point to the right.
|
||||
*/
|
||||
GuiExplanationPanel.prototype.ArrowSprites = {
|
||||
"left": "GoldenArrowRight",
|
||||
"top": "GoldenArrowDown",
|
||||
"right": "GoldenArrowLeft",
|
||||
"bottom": "GoldenArrowUp"
|
||||
};
|
||||
|
||||
GuiExplanationPanel.prototype.PanelWidth = 600;
|
||||
GuiExplanationPanel.prototype.MaxPanelHeight = 200;
|
||||
|
||||
/**
|
||||
* Margin between the target object and the panel itself. The arrow has to fit inside that gap.
|
||||
*/
|
||||
GuiExplanationPanel.prototype.PanelDistanceFromTarget = 40;
|
||||
|
||||
/**
|
||||
* Margin between the target object and the arrow.
|
||||
*/
|
||||
GuiExplanationPanel.prototype.ArrowDistanceFromTarget = 5;
|
||||
|
||||
/**
|
||||
* Greater than the z value of all other session GUI objects (except the watermark).
|
||||
*/
|
||||
GuiExplanationPanel.prototype.OverlayZValue = 250;
|
||||
|
||||
/**
|
||||
* The arrow is always twice as wide as it is long.
|
||||
* Therefore, for vertical arrows (pointing up or down) this defines the height and half the width,
|
||||
* while for horizontal arrows (pointing left or right) this defines the width and half the height.
|
||||
*/
|
||||
GuiExplanationPanel.prototype.ArrowScale = 32;
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<object name="guiExplanationPanel" type="image" sprite="GuiExplanationPanel">
|
||||
<object name="guiExplanationPanelFade" type="image" sprite="color:0 0 0 125" ghost="true" absolute="true"/>
|
||||
<object name="guiExplanationPanelText" type="text" size="18 18 100%-18 100%-54" style="TutorialExplanationText"/>
|
||||
<object name="guiExplanationPanelButton" type="button" style="ModernButtonRed" size="100%-170 100%-42 100%-30 100%-14"/>
|
||||
<object name="guiExplanationPanelHint" type="text" style="ModernLeftLabelText" size="25 100%-48 100%-190 100%-8"/>
|
||||
<object name="guiExplanationPanelArrow" type="image" absolute="true"/>
|
||||
</object>
|
||||
|
|
@ -14,7 +14,7 @@ class InfoPanel extends TutorialPanel
|
|||
|
||||
constructor(manager)
|
||||
{
|
||||
super("infoPanel", manager);
|
||||
super("infoPanel", manager.continue.bind(manager));
|
||||
}
|
||||
|
||||
displayStep(step)
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ class InstructionPanel extends TutorialPanel
|
|||
|
||||
constructor(manager)
|
||||
{
|
||||
super("instructionPanel", manager);
|
||||
super("instructionPanel", manager.continue.bind(manager));
|
||||
}
|
||||
|
||||
displayStep(step)
|
||||
|
|
|
|||
|
|
@ -1,7 +1,8 @@
|
|||
// Needs to be kept in sync with the one in gui/session/tutorial/Tutorial.js
|
||||
var TUTORIAL_STEP_TYPE = deepfreeze({
|
||||
"INSTRUCTION": 1,
|
||||
"INFO": 2
|
||||
"INFO": 2,
|
||||
"GUI_EXPLANATION": 3
|
||||
});
|
||||
|
||||
Engine.RegisterGlobal("TUTORIAL_STEP_TYPE", TUTORIAL_STEP_TYPE);
|
||||
|
|
|
|||
|
|
@ -29,9 +29,10 @@ Trigger.prototype.tutorialSteps = [
|
|||
}
|
||||
},
|
||||
{
|
||||
"type": TUTORIAL_STEP_TYPE.INFO,
|
||||
"type": TUTORIAL_STEP_TYPE.GUI_EXPLANATION,
|
||||
"panelData": {
|
||||
"appendable": true,
|
||||
"targetObject": "unitCommands",
|
||||
"side": "top",
|
||||
"title": markForTranslation("Production Panel"),
|
||||
"texts": [
|
||||
markForTranslation("Now that the Civic Center is selected, you will notice that a production panel will appear on the lower right of your screen detailing the actions that the buildings supports. For the production panel, available actions are not masked in any color, while an icon masked in gray indicates that the action has not been unlocked and a red mask indicates that you do not have sufficient resources to perform that action. Additionally, you can hover the cursor over any icon to show a tooltip with more details."),
|
||||
|
|
@ -166,13 +167,25 @@ Trigger.prototype.tutorialSteps = [
|
|||
this.NextStep();
|
||||
}
|
||||
},
|
||||
{
|
||||
|
||||
"type": TUTORIAL_STEP_TYPE.GUI_EXPLANATION,
|
||||
"panelData": {
|
||||
"targetObject": "resourceCounts",
|
||||
"side": "bottom",
|
||||
"title": markForTranslation("Resource Supply"),
|
||||
"text": markForTranslation("Direct your attention to the panel at the top of your screen. On the upper left, you will see your current resource supply (food, wood, stone, and metal). As each worker brings resources back to the Civic Center (or another dropsite), you will see the amount of the corresponding resource increase."),
|
||||
"showContinueButton": true
|
||||
},
|
||||
"OnTrainingFinished": function(msg)
|
||||
{
|
||||
this.trainingFinished = true;
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": TUTORIAL_STEP_TYPE.INFO,
|
||||
"panelData": {
|
||||
"texts": [
|
||||
markForTranslation("While waiting, direct your attention to the panel at the top of your screen. On the upper left, you will see your current resource supply (food, wood, stone, and metal). As each worker brings resources back to the Civic Center (or another dropsite), you will see the amount of the corresponding resource increase."),
|
||||
markForTranslation("This is a very important concept to keep in mind: gathered resources have to be brought back to a dropsite to be accounted, and you should always try to minimize the distance between resource and nearest dropsite to improve your gathering efficiency.")
|
||||
],
|
||||
"text": markForTranslation("This is a very important concept to keep in mind: gathered resources have to be brought back to a dropsite to be accounted, and you should always try to minimize the distance between resource and nearest dropsite to improve your gathering efficiency."),
|
||||
"showContinueButton": true
|
||||
},
|
||||
"OnTrainingFinished": function(msg)
|
||||
|
|
@ -270,8 +283,10 @@ Trigger.prototype.tutorialSteps = [
|
|||
}
|
||||
},
|
||||
{
|
||||
"type": TUTORIAL_STEP_TYPE.INSTRUCTION,
|
||||
"type": TUTORIAL_STEP_TYPE.GUI_EXPLANATION,
|
||||
"panelData": {
|
||||
"targetObject": "resourceCounts",
|
||||
"side": "bottom",
|
||||
"text": markForTranslation("The units should be ready soon.\nIn the meantime, direct your attention to your population count on the top panel. It is the fifth item from the left, after the resources. It would be prudent to keep an eye on it. It indicates your current population (including those being trained) and the current population limit, which is determined by your built structures."),
|
||||
"hint": markForTranslation("Wait for the training of the Civilians to finish.")
|
||||
},
|
||||
|
|
|
|||
Loading…
Reference in a new issue