Finally have inventory not crashing for most edge cases. This solves many bugs but mostly closes #58.

master
Zed A. Shaw 1 day ago
parent 601f3331ed
commit f64b202ee7
  1. 51
      gui/dnd_loot.cpp
  2. 5
      gui/dnd_loot.hpp
  3. 22
      gui/loot_ui.cpp
  4. 3
      gui/loot_ui.hpp
  5. 22
      gui/status_ui.cpp
  6. 1
      gui/status_ui.hpp
  7. 15
      systems.cpp
  8. 2
      systems.hpp
  9. 2
      wraps/lel-guecs.wrap

@ -61,11 +61,13 @@ namespace gui {
case LOOT_OPEN: case LOOT_OPEN:
END(CLOSE); END(CLOSE);
break; break;
case LOOT_SELECT: case LOOT_SELECT: {
if(commit_move($loot_ui.$gui, $grab_source, data)) { auto drop_id = std::any_cast<guecs::Entity>(data);
if(move_or_swap($loot_ui, drop_id)) {
state(DNDState::LOOTING); state(DNDState::LOOTING);
} }
break; } break;
case INV_SELECT: case INV_SELECT:
if(commit_drop($loot_ui.$gui, if(commit_drop($loot_ui.$gui,
$status_ui.$gui, $grab_source, data)) $status_ui.$gui, $grab_source, data))
@ -92,11 +94,12 @@ namespace gui {
state(DNDState::LOOTING); state(DNDState::LOOTING);
} }
break; break;
case INV_SELECT: case INV_SELECT: {
if(commit_move($status_ui.$gui, $grab_source, data)) { auto drop_id = std::any_cast<guecs::Entity>(data);
if(move_or_swap($status_ui, drop_id)) {
state(DNDState::LOOTING); state(DNDState::LOOTING);
} }
break; } break;
default: default:
handle_mouse(ev, $status_ui.$gui); handle_mouse(ev, $status_ui.$gui);
} }
@ -114,15 +117,10 @@ namespace gui {
} break; } break;
case INV_SELECT: { case INV_SELECT: {
auto drop_id = std::any_cast<guecs::Entity>(data); auto drop_id = std::any_cast<guecs::Entity>(data);
if(move_or_swap($status_ui, drop_id)) {
if($status_ui.occupied(drop_id)) {
$status_ui.swap(*$grab_source, drop_id);
END(CLOSE);
} else if(commit_move($status_ui.$gui, $grab_source, data)) {
END(CLOSE); END(CLOSE);
} }
} break; } break;
break;
default: default:
handle_mouse(ev, $status_ui.$gui); handle_mouse(ev, $status_ui.$gui);
} }
@ -252,13 +250,12 @@ namespace gui {
} }
} }
bool DNDLoot::commit_move(guecs::UI& gui, std::optional<guecs::Entity> source_id, std::any data) { bool DNDLoot::commit_move(guecs::UI& gui, std::optional<guecs::Entity> source_id, guecs::Entity drop_id) {
dbc::check(source_id != std::nullopt, "source_id must exist"); dbc::check(source_id != std::nullopt, "source_id must exist");
auto& grab = gui.get<guecs::GrabSource>(*source_id); auto& grab = gui.get<guecs::GrabSource>(*source_id);
grab.commit(); grab.commit();
auto drop_id = std::any_cast<guecs::Entity>(data);
auto& drop = gui.get<guecs::DropTarget>(drop_id); auto& drop = gui.get<guecs::DropTarget>(drop_id);
if(drop.commit(grab.world_entity)) { if(drop.commit(grab.world_entity)) {
@ -307,4 +304,30 @@ namespace gui {
clear_grab(); clear_grab();
return result; return result;
} }
/*
* If I refactored everything to use a levelmanager module then
* this and many other things could go away. Access to $level is
* making this too complicated. Do this for now, but fix bug #59.
*/
bool DNDLoot::move_or_swap(StatusUI& ui, guecs::Entity drop_id) {
if(ui.occupied(drop_id)) {
ui.swap(*$grab_source, drop_id);
clear_grab();
return true;
} else {
return commit_move(ui.$gui, $grab_source, drop_id);
}
}
bool DNDLoot::move_or_swap(LootUI& ui, guecs::Entity drop_id) {
if(ui.occupied(drop_id)) {
ui.swap(*$grab_source, drop_id);
clear_grab();
return true;
} else {
return commit_move(ui.$gui, $grab_source, drop_id);
}
}
} }

@ -50,13 +50,16 @@ namespace gui {
std::optional<guecs::Entity> source_id, std::any data); std::optional<guecs::Entity> source_id, std::any data);
bool commit_move(guecs::UI& gui, bool commit_move(guecs::UI& gui,
std::optional<guecs::Entity> source_id, std::any data); std::optional<guecs::Entity> source_id, guecs::Entity drop_id);
bool hold_item(guecs::UI& gui, guecs::Entity gui_id); bool hold_item(guecs::UI& gui, guecs::Entity gui_id);
bool throw_on_floor(guecs::UI& gui, bool from_status); bool throw_on_floor(guecs::UI& gui, bool from_status);
void clear_grab(); void clear_grab();
bool move_or_swap(StatusUI& status_ui, guecs::Entity drop_id);
bool move_or_swap(LootUI& ui, guecs::Entity drop_id);
sf::Vector2f mouse_position(); sf::Vector2f mouse_position();
}; };
} }

