Refactored inventory some so that the UI is not so knowing of the internals.

master
Zed A. Shaw 10 months ago
parent e0e7a1027c
commit 0878a9e978
  1. 60
      components.hpp
  2. 48
      dinky_components.hpp
  3. 27
      inventory.cpp
  4. 3
      inventory.hpp
  5. 2
      levelmanager.hpp
  6. 31
      status_ui.cpp
  7. 10
      systems.cpp
  8. 1
      systems.hpp

@ -1,17 +1,23 @@
#pragma once #pragma once
#include "dinkyecs.hpp"
#include "components.hpp" #include "components.hpp"
#include "constants.hpp"
#include "config.hpp" #include "config.hpp"
#include "dinky_components.hpp" #include "constants.hpp"
#include "dinkyecs.hpp"
#include "point.hpp" #include "point.hpp"
#include <SFML/System/Vector2.hpp>
#include <SFML/Graphics/Rect.hpp> #include <SFML/Graphics/Rect.hpp>
#include <SFML/System/Vector2.hpp>
#include <functional>
#include <nlohmann/json.hpp>
#include <nlohmann/json_fwd.hpp>
#define ENROLL_COMPONENT(COMPONENT, ...) \
NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(COMPONENT, __VA_ARGS__); \
template <> struct NameOf<COMPONENT> { \
static constexpr const char *name = #COMPONENT; \
};
namespace components { namespace components {
struct Player { using namespace nlohmann;
DinkyECS::Entity entity;
};
struct Position { struct Position {
Point location; Point location;
@ -104,7 +110,7 @@ namespace components {
void step(sf::Vector2f& scale_out, sf::IntRect& rect_out); void step(sf::Vector2f& scale_out, sf::IntRect& rect_out);
}; };
void configure(ComponentMap& component_map); template <typename T> struct NameOf;
// these need to be here if you're using components::convert outside of components.cpp // these need to be here if you're using components::convert outside of components.cpp
ENROLL_COMPONENT(Tile, display, foreground, background); ENROLL_COMPONENT(Tile, display, foreground, background);
@ -113,4 +119,42 @@ namespace components {
ENROLL_COMPONENT(LightSource, strength, radius); ENROLL_COMPONENT(LightSource, strength, radius);
ENROLL_COMPONENT(Weapon, damage); ENROLL_COMPONENT(Weapon, damage);
ENROLL_COMPONENT(Loot, amount); ENROLL_COMPONENT(Loot, amount);
using ReflFuncSignature = std::function<void(DinkyECS::World& world, DinkyECS::Entity ent, nlohmann::json &j)>;
using ComponentMap = std::unordered_map<std::string, ReflFuncSignature>;
struct Player {
DinkyECS::Entity entity;
};
template<typename COMPONENT> COMPONENT convert(nlohmann::json &data) {
COMPONENT result;
from_json(data, result);
return result;
}
template<typename COMPONENT> COMPONENT get(nlohmann::json &data) {
for (auto &i : data["components"]) {
if(i["_type"] == NameOf<COMPONENT>::name) {
COMPONENT result;
from_json(i, result);
return result;
}
}
return {};
}
template <typename COMPONENT> void enroll(ComponentMap &m) {
m[NameOf<COMPONENT>::name] = [](DinkyECS::World& world, DinkyECS::Entity ent, nlohmann::json &j) {
COMPONENT c;
from_json(j, c);
world.set<COMPONENT>(ent, c);
};
}
void configure(ComponentMap& component_map);
void configure_entity(const ComponentMap& component_map, DinkyECS::World& world, DinkyECS::Entity ent, json& data);
} }

@ -1,48 +0,0 @@
#pragma once
#include <functional>
#include <nlohmann/json.hpp>
#include <nlohmann/json_fwd.hpp>
#include "dinkyecs.hpp"
#define ENROLL_COMPONENT(COMPONENT, ...) \
NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(COMPONENT, __VA_ARGS__); \
template <> struct NameOf<COMPONENT> { \
static constexpr const char *name = #COMPONENT; \
};
namespace components {
using namespace nlohmann;
template <typename T> struct NameOf;
using ReflFuncSignature = std::function<void(DinkyECS::World& world, DinkyECS::Entity ent, nlohmann::json &j)>;
using ComponentMap = std::unordered_map<std::string, ReflFuncSignature>;
template<typename COMPONENT> COMPONENT convert(nlohmann::json &data) {
COMPONENT result;
from_json(data, result);
return result;
}
template<typename COMPONENT> COMPONENT get(nlohmann::json &data) {
for (auto &i : data["components"]) {
if(i["_type"] == NameOf<COMPONENT>::name) {
COMPONENT result;
from_json(i, result);
return result;
}
}
return {};
}
template <typename COMPONENT> void enroll(ComponentMap &m) {
m[NameOf<COMPONENT>::name] = [](DinkyECS::World& world, DinkyECS::Entity ent, nlohmann::json &j) {
COMPONENT c;
from_json(j, c);
world.set<COMPONENT>(ent, c);
};
}
void configure_entity(const ComponentMap& component_map, DinkyECS::World& world, DinkyECS::Entity ent, json& data);
}

@ -40,4 +40,31 @@ namespace components {
return -1; return -1;
} }
std::pair<bool, std::string> Inventory::use(GameLevel &level, size_t at) {
auto& player_combat = level.world->get<components::Combat>(level.player);
auto& item = get(at);
if(item.count == 0) return {false, item.data["name"]};
if(item.data["id"] == "SWORD_RUSTY") {
auto weapon = components::get<components::Weapon>(item.data);
player_combat.damage = weapon.damage;
} else if(item.data["id"] == "POTION_HEALING_SMALL") {
auto cure = components::get<components::Curative>(item.data);
player_combat.hp = std::min(player_combat.hp + cure.hp, player_combat.max_hp);
} else if(item.data["id"] == "TORCH_BAD") {
auto new_light = components::get<components::LightSource>(item.data);
level.world->set<components::LightSource>(level.player, new_light);
light = new_light;
} else {
return {false, fmt::format("UNKNOWN ITEM: {}", (std::string)item.data["id"])};
}
decrease(at, 1);
return {true, item.data["name"]};
}
} }

