diff --git a/src/game/HostileRefManager.cpp b/src/game/HostileRefManager.cpp index 1ba8f4b2b..5889b6cd1 100644 --- a/src/game/HostileRefManager.cpp +++ b/src/game/HostileRefManager.cpp @@ -21,6 +21,12 @@ #include "Unit.h" #include "DBCStructure.h" #include "SpellMgr.h" +#include "Map.h" + +HostileRefManager::HostileRefManager( Unit *pOwner ) : iOwner(pOwner), m_redirectionMod(0.0f) +{ + +} HostileRefManager::~HostileRefManager() { @@ -34,17 +40,34 @@ HostileRefManager::~HostileRefManager() void HostileRefManager::threatAssist(Unit *pVictim, float pThreat, SpellEntry const *pThreatSpell, bool pSingleTarget) { - HostileReference* ref; + float redirectedMod = pVictim->getHostileRefManager().GetThreatRedirectionMod(); + Unit* redirectedTarget = redirectedMod ? pVictim->getHostileRefManager().GetThreatRedirectionTarget() : NULL; uint32 size = pSingleTarget ? 1 : getSize(); // if pSingleTarget do not devide threat - ref = getFirst(); + HostileReference* ref = getFirst(); while(ref != NULL) { float threat = ThreatCalcHelper::calcThreat(pVictim, iOwner, pThreat, false, (pThreatSpell ? GetSpellSchoolMask(pThreatSpell) : SPELL_SCHOOL_MASK_NORMAL), pThreatSpell); - if(pVictim == getOwner()) + + if (threat > 0.0f) + { + if (redirectedTarget && redirectedTarget != ref->getTarget() && redirectedTarget->isAlive()) + { + float redirectedThreat = threat * redirectedMod; + threat -= redirectedThreat; + + if(redirectedTarget == getOwner()) // It is faster to modify the threat durectly if possible + ref->addThreat(float (threat) / size); + else + ref->getSource()->addThreat(redirectedTarget, redirectedThreat); + } + } + + if (pVictim == getOwner()) ref->addThreat(float (threat) / size); // It is faster to modify the threat durectly if possible else ref->getSource()->addThreat(pVictim, float (threat) / size); + ref = ref->next(); } } @@ -162,4 +185,10 @@ void HostileRefManager::setOnlineOfflineState(Unit *pCreature,bool pIsOnline) } } +Unit* HostileRefManager::GetThreatRedirectionTarget() const +{ + return !m_redirectionTargetGuid.IsEmpty() ? iOwner->GetMap()->GetUnit(m_redirectionTargetGuid) : NULL; +} + + //================================================= diff --git a/src/game/HostileRefManager.h b/src/game/HostileRefManager.h index e16621d01..a96962190 100644 --- a/src/game/HostileRefManager.h +++ b/src/game/HostileRefManager.h @@ -20,6 +20,7 @@ #define _HOSTILEREFMANAGER #include "Common.h" +#include "ObjectGuid.h" #include "Utilities/LinkedReference/RefManager.h" class Unit; @@ -31,10 +32,8 @@ struct SpellEntry; class HostileRefManager : public RefManager { - private: - Unit *iOwner; public: - explicit HostileRefManager(Unit *pOwner) { iOwner = pOwner; } + explicit HostileRefManager(Unit *pOwner); ~HostileRefManager(); Unit* getOwner() { return iOwner; } @@ -64,6 +63,22 @@ class HostileRefManager : public RefManager // delete one reference, defined by Unit void deleteReference(Unit *pCreature); + + // redirection threat data + void SetThreatRedirection(ObjectGuid guid, uint32 pct) + { + m_redirectionTargetGuid = guid; + m_redirectionMod = pct/100.0f; + } + + float GetThreatRedirectionMod() const { return m_redirectionMod; } + Unit* GetThreatRedirectionTarget() const; + + private: + Unit* iOwner; // owner of manager variable, back ref. to it, always exist + + float m_redirectionMod; + ObjectGuid m_redirectionTargetGuid; }; //================================================= #endif diff --git a/src/game/Spell.h b/src/game/Spell.h index 6543abf2c..038028fcc 100644 --- a/src/game/Spell.h +++ b/src/game/Spell.h @@ -304,6 +304,7 @@ class Spell void EffectCharge(SpellEffectIndex eff_idx); void EffectCharge2(SpellEffectIndex eff_idx); void EffectProspecting(SpellEffectIndex eff_idx); + void EffectRedirectThreat(SpellEffectIndex eff_idx); void EffectMilling(SpellEffectIndex eff_idx); void EffectRenamePet(SpellEffectIndex eff_idx); void EffectSendTaxi(SpellEffectIndex eff_idx); diff --git a/src/game/SpellEffects.cpp b/src/game/SpellEffects.cpp index 7836cb290..03a4c6b3c 100644 --- a/src/game/SpellEffects.cpp +++ b/src/game/SpellEffects.cpp @@ -190,7 +190,7 @@ pEffect SpellEffects[TOTAL_SPELL_EFFECTS]= &Spell::EffectProspecting, //127 SPELL_EFFECT_PROSPECTING Prospecting spell &Spell::EffectApplyAreaAura, //128 SPELL_EFFECT_APPLY_AREA_AURA_FRIEND &Spell::EffectApplyAreaAura, //129 SPELL_EFFECT_APPLY_AREA_AURA_ENEMY - &Spell::EffectNULL, //130 SPELL_EFFECT_REDIRECT_THREAT + &Spell::EffectRedirectThreat, //130 SPELL_EFFECT_REDIRECT_THREAT &Spell::EffectUnused, //131 SPELL_EFFECT_131 used in some test spells &Spell::EffectPlayMusic, //132 SPELL_EFFECT_PLAY_MUSIC sound id in misc value (SoundEntries.dbc) &Spell::EffectUnlearnSpecialization, //133 SPELL_EFFECT_UNLEARN_SPECIALIZATION unlearn profession specialization @@ -8051,6 +8051,12 @@ void Spell::EffectRestoreItemCharges( SpellEffectIndex eff_idx ) item->RestoreCharges(); } +void Spell::EffectRedirectThreat(SpellEffectIndex eff_idx) +{ + if (unitTarget) + m_caster->getHostileRefManager().SetThreatRedirection(unitTarget->GetObjectGuid(), uint32(damage)); +} + void Spell::EffectTeachTaxiNode( SpellEffectIndex eff_idx ) { if (unitTarget->GetTypeId() != TYPEID_PLAYER) diff --git a/src/game/ThreatManager.cpp b/src/game/ThreatManager.cpp index 84a64b981..5baf9cd45 100644 --- a/src/game/ThreatManager.cpp +++ b/src/game/ThreatManager.cpp @@ -392,6 +392,27 @@ void ThreatManager::addThreat(Unit* pVictim, float pThreat, bool crit, SpellScho float threat = ThreatCalcHelper::calcThreat(pVictim, iOwner, pThreat, crit, schoolMask, pThreatSpell); + if (threat > 0.0f) + { + if (float redirectedMod = pVictim->getHostileRefManager().GetThreatRedirectionMod()) + { + if (Unit* redirectedTarget = pVictim->getHostileRefManager().GetThreatRedirectionTarget()) + { + if (redirectedTarget != getOwner() && redirectedTarget->isAlive()) + { + float redirectedThreat = threat * redirectedMod; + threat -= redirectedThreat; + addThreatDirectly(redirectedTarget, redirectedThreat); + } + } + } + } + + addThreatDirectly(pVictim, threat); +} + +void ThreatManager::addThreatDirectly(Unit* pVictim, float threat) +{ HostileReference* ref = iThreatContainer.addThreat(pVictim, threat); // Ref is online if (ref) @@ -402,7 +423,7 @@ void ThreatManager::addThreat(Unit* pVictim, float pThreat, bool crit, SpellScho if(!ref) // there was no ref => create a new one { - // threat has to be 0 here + // threat has to be 0 here HostileReference* hostileReference = new HostileReference(pVictim, this, 0); iThreatContainer.addReference(hostileReference); hostileReference->addThreat(threat); // now we add the real threat diff --git a/src/game/ThreatManager.h b/src/game/ThreatManager.h index e9148644c..98ff67a55 100644 --- a/src/game/ThreatManager.h +++ b/src/game/ThreatManager.h @@ -183,6 +183,10 @@ class MANGOS_DLL_SPEC ThreatManager 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); } + + // add threat as raw value (ignore redirections and expection all mods applied already to it + void addThreatDirectly(Unit* pVictim, float threat); + void modifyThreatPercent(Unit *pVictim, int32 pPercent); float getThreat(Unit *pVictim, bool pAlsoSearchOfflineList = false); diff --git a/src/shared/revision_nr.h b/src/shared/revision_nr.h index d704f8038..d061556f1 100644 --- a/src/shared/revision_nr.h +++ b/src/shared/revision_nr.h @@ -1,4 +1,4 @@ #ifndef __REVISION_NR_H__ #define __REVISION_NR_H__ - #define REVISION_NR "10464" + #define REVISION_NR "10465" #endif // __REVISION_NR_H__