Public release of the DLU server code!

Have fun!
This commit is contained in:
Unknown
2021-12-05 18:54:36 +01:00
parent 5f7270e4ad
commit 0545adfac3
1146 changed files with 368646 additions and 1 deletions

View File

@@ -0,0 +1,26 @@
#pragma once
#include "dCommonVars.h"
/**
* Database information that specifies a pet
*/
struct DatabasePet
{
/**
* The lot of this pet
*/
LOT lot = LOT_NULL;
/**
* The name of the pet
*/
std::string name;
/**
* The current moderation state, see PetComponent for more info
*/
int32_t moderationState = 0;
};
const DatabasePet DATABASE_PET_INVALID;

View File

@@ -0,0 +1 @@
#include "EquippedItem.h"

View File

@@ -0,0 +1,29 @@
#pragma once
#include "dCommonVars.h"
/**
* An item that's equipped, generally as a smaller return type than the regular Item class
*/
struct EquippedItem
{
/**
* The object ID of the equipped item
*/
LWOOBJID id = LWOOBJID_EMPTY;
/**
* The LOT of this equipped item
*/
LOT lot = LOT_NULL;
/**
* The number of items that are stored in this slot
*/
uint32_t count = 0;
/**
* The slot this item is stored in
*/
uint32_t slot = 0;
};

View File

@@ -0,0 +1,354 @@
#include "Inventory.h"
#include "GameMessages.h"
#include "Game.h"
#include "Item.h"
std::vector<LOT> Inventory::m_GameMasterRestrictedItems = {
1727, // GM Only - JetPack
2243, // GM Only - Hammer of Doom
3293, // GM Only - Flamethrower
3735, // GM Only - Large Jetpack
5873, // GM Only - Winged Helm of Speed
6407, // Gm Only - Hat of Pwnage
14442 // The jamesster jetpack
};
Inventory::Inventory(const eInventoryType type, const uint32_t size, const std::vector<Item*>& items, InventoryComponent* component)
{
this->type = type;
this->size = size;
this->free = size;
this->component = component;
for (auto* item : items)
{
AddManagedItem(item);
}
}
eInventoryType Inventory::GetType() const
{
return type;
}
uint32_t Inventory::GetSize() const
{
return size;
}
std::map<LWOOBJID, Item*>& Inventory::GetItems()
{
return items;
}
std::map<uint32_t, Item*> Inventory::GetSlots() const
{
std::map<uint32_t, Item*> slots;
for (const auto& pair : items)
{
auto* item = pair.second;
slots.insert_or_assign(item->GetSlot(), item);
}
return slots;
}
InventoryComponent* Inventory::GetComponent() const
{
return component;
}
uint32_t Inventory::GetLotCount(const LOT lot) const
{
uint32_t count = 0;
for (const auto& pair : items)
{
const auto* item = pair.second;
if (item->GetLot() == lot)
{
count += item->GetCount();
}
}
return count;
}
void Inventory::SetSize(const uint32_t value)
{
free += static_cast<int32_t>(value) - static_cast<int32_t>(size);
size = value;
GameMessages::SendSetInventorySize(component->GetParent(), type, static_cast<int>(size));
}
int32_t Inventory::FindEmptySlot()
{
if (free <= 6) // Up from 1
{
if (type != ITEMS && type != VAULT_ITEMS)
{
uint32_t newSize = size;
if (type == MODELS || type == VAULT_MODELS)
{
newSize = 240;
}
else
{
newSize += 20;
}
if (newSize > GetSize())
{
SetSize(newSize);
}
}
}
if (free == 0)
{
return -1;
}
const auto slots = GetSlots();
for (auto i = 0u; i < size; ++i)
{
if (slots.find(i) == slots.end())
{
return i;
}
}
return -1;
}
int32_t Inventory::GetEmptySlots()
{
return free;
}
bool Inventory::IsSlotEmpty(int32_t slot)
{
const auto slots = GetSlots();
const auto& index = slots.find(slot);
return index == slots.end();
}
Item* Inventory::FindItemById(const LWOOBJID id) const
{
const auto& index = items.find(id);
if (index == items.end())
{
return nullptr;
}
return index->second;
}
Item* Inventory::FindItemByLot(const LOT lot, const bool ignoreEquipped, const bool ignoreBound) const
{
Item* smallest = nullptr;
for (const auto& pair : items)
{
auto* item = pair.second;
if (item->GetLot() != lot)
{
continue;
}
if (ignoreEquipped && item->IsEquipped())
{
continue;
}
if (ignoreBound && item->GetBound())
{
continue;
}
if (smallest == nullptr)
{
smallest = item;
continue;
}
if (smallest->GetCount() > item->GetCount())
{
smallest = item;
}
}
return smallest;
}
Item* Inventory::FindItemBySlot(const uint32_t slot) const
{
const auto slots = GetSlots();
const auto index = slots.find(slot);
if (index == slots.end())
{
return nullptr;
}
return index->second;
}
Item* Inventory::FindItemBySubKey(LWOOBJID id) const
{
for (const auto& item : items)
{
if (item.second->GetSubKey() == id)
{
return item.second;
}
}
return nullptr;
}
void Inventory::AddManagedItem(Item* item)
{
const auto id = item->GetId();
if (items.find(id) != items.end())
{
Game::logger->Log("Inventory", "Attempting to add an item with an already present id (%llu)!\n", id);
return;
}
const auto slots = GetSlots();
const auto slot = item->GetSlot();
if (slots.find(slot) != slots.end())
{
Game::logger->Log("Inventory", "Attempting to add an item with and already present slot (%i)!\n", slot);
return;
}
items.insert_or_assign(id, item);
free--;
}
void Inventory::RemoveManagedItem(Item* item)
{
const auto id = item->GetId();
if (items.find(id) == items.end())
{
Game::logger->Log("Inventory", "Attempting to remove an item with an invalid id (%llu), lot (%i)!\n", id, item->GetLot());
return;
}
items.erase(id);
free++;
}
eInventoryType Inventory::FindInventoryTypeForLot(const LOT lot)
{
auto itemComponent = FindItemComponent(lot);
const auto itemType = static_cast<eItemType>(itemComponent.itemType);
switch (itemType) {
case ITEM_TYPE_BRICK:
return BRICKS;
case ITEM_TYPE_BEHAVIOR:
return BEHAVIORS;
case ITEM_TYPE_PROPERTY:
return PROPERTY_DEEDS;
case ITEM_TYPE_MODEL:
case ITEM_TYPE_VEHICLE:
case ITEM_TYPE_LOOT_MODEL:
return MODELS;
case ITEM_TYPE_HAT:
case ITEM_TYPE_HAIR:
case ITEM_TYPE_NECK:
case ITEM_TYPE_LEFT_HAND:
case ITEM_TYPE_RIGHT_HAND:
case ITEM_TYPE_LEGS:
case ITEM_TYPE_LEFT_TRINKET:
case ITEM_TYPE_RIGHT_TRINKET:
case ITEM_TYPE_COLLECTIBLE:
case ITEM_TYPE_CONSUMABLE:
case ITEM_TYPE_CHEST:
case ITEM_TYPE_EGG:
case ITEM_TYPE_PET_FOOD:
case ITEM_TYPE_PET_INVENTORY_ITEM:
case ITEM_TYPE_PACKAGE:
case ITEM_TYPE_CURRENCY:
return ITEMS;
case ITEM_TYPE_QUEST_OBJECT:
case ITEM_TYPE_UNKNOWN:
default:
return HIDDEN;
}
}
const CDItemComponent& Inventory::FindItemComponent(const LOT lot)
{
auto* registry = CDClientManager::Instance()->GetTable<CDComponentsRegistryTable>("ComponentsRegistry");
auto* itemComponents = CDClientManager::Instance()->GetTable<CDItemComponentTable>("ItemComponent");
const auto componentId = registry->GetByIDAndType(lot, COMPONENT_TYPE_ITEM);
if (componentId == 0)
{
Game::logger->Log("Inventory", "Failed to find item component for (%i)!\n", lot);
return CDItemComponentTable::Default;
}
const auto& itemComponent = itemComponents->GetItemComponentByID(componentId);
return itemComponent;
}
bool Inventory::IsValidItem(const LOT lot)
{
auto* registry = CDClientManager::Instance()->GetTable<CDComponentsRegistryTable>("ComponentsRegistry");
const auto componentId = registry->GetByIDAndType(lot, COMPONENT_TYPE_ITEM);
return componentId != 0;
}
const std::vector<LOT>& Inventory::GetAllGMItems()
{
return m_GameMasterRestrictedItems;
}
Inventory::~Inventory()
{
for (auto item : items)
{
delete item.second;
}
items.clear();
}

