diff --git a/src/server/game/DataStores/DBCStructure.h b/src/server/game/DataStores/DBCStructure.h index f6999585ef..029ff2e3b3 100644 --- a/src/server/game/DataStores/DBCStructure.h +++ b/src/server/game/DataStores/DBCStructure.h @@ -2233,7 +2233,7 @@ struct SpellPowerEntry uint32 ManaPerSecond; // 4 //uint32 PowerDisplayID; // 5 //uint32 AltPowerBarID; // 6 - //float PowerCostPct; // 7 ?? + float PowerCostPct2; // 7 }; struct SpellRuneCostEntry diff --git a/src/server/game/DataStores/DBCfmt.h b/src/server/game/DataStores/DBCfmt.h index 16fc612542..20a635d797 100644 --- a/src/server/game/DataStores/DBCfmt.h +++ b/src/server/game/DataStores/DBCfmt.h @@ -162,7 +162,7 @@ char const SpellReagentsEntryfmt[] = "diiiiiiiiiiiiiiii"; char const SpellScalingEntryfmt[] = "diiiiffffffffffi"; char const SpellTotemsEntryfmt[] = "niiii"; char const SpellTargetRestrictionsEntryfmt[] = "nfiiii"; -char const SpellPowerEntryfmt[] = "diiiixxx"; +char const SpellPowerEntryfmt[] = "diiiixxf"; char const SpellInterruptsEntryfmt[] = "diiiii"; char const SpellEquippedItemsEntryfmt[] = "diii"; char const SpellAuraOptionsEntryfmt[] = "niiii"; diff --git a/src/server/game/Spells/SpellInfo.cpp b/src/server/game/Spells/SpellInfo.cpp index 9cce6d552e..d721446942 100644 --- a/src/server/game/Spells/SpellInfo.cpp +++ b/src/server/game/Spells/SpellInfo.cpp @@ -980,6 +980,7 @@ SpellInfo::SpellInfo(SpellEntry const* spellEntry, SpellEffectEntry const** effe ManaCost = _power ? _power->ManaCost : 0; ManaCostPerlevel = _power ? _power->ManaCostPerLevel : 0; ManaCostPercentage = _power ? _power->PowerCostPct : 0; + ManaCostPercentage2 = _power ? _power->PowerCostPct2 : 0.f; ManaPerSecond = _power ? _power->ManaPerSecond : 0; // SpellReagentsEntry @@ -3307,36 +3308,66 @@ int32 SpellInfo::CalcPowerCost(Unit const* caster, SpellSchoolMask schoolMask, S // Else drain all power if (PowerType < MAX_POWERS) return caster->GetPower(Powers(PowerType)); + TC_LOG_ERROR("spells", "SpellInfo::CalcPowerCost: Unknown power type '%d' in spell %d", PowerType, Id); return 0; } - // Base powerCost - int32 powerCost = ManaCost; - // PCT cost from total amount - if (ManaCostPercentage) + bool invertSign = false; + int32 powerCost = 0; + + if (SpellPowerId) { - switch (PowerType) + int32 manaCost = ManaCost; + powerCost = manaCost; + float powerCostPct = ManaCostPercentage2 != 0.f ? ManaCostPercentage2 : (float)ManaCostPercentage; + + if (manaCost < 0 || powerCostPct < 0.f) { - // health as power used - case POWER_HEALTH: - powerCost += int32(CalculatePct(caster->GetCreateHealth(), ManaCostPercentage)); - break; - case POWER_MANA: - powerCost += int32(CalculatePct(caster->GetCreateMana(), ManaCostPercentage)); - break; - case POWER_RAGE: - case POWER_FOCUS: - case POWER_ENERGY: - powerCost += int32(CalculatePct(caster->GetMaxPower(Powers(PowerType)), ManaCostPercentage)); - break; - case POWER_RUNE: - case POWER_RUNIC_POWER: - TC_LOG_DEBUG("spells", "CalculateManaCost: Not implemented yet!"); - break; - default: - TC_LOG_ERROR("spells", "CalculateManaCost: Unknown power type '%d' in spell %d", PowerType, Id); - return 0; + manaCost = std::abs(manaCost); + powerCostPct = std::fabs(powerCostPct); + invertSign = true; + powerCost = manaCost; + } + + // Base calculation + if (ManaCostPercentage) + { + int32 ressource = 0; + switch (PowerType) + { + // health as power used + case POWER_HEALTH: + ressource = caster->GetCreateHealth(); + break; + case POWER_MANA: + ressource = caster->GetCreateMana(); + break; + case POWER_RAGE: + case POWER_FOCUS: + case POWER_ENERGY: + ressource = caster->GetMaxPower(Powers(PowerType)); + break; + case POWER_RUNE: + case POWER_RUNIC_POWER: + TC_LOG_DEBUG("spells", "CalculateManaCost: Not implemented yet!"); + break; + default: + TC_LOG_ERROR("spells", "CalculateManaCost: Unknown power type '%d' in spell %d", PowerType, Id); + return 0; + } + + manaCost += int32((ressource * powerCostPct) / 100); + powerCost = manaCost; + } + + // Scaling + if (SpellScalingId) + powerCost = int32(ceilf(GetSpellScalingMultiplier(caster, GetSpellScaling(), true) * (double)powerCost)); + else + { + uint32 manaCostPerLevel = invertSign ? -int32(ManaCostPerlevel) : ManaCostPerlevel; + powerCost = manaCostPerLevel * SpellLevel + manaCost; } } @@ -3355,11 +3386,9 @@ int32 SpellInfo::CalcPowerCost(Unit const* caster, SpellSchoolMask schoolMask, S if (HasAttribute(SPELL_ATTR4_SPELL_VS_EXTEND_COST)) { uint32 speed = 0; -/* REVIEW - MERGE - if (SpellShapeshiftEntry const* ss = sSpellShapeshiftStore.LookupEntry(caster->GetShapeshiftForm())) - speed = ss->attackSpeed; + if (SpellShapeshiftFormEntry const* ss = sSpellShapeshiftFormStore.LookupEntry(caster->GetShapeshiftForm())) + speed = ss->CombatRoundTime; else -*/ { WeaponAttackType slot = BASE_ATTACK; if (HasAttribute(SPELL_ATTR3_REQ_OFFHAND)) @@ -3381,11 +3410,14 @@ int32 SpellInfo::CalcPowerCost(Unit const* caster, SpellSchoolMask schoolMask, S { GtNPCManaCostScalerEntry const* spellScaler = sGtNPCManaCostScalerStore.LookupEntry(SpellLevel - 1); GtNPCManaCostScalerEntry const* casterScaler = sGtNPCManaCostScalerStore.LookupEntry(caster->getLevel() - 1); - if (spellScaler && casterScaler) + if (spellScaler && spellScaler->ratio > 0.f && casterScaler && casterScaler->ratio > 0.f) powerCost *= casterScaler->ratio / spellScaler->ratio; } } + if (invertSign) + powerCost = -powerCost; + // PCT mod from user auras by spell school and power type Unit::AuraEffectList const& aurasPct = caster->GetAuraEffectsByType(SPELL_AURA_MOD_POWER_COST_SCHOOL_PCT); for (Unit::AuraEffectList::const_iterator i = aurasPct.begin(); i != aurasPct.end(); ++i) @@ -3401,6 +3433,35 @@ int32 SpellInfo::CalcPowerCost(Unit const* caster, SpellSchoolMask schoolMask, S return powerCost; } +float SpellInfo::GetSpellScalingMultiplier(Unit const* caster, SpellScalingEntry const* scalingEntry, bool isPowerCostRelated /*= false*/) const +{ + if (!caster || !scalingEntry) + return 1.f; + + float multiplier = 1.f; + float scalingMultiplier = 1.f; + + int32 castTimeMaxLevel = scalingEntry->CastTimeMaxLevel; + uint8 casterLevel = caster->getLevel(); + + if (casterLevel < castTimeMaxLevel && scalingEntry->CastTimeMax) + { + float castTimeMax = (float)scalingEntry->CastTimeMax; + int32 castTime = scalingEntry->CastTimeMin + ((casterLevel - 1) * (scalingEntry->CastTimeMax - scalingEntry->CastTimeMin)) / (castTimeMaxLevel - 1); + multiplier = castTime / castTimeMax; + scalingMultiplier = castTime / castTimeMax; + } + + if (!isPowerCostRelated) + { + int32 nerfMaxLevel = scalingEntry->NerfMaxLevel; + if (casterLevel < nerfMaxLevel) + scalingMultiplier = ((((1.f - scalingEntry->NerfFactor) * (casterLevel - 1)) / (nerfMaxLevel - 1)) + scalingEntry->NerfFactor) * multiplier; + } + + return scalingMultiplier; +} + bool SpellInfo::IsRanked() const { return ChainEntry != nullptr; diff --git a/src/server/game/Spells/SpellInfo.h b/src/server/game/Spells/SpellInfo.h index c98f059c5a..98404ba791 100644 --- a/src/server/game/Spells/SpellInfo.h +++ b/src/server/game/Spells/SpellInfo.h @@ -379,6 +379,7 @@ class TC_GAME_API SpellInfo uint32 ManaCostPerlevel; uint32 ManaPerSecond; uint32 ManaCostPercentage; + float ManaCostPercentage2; uint32 RuneCostID; SpellRangeEntry const* RangeEntry; float Speed; @@ -556,6 +557,7 @@ class TC_GAME_API SpellInfo uint32 GetRecoveryTime() const; int32 CalcPowerCost(Unit const* caster, SpellSchoolMask schoolMask, Spell* spell = nullptr) const; + float GetSpellScalingMultiplier(Unit const* caster, SpellScalingEntry const* scalingEntry, bool isPowerCostRelated = false) const; bool IsRanked() const; uint8 GetRank() const;