diff --git a/src/Items.cpp b/src/Items.cpp index 60ac3c8..67f4180 100644 --- a/src/Items.cpp +++ b/src/Items.cpp @@ -26,8 +26,7 @@ std::map> Items::CrateDropTypes; std::map Items::MiscDropChances; std::map Items::MiscDropTypes; std::map Items::MobDrops; -std::map Items::ItemSetTypes; -std::map Items::ItemSetChances; +std::map Items::ItemSets; #ifdef ACADEMY std::map Items::NanoCapsules; // crate id -> nano id @@ -99,7 +98,7 @@ static int choice(const std::vector& weights, int rolled) { return currentIndex; } -static int getRarity(int crateId, int itemSetTypeId) { +static int getRarity(int crateId, int itemSetId) { Crate& crate = Items::Crates[crateId]; // find rarity ratio @@ -118,7 +117,7 @@ static int getRarity(int crateId, int itemSetTypeId) { // remember that rarities start from 1! std::set rarityIndices; - for (int itemReferenceId : Items::ItemSetTypes[itemSetTypeId].itemReferenceIds) { + for (int itemReferenceId : Items::ItemSets[itemSetId].itemReferenceIds) { if (Items::ItemReferences.find(itemReferenceId) == Items::ItemReferences.end()) continue; @@ -130,7 +129,7 @@ static int getRarity(int crateId, int itemSetTypeId) { } if (rarityIndices.empty()) { - std::cout << "[WARN] Item Set " << crate.itemSetTypeId << " has no valid items assigned?!" << std::endl; + std::cout << "[WARN] Item Set " << crate.itemSetId << " has no valid items assigned?!" << std::endl; return -1; } @@ -142,53 +141,64 @@ static int getRarity(int crateId, int itemSetTypeId) { return Rand::randWeighted(relevantWeights) + 1; } -static int getCrateItem(sItemBase* result, int itemSetTypeId, int itemSetChanceId, int rarity, int playerGender) { - // (int, vector) - auto& [ignoreGender, itemReferenceIds] = Items::ItemSetTypes[itemSetTypeId]; +static int getCrateItem(sItemBase* result, int itemSetId, int rarity, int playerGender) { + ItemSet& itemSet = Items::ItemSets[itemSetId]; - // collect valid items that match the rarity and (if not ignored) gender + // collect valid items that match the rarity and gender (if not ignored) std::vector> validItems; - for (int i = 0; i < itemReferenceIds.size(); i++) { - int itemReferenceId = itemReferenceIds[i]; + for (int itemReferenceId : itemSet.itemReferenceIds) { 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; + << itemSetId << " was not found, skipping..." << std::endl; continue; } ItemReference* item = &Items::ItemReferences[itemReferenceId]; - if (item->rarity != rarity) + // alter rarity + int itemRarity; + if (itemSet.alterRarityMap.find(itemReferenceId) == itemSet.alterRarityMap.end()) + itemRarity = item->rarity; + else + itemRarity = itemSet.alterRarityMap[itemReferenceId]; + + // if rarity doesn't match the selected one, exclude item + // rarity 0 bypasses this step for an individual item + if (!itemSet.ignoreRarity && itemRarity != 0 && itemRarity != rarity) continue; + // alter rarity + int itemGender; + if (itemSet.alterGenderMap.find(itemReferenceId) == itemSet.alterGenderMap.end()) + itemGender = item->gender; + else + itemGender = itemSet.alterGenderMap[itemReferenceId]; + // if gender is incorrect, exclude item - if (!ignoreGender && item->gender != 0 && item->gender != playerGender) + // gender 0 bypasses this step for an individual item + if (!itemSet.ignoreGender && itemGender != 0 && itemGender != playerGender) continue; - validItems.push_back(std::make_pair(i, item)); + validItems.push_back(std::make_pair(itemReferenceId, item)); } if (validItems.empty()) { - std::cout << "[WARN] Set ID " << itemSetTypeId << " Chance ID " << itemSetChanceId - << " Rarity " << rarity << " contains no valid items" << std::endl; + std::cout << "[WARN] Set ID " << itemSetId << " Rarity " << rarity << " contains no valid items" << std::endl; return -1; } - // (int, map) - auto& [defaultWeight, indexWeightMap] = Items::ItemSetChances[itemSetChanceId]; + // initialize all weights as the default weight for all item slots + std::vector itemWeights(validItems.size(), itemSet.defaultItemWeight); - // initialize all weights as the default weight for all item slots - std::vector itemWeights(validItems.size(), defaultWeight); - - if (!indexWeightMap.empty()) { + if (!itemSet.alterItemWeightMap.empty()) { for (int i = 0; i < validItems.size(); i++) { - int dropIndex = validItems[i].first; + int itemReferenceId = validItems[i].first; - if (indexWeightMap.find(dropIndex) == indexWeightMap.end()) + if (itemSet.alterItemWeightMap.find(itemReferenceId) == itemSet.alterItemWeightMap.end()) continue; - int weight = indexWeightMap[dropIndex]; + int weight = itemSet.alterItemWeightMap[itemReferenceId]; // allow 0 weights for convenience if (weight > -1) itemWeights[i] = weight; @@ -215,30 +225,17 @@ static int getValidCrateId(int crateId) { return crateId; } -static int getValidItemSetTypeId(int crateId) { +static int getValidItemSetId(int crateId) { Crate& crate = Items::Crates[crateId]; // find item set type - if (Items::ItemSetTypes.find(crate.itemSetTypeId) == Items::ItemSetTypes.end()) { + if (Items::ItemSets.find(crate.itemSetId) == Items::ItemSets.end()) { std::cout << "[WARN] Crate " << crateId << " was assigned item set " - << crate.itemSetTypeId << " which is invalid!" << std::endl; + << crate.itemSetId << " which is invalid!" << std::endl; return -1; } - return crate.itemSetTypeId; -} - -static int getValidItemSetChanceId(int crateId) { - Crate& crate = Items::Crates[crateId]; - - // find item set chances - if (Items::ItemSetChances.find(crate.itemSetChanceId) == Items::ItemSetChances.end()) { - std::cout << "[WARN] Crate " << crateId << " was assigned item set chance object " - << crate.itemSetChanceId << " which is invalid!" << std::endl; - return -1; - } - - return crate.itemSetChanceId; + return crate.itemSetId; } static void itemMoveHandler(CNSocket* sock, CNPacketData* data) { @@ -560,25 +557,21 @@ static void chestOpenHandler(CNSocket *sock, CNPacketData *data) { item->iSlotNum = pkt->iSlotNum; item->eIL = 1; - int validItemSetTypeId = -1, validItemSetChanceId = -1, rarity = -1, ret = -1; + int validItemSetId = -1, rarity = -1, ret = -1; int validCrateId = getValidCrateId(chest->iID); bool failing = (validCrateId == -1); if (!failing) - validItemSetTypeId = getValidItemSetTypeId(validCrateId); - failing = (validItemSetTypeId == -1); + validItemSetId = getValidItemSetId(validCrateId); + failing = (validItemSetId == -1); if (!failing) - validItemSetChanceId = getValidItemSetChanceId(validCrateId); - failing = (validItemSetChanceId == -1); - - if (!failing) - rarity = getRarity(validCrateId, validItemSetTypeId); + rarity = getRarity(validCrateId, validItemSetId); failing = (rarity == -1); if (!failing) - ret = getCrateItem(&item->sItem, validItemSetTypeId, validItemSetChanceId, rarity, plr->PCStyle.iGender); + ret = getCrateItem(&item->sItem, validItemSetId, rarity, plr->PCStyle.iGender); failing = (ret == -1); // if we failed to open a crate, at least give the player a gumball (suggested by Jade) diff --git a/src/Items.hpp b/src/Items.hpp index 88c8686..36e01b7 100644 --- a/src/Items.hpp +++ b/src/Items.hpp @@ -10,8 +10,7 @@ struct CrocPotEntry { }; struct Crate { - int itemSetChanceId; - int itemSetTypeId; + int itemSetId; int rarityWeightId; }; @@ -41,14 +40,23 @@ struct MobDrop { int miscDropTypeId; }; -struct ItemSetType { +struct ItemSet { + // itemset-wise offswitch to rarity filtering, every crate drops every rarity (still based on rarity weights) + bool ignoreRarity; + // itemset-wise offswitch for gender filtering, every crate can now drop neutral/boys/girls items bool ignoreGender; - std::vector itemReferenceIds; -}; - -struct ItemSetChance { + // default weight of all items in the itemset int defaultItemWeight; - std::map indexWeightMap; + // change the rarity class of items in the itemset here + // rarity 0 bypasses the rarity filter for an individual item + std::map alterRarityMap; + // change the gender class of items in the itemset here + // gender 0 bypasses the gender filter for an individual item + std::map alterGenderMap; + // change the item weghts items in the itemset here + // only taken into account for chosen rarity, and if the item isn't filtered away due to gender + std::map alterItemWeightMap; + std::vector itemReferenceIds; }; struct ItemReference { @@ -86,8 +94,7 @@ namespace Items { extern std::map MiscDropChances; extern std::map MiscDropTypes; extern std::map MobDrops; - extern std::map ItemSetTypes; - extern std::map ItemSetChances; + extern std::map ItemSets; void init(); diff --git a/src/TableData.cpp b/src/TableData.cpp index 37a52ec..b0efadd 100644 --- a/src/TableData.cpp +++ b/src/TableData.cpp @@ -287,34 +287,33 @@ static void loadDrops() { Items::RarityWeights[(int)rarityWeightsObject["RarityWeightID"]] = toAdd; } - // ItemSetTypes - nlohmann::json itemSetTypes = dropData["ItemSetTypes"]; - for (nlohmann::json::iterator _itemSetType = itemSetTypes.begin(); _itemSetType != itemSetTypes.end(); _itemSetType++) { - auto itemSetType = _itemSetType.value(); - ItemSetType toAdd = {}; + // ItemSets + nlohmann::json itemSets = dropData["ItemSets"]; + for (nlohmann::json::iterator _itemSet = itemSets.begin(); _itemSet != itemSets.end(); _itemSet++) { + auto itemSet = _itemSet.value(); + ItemSet toAdd = {}; - toAdd.ignoreGender = (bool)itemSetType["IgnoreGender"]; + toAdd.ignoreRarity = (bool)itemSet["IgnoreRarity"]; + toAdd.ignoreGender = (bool)itemSet["IgnoreGender"]; + toAdd.defaultItemWeight = (int)itemSet["DefaultItemWeight"]; - nlohmann::json itemReferenceIds = itemSetType["ItemReferenceIDs"]; + nlohmann::json alterRarityMap = itemSet["AlterRarityMap"]; + for (nlohmann::json::iterator _alterRarityMapEntry = alterRarityMap.begin(); _alterRarityMapEntry != alterRarityMap.end(); _alterRarityMapEntry++) + toAdd.alterRarityMap[std::atoi(_alterRarityMapEntry.key().c_str())] = (int)_alterRarityMapEntry.value(); + + nlohmann::json alterGenderMap = itemSet["AlterGenderMap"]; + for (nlohmann::json::iterator _alterGenderMapEntry = alterGenderMap.begin(); _alterGenderMapEntry != alterGenderMap.end(); _alterGenderMapEntry++) + toAdd.alterGenderMap[std::atoi(_alterGenderMapEntry.key().c_str())] = (int)_alterGenderMapEntry.value(); + + nlohmann::json alterItemWeightMap = itemSet["AlterItemWeightMap"]; + for (nlohmann::json::iterator _alterItemWeightMapEntry = alterItemWeightMap.begin(); _alterItemWeightMapEntry != alterItemWeightMap.end(); _alterItemWeightMapEntry++) + toAdd.alterItemWeightMap[std::atoi(_alterItemWeightMapEntry.key().c_str())] = (int)_alterItemWeightMapEntry.value(); + + nlohmann::json itemReferenceIds = itemSet["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; - } - - // ItemSetChances - nlohmann::json itemSetChances = dropData["ItemSetChances"]; - for (nlohmann::json::iterator _itemSetChanceObject = itemSetChances.begin(); _itemSetChanceObject != itemSetChances.end(); _itemSetChanceObject++) { - auto itemSetChanceObject = _itemSetChanceObject.value(); - ItemSetChance toAdd = {}; - - toAdd.defaultItemWeight = (int)itemSetChanceObject["DefaultItemWeight"]; - - 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; + Items::ItemSets[(int)itemSet["ItemSetID"]] = toAdd; } // Crates @@ -323,8 +322,7 @@ static void loadDrops() { auto crate = _crate.value(); Items::Crates[(int)crate["CrateID"]] = { - (int)crate["ItemSetChanceID"], - (int)crate["ItemSetTypeID"], + (int)crate["ItemSetID"], (int)crate["RarityWeightID"] }; }