aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorNay <dnpd.dd@gmail.com>2012-09-22 10:56:41 +0100
committerNay <dnpd.dd@gmail.com>2012-09-22 10:56:41 +0100
commit95d713ac6f53a270be879b6661c3d988607261c5 (patch)
treee6be56757cba94dcd25af666a77386f25d16e1f2 /src
parent7090197c6ade85e1b223d3cb46923b89133f89a5 (diff)
parent5faa9d37b4240223a86939b4d898ec666e71f0c0 (diff)
Merge remote-tracking branch 'origin/master' into 4.3.4
Diffstat (limited to 'src')
-rwxr-xr-xsrc/server/game/AI/CreatureAI.cpp7
-rwxr-xr-xsrc/server/game/Entities/Unit/Unit.cpp13
-rwxr-xr-xsrc/server/game/Entities/Unit/Unit.h8
-rw-r--r--src/server/game/Spells/SpellMgr.cpp13
-rw-r--r--src/server/scripts/Northrend/Nexus/Oculus/boss_eregos.cpp2
-rw-r--r--src/server/scripts/Northrend/UtgardeKeep/UtgardeKeep/boss_ingvar_the_plunderer.cpp117
-rw-r--r--src/server/scripts/Northrend/UtgardeKeep/UtgardeKeep/boss_keleseth.cpp60
-rw-r--r--src/server/scripts/Northrend/UtgardeKeep/UtgardeKeep/boss_skarvald_dalronn.cpp31
-rw-r--r--src/server/scripts/Northrend/UtgardeKeep/UtgardeKeep/utgarde_keep.cpp77
-rw-r--r--src/server/scripts/Outland/shadowmoon_valley.cpp91
10 files changed, 346 insertions, 73 deletions
diff --git a/src/server/game/AI/CreatureAI.cpp b/src/server/game/AI/CreatureAI.cpp
index 17cef3ec1a1..e5868117da8 100755
--- a/src/server/game/AI/CreatureAI.cpp
+++ b/src/server/game/AI/CreatureAI.cpp
@@ -153,13 +153,20 @@ void CreatureAI::EnterEvadeMode()
me->GetMotionMaster()->MoveFollow(owner, PET_FOLLOW_DIST, me->GetFollowAngle(), MOTION_SLOT_ACTIVE);
}
else
+ {
+ // Required to prevent attacking creatures that are evading and cause them to reenter combat
+ // Does not apply to MoveFollow
+ me->AddUnitState(UNIT_STATE_EVADE);
me->GetMotionMaster()->MoveTargetedHome();
+ }
}
Reset();
if (me->IsVehicle()) // use the same sequence of addtoworld, aireset may remove all summons!
me->GetVehicleKit()->Reset(true);
+
+ me->SetLastDamagedTime(0);
}
/*void CreatureAI::AttackedBy(Unit* attacker)
diff --git a/src/server/game/Entities/Unit/Unit.cpp b/src/server/game/Entities/Unit/Unit.cpp
index 3952f70af71..71976bb3bfd 100755
--- a/src/server/game/Entities/Unit/Unit.cpp
+++ b/src/server/game/Entities/Unit/Unit.cpp
@@ -173,6 +173,7 @@ Unit::Unit(bool isWorldObject): WorldObject(isWorldObject)
, m_vehicleKit(NULL)
, m_unitTypeMask(UNIT_MASK_NONE)
, m_HostileRefManager(this)
+ , _lastDamagedTime(0)
{
#ifdef _MSC_VER
#pragma warning(default:4355)
@@ -11190,6 +11191,10 @@ int32 Unit::ModifyHealth(int32 dVal)
if (dVal == 0)
return 0;
+ // Part of Evade mechanics. Only track health lost, not gained.
+ if (dVal < 0 && GetTypeId() != TYPEID_PLAYER && !isPet())
+ SetLastDamagedTime(time(NULL));
+
int32 curHealth = (int32)GetHealth();
int32 val = dVal + curHealth;
@@ -12134,6 +12139,14 @@ Unit* Creature::SelectVictim()
return target;
}
+ // Case where mob is being kited.
+ // Mob may not be in range to attack or may have dropped target. In any case,
+ // don't evade if damage received within the last 10 seconds
+ // Does not apply to world bosses to prevent kiting to cities
+ if (!isWorldBoss() && !GetInstanceId())
+ if (time(NULL) - GetLastDamagedTime() <= MAX_AGGRO_RESET_TIME)
+ return target;
+
// last case when creature must not go to evade mode:
// it in combat but attacker not make any damage and not enter to aggro radius to have record in threat list
// for example at owner command to pet attack some far away creature
diff --git a/src/server/game/Entities/Unit/Unit.h b/src/server/game/Entities/Unit/Unit.h
index 7d9088bfabb..73d4cea3ba4 100755
--- a/src/server/game/Entities/Unit/Unit.h
+++ b/src/server/game/Entities/Unit/Unit.h
@@ -263,6 +263,8 @@ enum UnitRename
#define MAX_SPELL_POSSESS 8
#define MAX_SPELL_CONTROL_BAR 10
+#define MAX_AGGRO_RESET_TIME 10 // in seconds
+
enum Swing
{
NOSWING = 0,
@@ -2219,6 +2221,10 @@ class Unit : public WorldObject
// Movement info
Movement::MoveSpline * movespline;
+ // Part of Evade mechanics
+ time_t GetLastDamagedTime() const { return _lastDamagedTime; }
+ void SetLastDamagedTime(time_t val) { _lastDamagedTime = val; }
+
protected:
explicit Unit (bool isWorldObject);
@@ -2345,6 +2351,8 @@ class Unit : public WorldObject
Spell const* _focusSpell; ///> Locks the target during spell cast for proper facing
bool _isWalkingBeforeCharm; // Are we walking before we were charmed?
+
+ time_t _lastDamagedTime; // Part of Evade mechanics
};
namespace Trinity
diff --git a/src/server/game/Spells/SpellMgr.cpp b/src/server/game/Spells/SpellMgr.cpp
index 91041384200..57337d3c6a6 100644
--- a/src/server/game/Spells/SpellMgr.cpp
+++ b/src/server/game/Spells/SpellMgr.cpp
@@ -74,6 +74,9 @@ DiminishingGroup GetDiminishingReturnsGroupForSpell(SpellInfo const* spellproto,
// Pet charge effects (Infernal Awakening, Demon Charge)
if (spellproto->SpellVisual[0] == 2816 && spellproto->SpellIconID == 15)
return DIMINISHING_CONTROLLED_STUN;
+ // Frost Tomb
+ else if (spellproto->Id == 48400)
+ return DIMINISHING_NONE;
// Gnaw
else if (spellproto->Id == 47481)
return DIMINISHING_CONTROLLED_STUN;
@@ -3004,6 +3007,16 @@ void SpellMgr::LoadDbcDataCorrections()
switch (spellInfo->Id)
{
+ case 42730:
+ spellInfo->EffectTriggerSpell[EFFECT_1] = 42739;
+ break;
+ case 59735:
+ spellInfo->EffectTriggerSpell[EFFECT_1] = 59736;
+ break;
+ case 52611: // Summon Skeletons
+ case 52612: // Summon Skeletons
+ spellInfo->EffectMiscValueB[0] = 64;
+ break;
case 40244: // Simon Game Visual
case 40245: // Simon Game Visual
case 40246: // Simon Game Visual
diff --git a/src/server/scripts/Northrend/Nexus/Oculus/boss_eregos.cpp b/src/server/scripts/Northrend/Nexus/Oculus/boss_eregos.cpp
index e68e28be99b..76237fe1890 100644
--- a/src/server/scripts/Northrend/Nexus/Oculus/boss_eregos.cpp
+++ b/src/server/scripts/Northrend/Nexus/Oculus/boss_eregos.cpp
@@ -160,7 +160,7 @@ public:
_emeraldVoid = false;
if (me->FindNearestCreature(NPC_AMBER_DRAKE_VEHICLE, 500.0f, true))
_amberVoid = false;
- }
+ }
uint32 GetData(uint32 type)
{
diff --git a/src/server/scripts/Northrend/UtgardeKeep/UtgardeKeep/boss_ingvar_the_plunderer.cpp b/src/server/scripts/Northrend/UtgardeKeep/UtgardeKeep/boss_ingvar_the_plunderer.cpp
index 48667053373..ef17d6c0721 100644
--- a/src/server/scripts/Northrend/UtgardeKeep/UtgardeKeep/boss_ingvar_the_plunderer.cpp
+++ b/src/server/scripts/Northrend/UtgardeKeep/UtgardeKeep/boss_ingvar_the_plunderer.cpp
@@ -56,13 +56,16 @@ enum Events
EVENT_DARK_SMASH,
EVENT_DREADFUL_ROAR,
EVENT_WOE_STRIKE,
- EVENT_SHADOW_AXE
+ EVENT_SHADOW_AXE,
+ EVENT_JUST_TRANSFORMED,
+ EVENT_SUMMON_BANSHEE
};
enum Phases
{
PHASE_HUMAN = 1,
PHASE_UNDEAD,
+ PHASE_EVENT
};
enum Spells
@@ -83,7 +86,7 @@ enum Spells
SPELL_WOE_STRIKE = 42730,
ENTRY_THROW_TARGET = 23996,
- SPELL_SHADOW_AXE_SUMMON = 42749
+ SPELL_SHADOW_AXE_SUMMON = 42748
};
class boss_ingvar_the_plunderer : public CreatureScript
@@ -107,9 +110,6 @@ public:
InstanceScript* instance;
bool bIsUndead;
- bool bEventInProgress;
-
- uint32 uiSpawnResTimer;
void Reset()
{
@@ -117,7 +117,6 @@ public:
me->UpdateEntry(MOB_INGVAR_HUMAN);
bIsUndead = false;
- bEventInProgress = false;
me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IMMUNE_TO_PC);
me->SetStandState(UNIT_STAND_STATE_STAND);
@@ -130,13 +129,6 @@ public:
events.ScheduleEvent(EVENT_ENRAGE, urand(7,14)*IN_MILLISECONDS, 0, PHASE_HUMAN);
events.ScheduleEvent(EVENT_SMASH, urand(12,17)*IN_MILLISECONDS, 0, PHASE_HUMAN);
- events.ScheduleEvent(EVENT_DARK_SMASH, urand(14,22)*IN_MILLISECONDS, 0, PHASE_UNDEAD);
- events.ScheduleEvent(EVENT_DREADFUL_ROAR, urand(18,21)*IN_MILLISECONDS, 0, PHASE_UNDEAD);
- events.ScheduleEvent(EVENT_WOE_STRIKE, urand(10,14)*IN_MILLISECONDS, 0, PHASE_UNDEAD);
- events.ScheduleEvent(EVENT_SHADOW_AXE, 30*IN_MILLISECONDS, 0, PHASE_UNDEAD);
-
- uiSpawnResTimer = 3000;
-
if (instance)
instance->SetData(DATA_INGVAR_EVENT, NOT_STARTED);
}
@@ -156,37 +148,34 @@ public:
me->SetStandState(UNIT_STAND_STATE_DEAD);
// visuel hack end
- bEventInProgress = true;
- bIsUndead = true;
- events.SetPhase(PHASE_UNDEAD);
+ events.SetPhase(PHASE_EVENT);
+ events.ScheduleEvent(EVENT_SUMMON_BANSHEE, 3 * IN_MILLISECONDS, 0, PHASE_EVENT);
DoScriptText(YELL_DEAD_1, me);
}
- if (bEventInProgress)
- {
+ if (events.GetPhaseMask() & PHASE_EVENT)
damage = 0;
- }
}
void StartZombiePhase()
{
bIsUndead = true;
- bEventInProgress = false;
- me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE);
me->UpdateEntry(MOB_INGVAR_UNDEAD);
- me->SetInCombatWith(me->getVictim());
- me->GetMotionMaster()->MoveChase(me->getVictim());
+ events.ScheduleEvent(EVENT_JUST_TRANSFORMED, 2 * IN_MILLISECONDS, 0, PHASE_EVENT);
DoScriptText(YELL_AGGRO_2, me);
}
void EnterCombat(Unit* /*who*/)
{
- DoScriptText(YELL_AGGRO_1, me);
+ if (!bIsUndead)
+ DoScriptText(YELL_AGGRO_1, me);
if (instance)
instance->SetData(DATA_INGVAR_EVENT, IN_PROGRESS);
+
+ me->SetInCombatWithZone();
}
void JustDied(Unit* /*killer*/)
@@ -201,6 +190,15 @@ public:
}
}
+ void ScheduleSecondPhase()
+ {
+ events.SetPhase(PHASE_UNDEAD);
+ events.ScheduleEvent(EVENT_DARK_SMASH, urand(14,18)*IN_MILLISECONDS, 0, PHASE_UNDEAD);
+ events.ScheduleEvent(EVENT_DREADFUL_ROAR, urand(18,22)*IN_MILLISECONDS, 0, PHASE_UNDEAD);
+ events.ScheduleEvent(EVENT_WOE_STRIKE, urand(10,14)*IN_MILLISECONDS, 0, PHASE_UNDEAD);
+ events.ScheduleEvent(EVENT_SHADOW_AXE, 30*IN_MILLISECONDS, 0, PHASE_UNDEAD);
+ }
+
void KilledUnit(Unit* /*victim*/)
{
if (bIsUndead)
@@ -211,24 +209,9 @@ public:
void UpdateAI(const uint32 diff)
{
- if (!UpdateVictim())
+ if (!UpdateVictim() && !(events.GetPhaseMask() & PHASE_EVENT))
return;
- if (bEventInProgress)
- {
- if (uiSpawnResTimer)
- {
- if (uiSpawnResTimer <= diff)
- {
- DoCast(me, SPELL_SUMMON_BANSHEE); // Summons directly on caster position
- // DoCast(me, SPELL_SCOURG_RESURRECTION, true); // Not needed ?
- uiSpawnResTimer = 0;
- } else uiSpawnResTimer -= diff;
- }
-
- return;
- }
-
events.Update(diff);
if (me->HasUnitState(UNIT_STATE_CASTING))
@@ -245,7 +228,7 @@ public:
break;
case EVENT_STAGGERING_ROAR:
DoCast(me, SPELL_STAGGERING_ROAR);
- events.ScheduleEvent(EVENT_STAGGERING_ROAR, urand(18,21)*IN_MILLISECONDS, 0, PHASE_HUMAN);
+ events.ScheduleEvent(EVENT_STAGGERING_ROAR, urand(18,22)*IN_MILLISECONDS, 0, PHASE_HUMAN);
break;
case EVENT_ENRAGE:
DoCast(me, SPELL_ENRAGE);
@@ -253,16 +236,25 @@ public:
break;
case EVENT_SMASH:
DoCastVictim(SPELL_SMASH);
- events.ScheduleEvent(EVENT_SMASH, urand(12,17)*IN_MILLISECONDS, 0, PHASE_HUMAN);
+ events.ScheduleEvent(EVENT_SMASH, urand(12,16)*IN_MILLISECONDS, 0, PHASE_HUMAN);
break;
+ case EVENT_JUST_TRANSFORMED:
+ me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE);
+ me->SetInCombatWithZone();
+ me->GetMotionMaster()->MoveChase(me->getVictim());
+ ScheduleSecondPhase();
+ return;
+ case EVENT_SUMMON_BANSHEE:
+ DoCast(me, SPELL_SUMMON_BANSHEE);
+ return;
// PHASE TWO
case EVENT_DARK_SMASH:
DoCastVictim(SPELL_DARK_SMASH);
- events.ScheduleEvent(EVENT_DARK_SMASH, urand(14,22)*IN_MILLISECONDS, 0, PHASE_UNDEAD);
+ events.ScheduleEvent(EVENT_DARK_SMASH, urand(12,16)*IN_MILLISECONDS, 0, PHASE_UNDEAD);
break;
case EVENT_DREADFUL_ROAR:
DoCast(me, SPELL_DREADFUL_ROAR);
- events.ScheduleEvent(EVENT_DREADFUL_ROAR, urand(18,21)*IN_MILLISECONDS, 0, PHASE_UNDEAD);
+ events.ScheduleEvent(EVENT_DREADFUL_ROAR, urand(18,22)*IN_MILLISECONDS, 0, PHASE_UNDEAD);
break;
case EVENT_WOE_STRIKE:
DoCastVictim(SPELL_WOE_STRIKE);
@@ -271,8 +263,7 @@ public:
case EVENT_SHADOW_AXE:
if (Unit* target = SelectTarget(SELECT_TARGET_TOPAGGRO, 1))
{
- me->SummonCreature(ENTRY_THROW_TARGET, target->GetPositionX(), target->GetPositionY(), target->GetPositionZ(), 0, TEMPSUMMON_TIMED_DESPAWN, 2000);
- DoCast(me, SPELL_SHADOW_AXE_SUMMON);
+ DoCast(target, SPELL_SHADOW_AXE_SUMMON);
}
events.ScheduleEvent(EVENT_SHADOW_AXE, 30*IN_MILLISECONDS, 0, PHASE_UNDEAD);
break;
@@ -430,32 +421,34 @@ public:
{
}
- uint32 uiDespawnTimer;
-
void Reset()
{
- Unit* target = me->FindNearestCreature(ENTRY_THROW_TARGET, 50);
- if (target)
+ if (Creature* target = me->FindNearestCreature(ENTRY_THROW_TARGET, 50.0f))
{
- DoCast(me, SPELL_SHADOW_AXE_DAMAGE);
float x, y, z;
target->GetPosition(x, y, z);
- me->GetMotionMaster()->MovePoint(0, x, y, z);
+ me->GetMotionMaster()->MoveCharge(x, y, z, 42.0f, 28);
+ target->DisappearAndDie();
+ }
+ else
+ {
+ me->DisappearAndDie();
}
- uiDespawnTimer = 7000;
}
- void AttackStart(Unit* /*who*/) {}
- void MoveInLineOfSight(Unit* /*who*/) {}
- void EnterCombat(Unit* /*who*/) {}
- void UpdateAI(const uint32 diff)
+ void MovementInform(uint32 type, uint32 id)
{
- if (uiDespawnTimer <= diff)
+ if (type == POINT_MOTION_TYPE && id == 28)
{
- me->DealDamage(me, me->GetHealth());
- me->RemoveCorpse();
- uiDespawnTimer = 0;
- } else uiDespawnTimer -= diff;
+ DoCast(me, SPELL_SHADOW_AXE_DAMAGE);
+ me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_DISABLE_MOVE);
+ if (TempSummon* summon = me->ToTempSummon())
+ {
+ summon->UnSummon(10000);
+ }
+ else
+ me->DisappearAndDie();
+ }
}
};
};
diff --git a/src/server/scripts/Northrend/UtgardeKeep/UtgardeKeep/boss_keleseth.cpp b/src/server/scripts/Northrend/UtgardeKeep/UtgardeKeep/boss_keleseth.cpp
index b987b00fa5b..e718942d091 100644
--- a/src/server/scripts/Northrend/UtgardeKeep/UtgardeKeep/boss_keleseth.cpp
+++ b/src/server/scripts/Northrend/UtgardeKeep/UtgardeKeep/boss_keleseth.cpp
@@ -43,6 +43,9 @@ enum KelsethEncounter
NPC_FROSTTOMB = 23965,
NPC_SKELETON = 23970,
+ NPC_RUNEMAGE = 23960,
+ NPC_STRATEGIST = 23956,
+
SAY_START_COMBAT = 1,
SAY_SUMMON_SKELETONS,
SAY_FROST_TOMB,
@@ -118,10 +121,7 @@ public:
struct boss_kelesethAI : public BossAI
{
- boss_kelesethAI(Creature* creature) : BossAI(creature, DATA_PRINCEKELESETH_EVENT)
- {
- creature->SetReactState(REACT_DEFENSIVE);
- }
+ boss_kelesethAI(Creature* creature) : BossAI(creature, DATA_PRINCEKELESETH_EVENT){}
void Reset()
{
@@ -138,12 +138,37 @@ public:
onTheRocks = true;
}
- void EnterCombat(Unit* /*who*/)
+ void EnterCombat(Unit* who)
{
me->SetInCombatWithZone();
if (instance)
instance->SetData(DATA_PRINCEKELESETH_EVENT, IN_PROGRESS);
Talk(SAY_START_COMBAT);
+
+ if (!who)
+ return;
+
+ std::list<Creature*> runemages;
+ me->GetCreatureListWithEntryInGrid(runemages, NPC_RUNEMAGE, 60.0f);
+ if (!runemages.empty())
+ {
+ for (std::list<Creature*>::iterator itr = runemages.begin(); itr != runemages.end(); ++itr)
+ {
+ if ((*itr)->isAlive() && (*itr)->IsWithinLOSInMap(me))
+ (*itr)->AI()->AttackStart(who);
+ }
+ }
+
+ std::list<Creature*> strategists;
+ me->GetCreatureListWithEntryInGrid(strategists, NPC_STRATEGIST, 60.0f);
+ if (!strategists.empty())
+ {
+ for (std::list<Creature*>::iterator itr = strategists.begin(); itr != strategists.end(); ++itr)
+ {
+ if ((*itr)->isAlive() && (*itr)->IsWithinLOSInMap(me))
+ (*itr)->AI()->AttackStart(who);
+ }
+ }
}
void JustDied(Unit* /*killer*/)
@@ -168,10 +193,20 @@ public:
return 0;
}
- void ExecuteEvent(uint32 const eventId)
+ void UpdateAI(uint32 const diff)
{
- switch (eventId)
+ if (!UpdateVictim())
+ return;
+
+ events.Update(diff);
+
+ if (me->HasUnitState(UNIT_STATE_CASTING))
+ return;
+
+ while (uint32 eventId = events.ExecuteEvent())
{
+ switch (eventId)
+ {
case EVENT_SUMMON_SKELETONS:
Talk(SAY_SUMMON_SKELETONS);
SummonSkeletons();
@@ -192,7 +227,10 @@ public:
}
events.ScheduleEvent(EVENT_FROST_TOMB, urand(14,19)*IN_MILLISECONDS);
break;
+ }
}
+
+ DoMeleeAttackIfReady();
}
void SummonSkeletons()
@@ -225,7 +263,6 @@ public:
events.Reset();
events.ScheduleEvent(EVENT_DECREPIFY, urand(4,6)*IN_MILLISECONDS);
- DoCast(SPELL_BONE_ARMOR);
}
void DamageTaken(Unit* /*done_by*/, uint32 &damage)
@@ -278,6 +315,13 @@ public:
break;
case EVENT_SHADOW_FISSURE:
DoCast(me, SPELL_SHADOW_FISSURE, true);
+ if (TempSummon* temp = me->ToTempSummon())
+ {
+ if (Unit* summoner = temp->GetSummoner())
+ {
+ DoCast(summoner, SPELL_BONE_ARMOR);
+ }
+ }
me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE);
me->RemoveFlag(UNIT_FIELD_BYTES_1, UNIT_STAND_STATE_DEAD);
me->GetMotionMaster()->MoveChase(me->getVictim());
diff --git a/src/server/scripts/Northrend/UtgardeKeep/UtgardeKeep/boss_skarvald_dalronn.cpp b/src/server/scripts/Northrend/UtgardeKeep/UtgardeKeep/boss_skarvald_dalronn.cpp
index be8d60fbeb9..7c977250e79 100644
--- a/src/server/scripts/Northrend/UtgardeKeep/UtgardeKeep/boss_skarvald_dalronn.cpp
+++ b/src/server/scripts/Northrend/UtgardeKeep/UtgardeKeep/boss_skarvald_dalronn.cpp
@@ -47,6 +47,7 @@ enum eEnums
SPELL_CHARGE = 43651,
SPELL_STONE_STRIKE = 48583,
SPELL_SUMMON_SKARVALD_GHOST = 48613,
+ SPELL_ENRAGE = 48193,
MOB_SKARVALD_GHOST = 27390,
//Spells of Dalronn and his Ghost
MOB_DALRONN_THE_CONTROLLER = 24201,
@@ -58,6 +59,20 @@ enum eEnums
MOB_DALRONN_GHOST = 27389
};
+class SkarvaldChargePredicate
+{
+ public:
+ SkarvaldChargePredicate(Unit* unit) : me(unit) {}
+
+ bool operator() (WorldObject* object) const
+ {
+ return object->GetDistance2d(me) >= 5.0f && object->GetDistance2d(me) <= 30.0f;
+ }
+
+ private:
+ Unit* me;
+};
+
class boss_skarvald_the_constructor : public CreatureScript
{
public:
@@ -83,6 +98,7 @@ public:
uint32 Response_Timer;
uint32 Check_Timer;
bool Dalronn_isDead;
+ bool Enraged;
void Reset()
{
@@ -90,6 +106,7 @@ public:
StoneStrike_Timer = 10000;
Dalronn_isDead = false;
Check_Timer = 5000;
+ Enraged = false;
ghost = (me->GetEntry() == MOB_SKARVALD_GHOST);
if (!ghost && instance)
@@ -116,6 +133,15 @@ public:
}
}
+ void DamageTaken(Unit* /*attacker*/, uint32& damage)
+ {
+ if (!Enraged && !ghost && me->HealthBelowPctDamaged(15, damage))
+ {
+ Enraged = true;
+ DoCast(me, SPELL_ENRAGE);
+ }
+ }
+
void JustDied(Unit* killer)
{
if (!ghost && instance)
@@ -194,7 +220,7 @@ public:
if (Charge_Timer <= diff)
{
- DoCast(SelectTarget(SELECT_TARGET_RANDOM, 1), SPELL_CHARGE);
+ DoCast(SelectTarget(SELECT_TARGET_RANDOM, 0, SkarvaldChargePredicate(me)), SPELL_CHARGE);
Charge_Timer = 5000+rand()%5000;
} else Charge_Timer -= diff;
@@ -204,7 +230,8 @@ public:
StoneStrike_Timer = 5000+rand()%5000;
} else StoneStrike_Timer -= diff;
- DoMeleeAttackIfReady();
+ if (!me->HasUnitState(UNIT_STATE_CASTING))
+ DoMeleeAttackIfReady();
}
};
diff --git a/src/server/scripts/Northrend/UtgardeKeep/UtgardeKeep/utgarde_keep.cpp b/src/server/scripts/Northrend/UtgardeKeep/UtgardeKeep/utgarde_keep.cpp
index 2d53e7062eb..35bf7ee0b10 100644
--- a/src/server/scripts/Northrend/UtgardeKeep/UtgardeKeep/utgarde_keep.cpp
+++ b/src/server/scripts/Northrend/UtgardeKeep/UtgardeKeep/utgarde_keep.cpp
@@ -18,6 +18,8 @@
#include "ScriptMgr.h"
#include "ScriptedCreature.h"
#include "utgarde_keep.h"
+#include "SpellScript.h"
+#include "SpellAuraEffects.h"
uint32 entry_search[3] =
{
@@ -164,7 +166,82 @@ public:
};
};
+enum TickingTimeBomb
+{
+ SPELL_TICKING_TIME_BOMB_EXPLODE = 59687
+};
+class spell_ticking_time_bomb : public SpellScriptLoader
+{
+ public:
+ spell_ticking_time_bomb() : SpellScriptLoader("spell_ticking_time_bomb") { }
+
+ class spell_ticking_time_bomb_AuraScript : public AuraScript
+ {
+ PrepareAuraScript(spell_ticking_time_bomb_AuraScript);
+
+ bool Validate(SpellInfo const* /*spellEntry*/)
+ {
+ return (bool) sSpellMgr->GetSpellInfo(SPELL_TICKING_TIME_BOMB_EXPLODE);
+ }
+
+ void HandleOnEffectRemove(AuraEffect const* /* aurEff */, AuraEffectHandleModes /* mode */)
+ {
+ if (GetCaster() == GetTarget())
+ {
+ GetTarget()->CastSpell(GetTarget(), SPELL_TICKING_TIME_BOMB_EXPLODE, true);
+ }
+ }
+
+ void Register()
+ {
+ OnEffectRemove += AuraEffectRemoveFn(spell_ticking_time_bomb_AuraScript::HandleOnEffectRemove, EFFECT_0, SPELL_AURA_PERIODIC_DUMMY, AURA_EFFECT_HANDLE_REAL);
+ }
+ };
+
+ AuraScript* GetAuraScript() const
+ {
+ return new spell_ticking_time_bomb_AuraScript();
+ }
+};
+
+enum Fixate
+{
+ SPELL_FIXATE_TRIGGER = 40415
+};
+class spell_fixate : public SpellScriptLoader
+{
+ public:
+ spell_fixate() : SpellScriptLoader("spell_fixate") { }
+
+ class spell_fixate_SpellScript : public SpellScript
+ {
+ PrepareSpellScript(spell_fixate_SpellScript);
+
+ bool Validate(SpellInfo const* /*spellEntry*/)
+ {
+ return (bool) sSpellMgr->GetSpellInfo(SPELL_FIXATE_TRIGGER);
+ }
+
+ void HandleScriptEffect(SpellEffIndex /*effIndex*/)
+ {
+ // The unit has to cast the taunt on hisself, but we need the original caster for SPELL_AURA_MOD_TAUNT
+ GetCaster()->CastSpell(GetCaster(), SPELL_FIXATE_TRIGGER, true, 0, 0, GetHitUnit()->GetGUID());
+ }
+
+ void Register()
+ {
+ OnEffectHitTarget += SpellEffectFn(spell_fixate_SpellScript::HandleScriptEffect, EFFECT_2, SPELL_EFFECT_SCRIPT_EFFECT);
+ }
+ };
+
+ SpellScript* GetSpellScript() const
+ {
+ return new spell_fixate_SpellScript();
+ }
+};
void AddSC_utgarde_keep()
{
new npc_dragonflayer_forge_master();
+ new spell_ticking_time_bomb();
+ new spell_fixate();
}
diff --git a/src/server/scripts/Outland/shadowmoon_valley.cpp b/src/server/scripts/Outland/shadowmoon_valley.cpp
index 078f8f5a4f0..c84df2ee3d4 100644
--- a/src/server/scripts/Outland/shadowmoon_valley.cpp
+++ b/src/server/scripts/Outland/shadowmoon_valley.cpp
@@ -1899,6 +1899,96 @@ class spell_unlocking_zuluheds_chains : public SpellScriptLoader
}
};
+enum ShadowMoonTuberEnum
+{
+ SPELL_WHISTLE = 36652,
+ SPELL_SHADOWMOON_TUBER = 36462,
+
+ NPC_BOAR_ENTRY = 21195,
+ GO_SHADOWMOON_TUBER_MOUND = 184701,
+
+ POINT_TUBER = 1,
+ TYPE_BOAR = 1,
+ DATA_BOAR = 1
+};
+
+class npc_shadowmoon_tuber_node : public CreatureScript
+{
+public:
+ npc_shadowmoon_tuber_node() : CreatureScript("npc_shadowmoon_tuber_node") {}
+
+ struct npc_shadowmoon_tuber_nodeAI : public ScriptedAI
+ {
+ npc_shadowmoon_tuber_nodeAI(Creature* creature) : ScriptedAI(creature) {}
+
+ void Reset()
+ {
+ tapped = false;
+ tuberGUID = 0;
+ resetTimer = 60000;
+ }
+
+ void SetData(uint32 id, uint32 data)
+ {
+ if (id == TYPE_BOAR && data == DATA_BOAR)
+ {
+ // Spawn chest GO
+ DoCast(SPELL_SHADOWMOON_TUBER);
+
+ // Despawn the tuber
+ if (GameObject* tuber = me->FindNearestGameObject(GO_SHADOWMOON_TUBER_MOUND, 5.0f))
+ {
+ tuberGUID = tuber->GetGUID();
+ // @Workaround: find how to properly despawn the GO
+ tuber->SetPhaseMask(2, true);
+ }
+ }
+ }
+
+ void SpellHit(Unit* /*caster*/, const SpellInfo* spell)
+ {
+ if (!tapped && spell->Id == SPELL_WHISTLE)
+ {
+ if (Creature* boar = me->FindNearestCreature(NPC_BOAR_ENTRY, 30.0f))
+ {
+ // Disable trigger and force nearest boar to walk to him
+ tapped = true;
+ boar->SetWalk(false);
+ boar->GetMotionMaster()->MovePoint(POINT_TUBER, me->GetPositionX(), me->GetPositionY(), me->GetPositionZ());
+ }
+ }
+ }
+
+ void UpdateAI(const uint32 diff)
+ {
+ if (tapped)
+ {
+ if (resetTimer <= diff)
+ {
+ // Respawn the tuber
+ if (tuberGUID)
+ if (GameObject* tuber = GameObject::GetGameObject(*me, tuberGUID))
+ // @Workaround: find how to properly respawn the GO
+ tuber->SetPhaseMask(1, true);
+
+ Reset();
+ }
+ else
+ resetTimer -= diff;
+ }
+ }
+ private:
+ bool tapped;
+ uint64 tuberGUID;
+ uint32 resetTimer;
+ };
+
+ CreatureAI* GetAI(Creature* creature) const
+ {
+ return new npc_shadowmoon_tuber_nodeAI(creature);
+ }
+};
+
void AddSC_shadowmoon_valley()
{
new mob_mature_netherwing_drake();
@@ -1917,4 +2007,5 @@ void AddSC_shadowmoon_valley()
new mob_torloth_the_magnificent();
new npc_enraged_spirit();
new spell_unlocking_zuluheds_chains();
+ new npc_shadowmoon_tuber_node();
}