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