@ -47,7 +47,6 @@ namespace gui {
for(int i = 0; i < INV_SLOTS; i++) { for(int i = 0; i < INV_SLOTS; i++) {
auto name = fmt::format("item_{}", i); auto name = fmt::format("item_{}", i);
auto id = $gui.entity(name); auto id = $gui.entity(name);
$slot_to_name.insert_or_assign(id, name);
$gui.set<guecs::Rectangle>(id, {THEME.PADDING, $gui.set<guecs::Rectangle>(id, {THEME.PADDING,
THEME.TRANSPARENT, THEME.LIGHT_MID }); THEME.TRANSPARENT, THEME.LIGHT_MID });
@ -69,7 +68,7 @@ namespace gui {
for(size_t i = 0; i < INV_SLOTS; i++) { for(size_t i = 0; i < INV_SLOTS; i++) {
auto id = $gui.entity("item_", int(i)); auto id = $gui.entity("item_", int(i));
auto& slot_name = $slot_to_name.at(id); auto& slot_name = $gui.name_for(id);
if(contents.has(slot_name)) { if(contents.has(slot_name)) {
auto item = contents.get(slot_name); auto item = contents.get(slot_name);
@ -97,7 +96,7 @@ namespace gui {
} }
void LootUI::remove_slot(guecs::Entity slot_id) { void LootUI::remove_slot(guecs::Entity slot_id) {
auto& name = $slot_to_name.at(slot_id); auto& name = $gui.name_for(slot_id);
fmt::println("LootUI remove slot inv::Model id={} slot={}", $target, name); fmt::println("LootUI remove slot inv::Model id={} slot={}", $target, name);
System::remove_from_container(*$level.world, $target, name); System::remove_from_container(*$level.world, $target, name);
update(); update();
@ -106,7 +105,8 @@ namespace gui {
bool LootUI::place_slot(guecs::Entity id, DinkyECS::Entity world_entity) { bool LootUI::place_slot(guecs::Entity id, DinkyECS::Entity world_entity) {
fmt::println("LootUI target={} placing world entity {} in slot id {}", fmt::println("LootUI target={} placing world entity {} in slot id {}",
$target, id, world_entity); $target, id, world_entity);
auto& name = $slot_to_name.at(id); auto& name = $gui.name_for(id);
bool worked = System::place_in_container(*$level.world, $target, name, world_entity); bool worked = System::place_in_container(*$level.world, $target, name, world_entity);
if(worked) update(); if(worked) update();
return worked; return worked;
@ -136,4 +136,18 @@ namespace gui {
bool LootUI::mouse(float x, float y, bool hover) { bool LootUI::mouse(float x, float y, bool hover) {
return $gui.mouse(x, y, hover); return $gui.mouse(x, y, hover);
} }
bool LootUI::occupied(guecs::Entity slot) {
return System::inventory_occupied($level, $target, $gui.name_for(slot));
}
void LootUI::swap(guecs::Entity gui_a, guecs::Entity gui_b) {
if(gui_a != gui_b) {
auto& a_name = $gui.name_for(gui_a);
auto& b_name = $gui.name_for(gui_b);
System::inventory_swap($level, $target, a_name, b_name);
}
update();
}
} }

@ -13,7 +13,6 @@ namespace gui {
bool active = false; bool active = false;
guecs::UI $gui; guecs::UI $gui;
GameLevel $level; GameLevel $level;
std::unordered_map<guecs::Entity, std::string> $slot_to_name;
DinkyECS::Entity $temp_loot; DinkyECS::Entity $temp_loot;
DinkyECS::Entity $target; DinkyECS::Entity $target;
@ -34,5 +33,7 @@ namespace gui {
bool place_slot(guecs::Entity gui_id, DinkyECS::Entity world_entity); bool place_slot(guecs::Entity gui_id, DinkyECS::Entity world_entity);
void add_loose_item(DinkyECS::Entity entity); void add_loose_item(DinkyECS::Entity entity);
bool drop_item(DinkyECS::Entity item_id); bool drop_item(DinkyECS::Entity item_id);
bool occupied(guecs::Entity gui_id);
void swap(guecs::Entity gui_a, guecs::Entity gui_b);
}; };
} }

@ -29,7 +29,6 @@ namespace gui {
for(auto& [name, cell] : $gui.cells()) { for(auto& [name, cell] : $gui.cells()) {
auto gui_id = $gui.entity(name); auto gui_id = $gui.entity(name);
$slot_to_name.insert_or_assign(gui_id, name);
if(name == "character_view") { if(name == "character_view") {
$gui.set<Rectangle>(gui_id, {}); $gui.set<Rectangle>(gui_id, {});
@ -102,7 +101,7 @@ namespace gui {
} }
bool StatusUI::place_slot(guecs::Entity gui_id, DinkyECS::Entity world_entity) { bool StatusUI::place_slot(guecs::Entity gui_id, DinkyECS::Entity world_entity) {
auto& slot_name = $slot_to_name.at(gui_id); auto& slot_name = $gui.name_for(gui_id);
auto player = $level.world->get_the<components::Player>(); auto player = $level.world->get_the<components::Player>();
auto& inventory = $level.world->get<inventory::Model>(player.entity); auto& inventory = $level.world->get<inventory::Model>(player.entity);
@ -128,8 +127,7 @@ namespace gui {
// ground or moving from one container or another, so when loot_ui // 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 // moves to use an ECS id to a container I can have the System
// do it. // do it.
dbc::log(fmt::format("removing slot: {}", slot_id)); auto& slot_name = $gui.name_for(slot_id);
auto& slot_name = $slot_to_name.at(slot_id);
auto player = $level.world->get_the<components::Player>(); auto player = $level.world->get_the<components::Player>();
auto& inventory = $level.world->get<inventory::Model>(player.entity); auto& inventory = $level.world->get<inventory::Model>(player.entity);
@ -143,25 +141,17 @@ namespace gui {
void StatusUI::swap(guecs::Entity gui_a, guecs::Entity gui_b) { void StatusUI::swap(guecs::Entity gui_a, guecs::Entity gui_b) {
if(gui_a != gui_b) { if(gui_a != gui_b) {
auto& a_name = $gui.name_for(gui_a);
auto& b_name = $gui.name_for(gui_b);
auto player = $level.world->get_the<components::Player>(); auto player = $level.world->get_the<components::Player>();
auto& inventory = $level.world->get<inventory::Model>(player.entity); System::inventory_swap($level, player.entity, a_name, b_name);
auto& a_name = $slot_to_name.at(gui_a);
auto& b_name = $slot_to_name.at(gui_b);
auto a_ent = inventory.get(a_name);
auto b_ent = inventory.get(b_name);
inventory.swap(a_ent, b_ent);
} }
update(); update();
} }
bool StatusUI::occupied(guecs::Entity slot) { bool StatusUI::occupied(guecs::Entity slot) {
dbc::check($slot_to_name.contains(slot), "jank ass slot to name thing isn't loaded right you idiot.");
auto player = $level.world->get_the<components::Player>(); auto player = $level.world->get_the<components::Player>();
auto& inventory = $level.world->get<inventory::Model>(player.entity); return System::inventory_occupied($level, player.entity, $gui.name_for(slot));
auto& slot_name = $slot_to_name.at(slot);
return inventory.has(slot_name);
} }
} }

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

@ -562,3 +562,18 @@ Position& System::player_position(GameLevel& level) {
auto& player = level.world->get_the<components::Player>(); auto& player = level.world->get_the<components::Player>();
return level.world->get<components::Position>(player.entity); 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) {
dbc::check(a_name != b_name, "Attempt to inventory swap the same slot, you should check this and avoid calling me.");
auto& inventory = level.world->get<inventory::Model>(container_id);
auto a_ent = inventory.get(a_name);
auto b_ent = inventory.get(b_name);
inventory.swap(a_ent, b_ent);
}
bool System::inventory_occupied(GameLevel& level, Entity container_id, const std::string& name) {
auto& inventory = level.world->get<inventory::Model>(container_id);
return inventory.has(name);
}

@ -37,4 +37,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); 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);
} }

@ -1,5 +1,5 @@
[wrap-git] [wrap-git]
directory=lel-guecs-0.2.0 directory=lel-guecs-0.3.0
url=https://git.learnjsthehardway.com/learn-code-the-hard-way/lel-guecs.git url=https://git.learnjsthehardway.com/learn-code-the-hard-way/lel-guecs.git
revision=HEAD revision=HEAD
depth=1 depth=1

Loading…
Cancel
Save