nsnake
Classic snake game for the terminal
Loading...
Searching...
No Matches
GameStateMainMenu.cpp
1#include <States/GameStateMainMenu.hpp>
2#include <Engine/InputManager.hpp>
3#include <Engine/Graphics/Ncurses.hpp>
4#include <Engine/Graphics/Widgets/Dialog.hpp>
5#include <Engine/Helpers/Utils.hpp>
6#include <Engine/EngineGlobals.hpp>
7#include <Config/Globals.hpp>
8#include <Entities/BoardParser.hpp>
9#include <Entities/ScoreFile.hpp>
10
11#include <Engine/Flow/StateManager.hpp>
12#include <States/GameStateGame.hpp>
13
14enum NamesToEasilyIdentifyTheMenuItemsInsteadOfRawNumbers
15{
16 // Main Menu
17 ARCADE=1337,
18 LEVELS,
19 GAME_SETTINGS,
20 HELP,
21 GUI_OPTIONS,
22 CONTROLS,
23 QUIT_GAME,
24
25 // Level select Submenu
26 RANDOM,
27
28 // Game Settings Submenu
29 GO_BACK,
30 STARTING_SPEED,
31 TELEPORT,
32 FRUITS,
33 RANDOM_WALLS,
34 BOARD_SIZE,
35 SCROLL_DELAY,
36 SCROLL_RIGHT,
37 SCROLL_LEFT,
38 SCROLL_UP,
39 SCROLL_DOWN,
40 ERASE_HIGH_SCORES,
41
42 // GUI Submenu
43 SHOW_BORDERS,
44 FANCY_BORDERS,
45 OUTER_BORDER,
46 USE_COLORS,
47 CENTER_HORIZONTAL,
48 CENTER_VERTICAL,
49
50 // Controls Submenu
51 CONTROLS_KEY_LEFT,
52 CONTROLS_KEY_RIGHT,
53 CONTROLS_KEY_UP,
54 CONTROLS_KEY_DOWN,
55 CONTROLS_KEY_PAUSE,
56 CONTROLS_KEY_HELP,
57 CONTROLS_KEY_QUIT,
58 CONTROLS_DEFAULT
59};
60
61GameStateMainMenu::GameStateMainMenu():
62 layout(NULL),
63 menu(NULL),
64 menuLevels(NULL),
65 menuLevelsActivated(false),
66 menuGameSettings(NULL),
67 menuGameSettingsActivated(false),
68 menuGUIOptions(NULL),
69 menuGUIOptionsActivated(false),
70 menuControls(NULL),
71 menuControlsActivated(false),
72 helpWindows(NULL)
73{ }
74
75void GameStateMainMenu::load()
76{
77 this->layout = new LayoutMainMenu(80, 24, this);
78
79 createMainMenu();
80 createLevelsMenu();
81 createGameSettingsMenu();
82 createGUIOptionsMenu();
83 createControlsMenu();
84
85 this->helpWindows = new WindowGameHelp();
86}
87
88void GameStateMainMenu::unload()
89{
90 saveSettingsMenuGameSettings();
91 saveSettingsMenuGUIOptions();
92
93 SAFE_DELETE(this->layout);
94 SAFE_DELETE(this->menuLevels);
95 SAFE_DELETE(this->menuGameSettings);
96 SAFE_DELETE(this->menuGUIOptions);
97 SAFE_DELETE(this->menuControls);
98 SAFE_DELETE(this->menu);
99}
100
101void GameStateMainMenu::update()
102{
103 if (InputManager::isPressed("quit"))
104 StateManager::quit();
105
106 if (this->menuLevelsActivated)
107 {
108 this->menuLevels->handleInput();
109
110 if (this->menuLevels->willQuit())
111 {
112 switch (this->menuLevels->currentID())
113 {
114 case GO_BACK:
115 this->layout->menu->setTitle("Main Menu");
116 this->menuLevelsActivated = false;
117 break;
118
119 case RANDOM:
120 {
121 this->menuLevels->goRandom();
122
123 Globals::Game::current_level = this->menuLevels->current->label;
124 StateManager::change(new GameStateGame());
125 break;
126 }
127
128 default:
129 // Selected a level name!
130 Globals::Game::current_level = this->menuLevels->current->label;
131 StateManager::change(new GameStateGame());
132 break;
133 }
134 this->menuLevels->reset();
135 }
136 }
137 else if (this->menuGameSettingsActivated)
138 {
139 this->menuGameSettings->handleInput();
140
141 if (this->menuGameSettings->willQuit())
142 {
143 saveSettingsMenuGameSettings();
144
145 // And then exit based on the selected option.
146 switch (this->menuGameSettings->currentID())
147 {
148 case ERASE_HIGH_SCORES:
149 {
150 bool answer = Dialog::askBool("Are you sure?");
151
152 if (answer)
153 {
155 Dialog::show("All high scores erased!", true);
156 }
157 }
158 break;
159
160 case GO_BACK:
161 this->layout->menu->setTitle("Main Menu");
162 this->menuGameSettingsActivated = false;
163 break;
164 }
165 this->menuGameSettings->reset();
166 }
167 }
168 else if (this->menuGUIOptionsActivated)
169 {
170 this->menuGUIOptions->handleInput();
171
172 if (this->menuGUIOptions->willQuit())
173 {
174 switch(this->menuGUIOptions->currentID())
175 {
176 case GO_BACK:
177 this->layout->menu->setTitle("Main Menu");
178 this->menuGUIOptionsActivated = false;
179
180 // Redrawing the screen to refresh settings
181 saveSettingsMenuGUIOptions();
182 this->layout->windowsExit();
183 this->layout->windowsInit();
184 break;
185 }
186 this->menuGUIOptions->reset();
187 }
188 }
189 else if (this->menuControlsActivated)
190 {
191 this->menuControls->handleInput();
192
193 if (this->menuControls->willQuit())
194 {
195 std::string key(""); // for key binding
196
197 switch(this->menuControls->currentID())
198 {
199 case GO_BACK:
200 this->layout->menu->setTitle("Main Menu");
201 this->menuControlsActivated = false;
202 break;
203
204 case CONTROLS_KEY_LEFT: key = "left"; break;
205 case CONTROLS_KEY_RIGHT: key = "right"; break;
206 case CONTROLS_KEY_UP: key = "up"; break;
207 case CONTROLS_KEY_DOWN: key = "down"; break;
208 case CONTROLS_KEY_PAUSE: key = "pause"; break;
209 case CONTROLS_KEY_HELP: key = "help"; break;
210 case CONTROLS_KEY_QUIT: key = "quit"; break;
211
212 case CONTROLS_DEFAULT:
213 {
214 // Reset all keybindings to default
215 InputManager::bind("left", KEY_LEFT);
216 InputManager::bind("right", KEY_RIGHT);
217 InputManager::bind("up", KEY_UP);
218 InputManager::bind("down", KEY_DOWN);
219 InputManager::bind("pause", 'p');
220 InputManager::bind("help", 'h');
221 InputManager::bind("quit", 'q');
222
223 // Resetting the menu to show the new labels
224 createControlsMenu();
225 menuControls->goLast();
226 break;
227 }
228 }
229
230 // If we'll change a key binding
231 if (! key.empty())
232 {
233 Dialog::show("Press any key, Enter to Cancel");
234 int tmp = Ncurses::getInput(-1);
235
236 if ((tmp != KEY_ENTER) &&
237 (tmp != '\n') &&
238 (tmp != ERR))
239 {
240 InputManager::bind(key, tmp);
241
242 MenuItemLabel* label;
243 label = (MenuItemLabel*)menuControls->current;
244
245 label->set(InputManager::keyToString(tmp));
246 }
247 }
248 this->menuControls->reset();
249 }
250 }
251 else
252 {
253 // We're still at the Main Menu
254 this->menu->handleInput();
255
256 if (this->menu->willQuit())
257 {
258 switch(this->menu->currentID())
259 {
260 case ARCADE:
261 // Starting game on the default level
262 Globals::Game::current_level = "";
263 StateManager::change(new GameStateGame());
264 break;
265
266 case LEVELS:
267 // Before going to the Levels menu, we must check if
268 // the user has any levels on the level directory.
269 // If not, we should stay at the main menu.
270 if (BoardParser::listLevels().size() == 0)
271 {
272 Dialog::show("Sorry, it seems you have no levels.\n"
273 "\n"
274 "Please copy the default level files from\n"
275 "`" SYSTEM_LEVEL_DIR "/`\n"
276 "to\n"
277 "`" + BoardParser::directory + "`\n" +
278 "\n"
279 "You can also download more levels from the website:\n"
280 "http://nsnake.alexdantas.net/", true);
281 }
282 else
283 {
284 this->layout->menu->setTitle("Level Select");
285 this->menuLevelsActivated = true;
286 }
287 break;
288
289 case GAME_SETTINGS:
290 this->layout->menu->setTitle("Game Settings");
291 this->menuGameSettingsActivated = true;
292 break;
293
294 case GUI_OPTIONS:
295 this->layout->menu->setTitle("GUI Options");
296 this->menuGUIOptionsActivated = true;
297 break;
298
299 case CONTROLS:
300 this->layout->menu->setTitle("Controls");
301 this->menuControlsActivated = true;
302 break;
303
304 case HELP:
305 this->helpWindows->run();
306 break;
307
308 case QUIT_GAME:
309 StateManager::quit();
310 break;
311 }
312 this->menu->reset();
313 }
314 }
315}
316
317void GameStateMainMenu::draw()
318{
319 if (this->menuLevelsActivated)
320 this->layout->draw(this->menuLevels);
321
322 else if (this->menuGameSettingsActivated)
323 this->layout->draw(this->menuGameSettings);
324
325 else if (this->menuGUIOptionsActivated)
326 this->layout->draw(this->menuGUIOptions);
327
328 else if (this->menuControlsActivated)
329 this->layout->draw(this->menuControls);
330
331 else
332 this->layout->draw(this->menu);
333}
334
335void GameStateMainMenu::createMainMenu()
336{
337 SAFE_DELETE(this->menu);
338
339 // Creating the Menu and Items.
340 // Their default ids will be based on current's
341 // settings.
342 this->menu = new Menu(1,
343 1,
344 this->layout->menu->getW() - 2,
345 this->layout->menu->getH() - 2);
346
347 MenuItem* item;
348
349 item = new MenuItem("Arcade Mode", ARCADE);
350 menu->add(item);
351
352 item = new MenuItem("Level Select", LEVELS);
353 menu->add(item);
354
355 item = new MenuItem("Game Settings", GAME_SETTINGS);
356 menu->add(item);
357
358 item = new MenuItem("GUI Options", GUI_OPTIONS);
359 menu->add(item);
360
361 item = new MenuItem("Controls", CONTROLS);
362 menu->add(item);
363
364 item = new MenuItem("Help", HELP);
365 menu->add(item);
366
367 item = new MenuItem("Quit", QUIT_GAME);
368 menu->add(item);
369}
370void GameStateMainMenu::createLevelsMenu()
371{
372 SAFE_DELETE(this->menuLevels);
373
374 this->menuLevels = new MenuAlphabetic(1,
375 1,
376 this->layout->menu->getW() - 2,
377 this->layout->menu->getH() - 2);
378
379 MenuItem* item;
380
381 std::vector<std::string> levels = BoardParser::listLevels();
382
383 item = new MenuItem("Back", GO_BACK);
384 menuLevels->add(item);
385
386 item = new MenuItem("Random", RANDOM);
387 menuLevels->add(item);
388
389 menuLevels->addBlank();
390
391 for (size_t i = 0; i < levels.size(); i++)
392 {
393 item = new MenuItem(levels[i], i);
394 menuLevels->add(item);
395 }
396}
397void GameStateMainMenu::createGameSettingsMenu()
398{
399 SAFE_DELETE(this->menuGameSettings);
400
401 this->menuGameSettings = new Menu(1,
402 1,
403 this->layout->menu->getW() - 2,
404 this->layout->menu->getH() - 2);
405
406 MenuItem* item;
407
408 item = new MenuItem("Back", GO_BACK);
409 menuGameSettings->add(item);
410
411 menuGameSettings->addBlank();
412
413 MenuItemNumberbox* number;
414
415 number = new MenuItemNumberbox("Starting Speed", STARTING_SPEED, 1, 10, Globals::Game::starting_speed);
416 menuGameSettings->add(number);
417
418 number = new MenuItemNumberbox("Fruits", FRUITS, 1, 99, Globals::Game::fruits_at_once);
419 menuGameSettings->add(number);
420
421 MenuItemCheckbox* check;
422
423 check = new MenuItemCheckbox("Teleport", TELEPORT, Globals::Game::teleport);
424 menuGameSettings->add(check);
425
426 check = new MenuItemCheckbox("Random Walls", RANDOM_WALLS, Globals::Game::random_walls);
427 menuGameSettings->add(check);
428
429 // The board size
430 std::vector<std::string> options;
431 options.push_back("Small");
432 options.push_back("Medium");
433 options.push_back("Large");
434
435 MenuItemTextlist* list;
436
437 // the default board size
438 std::string defaullt;
439
440 switch (Globals::Game::board_size)
441 {
442 case Globals::Game::SMALL: defaullt = "Small"; break;
443 case Globals::Game::MEDIUM: defaullt = "Medium"; break;
444 default: defaullt = "Large"; break;
445 }
446
447 list = new MenuItemTextlist("Maze size",
448 BOARD_SIZE,
449 options,
450 defaullt);
451
452 menuGameSettings->add(list);
453
454 menuGameSettings->addBlank();
455
456 number = new MenuItemNumberbox("Scroll Delay(ms)", SCROLL_DELAY, 100, 5000, Globals::Game::board_scroll_delay, 100);
457 menuGameSettings->add(number);
458
459 check = new MenuItemCheckbox("Scroll Up", SCROLL_UP, Globals::Game::board_scroll_up);
460 menuGameSettings->add(check);
461
462 check = new MenuItemCheckbox("Scroll Down", SCROLL_DOWN, Globals::Game::board_scroll_down);
463 menuGameSettings->add(check);
464
465 check = new MenuItemCheckbox("Scroll Left", SCROLL_LEFT, Globals::Game::board_scroll_left);
466 menuGameSettings->add(check);
467
468 check = new MenuItemCheckbox("Scroll Right", SCROLL_RIGHT, Globals::Game::board_scroll_right);
469 menuGameSettings->add(check);
470
471 menuGameSettings->addBlank();
472
473 item = new MenuItem("Erase High Scores",
474 ERASE_HIGH_SCORES);
475 menuGameSettings->add(item);
476}
477void GameStateMainMenu::createGUIOptionsMenu()
478{
479 SAFE_DELETE(this->menuGUIOptions);
480
481 this->menuGUIOptions = new Menu(1,
482 1,
483 this->layout->menu->getW() - 2,
484 this->layout->menu->getH() - 2);
485
486 MenuItem* item;
487
488 item = new MenuItem("Back", GO_BACK);
489 menuGUIOptions->add(item);
490
491 menuGUIOptions->addBlank();
492
493 MenuItemCheckbox* check;
494
495 check = new MenuItemCheckbox("Show Borders",
496 SHOW_BORDERS,
497 EngineGlobals::Screen::show_borders);
498 menuGUIOptions->add(check);
499
500 check = new MenuItemCheckbox("Fancy Borders",
501 FANCY_BORDERS,
502 EngineGlobals::Screen::fancy_borders);
503 menuGUIOptions->add(check);
504
505 check = new MenuItemCheckbox("Outer Border",
506 OUTER_BORDER,
507 EngineGlobals::Screen::outer_border);
508 menuGUIOptions->add(check);
509
510 check = new MenuItemCheckbox("Center Horizontal",
511 CENTER_HORIZONTAL,
512 EngineGlobals::Screen::center_horizontally);
513 menuGUIOptions->add(check);
514
515 check = new MenuItemCheckbox("Center Vertical",
516 CENTER_VERTICAL,
517 EngineGlobals::Screen::center_vertically);
518 menuGUIOptions->add(check);
519}
520void GameStateMainMenu::createControlsMenu()
521{
522 SAFE_DELETE(this->menuControls);
523
524 this->menuControls = new Menu(1,
525 1,
526 this->layout->menu->getW() - 2,
527 this->layout->menu->getH() - 2);
528
529 MenuItem* item;
530
531 item = new MenuItem("Back", GO_BACK);
532 menuControls->add(item);
533
534 menuControls->addBlank();
535
536 MenuItemLabel* label;
537 std::string str;
538
539 str = InputManager::keyToString(InputManager::getBind("up"));
540 label = new MenuItemLabel("Key up", CONTROLS_KEY_UP, str);
541 menuControls->add(label);
542
543 str = InputManager::keyToString(InputManager::getBind("down"));
544 label = new MenuItemLabel("Key down", CONTROLS_KEY_DOWN, str);
545 menuControls->add(label);
546
547 str = InputManager::keyToString(InputManager::getBind("left"));
548 label = new MenuItemLabel("Key left", CONTROLS_KEY_LEFT, str);
549 menuControls->add(label);
550
551 str = InputManager::keyToString(InputManager::getBind("right"));
552 label = new MenuItemLabel("Key right", CONTROLS_KEY_RIGHT, str);
553 menuControls->add(label);
554
555 str = InputManager::keyToString(InputManager::getBind("pause"));
556 label = new MenuItemLabel("Key pause", CONTROLS_KEY_PAUSE, str);
557 menuControls->add(label);
558
559 str = InputManager::keyToString(InputManager::getBind("help"));
560 label = new MenuItemLabel("Key help", CONTROLS_KEY_HELP, str);
561 menuControls->add(label);
562
563 str = InputManager::keyToString(InputManager::getBind("quit"));
564 label = new MenuItemLabel("Key quit", CONTROLS_KEY_QUIT, str);
565 menuControls->add(label);
566
567 menuControls->addBlank();
568
569 item = new MenuItem("Reset to Defaults", CONTROLS_DEFAULT);
570 menuControls->add(item);
571}
572void GameStateMainMenu::saveSettingsMenuGUIOptions()
573{
574 if (!this->menuGUIOptions)
575 return;
576
577 // User selected an option
578 // Let's get ids from menu items
579 EngineGlobals::Screen::show_borders = this->menuGUIOptions->getBool(SHOW_BORDERS);
580 EngineGlobals::Screen::fancy_borders = this->menuGUIOptions->getBool(FANCY_BORDERS);
581 EngineGlobals::Screen::outer_border = this->menuGUIOptions->getBool(OUTER_BORDER);
582 EngineGlobals::Screen::center_horizontally = this->menuGUIOptions->getBool(CENTER_HORIZONTAL);
583 EngineGlobals::Screen::center_vertically = this->menuGUIOptions->getBool(CENTER_VERTICAL);
584}
585void GameStateMainMenu::saveSettingsMenuGameSettings()
586{
587 if (!this->menuGameSettings)
588 return;
589
590 // User selected an option
591 // Let's get ids from menu items
592 Globals::Game::starting_speed = (unsigned int)this->menuGameSettings->getInt(STARTING_SPEED);
593 Globals::Game::fruits_at_once = this->menuGameSettings->getInt(FRUITS);
594 Globals::Game::random_walls = this->menuGameSettings->getBool(RANDOM_WALLS);
595 Globals::Game::teleport = this->menuGameSettings->getBool(TELEPORT);
596
597 std::string tmp = this->menuGameSettings->getString(BOARD_SIZE);
598 if (tmp == "Small")
599 Globals::Game::board_size = Globals::Game::SMALL;
600
601 else if (tmp == "Medium")
602 Globals::Game::board_size = Globals::Game::MEDIUM;
603
604 else
605 Globals::Game::board_size = Globals::Game::LARGE;
606
607 Globals::Game::board_scroll_delay = this->menuGameSettings->getInt(SCROLL_DELAY);
608
609 Globals::Game::board_scroll_left = this->menuGameSettings->getBool(SCROLL_LEFT);
610 Globals::Game::board_scroll_right = this->menuGameSettings->getBool(SCROLL_RIGHT);
611 Globals::Game::board_scroll_up = this->menuGameSettings->getBool(SCROLL_UP);
612 Globals::Game::board_scroll_down = this->menuGameSettings->getBool(SCROLL_DOWN);
613}
static std::string directory
Default directory where the level files are.
static std::vector< std::string > listLevels()
Lists all levels found by the game.
This represents the actual game taking place.
How we show the screen at GameStateMainMenu.
void draw(Menu *menu)
Shows the Main Menu screen, along with drawing menu.
static void eraseAll()
Erases all high score files.
Definition ScoreFile.cpp:73
Specific Window that shows Help and other info during Game.
void run()
Updates and draws all tabs.