Big BIG refactor to make inventory use a model that's placed into the world, following a more sane MVC style.

master
Zed A. Shaw 6 days ago
parent 119b3ed11d
commit a0eff927b6
  1. 2
      Makefile
  2. 50
      gui/dnd_loot.cpp
  3. 6
      gui/dnd_loot.hpp
  4. 11
      gui/fsm.cpp
  5. 1
      gui/fsm.hpp
  6. 24
      gui/loot_ui.cpp
  7. 9
      gui/loot_ui.hpp
  8. 1
      gui/ritual_ui.cpp
  9. 2
      gui/ritual_ui.hpp
  10. 75
      gui/status_ui.cpp
  11. 2
      gui/status_ui.hpp
  12. 32
      gui/uisystems.cpp
  13. 10
      gui/uisystems.hpp
  14. 65
      inventory.cpp
  15. 21
      inventory.hpp
  16. 3
      meson.build
  17. 15
      systems.cpp
  18. 2
      systems.hpp
  19. 47
      tests/inventory.cpp
  20. 1
      tests/matrix.cpp
  21. 8
      worldbuilder.cpp

@ -57,7 +57,7 @@ clean:
meson compile --clean -C builddir
debug_test: build
gdb --nx -x .gdbinit --ex run --args builddir/runtests -e
gdb --nx -x .gdbinit --ex run --args builddir/runtests -e "[matrix:viewport]"
win_installer:
powershell 'start "C:\Program Files (x86)\solicus\InstallForge\bin\ifbuilderenvx86.exe" scripts\win_installer.ifp'

