[8658] Threat calculation fixes and improvements.

* Add single arg version Unit::AddThreat for just adding to threat list.
* Req. provide schollmask and crit flag for any real threat value for proper threats mod apply.
* Send crit flag in DealDamage as MELEE_HIT_CRIT for spell damage for later send to threat call.
* For not affected by modifiers threat values use SPELL_SCHOOL_MASK_NONE.
* Implement aura SPELL_AURA_MOD_CRITICAL_THREAT (used only in itemset 529 effect).
This commit is contained in:
VladimirMangos 2009-10-17 10:47:44 +04:00
parent ba62cdbe8f
commit b258a17ba4
15 changed files with 50 additions and 32 deletions

View file

@ -60,7 +60,7 @@ AggressorAI::MoveInLineOfSight(Unit *u)
}
else if(sMapStore.LookupEntry(m_creature->GetMapId())->IsDungeon())
{
m_creature->AddThreat(u, 0.0f);
m_creature->AddThreat(u);
u->SetInCombatWith(m_creature);
}
}
@ -155,7 +155,7 @@ AggressorAI::AttackStart(Unit *u)
// DEBUG_LOG("Creature %s tagged a victim to kill [guid=%u]", m_creature->GetName(), u->GetGUIDLow());
i_victimGuid = u->GetGUID();
m_creature->AddThreat(u, 0.0f);
m_creature->AddThreat(u);
m_creature->SetInCombatWith(u);
u->SetInCombatWith(m_creature);

View file

@ -2057,7 +2057,7 @@ void Creature::SetInCombatWithZone()
if (pPlayer->isAlive())
{
pPlayer->SetInCombatWith(this);
AddThreat(pPlayer, 0.0f);
AddThreat(pPlayer);
}
}
}

View file

@ -948,7 +948,7 @@ void CreatureEventAI::AttackStart(Unit *who)
if (m_creature->Attack(who, MeleeEnabled))
{
m_creature->AddThreat(who, 0.0f);
m_creature->AddThreat(who);
m_creature->SetInCombatWith(who);
who->SetInCombatWith(m_creature);
@ -1010,7 +1010,7 @@ void CreatureEventAI::MoveInLineOfSight(Unit *who)
}
else if (m_creature->GetMap()->IsDungeon())
{
m_creature->AddThreat(who, 0.0f);
m_creature->AddThreat(who);
who->SetInCombatWith(m_creature);
}
}

View file

