1// Console input example.
2// This sample demonstrates:
3//     - Implementing a crude text adventure game, which accepts input both through the engine console,
4//       and standard input.
5//     - Disabling default execution of console commands as immediate mode AngelScript.
6//     - Adding autocomplete options to the engine console.
7
8#include "Scripts/Utilities/Sample.as"
9
10bool gameOn;
11bool foodAvailable;
12bool eatenLastTurn;
13int numTurns;
14int hunger;
15int urhoThreat;
16
17// Hunger level descriptions
18String[] hungerLevels = {
19    "bursting",
20    "well-fed",
21    "fed",
22    "hungry",
23    "very hungry",
24    "starving"
25};
26
27// Urho threat level descriptions
28String[] urhoThreatLevels = {
29    "Suddenly Urho appears from a dark corner of the fish tank",
30    "Urho seems to have his eyes set on you",
31    "Urho is homing in on you mercilessly"
32};
33
34void Start()
35{
36    // Execute the common startup for samples
37    SampleStart();
38
39    // Disable default execution of AngelScript from the console
40    script.executeConsoleCommands = false;
41
42    // Subscribe to console commands and the frame update
43    SubscribeToEvent("ConsoleCommand", "HandleConsoleCommand");
44    SubscribeToEvent("Update", "HandleUpdate");
45
46    // Subscribe key down event
47    SubscribeToEvent("KeyDown", "HandleEscKeyDown");
48
49    // Hide logo to make room for the console
50    SetLogoVisible(false);
51
52    // Show the console by default, make it large
53    console.numRows = graphics.height / 16;
54    console.numBufferedRows = 2 * console.numRows;
55    console.commandInterpreter = "ScriptEventInvoker";
56    console.visible = true;
57	console.closeButton.visible = false;
58	console.AddAutoComplete("help");
59	console.AddAutoComplete("eat");
60	console.AddAutoComplete("hide");
61	console.AddAutoComplete("wait");
62	console.AddAutoComplete("score");
63	console.AddAutoComplete("quit");
64
65    // Show OS mouse cursor
66    input.mouseVisible = true;
67
68    // Set the mouse mode to use in the sample
69    SampleInitMouseMode(MM_FREE);
70
71    // Open the operating system console window (for stdin / stdout) if not open yet
72    // Do not open in fullscreen, as this would cause constant device loss
73    if (!graphics.fullscreen)
74        OpenConsoleWindow();
75
76    // Initialize game and print the welcome message
77    StartGame();
78
79    // Randomize from system clock
80    SetRandomSeed(time.systemTime);
81}
82
83void HandleConsoleCommand(StringHash eventType, VariantMap& eventData)
84{
85    if (eventData["Id"].GetString() == "ScriptEventInvoker")
86        HandleInput(eventData["Command"].GetString());
87}
88
89void HandleUpdate(StringHash eventType, VariantMap& eventData)
90{
91    // Check if there is input from stdin
92    String input = GetConsoleInput();
93    if (input.length > 0)
94        HandleInput(input);
95}
96
97void HandleEscKeyDown(StringHash eventType, VariantMap& eventData)
98{
99    // Unlike the other samples, exiting the engine when ESC is pressed instead of just closing the console
100    if (eventData["Key"].GetInt() == KEY_ESCAPE)
101        engine.Exit();
102}
103
104void StartGame()
105{
106    Print("Welcome to the Urho adventure game! You are the newest fish in the tank; your\n"
107          "objective is to survive as long as possible. Beware of hunger and the merciless\n"
108          "predator cichlid Urho, who appears from time to time. Evading Urho is easier\n"
109          "with an empty stomach. Type 'help' for available commands.");
110
111    gameOn = true;
112    foodAvailable = false;
113    eatenLastTurn = false;
114    numTurns = 0;
115    hunger = 2;
116    urhoThreat = 0;
117}
118
119void EndGame(const String&in message)
120{
121    Print(message);
122    Print("Game over! You survived " + String(numTurns) + " turns.\n"
123          "Do you want to play again (Y/N)?");
124
125    gameOn = false;
126}
127
128void Advance()
129{
130    if (urhoThreat > 0)
131    {
132        ++urhoThreat;
133        if (urhoThreat > 3)
134        {
135            EndGame("Urho has eaten you!");
136            return;
137        }
138    }
139    else if (urhoThreat < 0)
140        ++urhoThreat;
141    if (urhoThreat == 0 && Random() < 0.2f)
142        ++urhoThreat;
143
144    if (urhoThreat > 0)
145        Print(urhoThreatLevels[urhoThreat - 1] + ".");
146
147    if ((numTurns & 3) == 0 && !eatenLastTurn)
148    {
149        ++hunger;
150        if (hunger > 5)
151        {
152            EndGame("You have died from starvation!");
153            return;
154        }
155        else
156            Print("You are " + hungerLevels[hunger] + ".");
157    }
158
159    eatenLastTurn = false;
160
161    if (foodAvailable)
162    {
163        Print("The floating pieces of fish food are quickly eaten by other fish in the tank.");
164        foodAvailable = false;
165    }
166    else if (Random() < 0.15f)
167    {
168        Print("The overhead dispenser drops pieces of delicious fish food to the water!");
169        foodAvailable = true;
170    }
171
172    ++numTurns;
173}
174
175void HandleInput(const String&in input)
176{
177    String inputLower = input.ToLower().Trimmed();
178    if (inputLower.empty)
179    {
180        Print("Empty input given!");
181        return;
182    }
183
184    if (inputLower == "quit" || inputLower == "exit")
185        engine.Exit();
186    else if (gameOn)
187    {
188        // Game is on
189        if (inputLower == "help")
190            Print("The following commands are available: 'eat', 'hide', 'wait', 'score', 'quit'.");
191        else if (inputLower == "score")
192            Print("You have survived " + String(numTurns) + " turns.");
193        else if (inputLower == "eat")
194        {
195            if (foodAvailable)
196            {
197                Print("You eat several pieces of fish food.");
198                foodAvailable = false;
199                eatenLastTurn = true;
200                hunger -= (hunger > 3) ? 2 : 1;
201                if (hunger < 0)
202                {
203                    EndGame("You have killed yourself by over-eating!");
204                    return;
205                }
206                else
207                    Print("You are now " + hungerLevels[hunger] + ".");
208            }
209            else
210                Print("There is no food available.");
211
212            Advance();
213        }
214        else if (inputLower == "wait")
215        {
216            Print("Time passes...");
217            Advance();
218        }
219        else if (inputLower == "hide")
220        {
221            if (urhoThreat > 0)
222            {
223                bool evadeSuccess = hunger > 2 || Random() < 0.5f;
224                if (evadeSuccess)
225                {
226                    Print("You hide behind the thick bottom vegetation, until Urho grows bored.");
227                    urhoThreat = -2;
228                }
229                else
230                    Print("Your movements are too slow; you are unable to hide from Urho.");
231            }
232            else
233                Print("There is nothing to hide from.");
234
235            Advance();
236        }
237        else
238            Print("Cannot understand the input '" + input + "'.");
239    }
240    else
241    {
242        // Game is over, wait for (y)es or (n)o reply
243        if (inputLower[0] == 'y')
244            StartGame();
245        else if (inputLower[0] == 'n')
246            engine.Exit();
247        else
248            Print("Please answer 'y' or 'n'.");
249    }
250}
251
252// Create XML patch instructions for screen joystick layout specific to this sample app
253String patchInstructions =
254        "<patch>" +
255        "    <add sel=\"/element/element[./attribute[@name='Name' and @value='Button2']]\">" +
256        "        <attribute name=\"Is Visible\" value=\"false\" />" +
257        "    </add>" +
258        "    <add sel=\"/element/element[./attribute[@name='Name' and @value='Hat0']]\">" +
259        "        <attribute name=\"Is Visible\" value=\"false\" />" +
260        "    </add>" +
261        "</patch>";
262