View File

@@ -0,0 +1,184 @@
#pragma once
#include <map>
#include <vector>
#include "CDClientManager.h"
#include "dCommonVars.h"
class Item;
class InventoryComponent;
/**
* An inventory of a certain type that's owned by an entity
*/
class Inventory final
{
public:
explicit Inventory(eInventoryType type, uint32_t size, const std::vector<Item*>& items, InventoryComponent* component);
/**
* Returns the type of this inventory
* @return the type of this inventory
*/
eInventoryType GetType() const;
/**
* Returns the maximum amount of items this inventory can contain
* @return the maximum amount of items this inventory can contain
*/
uint32_t GetSize() const;
/**
* Returns all the items that are currently in this inventory, mapped by object ID
* @return all the items that are currently in this inventory, mapped by object ID
*/
std::map<LWOOBJID, Item*>& GetItems();
/**
* Returns all the items that are currently in this inventory, mapped by slot
* @return all the items that are currently in this inventory, mapped by slot
*/
std::map<uint32_t, Item*> GetSlots() const;
/**
* Returns the inventory component that this inventory is part of
* @return the inventory component that this inventory is part of
*/
InventoryComponent* GetComponent() const;
/**
* Returns the amount of items this inventory contains of the specified LOT
* @param lot the lot to find items for
* @return the amount of items this inventory contains of the specified LOT
*/
uint32_t GetLotCount(LOT lot) const;
/**
* Updates the max size of this inventory
* @param value the size to set
*/
void SetSize(uint32_t value);
/**
* Returns the first slot in this inventory that does not contain an item
* @return the first slot in this inventory that does not contain an item
*/
int32_t FindEmptySlot();
/**
* Returns the number of empty slots this inventory has left
* @return the number of empty slots this inventory has left
*/
int32_t GetEmptySlots();
/**
* Returns if the slot for the specified index is empty
* @param slot the index to check occupation for
* @return if the slot for the specified index is empty
*/
bool IsSlotEmpty(int32_t slot);
/**
* Finds an item in this inventory by the provided id
* @param id the object ID of the item to find
* @return item in this inventory by the provided id
*/
Item* FindItemById(LWOOBJID id) const;
/**
* Finds an item in the inventory for the provided LOT
* @param lot the lot to find items for
* @param ignoreEquipped ignores equipped items
* @param ignoreBound ignores bound items
* @return item in the inventory for the provided LOT
*/
Item* FindItemByLot(LOT lot, bool ignoreEquipped = false, bool ignoreBound = false) const;
/**
* Finds an item in the inventory stored on the provied slot
* @param slot to slot to find an item for
* @return item in the inventory stored on the provied slot
*/
Item* FindItemBySlot(uint32_t slot) const;
/**
* Finds an item based on a specified subkey (useful for pets)
* @param id the subkey to look for in the items
* @return item based on a specified subkey
*/
Item* FindItemBySubKey(LWOOBJID id) const;
/**
* Adds an item to the inventory, finding a slot to place it in
* @param item item to add to the inventory
*/
void AddManagedItem(Item* item);
/**
* Removes an item from the inventory, clearing its slot
* @param item
*/
void RemoveManagedItem(Item* item);
/**
* Returns the inventory type an item of the specified lot should be placed in
* @param lot the lot to find the inventory type for
* @return the inventory type an item of the specified lot should be placed in
*/
static eInventoryType FindInventoryTypeForLot(LOT lot);
/**
* Finds the database item component for a item of a certain LOT
* @param lot the LOT of the item to get the database item component for
* @return the database item component for a item of a certain LOT
*/
static const CDItemComponent& FindItemComponent(LOT lot);
/**
* Cheks if the provided lot has a database item component
* @param lot the LOT to check item validity for
* @return if the provided lot has a database item component
*/
static bool IsValidItem(LOT lot);
/**
* Returns all the items that are restricted to GMs
* @return all the items that are restricted to GMs
*/
static const std::vector<LOT>& GetAllGMItems();
~Inventory();
private:
/**
* The type of this inventory
*/
eInventoryType type;
/**
* The max size of this inventory
*/
uint32_t size;
/**
* The amount of items that can still be stored in this inventroy
*/
uint32_t free;
/**
* The items stored in this inventory
*/
std::map<LWOOBJID, Item*> items;
/**
* The inventory component this inventory belongs to
*/
InventoryComponent* component;
/**
* List of items that are GM restricted
*/
static std::vector<LOT> m_GameMasterRestrictedItems;
};

500
dGame/dInventory/Item.cpp Normal file
View File

