diff --git a/autowalker.cpp b/autowalker.cpp index 386f1b0..a3ec249 100644 --- a/autowalker.cpp +++ b/autowalker.cpp @@ -1,14 +1,15 @@ #include "autowalker.hpp" #include "ai_debug.hpp" #include "gui/ritual_ui.hpp" +#include "game_level.hpp" template -int number_left(gui::FSM& fsm) { +int number_left() { int count = 0; - fsm.$level.world->query( + Game::current_world()->query( [&](const auto ent, auto&, auto&) { - if(ent != fsm.$level.player) { + if(ent != Game::current().player) { count++; } }); @@ -17,16 +18,16 @@ int number_left(gui::FSM& fsm) { } template -Pathing compute_paths(gui::FSM& fsm) { - auto& walls_original = fsm.$level.map->$walls; +Pathing compute_paths() { + auto& walls_original = Game::current().map->$walls; auto walls_copy = walls_original; Pathing paths{matrix::width(walls_copy), matrix::height(walls_copy)}; - fsm.$level.world->query( + Game::current().world->query( [&](const auto ent, auto& position) { - if(ent != fsm.$level.player) { - if(fsm.$level.world->has(ent)) { + if(ent != Game::current().player) { + if(Game::current().world->has(ent)) { paths.set_target(position.location); } else { // this will mark that spot as a wall so we don't path there temporarily @@ -53,11 +54,11 @@ void Autowalker::close_status() { } Pathing Autowalker::path_to_enemies() { - return compute_paths(fsm); + return compute_paths(); } Pathing Autowalker::path_to_items() { - return compute_paths(fsm); + return compute_paths(); } void Autowalker::handle_window_events() { @@ -88,8 +89,7 @@ void Autowalker::process_combat() { } Point Autowalker::get_current_position() { - auto& player_position = fsm.$level.world->get(fsm.$level.player); - return player_position.location; + return Game::player_position().location; } void Autowalker::path_fail(Matrix& bad_paths, Point pos) { @@ -110,7 +110,7 @@ bool Autowalker::path_player(Pathing& paths, Point& target_out) { } } - if(!fsm.$level.map->can_move(target_out)) { + if(!Game::current().map->can_move(target_out)) { path_fail(paths.$paths, target_out); return false; } @@ -184,8 +184,8 @@ struct InventoryStats { }; ai::State Autowalker::update_state(ai::State start) { - int enemy_count = number_left(fsm); - int item_count = number_left(fsm); + int enemy_count = number_left(); + int item_count = number_left(); ai::set(start, "no_more_enemies", enemy_count == 0); ai::set(start, "no_more_items", item_count == 0); @@ -330,7 +330,7 @@ void Autowalker::process_move(Pathing& paths) { // what are we aiming at? auto aimed_at = fsm.$main_ui.camera_aim(); - if(aimed_at && fsm.$level.world->has(aimed_at)) { + if(aimed_at && Game::current_world()->has(aimed_at)) { // NOTE: if we're aiming at an item then pick it up // for now just loot it then close to get it off the map send_event(gui::Event::LOOT_ITEM); @@ -349,7 +349,8 @@ void Autowalker::send_event(gui::Event ev) { } bool Autowalker::player_health_good() { - auto combat = fsm.$level.world->get(fsm.$level.player); + auto world = Game::current_world(); + auto combat = world->get(Game::the_player()); return float(combat.hp) / float(combat.max_hp) > 0.5f; } diff --git a/game_level.cpp b/game_level.cpp new file mode 100644 index 0000000..e934099 --- /dev/null +++ b/game_level.cpp @@ -0,0 +1,66 @@ +#include "game_level.hpp" +#include "levelmanager.hpp" +#include "components.hpp" + +namespace Game { + using std::shared_ptr, std::string, std::make_shared; + + shared_ptr LEVELS; + bool initialized = false; + + void init() { + LEVELS = make_shared(); + initialized = true; + } + + LevelManager& get_the_manager() { + return *LEVELS; + } + + shared_ptr current_world() { + return current().world; + } + + shared_ptr create_bossfight() { + return LEVELS->create_bossfight(current_world()); + } + + GameLevel& create_level() { + LEVELS->create_level(current_world()); + return next(); + } + + GameLevel &next() { + return LEVELS->next(); + } + + GameLevel &previous() { + return LEVELS->previous(); + } + + GameLevel ¤t() { + return LEVELS->current(); + } + + size_t current_index() { + return LEVELS->current_index(); + } + + GameLevel &get(size_t index) { + return LEVELS->get(index); + } + + DinkyECS::Entity spawn_enemy(const std::string& named) { + return LEVELS->spawn_enemy(named); + } + + components::Position& player_position() { + auto world = current_world(); + auto& player = world->get_the(); + return world->get(player.entity); + } + + DinkyECS::Entity the_player() { + return current().player; + } +} diff --git a/game_level.hpp b/game_level.hpp new file mode 100644 index 0000000..d7743ba --- /dev/null +++ b/game_level.hpp @@ -0,0 +1,27 @@ +#pragma once + +#include "dinkyecs.hpp" +#include "gui/boss_fight_ui.hpp" + +struct GameLevel; +struct LevelManager; +namespace components { + struct Position; +} + +namespace Game { + std::shared_ptr create_bossfight(); + GameLevel& create_level(); + + void init(); + LevelManager& get_the_manager(); + GameLevel &next(); + GameLevel &previous(); + GameLevel ¤t(); + size_t current_index(); + std::shared_ptr current_world(); + GameLevel &get(size_t index); + DinkyECS::Entity spawn_enemy(const std::string& named); + components::Position& player_position(); + DinkyECS::Entity the_player(); +} diff --git a/gui/fsm.cpp b/gui/fsm.cpp index 0eef3c3..d544be7 100644 --- a/gui/fsm.cpp +++ b/gui/fsm.cpp @@ -12,19 +12,19 @@ #include "shaders.hpp" #include #include "gui/guecstra.hpp" +#include "game_level.hpp" namespace gui { using namespace components; FSM::FSM() : $window(sf::VideoMode({SCREEN_WIDTH, SCREEN_HEIGHT}), "Zed's Raycaster Thing"), - $debug_ui($levels), + $debug_ui(Game::get_the_manager()), $main_ui($window), - $level($levels.current()), - $combat_ui($level), - $status_ui($level), - $map_ui($level), - $loot_ui($level), + $combat_ui(Game::current()), + $status_ui(Game::current()), + $map_ui(Game::current()), + $loot_ui(Game::current()), $font{FONT_FILE_NAME}, $dnd_loot($status_ui, $loot_ui, $window, $router) { @@ -47,7 +47,8 @@ namespace gui { } void FSM::START(Event ) { - $main_ui.update_level($level); + auto& level = Game::current(); + $main_ui.update_level(level); $main_ui.init(); $loot_ui.init(); @@ -58,7 +59,7 @@ namespace gui { $combat_ui.init(); $status_ui.init(); - $boss_fight_ui = $levels.create_bossfight($level.world); + $boss_fight_ui = Game::create_bossfight(); $boss_fight_ui->init(); $map_ui.init(); @@ -72,7 +73,7 @@ namespace gui { void FSM::MOVING(Event ) { // this should be an optional that returns a point if(auto move_to = $main_ui.play_move()) { - System::plan_motion($level, *move_to); + System::plan_motion(Game::current(), *move_to); run_systems(); $main_ui.dirty(); state(State::IDLE); @@ -83,7 +84,7 @@ namespace gui { using enum Event; switch(ev) { case TICK: { - System::combat($level, $temp_attack_id); + System::combat(Game::current(), $temp_attack_id); run_systems(); state(State::IN_COMBAT); } break; @@ -101,7 +102,7 @@ namespace gui { void FSM::ROTATING(Event) { if(auto aim = $main_ui.play_rotate()) { - auto& player_pos = System::player_position($level); + auto& player_pos = Game::player_position(); player_pos.aiming_at = *aim; state(State::IDLE); } @@ -109,7 +110,7 @@ namespace gui { void FSM::COMBAT_ROTATE(Event) { if(auto aim = $main_ui.play_rotate()) { - auto& player_pos = System::player_position($level); + auto& player_pos = Game::player_position(); player_pos.aiming_at = *aim; state(State::IN_COMBAT); } @@ -194,7 +195,7 @@ namespace gui { auto gui_id = std::any_cast(data); auto& slot_name = $status_ui.$gui.name_for(gui_id); - if(System::use_item($level, slot_name)) { + if(System::use_item(Game::current(), slot_name)) { $status_ui.update(); } } break; @@ -206,7 +207,7 @@ namespace gui { mouse_action({1 << guecs::ModBit::hover}); } break; case AIM_CLICK: - System::pickup($level); + System::pickup(Game::current()); break; default: break; // ignore everything else @@ -272,11 +273,12 @@ namespace gui { } void FSM::try_move(int dir, bool strafe) { + auto& level = Game::current(); using enum State; // prevent moving into occupied space Point move_to = $main_ui.plan_move(dir, strafe); - if($level.map->can_move(move_to) && !$level.collision->occupied(move_to)) { + if(level.map->can_move(move_to) && !level.collision->occupied(move_to)) { sound::play("walk"); state(MOVING); } else { @@ -360,8 +362,9 @@ namespace gui { event(Event::LOOT_OPEN); break; case KEY::Z: { - auto& player_pos = System::player_position($level); - System::distribute_loot($level, {player_pos.aiming_at}); + auto& level = Game::current(); + auto& player_pos = Game::player_position(); + System::distribute_loot(level, {player_pos.aiming_at}); } break; case KEY::X: event(Event::STAIRS_DOWN); @@ -419,13 +422,14 @@ namespace gui { } void FSM::run_systems() { - System::generate_paths($level); - System::enemy_ai_initialize($level); - System::enemy_pathing($level); - System::collision($level); - System::motion($level); - System::lighting($level); - System::death($level); + auto& level = Game::current(); + System::generate_paths(level); + System::enemy_ai_initialize(level); + System::enemy_pathing(level); + System::collision(level); + System::motion(level); + System::lighting(level); + System::death(level); } bool FSM::active() { @@ -434,11 +438,11 @@ namespace gui { void FSM::handle_world_events() { using eGUI = Events::GUI; - auto& world = *$level.world; + auto world = Game::current_world(); - while(world.has_event()) { - auto [evt, entity, data] = world.recv(); - auto player = world.get_the(); + while(world->has_event()) { + auto [evt, entity, data] = world->recv(); + auto player = world->get_the(); // HERE: this has to go, unify these events and just use them in the state machine directly @@ -463,7 +467,7 @@ namespace gui { event(Event::START_COMBAT); break; case eGUI::ENTITY_SPAWN: { - auto& sprite = world.get(entity); + auto& sprite = world->get(entity); $main_ui.$rayview->update_sprite(entity, sprite); $main_ui.dirty(); run_systems(); @@ -489,7 +493,7 @@ namespace gui { event(Event::AIM_CLICK); break; case eGUI::LOOT_ITEM: { - dbc::check(world.has(entity), + dbc::check(world->has(entity), "INVALID LOOT_ITEM, that entity has no InventoryItem"); $loot_ui.add_loose_item(entity); event(Event::LOOT_ITEM); @@ -500,7 +504,7 @@ namespace gui { event(Event::LOOT_OPEN); } break; case eGUI::HP_STATUS: - System::player_status($level); + System::player_status(Game::current()); break; case eGUI::NEW_RITUAL: $combat_ui.init(); @@ -543,16 +547,15 @@ namespace gui { } void FSM::next_level() { - $levels.create_level($level.world); - $level = $levels.next(); + auto& level = Game::create_level(); - $status_ui.update_level($level); - $map_ui.update_level($level); - $combat_ui.update_level($level); - $main_ui.update_level($level); - $loot_ui.update_level($level); + $status_ui.update_level(level); + $map_ui.update_level(level); + $combat_ui.update_level(level); + $main_ui.update_level(level); + $loot_ui.update_level(level); - $boss_fight_ui = $levels.create_bossfight($level.world); + $boss_fight_ui = Game::create_bossfight(); $boss_fight_ui->init(); run_systems(); diff --git a/gui/fsm.hpp b/gui/fsm.hpp index 7bc3009..1f572f2 100644 --- a/gui/fsm.hpp +++ b/gui/fsm.hpp @@ -35,10 +35,8 @@ namespace gui { bool autowalking = false; bool $map_open = false; int $temp_attack_id = 0; - LevelManager $levels; DebugUI $debug_ui; MainUI $main_ui; - GameLevel $level; shared_ptr $boss_fight_ui = nullptr; CombatUI $combat_ui; StatusUI $status_ui; diff --git a/levelmanager.cpp b/levelmanager.cpp index 4c29770..a5e7a4f 100644 --- a/levelmanager.cpp +++ b/levelmanager.cpp @@ -27,16 +27,7 @@ inline shared_ptr clone_load_world(shared_ptr auto world = make_shared(); if(prev_world != nullptr) { - fmt::println("############### NEW WORLD #################"); prev_world->clone_into(*world); - - fmt::println("new world entity_count={}, prev={}", world->entity_count, prev_world->entity_count); - - for(auto [ent, is_set] : prev_world->$constants) { - if(world->has(ent)) { - fmt::println("#### Sprite {} copied to new world.", ent); - } - } } else { save::load_configs(*world); } diff --git a/main.cpp b/main.cpp index 006479f..003b34a 100644 --- a/main.cpp +++ b/main.cpp @@ -7,6 +7,7 @@ #include #include "shaders.hpp" #include "backend.hpp" +#include "game_level.hpp" int main(int argc, char* argv[]) { try { @@ -15,6 +16,7 @@ int main(int argc, char* argv[]) { guecs::init(&backend); ai::init("assets/ai.json"); animation::init(); + Game::init(); if(DEBUG_BUILD) sound::mute(true); diff --git a/meson.build b/meson.build index 54ad88e..7590106 100644 --- a/meson.build +++ b/meson.build @@ -125,6 +125,7 @@ sources = [ 'systems.cpp', 'textures.cpp', 'worldbuilder.cpp', + 'game_level.cpp', ] executable('runtests', sources + [ @@ -160,10 +161,6 @@ executable('runtests', sources + [ override_options: exe_defaults, dependencies: dependencies + [catch2]) -executable('corostate', - ['scratchpad/corostate.cpp'], - dependencies: [fmt]) - executable('zedcaster', sources + [ 'main.cpp' ], cpp_args: cpp_args, diff --git a/systems.cpp b/systems.cpp index 2be7556..9af40d1 100644 --- a/systems.cpp +++ b/systems.cpp @@ -16,6 +16,7 @@ #include #include "shaders.hpp" #include "inventory.hpp" +#include "game_level.hpp" using std::string; using namespace fmt; @@ -55,7 +56,7 @@ void System::lighting(GameLevel &level) { } void System::generate_paths(GameLevel &level) { - const auto &player_pos = player_position(level); + const auto &player_pos = Game::player_position(); level.map->set_target(player_pos.location); level.map->make_paths(); @@ -91,7 +92,7 @@ void System::enemy_ai_initialize(GameLevel &level) { void System::enemy_pathing(GameLevel &level) { auto &world = *level.world; auto &map = *level.map; - const auto &player_pos = player_position(level); + const auto &player_pos = Game::player_position(); world.query([&](auto ent, auto &position, auto &motion) { if(ent != level.player) { @@ -228,7 +229,7 @@ void System::combat(GameLevel &level, int attack_id) { if(!the_belt.has(attack_id)) return; auto& ritual = the_belt.get(attack_id); - const auto& player_pos = player_position(level); + const auto& player_pos = Game::player_position(); auto& player_combat = world.get(level.player); // this is guaranteed to not return the given position @@ -279,7 +280,7 @@ void System::combat(GameLevel &level, int attack_id) { void System::collision(GameLevel &level) { auto &collider = *level.collision; auto &world = *level.world; - const auto& player_pos = player_position(level); + const auto& player_pos = Game::player_position(); // this is guaranteed to not return the given position auto [found, nearby] = collider.neighbors(player_pos.location); @@ -319,7 +320,7 @@ void System::remove_from_world(GameLevel &level, Entity entity) { void System::pickup(GameLevel &level) { auto &world = *level.world; auto &collision = *level.collision; - auto pos = player_position(level); + auto pos = Game::player_position(); if(!collision.something_there(pos.aiming_at)) return; @@ -381,7 +382,7 @@ void System::device(World &world, Entity actor, Entity item) { } void System::plan_motion(GameLevel& level, Position move_to) { - auto& player_pos = player_position(level); + auto& player_pos = Game::player_position(); player_pos.aiming_at = move_to.aiming_at; @@ -479,10 +480,6 @@ void System::remove_from_container(World& world, Entity cont_id, const std::stri container.remove(entity); } -Position& System::player_position(GameLevel& level) { - auto& player = level.world->get_the(); - return level.world->get(player.entity); -} void System::inventory_swap(GameLevel &level, Entity container_id, const std::string& a_name, const std::string &b_name) { dbc::check(a_name != b_name, "Attempt to inventory swap the same slot, you should check this and avoid calling me."); diff --git a/systems.hpp b/systems.hpp index 24eeccf..151d33b 100644 --- a/systems.hpp +++ b/systems.hpp @@ -34,7 +34,6 @@ namespace System { void remove_from_container(World& world, Entity cont_id, const std::string& name); void remove_from_world(GameLevel &level, Entity entity); - Position& player_position(GameLevel& level); void inventory_swap(GameLevel &level, Entity container_id, const std::string& a_name, const std::string &b_name); bool inventory_occupied(GameLevel& level, Entity container_id, const std::string& name);