aboutsummaryrefslogtreecommitdiff
path: root/src/server/game/Spells
diff options
context:
space:
mode:
authorShauren <shauren.trinity@gmail.com>2016-05-02 18:52:15 +0200
committerShauren <shauren.trinity@gmail.com>2016-05-02 18:52:15 +0200
commit110ae3e6261694cd5a9ad1687ee209ef42a55c3e (patch)
tree77310f66c1d1d703ae9b8723d8aa0b6e2ce3dfe0 /src/server/game/Spells
parente8730061530cba48703508297dedc8aeb49681b1 (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.cpp20
-rw-r--r--src/server/game/Spells/Auras/SpellAuras.h12
-rw-r--r--src/server/game/Spells/SpellInfo.cpp129
-rw-r--r--src/server/game/Spells/SpellInfo.h6
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;