@@ -0,0 +1,500 @@
#include "Item.h"
#include <sstream>
#include "../dWorldServer/ObjectIDManager.h"
#include "GeneralUtils.h"
#include "GameMessages.h"
#include "Entity.h"
#include "Game.h"
#include "dLogger.h"
#include "EntityManager.h"
#include "RenderComponent.h"
class Inventory;
Item::Item(const LWOOBJID id, const LOT lot, Inventory* inventory, const uint32_t slot, const uint32_t count, const bool bound, const std::vector<LDFBaseData*>& config, const LWOOBJID parent, LWOOBJID subKey)
{
if (!Inventory::IsValidItem(lot))
{
return;
}
this->id = id;
this->lot = lot;
this->inventory = inventory;
this->slot = slot;
this->count = count;
this->bound = bound;
this->config = config;
this->parent = parent;
this->info = &Inventory::FindItemComponent(lot);
this->preconditions = new PreconditionExpression(this->info->reqPrecondition);
this->subKey = subKey;
inventory->AddManagedItem(this);
}
Item::Item(
const LOT lot,
Inventory* inventory,
const uint32_t slot,
const uint32_t count,
const std::vector<LDFBaseData*>& config,
const LWOOBJID parent,
bool showFlyingLoot,
bool isModMoveAndEquip,
LWOOBJID subKey,
bool bound)
{
if (!Inventory::IsValidItem(lot))
{
return;
}
if (isModMoveAndEquip)
{
showFlyingLoot = false;
}
this->lot = lot;
this->inventory = inventory;
this->slot = slot;
this->count = count;
this->config = config;
this->parent = parent;
this->id = LWOOBJID_EMPTY;
this->info = &Inventory::FindItemComponent(lot);
this->bound = info->isBOP || bound;
this->preconditions = new PreconditionExpression(this->info->reqPrecondition);
this->subKey = subKey;
LWOOBJID id = ObjectIDManager::GenerateRandomObjectID();
id = GeneralUtils::SetBit(id, OBJECT_BIT_CHARACTER);
id = GeneralUtils::SetBit(id, OBJECT_BIT_PERSISTENT);
this->id = id;
inventory->AddManagedItem(this);
auto* entity = inventory->GetComponent()->GetParent();
GameMessages::SendAddItemToInventoryClientSync(entity, entity->GetSystemAddress(), this, id, showFlyingLoot, static_cast<int>(this->count), subKey);
if (isModMoveAndEquip)
{
Equip();
Game::logger->Log("Item", "Move and equipped (%i) from (%i)\n", this->lot, this->inventory->GetType());
EntityManager::Instance()->SerializeEntity(inventory->GetComponent()->GetParent());
}
}
LWOOBJID Item::GetId() const
{
return id;
}
LOT Item::GetLot() const
{
return lot;
}
uint32_t Item::GetCount() const
{
return count;
}
uint32_t Item::GetSlot() const
{
return slot;
}
std::vector<LDFBaseData*>& Item::GetConfig()
{
return config;
}
const CDItemComponent& Item::GetInfo() const
{
return *info;
}
bool Item::GetBound() const
{
return bound;
}
Inventory* Item::GetInventory() const
{
return inventory;
}
LWOOBJID Item::GetParent() const
{
return parent;
}
LWOOBJID Item::GetSubKey() const
{
return subKey;
}
PreconditionExpression* Item::GetPreconditionExpression() const
{
return preconditions;
}
void Item::SetCount(const uint32_t value, const bool silent, const bool disassemble, const bool showFlyingLoot)
{
if (value == count)
{
return;
}
const auto delta = std::abs(static_cast<int32_t>(value) - static_cast<int32_t>(count));
const auto type = static_cast<eItemType>(info->itemType);
if (disassemble)
{
if (value < count)
{
for (auto i = 0; i < delta; ++i)
{
Disassemble();
}
}
}
if (!silent)
{
auto* entity = inventory->GetComponent()->GetParent();
if (value > count)
{
GameMessages::SendAddItemToInventoryClientSync(entity, entity->GetSystemAddress(), this, id, showFlyingLoot, delta);
}
else
{
GameMessages::SendRemoveItemFromInventory(entity, entity->GetSystemAddress(), id, lot, inventory->GetType(), delta, value);
}
}
count = value;
if (count == 0)
{
RemoveFromInventory();
}
}
void Item::SetSlot(const uint32_t value)
{
if (slot == value)
{
return;
}
for (const auto& pair : inventory->GetItems())
{
auto* item = pair.second;
if (item->slot == value)
{
item->slot = slot;
}
}
slot = value;
}
void Item::SetBound(const bool value)
{
bound = value;
}
void Item::SetSubKey(LWOOBJID value)
{
subKey = value;
}
void Item::SetInventory(Inventory* value)
{
inventory->RemoveManagedItem(this);
inventory = value;
inventory->AddManagedItem(this);
}
void Item::Equip(const bool skipChecks)
{
if (IsEquipped())
{
return;
}
inventory->GetComponent()->EquipItem(this, skipChecks);
}
void Item::UnEquip()
{
if (!IsEquipped())
{
return;
}
inventory->GetComponent()->UnEquipItem(this);
}
bool Item::IsEquipped() const
{
auto* component = inventory->GetComponent();
for (const auto& pair : component->GetEquippedItems())
{
const auto item = pair.second;
if (item.id == id)
{
return true;
}
}
return false;
}
bool Item::Consume()
{
auto* skillsTable = CDClientManager::Instance()->GetTable<CDObjectSkillsTable>("ObjectSkills");
auto skills = skillsTable->Query([=](const CDObjectSkills entry)
{
return entry.objectTemplate == static_cast<uint32_t>(lot);
});
auto success = false;
for (auto& skill : skills)
{
if (skill.castOnType == 3) // Consumable type
{
success = true;
}
}
Game::logger->Log("Item", "Consumed (%i) / (%llu) with (%d)\n", lot, id, success);
GameMessages::SendUseItemResult(inventory->GetComponent()->GetParent(), lot, success);
if (success)
{
inventory->GetComponent()->RemoveItem(lot, 1);
}
return success;
}
bool Item::UseNonEquip()
{
auto* compRegistryTable = CDClientManager::Instance()->GetTable<CDComponentsRegistryTable>("ComponentsRegistry");
const auto packageComponentId = compRegistryTable->GetByIDAndType(lot, COMPONENT_TYPE_PACKAGE);
auto* packCompTable = CDClientManager::Instance()->GetTable<CDPackageComponentTable>("PackageComponent");
auto packages = packCompTable->Query([=](const CDPackageComponent entry) {return entry.id == static_cast<uint32_t>(packageComponentId); });
const auto success = !packages.empty();
Game::logger->Log("Item", "Used (%i) with (%d)\n", lot, success);
if (subKey != LWOOBJID_EMPTY)
{
const auto& databasePet = GetInventory()->GetComponent()->GetDatabasePet(subKey);
if (databasePet.lot != LOT_NULL)
{
GetInventory()->GetComponent()->SpawnPet(this);
return true;
}
}
if (success)
{
auto* entityParent = inventory->GetComponent()->GetParent();
for (auto& pack : packages)
{
std::unordered_map<LOT, int32_t> result {};
Loot::CalculateLootMatrix(pack.LootMatrixIndex, entityParent, result);
if (!inventory->GetComponent()->HasSpaceForLoot(result))
{
return false;
}
Loot::GiveLoot(inventory->GetComponent()->GetParent(), result);
}
inventory->GetComponent()->RemoveItem(lot, 1);
}
return success;
}
void Item::Disassemble(const eInventoryType inventoryType)
{
for (auto* data : config)
{
if (data->GetKey() == u"assemblyPartLOTs")
{
auto modStr = data->GetValueAsString();
std::vector<LOT> modArray;
std::stringstream ssData(modStr);
std::string token;
const auto deliminator = '+';
while (std::getline(ssData, token, deliminator))
{
const auto modLot = std::stoi(token.substr(2, token.size() - 1));
modArray.push_back(modLot);
}
for (const auto mod : modArray)
{
inventory->GetComponent()->AddItem(mod, 1, inventoryType);
}
}
}
}
void Item::DisassembleModel()
{
auto* table = CDClientManager::Instance()->GetTable<CDComponentsRegistryTable>("ComponentsRegistry");
const auto componentId = table->GetByIDAndType(GetLot(), COMPONENT_TYPE_RENDER);
std::stringstream query;
query << "SELECT render_asset FROM RenderComponent WHERE id = " << std::to_string(componentId) << ";";
auto result = CDClientDatabase::ExecuteQuery(query.str());
if (result.eof())
{
return;
}
std::string renderAsset = result.fieldIsNull(0) ? "" : std::string(result.getStringField(0));
std::vector<std::string> renderAssetSplit = GeneralUtils::SplitString(renderAsset, '\\');
std::string lxfmlPath = "res/BrickModels/" + GeneralUtils::SplitString(renderAssetSplit.back(), '.')[0] + ".lxfml";
std::ifstream file(lxfmlPath);
result.finalize();
if (!file.good())
{
return;
}
std::stringstream data;
data << file.rdbuf();
if (data.str().empty())
{
return;
}
auto* doc = new tinyxml2::XMLDocument();
if (!doc)
{
return;
}
if (doc->Parse(data.str().c_str(), data.str().size()) != 0)
{
return;
}
std::vector<int> parts;
auto* lxfml = doc->FirstChildElement("LXFML");
auto* bricks = lxfml->FirstChildElement("Bricks");
std::string searchTerm = "Brick";
if (!bricks)
{
searchTerm = "Part";
bricks = lxfml->FirstChildElement("Scene")->FirstChildElement("Model")->FirstChildElement("Group");
if (!bricks)
{
return;
}
}
auto* currentBrick = bricks->FirstChildElement(searchTerm.c_str());
while (currentBrick)
{
if (currentBrick->Attribute("designID") != nullptr)
{
parts.push_back(std::stoi(currentBrick->Attribute("designID")));
}
currentBrick = currentBrick->NextSiblingElement(searchTerm.c_str());
}
auto* brickIDTable = CDClientManager::Instance()->GetTable<CDBrickIDTableTable>("BrickIDTable");
for (unsigned int part : parts)
{
const auto brickID = brickIDTable->Query([=](const CDBrickIDTable& entry)
{
return entry.LEGOBrickID == part;
});
if (brickID.empty())
{
continue;
}
GetInventory()->GetComponent()->AddItem(brickID[0].NDObjectID, 1);
}
}
void Item::RemoveFromInventory()
{
UnEquip();
count = 0;
inventory->RemoveManagedItem(this);
delete this;
}
Item::~Item()
{
delete preconditions;
for (auto* value : config)
{
delete value;
}
config.clear();
}

