diff --git a/source/game/StarInventoryTypes.hpp b/source/game/StarInventoryTypes.hpp index f184d48..a666f3f 100644 --- a/source/game/StarInventoryTypes.hpp +++ b/source/game/StarInventoryTypes.hpp @@ -19,7 +19,7 @@ enum class EquipmentSlot : uint8_t { }; extern EnumMap const EquipmentSlotNames; -typedef pair BagSlot; +typedef pair BagSlot; strong_typedef(Empty, SwapSlot); strong_typedef(Empty, TrashSlot); diff --git a/source/game/StarPlayerInventory.cpp b/source/game/StarPlayerInventory.cpp index 4f584e5..8ae052c 100644 --- a/source/game/StarPlayerInventory.cpp +++ b/source/game/StarPlayerInventory.cpp @@ -183,6 +183,17 @@ bool PlayerInventory::consumeSlot(InventorySlot const& slot, uint64_t count) { return consumed; } +bool PlayerInventory::slotValid(InventorySlot const& slot) const { + if (auto bagSlot = slot.ptr()) { + if (auto bag = bagContents(bagSlot->first)) { + if ((size_t)bagSlot->second >= bag->size()) + return false; + } + else return false; + } + return true; +} + ItemPtr PlayerInventory::addItems(ItemPtr items) { if (!items || items->empty()) return {}; @@ -219,7 +230,7 @@ ItemPtr PlayerInventory::addToBags(ItemPtr items) { if (!items) break; - for (uint8_t i = 0; i < pair.second->size(); ++i) { + for (unsigned i = 0; i < pair.second->size(); ++i) { if (!pair.second->at(i)) { pair.second->setItem(i, take(items)); autoAddToCustomBar(BagSlot(pair.first, i)); @@ -549,7 +560,7 @@ bool PlayerInventory::clearSwap() { }; auto tryBag = [&](String const& bagType) { - for (uint8_t i = 0; i < m_bags[bagType]->size(); ++i) { + for (unsigned i = 0; i < m_bags[bagType]->size(); ++i) { if (!m_swapSlot || !itemAllowedInBag(m_swapSlot, bagType)) break; trySlot(BagSlot(bagType, i)); diff --git a/source/game/StarPlayerInventory.hpp b/source/game/StarPlayerInventory.hpp index dfebea8..14a65ed 100644 --- a/source/game/StarPlayerInventory.hpp +++ b/source/game/StarPlayerInventory.hpp @@ -64,6 +64,8 @@ public: bool consumeSlot(InventorySlot const& slot, uint64_t count = 1); + bool slotValid(InventorySlot const& slot) const; + // Adds items to any slot except the trash or swap slots, returns stack left // over. ItemPtr addItems(ItemPtr items); diff --git a/source/game/scripting/StarLuaGameConverters.cpp b/source/game/scripting/StarLuaGameConverters.cpp index 070048e..a6f2738 100644 --- a/source/game/scripting/StarLuaGameConverters.cpp +++ b/source/game/scripting/StarLuaGameConverters.cpp @@ -2,6 +2,39 @@ namespace Star { +LuaValue LuaConverter::from(LuaEngine& engine, InventorySlot k) { + if (auto equipment = k.ptr()) + return engine.createString(EquipmentSlotNames.getRight(*equipment)); + else if (auto bag = k.ptr()) { + auto table = engine.createTable(2, 0); + table.set(1, bag->first); + table.set(2, bag->second); + return table; + } + else if (k.is()) + return engine.createString("Swap"); + else if (k.is()) + return engine.createString("Trash"); +} + +Maybe LuaConverter::to(LuaEngine&, LuaValue const& v) { + if (auto str = v.ptr()) { + auto string = str->toString(); + if (string.equalsIgnoreCase("Swap")) + return SwapSlot(); + else if (string.equalsIgnoreCase("Trash")) + return TrashSlot(); + else if (auto equipment = EquipmentSlotNames.leftPtr(str->toString())) + return *equipment; + else + return {}; + } + else if (auto table = v.ptr()) + return BagSlot(table->get(1).toString(), table->get(2)); + else + return {}; +} + LuaValue LuaConverter::from(LuaEngine& engine, CollisionKind k) { return engine.createString(CollisionKindNames.getRight(k)); } diff --git a/source/game/scripting/StarLuaGameConverters.hpp b/source/game/scripting/StarLuaGameConverters.hpp index 6188bf1..c8c7923 100644 --- a/source/game/scripting/StarLuaGameConverters.hpp +++ b/source/game/scripting/StarLuaGameConverters.hpp @@ -2,6 +2,7 @@ #define STAR_LUA_GAME_CONVERTERS_HPP #include "StarLuaConverters.hpp" +#include "StarInventoryTypes.hpp" #include "StarCollisionBlock.hpp" #include "StarPlatformerAStar.hpp" #include "StarActorMovementController.hpp" @@ -14,6 +15,12 @@ namespace Star { +template <> +struct LuaConverter { + static LuaValue from(LuaEngine& engine, InventorySlot k); + static Maybe to(LuaEngine& engine, LuaValue const& v); +}; + template <> struct LuaConverter { static LuaValue from(LuaEngine& engine, CollisionKind k); diff --git a/source/game/scripting/StarPlayerLuaBindings.cpp b/source/game/scripting/StarPlayerLuaBindings.cpp index c26422d..7214f02 100644 --- a/source/game/scripting/StarPlayerLuaBindings.cpp +++ b/source/game/scripting/StarPlayerLuaBindings.cpp @@ -153,81 +153,59 @@ LuaCallbacks LuaBindings::makePlayerCallbacks(Player* player) { } }); - callbacks.registerCallback("actionBarItem", [player](MVariant const& slot, Maybe offHand) -> Json { + callbacks.registerCallback("actionBarSlotLink", [player](int slot, String const& handName) { auto inventory = player->inventory(); - if (!slot) return {}; - else if (auto index = slot.ptr()) { - CustomBarIndex wrapped = (*index - 1) % (unsigned)inventory->customBarIndexes(); - Maybe s; - if (offHand.value(false)) s = inventory->customBarSecondarySlot(wrapped); - else s = inventory->customBarPrimarySlot(wrapped); - if (s.isNothing()) return {}; - return itemSafeDescriptor(inventory->itemsAt(s.value())).toJson(); - } else { - return itemSafeDescriptor(inventory->essentialItem(EssentialItemNames.getLeft(slot.get()))).toJson(); - } + CustomBarIndex wrapped = (slot - 1) % (unsigned)inventory->customBarIndexes(); + if (handName == "primary") + return inventory->customBarPrimarySlot(wrapped); + else if (handName == "alt") + return inventory->customBarSecondarySlot(wrapped); + else + throw StarException(strf("Unknown tool hand {}", handName)); + }); + + callbacks.registerCallback("setActionBarSlotLink", [player](int slot, String const& handName, Maybe inventorySlot) { + auto inventory = player->inventory(); + CustomBarIndex wrapped = (slot - 1) % (unsigned)inventory->customBarIndexes(); + if (inventorySlot && !inventory->slotValid(*inventorySlot)) + inventorySlot.reset(); + + if (handName == "primary") + inventory->setCustomBarPrimarySlot(wrapped, inventorySlot); + else if (handName == "alt") + inventory->setCustomBarSecondarySlot(wrapped, inventorySlot); + else + throw StarException(strf("Unknown tool hand {}", handName)); }); - callbacks.registerCallback("setActionBarItem", [player](MVariant const& slot, bool offHand, Json const& item) { + callbacks.registerCallback("itemBagSize", [player](String const& bagName) -> Maybe { + if (auto bag = player->inventory()->bagContents(bagName)) + return (unsigned)bag->size(); + else + return {}; + }); + + callbacks.registerCallback("itemAllowedInBag", [player](String const& bagName, Json const& item) { auto inventory = player->inventory(); auto itemDatabase = Root::singleton().itemDatabase(); - - if (!slot) return; - else if (auto index = slot.ptr()) { - CustomBarIndex wrapped = (*index - 1) % (unsigned)inventory->customBarIndexes(); - - if (item.type() == Json::Type::Object && item.contains("name")) { - auto itm = itemDatabase->item(ItemDescriptor(item)); - - Maybe found; - inventory->forEveryItem([player, &found, &itm](InventorySlot const& slot, ItemPtr const& item){ - if (!found.isNothing()) return; - if (item->matches(itm, true)) found = slot; - }); - if (!found.isNothing()) { - if (offHand) inventory->setCustomBarSecondarySlot(wrapped, found.value()); - else inventory->setCustomBarPrimarySlot(wrapped, found.value()); - } - } else { - if (offHand) inventory->setCustomBarSecondarySlot(wrapped, {}); - else inventory->setCustomBarPrimarySlot(wrapped, {}); - } - - } else { - // place into essential item slot - //if (item.isNothing()) inventory->setEssentialItem(EssentialItemNames.getLeft(slot.get()), {}); - inventory->setEssentialItem(EssentialItemNames.getLeft(slot.get()), itemDatabase->item(ItemDescriptor(item))); - // TODO: why does this always clear the slot. it's literally the same code as giveEssentialItem - } + if (!inventory->bagContents(bagName)) + return false; + else + return inventory->itemAllowedInBag(itemDatabase->item(ItemDescriptor(item)), bagName); }); - callbacks.registerCallback("itemBagSize", [player](String const& bag) { - auto inventory = player->inventory(); - auto b = inventory->bagContents(bag); - if (!b) return 0; - return (int)b->size(); + callbacks.registerCallback("item", [player](InventorySlot const& slot) -> Maybe { + if (!player->inventory()->slotValid(slot)) return {}; + if (auto item = player->inventory()->itemsAt(slot)) + return itemSafeDescriptor(item).toJson(); + else + return {}; }); - callbacks.registerCallback("itemAllowedInBag", [player](String const& bag, Json const& item) { - auto inventory = player->inventory(); + callbacks.registerCallback("setItem", [player](InventorySlot const& slot, Json const& item) { + if (!player->inventory()->slotValid(slot)) return; auto itemDatabase = Root::singleton().itemDatabase(); - if (!inventory->bagContents(bag)) return false; - return inventory->itemAllowedInBag(itemDatabase->item(ItemDescriptor(item)), bag); - }); - - callbacks.registerCallback("itemBagItem", [player](String const& bag, int slot) -> Json { - auto inventory = player->inventory(); - auto b = inventory->bagContents(bag); - if (!b || slot <= 0 || slot > (int)b->size()) return {}; - return itemSafeDescriptor(b->at(slot - 1)).toJson(); - }); - - callbacks.registerCallback("setItemBagItem", [player](String const& bag, int slot, Json const& item) { - auto inventory = player->inventory(); - auto itemDatabase = Root::singleton().itemDatabase(); - auto b = const_pointer_cast(inventory->bagContents(bag)); // bit of a Naughty Access Cheat here, but - if (!b || slot <= 0 || slot > (int)b->size()) return; - b->setItem(slot - 1, itemDatabase->item(ItemDescriptor(item))); + player->inventory()->setItem(slot, itemDatabase->item(ItemDescriptor(item))); }); callbacks.registerCallback("setDamageTeam", [player](String const& typeName, Maybe teamNumber) {