@ -138,7 +138,7 @@ void GuardAI::AttackStart(Unit *u)
if(m_creature->Attack(u,true))
{
i_victimGuid = u->GetGUID();
m_creature->AddThreat(u, 0.0f);
m_creature->AddThreat(u);
m_creature->SetInCombatWith(u);
u->SetInCombatWith(m_creature);

View file

@ -40,7 +40,7 @@ void HostileRefManager::threatAssist(Unit *pVictim, float pThreat, SpellEntry co
ref = getFirst();
while(ref != NULL)
{
float threat = ThreatCalcHelper::calcThreat(pVictim, iOwner, pThreat, (pThreatSpell ? GetSpellSchoolMask(pThreatSpell) : SPELL_SCHOOL_MASK_NORMAL), pThreatSpell);
float threat = ThreatCalcHelper::calcThreat(pVictim, iOwner, pThreat, false, (pThreatSpell ? GetSpellSchoolMask(pThreatSpell) : SPELL_SCHOOL_MASK_NORMAL), pThreatSpell);
if(pVictim == getOwner())
ref->addThreat(float (threat) / size); // It is faster to modify the threat durectly if possible
else

View file

@ -172,7 +172,7 @@ void PetAI::UpdateAI(const uint32 diff)
return;
//if pet misses its target, it will also be the first in threat list
m_creature->getVictim()->AddThreat(m_creature,0.0f);
m_creature->getVictim()->AddThreat(m_creature);
if( _needToStop() )
_stopAttack();

View file

@ -49,7 +49,7 @@ ReactorAI::AttackStart(Unit *p)
{
DEBUG_LOG("Tag unit GUID: %u (TypeId: %u) as a victim", p->GetGUIDLow(), p->GetTypeId());
i_victimGuid = p->GetGUID();
m_creature->AddThreat(p, 0.0f);
m_creature->AddThreat(p);
m_creature->SetInCombatWith(p);
p->SetInCombatWith(m_creature);

View file

@ -1092,7 +1092,7 @@ void Spell::DoSpellHitOnUnit(Unit *unit, const uint32 effectMask)
if (!unit->isInCombat() && unit->GetTypeId() != TYPEID_PLAYER && ((Creature*)unit)->AI())
((Creature*)unit)->AI()->AttackedBy(realCaster);
unit->AddThreat(realCaster, 0.0f);
unit->AddThreat(realCaster);
unit->SetInCombatWith(realCaster);
realCaster->SetInCombatWith(unit);
@ -1116,7 +1116,7 @@ void Spell::DoSpellHitOnUnit(Unit *unit, const uint32 effectMask)
if (unit->isInCombat() && !(m_spellInfo->AttributesEx & SPELL_ATTR_EX_NO_INITIAL_AGGRO))
{
realCaster->SetInCombatState(unit->GetCombatTimer() > 0);
unit->getHostileRefManager().threatAssist(realCaster, 0.0f);
unit->getHostileRefManager().threatAssist(realCaster, 0.0f, m_spellInfo);
}
}
}
@ -3770,7 +3770,7 @@ void Spell::HandleThreatSpells(uint32 spellId)
if(!threat)
return;
m_targets.getUnitTarget()->AddThreat(m_caster, float(threat));
m_targets.getUnitTarget()->AddThreat(m_caster, float(threat), false, GetSpellSchoolMask(m_spellInfo), m_spellInfo);
DEBUG_LOG("Spell %u, rank %u, added an additional %i threat", spellId, spellmgr.GetSpellRank(spellId), threat);
}

View file

@ -233,7 +233,7 @@ pAuraHandler AuraHandler[TOTAL_AURAS]=
&Aura::HandleNoImmediateEffect, //180 SPELL_AURA_MOD_FLAT_SPELL_DAMAGE_VERSUS implemented in Unit::SpellDamageBonus
&Aura::HandleUnused, //181 unused (3.0.8a) old SPELL_AURA_MOD_FLAT_SPELL_CRIT_DAMAGE_VERSUS
&Aura::HandleAuraModResistenceOfStatPercent, //182 SPELL_AURA_MOD_RESISTANCE_OF_STAT_PERCENT
&Aura::HandleNULL, //183 SPELL_AURA_MOD_CRITICAL_THREAT only used in 28746
&Aura::HandleNoImmediateEffect, //183 SPELL_AURA_MOD_CRITICAL_THREAT only used in 28746, implemented in ThreatCalcHelper::calcThreat
&Aura::HandleNoImmediateEffect, //184 SPELL_AURA_MOD_ATTACKER_MELEE_HIT_CHANCE implemented in Unit::RollMeleeOutcomeAgainst
&Aura::HandleNoImmediateEffect, //185 SPELL_AURA_MOD_ATTACKER_RANGED_HIT_CHANCE implemented in Unit::RollMeleeOutcomeAgainst
&Aura::HandleNoImmediateEffect, //186 SPELL_AURA_MOD_ATTACKER_SPELL_HIT_CHANCE implemented in Unit::MagicSpellHitResult
@ -2195,7 +2195,7 @@ void Aura::HandleAuraDummy(bool apply, bool Real)
case 1515: // Tame beast
// FIX_ME: this is 2.0.12 threat effect replaced in 2.1.x by dummy aura, must be checked for correctness
if( caster && m_target->CanHaveThreatList())
m_target->AddThreat(caster, 10.0f);
m_target->AddThreat(caster, 10.0f, false, GetSpellSchoolMask(GetSpellProto()), GetSpellProto());
return;
case 13139: // net-o-matic
// root to self part of (root_target->charge->root_self sequence
@ -4039,7 +4039,7 @@ void Aura::HandleAuraModTotalThreat(bool apply, bool Real)
float threatMod = apply ? float(m_modifier.m_amount) : float(-m_modifier.m_amount);
m_target->getHostileRefManager().threatAssist(caster, threatMod);
m_target->getHostileRefManager().threatAssist(caster, threatMod, GetSpellProto());
}
void Aura::HandleModTaunt(bool apply, bool Real)
@ -6311,6 +6311,10 @@ void Aura::PeriodicTick()
// This method can modify pdamage
bool isCrit = IsCritFromAbilityAura(pCaster, pdamage);
// send critical in hit info for threat calculation
if (isCrit)
cleanDamage.hitOutCome = MELEE_HIT_CRIT;
pCaster->CalcAbsorbResist(m_target, GetSpellSchoolMask(GetSpellProto()), DOT, pdamage, &absorb, &resist);
sLog.outDetail("PeriodicTick: %u (TypeId: %u) attacked %u (TypeId: %u) for %u dmg inflicted by %u abs is %u",
@ -6556,7 +6560,7 @@ void Aura::PeriodicTick()
if(gain_amount)
{
int32 gain = pCaster->ModifyPower(power, gain_amount);
m_target->AddThreat(pCaster, float(gain) * 0.5f, GetSpellSchoolMask(GetSpellProto()), GetSpellProto());
m_target->AddThreat(pCaster, float(gain) * 0.5f, pInfo.critical, GetSpellSchoolMask(GetSpellProto()), GetSpellProto());
}
break;
}