270
dGame/dInventory/Item.h Normal file
View File

@@ -0,0 +1,270 @@
#pragma once
#include "dCommonVars.h"
#include "Inventory.h"
#include "LDFFormat.h"
#include "CDClientManager.h"
#include "dLogger.h"
#include "Preconditions.h"
/**
* An item that can be stored in an inventory and optionally consumed or equipped
* TODO: ideally this should be a component
*/
class Item final
{
public:
/**
* Creates an item, should be used if the item is not picked up but already exists
* @param id the object ID of the item to create
* @param lot the LOT of the item
* @param inventory the inventory to add this item to
* @param slot the slot in the inventory to add this item to
* @param count the amount of items to add to the inventory
* @param bound if the item should be bound
* @param config config data for this item, e.g. for rockets
* @param parent optional parent of this item, e.g. for proxy items
* @param subKey optional subkey for this item, e.g. for pets
*/
explicit Item(
LWOOBJID id,
LOT lot,
Inventory* inventory,
uint32_t slot,
uint32_t count,
bool bound,
const std::vector<LDFBaseData*>& config,
LWOOBJID parent,
LWOOBJID subKey
);
/**
* Creates an item, should be used if the item is picked up / added to the inventory after load
* @param lot the LOT of the item
* @param inventory the inventory to add this item to
* @param slot the slot in the inventory to add this item to
* @param count the amount of items to add to the inventory
* @param config config data for this item, e.g. for rockets
* @param parent optional parent of this item, e.g. for proxy items
* @param showFlyingLoot show UI animation of the item being added
* @param isModMoveAndEquip equips the item
* @param subKey optional subkey for this item, e.g. for pets
* @param bound if the item should be bound
*/
explicit Item(
LOT lot,
Inventory* inventory,
uint32_t slot = 0,
uint32_t count = 1,
const std::vector<LDFBaseData*>& config = {},
LWOOBJID parent = LWOOBJID_EMPTY,
bool showFlyingLoot = true,
bool isModMoveAndEquip = false,
LWOOBJID subKey = LWOOBJID_EMPTY,
bool bound = false
);
~Item();
/**
* Returns the object ID of this item
* @return the object ID of this item
*/
LWOOBJID GetId() const;
/**
* Returns the lot of this item
* @return the lot of this item
*/
LOT GetLot() const;
/**
* Sets the number of items this item represents
* @param value the number to update by
* @param silent if true, the client will not be notified of the change with GMs
* @param disassemble if items were removed, this returns all the sub parts of the item individually if it had assembly part lots
* @param showFlyingLoot shows flying loot to the client, if not silent
*/
void SetCount(uint32_t value, bool silent = false, bool disassemble = true, bool showFlyingLoot = true);
/**
* Returns the number of items this item represents (e.g. for stacks)
* @return the number of items this item represents
*/
uint32_t GetCount() const;
/**
* Sets the slot this item is stored in
* @param value the slot this item is stored in
*/
void SetSlot(uint32_t value);
/**
* Returns the slot this item is in
* @return the slot this item is in
*/
uint32_t GetSlot() const;
/**
* Returns current config info for this item, e.g. for rockets
* @return current config info for this item
*/
std::vector<LDFBaseData*>& GetConfig();
/**
* Returns the database info for this item
* @return the database info for this item
*/
const CDItemComponent& GetInfo() const;
/**
* Sets if the item is bound
* @param value if the item is bound
*/
void SetBound(bool value);
/**
* Returns if the item is bound
* @return if the item is bound
*/
bool GetBound() const;
/**
* Sets the inventory this item belongs to
* @param value the inventory this item belongs to
*/
void SetInventory(Inventory* value);
/**
* Returns the inventory this item belongs to
* @return the inventory this item belongs to
*/
Inventory* GetInventory() const;
/**
* Returns the parent of this item, e.g. for proxy items
* @return the parent of this item
*/
LWOOBJID GetParent() const;
/**
* Sets the subkey for this item, e.g. for pets
* @param value the subkey for this item
*/
void SetSubKey(LWOOBJID value);
/**
* Returns the sub key this item has, e.g. for pets
* @return the sub key this item has
*/
LWOOBJID GetSubKey() const;
/**
* Returns the preconditions that must be met before this item may be used
* @return the preconditions that must be met before this item may be used
*/
PreconditionExpression* GetPreconditionExpression() const;
/**
* Equips this item into the linked inventory
* @param skipChecks skips equip checks for special items like rockets and cars
*/
void Equip(bool skipChecks = false);
/**
* Unequps the item from the linked inventory
*/
void UnEquip();
/**
* Returns if the item is equipped in the linked inventory
* @return if the item is equipped
*/
bool IsEquipped() const;
/**
* Attempts to consume one of this item, applying its skills
* @return whether the consumption was successful, e.g. the skill was cast
*/
bool Consume();
/**
* Uses this item if its non equip, essentially an interface for the linked GM
* @return whether the use was successful, e.g. the skill was cast
*/
bool UseNonEquip();
/**
* Disassembles the part LOTs of this item back into the inventory, if it has any
* @param inventoryType the inventory to dissassemble into
*/
void Disassemble(eInventoryType inventoryType = INVALID);
/**
* Disassembles this item into bricks
*/
void DisassembleModel();
/**
* Removes the item from the linked inventory
*/
void RemoveFromInventory();
private:
/**
* The object ID of this item
*/
LWOOBJID id;
/**
* The LOT of this item
*/
LOT lot;
/**
* The number of items this represents
*/
uint32_t count;
/**
* The slot this item is stored in
*/
uint32_t slot;
/**
* If this item is bound
*/
bool bound;
/**
* A potential parent of this item, if this item is a subitem
*/
LWOOBJID parent;
/**
* A potential subkey of this item, e.g. for pets
*/
LWOOBJID subKey;
/**
* Config data for this item, e.g. for rocket parts and car parts
*/
std::vector<LDFBaseData*> config;
/**
* The inventory this item belongs to
*/
Inventory* inventory;
/**
* The database information of this item
*/
const CDItemComponent* info;
/**
* A precondition to using this item
*/
PreconditionExpression* preconditions = nullptr;
};

