diff options
Diffstat (limited to 'src/shared/item/items.cc')
| -rw-r--r-- | src/shared/item/items.cc | 164 |
1 files changed, 164 insertions, 0 deletions
diff --git a/src/shared/item/items.cc b/src/shared/item/items.cc new file mode 100644 index 0000000..a5540fb --- /dev/null +++ b/src/shared/item/items.cc @@ -0,0 +1,164 @@ +#include "shared/item/items.hh" + +namespace shared { +namespace item { + +item_t make_item(const item::type_t& type, + const std::uint32_t& quantity) noexcept { + if (type >= block::type_offset) { + return std::make_shared<block>(type, quantity); + } + // TODO others + return std::make_shared<block>(type, quantity); +} + +item_t make_item(const enum shared::world::block::type& type, + const std::uint32_t& quantity) noexcept { + return std::make_shared<block>(type, quantity); +} + +item_t make_item(const proto::item& item) noexcept { + const auto type = item.type(); + + constexpr auto offset = shared::item::block::type_offset; + if (type >= offset) { + const auto block = + static_cast<enum shared::world::block::type>(type - offset); + return make_item(block, item.quantity()); + } + return make_item(static_cast<item::type_t>(item.type()), item.quantity()); +} + +items::items(const proto::item_array& proto) noexcept { + const auto length = static_cast<unsigned long>(proto.items_size()); + for (auto i = 0ul; i < length; ++i) { + + const auto& item = proto.items().at(static_cast<int>(i)); + + const auto index = item.index(); + this->contents[index] = make_item(item); + } +} + +// Annoying logic because we have to add into existing first, then start +// adding new stacks after. +bool items::maybe_add(const item::type_t& type, const std::uint32_t& quantity, + const make_item_func_t& func) noexcept { + + const auto stack_size = item::get_max_stack(type); + + std::uint32_t added = 0; + const auto get_existing = + std::ranges::find_if(this->contents, [&](const auto& item) { + if (item == nullptr) { + return false; + } + if (item->type != type) { + return false; + } + if (item->quantity >= stack_size) { + return false; + } + return true; + }); + for (auto it = get_existing; get_existing != std::end(this->contents); + it = get_existing) { + + const auto addition = + std::min(quantity - added, stack_size - (*it)->quantity); + (*it)->quantity += addition; + added += addition; + if (added != quantity) { + continue; + } + + return true; + } + + for (auto& item : this->contents) { + if (item != nullptr) { + continue; + } + + const auto addition = std::min(quantity - added, stack_size); + item = func(type, addition); + added += addition; + if (added != quantity) { + continue; + } + + return true; + } + + return false; +} + +bool items::maybe_remove(const item::type_t& type, + const std::uint32_t& quantity) noexcept { + const auto existing_it = + std::ranges::find_if(this->contents, [&type](const auto& i) { + if (i == nullptr) { + return false; + } + return type == i->get_type(); + }); + if (existing_it == std::end(this->contents)) { + return false; + } + + auto& existing = (*existing_it)->quantity; + if (existing > quantity) { + existing -= quantity; + return true; + } + + if (existing == quantity) { + (*existing_it) = nullptr; + return true; + } + + const auto diff = quantity - existing; + (*existing_it) = nullptr; + return this->maybe_remove(type, diff); +} + +void items::pack(proto::item_array* const proto) const noexcept { + const auto items = proto->mutable_items(); + for (auto i = 0ul; i < std::size(this->contents); ++i) { + const auto& item = contents[i]; + if (item == nullptr) { + continue; + } + + proto::item proto_item; + item->pack(&proto_item, static_cast<std::uint32_t>(i)); + items->Add(std::move(proto_item)); + } +} + +void items::increment(const std::uint32_t& index, + const make_item_func_t& func) noexcept { + auto& item = this->contents[index]; + if (item == nullptr) { + return; + } + if (item->quantity < shared::item::item::get_max_stack(item->type)) { + ++item->quantity; + return; + } + this->maybe_add(item->type, 1, func); +} + +void items::decrement(const std::uint32_t& index) noexcept { + auto& item = this->contents[index]; + if (item == nullptr) { + return; + } + item->quantity -= 1; + if (item->quantity == 0) { + item = nullptr; + } +} + +} // namespace item +} // namespace shared |
