void Player::UpdateSpellDamageAndHealingBonus() { // Magic damage modifiers implemented in Unit::SpellDamageBonus // This information for client side use only // Get healing bonus for all schools SetStatInt32Value(PLAYER_FIELD_MOD_HEALING_DONE_POS, SpellBaseHealingBonus(SPELL_SCHOOL_MASK_ALL)); // Get damage bonus for all schools for(int i = SPELL_SCHOOL_HOLY; i < MAX_SPELL_SCHOOL; ++i) SetStatInt32Value(PLAYER_FIELD_MOD_DAMAGE_DONE_POS+i, SpellBaseDamageBonus(SpellSchoolMask(1 << i))); }
bool SpellHistory::IsSchoolLocked(SpellSchoolMask schoolMask) const { Clock::time_point now = Clock::now(); for (uint32 i = 0; i < MAX_SPELL_SCHOOL; ++i) if (SpellSchoolMask(1 << i) & schoolMask) if (_schoolLockouts[i] > now) return true; return false; }
void SpellHistory::LockSpellSchool(SpellSchoolMask schoolMask, uint32 lockoutTime) { Clock::time_point lockoutEnd = Clock::now() + std::chrono::duration_cast<Clock::duration>(std::chrono::milliseconds(lockoutTime)); for (uint32 i = 0; i < MAX_SPELL_SCHOOL; ++i) if (SpellSchoolMask(1 << i) & schoolMask) _schoolLockouts[i] = lockoutEnd; std::set<uint32> knownSpells; if (Player* plrOwner = _owner->ToPlayer()) { for (auto const& p : plrOwner->GetSpellMap()) if (p.second->state != PLAYERSPELL_REMOVED) knownSpells.insert(p.first); } else if (Pet* petOwner = _owner->ToPet()) { for (auto const& p : petOwner->m_spells) if (p.second.state != PETSPELL_REMOVED) knownSpells.insert(p.first); } else { Creature* creatureOwner = _owner->ToCreature(); for (uint8 i = 0; i < CREATURE_MAX_SPELLS; ++i) if (creatureOwner->m_spells[i]) knownSpells.insert(creatureOwner->m_spells[i]); } PacketCooldowns cooldowns; WorldPacket spellCooldowns; for (uint32 spellId : knownSpells) { SpellInfo const* spellInfo = sSpellMgr->EnsureSpellInfo(spellId); if (spellInfo->IsCooldownStartedOnEvent()) continue; if (spellInfo->PreventionType != SPELL_PREVENTION_TYPE_SILENCE) continue; if ((schoolMask & spellInfo->GetSchoolMask()) && GetRemainingCooldown(spellId) < lockoutTime) { cooldowns[spellId] = lockoutTime; AddCooldown(spellId, 0, lockoutEnd); } } if (Player* player = GetPlayerOwner()) { if (!cooldowns.empty()) { BuildCooldownPacket(spellCooldowns, SPELL_COOLDOWN_FLAG_NONE, cooldowns); player->SendDirectMessage(&spellCooldowns); } } }
void CalculateAmountResistance(AuraEffect const* aurEff, int32& amount, bool& /*canBeRecalculated*/) { if (Pet* pPet = GetUnitOwner()->ToPet()) { if (pPet->GetOwnerScaling()) { SpellSchoolMask schoolMask = SpellSchoolMask(aurEff->GetMiscValue()); amount += int32(pPet->GetOwnerScaling()->CalculateScaling(STAT_IDENTIFIER_RESISTANCE, schoolMask, pPet->GetOwnerResistance(schoolMask))); } } }
void SpellHistory::LockSpellSchool(SpellSchoolMask schoolMask, uint32 lockoutTime) { Clock::time_point now = Clock::now(); Clock::time_point lockoutEnd = now + std::chrono::duration_cast<Clock::duration>(std::chrono::milliseconds(lockoutTime)); for (uint32 i = 0; i < MAX_SPELL_SCHOOL; ++i) if (SpellSchoolMask(1 << i) & schoolMask) _schoolLockouts[i] = lockoutEnd; std::set<uint32> knownSpells; if (Player* plrOwner = _owner->ToPlayer()) { for (auto const& p : plrOwner->GetSpellMap()) if (p.second->state != PLAYERSPELL_REMOVED) knownSpells.insert(p.first); } else if (Pet* petOwner = _owner->ToPet()) { for (auto const& p : petOwner->m_spells) if (p.second.state != PETSPELL_REMOVED) knownSpells.insert(p.first); } else { Creature* creatureOwner = _owner->ToCreature(); for (uint8 i = 0; i < CREATURE_MAX_SPELLS; ++i) if (creatureOwner->m_spells[i]) knownSpells.insert(creatureOwner->m_spells[i]); } WorldPackets::Spells::SpellCooldown spellCooldown; spellCooldown.Caster = _owner->GetGUID(); spellCooldown.Flags = SPELL_COOLDOWN_FLAG_NONE; for (uint32 spellId : knownSpells) { SpellInfo const* spellInfo = sSpellMgr->AssertSpellInfo(spellId); if (spellInfo->IsCooldownStartedOnEvent()) continue; if (!(spellInfo->PreventionType & SPELL_PREVENTION_TYPE_SILENCE)) continue; if ((schoolMask & spellInfo->GetSchoolMask()) && GetRemainingCooldown(spellInfo) < lockoutTime) { spellCooldown.SpellCooldowns.emplace_back(spellId, lockoutTime); AddCooldown(spellId, 0, lockoutEnd, 0, now); } } if (Player* player = GetPlayerOwner()) if (!spellCooldown.SpellCooldowns.empty()) player->SendDirectMessage(spellCooldown.Write()); }
void HandleEffect(SpellEffIndex effIndex) { Unit* caster = GetCaster(); if (Unit* target = GetHitUnit()) { SpellInfo const* spellInfo = GetSpellInfo(); int32 rageUsed = std::min<int32>(300 - spellInfo->CalcPowerCost(caster, SpellSchoolMask(spellInfo->SchoolMask)), caster->GetPower(POWER_RAGE)); int32 newRage = std::max<int32>(0, caster->GetPower(POWER_RAGE) - rageUsed); // Sudden Death rage save if (AuraEffect* aurEff = caster->GetAuraEffect(SPELL_AURA_PROC_TRIGGER_SPELL, SPELLFAMILY_GENERIC, WARRIOR_ICON_ID_SUDDEN_DEATH, EFFECT_0)) { int32 ragesave = aurEff->GetSpellInfo()->Effects[EFFECT_1].CalcValue() * 10; newRage = std::max(newRage, ragesave); } caster->SetPower(POWER_RAGE, uint32(newRage)); // Glyph of Execution bonus if (AuraEffect* aurEff = caster->GetAuraEffect(SPELL_WARRIOR_GLYPH_OF_EXECUTION, EFFECT_0)) rageUsed += aurEff->GetAmount() * 10; int32 bp = GetEffectValue() + int32(rageUsed * spellInfo->Effects[effIndex].DamageMultiplier + caster->GetTotalAttackPowerValue(BASE_ATTACK) * 0.2f); caster->CastCustomSpell(target, SPELL_WARRIOR_EXECUTE, &bp, NULL, NULL, true, NULL, NULL, GetOriginalCaster()->GetGUID()); } }
void HandleEffectProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) { PreventDefaultAction(); int32 focus = eventInfo.GetDamageInfo()->GetSpellInfo()->CalcPowerCost(GetTarget(), SpellSchoolMask(eventInfo.GetDamageInfo()->GetSchoolMask())); focus = CalculatePct(focus, aurEff->GetAmount()); GetTarget()->CastCustomSpell(GetTarget(), SPELL_HUNTER_THRILL_OF_THE_HUNT, &focus, NULL, NULL, true, NULL, aurEff); }
void HandleEffect(SpellEffIndex /*effIndex*/) { Unit* caster = GetCaster(); if (GetHitUnit()) { SpellInfo const* spellInfo = GetSpellInfo(); int32 rageUsed = std::min<int32>(200 - spellInfo->CalcPowerCost(caster, SpellSchoolMask(spellInfo->SchoolMask)), caster->GetPower(POWER_RAGE)); int32 newRage = std::max<int32>(0, caster->GetPower(POWER_RAGE) - rageUsed); // Sudden Death rage save if (AuraEffect* aurEff = caster->GetAuraEffect(SPELL_AURA_PROC_TRIGGER_SPELL, SPELLFAMILY_GENERIC, ICON_ID_SUDDEN_DEATH, EFFECT_0)) { int32 ragesave = aurEff->GetSpellInfo()->Effects[EFFECT_0].CalcValue() * 10; newRage = std::max(newRage, ragesave); } caster->SetPower(POWER_RAGE, uint32(newRage)); /// Formula taken from the DBC: "${10+$AP*0.437*$m1/100}" int32 baseDamage = int32(10 + caster->GetTotalAttackPowerValue(BASE_ATTACK) * 0.437f * GetEffectValue() / 100.0f); /// Formula taken from the DBC: "${$ap*0.874*$m1/100-1} = 20 rage" int32 moreDamage = int32(rageUsed * (caster->GetTotalAttackPowerValue(BASE_ATTACK) * 0.874f * GetEffectValue() / 100.0f - 1) / 200); SetHitDamage(baseDamage + moreDamage); } }
void HandleEffectProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo) { PreventDefaultAction(); std::vector<SpellInfo::CostData> costs = eventInfo.GetDamageInfo()->GetSpellInfo()->CalcPowerCost(GetTarget(), SpellSchoolMask(eventInfo.GetDamageInfo()->GetSchoolMask())); auto m = std::find_if(costs.begin(), costs.end(), [](SpellInfo::CostData const& cost) { return cost.Power == POWER_FOCUS; }); if (m != costs.end()) { int32 focus = CalculatePct(m->Amount, aurEff->GetAmount()); if (focus > 0) GetTarget()->CastCustomSpell(GetTarget(), SPELL_HUNTER_THRILL_OF_THE_HUNT, &focus, NULL, NULL, true, NULL, aurEff); } }
void ChangeDamage(SpellEffIndex effIndex) { Unit* caster = GetCaster(); Unit* target = GetHitUnit(); if (!target) return; int32 rageUsed = std::min<int32>(300 - GetSpellInfo()->CalcPowerCost(caster, SpellSchoolMask(GetSpellInfo()->SchoolMask)), caster->GetPower(POWER_RAGE)); int32 newRage = std::max<int32>(0, caster->GetPower(POWER_RAGE) - rageUsed); // Sudden Death rage refund if (AuraEffect* aurEff = caster->GetAuraEffect(SPELL_AURA_PROC_TRIGGER_SPELL, SPELLFAMILY_GENERIC, ICON_ID_SUDDEN_DEATH, EFFECT_0)) { int32 ragesave = aurEff->GetAmount() * 10; newRage = std::max(newRage, ragesave); } caster->SetPower(POWER_RAGE, uint32(newRage)); // DBC formula: ap * 0.874 * 100 / 100 - rageUsed int32 rageBonus = ((caster->GetTotalAttackPowerValue(BASE_ATTACK) * 0.874f) * 1000) / (1000 - rageUsed); int32 totalDamage = (GetHitDamage() + rageBonus); SetHitDamage(totalDamage); }
void Player::UpdateSpellDamageAndHealingBonus() { // Magic damage modifiers implemented in Unit::SpellDamageBonusDone // This information for client side use only // Get healing bonus for all schools SetStatInt32Value(PLAYER_FIELD_MOD_HEALING_DONE_POS, SpellBaseHealingBonusDone(SPELL_SCHOOL_MASK_ALL)); // Get damage bonus for all schools for(int i = SPELL_SCHOOL_HOLY; i < MAX_SPELL_SCHOOL; ++i) SetStatInt32Value(PLAYER_FIELD_MOD_DAMAGE_DONE_POS+i, SpellBaseDamageBonusDone(SpellSchoolMask(1 << i))); CallForAllControlledUnits(ApplyScalingBonusWithHelper(SCALING_TARGET_ATTACKPOWER, 0, false),CONTROLLED_PET|CONTROLLED_GUARDIANS); CallForAllControlledUnits(ApplyScalingBonusWithHelper(SCALING_TARGET_SPELLDAMAGE, 0, false),CONTROLLED_PET|CONTROLLED_GUARDIANS); }
void Player::UpdateSpellDamageAndHealingBonus() { bool activeOverride = false; // Handle overrides first AuraEffectList const& overrides = GetAuraEffectsByType(SPELL_AURA_OVERRIDE_SPELL_POWER_BY_AP_PCT); for (AuraEffectList::const_iterator i = overrides.begin(); i != overrides.end(); ++i) { activeOverride = true; SetFloatValue(PLAYER_FIELD_OVERRIDE_SPELL_POWER_BY_AP_PCT, float((*i)->GetAmount())); } if (!activeOverride) { // Magic damage modifiers implemented in Unit::SpellDamageBonusDone // This information for client side use only // Get healing bonus for all schools SetStatInt32Value(PLAYER_FIELD_MOD_HEALING_DONE_POS, SpellBaseHealingBonusDone(SPELL_SCHOOL_MASK_ALL)); // Get damage bonus for all schools //for (int i = SPELL_SCHOOL_HOLY; i < MAX_SPELL_SCHOOL; ++i) for (int i = SPELL_SCHOOL_HOLY; i < MAX_SPELL_SCHOOL; ++i) SetStatInt32Value(PLAYER_FIELD_MOD_DAMAGE_DONE_POS+i, SpellBaseDamageBonusDone(SpellSchoolMask(1 << i))); } RecalculatePetsScalingAttackPower(); RecalculatePetsScalingDamageDone(); }
void Player::UpdateSpellDamageAndHealingBonus() { // Magic damage modifiers implemented in Unit::SpellDamageBonusDone // This information for client side use only // Get healing bonus for all schools SetStatInt32Value(PLAYER_FIELD_MOD_HEALING_DONE_POS, SpellBaseHealingBonusDone(SPELL_SCHOOL_MASK_ALL)); // Get damage bonus for all schools Unit::AuraEffectList const& modDamageAuras = GetAuraEffectsByType(SPELL_AURA_MOD_DAMAGE_DONE); for (uint16 i = SPELL_SCHOOL_HOLY; i < MAX_SPELL_SCHOOL; ++i) { SetInt32Value(PLAYER_FIELD_MOD_DAMAGE_DONE_NEG + i, std::accumulate(modDamageAuras.begin(), modDamageAuras.end(), 0, [i](int32 negativeMod, AuraEffect const* aurEff) { if (aurEff->GetAmount() < 0 && aurEff->GetMiscValue() & (1 << i)) negativeMod += aurEff->GetAmount(); return negativeMod; })); SetStatInt32Value(PLAYER_FIELD_MOD_DAMAGE_DONE_POS + i, SpellBaseDamageBonusDone(SpellSchoolMask(1 << i)) - GetInt32Value(PLAYER_FIELD_MOD_DAMAGE_DONE_NEG + i)); } if (HasAuraType(SPELL_AURA_OVERRIDE_ATTACK_POWER_BY_SP_PCT)) { UpdateAttackPowerAndDamage(); UpdateAttackPowerAndDamage(true); } }
CanCastResult CreatureAI::CanCastSpell(Unit* pTarget, const SpellEntry* pSpell, bool isTriggered) { // If not triggered, we check if (!isTriggered) { // State does not allow if (m_creature->hasUnitState(UNIT_STAT_CAN_NOT_REACT_OR_LOST_CONTROL)) return CAST_FAIL_STATE; if (pSpell->PreventionType == SPELL_PREVENTION_TYPE_SILENCE && m_creature->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_SILENCED)) return CAST_FAIL_STATE; if (pSpell->PreventionType == SPELL_PREVENTION_TYPE_PACIFY && m_creature->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PACIFIED)) return CAST_FAIL_STATE; // Check for power (also done by Spell::CheckCast()) if (m_creature->GetPower((Powers)pSpell->powerType) < Spell::CalculatePowerCost(pSpell, m_creature)) return CAST_FAIL_POWER; // School-lock like effect after interrupt -- @Rikub if ((pSpell->InterruptFlags & SPELL_INTERRUPT_FLAG_INTERRUPT) && m_creature->IsSpellSchoolProhibited(SpellSchoolMask(pSpell->SchoolMask))) return CAST_FAIL_STATE; } if (const SpellRangeEntry* pSpellRange = sSpellRangeStore.LookupEntry(pSpell->rangeIndex)) { if (pTarget != m_creature) { // pTarget is out of range of this spell (also done by Spell::CheckCast()) float fDistance = m_creature->GetCombatDistance(pTarget, pSpell->rangeIndex == SPELL_RANGE_IDX_COMBAT); if (fDistance > pSpellRange->maxRange) return CAST_FAIL_TOO_FAR; float fMinRange = pSpellRange->minRange; if (fMinRange && fDistance < fMinRange) return CAST_FAIL_TOO_CLOSE; } return CAST_OK; } else return CAST_FAIL_OTHER; }