Fix Script Naxxramas/Gothik with help of scarymovie87

Fixes issue #80.

- Implement support for "merging" life and dead side after ~2 minutes, if group is not splitted
- Implement support for opening central gate at 30% boss health
- Implement Gothik teleport between side when above 30% boss health
- Fix dead-side mobs spawn in 25-Man difficulty
- Fix waves setup.
- Fix some timers (this may still need some tuning).
- Fix sporadic combat reset when Gothic teleport to ground.

--HG--
branch : trunk
This commit is contained in:
Trazom62
2010-01-17 10:58:11 +01:00
parent 782fa95f1f
commit c4eb172d04
4 changed files with 275 additions and 102 deletions
@@ -0,0 +1,5 @@
-- Usually creature_template changes MUST GO to TDB
-- creature_template spell1-spell8 are in the exceptions
UPDATE `creature_template` SET `spell8` = 27892 WHERE `entry` IN (16124, 29987);
UPDATE `creature_template` SET `spell8` = 27928 WHERE `entry` IN (16125, 29985);
UPDATE `creature_template` SET `spell8` = 27935 WHERE `entry` IN (16126, 29986);
@@ -16,6 +16,7 @@
#include "precompiled.h" #include "precompiled.h"
#include "naxxramas.h" #include "naxxramas.h"
#include "spellId.h"
enum Yells enum Yells
{ {
@@ -27,15 +28,15 @@ enum Yells
//Gothik //Gothik
enum Spells enum Spells
{ {
SPELL_HARVEST_SOUL = 28679, SPELL_HARVEST_SOUL = SPELL_HARVEST_SOUL_28679,
SPELL_SHADOW_BOLT = 29317, SPELL_SHADOW_BOLT = SPELL_SHADOW_BOLT_29317,
H_SPELL_SHADOW_BOLT = 56405, H_SPELL_SHADOW_BOLT = SPELL_SHADOW_BOLT_56405,
SPELL_INFORM_LIVE_TRAINEE = 27892, SPELL_INFORM_LIVE_TRAINEE = SPELL_TO_ANCHOR_1_27892,
SPELL_INFORM_LIVE_KNIGHT = 27928, SPELL_INFORM_LIVE_KNIGHT = SPELL_TO_ANCHOR_1_27928,
SPELL_INFORM_LIVE_RIDER = 27935, SPELL_INFORM_LIVE_RIDER = SPELL_TO_ANCHOR_1_27935,
SPELL_INFORM_DEAD_TRAINEE = 27915, SPELL_INFORM_DEAD_TRAINEE = SPELL_ANCHOR_TO_SKULLS_27915,
SPELL_INFORM_DEAD_KNIGHT = 27931, SPELL_INFORM_DEAD_KNIGHT = SPELL_ANCHOR_TO_SKULLS_27931,
SPELL_INFORM_DEAD_RIDER = 27937 SPELL_INFORM_DEAD_RIDER = SPELL_ANCHOR_TO_SKULLS_27937
}; };
enum Creatures enum Creatures
{ {
@@ -47,64 +48,45 @@ enum Creatures
MOB_DEAD_RIDER = 16150, MOB_DEAD_RIDER = 16150,
MOB_DEAD_HORSE = 16149 MOB_DEAD_HORSE = 16149
}; };
struct Waves { uint32 entry, number, time; };
struct Waves { uint32 entry, time; };
// wave setups are the same in heroic and normal difficulty, only count of mobs is different,
// but this is handled in DoGothikSummon function
const Waves waves[] = const Waves waves[] =
{ {
{MOB_LIVE_TRAINEE, 2, 20000}, {MOB_LIVE_TRAINEE, 20000},
{MOB_LIVE_TRAINEE, 2, 20000}, {MOB_LIVE_TRAINEE, 20000},
{MOB_LIVE_TRAINEE, 2, 10000}, {MOB_LIVE_TRAINEE, 10000},
{MOB_LIVE_KNIGHT, 1, 10000}, {MOB_LIVE_KNIGHT, 10000},
{MOB_LIVE_TRAINEE, 2, 15000}, {MOB_LIVE_TRAINEE, 15000},
{MOB_LIVE_KNIGHT, 1, 5000}, {MOB_LIVE_KNIGHT, 5000},
{MOB_LIVE_TRAINEE, 2, 20000}, {MOB_LIVE_TRAINEE, 20000},
{MOB_LIVE_TRAINEE, 2, 0}, {MOB_LIVE_TRAINEE, 0},
{MOB_LIVE_KNIGHT, 1, 10000}, {MOB_LIVE_KNIGHT, 10000},
{MOB_LIVE_RIDER, 1, 10000}, {MOB_LIVE_RIDER, 10000},
{MOB_LIVE_TRAINEE, 2, 5000}, {MOB_LIVE_TRAINEE, 5000},
{MOB_LIVE_KNIGHT, 1, 15000}, {MOB_LIVE_KNIGHT, 15000},
{MOB_LIVE_TRAINEE, 2, 0}, {MOB_LIVE_RIDER, 0},
{MOB_LIVE_RIDER, 1, 10000}, {MOB_LIVE_TRAINEE, 10000},
{MOB_LIVE_KNIGHT, 2, 10000}, {MOB_LIVE_KNIGHT, 10000},
{MOB_LIVE_TRAINEE, 2, 10000}, {MOB_LIVE_TRAINEE, 10000},
{MOB_LIVE_RIDER, 1, 5000}, {MOB_LIVE_RIDER, 5000},
{MOB_LIVE_KNIGHT, 1, 5000}, {MOB_LIVE_KNIGHT, 5000},
{MOB_LIVE_TRAINEE, 2, 20000}, {MOB_LIVE_TRAINEE, 20000},
{MOB_LIVE_TRAINEE, 2, 0}, {MOB_LIVE_RIDER, 0},
{MOB_LIVE_KNIGHT, 1, 0}, {MOB_LIVE_KNIGHT, 0},
{MOB_LIVE_RIDER, 1, 15000}, {MOB_LIVE_TRAINEE, 20000},
{MOB_LIVE_TRAINEE, 2, 29000}, {MOB_LIVE_TRAINEE, 25000},
{0, 0, 0}, {0, 0},
};
const Waves wavesHeroic[] =
{
{MOB_LIVE_TRAINEE, 3, 20000},
{MOB_LIVE_TRAINEE, 3, 20000},
{MOB_LIVE_TRAINEE, 3, 10000},
{MOB_LIVE_KNIGHT, 2, 10000},
{MOB_LIVE_TRAINEE, 3, 15000},
{MOB_LIVE_KNIGHT, 2, 5000},
{MOB_LIVE_TRAINEE, 3, 20000},
{MOB_LIVE_TRAINEE, 3, 0},
{MOB_LIVE_KNIGHT, 2, 10000},
{MOB_LIVE_TRAINEE, 3, 10000},
{MOB_LIVE_RIDER, 1, 5000},
{MOB_LIVE_TRAINEE, 3, 15000},
{MOB_LIVE_RIDER, 1, 10000},
{MOB_LIVE_KNIGHT, 2, 10000},
{MOB_LIVE_RIDER, 1, 10000},
{MOB_LIVE_RIDER, 1, 0},
{MOB_LIVE_TRAINEE, 3, 5000},
{MOB_LIVE_KNIGHT, 1, 0},
{MOB_LIVE_TRAINEE, 3, 5000},
{MOB_LIVE_RIDER, 1, 0},
{MOB_LIVE_TRAINEE, 3, 20000},
{MOB_LIVE_KNIGHT, 2, 0},
{MOB_LIVE_RIDER, 1, 0},
{MOB_LIVE_TRAINEE, 3, 29000},
{0, 0, 0},
}; };
#define POS_Y_GATE -3360.78f #define POS_Y_GATE -3360.78f
#define POS_Y_WEST -3285.0f
#define POS_Y_EAST -3434.0f
#define POS_X_NORTH 2750.49f
#define POS_X_SOUTH 2633.84f
#define IN_LIVE_SIDE(who) (who->GetPositionY() < POS_Y_GATE)
enum Events enum Events
{ {
@@ -112,18 +94,22 @@ enum Events
EVENT_SUMMON, EVENT_SUMMON,
EVENT_HARVEST, EVENT_HARVEST,
EVENT_BOLT, EVENT_BOLT,
EVENT_TELEPORT
}; };
enum Pos enum Pos
{ {
POS_LIVE = 3, POS_LIVE = 6,
POS_DEAD = 5 POS_DEAD = 5
}; };
const Position PosSummonLive[POS_LIVE] = const Position PosSummonLive[POS_LIVE] =
{ {
{2669.7, -3430.9, 268.56, 1.6}, {2669.7, -3428.76, 268.56, 1.6},
{2692.0, -3430.9, 268.56, 1.6}, {2692.1, -3428.76, 268.56, 1.6},
{2714.1, -3430.9, 268.56, 1.6}, {2714.4, -3428.76, 268.56, 1.6},
{2669.7, -3431.67, 268.56, 1.6},
{2692.1, -3431.67, 268.56, 1.6},
{2714.4, -3431.67, 268.56, 1.6},
}; };
const Position PosSummonDead[POS_DEAD] = const Position PosSummonDead[POS_DEAD] =
@@ -135,9 +121,19 @@ const Position PosSummonDead[POS_DEAD] =
{2664.8, -3340.7, 268.23, 3.7}, {2664.8, -3340.7, 268.23, 3.7},
}; };
const float PosGround[4] = {2691.2, -3362.7, 267.68, 1.7}; const float PosGroundLiveSide[4] = {2691.2, -3387.0, 267.68, 1.52};
const float PosGroundDeadSide[4] = {2693.5, -3334.6, 267.68, 4.67};
const float PosPlatform[4] = {2640.5, -3360.6, 285.26, 0}; const float PosPlatform[4] = {2640.5, -3360.6, 285.26, 0};
// Predicate function to check that the r efzr unit is NOT on the same side as the source.
struct NotOnSameSide : public std::unary_function<Unit *, bool> {
bool m_inLiveSide;
NotOnSameSide(Unit *pSource) : m_inLiveSide(IN_LIVE_SIDE(pSource)) {}
bool operator() (const Unit *pTarget) {
return (m_inLiveSide != IN_LIVE_SIDE(pTarget));
}
};
struct TRINITY_DLL_DECL boss_gothikAI : public BossAI struct TRINITY_DLL_DECL boss_gothikAI : public BossAI
{ {
boss_gothikAI(Creature *c) : BossAI(c, BOSS_GOTHIK) {} boss_gothikAI(Creature *c) : BossAI(c, BOSS_GOTHIK) {}
@@ -145,16 +141,22 @@ struct TRINITY_DLL_DECL boss_gothikAI : public BossAI
uint32 waveCount; uint32 waveCount;
typedef std::vector<Creature*> TriggerVct; typedef std::vector<Creature*> TriggerVct;
TriggerVct liveTrigger, deadTrigger; TriggerVct liveTrigger, deadTrigger;
bool mergedSides;
bool phaseTwo;
bool thirtyPercentReached;
void Reset() void Reset()
{ {
liveTrigger.clear(); liveTrigger.clear();
deadTrigger.clear(); deadTrigger.clear();
me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_OOC_NOT_ATTACKABLE); me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_OOC_NOT_ATTACKABLE|UNIT_FLAG_DISABLE_MOVE);
me->SetReactState(REACT_PASSIVE); me->SetReactState(REACT_PASSIVE);
if (instance) if (instance)
instance->SetData(DATA_GOTHIK_GATE, GO_STATE_ACTIVE); instance->SetData(DATA_GOTHIK_GATE, GO_STATE_ACTIVE);
_Reset(); _Reset();
mergedSides = false;
phaseTwo = false;
thirtyPercentReached = false;
} }
void EnterCombat(Unit *who) void EnterCombat(Unit *who)
@@ -174,7 +176,7 @@ struct TRINITY_DLL_DECL boss_gothikAI : public BossAI
} }
_EnterCombat(); _EnterCombat();
me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_OOC_NOT_ATTACKABLE); me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_OOC_NOT_ATTACKABLE|UNIT_FLAG_DISABLE_MOVE);
waveCount = 0; waveCount = 0;
events.ScheduleEvent(EVENT_SUMMON, 30000); events.ScheduleEvent(EVENT_SUMMON, 30000);
DoTeleportTo(PosPlatform); DoTeleportTo(PosPlatform);
@@ -187,25 +189,21 @@ struct TRINITY_DLL_DECL boss_gothikAI : public BossAI
{ {
if (summon->GetEntry() == WORLD_TRIGGER) if (summon->GetEntry() == WORLD_TRIGGER)
summon->setActive(true); summon->setActive(true);
else else if (!mergedSides)
{ {
summon->AI()->DoAction(me->HasReactState(REACT_PASSIVE) ? 1 : 0); summon->AI()->DoAction(me->HasReactState(REACT_PASSIVE) ? 1 : 0);
summon->AI()->EnterEvadeMode(); summon->AI()->EnterEvadeMode();
} }
else
{
summon->AI()->DoAction(0);
summon->AI()->DoZoneInCombat();
}
summons.Summon(summon); summons.Summon(summon);
} }
void SummonedCreatureDespawn(Creature *summon) void SummonedCreatureDespawn(Creature *summon)
{ {
if (summon->GetEntry() == WORLD_TRIGGER)
{
//for (TriggerVct::iterator itr = liveTrigger.begin(); itr != liveTrigger.end(); ++itr)
// if(*itr == summon)
error_log("boss_gothikAI: trigger is despawned!");
EnterEvadeMode();
return;
}
summons.Despawn(summon); summons.Despawn(summon);
} }
@@ -221,6 +219,85 @@ struct TRINITY_DLL_DECL boss_gothikAI : public BossAI
deadTrigger.clear(); deadTrigger.clear();
_JustDied(); _JustDied();
DoScriptText(SAY_DEATH, me); DoScriptText(SAY_DEATH, me);
if (instance)
instance->SetData(DATA_GOTHIK_GATE, GO_STATE_ACTIVE);
}
void DoGothikSummon(uint32 entry)
{
if (getDifficulty() == RAID_DIFFICULTY_25MAN_NORMAL)
{
switch(entry)
{
case MOB_LIVE_TRAINEE:
DoSummon(MOB_LIVE_TRAINEE, liveTrigger[0], 1);
DoSummon(MOB_LIVE_TRAINEE, liveTrigger[1], 1);
DoSummon(MOB_LIVE_TRAINEE, liveTrigger[2], 1);
break;
case MOB_LIVE_KNIGHT:
DoSummon(MOB_LIVE_KNIGHT, liveTrigger[3], 1);
DoSummon(MOB_LIVE_KNIGHT, liveTrigger[5], 1);
break;
case MOB_LIVE_RIDER:
DoSummon(MOB_LIVE_RIDER, liveTrigger[4], 1);
break;
}
}
else
{
switch(entry)
{
case MOB_LIVE_TRAINEE:
DoSummon(MOB_LIVE_TRAINEE, liveTrigger[0], 1);
DoSummon(MOB_LIVE_TRAINEE, liveTrigger[1], 1);
break;
case MOB_LIVE_KNIGHT:
DoSummon(MOB_LIVE_KNIGHT, liveTrigger[5], 1);
break;
case MOB_LIVE_RIDER:
DoSummon(MOB_LIVE_RIDER, liveTrigger[4], 1);
break;
}
}
}
bool CheckGroupSplitted()
{
bool checklife = false;
bool checkdead = false;
Map* pMap = me->GetMap();
if (pMap && pMap->IsDungeon())
{
Map::PlayerList const &PlayerList = pMap->GetPlayers();
if (!PlayerList.isEmpty())
{
for (Map::PlayerList::const_iterator i = PlayerList.begin(); i != PlayerList.end(); ++i)
{
if (i->getSource() && i->getSource()->isAlive() &&
i->getSource()->GetPositionX() <= POS_X_NORTH &&
i->getSource()->GetPositionX() >= POS_X_SOUTH &&
i->getSource()->GetPositionY() <= POS_Y_GATE &&
i->getSource()->GetPositionY() >= POS_Y_EAST)
{
checklife = true;
}
else if (i->getSource() && i->getSource()->isAlive() &&
i->getSource()->GetPositionX() <= POS_X_NORTH &&
i->getSource()->GetPositionX() >= POS_X_SOUTH &&
i->getSource()->GetPositionY() >= POS_Y_GATE &&
i->getSource()->GetPositionY() <= POS_Y_WEST)
{
checkdead = true;
}
if (checklife && checkdead)
return true;
}
}
}
return false;
} }
void SpellHit(Unit *caster, const SpellEntry *spell) void SpellHit(Unit *caster, const SpellEntry *spell)
@@ -246,10 +323,16 @@ struct TRINITY_DLL_DECL boss_gothikAI : public BossAI
switch(spell->Id) switch(spell->Id)
{ {
case SPELL_INFORM_DEAD_TRAINEE: DoSummon(MOB_DEAD_TRAINEE, pTarget, 0); break; case SPELL_INFORM_DEAD_TRAINEE:
case SPELL_INFORM_DEAD_KNIGHT: DoSummon(MOB_DEAD_KNIGHT, pTarget, 0); break; DoSummon(MOB_DEAD_TRAINEE, pTarget, 0);
case SPELL_INFORM_DEAD_RIDER: DoSummon(MOB_DEAD_RIDER, pTarget, 1.0f); break;
DoSummon(MOB_DEAD_HORSE, pTarget, 1.0f); break; case SPELL_INFORM_DEAD_KNIGHT:
DoSummon(MOB_DEAD_KNIGHT, pTarget, 0);
break;
case SPELL_INFORM_DEAD_RIDER:
DoSummon(MOB_DEAD_RIDER, pTarget, 1.0f);
DoSummon(MOB_DEAD_HORSE, pTarget, 1.0f);
break;
} }
} }
@@ -260,6 +343,13 @@ struct TRINITY_DLL_DECL boss_gothikAI : public BossAI
events.Update(diff); events.Update(diff);
if (!thirtyPercentReached && HealthBelowPct(30) && phaseTwo)
{
thirtyPercentReached = true;
if (instance)
instance->SetData(DATA_GOTHIK_GATE, GO_STATE_ACTIVE);
}
if (me->hasUnitState(UNIT_STAT_CASTING)) if (me->hasUnitState(UNIT_STAT_CASTING))
return; return;
@@ -270,33 +360,69 @@ struct TRINITY_DLL_DECL boss_gothikAI : public BossAI
case EVENT_SUMMON: case EVENT_SUMMON:
if (waves[waveCount].entry) if (waves[waveCount].entry)
{ {
for (uint32 i = 0; i < waves[waveCount].number; ++i) DoGothikSummon(waves[waveCount].entry);
DoSummon(waves[waveCount].entry, liveTrigger[rand()%POS_LIVE], 1.0f);
events.ScheduleEvent(EVENT_SUMMON, waves[waveCount].time); // if group is not splitted, open gate and merge both sides at ~ 2 minutes (wave 11)
++waveCount; if (waveCount == 11)
} {
else if (!CheckGroupSplitted())
{ {
DoScriptText(SAY_TELEPORT, me);
DoTeleportTo(PosGround);
me->SetReactState(REACT_AGGRESSIVE);
me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_OOC_NOT_ATTACKABLE);
if (instance) if (instance)
instance->SetData(DATA_GOTHIK_GATE, GO_STATE_ACTIVE); instance->SetData(DATA_GOTHIK_GATE, GO_STATE_ACTIVE);
summons.DoAction(0, 0); summons.DoAction(0, 0);
summons.DoZoneInCombat(); summons.DoZoneInCombat();
mergedSides = true;
}
}
++waveCount;
events.ScheduleEvent(EVENT_SUMMON, waves[waveCount].time);
}
else
{
phaseTwo = true;
DoScriptText(SAY_TELEPORT, me);
DoTeleportTo(PosGroundLiveSide);
me->SetReactState(REACT_AGGRESSIVE);
me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_OOC_NOT_ATTACKABLE);
summons.DoAction(0, 0);
summons.DoZoneInCombat();
events.ScheduleEvent(EVENT_BOLT, 1000); events.ScheduleEvent(EVENT_BOLT, 1000);
events.ScheduleEvent(EVENT_HARVEST, 15000); events.ScheduleEvent(EVENT_HARVEST, urand(3000,15000));
events.ScheduleEvent(EVENT_TELEPORT, 20000);
} }
break; break;
case EVENT_BOLT: case EVENT_BOLT:
DoCast(me->getVictim(), RAID_MODE(SPELL_SHADOW_BOLT, H_SPELL_SHADOW_BOLT)); DoCast(me->getVictim(), RAID_MODE(SPELL_SHADOW_BOLT, H_SPELL_SHADOW_BOLT));
events.ScheduleEvent(EVENT_BOLT, 1000); events.ScheduleEvent(EVENT_BOLT, 1000);
return; break;
case EVENT_HARVEST: case EVENT_HARVEST:
DoCast(me->getVictim(), SPELL_HARVEST_SOUL); DoCast(me->getVictim(), SPELL_HARVEST_SOUL, true);
events.ScheduleEvent(EVENT_HARVEST, 15000); events.ScheduleEvent(EVENT_HARVEST, urand(20000,25000));
return; break;
case EVENT_TELEPORT:
if (!thirtyPercentReached)
{
m_creature->AttackStop();
if (IN_LIVE_SIDE(m_creature))
{
DoTeleportTo(PosGroundDeadSide);
}
else
{
DoTeleportTo(PosGroundLiveSide);
}
m_creature->getThreatManager().resetAggro(NotOnSameSide(m_creature));
if (Unit *pTarget = SelectTarget(SELECT_TARGET_NEAREST, 0))
{
m_creature->getThreatManager().addThreat(pTarget, 100.0f);
AttackStart(pTarget);
}
events.ScheduleEvent(EVENT_TELEPORT, 20000);
}
break;
} }
} }
@@ -308,13 +434,16 @@ struct TRINITY_DLL_DECL mob_gothik_minionAI : public CombatAI
{ {
mob_gothik_minionAI(Creature *c) : CombatAI(c) mob_gothik_minionAI(Creature *c) : CombatAI(c)
{ {
liveSide = me->GetPositionY() < POS_Y_GATE; liveSide = IN_LIVE_SIDE(me);
} }
bool liveSide; bool liveSide;
bool gateClose; bool gateClose;
#define SIDE_CHECK(who) (liveSide == (who->GetPositionY() < POS_Y_GATE)) bool isOnSameSide(const Unit *pWho)
{
return (liveSide == IN_LIVE_SIDE(pWho));
}
void DoAction(const int32 param) void DoAction(const int32 param)
{ {
@@ -323,7 +452,7 @@ struct TRINITY_DLL_DECL mob_gothik_minionAI : public CombatAI
void DamageTaken(Unit *attacker, uint32 &damage) void DamageTaken(Unit *attacker, uint32 &damage)
{ {
if (gateClose && !SIDE_CHECK(attacker)) if (gateClose && !isOnSameSide(attacker))
damage = 0; damage = 0;
} }
@@ -351,15 +480,18 @@ struct TRINITY_DLL_DECL mob_gothik_minionAI : public CombatAI
if (pMap->IsDungeon()) if (pMap->IsDungeon())
{ {
Map::PlayerList const &PlayerList = pMap->GetPlayers(); Map::PlayerList const &PlayerList = pMap->GetPlayers();
if (!PlayerList.isEmpty())
{
for (Map::PlayerList::const_iterator i = PlayerList.begin(); i != PlayerList.end(); ++i) for (Map::PlayerList::const_iterator i = PlayerList.begin(); i != PlayerList.end(); ++i)
{ {
if (i->getSource()->isAlive() && SIDE_CHECK(i->getSource())) if (i->getSource() && i->getSource()->isAlive() && isOnSameSide(i->getSource()))
{ {
AttackStart(i->getSource()); AttackStart(i->getSource());
return; return;
} }
} }
} }
}
me->GetMotionMaster()->MoveIdle(); me->GetMotionMaster()->MoveIdle();
Reset(); Reset();
@@ -367,7 +499,7 @@ struct TRINITY_DLL_DECL mob_gothik_minionAI : public CombatAI
void UpdateAI(const uint32 diff) void UpdateAI(const uint32 diff)
{ {
if (gateClose && (!SIDE_CHECK(me) || me->getVictim() && !SIDE_CHECK(me->getVictim()))) if (gateClose && (!isOnSameSide(me) || me->getVictim() && !isOnSameSide(me->getVictim())))
{ {
EnterEvadeMode(); EnterEvadeMode();
return; return;
+14
View File
@@ -537,3 +537,17 @@ bool ThreatManager::isNeedUpdateToClient(uint32 time)
return false; return false;
} }
// Reset all aggro without modifying the threadlist.
void ThreatManager::resetAllAggro()
{
std::list<HostilReference*> &threatlist = getThreatList();
if (threatlist.empty())
return;
for (std::list<HostilReference*>::iterator itr = threatlist.begin(); itr != threatlist.end(); ++itr)
{
(*itr)->setThreat(0);
}
setDirty(true);
}
+22
View File
@@ -215,6 +215,28 @@ class TRINITY_DLL_SPEC ThreatManager
void setDirty(bool bDirty) { iThreatContainer.setDirty(bDirty); } void setDirty(bool bDirty) { iThreatContainer.setDirty(bDirty); }
// Reset all aggro without modifying the threadlist.
void resetAllAggro();
// Reset all aggro of unit in threadlist satisfying the predicate.
template<class PREDICATE> void resetAggro(PREDICATE predicate)
{
std::list<HostilReference*> &threatlist = getThreatList();
if (threatlist.empty())
return;
for (std::list<HostilReference*>::iterator itr = threatlist.begin(); itr != threatlist.end(); ++itr)
{
HostilReference* ref = (*itr);
if (predicate(ref->getTarget()))
{
ref->setThreat(0);
setDirty(true);
}
}
}
// methods to access the lists from the outside to do some dirty manipulation (scriping and such) // methods to access the lists from the outside to do some dirty manipulation (scriping and such)
// I hope they are used as little as possible. // I hope they are used as little as possible.
std::list<HostilReference*>& getThreatList() { return iThreatContainer.getThreatList(); } std::list<HostilReference*>& getThreatList() { return iThreatContainer.getThreatList(); }