View File

@@ -0,0 +1,235 @@
#include "ItemSet.h"
#include "InventoryComponent.h"
#include "Entity.h"
#include "SkillComponent.h"
#include "CDClientDatabase.h"
#include "Game.h"
#include "MissionComponent.h"
#include <algorithm>
ItemSet::ItemSet(const uint32_t id, InventoryComponent* inventoryComponent)
{
this->m_ID = id;
this->m_InventoryComponent = inventoryComponent;
this->m_PassiveAbilities = ItemSetPassiveAbility::FindAbilities(id, m_InventoryComponent->GetParent(), this);
std::stringstream query;
query << "SELECT skillSetWith2, skillSetWith3, skillSetWith4, skillSetWith5, skillSetWith6, itemIDs FROM ItemSets WHERE setID = " << std::to_string(id);
auto result = CDClientDatabase::ExecuteQuery(query.str());
if (result.eof())
{
return;
}
for (auto i = 0; i < 5; ++i)
{
if (result.fieldIsNull(i))
{
continue;
}
std::stringstream skillQuery;
skillQuery << "SELECT SkillID FROM ItemSetSkills WHERE SkillSetID = " << std::to_string(result.getIntField(i));
auto skillResult = CDClientDatabase::ExecuteQuery(skillQuery.str());
if (skillResult.eof())
{
return;
}
while (!skillResult.eof())
{
if (skillResult.fieldIsNull(0))
{
skillResult.nextRow();
continue;
}
const auto skillId = skillResult.getIntField(0);
switch (i)
{
case 0:
m_SkillsWith2.push_back(skillId);
break;
case 1:
m_SkillsWith3.push_back(skillId);
break;
case 2:
m_SkillsWith4.push_back(skillId);
break;
case 3:
m_SkillsWith5.push_back(skillId);
break;
case 4:
m_SkillsWith6.push_back(skillId);
break;
default:
break;
}
skillResult.nextRow();
}
}
std::string ids = result.getStringField(5);
ids.erase(std::remove_if(ids.begin(), ids.end(), ::isspace), ids.end());
std::istringstream stream(ids);
std::string token;
result.finalize();
m_Items = {};
while (std::getline(stream, token, ','))
{
int32_t value;
if (GeneralUtils::TryParse(token, value))
{
m_Items.push_back(value);
}
}
m_Equipped = {};
for (const auto item : m_Items)
{
if (inventoryComponent->IsEquipped(item))
{
m_Equipped.push_back(item);
}
}
}
bool ItemSet::Contains(const LOT lot)
{
return std::find(m_Items.begin(), m_Items.end(), lot) != m_Items.end();
}
void ItemSet::OnEquip(const LOT lot)
{
if (!Contains(lot))
{
return;
}
const auto& index = std::find(m_Equipped.begin(), m_Equipped.end(), lot);
if (index != m_Equipped.end())
{
return;
}
m_Equipped.push_back(lot);
const auto& skillSet = GetSkillSet(m_Equipped.size());
if (skillSet.empty())
{
return;
}
auto* skillComponent = m_InventoryComponent->GetParent()->GetComponent<SkillComponent>();
auto* missionComponent = m_InventoryComponent->GetParent()->GetComponent<MissionComponent>();
for (const auto skill : skillSet)
{
auto* skillTable = CDClientManager::Instance()->GetTable<CDSkillBehaviorTable>("SkillBehavior");
const auto behaviorId = skillTable->GetSkillByID(skill).behaviorID;
missionComponent->Progress(MissionTaskType::MISSION_TASK_TYPE_SKILL, skill);
skillComponent->HandleUnmanaged(behaviorId, m_InventoryComponent->GetParent()->GetObjectID());
}
}
void ItemSet::OnUnEquip(const LOT lot)
{
if (!Contains(lot))
{
return;
}
const auto& index = std::find(m_Equipped.begin(), m_Equipped.end(), lot);
if (index == m_Equipped.end())
{
return;
}
const auto& skillSet = GetSkillSet(m_Equipped.size());
m_Equipped.erase(index);
if (skillSet.empty())
{
return;
}
const auto& skillComponent = m_InventoryComponent->GetParent()->GetComponent<SkillComponent>();
for (const auto skill : skillSet)
{
auto* skillTable = CDClientManager::Instance()->GetTable<CDSkillBehaviorTable>("SkillBehavior");
const auto behaviorId = skillTable->GetSkillByID(skill).behaviorID;
skillComponent->HandleUnCast(behaviorId, m_InventoryComponent->GetParent()->GetObjectID());
}
}
uint32_t ItemSet::GetEquippedCount() const
{
return m_Equipped.size();
}
uint32_t ItemSet::GetID() const
{
return m_ID;
}
void ItemSet::Update(float deltaTime)
{
for (auto& passiveAbility : m_PassiveAbilities)
{
passiveAbility.Update(deltaTime);
}
}
void ItemSet::TriggerPassiveAbility(PassiveAbilityTrigger trigger)
{
for (auto& passiveAbility : m_PassiveAbilities)
{
passiveAbility.Trigger(trigger);
}
}
std::vector<uint32_t> ItemSet::GetSkillSet(const uint32_t itemCount) const
{
switch (itemCount)
{
case 2:
return m_SkillsWith2;
case 3:
return m_SkillsWith3;
case 4:
return m_SkillsWith4;
case 5:
return m_SkillsWith5;
case 6:
return m_SkillsWith6;
default:
return {};
}
}