@ -1,7 +1,5 @@
#define FSM_DEBUG 1
#include "gui/guecstra.hpp"
#include "gui/dnd_loot.hpp"
#include "gui/uisystems.hpp"
namespace gui {
@ -43,11 +41,11 @@ namespace gui {
END(Event::CLOSE);
break;
case LOOT_SELECT:
$grab_source = UISystem::loot_grab($loot_ui.$gui, data);
$grab_source = start_grab($loot_ui.$gui, data);
if($grab_source) state(DNDState::LOOT_GRAB);
break;
case INV_SELECT:
$grab_source = UISystem::loot_grab($status_ui.$gui, data);
$grab_source = start_grab($status_ui.$gui, data);
if($grab_source) state(DNDState::INV_GRAB);
break;
case MOUSE_DRAG_START:
@ -67,11 +65,11 @@ namespace gui {
END(Event::CLOSE);
break;
case LOOT_SELECT:
$grab_source = UISystem::loot_grab($loot_ui.$gui, data);
$grab_source = start_grab($loot_ui.$gui, data);
if($grab_source) state(DNDState::LOOTING);
break;
case INV_SELECT:
if(UISystem::loot_drop($loot_ui.$gui,
if(commit_drop($loot_ui.$gui,
$status_ui.$gui, $grab_source, data))
{
state(DNDState::LOOTING);
@ -90,14 +88,14 @@ namespace gui {
END(Event::CLOSE);
break;
case LOOT_SELECT:
if(UISystem::loot_drop($status_ui.$gui,
if(commit_drop($status_ui.$gui,
$loot_ui.$gui, $grab_source, data))
{
state(DNDState::LOOTING);
}
break;
case INV_SELECT:
$grab_source = UISystem::loot_grab($status_ui.$gui, data);
$grab_source = start_grab($status_ui.$gui, data);
state(DNDState::LOOTING);
break;
default:
@ -128,8 +126,7 @@ namespace gui {
switch(ev) {
case INV_SELECT:
if(UISystem::loot_drop($loot_ui.$gui,
$status_ui.$gui, $grab_source, data))
commit_drop($loot_ui.$gui, $status_ui.$gui, $grab_source, data);
{
END(Event::CLOSE);
}
@ -149,7 +146,7 @@ namespace gui {
case LOOT_ITEM: {
// NOTE: if > 1 items, go to LOOT_OPEN instead
auto gui_id = $loot_ui.$gui.entity("item_0");
$grab_source = UISystem::loot_grab($loot_ui.$gui, gui_id);
$grab_source = start_grab($loot_ui.$gui, gui_id);
if($grab_source) {
auto& source = $loot_ui.$gui.get<guecs::GrabSource>(*$grab_source);
@ -160,7 +157,7 @@ namespace gui {
}
} break;
case INV_SELECT: {
$grab_source = UISystem::loot_grab($status_ui.$gui, data);
$grab_source = start_grab($status_ui.$gui, data);
if($grab_source) {
auto& source = $status_ui.$gui.get<guecs::GrabSource>(*$grab_source);
@ -206,7 +203,6 @@ namespace gui {
case MOUSE_DRAG:
case MOUSE_MOVE: {
if($grab_source) {
fmt::println("MOVING that thing");
auto& source = gui.get<guecs::GrabSource>(*$grab_source);
source.move($window.mapPixelToCoords($router.position));
}
@ -240,4 +236,32 @@ namespace gui {
$window.draw(*$grab_sprite);
}
}
std::optional<guecs::Entity> DNDLoot::start_grab(guecs::UI& gui, std::any data) {
auto gui_id = std::any_cast<guecs::Entity>(data);
if(auto source = gui.get_if<guecs::GrabSource>(gui_id)) {
source->grab();
return gui_id;
} else {
return std::nullopt;
}
}
bool DNDLoot::commit_drop(guecs::UI& source, guecs::UI& target,
std::optional<guecs::Entity> source_id, std::any data)
{
if(!source_id) return false;
auto target_id = std::any_cast<guecs::Entity>(data);
auto& drop = target.get<guecs::DropTarget>(target_id);
auto& grab = source.get<guecs::GrabSource>(*source_id);
if(drop.commit(grab.world_entity)) {
grab.commit();
return true;
} else {
return false;
}
}
}

@ -38,11 +38,17 @@ namespace gui {
void END(Event ev, std::any data={});
void ITEM_PICKUP(Event ev, std::any data);
void INV_PICKUP(Event ev, std::any data);
void handle_mouse(Event ev, guecs::UI& gui);
void mouse_action(bool hover);
void render();
void open();
void close();
std::optional<guecs::Entity> start_grab(guecs::UI& gui, std::any data);
bool commit_drop(guecs::UI& source, guecs::UI& target,
std::optional<guecs::Entity> source_id, std::any data);
sf::Vector2f mouse_position();
};
}

@ -6,7 +6,6 @@
#include "components.hpp"
#include <numbers>
#include "systems.hpp"
#include "gui/uisystems.hpp"
#include "gui/fsm_events.hpp"
#include "events.hpp"
#include "sound.hpp"
@ -69,7 +68,6 @@ namespace gui {
run_systems();
this_crap_must_die();
state(State::IDLE);
}
@ -461,8 +459,7 @@ namespace gui {
dbc::check(world.has<components::InventoryItem>(entity),
"INVALID LOOT_ITEM, that entity has no InventoryItem");
dbc::log("@@@@ SENDING LOOT_ITEM");
auto gui_id = $loot_ui.$gui.entity("item_0");
$loot_ui.contents.insert_or_assign(gui_id, entity);
$loot_ui.contents.add("item_0", entity);
$loot_ui.update();
event(Event::LOOT_ITEM);
} break;
@ -517,10 +514,4 @@ namespace gui {
run_systems();
}
void FSM::this_crap_must_die() {
auto torch_id = System::spawn_item($level, "TORCH_BAD");
auto hand_l = $status_ui.$gui.entity("hand_l");
$status_ui.place_slot(hand_l, torch_id);
}
}

@ -79,6 +79,5 @@ namespace gui {
void handle_world_events();
void next_level();
void debug_render();
void this_crap_must_die();
};
}

@ -40,7 +40,10 @@ namespace gui {
make_button("destroy", L"DESTROY", Events::GUI::LOOT_CLOSE);
for(int i = 0; i < INV_SLOTS; i++) {
auto id = $gui.entity("item_", i);
auto name = fmt::format("item_{}", i);
auto id = $gui.entity(name);
$slot_to_name.insert_or_assign(id, name);
$gui.set<guecs::Rectangle>(id, {THEME.PADDING,
THEME.TRANSPARENT, THEME.LIGHT_MID });
$gui.set<guecs::Effect>(id, {0.4f, "ui_shader"});
@ -54,13 +57,12 @@ namespace gui {
}
void LootUI::update() {
dbc::check(contents.size() < INV_SLOTS, "too many items in loot contents, must be < 16");
for(size_t i = 0; i < INV_SLOTS; i++) {
auto id = $gui.entity("item_", int(i));
auto& slot_name = $slot_to_name.at(id);
if(contents.contains(id)) {
auto item = contents.at(id);
if(contents.has(slot_name)) {
auto item = contents.get(slot_name);
dbc::check($level.world->has<components::Sprite>(item),
"item in inventory UI doesn't exist in world. New level?");
auto& sprite = $level.world->get<components::Sprite>(item);
@ -85,13 +87,16 @@ namespace gui {
}
void LootUI::remove_slot(DinkyECS::Entity slot_id) {
contents.erase(slot_id);
auto& name = $slot_to_name.at(slot_id);
contents.remove(name);
update();
}
bool LootUI::place_slot(DinkyECS::Entity id, DinkyECS::Entity world_entity) {
if(contents.size() < INV_SLOTS && !contents.contains(id)) {
contents.try_emplace(id, world_entity);
bool LootUI::place_slot(guecs::Entity id, DinkyECS::Entity world_entity) {
auto& name = $slot_to_name.at(id);
if(!contents.has(name)) {
contents.add(name, world_entity);
update();
return true;
} else {
@ -105,7 +110,6 @@ namespace gui {
void LootUI::update_level(GameLevel &level) {
$level = level;
contents.clear();
init();
}

@ -5,6 +5,7 @@
#include <SFML/Graphics/Font.hpp>
#include <guecs/ui.hpp>
#include "events.hpp"
#include "inventory.hpp"
namespace gui {
class LootUI {
@ -12,7 +13,9 @@ namespace gui {
bool active = false;
guecs::UI $gui;
GameLevel $level;
std::unordered_map<DinkyECS::Entity, DinkyECS::Entity> contents;
std::unordered_map<guecs::Entity, std::string> $slot_to_name;
// NOTE: this should then become just an ECS id for a container
inventory::Model contents;
LootUI(GameLevel level);
void init();
@ -22,7 +25,7 @@ namespace gui {
bool mouse(float x, float y, bool hover);
void make_button(const std::string &name, const std::wstring& label, Events::GUI event);
void remove_slot(DinkyECS::Entity slot_id);
bool place_slot(DinkyECS::Entity gui_id, DinkyECS::Entity world_entity);
void remove_slot(guecs::Entity slot_id);
bool place_slot(guecs::Entity gui_id, DinkyECS::Entity world_entity);
};
}

@ -47,6 +47,7 @@ namespace gui {
$ritual_ui = textures::get("ritual_crafting_area");
$ritual_ui.sprite->setPosition($gui.get_position());
$ritual_ui.sprite->setTextureRect($ritual_closed_rect);
// BUG: why am I doing this twice?
state(State::CLOSED);
$ritual_anim = animation::load("ritual_blanket");

@ -27,7 +27,7 @@ namespace gui {
};
struct SelectedItem {
DinkyECS::Entity slot_id;
guecs::Entity slot_id;
DinkyECS::Entity item_id;
};

@ -5,6 +5,7 @@
#include <fmt/xchar.h>
#include "gui/guecstra.hpp"
#include "systems.hpp"
#include "inventory.hpp"
namespace gui {
using namespace guecs;
@ -27,28 +28,29 @@ namespace gui {
$gui.set<Background>($gui.MAIN, {$gui.$parser});
for(auto& [name, cell] : $gui.cells()) {
auto gui_id = $gui.entity(name);
$slot_to_name.insert_or_assign(gui_id, name);
if(name == "character_view") {
auto char_view = $gui.entity(name);
$gui.set<Rectangle>(char_view, {});
$gui.set<Sprite>(char_view, {"armored_knight"});
$gui.set<Rectangle>(gui_id, {});
$gui.set<Sprite>(gui_id, {"armored_knight"});
} else {
auto button = $gui.entity(name);
$gui.set<Rectangle>(button, {});
$gui.set<ActionData>(button, {make_any<string>(name)});
$gui.set<Rectangle>(gui_id, {});
$gui.set<ActionData>(gui_id, {make_any<string>(name)});
if(name == "ritual_ui") {
$gui.set<Clickable>(button, {
$gui.set<Clickable>(gui_id, {
[this](auto, auto){ select_ritual(); }
});
$gui.set<Sound>(button, {"pickup"});
$gui.set<Sound>(gui_id, {"pickup"});
} else {
$gui.set<Textual>(button, {guecs::to_wstring(name)});
$gui.set<Clickable>(button, {
guecs::make_action($level, Events::GUI::INV_SELECT, {button})
$gui.set<Textual>(gui_id, {guecs::to_wstring(name)});
$gui.set<Clickable>(gui_id, {
guecs::make_action($level, Events::GUI::INV_SELECT, {gui_id})
});
$gui.set<DropTarget>(button, {
.commit=[&, button](DinkyECS::Entity world_target) -> bool {
return place_slot(button, world_target);
$gui.set<DropTarget>(gui_id, {
.commit=[&, gui_id](DinkyECS::Entity world_target) -> bool {
return place_slot(gui_id, world_target);
}
});
}
@ -57,6 +59,7 @@ namespace gui {
$ritual_ui.event(ritual::Event::STARTED);
$gui.init();
update();
}
bool StatusUI::mouse(float x, float y, bool hover) {
@ -72,7 +75,17 @@ namespace gui {
}
void StatusUI::update() {
dbc::log("REWRITE ME!");
auto& inventory = $level.world->get_the<inventory::Model>();
for(auto& [slot, world_entity] : inventory.by_slot) {
auto gui_id = $gui.entity(slot);
auto& sprite = $level.world->get<components::Sprite>(world_entity);
$gui.set_init<guecs::Sprite>(gui_id, {sprite.name});
guecs::GrabSource grabber{ world_entity,
[&, gui_id]() { return remove_slot(gui_id); }};
grabber.setSprite($gui, gui_id);
$gui.set<guecs::GrabSource>(gui_id, grabber);
}
}
void StatusUI::render(sf::RenderWindow &window) {
@ -87,30 +100,30 @@ namespace gui {
}
bool StatusUI::place_slot(guecs::Entity gui_id, DinkyECS::Entity world_entity) {
if($level.world->has<components::Sprite>(world_entity)) {
auto& sprite = $level.world->get<components::Sprite>(world_entity);
$gui.set_init<guecs::Sprite>(gui_id, {sprite.name});
guecs::GrabSource grabber{ world_entity,
[&, gui_id]() { return remove_slot(gui_id); }};
grabber.setSprite($gui, gui_id);
$gui.set<guecs::GrabSource>(gui_id, grabber);
contents.insert_or_assign(gui_id, world_entity);
auto& slot_name = $slot_to_name.at(gui_id);
auto& inventory = $level.world->get_the<inventory::Model>();
inventory.add(slot_name, world_entity);
update();
return true;
} else {
return false;
}
}
bool StatusUI::drop_item(DinkyECS::Entity item_id) {
return System::drop_item($level, item_id);
bool dropped = System::drop_item($level, item_id);
if(dropped) update();
return dropped;
}
// NOTE: do I need this or how does it relate to drop_item?
void StatusUI::remove_slot(guecs::Entity slot_id) {
if(contents.contains(slot_id)) {
contents.erase(slot_id);
// NOTE: really the System should coordinate either dropping on the
// ground or moving from one container or another, so when loot_ui
// moves to use an ECS id to a container I can have the System
// do it.
auto& slot_name = $slot_to_name.at(slot_id);
auto& inventory = $level.world->get_the<inventory::Model>();
inventory.remove(slot_name);
$gui.remove<guecs::GrabSource>(slot_id);
$gui.remove<guecs::Sprite>(slot_id);
}
}
}

@ -12,7 +12,7 @@ namespace gui {
public:
guecs::UI $gui;
GameLevel $level;
std::unordered_map<guecs::Entity, DinkyECS::Entity> contents;
std::unordered_map<guecs::Entity, std::string> $slot_to_name;
ritual::UI $ritual_ui;
StatusUI(GameLevel level);

@ -1,32 +0,0 @@
#include "gui/uisystems.hpp"
#include "gui/guecstra.hpp"
namespace UISystem {
std::optional<guecs::Entity> loot_grab(guecs::UI& gui, std::any data) {
auto gui_id = std::any_cast<guecs::Entity>(data);
if(auto source = gui.get_if<guecs::GrabSource>(gui_id)) {
source->grab();
return gui_id;
} else {
return std::nullopt;
}
}
bool loot_drop(guecs::UI& source, guecs::UI& target,
std::optional<guecs::Entity> source_id, std::any data)
{
if(!source_id) return false;
auto target_id = std::any_cast<guecs::Entity>(data);
auto& drop = target.get<guecs::DropTarget>(target_id);
auto& grab = source.get<guecs::GrabSource>(*source_id);
if(drop.commit(grab.world_entity)) {
grab.commit();
return true;
} else {
return false;
}
}
}

@ -1,10 +0,0 @@
#pragma once
#include <guecs/ui.hpp>
#include <optional>
namespace UISystem {
std::optional<guecs::Entity> loot_grab(guecs::UI& gui, std::any data);
bool loot_drop(guecs::UI& source, guecs::UI& target,
std::optional<guecs::Entity> source_id, std::any data);
}

@ -0,0 +1,65 @@
#include "inventory.hpp"
namespace inventory {
void Model::add(const Slot &in_slot, DinkyECS::Entity ent) {
if(by_entity.contains(ent)) {
// doing it this way so we can get the offending entity, otherwise it
// crashes on the by_entity.at when this test _passes_
dbc::sentinel(fmt::format("failed to add item to inventory, entity {} is already in the inventory slot {}", ent, by_entity.at(ent)));
}
by_entity.insert_or_assign(ent, in_slot);
by_slot.insert_or_assign(in_slot, ent);
invariant();
}
Slot& Model::get(DinkyECS::Entity ent) {
return by_entity.at(ent);
}
DinkyECS::Entity Model::get(const Slot& slot) {
return by_slot.at(slot);
}
bool Model::has(DinkyECS::Entity ent) {
return by_entity.contains(ent);
}
bool Model::has(const Slot& slot) {
return by_slot.contains(slot);
}
void Model::remove(const Slot& slot, DinkyECS::Entity ent) {
by_entity.erase(ent);
by_slot.erase(slot);
invariant();
}
void Model::remove(DinkyECS::Entity ent) {
auto& slot = by_entity.at(ent);
remove(slot, ent);
invariant();
}
void Model::remove(const Slot& slot) {
auto ent = by_slot.at(slot);
remove(slot, ent);
invariant();
}
void Model::invariant() {
dbc::check(by_slot.size() == by_entity.size(), "by_slot and by_entity have differing sizes");
// std::unordered_map<DinkyECS::Entity, Slot> find_dupes;
for(auto& [slot, ent] : by_slot) {
dbc::check(by_entity.at(ent) == slot,
fmt::format("mismatched slot {} in by_slot doesn't match entity {}", slot, ent));
}
for(auto& [ent, slot] : by_entity) {
dbc::check(by_slot.at(slot) == ent,
fmt::format("mismatched entity {} in by_entity doesn't match entity {}", ent, slot));
}
}
}

@ -0,0 +1,21 @@
#include "dinkyecs.hpp"
#include <unordered_map>
namespace inventory {
using Slot = std::string;
struct Model {
std::unordered_map<Slot, DinkyECS::Entity> by_slot;
std::unordered_map<DinkyECS::Entity, Slot> by_entity;
void add(const Slot &in_slot, DinkyECS::Entity ent);
Slot& get(DinkyECS::Entity ent);
DinkyECS::Entity get(const Slot& slot);
bool has(DinkyECS::Entity ent);
bool has(const Slot& slot);
void remove(const Slot& slot, DinkyECS::Entity ent);
void remove(DinkyECS::Entity ent);
void remove(const Slot& slot);
void invariant();
};
}

@ -106,7 +106,7 @@ sources = [
'gui/overlay_ui.cpp',
'gui/ritual_ui.cpp',
'gui/status_ui.cpp',
'gui/uisystems.cpp',
'inventory.cpp',
'levelmanager.cpp',
'lights.cpp',
'map.cpp',
@ -139,6 +139,7 @@ executable('runtests', sources + [
'tests/easings.cpp',
'tests/event_router.cpp',
'tests/fsm.cpp',
'tests/inventory.cpp',
'tests/levelmanager.cpp',
'tests/lighting.cpp',
'tests/loot.cpp',

@ -15,6 +15,7 @@
#include "battle.hpp"
#include <iostream>
#include "shaders.hpp"
#include "inventory.hpp"
using std::string;
using namespace fmt;
@ -461,12 +462,12 @@ std::shared_ptr<sf::Shader> System::sprite_effect(GameLevel &level, DinkyECS::En
}
}
DinkyECS::Entity System::spawn_item(GameLevel& level, const std::string& name) {
DinkyECS::Entity System::spawn_item(DinkyECS::World& world, const std::string& name) {
Config config("assets/items.json");
auto& item_config = config[name];
auto item_id = level.world->entity();
level.world->set<InventoryItem>(item_id, {1, item_config});
components::configure_entity(*level.world, item_id, item_config["components"]);
auto item_id = world.entity();
world.set<InventoryItem>(item_id, {1, item_config});
components::configure_entity(world, item_id, item_config["components"]);
return item_id;
}
@ -478,13 +479,17 @@ bool System::drop_item(GameLevel& level, DinkyECS::Entity item) {
auto player = world.get_the<Player>();
auto player_pos = world.get<Position>(player.entity);
auto& player_inv = world.get_the<inventory::Model>();
// doesn't compass already avoid walls?
for(matrix::box it{map.walls(), player_pos.location.x, player_pos.location.y, 1}; it.next();) {
for(matrix::box it{map.walls(), player_pos.location.x, player_pos.location.y, 1}; it.next();)
{
Position pos{it.x, it.y};
if(map.can_move(pos.location) && !collision.occupied(pos.location)) {
world.set<Position>(item, pos);
collision.insert(pos.location, item);
// BUG: really there should be another system that handles loot->inv moves
if(player_inv.has(item)) player_inv.remove(item);
level.world->send<Events::GUI>(Events::GUI::ENEMY_SPAWN, item, {});
return true;
}

@ -18,7 +18,7 @@ namespace System {
void device(DinkyECS::World &world, DinkyECS::Entity actor, DinkyECS::Entity item);
void plan_motion(DinkyECS::World& world, Point move_to);
std::wstring draw_map(GameLevel level, size_t view_x, size_t view_y, int compass_dir);
DinkyECS::Entity spawn_item(GameLevel& level, const std::string& name);
DinkyECS::Entity spawn_item(DinkyECS::World& world, const std::string& name);
bool drop_item(GameLevel& level, DinkyECS::Entity item);
void enemy_ai(GameLevel &level);

@ -0,0 +1,47 @@
#include <catch2/catch_test_macros.hpp>
#include <fmt/core.h>
#include <string>
#include "inventory.hpp"
using namespace fmt;
TEST_CASE("base test", "[inventory]") {
inventory::Model inv;
DinkyECS::Entity test_ent = 1;
inv.add("hand_l", test_ent);
inv.invariant();
auto& slot = inv.get(test_ent);
REQUIRE(slot == "hand_l");
auto ent = inv.get(slot);
REQUIRE(ent == test_ent);
REQUIRE(inv.has(ent));
REQUIRE(inv.has(slot));
// test base remove
inv.remove(slot, ent);
REQUIRE(!inv.has(slot));
REQUIRE(!inv.has(ent));
// test remove just by slot
inv.add("hand_r", test_ent);
REQUIRE(inv.has("hand_r"));
REQUIRE(inv.has(test_ent));
inv.invariant();
inv.remove("hand_r");
REQUIRE(!inv.has("hand_r"));
REQUIRE(!inv.has(test_ent));
// test remove just by entity
inv.add("pocket_l", test_ent);
REQUIRE(inv.has("pocket_l"));
REQUIRE(inv.has(test_ent));
inv.invariant();
inv.remove(test_ent);
REQUIRE(!inv.has("pocket_l"));
REQUIRE(!inv.has(test_ent));
}

@ -14,6 +14,7 @@ using std::string;
using matrix::Matrix;
shared_ptr<Map> make_map() {
// BUG? I mean, it's a shared_ptr so it should keep it around but....
LevelManager levels;
GameLevel level = levels.current();
return level.map;

@ -6,6 +6,8 @@
#include "rituals.hpp"
#include "maze.hpp"
#include "textures.hpp"
#include "inventory.hpp"
#include "systems.hpp"
using namespace fmt;
using namespace components;
@ -172,6 +174,11 @@ void WorldBuilder::configure_starting_items(DinkyECS::World &world) {
ritual::JunkItem name = el;
blanket.add(name);
};
auto torch_id = System::spawn_item(world, "TORCH_BAD");
auto &inventory = world.get_the<inventory::Model>();
inventory.add("hand_r", torch_id);
}
void WorldBuilder::place_entities(DinkyECS::World &world) {
@ -202,6 +209,7 @@ void WorldBuilder::place_entities(DinkyECS::World &world) {
world.set_the<Player>(player);
world.set_the<ritual::Belt>({});
world.set_the<ritual::Blanket>({});
world.set_the<inventory::Model>({});
configure_starting_items(world);
world.make_constant(player.entity);
}

Loading…
Cancel
Save