diff options
Diffstat (limited to 'Userland/Games/Spider/main.cpp')
-rw-r--r-- | Userland/Games/Spider/main.cpp | 190 |
1 files changed, 190 insertions, 0 deletions
diff --git a/Userland/Games/Spider/main.cpp b/Userland/Games/Spider/main.cpp new file mode 100644 index 0000000000..1914ee4f23 --- /dev/null +++ b/Userland/Games/Spider/main.cpp @@ -0,0 +1,190 @@ +/* + * Copyright (c) 2021, Jamie Mansfield <jmansfield@cadixdev.org> + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include "Game.h" +#include <Games/Spider/SpiderGML.h> +#include <LibCore/ConfigFile.h> +#include <LibCore/Timer.h> +#include <LibGUI/Action.h> +#include <LibGUI/ActionGroup.h> +#include <LibGUI/Application.h> +#include <LibGUI/Icon.h> +#include <LibGUI/Menu.h> +#include <LibGUI/Menubar.h> +#include <LibGUI/MessageBox.h> +#include <LibGUI/Statusbar.h> +#include <LibGUI/Window.h> +#include <stdio.h> +#include <unistd.h> + +int main(int argc, char** argv) +{ + auto app = GUI::Application::construct(argc, argv); + auto app_icon = GUI::Icon::default_icon("app-spider"); + auto config = Core::ConfigFile::get_for_app("Spider"); + + if (pledge("stdio recvfd sendfd rpath wpath cpath", nullptr) < 0) { + perror("pledge"); + return 1; + } + + if (unveil("/res", "r") < 0) { + perror("unveil"); + return 1; + } + + if (unveil(config->filename().characters(), "crw") < 0) { + perror("unveil"); + return 1; + } + + if (unveil(nullptr, nullptr) < 0) { + perror("unveil"); + return 1; + } + + auto window = GUI::Window::construct(); + window->set_title("Spider"); + + auto mode = static_cast<Spider::Mode>(config->read_num_entry("Settings", "Mode", static_cast<int>(Spider::Mode::SingleSuit))); + + auto update_mode = [&](Spider::Mode new_mode) { + mode = new_mode; + config->write_num_entry("Settings", "Mode", static_cast<int>(mode)); + if (!config->sync()) + GUI::MessageBox::show(window, "Configuration could not be saved", "Error", GUI::MessageBox::Type::Error); + }; + + auto high_score = [&]() { + switch (mode) { + case Spider::Mode::SingleSuit: + return static_cast<u32>(config->read_num_entry("HighScores", "SingleSuit", 0)); + case Spider::Mode::TwoSuit: + return static_cast<u32>(config->read_num_entry("HighScores", "TwoSuit", 0)); + default: + VERIFY_NOT_REACHED(); + } + }; + + auto update_high_score = [&](u32 new_high_score) { + switch (mode) { + case Spider::Mode::SingleSuit: + config->write_num_entry("HighScores", "SingleSuit", static_cast<int>(new_high_score)); + break; + case Spider::Mode::TwoSuit: + config->write_num_entry("HighScores", "TwoSuit", static_cast<int>(new_high_score)); + break; + default: + VERIFY_NOT_REACHED(); + } + + if (!config->sync()) + GUI::MessageBox::show(window, "Configuration could not be saved", "Error", GUI::MessageBox::Type::Error); + }; + + if (mode >= Spider::Mode::__Count) + update_mode(Spider::Mode::SingleSuit); + + auto& widget = window->set_main_widget<GUI::Widget>(); + widget.load_from_gml(spider_gml); + + auto& game = *widget.find_descendant_of_type_named<Spider::Game>("game"); + game.set_focus(true); + + auto& statusbar = *widget.find_descendant_of_type_named<GUI::Statusbar>("statusbar"); + statusbar.set_text(0, "Score: 0"); + statusbar.set_text(1, String::formatted("High Score: {}", high_score())); + statusbar.set_text(2, "Time: 00:00:00"); + + app->on_action_enter = [&](GUI::Action& action) { + auto text = action.status_tip(); + if (text.is_empty()) + text = Gfx::parse_ampersand_string(action.text()); + statusbar.set_override_text(move(text)); + }; + + app->on_action_leave = [&](GUI::Action&) { + statusbar.set_override_text({}); + }; + + game.on_score_update = [&](uint32_t score) { + statusbar.set_text(0, String::formatted("Score: {}", score)); + }; + + uint64_t seconds_elapsed = 0; + + auto timer = Core::Timer::create_repeating(1000, [&]() { + ++seconds_elapsed; + + uint64_t hours = seconds_elapsed / 3600; + uint64_t minutes = (seconds_elapsed / 60) % 60; + uint64_t seconds = seconds_elapsed % 60; + + statusbar.set_text(2, String::formatted("Time: {:02}:{:02}:{:02}", hours, minutes, seconds)); + }); + + game.on_game_start = [&]() { + seconds_elapsed = 0; + timer->start(); + statusbar.set_text(2, "Time: 00:00:00"); + }; + game.on_game_end = [&](Spider::GameOverReason reason, uint32_t score) { + if (timer->is_active()) + timer->stop(); + + if (reason == Spider::GameOverReason::Victory) { + if (score > high_score()) { + update_high_score(score); + statusbar.set_text(1, String::formatted("High Score: {}", score)); + } + } + statusbar.set_text(2, "Timer starts after your first move"); + }; + + GUI::ActionGroup suit_actions; + suit_actions.set_exclusive(true); + + auto single_suit_action = GUI::Action::create_checkable("&Single Suit", [&](auto&) { + update_mode(Spider::Mode::SingleSuit); + statusbar.set_text(1, String::formatted("High Score: {}", high_score())); + game.setup(mode); + }); + single_suit_action->set_checked(mode == Spider::Mode::SingleSuit); + suit_actions.add_action(single_suit_action); + + auto two_suit_action = GUI::Action::create_checkable("&Two Suit", [&](auto&) { + update_mode(Spider::Mode::TwoSuit); + statusbar.set_text(1, String::formatted("High Score: {}", high_score())); + game.setup(mode); + }); + two_suit_action->set_checked(mode == Spider::Mode::TwoSuit); + suit_actions.add_action(two_suit_action); + + auto menubar = GUI::Menubar::construct(); + + auto& game_menu = menubar->add_menu("&Game"); + game_menu.add_action(GUI::Action::create("&New Game", { Mod_None, Key_F2 }, [&](auto&) { + game.setup(mode); + })); + game_menu.add_separator(); + game_menu.add_action(single_suit_action); + game_menu.add_action(two_suit_action); + game_menu.add_separator(); + game_menu.add_action(GUI::CommonActions::make_quit_action([&](auto&) { app->quit(); })); + + auto& help_menu = menubar->add_menu("&Help"); + help_menu.add_action(GUI::CommonActions::make_about_action("Spider", app_icon, window)); + + window->set_resizable(false); + window->resize(Spider::Game::width, Spider::Game::height + statusbar.max_height()); + window->set_menubar(move(menubar)); + window->set_icon(app_icon.bitmap_for_size(16)); + window->show(); + + game.setup(mode); + + return app->exec(); +} |