diff --git a/src/server/apps/worldserver/worldserver.conf.dist b/src/server/apps/worldserver/worldserver.conf.dist index ac3935a12..8f751fad4 100644 --- a/src/server/apps/worldserver/worldserver.conf.dist +++ b/src/server/apps/worldserver/worldserver.conf.dist @@ -2267,7 +2267,20 @@ Rate.Drop.Item.Artifact = 1 Rate.Drop.Item.Referenced = 1 Rate.Drop.Money = 1 -# RewardBonusMoney +# Rate.Drop.Item.ReferencedAmount +# Description: Multiplier for referenced loot amount. Makes many raid bosses (and others) drop additional loot. +# Default: 1 + +Rate.Drop.Item.ReferencedAmount = 1 + +# +# Rate.Drop.Item.GroupAmount +# Description: Multiplier for grouped items. Makes many dungeon bosses (and others) drop additional loot. +# Default: 1 + +Rate.Drop.Item.GroupAmount = 1 + +# Rate.RewardBonusMoney # Description: Allows to further tweak the amount of extra money rewarded by quests when the player # is at MaxPlayerLevel (this amount is specified in quest_template.RewardBonusMoney). # NOTE: the final amount will also affected by Rate.Drop.Money @@ -2331,13 +2344,6 @@ Rate.BuyValue.Item.Legendary = 1 Rate.BuyValue.Item.Artifact = 1 Rate.BuyValue.Item.Heirloom = 1 -# -# Rate.Drop.Item.ReferencedAmount -# Description: Multiplier for referenced loot amount. -# Default: 1 - -Rate.Drop.Item.ReferencedAmount = 1 - # # Rate.XP.Kill # Rate.XP.Quest diff --git a/src/server/game/Loot/LootMgr.cpp b/src/server/game/Loot/LootMgr.cpp index 7d64fed6e..94d328dfe 100644 --- a/src/server/game/Loot/LootMgr.cpp +++ b/src/server/game/Loot/LootMgr.cpp @@ -100,7 +100,7 @@ public: bool HasQuestDrop(LootTemplateMap const& store) const; // True if group includes at least 1 quest drop entry bool HasQuestDropForPlayer(Player const* player, LootTemplateMap const& store) const; // The same for active quests of the player - void Process(Loot& loot, Player const* player, LootStore const& lootstore, uint16 lootMode) const; // Rolls an item from the group (if any) and adds the item to the loot + void Process(Loot& loot, Player const* player, LootStore const& lootstore, uint16 lootMode, uint16 nonRefIterationsLeft) const; // Rolls an item from the group (if any) and adds the item to the loot float RawTotalChance() const; // Overall chance for the group (without equal chanced items) float TotalChance() const; // Overall chance for the group @@ -570,7 +570,8 @@ bool Loot::FillLoot(uint32 lootId, LootStore const& store, Player* lootOwner, bo items.reserve(MAX_NR_LOOT_ITEMS); quest_items.reserve(MAX_NR_QUEST_ITEMS); - tab->Process(*this, store, lootMode, lootOwner); // Processing is done there, callback via Loot::AddItem() + // Initial group is 0, top level set to True + tab->Process(*this, store, lootMode, lootOwner, 0, true); // Processing is done there, callback via Loot::AddItem() sScriptMgr->OnAfterLootTemplateProcess(this, tab, store, lootOwner, personal, noEmptyError, lootMode); @@ -1413,7 +1414,7 @@ void LootTemplate::LootGroup::CopyConditions(ConditionList /*conditions*/) } // Rolls an item from the group (if any takes its chance) and adds the item to the loot -void LootTemplate::LootGroup::Process(Loot& loot, Player const* player, LootStore const& store, uint16 lootMode) const +void LootTemplate::LootGroup::Process(Loot& loot, Player const* player, LootStore const& store, uint16 lootMode, uint16 nonRefIterationsLeft) const { if (LootStoreItem const* item = Roll(loot, player, store, lootMode)) { @@ -1426,7 +1427,9 @@ void LootTemplate::LootGroup::Process(Loot& loot, Player const* player, LootStor uint32 maxcount = uint32(float(item->maxcount) * sWorld->getRate(RATE_DROP_ITEM_REFERENCED_AMOUNT)); sScriptMgr->OnAfterRefCount(player, loot, rate, lootMode, const_cast(item), maxcount, store); for (uint32 loop = 0; loop < maxcount; ++loop) // Ref multiplicator - Referenced->Process(loot, store, lootMode, player, item->groupid); + // This reference needs to be processed further, but it is marked isTopLevel=false so that any groups inside + // the reference are not multiplied by Rate.Drop.Item.GroupAmount + Referenced->Process(loot, store, lootMode, player, item->groupid, false); } } else @@ -1434,6 +1437,14 @@ void LootTemplate::LootGroup::Process(Loot& loot, Player const* player, LootStor // Plain entries (not a reference, not grouped) sScriptMgr->OnBeforeDropAddItem(player, loot, rate, lootMode, const_cast(item), store); loot.AddItem(*item); // Chance is already checked, just add + + // If we still have non-ref runs to do for this group AND this item wasn't a reference, + // recursively call this function to produce more items for this group. + // However, if this is a quest item we shouldn't multiply this group. + if (nonRefIterationsLeft > 1 && !item->needs_quest) + { + this->Process(loot, player, store, lootMode, nonRefIterationsLeft-1); + } } } } @@ -1665,7 +1676,7 @@ bool LootTemplate::CopyConditions(LootItem* li, uint32 conditionLootId) const } // Rolls for every item in the template and adds the rolled items the the loot -void LootTemplate::Process(Loot& loot, LootStore const& store, uint16 lootMode, Player const* player, uint8 groupId) const +void LootTemplate::Process(Loot& loot, LootStore const& store, uint16 lootMode, Player const* player, uint8 groupId, bool isTopLevel) const { bool rate = store.IsRatesAllowed(); @@ -1677,7 +1688,15 @@ void LootTemplate::Process(Loot& loot, LootStore const& store, uint16 lootMode, if (!Groups[groupId - 1]) return; - Groups[groupId - 1]->Process(loot, player, store, lootMode); + // Rate.Drop.Item.GroupAmount is only in effect for the top loot template level + if (isTopLevel) + { + Groups[groupId - 1]->Process(loot, player, store, lootMode, sWorld->getRate(RATE_DROP_ITEM_GROUP_AMOUNT)); + } + else + { + Groups[groupId - 1]->Process(loot, player, store, lootMode, 0); + } return; } @@ -1687,7 +1706,6 @@ void LootTemplate::Process(Loot& loot, LootStore const& store, uint16 lootMode, LootStoreItem* item = *i; if (!(item->lootmode & lootMode)) // Do not add if mode mismatch continue; - if (!item->Roll(rate, player, loot, store)) continue; // Bad luck for the entry @@ -1700,7 +1718,8 @@ void LootTemplate::Process(Loot& loot, LootStore const& store, uint16 lootMode, uint32 maxcount = uint32(float(item->maxcount) * sWorld->getRate(RATE_DROP_ITEM_REFERENCED_AMOUNT)); sScriptMgr->OnAfterRefCount(player, loot, rate, lootMode, item, maxcount, store); for (uint32 loop = 0; loop < maxcount; ++loop) // Ref multiplicator - Referenced->Process(loot, store, lootMode, player, item->groupid); + // we're no longer in the top level, so isTopLevel is false + Referenced->Process(loot, store, lootMode, player, item->groupid, false); } else { @@ -1713,7 +1732,17 @@ void LootTemplate::Process(Loot& loot, LootStore const& store, uint16 lootMode, // Now processing groups for (LootGroups::const_iterator i = Groups.begin(); i != Groups.end(); ++i) if (LootGroup* group = *i) - group->Process(loot, player, store, lootMode); + { + // Rate.Drop.Item.GroupAmount is only in effect for the top loot template level + if (isTopLevel) + { + group->Process(loot, player, store, lootMode, sWorld->getRate(RATE_DROP_ITEM_GROUP_AMOUNT)); + } + else + { + group->Process(loot, player, store, lootMode, 0); + } + } } // True if template includes at least 1 quest drop entry diff --git a/src/server/game/Loot/LootMgr.h b/src/server/game/Loot/LootMgr.h index b21cfcdbd..ee785e256 100644 --- a/src/server/game/Loot/LootMgr.h +++ b/src/server/game/Loot/LootMgr.h @@ -253,7 +253,7 @@ public: // Adds an entry to the group (at loading stage) void AddEntry(LootStoreItem* item); // Rolls for every item in the template and adds the rolled items the the loot - void Process(Loot& loot, LootStore const& store, uint16 lootMode, Player const* player, uint8 groupId = 0) const; + void Process(Loot& loot, LootStore const& store, uint16 lootMode, Player const* player, uint8 groupId = 0, bool isTopLevel = true) const; void CopyConditions(ConditionList conditions); bool CopyConditions(LootItem* li, uint32 conditionLootId = 0) const; diff --git a/src/server/game/World/IWorld.h b/src/server/game/World/IWorld.h index c5fff797b..689c62301 100644 --- a/src/server/game/World/IWorld.h +++ b/src/server/game/World/IWorld.h @@ -436,8 +436,8 @@ enum Rates RATE_DROP_ITEM_LEGENDARY, RATE_DROP_ITEM_ARTIFACT, RATE_DROP_ITEM_REFERENCED, - RATE_DROP_ITEM_REFERENCED_AMOUNT, + RATE_DROP_ITEM_GROUP_AMOUNT, RATE_SELLVALUE_ITEM_POOR, RATE_SELLVALUE_ITEM_NORMAL, RATE_SELLVALUE_ITEM_UNCOMMON, diff --git a/src/server/game/World/World.cpp b/src/server/game/World/World.cpp index b53515b1e..72a3bc19d 100644 --- a/src/server/game/World/World.cpp +++ b/src/server/game/World/World.cpp @@ -492,7 +492,9 @@ void World::LoadConfigSettings(bool reload) _rate_values[RATE_DROP_ITEM_ARTIFACT] = sConfigMgr->GetOption("Rate.Drop.Item.Artifact", 1.0f); _rate_values[RATE_DROP_ITEM_REFERENCED] = sConfigMgr->GetOption("Rate.Drop.Item.Referenced", 1.0f); _rate_values[RATE_DROP_ITEM_REFERENCED_AMOUNT] = sConfigMgr->GetOption("Rate.Drop.Item.ReferencedAmount", 1.0f); + _rate_values[RATE_DROP_ITEM_GROUP_AMOUNT] = sConfigMgr->GetOption("Rate.Drop.Item.GroupAmount", 1.0f); _rate_values[RATE_DROP_MONEY] = sConfigMgr->GetOption("Rate.Drop.Money", 1.0f); + _rate_values[RATE_REWARD_BONUS_MONEY] = sConfigMgr->GetOption("Rate.RewardBonusMoney", 1.0f); _rate_values[RATE_XP_KILL] = sConfigMgr->GetOption("Rate.XP.Kill", 1.0f); _rate_values[RATE_XP_BG_KILL_AV] = sConfigMgr->GetOption("Rate.XP.BattlegroundKillAV", 1.0f);