View file

@ -4681,7 +4681,7 @@ void Spell::EffectThreat(uint32 /*i*/)
if(!unitTarget->CanHaveThreatList())
return;
unitTarget->AddThreat(m_caster, float(damage));
unitTarget->AddThreat(m_caster, float(damage), false, GetSpellSchoolMask(m_spellInfo), m_spellInfo);
}
void Spell::EffectHealMaxHealth(uint32 /*i*/)

View file

@ -30,12 +30,21 @@
//==============================================================
// The pHatingUnit is not used yet
float ThreatCalcHelper::calcThreat(Unit* pHatedUnit, Unit* pHatingUnit, float pThreat, SpellSchoolMask schoolMask, SpellEntry const *pThreatSpell)
float ThreatCalcHelper::calcThreat(Unit* pHatedUnit, Unit* pHatingUnit, float pThreat, bool crit, SpellSchoolMask schoolMask, SpellEntry const *pThreatSpell)
{
// all flat mods applied early
if(!pThreat)
return 0.0f;
if (pThreatSpell)
{
if (Player* modOwner = pHatedUnit->GetSpellModOwner())
modOwner->ApplySpellMod(pThreatSpell->Id, SPELLMOD_THREAT, pThreat);
if(crit)
pThreat *= pHatedUnit->GetTotalAuraMultiplierByMiscMask(SPELL_AURA_MOD_CRITICAL_THREAT,schoolMask);
}
float threat = pHatedUnit->ApplyTotalThreatModifier(pThreat, schoolMask);
return threat;
}
@ -357,7 +366,7 @@ void ThreatManager::clearReferences()
//============================================================
void ThreatManager::addThreat(Unit* pVictim, float pThreat, SpellSchoolMask schoolMask, SpellEntry const *pThreatSpell)
void ThreatManager::addThreat(Unit* pVictim, float pThreat, bool crit, SpellSchoolMask schoolMask, SpellEntry const *pThreatSpell)
{
//function deals with adding threat and adding players and pets into ThreatList
//mobs, NPCs, guards have ThreatList and HateOfflineList
@ -378,7 +387,7 @@ void ThreatManager::addThreat(Unit* pVictim, float pThreat, SpellSchoolMask scho
assert(getOwner()->GetTypeId()== TYPEID_UNIT);
float threat = ThreatCalcHelper::calcThreat(pVictim, iOwner, pThreat, schoolMask, pThreatSpell);
float threat = ThreatCalcHelper::calcThreat(pVictim, iOwner, pThreat, crit, schoolMask, pThreatSpell);
HostileReference* ref = iThreatContainer.addThreat(pVictim, threat);
// Ref is not in the online refs, search the offline refs next

View file

@ -39,7 +39,7 @@ struct SpellEntry;
class ThreatCalcHelper
{
public:
static float calcThreat(Unit* pHatedUnit, Unit* pHatingUnit, float threat, SpellSchoolMask schoolMask = SPELL_SCHOOL_MASK_NORMAL, SpellEntry const *threatSpell = NULL);
static float calcThreat(Unit* pHatedUnit, Unit* pHatingUnit, float threat, bool crit, SpellSchoolMask schoolMask, SpellEntry const *threatSpell);
};
//==============================================================
@ -176,7 +176,8 @@ class MANGOS_DLL_SPEC ThreatManager
void clearReferences();
void addThreat(Unit* pVictim, float threat, SpellSchoolMask schoolMask = SPELL_SCHOOL_MASK_NORMAL, SpellEntry const *threatSpell = NULL);
void addThreat(Unit* pVictim, float threat, bool crit, SpellSchoolMask schoolMask, SpellEntry const *threatSpell);
void addThreat(Unit* pVictim, float threat) { addThreat(pVictim,threat,false,SPELL_SCHOOL_MASK_NONE,NULL); }
void modifyThreatPercent(Unit *pVictim, int32 pPercent);
float getThreat(Unit *pVictim, bool pAlsoSearchOfflineList = false);

View file

@ -761,9 +761,9 @@ uint32 Unit::DealDamage(Unit *pVictim, uint32 damage, CleanDamage const* cleanDa
if (pVictim->GetTypeId() != TYPEID_PLAYER)
{
if(spellProto && IsDamageToThreatSpell(spellProto))
pVictim->AddThreat(this, damage*2, damageSchoolMask, spellProto);
pVictim->AddThreat(this, damage*2, (cleanDamage && cleanDamage->hitOutCome == MELEE_HIT_CRIT), damageSchoolMask, spellProto);
else
pVictim->AddThreat(this, damage, damageSchoolMask, spellProto);
pVictim->AddThreat(this, damage, (cleanDamage && cleanDamage->hitOutCome == MELEE_HIT_CRIT), damageSchoolMask, spellProto);
}
else // victim is a player
{
@ -1125,7 +1125,7 @@ void Unit::CalculateSpellDamage(SpellNonMeleeDamage *damageInfo, int32 damage, S
void Unit::DealSpellDamage(SpellNonMeleeDamage *damageInfo, bool durabilityLoss)
{
if (damageInfo==0)
if (!damageInfo)
return;
Unit *pVictim = damageInfo->target;
@ -1152,8 +1152,8 @@ void Unit::DealSpellDamage(SpellNonMeleeDamage *damageInfo, bool durabilityLoss)
return;
}
// Call default DealDamage
CleanDamage cleanDamage(damageInfo->cleanDamage, BASE_ATTACK, MELEE_HIT_NORMAL);
// Call default DealDamage (send critical in hit info for threat calculation)
CleanDamage cleanDamage(damageInfo->cleanDamage, BASE_ATTACK, damageInfo->HitInfo & SPELL_HIT_TYPE_CRIT ? MELEE_HIT_CRIT : MELEE_HIT_NORMAL);
DealDamage(pVictim, damageInfo->damage, &cleanDamage, SPELL_DIRECT_DAMAGE, SpellSchoolMask(damageInfo->schoolMask), spellProto, durabilityLoss);
}
@ -10199,6 +10199,9 @@ float Unit::ApplyTotalThreatModifier(float threat, SpellSchoolMask schoolMask)
if (!HasAuraType(SPELL_AURA_MOD_THREAT))
return threat;
if (schoolMask == SPELL_SCHOOL_MASK_NONE)
return threat;
SpellSchools school = GetFirstSchoolInMask(schoolMask);
return threat * m_threatModifier[school];
@ -10206,11 +10209,11 @@ float Unit::ApplyTotalThreatModifier(float threat, SpellSchoolMask schoolMask)
//======================================================================
void Unit::AddThreat(Unit* pVictim, float threat, SpellSchoolMask schoolMask, SpellEntry const *threatSpell)
void Unit::AddThreat(Unit* pVictim, float threat, bool crit, SpellSchoolMask schoolMask, SpellEntry const *threatSpell /*= NULL*/)
{
// Only mobs can manage threat lists
if(CanHaveThreatList())
m_ThreatManager.addThreat(pVictim, threat, schoolMask, threatSpell);
m_ThreatManager.addThreat(pVictim, threat, crit, schoolMask, threatSpell);
}
//======================================================================

View file

@ -1336,7 +1336,8 @@ class MANGOS_DLL_SPEC Unit : public WorldObject
// Threat related methods
bool CanHaveThreatList() const;
void AddThreat(Unit* pVictim, float threat, SpellSchoolMask schoolMask = SPELL_SCHOOL_MASK_NORMAL, SpellEntry const *threatSpell = NULL);
void AddThreat(Unit* pVictim, float threat, bool crit, SpellSchoolMask schoolMask, SpellEntry const *threatSpell = NULL);
void AddThreat(Unit* pVictim) { AddThreat(pVictim, 0.0f, false, SPELL_SCHOOL_MASK_NORMAL, NULL); }
float ApplyTotalThreatModifier(float threat, SpellSchoolMask schoolMask = SPELL_SCHOOL_MASK_NORMAL);
void DeleteThreatList();
bool SelectHostileTarget();

View file

@ -1,4 +1,4 @@
#ifndef __REVISION_NR_H__
#define __REVISION_NR_H__
#define REVISION_NR "8657"
#define REVISION_NR "8658"
#endif // __REVISION_NR_H__