From 6ecaebb19e50970fde379cd2989aaa0b05d3776e Mon Sep 17 00:00:00 2001 From: Ovahlord Date: Tue, 17 Jan 2023 22:05:16 +0100 Subject: [PATCH] Core/GameObject: implement gaining experience from unlocking chests * this handles gathering experience as well as getting some extra xp from opening hidden treasure chests --- .../game/Entities/GameObject/GameObject.cpp | 2 +- .../game/Entities/GameObject/GameObject.h | 6 +-- src/server/game/Quests/QuestDef.cpp | 47 ++++++++++--------- src/server/game/Quests/QuestDef.h | 6 +-- src/server/game/Spells/SpellEffects.cpp | 26 +++++++--- 5 files changed, 52 insertions(+), 35 deletions(-) diff --git a/src/server/game/Entities/GameObject/GameObject.cpp b/src/server/game/Entities/GameObject/GameObject.cpp index 81eb9635ad..efeb8b11af 100644 --- a/src/server/game/Entities/GameObject/GameObject.cpp +++ b/src/server/game/Entities/GameObject/GameObject.cpp @@ -895,7 +895,7 @@ void GameObject::Update(uint32 diff) } m_respawnTime = 0; - m_SkillupList.clear(); + _tappingPlayers.clear(); m_usetimes = 0; switch (GetGoType()) diff --git a/src/server/game/Entities/GameObject/GameObject.h b/src/server/game/Entities/GameObject/GameObject.h index ae798df574..9200b5b0dd 100644 --- a/src/server/game/Entities/GameObject/GameObject.h +++ b/src/server/game/Entities/GameObject/GameObject.h @@ -221,8 +221,8 @@ class TC_GAME_API GameObject : public WorldObject, public GridObject void SetLootGenerationTime(); uint32 GetLootGenerationTime() const { return m_lootGenerationTime; } - void AddToSkillupList(ObjectGuid::LowType playerLowGUID) { m_SkillupList.push_back(playerLowGUID); } - bool IsInSkillupList(ObjectGuid::LowType playerLowGUID) const { return std::find(m_SkillupList.begin(), m_SkillupList.end(), playerLowGUID) != m_SkillupList.end(); } + bool IsTappedByPlayer(ObjectGuid playerGuid) const { return std::find(_tappingPlayers.begin(), _tappingPlayers.end(), playerGuid) != _tappingPlayers.end(); } + void AddPlayerToTapperList(ObjectGuid playerGuid) { _tappingPlayers.emplace_back(playerGuid); } void AddUniqueUse(Player* player); void AddUse() { ++m_usetimes; } @@ -345,7 +345,7 @@ class TC_GAME_API GameObject : public WorldObject, public GridObject // For traps this: spell casting cooldown, for doors/buttons: reset time. GOState m_prevGoState; // What state to set whenever resetting - std::list m_SkillupList; + std::vector _tappingPlayers; ObjectGuid m_ritualOwnerGUID; // used for GAMEOBJECT_TYPE_SUMMONING_RITUAL where GO is not summoned (no owner) GuidSet m_unique_users; diff --git a/src/server/game/Quests/QuestDef.cpp b/src/server/game/Quests/QuestDef.cpp index 27ca27f55e..091c98f381 100644 --- a/src/server/game/Quests/QuestDef.cpp +++ b/src/server/game/Quests/QuestDef.cpp @@ -242,30 +242,33 @@ void Quest::LoadQuestMailSender(Field* fields) uint32 Quest::GetXPReward(Player const* player) const { - if (player) + if (!player) + return 0; + + return Quest::CalcXPReward(player->getLevel(), _level, _rewardXPDifficulty); +} + +/*static*/ uint32 Quest::CalcXPReward(uint8 playerLevel, int32 targetLevel, uint8 xpDifficulty) +{ + int32 effectiveLevel = (targetLevel == -1 ? playerLevel : targetLevel); + const QuestXPEntry* xpentry = sQuestXPStore.LookupEntry(effectiveLevel); + if (!xpentry) + return 0; + + int32 diffFactor = 2 * (effectiveLevel - playerLevel) + 20; + if (diffFactor < 1) + diffFactor = 1; + else if (diffFactor > 10) + diffFactor = 10; + + uint32 xp = RoundXPValue(diffFactor * xpentry->Difficulty[xpDifficulty] / 10); + if (sWorld->getIntConfig(CONFIG_MIN_QUEST_SCALED_XP_RATIO)) { - int32 quest_level = (_level == -1 ? player->getLevel() : _level); - const QuestXPEntry* xpentry = sQuestXPStore.LookupEntry(quest_level); - if (!xpentry) - return 0; - - int32 diffFactor = 2 * (quest_level - player->getLevel()) + 20; - if (diffFactor < 1) - diffFactor = 1; - else if (diffFactor > 10) - diffFactor = 10; - - uint32 xp = RoundXPValue(diffFactor * xpentry->Difficulty[_rewardXPDifficulty] / 10); - if (sWorld->getIntConfig(CONFIG_MIN_QUEST_SCALED_XP_RATIO)) - { - uint32 minScaledXP = RoundXPValue(xpentry->Difficulty[_rewardXPDifficulty]) * sWorld->getIntConfig(CONFIG_MIN_QUEST_SCALED_XP_RATIO) / 100; - xp = std::max(minScaledXP, xp); - } - - return xp; + uint32 minScaledXP = RoundXPValue(xpentry->Difficulty[xpDifficulty]) * sWorld->getIntConfig(CONFIG_MIN_QUEST_SCALED_XP_RATIO) / 100; + xp = std::max(minScaledXP, xp); } - return 0; + return xp; } /*static*/ bool Quest::IsTakingQuestEnabled(uint32 questId) @@ -409,7 +412,7 @@ bool Quest::CanIncreaseRewardedQuestCounters() const return (!IsDFQuest() && !IsDaily() && (!IsRepeatable() || IsWeekly() || IsMonthly() || IsSeasonal())); } -uint32 Quest::RoundXPValue(uint32 xp) +/*static*/ uint32 Quest::RoundXPValue(uint32 xp) { if (xp <= 100) return 5 * ((xp + 2) / 5); diff --git a/src/server/game/Quests/QuestDef.h b/src/server/game/Quests/QuestDef.h index 7ea1022fa5..fae62cf22e 100644 --- a/src/server/game/Quests/QuestDef.h +++ b/src/server/game/Quests/QuestDef.h @@ -237,6 +237,7 @@ class TC_GAME_API Quest void LoadQuestMailSender(Field* fields); uint32 GetXPReward(Player const* player) const; + static uint32 CalcXPReward(uint8 playerLevel, int32 targetLevel, uint8 xpDifficulty); bool HasFlag(uint32 flag) const { return (_flags & flag) != 0; } void SetFlag(uint32 flag) { _flags |= flag; } @@ -372,6 +373,8 @@ class TC_GAME_API Quest void BuildQuestRewards(WorldPackets::Quest::QuestRewards& rewards, Player* player) const; + static uint32 RoundXPValue(uint32 xp); + static void AddQuestLevelToTitle(std::string& title, int32 level); void InitializeQueryData(); WorldPacket BuildQueryData(LocaleConstant loc) const; @@ -468,9 +471,6 @@ class TC_GAME_API Quest uint32 _specialFlags = 0; // custom flags, not sniffed/WDB uint32 _allowableRaces = 0; uint32 _timeAllowed = 0; - - // Helpers - static uint32 RoundXPValue(uint32 xp); }; struct QuestStatusData diff --git a/src/server/game/Spells/SpellEffects.cpp b/src/server/game/Spells/SpellEffects.cpp index 93066b0f78..ea70347178 100644 --- a/src/server/game/Spells/SpellEffects.cpp +++ b/src/server/game/Spells/SpellEffects.cpp @@ -53,6 +53,7 @@ #include "Pet.h" #include "PhasingHandler.h" #include "Player.h" +#include "QuestDef.h" #include "ReputationMgr.h" #include "ScriptMgr.h" #include "SharedDefines.h" @@ -1655,10 +1656,10 @@ void Spell::EffectOpenLock(SpellEffIndex effIndex) ObjectGuid guid; // Get lockId + GameObjectTemplate const* goInfo; if (gameObjTarget) { - GameObjectTemplate const* goInfo = gameObjTarget->GetGOInfo(); - + goInfo = gameObjTarget->GetGOInfo(); if (goInfo->CannotBeUsedUnderImmunity() && m_caster->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IMMUNE)) return; @@ -1711,7 +1712,7 @@ void Spell::EffectOpenLock(SpellEffIndex effIndex) SkillType skillId = SKILL_NONE; int32 reqSkillValue = 0; - int32 skillValue; + int32 skillValue = 0; SpellCastResult res = CanOpenLock(effIndex, lockId, skillId, reqSkillValue, skillValue); if (res != SPELL_CAST_OK) @@ -1741,9 +1742,22 @@ void Spell::EffectOpenLock(SpellEffIndex effIndex) { if (gameObjTarget) { - // Allow one skill-up until respawned - if (!gameObjTarget->IsInSkillupList(player->GetGUID().GetCounter()) && player->UpdateGatherSkill(skillId, pureSkillValue, reqSkillValue)) - gameObjTarget->AddToSkillupList(player->GetGUID().GetCounter()); + // Only allow unique uses for gathering and experience rewards + if (!gameObjTarget->IsTappedByPlayer(player->GetGUID())) + { + gameObjTarget->AddPlayerToTapperList(player->GetGUID()); + player->UpdateGatherSkill(skillId, pureSkillValue, reqSkillValue); + + if (goInfo->type == GAMEOBJECT_TYPE_CHEST) + { + // Chests, such as gathering nodes and treasure chests calculate their XP rewards just like quests + if (uint8 xpDifficulty = goInfo->chest.xpDifficulty) + { + int32 xpLevel = goInfo->chest.xpMinLevel; + player->GiveXP(Quest::CalcXPReward(player->getLevel(), xpLevel, xpDifficulty), nullptr); + } + } + } } else if (itemTarget) {