114
dGame/dInventory/ItemSet.h Normal file
View File

@@ -0,0 +1,114 @@
#pragma once
#include <vector>
#include "dCommonVars.h"
#include "ItemSetPassiveAbility.h"
class InventoryComponent;
/**
* A set of items that can be worn together for special bonuses, for example faction gear.
*/
class ItemSet
{
public:
explicit ItemSet(uint32_t id, InventoryComponent* inventoryComponent);
void Update(float deltaTime);
/**
* Returns if this item set contains the LOT specified
* @param lot the lot to check for
* @return if this item set contains the LOT specified
*/
bool Contains(LOT lot);
/**
* Equips the item set skill for this LOT (if it's in the item set)
* @param lot the LOT of the item to equip skills for
*/
void OnEquip(LOT lot);
/**
* Unequips the item set skill for this LOT (if it's in the item set)
* @param lot the LOT of the item to unequip skills for
*/
void OnUnEquip(LOT lot);
/**
* Returns the number of items in the item set that are currently equipped
* @return the number of items in the item set that are currently equipped
*/
uint32_t GetEquippedCount() const;
/**
* Returns the ID of this item set
* @return the ID of this item set
*/
uint32_t GetID() const;
/**
* Triggers all the passive abilities in this item set that match this trigger
* @param trigger the trigger to use to trigger passive abilities
*/
void TriggerPassiveAbility(PassiveAbilityTrigger trigger);
/**
* Returns the skills that can be equipped for a specified amount of equipped items
* @param itemCount the amount of items equipped to check for
* @return the skills that can be equipped for a specified amount of equipped items
*/
std::vector<uint32_t> GetSkillSet(uint32_t itemCount) const;
private:
/**
* The ID of this skill set
*/
uint32_t m_ID;
/**
* The inventory this skill set belongs to
*/
InventoryComponent* m_InventoryComponent;
/**
* The items in the skill set that are currently equipped
*/
std::vector<LOT> m_Equipped;
/**
* The total list of items in this skill set
*/
std::vector<LOT> m_Items;
/**
* The skills that can be triggered when 2 items are equipped
*/
std::vector<uint32_t> m_SkillsWith2;
/**
* The skills that can be triggered when 3 items are equipped
*/
std::vector<uint32_t> m_SkillsWith3;
/**
* The skills that can be triggered when 4 items are equipped
*/
std::vector<uint32_t> m_SkillsWith4;
/**
* The skills that can be triggered when 5 items are equipped
*/
std::vector<uint32_t> m_SkillsWith5;
/**
* The skills that can be triggered when 6 items are equipped
*/
std::vector<uint32_t> m_SkillsWith6;
/**
* The passive abilities associated with this skill set
*/
std::vector<ItemSetPassiveAbility> m_PassiveAbilities;
};

View File

