#pragma once #ifndef INVENTORYCOMPONENT_H #define INVENTORYCOMPONENT_H #include #include #include "BehaviorSlot.h" #include "tinyxml2.h" #include "dCommonVars.h" #include "EquippedItem.h" #include "Inventory.h" #include "LDFFormat.h" #include "DatabasePet.h" #include "Component.h" #include "ItemSetPassiveAbility.h" #include "eItemSetPassiveAbilityID.h" #include "PossessorComponent.h" #include "eInventoryType.h" #include "eReplicaComponentType.h" #include "eLootSourceType.h" class Entity; class ItemSet; typedef std::map EquipmentMap; enum class eItemType : int32_t; /** * Handles the inventory of entity, including the items they possess and have equipped. An entity can have inventories * of different types, each type representing a different group of items, see `eInventoryType` for a list of * inventories. */ class InventoryComponent final : public Component { public: struct Group { // Generated ID for the group. The ID is sent by the client and has the format user_group + Math.random() * UINT_MAX. std::string groupId; // Custom name assigned by the user. std::string groupName; // All the lots the user has in the group. std::set lots; }; enum class GroupUpdateCommand { ADD, ADD_LOT, MODIFY, REMOVE, REMOVE_LOT, }; // Based on the command, certain fields will be used or not used. // for example, ADD_LOT wont use groupName, MODIFY wont use lots, etc. struct GroupUpdate { std::string groupId; std::string groupName; LOT lot; eInventoryType inventory; GroupUpdateCommand command; }; static constexpr uint32_t MaximumGroupCount = 50; static constexpr eReplicaComponentType ComponentType = eReplicaComponentType::INVENTORY; InventoryComponent(Entity* parent); void Update(float deltaTime) override; void Serialize(RakNet::BitStream& outBitStream, bool bIsInitialUpdate) override; void LoadXml(const tinyxml2::XMLDocument& document); void UpdateXml(tinyxml2::XMLDocument& document) override; /** * Returns an inventory of the specified type, if it exists * @param type the inventory type to find an inventory for * @return the inventory of the specified type */ Inventory* GetInventory(eInventoryType type); /** * Returns all the inventories this entity has, indexed by type * @return all the inventories this entity has, indexed by type */ const std::map& GetInventories() const; /** * Returns the amount of items this entity possesses of a certain LOT * @param lot the lot to search for * @return the amount of items this entity possesses the specified LOT */ uint32_t GetLotCount(LOT lot) const; /** * Returns the amount of items this entity possesses of a LOT, given that they're not in a temporary inventory * (vendor buyback, vault, etc). * @param lot the lot to search for * @return the amount of items this entity possesses of the specified lot */ uint32_t GetLotCountNonTransfer(LOT lot) const; /** * Returns the items that are currently equipped by this entity * @return the items that are currently equipped by this entity */ const EquipmentMap& GetEquippedItems() const; /** * Adds an item to the inventory of the entity * @param lot the lot to add * @param count the amount of items to add * @param inventoryType the inventory to add the item to * @param config optional config for this item, used for example for rockets * @param parent optional parent of this item, used for proxy items * @param showFlyingLoot show a client animation if the item is added * @param isModMoveAndEquip equips the item * @param subKey optional sub ID of a related object, used by pets * @param inventorySourceType if the inventory was moved, the source inventory * @param sourceType the source of the item, used to determine if the item is dropped or mailed if the inventory is full * @param bound whether this item is bound * @param preferredSlot the preferred slot to store this item * @param lootSourceType The source of the loot. Defaults to none. */ void AddItem( LOT lot, uint32_t count, eLootSourceType lootSourceType = eLootSourceType::NONE, eInventoryType inventoryType = INVALID, const std::vector& config = {}, LWOOBJID parent = LWOOBJID_EMPTY, bool showFlyingLoot = true, bool isModMoveAndEquip = false, LWOOBJID subKey = LWOOBJID_EMPTY, eInventoryType inventorySourceType = INVALID, int32_t sourceType = 0, bool bound = false, int32_t preferredSlot = -1 ); /** * Removes a LOT from the inventory * @param lot the lot to remove * @param count the number of items to remove * @param inventoryType optional inventory type to remove the item from * @param ignoreBound ignores bound items * @param silent silently remove the item */ bool RemoveItem(LOT lot, uint32_t count, eInventoryType inventoryType = INVALID, bool ignoreBound = false, bool silent = false); /** * Moves an existing item to an inventory of the entity * @param item the item to add * @param inventory the inventory to add the item to * @param count the number of items to add * @param showFlyingLot displays UI animation to the user * @param isModMoveAndEquip equips the item * @param ignoreEquipped does not stack on equipped items * @param preferredSlot the preferred slot to store the item in */ void MoveItemToInventory(Item* item, eInventoryType inventory, uint32_t count, bool showFlyingLot = true, bool isModMoveAndEquip = false, bool ignoreEquipped = false, int32_t preferredSlot = -1); /** * Moves a stack of items to an inventory * @param item the item to move * @param inventory the inventory to move the item to * @param slot the slot in the inventory to move the item to */ void MoveStack(Item* item, eInventoryType inventory, uint32_t slot = 0); /** * Returns an item in the inventory by object ID * @param id the id of the item to find * @return item in the inventory by object ID */ Item* FindItemById(LWOOBJID id) const; /** * Returns an item in the inventory that matches the specified LOT * @param lot the lot of the item to find * @param inventoryType optional inventory to search in * @param ignoreEquipped ignores items that are equipped * @param ignoreBound ignores items that are bound * @return item in the inventory that matches the specified LOT */ Item* FindItemByLot(LOT lot, eInventoryType inventoryType = INVALID, bool ignoreEquipped = false, bool ignoreBound = false); /** * Finds an item in the inventory that has the specified subkey, useful for pets * @param id the subkey to look for * @param inventoryType optional inventory type to search in * @return item in the inventory that has the specified subkey */ Item* FindItemBySubKey(LWOOBJID id, eInventoryType inventoryType = INVALID); /** * Checks if the entity has enough space for a batch of loot * @param loot a map of items to add and how many to add * @return whether the entity has enough space for all the items */ bool HasSpaceForLoot(const std::unordered_map& loot); /** * Equips an item in the specified slot * @param location the location to store the item (e.g. chest, left hand, etc.) * @param item the item to place * @param keepCurrent stores the item in an additional temp slot if there's already an item equipped */ void UpdateSlot(const std::string& location, EquippedItem item, bool keepCurrent = false); /** * Removes a slot from the inventory * @param location the slot to remove */ void RemoveSlot(const std::string& location); /** * Equips the given item, guesses the slot to equip it in * @param item the item to equip * @param skipChecks skips checks for equipping cars and rockets (e.g. no special behavior follows) */ void EquipItem(Item* item, bool skipChecks = false); /** * Unequips an item from the inventory * @param item the item to unequip */ void UnEquipItem(Item* item); /** * Unequips an Item from the inventory * @param item the Item to unequip * @return if we were successful */ void HandlePossession(Item* item); /** * Adds a buff related to equipping a lot to the entity * @param item the item to find buffs for */ void ApplyBuff(Item* item) const; /** * Removes buffs related to equipping a lot from the entity * @param item the item to find buffs for */ void RemoveBuff(Item* item) const; /** * Saves the equipped items into a temp state */ void PushEquippedItems(); /** * Unequips all the temporary items and equips the previous item state */ void PopEquippedItems(); /** * Returns if the entity has an item equipped of the given lot * @param lot to lot to search for * @return if the entity has an item equipped of the given lot */ bool IsEquipped(LOT lot) const; /** * Checks and ensures that we have loaded the item set that might be related to this item * @param lot the lot to check the item set for */ void CheckItemSet(LOT lot); /** * Sets the current consumable lot * @param lot the lot to set as consumable */ void SetConsumable(LOT lot); /** * Returns the current consumable lot * @return the current consumable lot */ LOT GetConsumable() const; /** * Finds all the buffs related to a lot * @param item the item to get the buffs for * @param castOnEquip if true, the skill missions for these buffs will be progressed * @return the buffs related to the specified lot */ std::vector FindBuffs(Item* item, bool castOnEquip) const; /** * Initializes the equipped items with a list of items * @param items the items to equip */ void SetNPCItems(const std::vector& items); /** * Adds a skill related to a passed item to the currently equipped skills * @param lot the lot to add a skill for */ void AddItemSkills(LOT lot); /** * Removes the skills related to the passed LOT from the currently equipped skills * @param lot the lot to remove */ void RemoveItemSkills(LOT lot); /** * Triggers one of the passive abilities from the equipped item set * @param trigger the trigger to fire */ void TriggerPassiveAbility(PassiveAbilityTrigger trigger, Entity* target = nullptr); /** * Returns if the entity has any of the passed passive abilities equipped * @param passiveIDs the IDs to check for * @param equipmentRequirement the number of equipment required to be allowed to have the ability * @return if the entity has any of the passed passive abilities equipped */ bool HasAnyPassive(const std::vector& passiveIDs, int32_t equipmentRequirement) const; /** * Despawns the currently active pet, if any */ void DespawnPet(); /** * Spawns the item as a pet (if it is one) * @param item the pet to spawn */ void SpawnPet(Item* item); /** * Updates the database pet data for an item (e.g. moderation status) * @param id the id of the pet to find * @param data the data to store on the pet */ void SetDatabasePet(LWOOBJID id, const DatabasePet& data); /** * Returns the database pet information for an object * @param id the object ID to search for * @return the database pet information for the object that belongs to the passed id */ const DatabasePet& GetDatabasePet(LWOOBJID id) const; /** * Checks if the provided object ID is in this inventory and is a pet * @param id the id of the object to check for * @return if the provided object ID is in this inventory and is a pet */ bool IsPet(LWOOBJID id) const; /** * Removes pet database information from the item with the specified object id * @param id the object id to remove pet info for */ void RemoveDatabasePet(LWOOBJID id); /** * Returns the current behavior slot active for the passed item type * @param type the item type to find the behavior slot for * @return the current behavior slot active for the passed item type */ static BehaviorSlot FindBehaviorSlot(eItemType type); /** * Checks if the inventory type is a temp inventory * @param type the inventory type to check * @return if the inventory type is a temp inventory */ static bool IsTransferInventory(eInventoryType type); /** * Finds the skill related to the passed LOT from the ObjectSkills table * @param lot the lot to find * @return the skill related to the passed LOT */ static uint32_t FindSkill(LOT lot); /** * Call this when you equip an item. This calls OnFactionTriggerItemEquipped for any scripts found on the items. * * @param equippedItem The item script to lookup and call equip on */ void EquipScripts(Item* equippedItem); /** * Call this when you unequip an item. This calls OnFactionTriggerItemUnequipped for any scripts found on the items. * * @param unequippedItem The item script to lookup and call unequip on */ void UnequipScripts(Item* unequippedItem); std::map GetSkills() { return m_Skills; }; bool SetSkill(int slot, uint32_t skillId); bool SetSkill(BehaviorSlot slot, uint32_t skillId); void UpdateGroup(const GroupUpdate& groupUpdate); void RemoveGroup(const std::string& groupId); void FixInvisibleItems(); ~InventoryComponent() override; private: /** * The key is the inventory the group belongs to, the value maps' key is the id for the group. * This is only used for bricks and model inventories. */ std::map> m_Groups{ { eInventoryType::BRICKS, {} }, { eInventoryType::MODELS, {} } }; /** * All the inventory this entity possesses */ std::map m_Inventories; /** * The skills that this entity currently has active */ std::map m_Skills; /** * The pets this entity has, mapped by object ID and pet info */ std::unordered_map m_Pets; /** * Cache of item sets this entity has encountered */ std::vector m_Itemsets; /** * The LOTs we've checked all the item sets for (for cache reasons) */ std::vector m_ItemSetsChecked; /** * all the equipped items */ EquipmentMap m_Equipped; /** * Clone of the equipped items before unequipping all of them */ EquipmentMap m_Pushed; /** * If the inventory has changed */ bool m_Dirty; /** * The currently active consumable */ LOT m_Consumable; /** * Currently has a car equipped */ bool hasCarEquipped = false; Entity* equippedCarEntity = nullptr; LWOOBJID previousPossessableID = LWOOBJID_EMPTY; LWOOBJID previousPossessorID = LWOOBJID_EMPTY; /** * Creates all the proxy items (subitems) for a parent item * @param parent the parent item to generate all the subitems for * @return the proxy items (subitems) for a parent item */ std::vector GenerateProxies(Item* parent); /** * Finds all the proxy items in this inventory for a given parent item * @param parent the parent to find proxy items for * @return the proxy items for the parent */ std::vector FindProxies(LWOOBJID parent); /** * Returns true if the provided LWOOBJID is the parent of this Item. * @param parent the parent item to check for proxies * @return if the provided ID is a valid proxy item */ bool IsValidProxy(LWOOBJID parent); /** * Returns if the provided ID is a valid proxy item (e.g. we have children for it) * @param parent the parent item to check for * @return if the provided ID is a valid proxy item */ bool IsParentValid(Item* root); /** * Removes all the proxy items that have a dangling parent */ void CheckProxyIntegrity(); /** * Removes all the proxy items for a given parent from the inventory * @param item the item to remove proxy items for */ void PurgeProxies(Item* item); /** * Saves all the pet information stored in inventory items to the database * @param document the xml doc to save to */ void LoadPetXml(const tinyxml2::XMLDocument& document); /** * Loads all the pet information from an xml doc into items * @param document the xml doc to load from */ void UpdatePetXml(tinyxml2::XMLDocument& document); void LoadGroupXml(const tinyxml2::XMLElement& groups); void UpdateGroupXml(tinyxml2::XMLElement& groups) const; }; #endif