diff options
-rw-r--r-- | src/game/LootMgr.cpp | 85 |
1 files changed, 59 insertions, 26 deletions
diff --git a/src/game/LootMgr.cpp b/src/game/LootMgr.cpp index f791a86e103..b85afa18d66 100644 --- a/src/game/LootMgr.cpp +++ b/src/game/LootMgr.cpp @@ -813,13 +813,13 @@ void LootTemplate::LootGroup::AddEntry(LootStoreItem& item) // Rolls an item from the group, returns NULL if all miss their chances LootStoreItem const * LootTemplate::LootGroup::Roll() const { - if (!ExplicitlyChanced.empty()) // First explicitly chanced entries are checked + if (!ExplicitlyChanced.empty()) // First explicitly chanced entries are checked { float Roll = rand_chance(); - for (uint32 i=0; i<ExplicitlyChanced.size(); ++i) //check each explicitly chanced entry in the template and modify its chance based on quality. + for (uint32 i = 0; i < ExplicitlyChanced.size(); ++i) // check each explicitly chanced entry in the template and modify its chance based on quality. { - if(ExplicitlyChanced[i].chance>=100.0f) + if (ExplicitlyChanced[i].chance >= 100.0f) return &ExplicitlyChanced[i]; Roll -= ExplicitlyChanced[i].chance; @@ -861,49 +861,82 @@ bool LootTemplate::LootGroup::HasQuestDropForPlayer(Player const * player) const void LootTemplate::LootGroup::Process(Loot& loot, uint16 lootMode) const { // build up list of possible drops - std::list<uint32> *possibleDrops = new std::list<uint32>(); - for (LootStoreItemList::const_iterator itr = EqualChanced.begin(); itr != EqualChanced.end(); ++itr) - possibleDrops->push_back(itr->itemid); // add all of the equal chanced items to possibleDrops + LootStoreItemList EqualPossibleDrops = EqualChanced; + LootStoreItemList ExplicitPossibleDrops = ExplicitlyChanced; - for (LootStoreItemList::const_iterator itr = ExplicitlyChanced.begin(); itr != ExplicitlyChanced.end(); ++itr) - possibleDrops->push_back(itr->itemid); // add all of the explicitly chanced items to possibleDrops + uint8 uiAttemptCount = 0; + const uint8 uiMaxAttempts = ExplicitlyChanced.size() + EqualChanced.size(); - possibleDrops->unique(); // remove duplicates + while (!ExplicitPossibleDrops.empty() || !EqualPossibleDrops.empty()) + { + if (uiAttemptCount == uiMaxAttempts) // already tried rolling too many times, just abort + return; - uint8 uiFailSafeLoopBreaker = 0; + LootStoreItem *item = NULL; - while (!possibleDrops->empty()) // continue rolling while possibleDrops contains data - { - ++uiFailSafeLoopBreaker; - if (uiFailSafeLoopBreaker == 255) + // begin rolling (normally called via Roll()) + LootStoreItemList::iterator itr; + uint8 itemSource = 0; + if (!ExplicitPossibleDrops.empty()) // First explicitly chanced entries are checked { - sLog.outError("Tried to roll for loot from the same loot group too many times, aborting to avoid a crash."); - return; + itemSource = 1; + float Roll = rand_chance(); + // check each explicitly chanced entry in the template and modify its chance based on quality + for (itr = ExplicitPossibleDrops.begin(); itr != ExplicitPossibleDrops.end(); ++itr) + { + if (itr->chance >= 100.0f) + { + item = &*itr; + break; + } + + Roll -= itr->chance; + if (Roll < 0) + { + item = &*itr; + break; + } + // this item failed it's roll, so don't roll for it again + ExplicitPossibleDrops.erase(itr); + } } + if (item == NULL && !EqualPossibleDrops.empty()) // If nothing selected yet - an item is taken from equal-chanced part + { + itemSource = 2; + itr = EqualPossibleDrops.begin(); + std::advance(itr, irand(0, EqualPossibleDrops.size()-1)); + item = &*itr; + } + // finish rolling - LootStoreItem const *item = Roll(); + ++uiAttemptCount; - if (item != NULL && item->lootmode & lootMode) // only add this item if roll succeeds and the mode matches + if (item != NULL && item->lootmode & lootMode) // only add this item if roll succeeds and the mode matches { - if (std::find(possibleDrops->begin(), possibleDrops->end(), item->itemid) == possibleDrops->end()) - continue; // if item->itemid can't be found in possibleDrops, roll again - bool duplicate = false; if (ItemPrototype const *_proto = sItemStorage.LookupEntry<ItemPrototype>(item->itemid)) { uint8 _item_counter = 0; for (LootItemList::const_iterator _item = loot.items.begin(); _item != loot.items.end(); ++_item) - if (_item->itemid == item->itemid) // search through the items that have already dropped + if (_item->itemid == item->itemid) // search through the items that have already dropped { ++_item_counter; - if (_proto->InventoryType == 0 && _item_counter == 3) // Non-equippable items are limited to 3 drops + if (_proto->InventoryType == 0 && _item_counter == 3) // Non-equippable items are limited to 3 drops duplicate = true; - else if(_proto->InventoryType != 0 && _item_counter == 1) // Equippable item are limited to 1 drop + else if (_proto->InventoryType != 0 && _item_counter == 1) // Equippable item are limited to 1 drop duplicate = true; } } - if (duplicate) // if item->itemid is a duplicate, remove it from possibleDrops - possibleDrops->remove(item->itemid); + if (duplicate) // if item->itemid is a duplicate, remove it + switch (itemSource) + { + case 1: // item came from ExplicitPossibleDrops + ExplicitPossibleDrops.erase(itr); + break; + case 2: // item came from EqualPossibleDrops + EqualPossibleDrops.erase(itr); + break; + } else // otherwise, add the item and exit the function { loot.AddItem(*item); |