nsnake
Classic snake game for the terminal
Loading...
Searching...
No Matches
Globals.cpp
1#include <Config/Globals.hpp>
2#include <Engine/EngineGlobals.hpp>
3#include <Engine/Helpers/INI.hpp>
4#include <Engine/Helpers/File.hpp>
5#include <Engine/Helpers/String.hpp>
6#include <Engine/InputManager.hpp>
7#include <Entities/BoardParser.hpp>
8#include <Entities/ScoreFile.hpp>
9
10#include <ncurses.h>
11#include <iostream>
12#include <fstream>
13
14// VERSION is formatted like "0.0.1" - i'm skipping the dots
15char Globals::version[3] = { VERSION[0],
16 VERSION[2],
17 VERSION[4] };
18
19// __ ___ _ ____ _ __
20// / /` / / \ | |\ | | |_ | | / /`_
21// \_\_, \_\_/ |_| \| |_| |_| \_\_/
22
23// real initialization at init()
24std::string Globals::Config::directory = "";
25std::string Globals::Config::file = "";
26std::string Globals::Config::scoresFile = "";
27
28unsigned int Globals::Game::starting_speed = 1;
29int Globals::Game::fruits_at_once = 1;
30bool Globals::Game::random_walls = false;
31bool Globals::Game::teleport = false;
32std::string Globals::Game::current_level = "";
33
34ColorPair Globals::Theme::player_head;
35ColorPair Globals::Theme::player_head_dead;
36ColorPair Globals::Theme::player_body;
37ColorPair Globals::Theme::fruit;
38
39Globals::Game::BoardSize Globals::Game::board_size = LARGE;
40
41Globals::Game::BoardSize Globals::Game::intToBoardSize(int val)
42{
43 if (val == 0)
44 return Globals::Game::SMALL;
45
46 if (val == 1)
47 return Globals::Game::MEDIUM;
48
49 return Globals::Game::LARGE;
50}
51int Globals::Game::boardSizeToInt(Globals::Game::BoardSize size)
52{
53 if (size == Globals::Game::SMALL)
54 return 0;
55
56 if (size == Globals::Game::MEDIUM)
57 return 1;
58
59 return 2;
60}
61
62int Globals::Game::board_scroll_delay = 1000;
63
64bool Globals::Game::board_scroll_up = false;
65bool Globals::Game::board_scroll_down = false;
66bool Globals::Game::board_scroll_left = false;
67bool Globals::Game::board_scroll_right = false;
68
69bool Globals::Error::has_config_file = true;
70bool Globals::Error::has_score_file = true;
71bool Globals::Error::old_version_score_file = false;
72bool Globals::Error::strange_score_file = false;
73
74// _ _ _ _____
75// | | | |\ | | | | |
76// |_| |_| \| |_| |_|
77
79{
80 // Making sure default config directory exists
81 // By default it's `~/.local/share/nsnake/`
82
83 Globals::Config::directory = (Utils::File::getHome() +
84 ".local/share/" +
85 PACKAGE + "/");
86
87 if (Utils::String::front(Globals::Config::directory) != '/')
88 {
89 // We couldn't get user's home directory,
90 // so let's fallback to `/tmp/.local/share...`
91 Globals::Config::directory = ("/tmp/" +
92 Globals::Config::directory);
93 }
94
95 Globals::Config::file = (Globals::Config::directory +
96 "settings.ini");
97
98 Globals::Config::scoresFile = (Globals::Config::directory +
99 "arcade.nsnakescores");
100
101 if (! Utils::File::isDirectory(Globals::Config::directory))
102 Utils::File::mkdir_p(Globals::Config::directory);
103
104 if (! Utils::File::isDirectory(Globals::Config::directory))
105 {
106 // We REALLY can't access the disk by any means.
107 // Let's throw everything away and give up.
108 Globals::Config::directory = "/dev/";
109 Globals::Config::file = "/dev/null";
110 return;
111 }
112
113 // Default Input configurationa
114 InputManager::bind("left", KEY_LEFT);
115 InputManager::bind("right", KEY_RIGHT);
116 InputManager::bind("up", KEY_UP);
117 InputManager::bind("down", KEY_DOWN);
118 InputManager::bind("pause", 'p');
119 InputManager::bind("help", 'h');
120 InputManager::bind("quit", 'q');
121
122
123 // Aww yeah, rev up dem colors
124 Globals::Theme::player_head = Colors::pair("green", "default", true);
125 Globals::Theme::player_head_dead = Colors::pair("red", "default", true);
126 Globals::Theme::player_body = Colors::pair("green", "default", true);
127
128 Globals::Theme::fruit = Colors::pair("red", "default", true);
129
134 BoardParser::directory = Globals::Config::directory + "levels/";
136
138 if (! Utils::File::isDirectory(BoardParser::directory))
139 Utils::File::mkdir_p(BoardParser::directory);
140}
142{
143 // Now, back on track
144 if (! Utils::File::exists(Globals::Config::file))
145 return;
146
147 INI::Parser* ini = NULL;
148
149 try {
150 ini = new INI::Parser(Globals::Config::file);
151 }
152 catch(std::runtime_error& e)
153 {
154 // File doesn't exist (or we couldn't access it)
155 // Either way, ignore it silently
156 SAFE_DELETE(ini);
157 return;
158 }
159
160 // Will be used on this macro below
161 std::string buffer = "";
162
163// Small macro to avoid unnecessary typing.
164//
165// To get something from the ini file we send the
166// text (to identify some value) and the default
167// value in case it doesn't exist.
168//
169// For the last one I send the variable itself,
170// so we fallback to the default values.
171#define INI_GET(var, out, in) \
172 { \
173 buffer = (* ini)(out)[in]; \
174 if (! buffer.empty()) \
175 { \
176 Utils::String::convert(buffer, var); \
177 } \
178 }
179
180 INI_GET(EngineGlobals::Screen::center_horizontally, "screen", "center_horizontal");
181 INI_GET(EngineGlobals::Screen::center_vertically, "screen", "center_vertical");
182
183 INI_GET(EngineGlobals::Screen::show_borders, "screen", "borders");
184 INI_GET(EngineGlobals::Screen::fancy_borders, "screen", "fancy_borders");
185 INI_GET(EngineGlobals::Screen::outer_border, "screen", "outer_border");
186
187 INI_GET(Globals::Game::random_walls, "game", "random_walls");
188 INI_GET(Globals::Game::fruits_at_once, "game", "fruits_at_once");
189 INI_GET(Globals::Game::teleport, "game", "teleport");
190 INI_GET(Globals::Game::board_scroll_delay, "game", "board_scroll_delay");
191
192 INI_GET(Globals::Game::board_scroll_up, "game", "board_scroll_up");
193 INI_GET(Globals::Game::board_scroll_down, "game", "board_scroll_down");
194 INI_GET(Globals::Game::board_scroll_left, "game", "board_scroll_left");
195 INI_GET(Globals::Game::board_scroll_right, "game", "board_scroll_right");
196
197 // unsigned ints are the exception - their overloading
198 // is ambiguous... I should consider removing them altogether
199 buffer = (* ini)("game")["starting_speed"];
200 if (! buffer.empty())
201 {
202 int starting_speed = Globals::Game::starting_speed;
203 Utils::String::convert(buffer, starting_speed);
204 Globals::Game::starting_speed = starting_speed;
205 }
206
207 // Special Cases
208
209 // Getting input keys
210 std::string tmp;
211
212 INI_GET(tmp, "input", "left");
213 InputManager::bind("left", InputManager::stringToKey(tmp));
214
215 INI_GET(tmp, "input", "right");
216 InputManager::bind("right", InputManager::stringToKey(tmp));
217
218 INI_GET(tmp, "input", "up");
219 InputManager::bind("up", InputManager::stringToKey(tmp));
220
221 INI_GET(tmp, "input", "down");
222 InputManager::bind("down", InputManager::stringToKey(tmp));
223
224 INI_GET(tmp, "input", "pause");
225 InputManager::bind("pause", InputManager::stringToKey(tmp));
226
227 INI_GET(tmp, "input", "help");
228 InputManager::bind("help", InputManager::stringToKey(tmp));
229
230 INI_GET(tmp, "input", "quit");
231 InputManager::bind("quit", InputManager::stringToKey(tmp));
232
233 // Board Size
234 int board_size = 2;
235 INI_GET(board_size, "game", "board_size");
236 Globals::Game::board_size = Globals::Game::intToBoardSize(board_size);
237
238 // Getting the colors from their strings
239 INI_GET(tmp, "gui_colors", "text");
240 EngineGlobals::Theme::text = ColorPair::fromString(tmp);
241
242 INI_GET(tmp, "gui_colors", "hilite_text");
243 EngineGlobals::Theme::hilite_text = ColorPair::fromString(tmp);
244
245 INI_GET(tmp, "gui_colors", "textbox");
246 EngineGlobals::Theme::textbox = ColorPair::fromString(tmp);
247
248 INI_GET(tmp, "game_colors", "player_head");
249 Globals::Theme::player_head = ColorPair::fromString(tmp);
250
251 INI_GET(tmp, "game_colors", "player_head_dead");
252 Globals::Theme::player_head_dead = ColorPair::fromString(tmp);
253
254 INI_GET(tmp, "game_colors", "player_body");
255 Globals::Theme::player_body = ColorPair::fromString(tmp);
256
257 INI_GET(tmp, "game_colors", "fruit");
258 Globals::Theme::fruit = ColorPair::fromString(tmp);
259
260 SAFE_DELETE(ini);
261}
263{
264 // Even if the file doesn't exist, we'll create it.
265 INI::Parser* ini;
266
267 try
268 {
269 ini = new INI::Parser(Globals::Config::file);
270 }
271 catch(std::runtime_error& e)
272 {
273 ini = new INI::Parser();
274 ini->create();
275 }
276
277 // Will be used on this macro below
278 std::string buffer;
279
280// Other macro to avoid typing, similar to the one
281// at loadFile()
282#define INI_SET(out, in, var) \
283 { \
284 buffer = Utils::String::toString(var); \
285 ini->top().addGroup(out); \
286 (* ini)(out).addKey(in, buffer); \
287 }
288
289 INI_SET("screen", "center_horizontal", EngineGlobals::Screen::center_horizontally);
290 INI_SET("screen", "center_vertical", EngineGlobals::Screen::center_vertically);
291
292 INI_SET("screen", "borders", EngineGlobals::Screen::show_borders);
293 INI_SET("screen", "fancy_borders", EngineGlobals::Screen::fancy_borders);
294 INI_SET("screen", "outer_border", EngineGlobals::Screen::outer_border);
295
296 INI_SET("game", "random_walls", Globals::Game::random_walls);
297 INI_SET("game", "fruits_at_once", Globals::Game::fruits_at_once);
298 INI_SET("game", "teleport", Globals::Game::teleport);
299
300 INI_SET("game", "board_scroll_delay", Globals::Game::board_scroll_delay);
301
302 INI_SET("game", "board_scroll_up", Globals::Game::board_scroll_up);
303 INI_SET("game", "board_scroll_down", Globals::Game::board_scroll_down);
304 INI_SET("game", "board_scroll_left", Globals::Game::board_scroll_left);
305 INI_SET("game", "board_scroll_right", Globals::Game::board_scroll_right);
306
307 // unsigned ints are the exception - their overloading
308 // is ambiguous... I should consider removing them altogether
309 int starting_speed = Globals::Game::starting_speed;
310 buffer = Utils::String::toString(starting_speed);
311 ini->top().addGroup("game");
312 (* ini)("game").addKey("starting_speed", buffer);
313
314 // Special Cases
315
316 // Input Keys
317 std::string key;
318
319 key = InputManager::keyToString(InputManager::getBind("left"));
320 INI_SET("input", "left", key);
321
322 key = InputManager::keyToString(InputManager::getBind("right"));
323 INI_SET("input", "right", key);
324
325 key = InputManager::keyToString(InputManager::getBind("up"));
326 INI_SET("input", "up", key);
327
328 key = InputManager::keyToString(InputManager::getBind("down"));
329 INI_SET("input", "down", key);
330
331 key = InputManager::keyToString(InputManager::getBind("pause"));
332 INI_SET("input", "pause", key);
333
334 key = InputManager::keyToString(InputManager::getBind("help"));
335 INI_SET("input", "help", key);
336
337 key = InputManager::keyToString(InputManager::getBind("quit"));
338 INI_SET("input", "quit", key);
339
340 // Board size
341 int board_size = Globals::Game::boardSizeToInt(Globals::Game::board_size);
342 INI_SET("game", "board_size", board_size);
343
344 // Saving the colors from their strings
345 INI_SET("gui_colors", "text", EngineGlobals::Theme::text.toString());
346
347 INI_SET("gui_colors", "hilite_text", EngineGlobals::Theme::hilite_text.toString());
348
349 INI_SET("gui_colors", "textbox", EngineGlobals::Theme::textbox.toString());
350
351
352 INI_SET("game_colors", "player_head", Globals::Theme::player_head.toString());
353
354 INI_SET("game_colors", "player_head_dead", Globals::Theme::player_head_dead.toString());
355
356 INI_SET("game_colors", "player_body", Globals::Theme::player_body.toString());
357
358 INI_SET("game_colors", "fruit", Globals::Theme::fruit.toString());
359
360 try
361 {
362 ini->saveAs(Globals::Config::file);
363 }
364 catch(std::runtime_error& e)
365 {
366 // Couldn't save the file...
367 // ... do nothing
368 }
369 SAFE_DELETE(ini);
370}
372{
373 if (! Globals::Error::has_config_file)
374 {
375 std::cout << "Warning: We could not create the configuration file.\n"
376 << " Please check permissions to the path:\n"
377 << " " + Globals::Config::file
378 << std::endl;
379 }
380 if (! Globals::Error::has_score_file)
381 {
382 std::cout << "Warning: We could not create the score file.\n"
383 << " Please check permissions to the path:\n"
384 << " " + Globals::Config::scoresFile
385 << std::endl;
386 }
387 if (Globals::Error::old_version_score_file)
388 {
389 std::cout << "Warning: Your high score file is from an old nsnake version."
390 << std::endl;
391 }
392 if (Globals::Error::strange_score_file)
393 {
394 // Erasing high scores...
395 Utils::File::create(Globals::Config::scoresFile);
396
397 std::cout << "Error: Corrupted high score file!\n"
398 << " We're sorry, but we had to erase it"
399 << std::endl;
400 }
401}
402
static std::string directory
Default directory where the level files are.
static std::string directory
Default directory where we store the game score files.
Definition ScoreFile.hpp:97
void init()
Initializes global variables with default values.
Definition Globals.cpp:78
char version[3]
Game version (format MMP - Major Minor Patch).
Definition Globals.cpp:15
void warnErrors()
Warns the user about any errors and warnings found during the program's execution.
Definition Globals.cpp:371
void loadFile()
Loads global variables from the default file.
Definition Globals.cpp:141
void saveFile()
Loads global variables to the default file.
Definition Globals.cpp:262