diff options
| author | Shauren <shauren.trinity@gmail.com> | 2016-05-02 18:52:15 +0200 |
|---|---|---|
| committer | Shauren <shauren.trinity@gmail.com> | 2016-05-02 18:52:15 +0200 |
| commit | 110ae3e6261694cd5a9ad1687ee209ef42a55c3e (patch) | |
| tree | 77310f66c1d1d703ae9b8723d8aa0b6e2ce3dfe0 /src/server/game/Spells | |
| parent | e8730061530cba48703508297dedc8aeb49681b1 (diff) | |
Core/Spells: Implemented RPPM proc effects
Closes #17001
Diffstat (limited to 'src/server/game/Spells')
| -rw-r--r-- | src/server/game/Spells/Auras/SpellAuras.cpp | 20 | ||||
| -rw-r--r-- | src/server/game/Spells/Auras/SpellAuras.h | 12 | ||||
| -rw-r--r-- | src/server/game/Spells/SpellInfo.cpp | 129 | ||||
| -rw-r--r-- | src/server/game/Spells/SpellInfo.h | 6 |
4 files changed, 161 insertions, 6 deletions
diff --git a/src/server/game/Spells/Auras/SpellAuras.cpp b/src/server/game/Spells/Auras/SpellAuras.cpp index 5e5b17f4993..521abd26e7b 100644 --- a/src/server/game/Spells/Auras/SpellAuras.cpp +++ b/src/server/game/Spells/Auras/SpellAuras.cpp @@ -368,7 +368,8 @@ m_spellInfo(spellproto), m_casterGuid(!casterGUID.IsEmpty() ? casterGUID : caste m_castItemGuid(castItem ? castItem->GetGUID() : ObjectGuid::Empty), m_castItemLevel(castItemLevel), m_applyTime(time(NULL)), m_owner(owner), m_timeCla(0), m_updateTargetMapInterval(0), m_casterLevel(caster ? caster->getLevel() : m_spellInfo->SpellLevel), m_procCharges(0), m_stackAmount(1), -m_isRemoved(false), m_isSingleTarget(false), m_isUsingCharges(false), m_dropEvent(nullptr) +m_isRemoved(false), m_isSingleTarget(false), m_isUsingCharges(false), m_dropEvent(nullptr), +m_lastProcAttemptTime(std::chrono::steady_clock::now() - Seconds(10)), m_lastProcSuccessTime(std::chrono::steady_clock::now() - Seconds(120)) { std::vector<SpellPowerEntry const*> powers = sDB2Manager.GetSpellPowers(GetId(), caster ? caster->GetMap()->GetDifficultyID() : DIFFICULTY_NONE); for (SpellPowerEntry const* power : powers) @@ -1933,6 +1934,23 @@ void Aura::TriggerProcOnEvent(AuraApplication* aurApp, ProcEventInfo& eventInfo) Remove(); } +float Aura::CalcPPMProcChance(Unit* actor) const +{ + using FSeconds = std::chrono::duration<float, Seconds::period>; + + // Formula see http://us.battle.net/wow/en/forum/topic/8197741003#1 + float ppm = m_spellInfo->CalcProcPPM(actor, m_castItemLevel); + float averageProcInterval = 60.0f / ppm; + + std::chrono::steady_clock::time_point currentTime = std::chrono::steady_clock::now(); + float secondsSinceLastAttempt = std::min(std::chrono::duration_cast<FSeconds>(currentTime - m_lastProcAttemptTime).count(), 10.0f); + float secondsSinceLastProc = std::min(std::chrono::duration_cast<FSeconds>(currentTime - m_lastProcSuccessTime).count(), 1000.0f); + + float chance = std::max(1.0f, 1.0f + ((secondsSinceLastProc / averageProcInterval - 1.5f) * 3.0f)) * ppm * secondsSinceLastAttempt / 60.0f; + RoundToInterval(chance, 0.0f, 1.0f); + return chance * 100.0f; +} + void Aura::_DeleteRemovedApplications() { while (!m_removedApplications.empty()) diff --git a/src/server/game/Spells/Auras/SpellAuras.h b/src/server/game/Spells/Auras/SpellAuras.h index 65cdbced339..27e2333bd97 100644 --- a/src/server/game/Spells/Auras/SpellAuras.h +++ b/src/server/game/Spells/Auras/SpellAuras.h @@ -253,6 +253,9 @@ class TC_GAME_API Aura bool IsProcTriggeredOnEvent(AuraApplication* aurApp, ProcEventInfo& eventInfo) const; float CalcProcChance(SpellProcEntry const& procEntry, ProcEventInfo& eventInfo) const; void TriggerProcOnEvent(AuraApplication* aurApp, ProcEventInfo& eventInfo); + float CalcPPMProcChance(Unit* actor) const; + void SetLastProcAttemptTime(std::chrono::steady_clock::time_point lastProcAttemptTime) { m_lastProcAttemptTime = lastProcAttemptTime; } + void SetLastProcSuccessTime(std::chrono::steady_clock::time_point lastProcSuccessTime) { m_lastProcSuccessTime = lastProcSuccessTime; } // AuraScript void LoadScripts(); @@ -313,12 +316,15 @@ class TC_GAME_API Aura //AuraEffect* m_effects[3]; ApplicationMap m_applications; - bool m_isRemoved:1; - bool m_isSingleTarget:1; // true if it's a single target spell and registered at caster - can change at spell steal for example - bool m_isUsingCharges:1; + bool m_isRemoved; + bool m_isSingleTarget; // true if it's a single target spell and registered at caster - can change at spell steal for example + bool m_isUsingCharges; ChargeDropEvent* m_dropEvent; + std::chrono::steady_clock::time_point m_lastProcAttemptTime; + std::chrono::steady_clock::time_point m_lastProcSuccessTime; + private: Unit::AuraApplicationList m_removedApplications; diff --git a/src/server/game/Spells/SpellInfo.cpp b/src/server/game/Spells/SpellInfo.cpp index bc16ad62075..a91c94b63c8 100644 --- a/src/server/game/Spells/SpellInfo.cpp +++ b/src/server/game/Spells/SpellInfo.cpp @@ -995,7 +995,6 @@ SpellInfo::SpellInfo(SpellEntry const* spellEntry, SpellEffectEntryMap const& ef } SpellName = spellEntry->Name_lang; - Rank = nullptr; RuneCostID = spellEntry->RuneCostID; SpellDifficultyId = 0; SpellScalingId = spellEntry->ScalingID; @@ -1054,9 +1053,14 @@ SpellInfo::SpellInfo(SpellEntry const* spellEntry, SpellEffectEntryMap const& ef // SpellAuraOptionsEntry SpellAuraOptionsEntry const* _options = GetSpellAuraOptions(); + SpellProcsPerMinuteEntry const* _ppm = _options ? sSpellProcsPerMinuteStore.LookupEntry(_options->SpellProcsPerMinuteID) : nullptr; ProcFlags = _options ? _options->ProcTypeMask : 0; ProcChance = _options ? _options->ProcChance : 0; ProcCharges = _options ? _options->ProcCharges : 0; + ProcCooldown = _options ? _options->ProcCategoryRecovery : 0; + ProcBasePPM = _ppm ? _ppm->BaseProcRate : 0.0f; + if (_options) + ProcPPMMods = sDB2Manager.GetSpellProcsPerMinuteMods(_options->SpellProcsPerMinuteID); StackAmount = _options ? _options->CumulativeAura : 0; // SpellAuraRestrictionsEntry @@ -2748,6 +2752,126 @@ std::vector<SpellInfo::CostData> SpellInfo::CalcPowerCost(Unit const* caster, Sp return costs; } +inline float CalcPPMHasteMod(SpellProcsPerMinuteModEntry const* mod, Unit* caster) +{ + float haste = caster->GetFloatValue(UNIT_FIELD_MOD_HASTE); + float rangedHaste = caster->GetFloatValue(UNIT_FIELD_MOD_RANGED_HASTE); + float spellHaste = caster->GetFloatValue(UNIT_MOD_CAST_HASTE); + float regenHaste = caster->GetFloatValue(UNIT_FIELD_MOD_HASTE_REGEN); + + switch (mod->Param) + { + case 1: + return (1.0f / haste - 1.0f) * mod->Coeff; + case 2: + return (1.0f / rangedHaste - 1.0f) * mod->Coeff; + case 3: + return (1.0f / spellHaste - 1.0f) * mod->Coeff; + case 4: + return (1.0f / regenHaste - 1.0f) * mod->Coeff; + case 5: + return (1.0f / std::min(std::min(std::min(haste, rangedHaste), spellHaste), regenHaste) - 1.0f) * mod->Coeff; + default: + break; + } + + return 0.0f; +} + +inline float CalcPPMCritMod(SpellProcsPerMinuteModEntry const* mod, Unit* caster) +{ + if (caster->GetTypeId() != TYPEID_PLAYER) + return 0.0f; + + float crit = caster->GetFloatValue(PLAYER_CRIT_PERCENTAGE); + float rangedCrit = caster->GetFloatValue(PLAYER_RANGED_CRIT_PERCENTAGE); + float spellCrit = caster->GetFloatValue(PLAYER_SPELL_CRIT_PERCENTAGE1); + + switch (mod->Param) + { + case 1: + return crit * mod->Coeff * 0.01f; + case 2: + return rangedCrit * mod->Coeff * 0.01f; + case 3: + return spellCrit * mod->Coeff * 0.01f; + case 4: + return std::min(std::min(crit, rangedCrit), spellCrit) * mod->Coeff * 0.01f; + default: + break; + } + + return 0.0f; +} + +inline float CalcPPMItemLevelMod(SpellProcsPerMinuteModEntry const* mod, int32 itemLevel) +{ + if (uint32(itemLevel) == mod->Param) + return 0.0f; + + float itemLevelPoints = GetRandomPropertyPoints(itemLevel, ITEM_QUALITY_RARE, INVTYPE_CHEST, 0); + float basePoints = GetRandomPropertyPoints(mod->Param, ITEM_QUALITY_RARE, INVTYPE_CHEST, 0); + if (itemLevelPoints != basePoints) + return 0.0f; + + return ((itemLevelPoints / basePoints) - 1.0f) * mod->Coeff; +} + +float SpellInfo::CalcProcPPM(Unit* caster, int32 itemLevel) const +{ + float ppm = ProcBasePPM; + for (SpellProcsPerMinuteModEntry const* mod : ProcPPMMods) + { + switch (mod->Type) + { + case SPELL_PPM_MOD_HASTE: + { + ppm *= 1.0f + CalcPPMHasteMod(mod, caster); + break; + } + case SPELL_PPM_MOD_CRIT: + { + ppm *= 1.0f + CalcPPMCritMod(mod, caster); + break; + } + case SPELL_PPM_MOD_CLASS: + { + if (caster->getClassMask() & mod->Param) + ppm *= 1.0f + mod->Coeff; + break; + } + case SPELL_PPM_MOD_SPEC: + { + if (Player* plrCaster = caster->ToPlayer()) + if (plrCaster->GetSpecId(plrCaster->GetActiveTalentGroup()) == mod->Param) + ppm *= 1.0f + mod->Coeff; + break; + } + case SPELL_PPM_MOD_RACE: + { + if (caster->getRaceMask() & mod->Param) + ppm *= 1.0f + mod->Coeff; + break; + } + case SPELL_PPM_MOD_ITEM_LEVEL: + { + ppm *= 1.0f + CalcPPMItemLevelMod(mod, itemLevel); + break; + } + case SPELL_PPM_MOD_BATTLEGROUND: + { + if (caster->GetMap()->IsBattlegroundOrArena()) + ppm *= 1.0f + mod->Coeff; + break; + } + default: + break; + } + } + + return ppm; +} + bool SpellInfo::IsRanked() const { return ChainEntry != NULL; @@ -2766,18 +2890,21 @@ SpellInfo const* SpellInfo::GetFirstRankSpell() const return this; return ChainEntry->first; } + SpellInfo const* SpellInfo::GetLastRankSpell() const { if (!ChainEntry) return NULL; return ChainEntry->last; } + SpellInfo const* SpellInfo::GetNextRankSpell() const { if (!ChainEntry) return NULL; return ChainEntry->next; } + SpellInfo const* SpellInfo::GetPrevRankSpell() const { if (!ChainEntry) diff --git a/src/server/game/Spells/SpellInfo.h b/src/server/game/Spells/SpellInfo.h index 4217fb16916..4faf98a0791 100644 --- a/src/server/game/Spells/SpellInfo.h +++ b/src/server/game/Spells/SpellInfo.h @@ -371,6 +371,9 @@ public: uint32 ProcFlags; uint32 ProcChance; uint32 ProcCharges; + uint32 ProcCooldown; + float ProcBasePPM; + std::vector<SpellProcsPerMinuteModEntry const*> ProcPPMMods; uint32 MaxLevel; uint32 BaseLevel; uint32 SpellLevel; @@ -391,7 +394,6 @@ public: uint32 SpellIconID; uint32 ActiveIconID; char* SpellName; - char* Rank; uint32 MaxTargetLevel; uint32 MaxAffectedTargets; uint32 SpellFamilyName; @@ -560,6 +562,8 @@ public: std::vector<CostData> CalcPowerCost(Unit const* caster, SpellSchoolMask schoolMask) const; + float CalcProcPPM(Unit* caster, int32 itemLevel) const; + bool IsRanked() const; uint8 GetRank() const; SpellInfo const* GetFirstRankSpell() const; |
