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