diff options
author | Ovahlord <dreadkiller@gmx.de> | 2024-08-22 16:28:26 +0200 |
---|---|---|
committer | Ovahlord <dreadkiller@gmx.de> | 2024-08-22 16:28:26 +0200 |
commit | 926fda01d8e115cae70f015539b269d7ae4860f2 (patch) | |
tree | efb5228f271db89921183e6a88c55aa0ff387448 | |
parent | d6375047854b5dd6639d6208619f12ad4c09d6cc (diff) |
Core/Quests: fixed max level quest money rewards and calculate them during runtime instead of using dumped DB values
* this fixes an exploit that was allowing players that have capped their level via npc to obtain higher max level money rewards if the quest info came from a sniff that was done with a max level character
-rw-r--r-- | src/server/game/Entities/Player/Player.cpp | 28 | ||||
-rw-r--r-- | src/server/game/Quests/QuestDef.cpp | 19 | ||||
-rw-r--r-- | src/server/game/Quests/QuestDef.h | 4 | ||||
-rw-r--r-- | src/server/game/Spells/SpellEffects.cpp | 2 |
4 files changed, 23 insertions, 30 deletions
diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp index e05004e1f98..d3905dcc807 100644 --- a/src/server/game/Entities/Player/Player.cpp +++ b/src/server/game/Entities/Player/Player.cpp @@ -14104,7 +14104,11 @@ void Player::IncompleteQuest(uint32 quest_id) uint32 Player::GetQuestMoneyReward(Quest const* quest) const { - return quest->GetMoneyReward(this) * sWorld->getRate(RATE_MONEY_QUEST); + uint32 moneyReward = quest->GetMoneyReward(this) * sWorld->getRate(RATE_MONEY_QUEST); + if (IsMaxLevel()) + moneyReward += quest->GetRewMoneyMaxLevel(this) * sWorld->getRate(RATE_MONEY_MAX_LEVEL_QUEST); + + return moneyReward; } uint32 Player::GetQuestXPReward(Quest const* quest) @@ -14328,14 +14332,10 @@ void Player::RewardQuest(Quest const* quest, LootItemType rewardType, uint32 rew uint32 XP = GetQuestXPReward(quest); - int32 moneyRew = 0; if (!IsMaxLevel()) GiveXP(XP, nullptr); - else - moneyRew = int32(quest->GetRewMoneyMaxLevel() * sWorld->getRate(RATE_DROP_MONEY)); - - moneyRew += GetQuestMoneyReward(quest); + int32 moneyRew = GetQuestMoneyReward(quest); if (moneyRew) { ModifyMoney(moneyRew); @@ -16216,23 +16216,11 @@ void Player::SendQuestReward(Quest const* quest, Creature const* questGiver, uin uint32 questId = quest->GetQuestId(); sGameEventMgr->HandleQuestComplete(questId); - uint32 moneyReward; - - if (!IsMaxLevel()) - { - moneyReward = GetQuestMoneyReward(quest); - } - else // At max level, increase gold reward - { - xp = 0; - moneyReward = uint32(GetQuestMoneyReward(quest) + int32(quest->GetRewMoneyMaxLevel() * sWorld->getRate(RATE_DROP_MONEY))); - } - WorldPackets::Quest::QuestGiverQuestComplete packet; packet.QuestID = questId; - packet.MoneyReward = moneyReward; - packet.XPReward = xp; + packet.MoneyReward = GetQuestMoneyReward(quest); + packet.XPReward = IsMaxLevel() ? 0 : xp; packet.SkillLineIDReward = quest->GetRewardSkillId(); packet.NumSkillUpsReward = quest->GetRewardSkillPoints(); diff --git a/src/server/game/Quests/QuestDef.cpp b/src/server/game/Quests/QuestDef.cpp index 9de14cfd28f..55db20cb361 100644 --- a/src/server/game/Quests/QuestDef.cpp +++ b/src/server/game/Quests/QuestDef.cpp @@ -410,16 +410,16 @@ void Quest::LoadConditionalConditionalQuestCompletionLog(Field* fields) uint32 Quest::XPValue(Player const* player) const { - return XPValue(player, GetQuestLevelForPlayer(player) , _level, _rewardXPDifficulty, _rewardXPMultiplier); + return XPValue(player ? player->GetLevel() : 0, GetQuestLevelForPlayer(player), _level, _rewardXPDifficulty, _rewardXPMultiplier); } -uint32 Quest::XPValue(Player const* player, uint32 questLevel, int32 unscaledQuestLevel, uint32 xpDifficulty, float xpMultiplier /*= 1.0f*/) +uint32 Quest::XPValue(uint8 playerLevel, uint32 questLevel, int32 unscaledQuestLevel, uint32 xpDifficulty, float xpMultiplier /*= 1.0f*/) { QuestXPEntry const* questXp = sQuestXPStore.LookupEntry(questLevel); if (!questXp || xpDifficulty >= 10) return 0; - int32 diffFactor = 2 * (questLevel - (unscaledQuestLevel == -1 ? 0 : -5) - (player ? player->GetLevel() : 0)) + 10; + int32 diffFactor = 2 * (questLevel - (unscaledQuestLevel == -1 ? 0 : -5) - playerLevel) + 10; if (diffFactor < 1) diffFactor = 1; else if (diffFactor > 10) @@ -541,14 +541,19 @@ void Quest::BuildQuestRewards(WorldPackets::Quest::QuestRewards& rewards, Player } } -uint32 Quest::GetRewMoneyMaxLevel() const +uint32 Quest::GetRewMoneyMaxLevel(Player const* player /*= nullptr*/) const { // If Quest has flag to not give money on max level, it's 0 if (HasFlag(QUEST_FLAGS_NO_MONEY_FOR_XP)) return 0; - // Else, return the rewarded copper sum modified by the rate - return uint32(_rewardBonusMoney * sWorld->getRate(RATE_MONEY_MAX_LEVEL_QUEST)); + uint32 maxQuestLevel = _level == -1 ? _maxScalingLevel : _level; + + // Query initialization during startup does not provide a valid player so we just go for the expansion's max level + uint8 playerLevel = player ? player->GetLevel() : GetMaxLevelForExpansion(CURRENT_EXPANSION); + + // The conversion rate is XP * 6 copper + return XPValue(playerLevel, maxQuestLevel, _level, _rewardXPDifficulty, _rewardXPMultiplier) * 6; } bool Quest::IsAutoAccept() const @@ -677,7 +682,7 @@ WorldPacket Quest::BuildQueryData(LocaleConstant loc, Player* player) const response.Info.RewardMoneyDifficulty = GetRewMoneyDifficulty(); response.Info.RewardMoneyMultiplier = GetMoneyMultiplier(); - response.Info.RewardBonusMoney = GetRewMoneyMaxLevel(); + response.Info.RewardBonusMoney = GetRewMoneyMaxLevel(player); for (uint8 i = 0; i < QUEST_REWARD_DISPLAY_SPELL_COUNT; ++i) response.Info.RewardDisplaySpell[i] = RewardDisplaySpell[i].SpellId; diff --git a/src/server/game/Quests/QuestDef.h b/src/server/game/Quests/QuestDef.h index edcde0fd66f..3b800a679bc 100644 --- a/src/server/game/Quests/QuestDef.h +++ b/src/server/game/Quests/QuestDef.h @@ -532,7 +532,7 @@ class TC_GAME_API Quest void LoadConditionalConditionalQuestCompletionLog(Field* fields); uint32 XPValue(Player const* player) const; - static uint32 XPValue(Player const* player, uint32 questLevel, int32 unscaledQuestLevel, uint32 xpDifficulty, float xpMultiplier = 1.0f); + static uint32 XPValue(uint8 playerLevel, uint32 questLevel, int32 unscaledQuestLevel, uint32 xpDifficulty, float xpMultiplier = 1.0f); uint32 GetMoneyReward(Player const* player) const; Optional<QuestTagType> GetQuestTag() const; bool IsImportant() const; @@ -610,7 +610,7 @@ class TC_GAME_API Quest uint32 GetArtifactXPDifficulty() const { return _rewardArtifactXPDifficulty; } float GetArtifactXPMultiplier() const { return _rewardArtifactXPMultiplier; } uint32 GetArtifactCategoryId() const { return _rewardArtifactCategoryID; } - uint32 GetRewMoneyMaxLevel() const; // use in XP calculation at client + uint32 GetRewMoneyMaxLevel(Player const* player = nullptr) const; uint32 GetRewSpell() const { return _rewardSpell; } uint32 GetRewMailTemplateId() const { return _rewardMailTemplateId; } uint32 GetRewMailDelaySecs() const { return _rewardMailDelay; } diff --git a/src/server/game/Spells/SpellEffects.cpp b/src/server/game/Spells/SpellEffects.cpp index b1623f71790..2502a2a66d3 100644 --- a/src/server/game/Spells/SpellEffects.cpp +++ b/src/server/game/Spells/SpellEffects.cpp @@ -5418,7 +5418,7 @@ void Spell::EffectGiveExperience() if (!playerTarget) return; - uint32 xp = Quest::XPValue(playerTarget, 0, 0, effectInfo->MiscValueB); + uint32 xp = Quest::XPValue(playerTarget->GetLevel(), 0, 0, effectInfo->MiscValueB); playerTarget->GiveXP(xp, nullptr); } |