diff --git a/src/Items.cpp b/src/Items.cpp index 576c722..60ac3c8 100644 --- a/src/Items.cpp +++ b/src/Items.cpp @@ -18,7 +18,7 @@ std::map, Items::Item> Items::ItemData; std::map Items::CrocPotTable; std::map> Items::RarityWeights; std::map Items::Crates; -std::map Items::DroppableItems; +std::map Items::ItemReferences; std::map>> Items::CodeItems; std::map Items::CrateDropChances; @@ -118,11 +118,11 @@ static int getRarity(int crateId, int itemSetTypeId) { // remember that rarities start from 1! std::set rarityIndices; - for (int droppableItemId : Items::ItemSetTypes[itemSetTypeId].droppableItemIds) { - if (Items::DroppableItems.find(droppableItemId) == Items::DroppableItems.end()) + for (int itemReferenceId : Items::ItemSetTypes[itemSetTypeId].itemReferenceIds) { + if (Items::ItemReferences.find(itemReferenceId) == Items::ItemReferences.end()) continue; - rarityIndices.insert(Items::DroppableItems[droppableItemId].rarity - 1); + rarityIndices.insert(Items::ItemReferences[itemReferenceId].rarity - 1); // shortcut if (rarityIndices.size() == rarityWeights.size()) @@ -144,37 +144,29 @@ static int getRarity(int crateId, int itemSetTypeId) { static int getCrateItem(sItemBase* result, int itemSetTypeId, int itemSetChanceId, int rarity, int playerGender) { // (int, vector) - auto& [ignoreGender, droppableItemIds] = Items::ItemSetTypes[itemSetTypeId]; + auto& [ignoreGender, itemReferenceIds] = Items::ItemSetTypes[itemSetTypeId]; // collect valid items that match the rarity and (if not ignored) gender - std::vector> validItems; - for (int i = 0; i < droppableItemIds.size(); i++) { - int droppableItemId = droppableItemIds[i]; + std::vector> validItems; + for (int i = 0; i < itemReferenceIds.size(); i++) { + int itemReferenceId = itemReferenceIds[i]; - if (Items::DroppableItems.find(droppableItemId) == Items::DroppableItems.end()) { - std::cout << "[WARN] Droppable item " << droppableItemId << " was not found, skipping..." << std::endl; + if (Items::ItemReferences.find(itemReferenceId) == Items::ItemReferences.end()) { + std::cout << "[WARN] Item reference " << itemReferenceId << " in item set type " + << itemSetTypeId << " was not found, skipping..." << std::endl; continue; } - DroppableItem* droppableItem = &Items::DroppableItems[droppableItemId]; + ItemReference* item = &Items::ItemReferences[itemReferenceId]; - if (droppableItem->rarity != rarity) + if (item->rarity != rarity) continue; - auto key = std::make_pair(droppableItem->itemId, droppableItem->type); - - if (Items::ItemData.find(key) == Items::ItemData.end()) { - std::cout << "[WARN] Item-Type pair (" << key.first << ", " << key.second << ") specified by droppable item " - << droppableItemId << " was not found, skipping..." << std::endl; - continue; - } - // if gender is incorrect, exclude item - int itemGender = Items::ItemData[key].gender; - if (!ignoreGender && itemGender != 0 && itemGender != playerGender) + if (!ignoreGender && item->gender != 0 && item->gender != playerGender) continue; - validItems.push_back(std::make_pair(i, droppableItem)); + validItems.push_back(std::make_pair(i, item)); } if (validItems.empty()) { @@ -184,20 +176,19 @@ static int getCrateItem(sItemBase* result, int itemSetTypeId, int itemSetChanceI } // (int, map) - auto& [defaultWeight, specialWeights] = Items::ItemSetChances[itemSetChanceId]; + auto& [defaultWeight, indexWeightMap] = Items::ItemSetChances[itemSetChanceId]; // initialize all weights as the default weight for all item slots std::vector itemWeights(validItems.size(), defaultWeight); - if (!specialWeights.empty()) { + if (!indexWeightMap.empty()) { for (int i = 0; i < validItems.size(); i++) { - // (int, DroppableItem*) - auto& [dropIndex, droppableItem] = validItems[i]; + int dropIndex = validItems[i].first; - if (specialWeights.find(dropIndex) == specialWeights.end()) + if (indexWeightMap.find(dropIndex) == indexWeightMap.end()) continue; - int weight = specialWeights[dropIndex]; + int weight = indexWeightMap[dropIndex]; // allow 0 weights for convenience if (weight > -1) itemWeights[i] = weight; @@ -205,7 +196,7 @@ static int getCrateItem(sItemBase* result, int itemSetTypeId, int itemSetChanceI } int chosenIndex = Rand::randWeighted(itemWeights); - DroppableItem* item = validItems[chosenIndex].second; + ItemReference* item = validItems[chosenIndex].second; result->iID = item->itemId; result->iType = item->type; @@ -866,7 +857,7 @@ void Items::giveMobDrop(CNSocket *sock, Mob* mob, int rolledBoosts, int rolledPo sock->sendPacket((void*)respbuf, P_FE2CL_REP_REWARD_ITEM, sizeof(sP_FE2CL_REP_REWARD_ITEM)); } else { // item reward - getMobDrop(&item->sItem, crateDropChance.crateWeights, crateDropType, rolledCrateType); + getMobDrop(&item->sItem, crateDropChance.crateTypeDropWeights, crateDropType, rolledCrateType); item->iSlotNum = slot; item->eIL = 1; // Inventory Location. 1 means player inventory. diff --git a/src/Items.hpp b/src/Items.hpp index 60eb4f8..88c8686 100644 --- a/src/Items.hpp +++ b/src/Items.hpp @@ -17,7 +17,7 @@ struct Crate { struct CrateDropChance { int dropChance, dropChanceTotal; - std::vector crateWeights; + std::vector crateTypeDropWeights; }; struct MiscDropChance { @@ -43,18 +43,19 @@ struct MobDrop { struct ItemSetType { bool ignoreGender; - std::vector droppableItemIds; + std::vector itemReferenceIds; }; struct ItemSetChance { int defaultItemWeight; - std::map specialItemWeights; + std::map indexWeightMap; }; -struct DroppableItem { +struct ItemReference { int itemId; - int rarity; int type; + int rarity; + int gender; }; namespace Items { @@ -76,7 +77,7 @@ namespace Items { extern std::map CrocPotTable; // level gap -> entry extern std::map> RarityWeights; extern std::map Crates; - extern std::map DroppableItems; + extern std::map ItemReferences; extern std::map>> CodeItems; // code -> vector of // mob drops diff --git a/src/TableData.cpp b/src/TableData.cpp index ceab826..37a52ec 100644 --- a/src/TableData.cpp +++ b/src/TableData.cpp @@ -213,7 +213,7 @@ static void loadDrops() { nlohmann::json crateWeights = crateDropChance["CrateTypeDropWeights"]; for (nlohmann::json::iterator _crateWeight = crateWeights.begin(); _crateWeight != crateWeights.end(); _crateWeight++) - toAdd.crateWeights.push_back((int)_crateWeight.value()); + toAdd.crateTypeDropWeights.push_back((int)_crateWeight.value()); Items::CrateDropChances[(int)crateDropChance["CrateDropChanceID"]] = toAdd; } @@ -295,9 +295,9 @@ static void loadDrops() { toAdd.ignoreGender = (bool)itemSetType["IgnoreGender"]; - nlohmann::json droppableItemIds = itemSetType["DroppableItemIDs"]; - for (nlohmann::json::iterator _droppableItemId = droppableItemIds.begin(); _droppableItemId != droppableItemIds.end(); _droppableItemId++) - toAdd.droppableItemIds.push_back((int)_droppableItemId.value()); + nlohmann::json itemReferenceIds = itemSetType["ItemReferenceIDs"]; + for (nlohmann::json::iterator itemReferenceId = itemReferenceIds.begin(); itemReferenceId != itemReferenceIds.end(); itemReferenceId++) + toAdd.itemReferenceIds.push_back((int)itemReferenceId.value()); Items::ItemSetTypes[(int)itemSetType["ItemSetTypeID"]] = toAdd; } @@ -310,12 +310,9 @@ static void loadDrops() { toAdd.defaultItemWeight = (int)itemSetChanceObject["DefaultItemWeight"]; - nlohmann::json specialItemWeightIndices = itemSetChanceObject["SpecialItemWeightIndices"]; - nlohmann::json specialItemWeightVector = itemSetChanceObject["SpecialItemWeights"]; - for (nlohmann::json::iterator _specialItemWeightIndex = specialItemWeightIndices.begin(), _specialItemWeight = specialItemWeightVector.begin(); - _specialItemWeightIndex != specialItemWeightIndices.end() && _specialItemWeight != specialItemWeightVector.end(); - _specialItemWeightIndex++, _specialItemWeight++) - toAdd.specialItemWeights[(int)_specialItemWeightIndex.value()] = (int)_specialItemWeight.value(); + nlohmann::json indexWeightMap = itemSetChanceObject["IndexWeightMap"]; + for (nlohmann::json::iterator _indexWeightMapEntry = indexWeightMap.begin(); _indexWeightMapEntry != indexWeightMap.end(); _indexWeightMapEntry++) + toAdd.indexWeightMap[std::atoi(_indexWeightMapEntry.key().c_str())] = (int)_indexWeightMapEntry.value(); Items::ItemSetChances[(int)itemSetChanceObject["ItemSetChanceID"]] = toAdd; } @@ -332,15 +329,29 @@ static void loadDrops() { }; } - // DroppableItems - nlohmann::json droppableItems = dropData["DroppableItems"]; - for (nlohmann::json::iterator _droppableItem = droppableItems.begin(); _droppableItem != droppableItems.end(); _droppableItem++) { - auto droppableItem = _droppableItem.value(); + // ItemReferences + nlohmann::json itemReferences = dropData["ItemReferences"]; + for (nlohmann::json::iterator _itemReference = itemReferences.begin(); _itemReference != itemReferences.end(); _itemReference++) { + auto itemReference = _itemReference.value(); - Items::DroppableItems[(int)droppableItem["DroppableItemID"]] = { - (int)droppableItem["ItemID"], - (int)droppableItem["Rarity"], - (int)droppableItem["Type"] + int itemReferenceId = (int)itemReference["ItemReferenceID"]; + int itemId = (int)itemReference["ItemID"]; + int type = (int)itemReference["Type"]; + + // validate and fetch relevant fields as they're loaded + auto key = std::make_pair(itemId, type); + if (Items::ItemData.find(key) == Items::ItemData.end()) { + std::cout << "[WARN] Item-Type pair (" << key.first << ", " << key.second << ") specified by item reference " + << itemReferenceId << " was not found, skipping..." << std::endl; + continue; + } + Items::Item& item = Items::ItemData[key]; + + Items::ItemReferences[itemReferenceId] = { + itemId, + type, + item.rarity, + item.gender }; } @@ -405,15 +416,27 @@ static void loadDrops() { std::string codeStr = code["Code"]; std::vector> itemVector; - nlohmann::json items = code["Items"]; - for (nlohmann::json::iterator _item = items.begin(); _item != items.end(); _item++) - itemVector.push_back(std::make_pair((int)code["ItemID"], (int)code["Type"])); + nlohmann::json itemReferenceIds = code["ItemReferenceIDs"]; + for (nlohmann::json::iterator _itemReferenceId = itemReferenceIds.begin(); _itemReferenceId != itemReferenceIds.end(); _itemReferenceId++) { + int itemReferenceId = (int)_itemReferenceId.value(); + + // validate and convert here + if (Items::ItemReferences.find(itemReferenceId) == Items::ItemReferences.end()) { + std::cout << "[WARN] Item reference " << itemReferenceId << " for code " + << codeStr << " was not found, skipping..." << std::endl; + continue; + } + + // no need to further check whether this is a real item or not, we already did this! + ItemReference& itemReference = Items::ItemReferences[itemReferenceId]; + itemVector.push_back(std::make_pair(itemReference.itemId, itemReference.type)); + } Items::CodeItems[codeStr] = itemVector; } std::cout << "[INFO] Loaded " << Items::Crates.size() << " Crates containing " - << Items::DroppableItems.size() << " unique items" << std::endl; + << Items::ItemReferences.size() << " unique items" << std::endl; } catch (const std::exception& err) {