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. 61
      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:
END(CLOSE);
break;
case LOOT_SELECT:
if(commit_move($loot_ui.$gui, $grab_source, data)) {
state(DNDState::LOOTING);
}
break;
case LOOT_SELECT: {
auto drop_id = std::any_cast<guecs::Entity>(data);
if(move_or_swap($loot_ui, drop_id)) {
state(DNDState::LOOTING);
}
} break;
case INV_SELECT:
if(commit_drop($loot_ui.$gui,
$status_ui.$gui, $grab_source, data))
@ -92,11 +94,12 @@ namespace gui {
state(DNDState::LOOTING);
}
break;
case INV_SELECT:
if(commit_move($status_ui.$gui, $grab_source, data)) {
state(DNDState::LOOTING);
}
break;
case INV_SELECT: {
auto drop_id = std::any_cast<guecs::Entity>(data);
if(move_or_swap($status_ui, drop_id)) {
state(DNDState::LOOTING);
}
} break;
default:
handle_mouse(ev, $status_ui.$gui);
}
@ -114,15 +117,10 @@ namespace gui {
} break;
case INV_SELECT: {
auto drop_id = std::any_cast<guecs::Entity>(data);
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)) {
if(move_or_swap($status_ui, drop_id)) {
END(CLOSE);
}
} break;
break;
} break;
default:
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");
auto& grab = gui.get<guecs::GrabSource>(*source_id);
grab.commit();
auto drop_id = std::any_cast<guecs::Entity>(data);
auto& drop = gui.get<guecs::DropTarget>(drop_id);
if(drop.commit(grab.world_entity)) {
@ -307,4 +304,30 @@ namespace gui {
clear_grab();
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);
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 throw_on_floor(guecs::UI& gui, bool from_status);
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();
};
}

@ -47,7 +47,6 @@ namespace gui {
for(int i = 0; i < INV_SLOTS; 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 });
@ -69,7 +68,7 @@ namespace gui {
for(size_t i = 0; i < INV_SLOTS; 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)) {
auto item = contents.get(slot_name);
@ -97,7 +96,7 @@ namespace gui {
}
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);
System::remove_from_container(*$level.world, $target, name);
update();
@ -106,7 +105,8 @@ namespace gui {
bool LootUI::place_slot(guecs::Entity id, DinkyECS::Entity world_entity) {
fmt::println("LootUI target={} placing world entity {} in slot id {}",
$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);
if(worked) update();
return worked;
@ -136,4 +136,18 @@ namespace gui {
bool LootUI::mouse(float x, float y, bool 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;
guecs::UI $gui;
GameLevel $level;
std::unordered_map<guecs::Entity, std::string> $slot_to_name;
DinkyECS::Entity $temp_loot;
DinkyECS::Entity $target;
@ -34,5 +33,7 @@ namespace gui {
bool place_slot(guecs::Entity gui_id, DinkyECS::Entity world_entity);
void add_loose_item(DinkyECS::Entity entity);
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()) {
auto gui_id = $gui.entity(name);
$slot_to_name.insert_or_assign(gui_id, name);
if(name == "character_view") {
$gui.set<Rectangle>(gui_id, {});
@ -102,7 +101,7 @@ namespace gui {
}
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& 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
// moves to use an ECS id to a container I can have the System
// do it.
dbc::log(fmt::format("removing slot: {}", slot_id));
auto& slot_name = $slot_to_name.at(slot_id);
auto& slot_name = $gui.name_for(slot_id);
auto player = $level.world->get_the<components::Player>();
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) {
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& inventory = $level.world->get<inventory::Model>(player.entity);
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);
System::inventory_swap($level, player.entity, a_name, b_name);
}
update();
}
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& inventory = $level.world->get<inventory::Model>(player.entity);
auto& slot_name = $slot_to_name.at(slot);
return inventory.has(slot_name);
return System::inventory_occupied($level, player.entity, $gui.name_for(slot));
}
}

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

@ -562,3 +562,18 @@ 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) {
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_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);
bool inventory_occupied(GameLevel& level, Entity container_id, const std::string& name);
}

@ -1,5 +1,5 @@
[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
revision=HEAD
depth=1

Loading…
Cancel
Save