Big BIG refactor to make inventory use a model that's placed into the world, following a more sane MVC style.
This commit is contained in:
parent
119b3ed11d
commit
a0eff927b6
21 changed files with 270 additions and 123 deletions
|
@ -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();
|
||||
};
|
||||
}
|
||||
|
|
11
gui/fsm.cpp
11
gui/fsm.cpp
|
@ -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);
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
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);
|
||||
$gui.remove<guecs::GrabSource>(slot_id);
|
||||
$gui.remove<guecs::Sprite>(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);
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue