diff --git a/Makefile b/Makefile index 27ba792..a4e2247 100644 --- a/Makefile +++ b/Makefile @@ -41,20 +41,20 @@ test: build run: build test ifeq '$(OS)' 'Windows_NT' - powershell "cp ./builddir/zedcaster.exe ." - ./zedcaster + powershell "cp ./builddir/under_the_dome.exe ." + ./under_the_dome else - ./builddir/zedcaster + ./builddir/under_the_dome endif debug: build gdb --nx -x .gdbinit --ex run --args builddir/runtests debug_run: build - gdb --nx -x .gdbinit --batch --ex run --ex bt --ex q --args builddir/zedcaster + gdb --nx -x .gdbinit --batch --ex run --ex bt --ex q --args builddir/under_the_dome debug_walk: build test - gdb --nx -x .gdbinit --batch --ex run --ex bt --ex q --args builddir/zedcaster t + gdb --nx -x .gdbinit --batch --ex run --ex bt --ex q --args builddir/under_the_dome t clean: meson compile --clean -C builddir diff --git a/assets/enemies.json b/assets/enemies.json index dd3c0e0..48ffc40 100644 --- a/assets/enemies.json +++ b/assets/enemies.json @@ -6,7 +6,7 @@ "foreground": "enemies/fg:player", "background": "color:transparent" }, - {"_type": "Combat", "max_hp": 200, "max_ap": 12, "ap_delta": 6, "damage": 200, + {"_type": "Combat", "max_hp": 200, "max_ap": 12, "ap_delta": 6, "damage": 20, "body_parts": { "head": 200, "chest": 200, diff --git a/assets/scenes.json b/assets/scenes.json index 03b95fd..48a7f78 100644 --- a/assets/scenes.json +++ b/assets/scenes.json @@ -65,18 +65,6 @@ } ], "fixtures": [ - { - "name": "ag_bot_speech", - "sprite": "ag_bot_speech", - "scale_x": 1.0, - "scale_y": 1.0, - "flipped": false, - "cell": "speech", - "x": 0, - "y": 0, - "at_mid": false, - "flipped": false - } ], "buttons": { "layout": [ diff --git a/meson.build b/meson.build index d1aaf4f..b207239 100644 --- a/meson.build +++ b/meson.build @@ -1,5 +1,5 @@ -project('raycaster', 'cpp', +project('under_the_dome', 'cpp', version: '0.1.0', default_options: [ 'cpp_std=c++23', @@ -22,6 +22,14 @@ cc = meson.get_compiler('cpp') dependencies = [] if build_machine.system() == 'windows' + add_global_link_arguments( + '-static-libgcc', + '-static-libstdc++', + '-static', + '-flto', + language: 'cpp', + ) + sfml_main = subproject('sfml').get_variable('sfml_main_dep') opengl32 = cc.find_library('opengl32', required: true) winmm = cc.find_library('winmm', required: true) @@ -33,6 +41,10 @@ if build_machine.system() == 'windows' exe_defaults += ['werror=true'] elif build_machine.system() == 'darwin' + add_global_link_arguments( + language: 'cpp', + ) + opengl = dependency('OpenGL') corefoundation = dependency('CoreFoundation') carbon = dependency('Carbon') @@ -97,7 +109,7 @@ executable('runtests', sources + tests, override_options: exe_defaults, dependencies: dependencies + [catch2]) -executable('zedcaster', +executable('under_the_dome', [ 'src/main.cpp' ], cpp_args: cpp_args, link_args: link_args, diff --git a/src/game/level.cpp b/src/game/level.cpp index 2b6f02b..02edab1 100644 --- a/src/game/level.cpp +++ b/src/game/level.cpp @@ -34,6 +34,21 @@ namespace GameDB { }; } + void init() { + components::init(); + textures::init(); + + if(!initialized) { + reset(); + } + } + + void reset() { + LDB = make_shared(); + initialized = true; + new_level(NULL); + } + shared_ptr clone_load_world(shared_ptr prev_world) { auto world = make_shared(); @@ -82,17 +97,6 @@ namespace GameDB { .collision=collision}); } - void init() { - components::init(); - textures::init(); - - if(!initialized) { - LDB = make_shared(); - initialized = true; - new_level(NULL); - } - } - shared_ptr current_world() { dbc::check(initialized, "Forgot to call GameDB::init()"); return current_level().world; diff --git a/src/game/level.hpp b/src/game/level.hpp index abc5bff..8189a91 100644 --- a/src/game/level.hpp +++ b/src/game/level.hpp @@ -23,7 +23,10 @@ namespace GameDB { Level& create_level(); void init(); + void reset(); + Level ¤t_level(); + void new_level(std::shared_ptr prev_world); std::shared_ptr current_world(); components::Position& player_position(); DinkyECS::Entity the_player(); diff --git a/src/game/systems.cpp b/src/game/systems.cpp index 65d1c3e..ea896e8 100644 --- a/src/game/systems.cpp +++ b/src/game/systems.cpp @@ -538,6 +538,10 @@ void System::clear_attack() { void System::spawn_attack(World& world, int attack_id, DinkyECS::Entity enemy) { } +void System::restart() { + // reset game db + GameDB::reset(); +} void System::init(Registry& reg) { reg.addRender(System::clear_attack); diff --git a/src/game/systems.hpp b/src/game/systems.hpp index 38f29e0..b2cc47e 100644 --- a/src/game/systems.hpp +++ b/src/game/systems.hpp @@ -13,6 +13,9 @@ namespace System { using namespace DinkyECS; using std::string, matrix::Matrix; + void init(Registry& reg); + void restart(); + void lighting(); void motion(); void collision(); @@ -70,5 +73,4 @@ namespace System { void clear_attack(); void spawn_attack(World& world, int attack_id, DinkyECS::Entity enemy); - void init(Registry& reg); } diff --git a/src/gui/fsm.cpp b/src/gui/fsm.cpp index 7ba8910..7af7625 100644 --- a/src/gui/fsm.cpp +++ b/src/gui/fsm.cpp @@ -17,15 +17,12 @@ namespace gui { using namespace components; using game::Event; - FSM::FSM() : - $window(sf::VideoMode({SCREEN_WIDTH, SCREEN_HEIGHT}), "Zed's Raycaster Thing"), + FSM::FSM(sf::RenderWindow& window) : + $window(window), $main_ui($window), $dnd_loot($status_ui, $loot_ui, $window, $router) { - $window.setVerticalSyncEnabled(VSYNC); - if(FRAME_LIMIT) $window.setFramerateLimit(FRAME_LIMIT); - $window.setPosition({0,0}); - + System::init($systems); } void FSM::event(Event ev, std::any data) { @@ -41,7 +38,9 @@ namespace gui { FSM_STATE(State, ROTATING, ev); FSM_STATE(State, IDLE, ev, data); FSM_STATE(State, LOOTING, ev, data); - FSM_STATE(State, END, ev); + FSM_STATE(State, END_QUIT, ev); + FSM_STATE(State, END_PLAY_AGAIN, ev); + FSM_STATE(State, END_PLAYER_DIED, ev); } } @@ -59,9 +58,9 @@ namespace gui { $debug_ui.init(cell); $status_ui.init(); run_systems(); - $story = std::make_shared("intro_story"); - $story->init(); - state(State::INTRO); + + show_scene("STARTING"); + state(State::START_SCENE); } void FSM::INTRO(Event ev) { @@ -73,8 +72,7 @@ namespace gui { } } else { $story = nullptr; - show_scene("STARTING"); - state(State::START_SCENE); + state(State::IDLE); } } @@ -90,7 +88,9 @@ namespace gui { } break; case START: close_scene(); - state(State::IDLE); + $story = std::make_shared("intro_story"); + $story->init(); + state(State::INTRO); break; case QUIT: FSM::IDLE(ev, {}); @@ -115,7 +115,7 @@ namespace gui { } break; case START: close_scene(); - state(State::IDLE); + state(State::END_PLAYER_DIED); break; case QUIT: FSM::IDLE(ev, {}); @@ -137,7 +137,7 @@ namespace gui { } break; case START: close_scene(); - state(State::IDLE); + state(State::END_PLAY_AGAIN); break; case QUIT: FSM::IDLE(ev, {}); @@ -232,7 +232,7 @@ namespace gui { switch(ev) { case QUIT: $window.close(); - state(State::END); + state(State::END_QUIT); return; // done case MOVE_FORWARD: try_move(1, false); @@ -317,8 +317,16 @@ namespace gui { } } - void FSM::END(Event ev) { - dbc::log($F("END: received event after done: {}", int(ev))); + void FSM::END_QUIT(Event ev) { + dbc::log($F("END_QUIT: received event after done: {}", int(ev))); + } + + void FSM::END_PLAYER_DIED(Event ev) { + dbc::log($F("END_PLAYER_DIED: received event after done: {}", int(ev))); + } + + void FSM::END_PLAY_AGAIN(Event ev) { + dbc::log($F("END_PLAY_AGAIN: received event after done: {}", int(ev))); } sf::Vector2f FSM::mouse_position() { @@ -458,7 +466,9 @@ namespace gui { } bool FSM::active() { - return !in_state(State::END); + return !(in_state(State::END_QUIT) + || in_state(State::END_PLAY_AGAIN) + || in_state(State::END_PLAYER_DIED)); } void FSM::handle_world_events() { diff --git a/src/gui/fsm.hpp b/src/gui/fsm.hpp index 4e39d74..aec9127 100644 --- a/src/gui/fsm.hpp +++ b/src/gui/fsm.hpp @@ -27,12 +27,14 @@ namespace gui { ROTATING=__LINE__, LOOTING=__LINE__, IDLE=__LINE__, - END=__LINE__, + END_QUIT=__LINE__, + END_PLAYER_DIED=__LINE__, + END_PLAY_AGAIN=__LINE__, }; class FSM : public DeadSimpleFSM { public: - sf::RenderWindow $window; + sf::RenderWindow& $window; bool $draw_stats = false; DebugUI $debug_ui; MainUI $main_ui; @@ -51,7 +53,7 @@ namespace gui { std::shared_ptr $cur_scene = nullptr; std::shared_ptr $story = nullptr; - FSM(); + FSM(sf::RenderWindow& window); void event(game::Event ev, std::any data={}); @@ -67,7 +69,9 @@ namespace gui { void MAPPING(game::Event ev); void ROTATING(game::Event ev); void LOOTING(game::Event ev, std::any data); - void END(game::Event ev); + void END_QUIT(game::Event ev); + void END_PLAYER_DIED(game::Event ev); + void END_PLAY_AGAIN(game::Event ev); void try_move(int dir, bool strafe); sf::Vector2f mouse_position(); diff --git a/src/gui/loot_ui.cpp b/src/gui/loot_ui.cpp index 07c55b4..726078e 100644 --- a/src/gui/loot_ui.cpp +++ b/src/gui/loot_ui.cpp @@ -7,10 +7,19 @@ namespace gui { using namespace guecs; - LootUI::LootUI() : - $temp_loot(GameDB::current_world()->entity()), - $target($temp_loot) + LootUI::LootUI() { + } + + void LootUI::make_button(const std::string &name, const std::wstring& label, game::Event event) { + auto button = $gui.entity(name); + $gui.set(button, {}); + $gui.set(button, {label}); + $gui.set(button, + guecs::make_action(button, event)); + } + + void LootUI::init() { $gui.position(RAY_VIEW_X+RAY_VIEW_WIDTH/2-200, RAY_VIEW_Y+RAY_VIEW_HEIGHT/2-200, 400, 400); @@ -21,21 +30,14 @@ namespace gui { "[=item_12| =item_13|=item_14|=item_15 ]" "[ =take_all | =close| =destroy]"); + // setup a fake container for our loot + $temp_loot = GameDB::current_world()->entity(); + $target = $temp_loot; + auto world = GameDB::current_world(); world->set($temp_loot, {}); world->make_constant($temp_loot); - } - void LootUI::make_button(const std::string &name, const std::wstring& label, game::Event event) { - - auto button = $gui.entity(name); - $gui.set(button, {}); - $gui.set(button, {label}); - $gui.set(button, - guecs::make_action(button, event)); - } - - void LootUI::init() { using guecs::THEME; auto bg_color = THEME.DARK_LIGHT; bg_color.a = 140; @@ -65,7 +67,7 @@ namespace gui { auto world = GameDB::current_world(); dbc::check(world->has($target), - "update called but $target isn't in world"); + $F("update called but $target isn't in world: {}", $target)); auto& contents = world->get($target); diff --git a/src/main.cpp b/src/main.cpp index 7ea502d..7186840 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -9,6 +9,33 @@ #include "graphics/camera.hpp" #include "game/systems.hpp" + +void play_game(std::shared_ptr main) { + sound::play("ambient_1", true); + main->event(game::Event::START); + + while(main->active()) { + main->update(); + main->render(); + + // BUG: need to sort out how to deal with this in the FSM + if(main->in_state(gui::State::IDLE) + || main->in_state(gui::State::START_SCENE) + || main->in_state(gui::State::INTRO) + || main->in_state(gui::State::WIN_SCENE) + || main->in_state(gui::State::DEATH_SCENE) + || main->in_state(gui::State::NEXT_LEVEL_SCENE) + || main->in_state(gui::State::LOOTING)) + { + main->handle_keyboard_mouse(); + } else{ + main->event(game::Event::TICK); + } + + main->handle_world_events(); + } +} + int main(int argc, char* argv[]) { try { gui::Backend backend; @@ -21,34 +48,28 @@ int main(int argc, char* argv[]) { cinematic::init(); sound::mute(true); - gui::FSM main; - System::init(main.$systems); - main.event(game::Event::START); + sf::RenderWindow window(sf::VideoMode({SCREEN_WIDTH, SCREEN_HEIGHT}), "Zed's Raycaster Thing"); + window.setVerticalSyncEnabled(VSYNC); + if(FRAME_LIMIT) window.setFramerateLimit(FRAME_LIMIT); + window.setPosition({0,0}); - sound::play("ambient_1", true); + auto main = std::make_shared(window); - while(main.active()) { - main.update(); - main.render(); + while(true) { + play_game(main); - // BUG: need to sort out how to deal with this in the FSM - if(main.in_state(gui::State::IDLE) - || main.in_state(gui::State::START_SCENE) - || main.in_state(gui::State::INTRO) - || main.in_state(gui::State::WIN_SCENE) - || main.in_state(gui::State::DEATH_SCENE) - || main.in_state(gui::State::NEXT_LEVEL_SCENE) - || main.in_state(gui::State::LOOTING)) - { - main.handle_keyboard_mouse(); - } else{ - main.event(game::Event::TICK); + if(main->in_state(gui::State::END_QUIT)) { + return 0; + } else if(main->in_state(gui::State::END_PLAYER_DIED)) { + System::restart(); + main = std::make_shared(window); + } else if(main->in_state(gui::State::END_PLAY_AGAIN)) { + System::restart(); + main = std::make_shared(window); + } else { + dbc::sentinel("Unknown game end state"); } - - main.handle_world_events(); } - - return 0; } catch(const std::system_error& e) { std::cout << "WARNING: On OSX you'll get this error on shutdown.\n"; std::cout << "Caught system_error with code "