Next phase of the refactor is done. Now to replace everything in Systems.

master
Zed A. Shaw 7 days ago
parent 644ff6edc0
commit 81e25f73bb
  1. 35
      autowalker.cpp
  2. 66
      game_level.cpp
  3. 27
      game_level.hpp
  4. 81
      gui/fsm.cpp
  5. 2
      gui/fsm.hpp
  6. 9
      levelmanager.cpp
  7. 2
      main.cpp
  8. 5
      meson.build
  9. 17
      systems.cpp
  10. 1
      systems.hpp

@ -1,14 +1,15 @@
#include "autowalker.hpp" #include "autowalker.hpp"
#include "ai_debug.hpp" #include "ai_debug.hpp"
#include "gui/ritual_ui.hpp" #include "gui/ritual_ui.hpp"
#include "game_level.hpp"
template<typename Comp> template<typename Comp>
int number_left(gui::FSM& fsm) { int number_left() {
int count = 0; int count = 0;
fsm.$level.world->query<components::Position, Comp>( Game::current_world()->query<components::Position, Comp>(
[&](const auto ent, auto&, auto&) { [&](const auto ent, auto&, auto&) {
if(ent != fsm.$level.player) { if(ent != Game::current().player) {
count++; count++;
} }
}); });
@ -17,16 +18,16 @@ int number_left(gui::FSM& fsm) {
} }
template<typename Comp> template<typename Comp>
Pathing compute_paths(gui::FSM& fsm) { Pathing compute_paths() {
auto& walls_original = fsm.$level.map->$walls; auto& walls_original = Game::current().map->$walls;
auto walls_copy = walls_original; auto walls_copy = walls_original;
Pathing paths{matrix::width(walls_copy), matrix::height(walls_copy)}; Pathing paths{matrix::width(walls_copy), matrix::height(walls_copy)};
fsm.$level.world->query<components::Position>( Game::current().world->query<components::Position>(
[&](const auto ent, auto& position) { [&](const auto ent, auto& position) {
if(ent != fsm.$level.player) { if(ent != Game::current().player) {
if(fsm.$level.world->has<Comp>(ent)) { if(Game::current().world->has<Comp>(ent)) {
paths.set_target(position.location); paths.set_target(position.location);
} else { } else {
// this will mark that spot as a wall so we don't path there temporarily // 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() { Pathing Autowalker::path_to_enemies() {
return compute_paths<components::Combat>(fsm); return compute_paths<components::Combat>();
} }
Pathing Autowalker::path_to_items() { Pathing Autowalker::path_to_items() {
return compute_paths<components::InventoryItem>(fsm); return compute_paths<components::InventoryItem>();
} }
void Autowalker::handle_window_events() { void Autowalker::handle_window_events() {
@ -88,8 +89,7 @@ void Autowalker::process_combat() {
} }
Point Autowalker::get_current_position() { Point Autowalker::get_current_position() {
auto& player_position = fsm.$level.world->get<components::Position>(fsm.$level.player); return Game::player_position().location;
return player_position.location;
} }
void Autowalker::path_fail(Matrix& bad_paths, Point pos) { 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); path_fail(paths.$paths, target_out);
return false; return false;
} }
@ -184,8 +184,8 @@ struct InventoryStats {
}; };
ai::State Autowalker::update_state(ai::State start) { ai::State Autowalker::update_state(ai::State start) {
int enemy_count = number_left<components::Combat>(fsm); int enemy_count = number_left<components::Combat>();
int item_count = number_left<components::InventoryItem>(fsm); int item_count = number_left<components::InventoryItem>();
ai::set(start, "no_more_enemies", enemy_count == 0); ai::set(start, "no_more_enemies", enemy_count == 0);
ai::set(start, "no_more_items", item_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? // what are we aiming at?
auto aimed_at = fsm.$main_ui.camera_aim(); auto aimed_at = fsm.$main_ui.camera_aim();
if(aimed_at && fsm.$level.world->has<components::InventoryItem>(aimed_at)) { if(aimed_at && Game::current_world()->has<components::InventoryItem>(aimed_at)) {
// NOTE: if we're aiming at an item then pick it up // 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 // for now just loot it then close to get it off the map
send_event(gui::Event::LOOT_ITEM); send_event(gui::Event::LOOT_ITEM);
@ -349,7 +349,8 @@ void Autowalker::send_event(gui::Event ev) {
} }
bool Autowalker::player_health_good() { bool Autowalker::player_health_good() {
auto combat = fsm.$level.world->get<components::Combat>(fsm.$level.player); auto world = Game::current_world();
auto combat = world->get<components::Combat>(Game::the_player());
return float(combat.hp) / float(combat.max_hp) > 0.5f; return float(combat.hp) / float(combat.max_hp) > 0.5f;
} }

@ -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<LevelManager> LEVELS;
bool initialized = false;
void init() {
LEVELS = make_shared<LevelManager>();
initialized = true;
}
LevelManager& get_the_manager() {
return *LEVELS;
}
shared_ptr<DinkyECS::World> current_world() {
return current().world;
}
shared_ptr<gui::BossFightUI> 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 &current() {
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<components::Player>();
return world->get<components::Position>(player.entity);
}
DinkyECS::Entity the_player() {
return current().player;
}
}

@ -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<gui::BossFightUI> create_bossfight();
GameLevel& create_level();
void init();
LevelManager& get_the_manager();
GameLevel &next();
GameLevel &previous();
GameLevel &current();
size_t current_index();
std::shared_ptr<DinkyECS::World> current_world();
GameLevel &get(size_t index);
DinkyECS::Entity spawn_enemy(const std::string& named);
components::Position& player_position();
DinkyECS::Entity the_player();
}

@ -12,19 +12,19 @@
#include "shaders.hpp" #include "shaders.hpp"
#include <fmt/xchar.h> #include <fmt/xchar.h>
#include "gui/guecstra.hpp" #include "gui/guecstra.hpp"
#include "game_level.hpp"
namespace gui { namespace gui {
using namespace components; using namespace components;
FSM::FSM() : FSM::FSM() :
$window(sf::VideoMode({SCREEN_WIDTH, SCREEN_HEIGHT}), "Zed's Raycaster Thing"), $window(sf::VideoMode({SCREEN_WIDTH, SCREEN_HEIGHT}), "Zed's Raycaster Thing"),
$debug_ui($levels), $debug_ui(Game::get_the_manager()),
$main_ui($window), $main_ui($window),
$level($levels.current()), $combat_ui(Game::current()),
$combat_ui($level), $status_ui(Game::current()),
$status_ui($level), $map_ui(Game::current()),
$map_ui($level), $loot_ui(Game::current()),
$loot_ui($level),
$font{FONT_FILE_NAME}, $font{FONT_FILE_NAME},
$dnd_loot($status_ui, $loot_ui, $window, $router) $dnd_loot($status_ui, $loot_ui, $window, $router)
{ {
@ -47,7 +47,8 @@ namespace gui {
} }
void FSM::START(Event ) { void FSM::START(Event ) {
$main_ui.update_level($level); auto& level = Game::current();
$main_ui.update_level(level);
$main_ui.init(); $main_ui.init();
$loot_ui.init(); $loot_ui.init();
@ -58,7 +59,7 @@ namespace gui {
$combat_ui.init(); $combat_ui.init();
$status_ui.init(); $status_ui.init();
$boss_fight_ui = $levels.create_bossfight($level.world); $boss_fight_ui = Game::create_bossfight();
$boss_fight_ui->init(); $boss_fight_ui->init();
$map_ui.init(); $map_ui.init();
@ -72,7 +73,7 @@ namespace gui {
void FSM::MOVING(Event ) { void FSM::MOVING(Event ) {
// this should be an optional that returns a point // this should be an optional that returns a point
if(auto move_to = $main_ui.play_move()) { if(auto move_to = $main_ui.play_move()) {
System::plan_motion($level, *move_to); System::plan_motion(Game::current(), *move_to);
run_systems(); run_systems();
$main_ui.dirty(); $main_ui.dirty();
state(State::IDLE); state(State::IDLE);
@ -83,7 +84,7 @@ namespace gui {
using enum Event; using enum Event;
switch(ev) { switch(ev) {
case TICK: { case TICK: {
System::combat($level, $temp_attack_id); System::combat(Game::current(), $temp_attack_id);
run_systems(); run_systems();
state(State::IN_COMBAT); state(State::IN_COMBAT);
} break; } break;
@ -101,7 +102,7 @@ namespace gui {
void FSM::ROTATING(Event) { void FSM::ROTATING(Event) {
if(auto aim = $main_ui.play_rotate()) { 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; player_pos.aiming_at = *aim;
state(State::IDLE); state(State::IDLE);
} }
@ -109,7 +110,7 @@ namespace gui {
void FSM::COMBAT_ROTATE(Event) { void FSM::COMBAT_ROTATE(Event) {
if(auto aim = $main_ui.play_rotate()) { 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; player_pos.aiming_at = *aim;
state(State::IN_COMBAT); state(State::IN_COMBAT);
} }
@ -194,7 +195,7 @@ namespace gui {
auto gui_id = std::any_cast<guecs::Entity>(data); auto gui_id = std::any_cast<guecs::Entity>(data);
auto& slot_name = $status_ui.$gui.name_for(gui_id); 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(); $status_ui.update();
} }
} break; } break;
@ -206,7 +207,7 @@ namespace gui {
mouse_action({1 << guecs::ModBit::hover}); mouse_action({1 << guecs::ModBit::hover});
} break; } break;
case AIM_CLICK: case AIM_CLICK:
System::pickup($level); System::pickup(Game::current());
break; break;
default: default:
break; // ignore everything else break; // ignore everything else
@ -272,11 +273,12 @@ namespace gui {
} }
void FSM::try_move(int dir, bool strafe) { void FSM::try_move(int dir, bool strafe) {
auto& level = Game::current();
using enum State; using enum State;
// prevent moving into occupied space // prevent moving into occupied space
Point move_to = $main_ui.plan_move(dir, strafe); 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"); sound::play("walk");
state(MOVING); state(MOVING);
} else { } else {
@ -360,8 +362,9 @@ namespace gui {
event(Event::LOOT_OPEN); event(Event::LOOT_OPEN);
break; break;
case KEY::Z: { case KEY::Z: {
auto& player_pos = System::player_position($level); auto& level = Game::current();
System::distribute_loot($level, {player_pos.aiming_at}); auto& player_pos = Game::player_position();
System::distribute_loot(level, {player_pos.aiming_at});
} break; } break;
case KEY::X: case KEY::X:
event(Event::STAIRS_DOWN); event(Event::STAIRS_DOWN);
@ -419,13 +422,14 @@ namespace gui {
} }
void FSM::run_systems() { void FSM::run_systems() {
System::generate_paths($level); auto& level = Game::current();
System::enemy_ai_initialize($level); System::generate_paths(level);
System::enemy_pathing($level); System::enemy_ai_initialize(level);
System::collision($level); System::enemy_pathing(level);
System::motion($level); System::collision(level);
System::lighting($level); System::motion(level);
System::death($level); System::lighting(level);
System::death(level);
} }
bool FSM::active() { bool FSM::active() {
@ -434,11 +438,11 @@ namespace gui {
void FSM::handle_world_events() { void FSM::handle_world_events() {
using eGUI = Events::GUI; using eGUI = Events::GUI;
auto& world = *$level.world; auto world = Game::current_world();
while(world.has_event<eGUI>()) { while(world->has_event<eGUI>()) {
auto [evt, entity, data] = world.recv<eGUI>(); auto [evt, entity, data] = world->recv<eGUI>();
auto player = world.get_the<Player>(); auto player = world->get_the<Player>();
// HERE: this has to go, unify these events and just use them in the state machine directly // 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); event(Event::START_COMBAT);
break; break;
case eGUI::ENTITY_SPAWN: { case eGUI::ENTITY_SPAWN: {
auto& sprite = world.get<components::Sprite>(entity); auto& sprite = world->get<components::Sprite>(entity);
$main_ui.$rayview->update_sprite(entity, sprite); $main_ui.$rayview->update_sprite(entity, sprite);
$main_ui.dirty(); $main_ui.dirty();
run_systems(); run_systems();
@ -489,7 +493,7 @@ namespace gui {
event(Event::AIM_CLICK); event(Event::AIM_CLICK);
break; break;
case eGUI::LOOT_ITEM: { case eGUI::LOOT_ITEM: {
dbc::check(world.has<components::InventoryItem>(entity), dbc::check(world->has<components::InventoryItem>(entity),
"INVALID LOOT_ITEM, that entity has no InventoryItem"); "INVALID LOOT_ITEM, that entity has no InventoryItem");
$loot_ui.add_loose_item(entity); $loot_ui.add_loose_item(entity);
event(Event::LOOT_ITEM); event(Event::LOOT_ITEM);
@ -500,7 +504,7 @@ namespace gui {
event(Event::LOOT_OPEN); event(Event::LOOT_OPEN);
} break; } break;
case eGUI::HP_STATUS: case eGUI::HP_STATUS:
System::player_status($level); System::player_status(Game::current());
break; break;
case eGUI::NEW_RITUAL: case eGUI::NEW_RITUAL:
$combat_ui.init(); $combat_ui.init();
@ -543,16 +547,15 @@ namespace gui {
} }
void FSM::next_level() { void FSM::next_level() {
$levels.create_level($level.world); auto& level = Game::create_level();
$level = $levels.next();
$status_ui.update_level($level); $status_ui.update_level(level);
$map_ui.update_level($level); $map_ui.update_level(level);
$combat_ui.update_level($level); $combat_ui.update_level(level);
$main_ui.update_level($level); $main_ui.update_level(level);
$loot_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(); $boss_fight_ui->init();
run_systems(); run_systems();

@ -35,10 +35,8 @@ namespace gui {
bool autowalking = false; bool autowalking = false;
bool $map_open = false; bool $map_open = false;
int $temp_attack_id = 0; int $temp_attack_id = 0;
LevelManager $levels;
DebugUI $debug_ui; DebugUI $debug_ui;
MainUI $main_ui; MainUI $main_ui;
GameLevel $level;
shared_ptr<BossFightUI> $boss_fight_ui = nullptr; shared_ptr<BossFightUI> $boss_fight_ui = nullptr;
CombatUI $combat_ui; CombatUI $combat_ui;
StatusUI $status_ui; StatusUI $status_ui;

@ -27,16 +27,7 @@ inline shared_ptr<DinkyECS::World> clone_load_world(shared_ptr<DinkyECS::World>
auto world = make_shared<DinkyECS::World>(); auto world = make_shared<DinkyECS::World>();
if(prev_world != nullptr) { if(prev_world != nullptr) {
fmt::println("############### NEW WORLD #################");
prev_world->clone_into(*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<components::Sprite>(ent)) {
fmt::println("#### Sprite {} copied to new world.", ent);
}
}
} else { } else {
save::load_configs(*world); save::load_configs(*world);
} }

@ -7,6 +7,7 @@
#include <iostream> #include <iostream>
#include "shaders.hpp" #include "shaders.hpp"
#include "backend.hpp" #include "backend.hpp"
#include "game_level.hpp"
int main(int argc, char* argv[]) { int main(int argc, char* argv[]) {
try { try {
@ -15,6 +16,7 @@ int main(int argc, char* argv[]) {
guecs::init(&backend); guecs::init(&backend);
ai::init("assets/ai.json"); ai::init("assets/ai.json");
animation::init(); animation::init();
Game::init();
if(DEBUG_BUILD) sound::mute(true); if(DEBUG_BUILD) sound::mute(true);

@ -125,6 +125,7 @@ sources = [
'systems.cpp', 'systems.cpp',
'textures.cpp', 'textures.cpp',
'worldbuilder.cpp', 'worldbuilder.cpp',
'game_level.cpp',
] ]
executable('runtests', sources + [ executable('runtests', sources + [
@ -160,10 +161,6 @@ executable('runtests', sources + [
override_options: exe_defaults, override_options: exe_defaults,
dependencies: dependencies + [catch2]) dependencies: dependencies + [catch2])
executable('corostate',
['scratchpad/corostate.cpp'],
dependencies: [fmt])
executable('zedcaster', executable('zedcaster',
sources + [ 'main.cpp' ], sources + [ 'main.cpp' ],
cpp_args: cpp_args, cpp_args: cpp_args,

@ -16,6 +16,7 @@
#include <iostream> #include <iostream>
#include "shaders.hpp" #include "shaders.hpp"
#include "inventory.hpp" #include "inventory.hpp"
#include "game_level.hpp"
using std::string; using std::string;
using namespace fmt; using namespace fmt;
@ -55,7 +56,7 @@ void System::lighting(GameLevel &level) {
} }
void System::generate_paths(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->set_target(player_pos.location);
level.map->make_paths(); level.map->make_paths();
@ -91,7 +92,7 @@ void System::enemy_ai_initialize(GameLevel &level) {
void System::enemy_pathing(GameLevel &level) { void System::enemy_pathing(GameLevel &level) {
auto &world = *level.world; auto &world = *level.world;
auto &map = *level.map; auto &map = *level.map;
const auto &player_pos = player_position(level); const auto &player_pos = Game::player_position();
world.query<Position, Motion>([&](auto ent, auto &position, auto &motion) { world.query<Position, Motion>([&](auto ent, auto &position, auto &motion) {
if(ent != level.player) { if(ent != level.player) {
@ -228,7 +229,7 @@ void System::combat(GameLevel &level, int attack_id) {
if(!the_belt.has(attack_id)) return; if(!the_belt.has(attack_id)) return;
auto& ritual = the_belt.get(attack_id); 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<Combat>(level.player); auto& player_combat = world.get<Combat>(level.player);
// this is guaranteed to not return the given position // 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) { void System::collision(GameLevel &level) {
auto &collider = *level.collision; auto &collider = *level.collision;
auto &world = *level.world; 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 // this is guaranteed to not return the given position
auto [found, nearby] = collider.neighbors(player_pos.location); 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) { void System::pickup(GameLevel &level) {
auto &world = *level.world; auto &world = *level.world;
auto &collision = *level.collision; auto &collision = *level.collision;
auto pos = player_position(level); auto pos = Game::player_position();
if(!collision.something_there(pos.aiming_at)) return; 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) { 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; 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); container.remove(entity);
} }
Position& System::player_position(GameLevel& level) {
auto& player = level.world->get_the<components::Player>();
return level.world->get<components::Position>(player.entity);
}
void System::inventory_swap(GameLevel &level, Entity container_id, const std::string& a_name, const std::string &b_name) { 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."); dbc::check(a_name != b_name, "Attempt to inventory swap the same slot, you should check this and avoid calling me.");

@ -34,7 +34,6 @@ namespace System {
void remove_from_container(World& world, Entity cont_id, const std::string& name); void remove_from_container(World& world, Entity cont_id, const std::string& name);
void remove_from_world(GameLevel &level, Entity entity); 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); 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); bool inventory_occupied(GameLevel& level, Entity container_id, const std::string& name);

Loading…
Cancel
Save