nsnake
Classic snake game for the terminal
Loading...
Searching...
No Matches
GameStateMainMenu.cpp
1#include <Flow/GameStateMainMenu.hpp>
2#include <Flow/InputManager.hpp>
3#include <Interface/Ncurses.hpp>
4#include <Interface/Dialog.hpp>
5#include <Misc/Utils.hpp>
6#include <Config/Globals.hpp>
7#include <Game/BoardParser.hpp>
8#include <Game/ScoreFile.hpp>
9
10enum NamesToEasilyIdentifyTheMenuItemsInsteadOfRawNumbers
11{
12 // Main Menu
13 ARCADE=1337,
14 LEVELS,
15 GAME_SETTINGS,
16 HELP,
17 GUI_OPTIONS,
18 CONTROLS,
19 QUIT_GAME,
20
21 // Level select Submenu
22 RANDOM,
23
24 // Game Settings Submenu
25 GO_BACK,
26 STARTING_SPEED,
27 TELEPORT,
28 FRUITS,
29 RANDOM_WALLS,
30 BOARD_SIZE,
31 SCROLL_DELAY,
32 SCROLL_RIGHT,
33 SCROLL_LEFT,
34 SCROLL_UP,
35 SCROLL_DOWN,
36 ERASE_HIGH_SCORES,
37
38 // GUI Submenu
39 SHOW_BORDERS,
40 FANCY_BORDERS,
41 OUTER_BORDER,
42 USE_COLORS,
43 CENTER_HORIZONTAL,
44 CENTER_VERTICAL,
45
46 // Controls Submenu
47 CONTROLS_KEY_LEFT,
48 CONTROLS_KEY_RIGHT,
49 CONTROLS_KEY_UP,
50 CONTROLS_KEY_DOWN,
51 CONTROLS_KEY_PAUSE,
52 CONTROLS_KEY_HELP,
53 CONTROLS_KEY_QUIT,
54 CONTROLS_DEFAULT
55};
56
57GameStateMainMenu::GameStateMainMenu():
58 layout(NULL),
59 menu(NULL),
60 menuLevels(NULL),
61 menuLevelsActivated(false),
62 menuGameSettings(NULL),
63 menuGameSettingsActivated(false),
64 menuGUIOptions(NULL),
65 menuGUIOptionsActivated(false),
66 menuControls(NULL),
67 menuControlsActivated(false),
68 helpWindows(NULL)
69{ }
70
72{
73 UNUSED(stack);
74
75 this->layout = new LayoutMainMenu(80, 24, this);
76
77 createMainMenu();
78 createLevelsMenu();
79 createGameSettingsMenu();
80 createGUIOptionsMenu();
81 createControlsMenu();
82
83 this->helpWindows = new WindowGameHelp();
84}
85
87{
88 saveSettingsMenuGameSettings();
89 saveSettingsMenuGUIOptions();
90
91 SAFE_DELETE(this->layout);
92 SAFE_DELETE(this->menuLevels);
93 SAFE_DELETE(this->menuGameSettings);
94 SAFE_DELETE(this->menuGUIOptions);
95 SAFE_DELETE(this->menuControls);
96 SAFE_DELETE(this->menu);
97
98 return 0;
99}
100
102{
103 if (InputManager::isPressed("quit"))
104 return GameState::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 return GameState::GAME_START;
125 break;
126 }
127
128 default:
129 // Selected a level name!
130 Globals::Game::current_level = this->menuLevels->current->label;
131 return GameState::GAME_START;
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 return GameState::GAME_START;
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 return GameState::QUIT;
310 break;
311 }
312 this->menu->reset();
313 }
314 }
315
316 // Otherwise, continuing things...
317 return GameState::CONTINUE;
318}
319
321{
322 if (this->menuLevelsActivated)
323 this->layout->draw(this->menuLevels);
324
325 else if (this->menuGameSettingsActivated)
326 this->layout->draw(this->menuGameSettings);
327
328 else if (this->menuGUIOptionsActivated)
329 this->layout->draw(this->menuGUIOptions);
330
331 else if (this->menuControlsActivated)
332 this->layout->draw(this->menuControls);
333
334 else
335 this->layout->draw(this->menu);
336}
337
338void GameStateMainMenu::createMainMenu()
339{
340 SAFE_DELETE(this->menu);
341
342 // Creating the Menu and Items.
343 // Their default ids will be based on current's
344 // settings.
345 this->menu = new Menu(1,
346 1,
347 this->layout->menu->getW() - 2,
348 this->layout->menu->getH() - 2);
349
350 MenuItem* item;
351
352 item = new MenuItem("Arcade Mode", ARCADE);
353 menu->add(item);
354
355 item = new MenuItem("Level Select", LEVELS);
356 menu->add(item);
357
358 item = new MenuItem("Game Settings", GAME_SETTINGS);
359 menu->add(item);
360
361 item = new MenuItem("GUI Options", GUI_OPTIONS);
362 menu->add(item);
363
364 item = new MenuItem("Controls", CONTROLS);
365 menu->add(item);
366
367 item = new MenuItem("Help", HELP);
368 menu->add(item);
369
370 item = new MenuItem("Quit", QUIT_GAME);
371 menu->add(item);
372}
373void GameStateMainMenu::createLevelsMenu()
374{
375 SAFE_DELETE(this->menuLevels);
376
377 this->menuLevels = new MenuAlphabetic(1,
378 1,
379 this->layout->menu->getW() - 2,
380 this->layout->menu->getH() - 2);
381
382 MenuItem* item;
383
384 std::vector<std::string> levels = BoardParser::listLevels();
385
386 item = new MenuItem("Back", GO_BACK);
387 menuLevels->add(item);
388
389 item = new MenuItem("Random", RANDOM);
390 menuLevels->add(item);
391
392 menuLevels->addBlank();
393
394 for (size_t i = 0; i < levels.size(); i++)
395 {
396 item = new MenuItem(levels[i], i);
397 menuLevels->add(item);
398 }
399}
400void GameStateMainMenu::createGameSettingsMenu()
401{
402 SAFE_DELETE(this->menuGameSettings);
403
404 this->menuGameSettings = new Menu(1,
405 1,
406 this->layout->menu->getW() - 2,
407 this->layout->menu->getH() - 2);
408
409 MenuItem* item;
410
411 item = new MenuItem("Back", GO_BACK);
412 menuGameSettings->add(item);
413
414 menuGameSettings->addBlank();
415
416 MenuItemNumberbox* number;
417
418 number = new MenuItemNumberbox("Starting Speed", STARTING_SPEED, 1, 10, Globals::Game::starting_speed);
419 menuGameSettings->add(number);
420
421 number = new MenuItemNumberbox("Fruits", FRUITS, 1, 99, Globals::Game::fruits_at_once);
422 menuGameSettings->add(number);
423
424 MenuItemCheckbox* check;
425
426 check = new MenuItemCheckbox("Teleport", TELEPORT, Globals::Game::teleport);
427 menuGameSettings->add(check);
428
429 check = new MenuItemCheckbox("Random Walls", RANDOM_WALLS, Globals::Game::random_walls);
430 menuGameSettings->add(check);
431
432 // The board size
433 std::vector<std::string> options;
434 options.push_back("Small");
435 options.push_back("Medium");
436 options.push_back("Large");
437
438 MenuItemTextlist* list;
439
440 // the default board size
441 std::string defaullt;
442
443 switch (Globals::Game::board_size)
444 {
445 case Globals::Game::SMALL: defaullt = "Small"; break;
446 case Globals::Game::MEDIUM: defaullt = "Medium"; break;
447 default: defaullt = "Large"; break;
448 }
449
450 list = new MenuItemTextlist("Maze size",
451 BOARD_SIZE,
452 options,
453 defaullt);
454
455 menuGameSettings->add(list);
456
457 menuGameSettings->addBlank();
458
459 number = new MenuItemNumberbox("Scroll Delay(ms)", SCROLL_DELAY, 100, 5000, Globals::Game::board_scroll_delay, 100);
460 menuGameSettings->add(number);
461
462 check = new MenuItemCheckbox("Scroll Up", SCROLL_UP, Globals::Game::board_scroll_up);
463 menuGameSettings->add(check);
464
465 check = new MenuItemCheckbox("Scroll Down", SCROLL_DOWN, Globals::Game::board_scroll_down);
466 menuGameSettings->add(check);
467
468 check = new MenuItemCheckbox("Scroll Left", SCROLL_LEFT, Globals::Game::board_scroll_left);
469 menuGameSettings->add(check);
470
471 check = new MenuItemCheckbox("Scroll Right", SCROLL_RIGHT, Globals::Game::board_scroll_right);
472 menuGameSettings->add(check);
473
474 menuGameSettings->addBlank();
475
476 item = new MenuItem("Erase High Scores",
477 ERASE_HIGH_SCORES);
478 menuGameSettings->add(item);
479}
480void GameStateMainMenu::createGUIOptionsMenu()
481{
482 SAFE_DELETE(this->menuGUIOptions);
483
484 this->menuGUIOptions = new Menu(1,
485 1,
486 this->layout->menu->getW() - 2,
487 this->layout->menu->getH() - 2);
488
489 MenuItem* item;
490
491 item = new MenuItem("Back", GO_BACK);
492 menuGUIOptions->add(item);
493
494 menuGUIOptions->addBlank();
495
496 MenuItemCheckbox* check;
497
498 check = new MenuItemCheckbox("Show Borders",
499 SHOW_BORDERS,
500 Globals::Screen::show_borders);
501 menuGUIOptions->add(check);
502
503 check = new MenuItemCheckbox("Fancy Borders",
504 FANCY_BORDERS,
505 Globals::Screen::fancy_borders);
506 menuGUIOptions->add(check);
507
508 check = new MenuItemCheckbox("Outer Border",
509 OUTER_BORDER,
510 Globals::Screen::outer_border);
511 menuGUIOptions->add(check);
512
513 check = new MenuItemCheckbox("Center Horizontal",
514 CENTER_HORIZONTAL,
515 Globals::Screen::center_horizontally);
516 menuGUIOptions->add(check);
517
518 check = new MenuItemCheckbox("Center Vertical",
519 CENTER_VERTICAL,
520 Globals::Screen::center_vertically);
521 menuGUIOptions->add(check);
522}
523void GameStateMainMenu::createControlsMenu()
524{
525 SAFE_DELETE(this->menuControls);
526
527 this->menuControls = new Menu(1,
528 1,
529 this->layout->menu->getW() - 2,
530 this->layout->menu->getH() - 2);
531
532 MenuItem* item;
533
534 item = new MenuItem("Back", GO_BACK);
535 menuControls->add(item);
536
537 menuControls->addBlank();
538
539 MenuItemLabel* label;
540 std::string str;
541
542 str = InputManager::keyToString(InputManager::getBind("up"));
543 label = new MenuItemLabel("Key up", CONTROLS_KEY_UP, str);
544 menuControls->add(label);
545
546 str = InputManager::keyToString(InputManager::getBind("down"));
547 label = new MenuItemLabel("Key down", CONTROLS_KEY_DOWN, str);
548 menuControls->add(label);
549
550 str = InputManager::keyToString(InputManager::getBind("left"));
551 label = new MenuItemLabel("Key left", CONTROLS_KEY_LEFT, str);
552 menuControls->add(label);
553
554 str = InputManager::keyToString(InputManager::getBind("right"));
555 label = new MenuItemLabel("Key right", CONTROLS_KEY_RIGHT, str);
556 menuControls->add(label);
557
558 str = InputManager::keyToString(InputManager::getBind("pause"));
559 label = new MenuItemLabel("Key pause", CONTROLS_KEY_PAUSE, str);
560 menuControls->add(label);
561
562 str = InputManager::keyToString(InputManager::getBind("help"));
563 label = new MenuItemLabel("Key help", CONTROLS_KEY_HELP, str);
564 menuControls->add(label);
565
566 str = InputManager::keyToString(InputManager::getBind("quit"));
567 label = new MenuItemLabel("Key quit", CONTROLS_KEY_QUIT, str);
568 menuControls->add(label);
569
570 menuControls->addBlank();
571
572 item = new MenuItem("Reset to Defaults", CONTROLS_DEFAULT);
573 menuControls->add(item);
574}
575void GameStateMainMenu::saveSettingsMenuGUIOptions()
576{
577 if (!this->menuGUIOptions)
578 return;
579
580 // User selected an option
581 // Let's get ids from menu items
582 Globals::Screen::show_borders = this->menuGUIOptions->getBool(SHOW_BORDERS);
583 Globals::Screen::fancy_borders = this->menuGUIOptions->getBool(FANCY_BORDERS);
584 Globals::Screen::outer_border = this->menuGUIOptions->getBool(OUTER_BORDER);
585 Globals::Screen::center_horizontally = this->menuGUIOptions->getBool(CENTER_HORIZONTAL);
586 Globals::Screen::center_vertically = this->menuGUIOptions->getBool(CENTER_VERTICAL);
587}
588void GameStateMainMenu::saveSettingsMenuGameSettings()
589{
590 if (!this->menuGameSettings)
591 return;
592
593 // User selected an option
594 // Let's get ids from menu items
595 Globals::Game::starting_speed = (unsigned int)this->menuGameSettings->getInt(STARTING_SPEED);
596 Globals::Game::fruits_at_once = this->menuGameSettings->getInt(FRUITS);
597 Globals::Game::random_walls = this->menuGameSettings->getBool(RANDOM_WALLS);
598 Globals::Game::teleport = this->menuGameSettings->getBool(TELEPORT);
599
600 std::string tmp = this->menuGameSettings->getString(BOARD_SIZE);
601 if (tmp == "Small")
602 Globals::Game::board_size = Globals::Game::SMALL;
603
604 else if (tmp == "Medium")
605 Globals::Game::board_size = Globals::Game::MEDIUM;
606
607 else
608 Globals::Game::board_size = Globals::Game::LARGE;
609
610 Globals::Game::board_scroll_delay = this->menuGameSettings->getInt(SCROLL_DELAY);
611
612 Globals::Game::board_scroll_left = this->menuGameSettings->getBool(SCROLL_LEFT);
613 Globals::Game::board_scroll_right = this->menuGameSettings->getBool(SCROLL_RIGHT);
614 Globals::Game::board_scroll_up = this->menuGameSettings->getBool(SCROLL_UP);
615 Globals::Game::board_scroll_down = this->menuGameSettings->getBool(SCROLL_DOWN);
616}
617
static std::string directory
Default directory where the level files are.
static std::vector< std::string > listLevels()
Lists all levels found by the game.
GameState::StateCode update()
Called every frame, where states calculate everything that can change.
void load(int stack=0)
Where every state initializes it's resources.
void draw()
Called every frame, where states draw stuff on screen.
int unload()
Gets called when we're leaving this menu.
StateCode
All possible transitions between states.
Definition GameState.hpp:40
How we show the screen at GameStateMainMenu.
void draw(Menu *menu)
Shows the Main Menu screen, along with drawing menu.
Menu on which its items are always sorted alphabetically.
void goRandom()
Selects a random item right AFTER the first blank one.
A list of selectable text.
List of selectable items.
Definition Menu.hpp:29
bool getBool(int id)
Returns the bool internal value of item that has #id.
Definition Menu.cpp:350
bool willQuit()
Tells if the user selected an item that quits the menu.
Definition Menu.cpp:330
void handleInput()
Makes the menu react to input, as seen on the global InputManager.
Definition Menu.cpp:183
int currentID()
Returns the user-specified id of the selected item.
Definition Menu.cpp:343
int getInt(int id)
Returns the integer value of the item that has #id.
Definition Menu.cpp:372
std::string getString(int id)
Returns the string value of the item that has #id.
Definition Menu.cpp:394
MenuItem * current
Current item selected.
Definition Menu.hpp:115
void reset()
Makes the menu able to be selected again.
Definition Menu.cpp:424
static void eraseAll()
Erases all high score files.
Definition ScoreFile.cpp:71
Specific Window that shows Help and other info during Game.
void run()
Updates and draws all tabs.
void setTitle(std::string title, WindowTitlePosition position=Window::TOP_LEFT)
Sets a text that will appear at the top of the Window.
Definition Window.cpp:214
bool askBool(std::string question, std::string title="", bool default_value=false)
Spawns a Dialog box asking for a yes-or-no #question.
Definition Dialog.cpp:58
void show(std::string message, bool pressAnyKey=false)
Shows a message on the screen.
Definition Dialog.cpp:12
int getInput(int delay_ms=-1)
Returns a pressed character within a timespan of delay_ms (milliseconds).
Definition Ncurses.cpp:37
A little box that can be checked or not.
Shows a Menu Item with left and right labels.
Allows to select a number, kinda like a slider.
Simplest type of item possible, with a label and user-defined id.
Definition MenuItem.hpp:12
std::string label
Text that will be shown on the screen.
Definition MenuItem.hpp:54