@ -1,6 +1,7 @@
#pragma once #pragma once
#include "components.hpp" #include "components.hpp"
#include <nlohmann/json.hpp> #include <nlohmann/json.hpp>
#include "levelmanager.hpp"
namespace components { namespace components {
using namespace nlohmann; using namespace nlohmann;
@ -26,5 +27,7 @@ namespace components {
int item_index(std::string id); int item_index(std::string id);
void erase_item(size_t at); void erase_item(size_t at);
std::pair<bool, std::string> use(GameLevel &level, size_t at);
}; };
} }

@ -6,7 +6,7 @@
#include <vector> #include <vector>
#include <memory> #include <memory>
#include "spatialmap.hpp" #include "spatialmap.hpp"
#include "dinky_components.hpp" #include "components.hpp"
using std::shared_ptr; using std::shared_ptr;

@ -47,34 +47,15 @@ namespace gui {
if(world->has<components::Inventory>($level.player)) { if(world->has<components::Inventory>($level.player)) {
auto& inventory = world->get<components::Inventory>($level.player); auto& inventory = world->get<components::Inventory>($level.player);
for(size_t i = 0; i < inventory.count(); i++) { for(size_t i = 0; i < inventory.count(); i++) {
if($slots[i] == cn.name) { if($slots[i] == cn.name) {
auto& player_combat = world->get<components::Combat>($level.player); auto [used, name] = inventory.use($level, i);
auto& item = inventory.get(i);
if(item.count == 0) continue; if(used) {
log(fmt::format("Used item: {}", name));
if(item.data["id"] == "SWORD_RUSTY") { } else {
auto weapon = components::get<components::Weapon>(item.data); log(fmt::format("You are out of {}.", name));
player_combat.damage = weapon.damage;
inventory.decrease(i, 1);
log("You equip a new sword.");
break;
} else if(item.data["id"] == "POTION_HEALING_SMALL") {
auto cure = components::get<components::Curative>(item.data);
int prev_hp = player_combat.hp;
player_combat.hp = std::min(player_combat.hp + cure.hp, player_combat.max_hp);
log(fmt::format("Healed player from {} to {}", prev_hp, player_combat.hp));
inventory.decrease(i, 1);
break;
} else if(item.data["id"] == "TORCH_BAD") {
auto new_light = components::get<components::LightSource>(item.data);
world->set<components::LightSource>($level.player, new_light);
inventory.light = new_light;
inventory.decrease(i, 1);
log("You are using a new torch.");
break;
} }
} }
} }

@ -141,6 +141,7 @@ void System::death(GameLevel &level, components::ComponentMap& components) {
auto entity_data = config.items["GRAVE_STONE"]; auto entity_data = config.items["GRAVE_STONE"];
components::configure_entity(components, world, ent, entity_data["components"]); components::configure_entity(components, world, ent, entity_data["components"]);
if(entity_data["inventory_count"] > 0) { if(entity_data["inventory_count"] > 0) {
// right here use a std::any that's already converted instead?
world.set<InventoryItem>(ent, {entity_data["inventory_count"], entity_data}); world.set<InventoryItem>(ent, {entity_data["inventory_count"], entity_data});
} }
} }
@ -248,15 +249,6 @@ void System::collision(GameLevel &level) {
} }
} }
void System::pickup(DinkyECS::World &world, DinkyECS::Entity actor, DinkyECS::Entity item) {
dbc::pre("System::pickup actor doesn't have inventory", world.has<Inventory>(actor));
dbc::pre("System::pickup item isn't configured with InventoryItem.", world.has<InventoryItem>(item));
auto& inventory = world.get<Inventory>(actor);
auto& invitem = world.get<InventoryItem>(item);
inventory.add(invitem);
}
void System::device(DinkyECS::World &world, DinkyECS::Entity actor, DinkyECS::Entity item) { void System::device(DinkyECS::World &world, DinkyECS::Entity actor, DinkyECS::Entity item) {
auto& device = world.get<Device>(item); auto& device = world.get<Device>(item);

@ -14,7 +14,6 @@ namespace System {
void enemy_pathing(GameLevel &level); void enemy_pathing(GameLevel &level);
void init_positions(DinkyECS::World &world, SpatialMap &collider); void init_positions(DinkyECS::World &world, SpatialMap &collider);
void pickup(DinkyECS::World &world, DinkyECS::Entity actor, DinkyECS::Entity item);
void device(DinkyECS::World &world, DinkyECS::Entity actor, DinkyECS::Entity item); void device(DinkyECS::World &world, DinkyECS::Entity actor, DinkyECS::Entity item);
void plan_motion(DinkyECS::World& world, Point move_to); void plan_motion(DinkyECS::World& world, Point move_to);
void draw_entities(DinkyECS::World &world, Map &map, const Matrix &lights, ftxui::Canvas &canvas, const Point &cam_orig, size_t view_x, size_t view_y); void draw_entities(DinkyECS::World &world, Map &map, const Matrix &lights, ftxui::Canvas &canvas, const Point &cam_orig, size_t view_x, size_t view_y);