@@ -0,0 +1,327 @@
#include "ItemSetPassiveAbility.h"
#include "DestroyableComponent.h"
#include "SkillComponent.h"
#include "ItemSet.h"
#include "ItemSetPassiveAbilityID.h"
ItemSetPassiveAbility::ItemSetPassiveAbility(PassiveAbilityTrigger trigger, Entity* parent, ItemSet* itemSet)
{
m_Trigger = trigger;
m_Parent = parent;
m_ItemSet = itemSet;
m_Cooldown = 0.0f;
}
ItemSetPassiveAbility::~ItemSetPassiveAbility()
{
}
void ItemSetPassiveAbility::Trigger(PassiveAbilityTrigger trigger)
{
if (m_Trigger != trigger || m_Cooldown > 0.0f)
{
return;
}
Activate();
}
void ItemSetPassiveAbility::Update(float deltaTime)
{
if (m_Cooldown > 0.0f)
{
m_Cooldown -= deltaTime;
}
}
void ItemSetPassiveAbility::Activate()
{
if (m_Trigger == PassiveAbilityTrigger::EnemySmashed)
{
OnEnemySmshed();
return;
}
auto* destroyableComponent = m_Parent->GetComponent<DestroyableComponent>();
auto* skillComponent = m_Parent->GetComponent<SkillComponent>();
if (destroyableComponent == nullptr || skillComponent == nullptr)
{
return;
}
EntityManager::Instance()->SerializeEntity(m_Parent);
const auto id = static_cast<ItemSetPassiveAbilityID>(m_ItemSet->GetID());
const auto parentID = m_Parent->GetObjectID();
const auto equippedCount = m_ItemSet->GetEquippedCount();
switch (id)
{
// Assembly
case ItemSetPassiveAbilityID::InventorRank1:
case ItemSetPassiveAbilityID::SummonerRank1:
case ItemSetPassiveAbilityID::EngineerRank1: {
if (equippedCount < 4) return;
m_Cooldown = 11.0f;
skillComponent->CalculateBehavior(394, 4401, parentID);
break;
}
case ItemSetPassiveAbilityID::InventorRank2:
case ItemSetPassiveAbilityID::SummonerRank2:
case ItemSetPassiveAbilityID::EngineerRank2: {
if (equippedCount < 4) return;
m_Cooldown = 11.0f;
skillComponent->CalculateBehavior(581, 9433, parentID);
break;
}
case ItemSetPassiveAbilityID::InventorRank3:
case ItemSetPassiveAbilityID::SummonerRank3:
case ItemSetPassiveAbilityID::EngineerRank3: {
if (equippedCount < 4) return;
m_Cooldown = 11.0f;
skillComponent->CalculateBehavior(582, 9435, parentID);
break;
}
// Sentinel
case ItemSetPassiveAbilityID::KnightRank1: {
if (equippedCount < 4) return;
m_Cooldown = 11.0f;
skillComponent->CalculateBehavior(559, 8884, parentID);
break;
}
case ItemSetPassiveAbilityID::KnightRank2: {
if (equippedCount < 4) return;
m_Cooldown = 11.0f;
skillComponent->CalculateBehavior(560, 8885, parentID);
break;
}
case ItemSetPassiveAbilityID::KnightRank3: {
if (equippedCount < 4) return;
m_Cooldown = 11.0f;
skillComponent->CalculateBehavior(561, 8890, parentID);
break;
}
case ItemSetPassiveAbilityID::SpaceRangerRank1: {
if (equippedCount < 4) return;
m_Cooldown = 11.0f;
skillComponent->CalculateBehavior(1101, 24612, parentID);
break;
}
case ItemSetPassiveAbilityID::SpaceRangerRank2: {
if (equippedCount < 4) return;
m_Cooldown = 11.0f;
skillComponent->CalculateBehavior(1102, 24617, parentID);
break;
}
case ItemSetPassiveAbilityID::SpaceRangerRank3: {
if (equippedCount < 4) return;
m_Cooldown = 11.0f;
skillComponent->CalculateBehavior(1103, 24622, parentID);
break;
}
case ItemSetPassiveAbilityID::SamuraiRank1: {
if (equippedCount < 4) return;
m_Cooldown = 11.0f;
skillComponent->CalculateBehavior(562, 8899, parentID);
break;
}
case ItemSetPassiveAbilityID::SamuraiRank2: {
if (equippedCount < 4) return;
m_Cooldown = 11.0f;
skillComponent->CalculateBehavior(563, 8904, parentID);
break;
}
case ItemSetPassiveAbilityID::SamuraiRank3: {
if (equippedCount < 4) return;
m_Cooldown = 11.0f;
skillComponent->CalculateBehavior(564, 8909, parentID);
break;
}
default:
break;
}
}
std::vector<ItemSetPassiveAbility> ItemSetPassiveAbility::FindAbilities(uint32_t itemSetID, Entity* parent, ItemSet* itemSet)
{
std::vector<ItemSetPassiveAbility> abilities;
switch (static_cast<ItemSetPassiveAbilityID>(itemSetID)) {
// Assembly
case ItemSetPassiveAbilityID::SummonerRank1:
case ItemSetPassiveAbilityID::SummonerRank2:
case ItemSetPassiveAbilityID::SummonerRank3:
case ItemSetPassiveAbilityID::InventorRank1:
case ItemSetPassiveAbilityID::InventorRank2:
case ItemSetPassiveAbilityID::InventorRank3:
case ItemSetPassiveAbilityID::EngineerRank1:
case ItemSetPassiveAbilityID::EngineerRank2:
case ItemSetPassiveAbilityID::EngineerRank3: {
abilities.emplace_back(PassiveAbilityTrigger::AssemblyImagination, parent, itemSet);
break;
}
// Sentinel
case ItemSetPassiveAbilityID::KnightRank1:
case ItemSetPassiveAbilityID::KnightRank2:
case ItemSetPassiveAbilityID::KnightRank3:
case ItemSetPassiveAbilityID::SpaceRangerRank1:
case ItemSetPassiveAbilityID::SpaceRangerRank2:
case ItemSetPassiveAbilityID::SpaceRangerRank3:
case ItemSetPassiveAbilityID::SamuraiRank1:
case ItemSetPassiveAbilityID::SamuraiRank2:
case ItemSetPassiveAbilityID::SamuraiRank3: {
abilities.emplace_back(PassiveAbilityTrigger::SentinelArmor, parent, itemSet);
abilities.emplace_back(PassiveAbilityTrigger::EnemySmashed, parent, itemSet);
break;
}
// Paradox
case ItemSetPassiveAbilityID::SpaceMarauderRank1:
case ItemSetPassiveAbilityID::SpaceMarauderRank2:
case ItemSetPassiveAbilityID::SpaceMarauderRank3:
case ItemSetPassiveAbilityID::SorcererRank1:
case ItemSetPassiveAbilityID::SorcererRank2:
case ItemSetPassiveAbilityID::SorcererRank3:
case ItemSetPassiveAbilityID::ShinobiRank1:
case ItemSetPassiveAbilityID::ShinobiRank2:
case ItemSetPassiveAbilityID::ShinobiRank3: {
abilities.emplace_back(PassiveAbilityTrigger::EnemySmashed, parent, itemSet);
break;
}
default:
break;
}
return abilities;
}
void ItemSetPassiveAbility::OnEnemySmshed()
{
auto* destroyableComponent = m_Parent->GetComponent<DestroyableComponent>();
auto* skillComponent = m_Parent->GetComponent<SkillComponent>();
if (destroyableComponent == nullptr || skillComponent == nullptr)
{
return;
}
EntityManager::Instance()->SerializeEntity(m_Parent);
const auto id = static_cast<ItemSetPassiveAbilityID>(m_ItemSet->GetID());
const auto parentID = m_Parent->GetObjectID();
const auto equippedCount = m_ItemSet->GetEquippedCount();
switch (id)
{
// Sentinel
case ItemSetPassiveAbilityID::KnightRank1: {
if (equippedCount < 5) return;
destroyableComponent->Repair(1);
break;
}
case ItemSetPassiveAbilityID::KnightRank2: {
if (equippedCount < 5) return;
destroyableComponent->Repair(1);
break;
}
case ItemSetPassiveAbilityID::KnightRank3: {
if (equippedCount < 5) return;
destroyableComponent->Repair(1);
break;
}
case ItemSetPassiveAbilityID::SpaceRangerRank1: {
if (equippedCount < 5) return;
destroyableComponent->Repair(1);
break;
}
case ItemSetPassiveAbilityID::SpaceRangerRank2: {
if (equippedCount < 5) return;
destroyableComponent->Repair(1);
break;
}
case ItemSetPassiveAbilityID::SpaceRangerRank3: {
if (equippedCount < 5) return;
destroyableComponent->Repair(1);
break;
}
case ItemSetPassiveAbilityID::SamuraiRank1: {
if (equippedCount < 5) return;
destroyableComponent->Repair(1);
break;
}
case ItemSetPassiveAbilityID::SamuraiRank2: {
if (equippedCount < 5) return;
destroyableComponent->Repair(1);
break;
}
case ItemSetPassiveAbilityID::SamuraiRank3: {
if (equippedCount < 5) return;
destroyableComponent->Repair(1);
break;
}
// Paradox
case ItemSetPassiveAbilityID::SpaceMarauderRank1: {
if (equippedCount < 4) return;
destroyableComponent->Imagine(1);
break;
}
case ItemSetPassiveAbilityID::SpaceMarauderRank2: {
if (equippedCount < 4) return;
destroyableComponent->Imagine(2);
break;
}
case ItemSetPassiveAbilityID::SpaceMarauderRank3: {
if (equippedCount < 4) return;
destroyableComponent->Imagine(3);
break;
}
case ItemSetPassiveAbilityID::ShinobiRank1: {
if (equippedCount < 4) return;
destroyableComponent->Imagine(1);
break;
}
case ItemSetPassiveAbilityID::ShinobiRank2: {
if (equippedCount < 4) return;
destroyableComponent->Imagine(2);
break;
}
case ItemSetPassiveAbilityID::ShinobiRank3: {
if (equippedCount < 4) return;
destroyableComponent->Imagine(3);
break;
}
case ItemSetPassiveAbilityID::SorcererRank1: {
if (equippedCount < 4) return;
destroyableComponent->Imagine(1);
break;
}
case ItemSetPassiveAbilityID::SorcererRank2: {
if (equippedCount < 4) return;
destroyableComponent->Imagine(2);
break;
}
case ItemSetPassiveAbilityID::SorcererRank3: {
if (equippedCount < 4) return;
destroyableComponent->Imagine(3);
break;
}
default:
break;
}
}

