// not 100% sure how this one should work and PVP affects ... void Aura::ProcessOnAllFriendlies(Mob *owner) { auto &mob_list = entity_list.GetMobList(); // read only reference so we can do it all inline std::set<int> delayed_remove; bool is_buff = IsBuffSpell(spell_id); // non-buff spells don't cast on enter for (auto &e : mob_list) { auto mob = e.second; if (mob->IsClient() || mob->IsPetOwnerClient() || mob->IsMerc()) { auto it = casted_on.find(mob->GetID()); if (it != casted_on.end()) { // we are already on the list, let's check for removal if (DistanceSquared(GetPosition(), mob->GetPosition()) > distance) delayed_remove.insert(mob->GetID()); } else { // not on list, lets check if we're in range if (DistanceSquared(GetPosition(), mob->GetPosition()) <= distance) { casted_on.insert(mob->GetID()); if (is_buff) SpellFinished(spell_id, mob); } } } } for (auto &e : delayed_remove) { auto mob = entity_list.GetMob(e); if (mob != nullptr && is_buff) // some auras cast instant spells so no need to remove mob->BuffFadeBySpellIDAndCaster(spell_id, GetID()); casted_on.erase(e); } // so if we have a cast timer and our set isn't empty and timer is disabled we need to enable it if (cast_timer.GetDuration() > 0 && !cast_timer.Enabled() && !casted_on.empty()) cast_timer.Start(); if (!cast_timer.Enabled() || !cast_timer.Check()) return; for (auto &e : casted_on) { auto mob = entity_list.GetMob(e); if (mob != nullptr) SpellFinished(spell_id, mob); } }
int32 Mob::GetActSpellDamage(uint16 spell_id, int32 value, Mob* target) { if (spells[spell_id].targettype == ST_Self) return value; if (IsNPC()) value += value*CastToNPC()->GetSpellFocusDMG()/100; bool Critical = false; int32 value_BaseEffect = 0; int chance = 0; value_BaseEffect = value + (value*GetFocusEffect(focusFcBaseEffects, spell_id)/100); // Need to scale HT damage differently after level 40! It no longer scales by the constant value in the spell file. It scales differently, instead of 10 more damage per level, it does 30 more damage per level. So we multiply the level minus 40 times 20 if they are over level 40. if ((spell_id == SPELL_HARM_TOUCH || spell_id == SPELL_HARM_TOUCH2 || spell_id == SPELL_IMP_HARM_TOUCH ) && GetLevel() > 40) value -= (GetLevel() - 40) * 20; //This adds the extra damage from the AA Unholy Touch, 450 per level to the AA Improved Harm TOuch. if (spell_id == SPELL_IMP_HARM_TOUCH && IsClient()) //Improved Harm Touch value -= GetAA(aaUnholyTouch) * 450; //Unholy Touch chance = RuleI(Spells, BaseCritChance); //Wizard base critical chance is 2% (Does not scale with level) chance += itembonuses.CriticalSpellChance + spellbonuses.CriticalSpellChance + aabonuses.CriticalSpellChance; chance += itembonuses.FrenziedDevastation + spellbonuses.FrenziedDevastation + aabonuses.FrenziedDevastation; //Crtical Hit Calculation pathway if (chance > 0 || (IsClient() && GetClass() == WIZARD && GetLevel() >= RuleI(Spells, WizCritLevel))) { int32 ratio = RuleI(Spells, BaseCritRatio); //Critical modifier is applied from spell effects only. Keep at 100 for live like criticals. //Improved Harm Touch is a guaranteed crit if you have at least one level of SCF. if (spell_id == SPELL_IMP_HARM_TOUCH && IsClient() && (GetAA(aaSpellCastingFury) > 0) && (GetAA(aaUnholyTouch) > 0)) chance = 100; if (zone->random.Roll(chance)) { Critical = true; ratio += itembonuses.SpellCritDmgIncrease + spellbonuses.SpellCritDmgIncrease + aabonuses.SpellCritDmgIncrease; ratio += itembonuses.SpellCritDmgIncNoStack + spellbonuses.SpellCritDmgIncNoStack + aabonuses.SpellCritDmgIncNoStack; } else if ((IsClient() && GetClass() == WIZARD) || (IsMerc() && GetClass() == CASTERDPS)) { if ((GetLevel() >= RuleI(Spells, WizCritLevel)) && zone->random.Roll(RuleI(Spells, WizCritChance))){ //Wizard innate critical chance is calculated seperately from spell effect and is not a set ratio. (20-70 is parse confirmed) ratio += zone->random.Int(20,70); Critical = true; } } if (IsClient() && GetClass() == WIZARD) ratio += RuleI(Spells, WizCritRatio); //Default is zero if (Critical){ value = value_BaseEffect*ratio/100; value += value_BaseEffect*GetFocusEffect(focusImprovedDamage, spell_id)/100; value += int(value_BaseEffect*GetFocusEffect(focusFcDamagePctCrit, spell_id)/100)*ratio/100; if (target) { value += int(value_BaseEffect*target->GetVulnerability(this, spell_id, 0)/100)*ratio/100; value -= target->GetFcDamageAmtIncoming(this, spell_id); } value -= GetFocusEffect(focusFcDamageAmtCrit, spell_id)*ratio/100; value -= GetFocusEffect(focusFcDamageAmt, spell_id); if(itembonuses.SpellDmg && spells[spell_id].classes[(GetClass()%16) - 1] >= GetLevel() - 5) value -= GetExtraSpellAmt(spell_id, itembonuses.SpellDmg, value)*ratio/100; else if (IsNPC() && CastToNPC()->GetSpellScale()) value = int(static_cast<float>(value) * CastToNPC()->GetSpellScale() / 100.0f); entity_list.MessageClose_StringID(this, true, 100, MT_SpellCrits, OTHER_CRIT_BLAST, GetName(), itoa(-value)); if (IsClient()) Message_StringID(MT_SpellCrits, YOU_CRIT_BLAST, itoa(-value)); return value; } } //Non Crtical Hit Calculation pathway value = value_BaseEffect; value += value_BaseEffect*GetFocusEffect(focusImprovedDamage, spell_id)/100; value += value_BaseEffect*GetFocusEffect(focusFcDamagePctCrit, spell_id)/100; if (target) { value += value_BaseEffect*target->GetVulnerability(this, spell_id, 0)/100; value -= target->GetFcDamageAmtIncoming(this, spell_id); } value -= GetFocusEffect(focusFcDamageAmtCrit, spell_id); value -= GetFocusEffect(focusFcDamageAmt, spell_id); if(itembonuses.SpellDmg && spells[spell_id].classes[(GetClass()%16) - 1] >= GetLevel() - 5) value -= GetExtraSpellAmt(spell_id, itembonuses.SpellDmg, value); if (IsNPC() && CastToNPC()->GetSpellScale()) value = int(static_cast<float>(value) * CastToNPC()->GetSpellScale() / 100.0f); return value; }