Add an info panel to the tutorial

This patch adds a new tutorial step type and corresponding tutorial
panel labelled "info". It is intended to display steps whose purpose it
is to explain something to the player and give tips -- rather than
just giving instructions and telling the player what to do, like the
instruction panel does.
Also, it can show several related steps at once. To do that, the first
step has to set the 'appendable' flag to true and can also define a
title; then the succeeding steps can then set the 'appendToPrevious'
flag to true in order to do exactly that.
Note: 'info'-type tutorial steps are still supposed to be able to define
triggers, switch to the next step on their own and hide the continue
button on the info panel, to teach the topic interactively, e.g.
"Select a unit by left-clicking on it."

In order to prevent code duplication between `InfoPanel` and
`InstructionPanel` a generic superclass `TutorialPanel` is introduced,
which manages the text, hint, and button objects.
This commit is contained in:
Vantha
2026-03-09 18:42:43 +01:00
committed by Vantha
parent 6dd8139b43
commit 7e77065c56
13 changed files with 427 additions and 149 deletions
@@ -21,6 +21,7 @@
<script directory="gui/session/top_panel/IconButtons/"/>
<script directory="gui/session/trade/"/>
<script directory="gui/session/tutorial/"/>
<script directory="gui/session/tutorial/panels/"/>
<object name="session">
@@ -234,6 +234,26 @@
sprite_overlay="ModernDarkBoxGoldBorder"
/>
<style name="TutorialInfoText"
buffer_zone="16"
font="sans-16"
sprite="ModernDarkBoxGold"
scrollbar="true"
scrollbar_style="ModernScrollBar"
scroll_bottom="true"
textcolor="white"
text_align="left"
text_valign="top"
/>
<style name="TutorialInfoTitle"
buffer_zone="10"
font="sans-bold-18"
textcolor="white"
text_align="center"
text_valign="center"
/>
<!-- ================================ ================================ -->
<!-- Icon Styles -->
<!-- ================================ ================================ -->
@@ -1,75 +0,0 @@
/**
* This class manages a tutorial panel meant to display basic instructions of simple tasks for the player to fulfill,
* consisting of just a text, like "Order one of your units to build a house."
*/
class InstructionPanel
{
panel = Engine.GetGUIObjectByName("instructionPanel");
text = Engine.GetGUIObjectByName("instructionPanelText");
hint = Engine.GetGUIObjectByName("instructionPanelHint");
continueButton = Engine.GetGUIObjectByName("instructionPanelContinueButton");
instructions = [];
closePage;
constructor(closePage)
{
this.closePage = closePage;
this.continueButton.onPress = () =>
{
Engine.PostNetworkCommand({ "type": "dialog-answer", "tutorial": "continue" });
};
}
setVisible(visible)
{
this.panel.hidden = !visible;
}
displayWarning(warning)
{
this.hint.caption = setStringTags(warning, this.WarningTags);
}
displayStep(panelData)
{
this.text.caption = panelData.text;
const panelHeight = Math.min(this.MaxPanelHeight, this.text.size.top + this.text.getTextSize().height - this.text.size.bottom);
this.panel.size.bottom = this.panel.getComputedSize().top + panelHeight;
if (panelData.showContinueButton)
{
this.continueButton.hidden = false;
if (panelData.isLast)
{
this.hint.caption = translate("Click to quit this tutorial.");
this.continueButton.caption = translate("Quit");
this.continueButton.onPress = this.closePage;
}
else
this.hint.caption = this.HintCaptions.Continue;
}
else
{
this.hint.caption = this.HintCaptions.Instruction;
this.continueButton.hidden = true;
}
}
}
/**
* Tags applied to the most recent instruction.
*/
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.")
};
InstructionPanel.prototype.MaxPanelHeight = 185;
@@ -1,4 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<object name="tutorialPanels">
<include file="gui/session/tutorial/InstructionPanel.xml"/>
<include directory="gui/session/tutorial/panels/"/>
</object>
@@ -1,6 +1,7 @@
// Needs to be kept in sync with the one in maps/scripts/Tutorial.js
const TUTORIAL_STEP_TYPE = deepfreeze({
"INSTRUCTION": 1
"INSTRUCTION": 1,
"INFO": 2
});
/**
@@ -21,6 +22,7 @@ class TutorialManager
this.closePageCallback = closePageCallback;
this.panels.set(TUTORIAL_STEP_TYPE.INSTRUCTION, new InstructionPanel(this.closePage.bind(this)));
this.panels.set(TUTORIAL_STEP_TYPE.INFO, new InfoPanel(this.closePage.bind(this)));
this.parentObj.hidden = true;
}
@@ -0,0 +1,77 @@
/**
* Generic superclass for tutorial panels that manages:
* - a text object showing a step's main content
* - a hint object giving hints or showing warnings
* - a button to continue the tutorial or quit when it's over
*/
class TutorialPanel
{
panel;
text;
hint;
button;
closePage;
constructor(name, closePage)
{
this.panel = Engine.GetGUIObjectByName(name);
this.text = Engine.GetGUIObjectByName(name + "Text");
this.hint = Engine.GetGUIObjectByName(name + "Hint");
this.button = Engine.GetGUIObjectByName(name + "Button");
this.button.caption = this.ButtonCaptions.Continue;
this.button.onPress = () =>
{
Engine.PostNetworkCommand({ "type": "dialog-answer", "tutorial": "continue" });
};
this.closePage = closePage;
}
setVisible(visible)
{
this.panel.hidden = !visible;
}
displayWarning(warning)
{
this.hint.caption = coloredText(warning, this.WarningColor);
}
displayStep(step)
{
this.text.caption = step.text;
if (step.showContinueButton)
{
this.button.hidden = false;
if (step.isLast)
{
this.hint.caption = this.HintCaptions.Quit;
this.button.caption = this.ButtonCaptions.Quit;
this.button.onPress = this.closePage;
}
else
this.hint.caption = this.HintCaptions.Continue;
}
else
{
this.hint.caption = this.HintCaptions.Instruction;
this.button.hidden = true;
}
}
}
TutorialPanel.prototype.WarningColor = "orange";
TutorialPanel.prototype.ButtonCaptions = {
"Quit": translateWithContext("button caption", "Quit"),
"Continue": translateWithContext("button caption", "Continue")
};
TutorialPanel.prototype.HintCaptions = {
"Continue": translate("Click to continue."),
"Instruction": translate("Follow the instructions."),
"Quit": translate("Click to quit this tutorial.")
};
@@ -0,0 +1,66 @@
/**
* This class manages a tutorial panel meant to explain game concepts or mechanics to the player, like selecting units
* or bartering, for example.
* These explanations consist of a title and paragraphs of texts. New steps to display don't have to replace the
* preceding ones; with the 'appendable' flag they can add a paragraph to the bottom of an existing explanation instead
* making a brand new one.
*/
class InfoPanel extends TutorialPanel
{
title = Engine.GetGUIObjectByName("infoPanelTitle");
paragraphs = [];
appendable = true;
constructor(closePage)
{
super("infoPanel", closePage);
}
displayStep(step)
{
super.displayStep(step);
if (step.appendToPrevious && !this.appendable)
{
error("InfoPanel: Can't append step to previous because previous is marked unappendable.");
return;
}
if (!step.appendToPrevious)
{
this.paragraphs = [];
if (step.title)
this.title.caption = step.title;
else
this.title.hidden = true;
}
// Appendable being false means that no paragraph will be appended to this (first one) in the future.
// In that case, we want to portray it as a single piece of info rather than a list of them.
this.appendable = step.appendToPrevious || step.appendable;
if (this.appendable)
{
this.text.text_align = "left";
const newParagraph = sprintf(this.BulletPointFormat, { "text": step.text });
this.text.caption = this.paragraphs.length ?
this.paragraphs.concat(coloredText(newParagraph, this.NewParagraphColor)).join("\n") :
newParagraph;
this.paragraphs.push(newParagraph);
}
else
{
this.text.text_align = "center";
this.text.caption = step.text;
}
this.text.size.top = this.title.hidden || !this.title.caption ? 27 : 54;
const panelHeight = Math.min(this.MaxPanelHeight, this.text.size.top + this.text.getTextSize().height - this.text.size.bottom);
this.panel.size.bottom = this.panel.getComputedSize().top + panelHeight;
}
}
InfoPanel.prototype.BulletPointFormat = translateWithContext("bullet point format", " • %(text)s");
InfoPanel.prototype.NewParagraphColor = "gold";
InfoPanel.prototype.MaxPanelHeight = 235;
@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<object name="infoPanel" type="image" sprite="ModernDialog" size="50%-365 90 50%+365 345">
<object type="text" size="50%-96 -16 50%+96 10" style="TitleText">
<translatableAttribute id="caption">Information</translatableAttribute>
</object>
<object name="infoPanelTitle" type="text" size="25 17 100%-25 52" style="TutorialInfoTitle"/>
<object name="infoPanelText" type="text" size="25 52 100%-25 100%-64" style="TutorialInfoText"/>
<object name="infoPanelHint" type="text" style="ModernLeftLabelText" size="30 100%-54 100%-200 100%-14"/>
<object name="infoPanelButton" type="button" size="100%-180 100%-48 100%-30 100%-20" style="ModernButtonRed"/>
</object>
@@ -0,0 +1,23 @@
/**
* This class manages a tutorial panel meant to display basic instructions of simple tasks for the player to fulfill,
* consisting of just a text, like "Order one of your units to build a house."
*/
class InstructionPanel extends TutorialPanel
{
instructions = [];
constructor(closePage)
{
super("instructionPanel", closePage);
}
displayStep(step)
{
super.displayStep(step);
const panelHeight = Math.min(this.MaxPanelHeight, this.text.size.top + this.text.getTextSize().height - this.text.size.bottom);
this.panel.size.bottom = this.panel.getComputedSize().top + panelHeight;
}
}
InstructionPanel.prototype.MaxPanelHeight = 185;
@@ -2,7 +2,5 @@
<object name="instructionPanel" type="image" sprite="color:0 0 0 125" size="50%-310 80 50%+310 210">
<object name="instructionPanelText" type="text" style="TutorialInstructionText" size="10 10 100%-10 100%-52"/>
<object name="instructionPanelHint" type="text" style="ModernLeftLabelText" size="25 100%-46 100%-190 100%-6"/>
<object name="instructionPanelContinueButton" type="button" style="ModernButtonRed" size="100%-170 100%-40 100%-30 100%-12">
<translatableAttribute id="caption">Continue</translatableAttribute>
</object>
<object name="instructionPanelButton" type="button" style="ModernButtonRed" size="100%-170 100%-40 100%-30 100%-12"/>
</object>
@@ -1,6 +1,7 @@
// Needs to be kept in sync with the one in gui/session/tutorial/Tutorial.js
var TUTORIAL_STEP_TYPE = deepfreeze({
"INSTRUCTION": 1
"INSTRUCTION": 1,
"INFO": 2
});
Engine.RegisterGlobal("TUTORIAL_STEP_TYPE", TUTORIAL_STEP_TYPE);
@@ -2,13 +2,38 @@ Trigger.prototype.tutorialSteps = [
{
"type": TUTORIAL_STEP_TYPE.INSTRUCTION,
"panelData": {
"text":
markForTranslation("This tutorial will teach the basics of developing your economy. Typically, you will start with a Civic Center and a couple units in Village Phase and ultimately, your goal will be to develop and expand your empire, often by evolving to Town Phase and City Phase afterward.\n") +
markForTranslation("\nBefore starting, you can toggle between fullscreen and windowed mode using %(hotkey1)s.") +
markForTranslation("You can change the level of zoom using the mouse wheel and the camera view using any of your keyboard's arrow keys.\n") +
markForTranslation("Adjust the game window to your preferences.\n") +
markForTranslation("\nYou may also toggle between showing and hiding this tutorial panel at any moment using %(hotkey2)s.\n"),
"hotkeys": ["togglefullscreen", "session.gui.tutorial.toggle"]
"text": markForTranslation("This tutorial will teach the basics of developing your economy. Typically, you will start with a Civic Center and a couple units in Village Phase and ultimately, your goal will be to develop and expand your empire, often by evolving to Town Phase and City Phase afterward.")
}
},
{
"type": TUTORIAL_STEP_TYPE.INFO,
"panelData": {
"appendable": "true",
"title": markForTranslation("Basic Controls"),
"text": markForTranslation("You can toggle between fullscreen and windowed mode using %(hotkey)s."),
"hotkeys": ["togglefullscreen"]
}
},
{
"type": TUTORIAL_STEP_TYPE.INFO,
"panelData": {
"appendToPrevious": "true",
"text": markForTranslation("You can change the level of zoom using the mouse wheel and the camera view using any of your keyboard's arrow keys.")
}
},
{
"type": TUTORIAL_STEP_TYPE.INFO,
"panelData": {
"appendToPrevious": "true",
"text": markForTranslation("Adjust the game window to your preferences.")
}
},
{
"type": TUTORIAL_STEP_TYPE.INFO,
"panelData": {
"appendToPrevious": "true",
"text": markForTranslation("You may also toggle between showing and hiding this tutorial panel at any moment using %(hotkey)s."),
"hotkeys": ["session.gui.tutorial.toggle"]
}
},
{
@@ -18,38 +43,81 @@ Trigger.prototype.tutorialSteps = [
}
},
{
"type": TUTORIAL_STEP_TYPE.INSTRUCTION,
"type": TUTORIAL_STEP_TYPE.INFO,
"panelData": {
"text":
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.\n") +
markForTranslation("The top row of buttons contains portraits of units that may be trained at the building while the bottom one or two rows will have researchable technologies. Hover the cursor over the II icon. The tooltip will tell us that advancing to Town Phase requires both more constructed structures as well as more food and wood resources.")
"appendable": "true",
"title": markForTranslation("Production Panel"),
"text": 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.")
}
},
{
"type": TUTORIAL_STEP_TYPE.INFO,
"panelData": {
"appendToPrevious": "true",
"text": markForTranslation("The top row of buttons contains portraits of units that may be trained at the building while the bottom one or two rows will have researchable technologies. Hover the cursor over the II icon. The tooltip will tell us that advancing to Town Phase requires both more constructed structures as well as more food and wood resources.")
}
},
{
"type": TUTORIAL_STEP_TYPE.INFO,
"panelData": {
"title": markForTranslation("Types of Units"),
"text": markForTranslation("You have two main types of starting units: Civilians and Citizen Soldiers. Civilians are purely economic units; they have low health and little to no attack. Citizen Soldiers are workers by default, but in times of need, can utilize a weapon to fight. You have two categories of Citizen Soldiers: Infantry and Cavalry. Civilians and Infantry Citizen Soldiers can gather any land resources while Cavalry Citizen Soldiers can only gather meat from animals.")
}
},
{
"type": TUTORIAL_STEP_TYPE.INFO,
"panelData": {
"text": markForTranslation("As a general rule of thumb, left-clicking represents selection while right-clicking with an entity selected represents an order (gather, build, fight, etc.).")
}
},
{
"type": TUTORIAL_STEP_TYPE.INFO,
"panelData": {
"appendable": "true",
"title": markForTranslation("Making Selections"),
"text": markForTranslation("There are primarily three ways to select units:")
}
},
{
"type": TUTORIAL_STEP_TYPE.INFO,
"panelData": {
"appendToPrevious": "true",
"text": markForTranslation("1) Hold the left mouse button and drag a selection rectangle that encloses the units you want to select.")
}
},
{
"type": TUTORIAL_STEP_TYPE.INFO,
"panelData": {
"appendToPrevious": "true",
"text": markForTranslation("2) Click on one of them and then add additional units to your selection by holding %(hotkey)s and clicking each additional unit (or also via the above selection rectangle)."),
"hotkeys": ["selection.add"]
}
},
{
"type": TUTORIAL_STEP_TYPE.INFO,
"panelData": {
"appendToPrevious": "true",
"text": markForTranslation("3) Double-click on a unit. This will select every unit of the same type as the specified unit in your visible window. %(hotkey)s+double-click will select all units of the same type on the entire map."),
"hotkeys": ["selection.offscreen"]
}
},
{
"type": TUTORIAL_STEP_TYPE.INFO,
"panelData": {
"appendToPrevious": "true",
"text": markForTranslation("You can click on an empty space on the map to reset the selection.")
}
},
{
"type": TUTORIAL_STEP_TYPE.INFO,
"panelData": {
"text": markForTranslation("At this point, food and wood are the most important resources for developing your economy.")
}
},
{
"type": TUTORIAL_STEP_TYPE.INSTRUCTION,
"panelData": {
"text":
markForTranslation("You have two main types of starting units: Civilians and Citizen Soldiers. Civilians are purely economic units; they have low health and little to no attack. Citizen Soldiers are workers by default, but in times of need, can utilize a weapon to fight. You have two categories of Citizen Soldiers: Infantry and Cavalry. Civilians and Infantry Citizen Soldiers can gather any land resources while Cavalry Citizen Soldiers can only gather meat from animals.\n")
}
},
{
"type": TUTORIAL_STEP_TYPE.INSTRUCTION,
"panelData": {
"text":
markForTranslation("As a general rule of thumb, left-clicking represents selection while right-clicking with an entity selected represents an order (gather, build, fight, etc.).\n")
}
},
{
"type": TUTORIAL_STEP_TYPE.INSTRUCTION,
"panelData": {
"text":
markForTranslation("At this point, food and wood are the most important resources for developing your economy, so let's start with gathering food. Civilians gather vegetables faster than other units.\n") +
markForTranslation("There are primarily three ways to select units:\n") +
markForTranslation("1) Hold the left mouse button and drag a selection rectangle that encloses the units you want to select.\n") +
markForTranslation("2) Click on one of them and then add additional units to your selection by holding %(hotkey1)s and clicking each additional unit (or also via the above selection rectangle).\n") +
markForTranslation("3) Double-click on a unit. This will select every unit of the same type as the specified unit in your visible window. %(hotkey2)s+double-click will select all units of the same type on the entire map.\n") +
markForTranslation("You can click on an empty space on the map to reset the selection. Try each of these methods before tasking all of your Civilians to gather the berries to the southeast of your Civic Center by right-clicking on the berries when you have all the Civilians selected."),
"hotkeys": ["selection.add", "selection.offscreen"]
"text": markForTranslation("Let's start with gathering food. Civilians gather vegetables faster than other units. Select them and order them to gather the berries to the southeast of your Civic Center by right-clicking on the berries.")
},
"OnPlayerCommand": function(msg)
{
@@ -85,10 +153,15 @@ Trigger.prototype.tutorialSteps = [
{
"type": TUTORIAL_STEP_TYPE.INSTRUCTION,
"panelData": {
"text":
markForTranslation("All your units are now gathering resources. We should train more units!\n") +
markForTranslation("First, let's set a rally point. Setting a rally point on a building that can train units will automatically designate a task to the new unit upon completion of training. We want to send the newly trained units to gather wood on the group of trees to the south of the Civic Center. To do so, select the Civic Center by clicking on it and then right-click on one of the trees.\n") +
markForTranslation("Rally points are indicated by a small flag at the end of the blue line.")
"text": markForTranslation("All your units are now gathering resources. We should train more units!")
}
},
{
"type": TUTORIAL_STEP_TYPE.INFO,
"panelData": {
"appendable": true,
"title": markForTranslation("Rally Points"),
"text": markForTranslation("First, let's set a rally point. Setting a rally point on a building that can train units will automatically designate a task to the new unit upon completion of training. We want to send the newly trained units to gather wood on the group of trees to the south of the Civic Center. To do so, select the Civic Center by clicking on it and then right-click on one of the trees.")
},
"OnPlayerCommand": function(msg)
{
@@ -102,11 +175,24 @@ Trigger.prototype.tutorialSteps = [
this.NextStep();
}
},
{
"type": TUTORIAL_STEP_TYPE.INFO,
"panelData": {
"appendToPrevious": true,
"text": markForTranslation("Rally points are indicated by a small flag at the end of the blue line.")
}
},
{
"type": TUTORIAL_STEP_TYPE.INFO,
"panelData": {
"appendToPrevious": true,
"text": markForTranslation("Now that the rally point is set, we can produce additional units and they will do their assigned task automatically.")
}
},
{
"type": TUTORIAL_STEP_TYPE.INSTRUCTION,
"panelData": {
"text":
markForTranslation("Now that the rally point is set, we can produce additional units and they will do their assigned task automatically.\n") +
markForTranslation("Citizen Soldiers gather wood faster than Civilians. Select the Civic Center and, while holding %(hotkey)s, click on the second unit icon, the Hoplites (holding %(hotkey)s trains a batch of five units). You can also train units individually by simply clicking, but training 5 units together takes less time than training 5 units individually."),
"hotkeys": ["session.batchtrain"]
},
@@ -126,26 +212,64 @@ Trigger.prototype.tutorialSteps = [
this.NextStep();
}
},
{
"type": TUTORIAL_STEP_TYPE.INFO,
"panelData": {
"appendable": true,
"text": 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."),
"showContinueButton": true
},
"OnTrainingFinished": function(msg)
{
this.trainingFinished = true;
}
},
{
"type": TUTORIAL_STEP_TYPE.INFO,
"panelData": {
"appendToPrevious": true,
"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)
{
this.trainingFinished = true;
}
},
{
"type": TUTORIAL_STEP_TYPE.INSTRUCTION,
"panelData": {
"text":
markForTranslation("Let's wait for the units to be trained.\n") +
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.\n") +
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("Let's wait for the units to be trained.")
},
"IsDone": function()
{
return this.trainingFinished;
},
"OnTrainingFinished": function(msg)
{
this.NextStep();
}
},
{
"type": TUTORIAL_STEP_TYPE.INFO,
"panelData": {
"appendable": true,
"title": markForTranslation("Storehouse"),
"text": markForTranslation("The newly trained units automatically go to the trees and start gathering wood.")
}
},
{
"type": TUTORIAL_STEP_TYPE.INFO,
"panelData": {
"appendToPrevious": true,
"text": markForTranslation("But as they have to bring it back to the Civic Center to deposit it, their gathering efficiency suffers from the distance. To fix that, we can build a Storehouse, a dropsite for wood, stone, and metal, close to the trees.")
}
},
{
"type": TUTORIAL_STEP_TYPE.INSTRUCTION,
"panelData": {
"text":
markForTranslation("The newly trained units automatically go to the trees and start gathering wood.\n") +
markForTranslation("But as they have to bring it back to the Civic Center to deposit it, their gathering efficiency suffers from the distance. To fix that, we can build a Storehouse, a dropsite for wood, stone, and metal, close to the trees. To do so, select your five newly trained Citizen Soldiers and look for the construction panel on the bottom right, click on the Storehouse icon, move the mouse as close as possible to the trees you want to gather and click on a valid place to build the dropsite.\n") +
markForTranslation("Invalid (obstructed) positions will show the building preview overlay in red.")
markForTranslation("To do so, select your five newly trained Citizen Soldiers and look for the construction panel on the bottom right, click on the Storehouse icon, move the mouse as close as possible to the trees you want to gather and click on a valid place to build the dropsite. Invalid (obstructed) positions will show the building preview overlay in red.")
},
"OnPlayerCommand": function(msg)
{
@@ -154,7 +278,7 @@ Trigger.prototype.tutorialSteps = [
}
},
{
"type": TUTORIAL_STEP_TYPE.INSTRUCTION,
"type": TUTORIAL_STEP_TYPE.INFO,
"panelData": {
"text": markForTranslation("The selected Citizens will automatically start constructing the building once you place the foundation.")
},
@@ -165,12 +289,16 @@ Trigger.prototype.tutorialSteps = [
this.NextStep();
}
},
{
"type": TUTORIAL_STEP_TYPE.INFO,
"panelData": {
"text": markForTranslation("When construction finishes, the builders default to gathering wood automatically.")
}
},
{
"type": TUTORIAL_STEP_TYPE.INSTRUCTION,
"panelData": {
"text":
markForTranslation("When construction finishes, the builders default to gathering wood automatically.\n") +
markForTranslation("In the meantime, we seem to have enough workers gathering wood. We should remove the current rally point of the Civic Center away from gathering wood. For that purpose, right-click on the Civic Center when it is selected (and the flag icon indicating the rally point is crossed out).")
"text": markForTranslation("In the meantime, we seem to have enough workers gathering wood. We should remove the current rally point of the Civic Center away from gathering wood. For that purpose, right-click on the Civic Center when it is selected (and the flag icon indicating the rally point is crossed out).")
},
"OnPlayerCommand": function(msg)
{
@@ -203,21 +331,24 @@ Trigger.prototype.tutorialSteps = [
{
"type": TUTORIAL_STEP_TYPE.INSTRUCTION,
"panelData": {
"text":
markForTranslation("The units should be ready soon.\n") +
markForTranslation("In 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.")
"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.")
},
"OnTrainingFinished": function(msg)
{
this.NextStep();
}
},
{
"type": TUTORIAL_STEP_TYPE.INFO,
"panelData": {
"title": markForTranslation("Population Limit"),
"text": markForTranslation("As you have nearly reached the population limit, you must increase it by building some new structures if you want to train more units. The most cost effective structure to increase your population limit is the House.")
}
},
{
"type": TUTORIAL_STEP_TYPE.INSTRUCTION,
"panelData": {
"text":
markForTranslation("As you have nearly reached the population limit, you must increase it by building some new structures if you want to train more units. The most cost effective structure to increase your population limit is the House.\n") +
markForTranslation("Now that the units are ready, let's see how to build several Houses in a row.")
"text": markForTranslation("Now that the units are ready, let's see how to build several Houses in a row.")
}
},
{
@@ -258,12 +389,22 @@ Trigger.prototype.tutorialSteps = [
}
},
{
"type": TUTORIAL_STEP_TYPE.INSTRUCTION,
"type": TUTORIAL_STEP_TYPE.INFO,
"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."),
"showContinueButton": true
"appendable": true,
"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.")
},
"OnOwnershipChanged": function(msg)
{
if (this.houseGoal.has(+msg.entity))
this.houseGoal.delete(+msg.entity);
}
},
{
"type": TUTORIAL_STEP_TYPE.INFO,
"panelData": {
"appendToPrevious": true,
"text": markForTranslation("But to minimize the distance between a farm and its corresponding food dropsite, we will first build a Farmstead.")
},
"OnOwnershipChanged": function(msg)
{
@@ -292,7 +433,7 @@ Trigger.prototype.tutorialSteps = [
}
},
{
"type": TUTORIAL_STEP_TYPE.INSTRUCTION,
"type": TUTORIAL_STEP_TYPE.INFO,
"panelData": {
"text":
markForTranslation("When the Farmstead construction is finished, its builders will automatically look for food, and in this case, they will go after the nearby goats.\n") +
@@ -321,12 +462,16 @@ Trigger.prototype.tutorialSteps = [
this.NextStep();
}
},
{
"type": TUTORIAL_STEP_TYPE.INFO,
"panelData": {
"text": markForTranslation("When the Field is ready, the builders will automatically start gathering it.")
}
},
{
"type": TUTORIAL_STEP_TYPE.INSTRUCTION,
"panelData": {
"text":
markForTranslation("When the Field is ready, the builders will automatically start gathering it.\n") +
markForTranslation("The cavalry unit should have slaughtered all chickens by now. Select it and explore the area to the south of the Civic Center: there is a lake with some camels around. Move your cavalry by right-clicking on the point you want to go, and when you see a herd of camels, right-click on one of them to start hunting for food.")
"text": markForTranslation("The cavalry unit should have slaughtered all chickens by now. Select it and explore the area to the south of the Civic Center: there is a lake with some camels around. Move your cavalry by right-clicking on the point you want to go, and when you see a herd of camels, right-click on one of them to start hunting for food.")
},
"OnPlayerCommand": function(msg)
{
@@ -379,11 +524,18 @@ Trigger.prototype.tutorialSteps = [
}
},
{
"type": TUTORIAL_STEP_TYPE.INSTRUCTION,
"type": TUTORIAL_STEP_TYPE.INFO,
"panelData": {
"text":
markForTranslation("You can increase the gather rates of your workers by researching new technologies available in some buildings.\n") +
markForTranslation("The farming rate, for example, can be improved with a researchable technology in the Farmstead. Select the Farmstead and look at its production panel on the bottom right. You will see several researchable technologies. Hover the cursor over them to see their costs and effects and click on the one you want to research.")
"appendable": true,
"title": markForTranslation("Technologies"),
"text": markForTranslation("You can increase the gather rates of your workers by researching new technologies available in some buildings.")
}
},
{
"type": TUTORIAL_STEP_TYPE.INFO,
"panelData": {
"appendToPrevious": true,
"text": markForTranslation("The farming rate, for example, can be improved with a researchable technology in the Farmstead. Select the Farmstead and look at its production panel on the bottom right. You will see several researchable technologies. Hover the cursor over them to see their costs and effects and click on the one you want to research.")
},
"IsDone": function()
{