View File

@@ -0,0 +1,71 @@
#pragma once
#include <vector>
#include "dCommonVars.h"
class Entity;
class ItemSet;
enum class PassiveAbilityTrigger
{
AssemblyImagination, // Less than 1 imagination
ParadoxHealth, // Less or equal to 1 health
SentinelArmor, // Less than 1 armor
VentureHealth, // Less than 3 health
EnemySmashed, // Enemy is smashed
};
/**
* Passive abilities that belong to an item set, activated when a PassiveAbilityTrigger condition is met
*/
class ItemSetPassiveAbility
{
public:
ItemSetPassiveAbility(PassiveAbilityTrigger trigger, Entity* parent, ItemSet* itemSet);
~ItemSetPassiveAbility();
void Update(float deltaTime);
/**
* Attempts to trigger a passive ability for this item set, if this is the wrong trigger this is a no-op
* @param trigger the trigger to attempt to fire
*/
void Trigger(PassiveAbilityTrigger trigger);
/**
* Activates the passive ability
*/
void Activate();
/**
* Finds all the passive abilities associated with a certain item set
* @param itemSetID the item set to find abilities for
* @param parent the parent to add to the passive abilities
* @param itemSet the item set to add to the passive abilities
* @return the passive abilities for the provided item set
*/
static std::vector<ItemSetPassiveAbility> FindAbilities(uint32_t itemSetID, Entity* parent, ItemSet* itemSet);
private:
void OnEnemySmshed();
/**
* The means of triggering this ability
*/
PassiveAbilityTrigger m_Trigger;
/**
* The owner of this ability
*/
Entity* m_Parent;
/**
* The item set this ability belongs to
*/
ItemSet* m_ItemSet;
/**
* The cooldown on this ability until it can be activated again
*/
float m_Cooldown;
};

View File

@@ -0,0 +1,105 @@
#pragma once
/**
2 Engineer (Rank 1) Item Set
3 Engineer (Rank 2) Item Set
4 Engineer (Rank 3) Item Set
7 Knight (Rank 1) Item Set
8 Knight (Rank 2) Item Set
9 Knight (Rank 3) Item Set
10 Space Ranger (Rank 1) Item Set
11 Space Ranger (Rank 2) Item Set
12 Space Ranger (Rank 3) Item Set
13 Samurai (Rank 1) Item Set
14 Samurai (Rank 2) Item Set
15 Samurai (Rank 3) Item Set
16 Sorcerer (Rank 1) Item Set
17 Sorcerer (Rank 2) Item Set
18 Sorcerer (Rank 3) Item Set
19 Space Marauder (Rank 1) Item Set
20 Space Marauder (Rank 2) Item Set
21 Space Marauder (Rank 3) Item Set
22 Shinobi (Rank 1) Item Set
23 Shinobi (Rank 2) Item Set
24 Shinobi (Rank 3) Item Set
25 Inventor (Rank 1) Item Set
26 Inventor (Rank 2) Item Set
27 Inventor (Rank 3) Item Set
28 Summoner (Rank 1) Item Set
29 Summoner (Rank 2) Item Set
30 Summoner (Rank 3) Item Set
31 Adventurer (Rank 1) Item Set
32 Adventurer (Rank 2) Item Set
33 Adventurer (Rank 3) Item Set
34 Daredevil (Rank 1) Item Set
35 Daredevil (Rank 2) Item Set
36 Daredevil (Rank 3) Item Set
37 Buccaneer (Rank 1) Item Set
38 Buccaneer (Rank 2) Item Set
39 Buccaneer (Rank 3) Item Set
40 Bone Suit Item Set
41 Imagination Spinjitzu Item Set
42 Bat Lord Item Set
43 Mosaic Jester Item Set
44 Explorien Bot Item Set
45 [Unnamed] Item Set
46 [Unnamed] Item Set
47 [Unnamed] Item Set
48 Earth Spinjitzu Item Set
49 [Unnamed] Item Set
50 Fire Spinjitzu Item Set
51 Ice Spinjitzu Item Set
52 Lightning Spinjitzu Item Set
*/
enum class ItemSetPassiveAbilityID
{
EngineerRank1 = 2,
EngineerRank2 = 3,
EngineerRank3 = 4,
KnightRank1 = 7,
KnightRank2 = 8,
KnightRank3 = 9,
SpaceRangerRank1 = 10,
SpaceRangerRank2 = 11,
SpaceRangerRank3 = 12,
SamuraiRank1 = 13,
SamuraiRank2 = 14,
SamuraiRank3 = 15,
SorcererRank1 = 16,
SorcererRank2 = 17,
SorcererRank3 = 18,
SpaceMarauderRank1 = 19,
SpaceMarauderRank2 = 20,
SpaceMarauderRank3 = 21,
ShinobiRank1 = 22,
ShinobiRank2 = 23,
ShinobiRank3 = 24,
InventorRank1 = 25,
InventorRank2 = 26,
InventorRank3 = 27,
SummonerRank1 = 28,
SummonerRank2 = 29,
SummonerRank3 = 30,
AdventurerRank1 = 31,
AdventurerRank2 = 32,
AdventurerRank3 = 33,
DaredevilRank1 = 34,
DaredevilRank2 = 35,
DaredevilRank3 = 36,
BuccaneerRank1 = 37,
BuccaneerRank2 = 38,
BuccaneerRank3 = 39,
BoneSuit = 40,
ImaginationSpinjitzu = 41,
BatLord = 42,
MosaicJester = 43,
ExplorienBot = 44,
Unnamed1 = 45,
Unnamed2 = 46,
Unnamed3 = 47,
EarthSpinjitzu = 48,
Unnamed4 = 49,
FireSpinjitzu = 50,
IceSpinjitzu = 51,
LightningSpinjitzu = 52
};