*Razorscale script rewrite. Still needs Harpoon and Stun implementation.
--HG-- branch : trunk
This commit is contained in:
@@ -18,77 +18,73 @@
|
|||||||
|
|
||||||
/* ScriptData
|
/* ScriptData
|
||||||
SDName: razorscale
|
SDName: razorscale
|
||||||
|
SDAuthor: MaXiMiUS
|
||||||
SD%Complete: 65
|
SD%Complete: 65
|
||||||
EndScriptData */
|
EndScriptData */
|
||||||
|
|
||||||
#include "precompiled.h"
|
#include "precompiled.h"
|
||||||
#include "ulduar.h"
|
#include "ulduar.h"
|
||||||
|
|
||||||
//wrong text ids. correct are between -1000000 AND -1999999
|
//not in db
|
||||||
//between -2000000 and -2999999 are custom texts so wtf?
|
|
||||||
#define SAY_AGGRO -2000000
|
#define SAY_AGGRO -2000000
|
||||||
#define SAY_KILL -2000001
|
#define SAY_KILL -2000001
|
||||||
#define SAY_PHASE_2_TRANS -2000002
|
#define SAY_PHASE_2_TRANS -2000002
|
||||||
#define SAY_PHASE_3_TRANS -2000003
|
#define SAY_PHASE_3_TRANS -2000003
|
||||||
#define EMOTE_BREATH -2000004
|
#define EMOTE_BREATH -2000004
|
||||||
|
|
||||||
#define SPELL_FLAMEBUFFET 64016
|
enum Spells
|
||||||
#define SPELL_FIREBALL 62796
|
|
||||||
|
|
||||||
#define SPELL_WINGBUFFET 62666
|
|
||||||
#define SPELL_FLAMEBREATH 63317
|
|
||||||
#define SPELL_FUSEARMOR 64771
|
|
||||||
#define SPELL_DEVOURINGFLAME 63014
|
|
||||||
|
|
||||||
#define SPELL_SUMMONADDS 17646
|
|
||||||
|
|
||||||
#define CREATURE_ADDS 33846
|
|
||||||
|
|
||||||
static float MovementLocations[4][3] =
|
|
||||||
{
|
{
|
||||||
{607.7, -281.9, 408.6},
|
SPELL_FLAMEBUFFET = 64016,
|
||||||
{602.0, -245.5, 424.7},
|
SPELL_FIREBALL = 62796,
|
||||||
{612.3, -230.8, 409.1},
|
|
||||||
{624.1, -251.8, 426.1}
|
SPELL_WINGBUFFET = 62666,
|
||||||
|
SPELL_FLAMEBREATH = 63317,
|
||||||
|
SPELL_FUSEARMOR = 64771,
|
||||||
|
SPELL_DEVOURINGFLAME = 63014
|
||||||
};
|
};
|
||||||
|
|
||||||
static float SpawnLocations[4][3] =
|
enum Mobs
|
||||||
{
|
{
|
||||||
{602.0, -248.1, 391.2},
|
NPC_DARK_RUNE_SENTINEL = 33846
|
||||||
{624.4, -232-4, 391.1},
|
|
||||||
{643.3, -256.4, 391.4},
|
|
||||||
{626.6, -271.5, 391.4},
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct TRINITY_DLL_DECL boss_razorscaleAI : public BossAI
|
struct TRINITY_DLL_DECL boss_razorscaleAI : public BossAI
|
||||||
{
|
{
|
||||||
boss_razorscaleAI(Creature *pCreature) : BossAI(pCreature, TYPE_RAZORSCALE) {}
|
boss_razorscaleAI(Creature *pCreature) : BossAI(pCreature, TYPE_RAZORSCALE) {}
|
||||||
|
|
||||||
uint32 Phase;
|
uint8 Phase;
|
||||||
|
|
||||||
uint32 FlameBreathTimer;
|
uint32 FlameBreathTimer;
|
||||||
uint32 FUSEARMORTimer;
|
uint32 FuseArmorTimer;
|
||||||
uint32 DEVOURINGFLAMETimer;
|
uint32 DevouringFlameTimer;
|
||||||
uint32 MovementTimer;
|
uint32 FlameBuffetTimer;
|
||||||
uint32 SummonAddsTimer;
|
uint32 SummonAddsTimer;
|
||||||
uint32 WingBuffetTimer;
|
uint32 WingBuffetTimer;
|
||||||
uint32 FireballTimer;
|
uint32 FireballTimer;
|
||||||
|
//uint32 StunTimer;
|
||||||
|
//uint32 CastSpellsTimer;
|
||||||
|
|
||||||
bool InitialSpawn;
|
bool InitialSpawn;
|
||||||
|
bool IsFlying;
|
||||||
|
|
||||||
void Reset()
|
void Reset()
|
||||||
{
|
{
|
||||||
Phase = 1;
|
Phase = 1;
|
||||||
|
|
||||||
|
FlyPhase(Phase, 0);
|
||||||
|
|
||||||
FlameBreathTimer = 20000;
|
FlameBreathTimer = 20000;
|
||||||
DEVOURINGFLAMETimer = 2000;
|
DevouringFlameTimer = 2000;
|
||||||
FUSEARMORTimer = 15000;
|
FuseArmorTimer = 15000;
|
||||||
MovementTimer = 3000;
|
FlameBuffetTimer = 3000;
|
||||||
SummonAddsTimer = 45000;
|
SummonAddsTimer = 45000;
|
||||||
WingBuffetTimer = 17000;
|
WingBuffetTimer = 17000;
|
||||||
FireballTimer = 18000;
|
FireballTimer = 18000;
|
||||||
|
//StunTimer = 30000;
|
||||||
|
//CastSpellsTimer = 0;
|
||||||
|
|
||||||
InitialSpawn = true;
|
InitialSpawn = true;
|
||||||
|
IsFlying = true;
|
||||||
|
|
||||||
m_creature->ApplySpellImmune(0, IMMUNITY_STATE, SPELL_AURA_MOD_TAUNT, true);
|
m_creature->ApplySpellImmune(0, IMMUNITY_STATE, SPELL_AURA_MOD_TAUNT, true);
|
||||||
m_creature->ApplySpellImmune(1, IMMUNITY_EFFECT,SPELL_EFFECT_ATTACK_ME, true);
|
m_creature->ApplySpellImmune(1, IMMUNITY_EFFECT,SPELL_EFFECT_ATTACK_ME, true);
|
||||||
@@ -122,55 +118,40 @@ struct TRINITY_DLL_DECL boss_razorscaleAI : public BossAI
|
|||||||
m_creature->GetMotionMaster()->MoveTargetedHome();
|
m_creature->GetMotionMaster()->MoveTargetedHome();
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((m_creature->GetHealth()*100 / m_creature->GetMaxHealth()) < 99 && Phase == 1)
|
if(!m_creature->getVictim()->GetCharmerOrOwnerPlayerOrPlayerItself()) // Victim is not controlled by a player (should never happen)
|
||||||
|
m_creature->getVictim()->CombatStop(); // Forcibly stop combat with this victim
|
||||||
|
|
||||||
|
if ((m_creature->GetHealth()*100 / m_creature->GetMaxHealth()) < 99 && Phase == 1) // TODO: Only land (exit Phase 1) if brought down with harpoon guns! This is important!
|
||||||
{
|
{
|
||||||
Phase = 2;
|
Phase = 2;
|
||||||
m_creature->AddUnitMovementFlag(MOVEMENTFLAG_LEVITATING);
|
DoScriptText(SAY_PHASE_2_TRANS, m_creature); // Audio: "Move quickly! She won't remain grounded for long!"
|
||||||
m_creature->SetHover(true);
|
|
||||||
m_creature->GetMotionMaster()->Clear(false);
|
|
||||||
m_creature->GetMotionMaster()->MoveIdle();
|
|
||||||
DoScriptText(SAY_PHASE_2_TRANS, m_creature);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((m_creature->GetHealth()*100 / m_creature->GetMaxHealth()) < 50 && Phase == 2)
|
if ((m_creature->GetHealth()*100 / m_creature->GetMaxHealth()) < 33 && Phase == 2) // Health under 33%, Razorscale can't fly anymore.
|
||||||
{
|
{
|
||||||
Phase = 3;
|
Phase = 3;
|
||||||
m_creature->RemoveUnitMovementFlag(MOVEMENTFLAG_LEVITATING);
|
DoScriptText(SAY_PHASE_3_TRANS, m_creature); // "Razorscale lands permanently!"
|
||||||
m_creature->SetHover(false);
|
// TODO: Cast Devouring Flame on all harpoon guns simultaneously, briefly after Phase 3 starts (lasts until the harpoon guns are destroyed)
|
||||||
m_creature->GetMotionMaster()->MovePoint(0, 619.6, -261.1, 391.471832);
|
|
||||||
DoStartMovement(m_creature->getVictim());
|
|
||||||
m_creature->RemoveUnitMovementFlag(MOVEMENTFLAG_WALK_MODE);
|
|
||||||
DoScriptText(SAY_PHASE_3_TRANS, m_creature);
|
|
||||||
m_creature->GetMotionMaster()->MoveChase(m_creature->getVictim());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Phase == 1 || Phase == 3)
|
/*
|
||||||
|
if (Phase == 2 && CastSpellsTimer > 0) // 5 seconds of spell casting, after stun breaks, during Phase 2
|
||||||
{
|
{
|
||||||
if (FlameBreathTimer <= diff)
|
if (CastSpellsTimer <= diff) // 5 seconds are up
|
||||||
{
|
Phase = 1; // Return to phase 1
|
||||||
DoCastVictim(SPELL_FLAMEBREATH);
|
else
|
||||||
FlameBreathTimer = 15000;
|
CastSpellsTimer -= diff;
|
||||||
} else FlameBreathTimer -= diff;
|
}*/
|
||||||
|
|
||||||
if (DEVOURINGFLAMETimer <= diff)
|
FlyPhase(Phase, diff);
|
||||||
{
|
|
||||||
std::list<Unit*> pTargets;
|
|
||||||
SelectTargetList(pTargets, 10, SELECT_TARGET_RANDOM, 100, true);
|
|
||||||
for (std::list<Unit*>::iterator i = pTargets.begin(); i != pTargets.end(); ++i)
|
|
||||||
if (!m_creature->HasInArc(M_PI, *i))
|
|
||||||
{
|
|
||||||
DoCast(*i, SPELL_DEVOURINGFLAME);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
DEVOURINGFLAMETimer = 10000;
|
if (Phase >= 2) // Ground Phase (Phase 3 = permanent ground phase)
|
||||||
} else DEVOURINGFLAMETimer -= diff;
|
{
|
||||||
|
if (FuseArmorTimer <= diff)
|
||||||
if (FUSEARMORTimer <= diff)
|
|
||||||
{
|
{
|
||||||
DoCastVictim(SPELL_FUSEARMOR);
|
DoCastVictim(SPELL_FUSEARMOR);
|
||||||
FUSEARMORTimer = 10000;
|
FuseArmorTimer = 10000;
|
||||||
} else FUSEARMORTimer -= diff;
|
} else FuseArmorTimer -= diff;
|
||||||
|
|
||||||
if (WingBuffetTimer <= diff)
|
if (WingBuffetTimer <= diff)
|
||||||
{
|
{
|
||||||
@@ -178,10 +159,53 @@ struct TRINITY_DLL_DECL boss_razorscaleAI : public BossAI
|
|||||||
WingBuffetTimer = urand(7000,14000);
|
WingBuffetTimer = urand(7000,14000);
|
||||||
} else WingBuffetTimer -= diff;
|
} else WingBuffetTimer -= diff;
|
||||||
|
|
||||||
|
if (FireballTimer <= diff)
|
||||||
|
{
|
||||||
|
if (Unit *pTarget = SelectTarget(SELECT_TARGET_RANDOM, 0, 200, true))
|
||||||
|
{
|
||||||
|
m_creature->SetInFront(pTarget);
|
||||||
|
DoCast(pTarget, SPELL_FIREBALL);
|
||||||
|
}
|
||||||
|
|
||||||
|
FireballTimer = 18000;
|
||||||
|
} else FireballTimer -= diff;
|
||||||
|
|
||||||
|
if (FlameBreathTimer <= diff)
|
||||||
|
{
|
||||||
|
DoScriptText(EMOTE_BREATH, m_creature); // TODO: "Razorscale takes a deep breath..."
|
||||||
|
DoCastVictim(SPELL_FLAMEBREATH);
|
||||||
|
FlameBreathTimer = 15000;
|
||||||
|
WingBuffetTimer = 0;
|
||||||
|
} else FlameBreathTimer -= diff;
|
||||||
|
|
||||||
|
if (Phase == 3)
|
||||||
|
{
|
||||||
|
if (FlameBuffetTimer <= diff)
|
||||||
|
{
|
||||||
|
DoScriptText(EMOTE_BREATH, m_creature);
|
||||||
|
std::list<Unit*> pTargets;
|
||||||
|
SelectTargetList(pTargets, HEROIC(3,9), SELECT_TARGET_RANDOM, 100, true);
|
||||||
|
uint8 i = 0;
|
||||||
|
for (std::list<Unit*>::iterator itr = pTargets.begin(); itr != pTargets.end();)
|
||||||
|
{
|
||||||
|
if (m_creature->HasInArc(M_PI, *itr))
|
||||||
|
{
|
||||||
|
DoCast(*itr, SPELL_FLAMEBUFFET, true);
|
||||||
|
++i;
|
||||||
|
}
|
||||||
|
if (++itr == pTargets.end() || i == HEROIC(3,9))
|
||||||
|
{
|
||||||
|
AttackStart(*--itr); // seems to attack targets randomly during perma-ground phase..
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
FlameBuffetTimer = 25000;
|
||||||
|
} else FlameBuffetTimer -= diff;
|
||||||
|
}
|
||||||
|
|
||||||
DoMeleeAttackIfReady();
|
DoMeleeAttackIfReady();
|
||||||
}
|
}
|
||||||
|
else if (Phase == 1) //Flying Phase
|
||||||
if (Phase == 2)
|
|
||||||
{
|
{
|
||||||
if (InitialSpawn)
|
if (InitialSpawn)
|
||||||
SummonAdds();
|
SummonAdds();
|
||||||
@@ -190,30 +214,25 @@ struct TRINITY_DLL_DECL boss_razorscaleAI : public BossAI
|
|||||||
|
|
||||||
if (FireballTimer <= diff)
|
if (FireballTimer <= diff)
|
||||||
{
|
{
|
||||||
std::list<Unit*> pTargets;
|
if (Unit *pTarget = SelectTarget(SELECT_TARGET_RANDOM, 0, 200, true))
|
||||||
SelectTargetList(pTargets, 10, SELECT_TARGET_RANDOM, 100, true);
|
{
|
||||||
for (std::list<Unit*>::iterator i = pTargets.begin(); i != pTargets.end(); ++i)
|
m_creature->SetInFront(pTarget);
|
||||||
if (!m_creature->HasInArc(M_PI, *i))
|
DoCast(pTarget, SPELL_FIREBALL);
|
||||||
{
|
}
|
||||||
DoCast(*i, SPELL_FIREBALL);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
FireballTimer = 18000;
|
FireballTimer = 18000;
|
||||||
} else FireballTimer -= diff;
|
} else FireballTimer -= diff;
|
||||||
|
|
||||||
if (MovementTimer <= diff)
|
if (DevouringFlameTimer <= diff)
|
||||||
{
|
{
|
||||||
if (urand(0,99) < 30)
|
if (Unit *pTarget = SelectTarget(SELECT_TARGET_RANDOM, 0, 200, true))
|
||||||
{
|
{
|
||||||
DoScriptText(EMOTE_BREATH, m_creature);
|
m_creature->SetInFront(pTarget);
|
||||||
if (Unit *pTarget = SelectTarget(SELECT_TARGET_RANDOM, 0, 100, true))
|
DoCast(pTarget, SPELL_DEVOURINGFLAME);
|
||||||
DoCast(pTarget, SPELL_FLAMEBUFFET);
|
|
||||||
}
|
}
|
||||||
else ChangePosition();
|
|
||||||
|
|
||||||
MovementTimer = 25000;
|
DevouringFlameTimer = 10000;
|
||||||
} else MovementTimer -= diff;
|
} else DevouringFlameTimer -= diff;
|
||||||
|
|
||||||
if (SummonAddsTimer <= diff)
|
if (SummonAddsTimer <= diff)
|
||||||
SummonAdds();
|
SummonAdds();
|
||||||
@@ -221,24 +240,75 @@ struct TRINITY_DLL_DECL boss_razorscaleAI : public BossAI
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ChangePosition()
|
|
||||||
{
|
|
||||||
/* Malfunctioning, Razorscale is flying around randomly, attacking players from hundreds of yards away.
|
|
||||||
uint8 random = urand(0,3);
|
|
||||||
m_creature->GetMotionMaster()->MovePoint(0, MovementLocations[random][0], MovementLocations[random][1], MovementLocations[random][2]); */
|
|
||||||
}
|
|
||||||
|
|
||||||
void SummonAdds()
|
void SummonAdds()
|
||||||
{
|
{
|
||||||
for (uint32 i = 0; i < 4; ++i)
|
// TODO: Adds will come in waves from mole machines. One mole can spawn a Dark Rune Watcher
|
||||||
|
// with 1-2 Guardians, or a lone Sentinel. Up to 4 mole machines can spawn adds at any given time.
|
||||||
|
uint8 random = urand(1,4);
|
||||||
|
for (uint8 i = 0; i < random; ++i)
|
||||||
{
|
{
|
||||||
uint8 random = urand(0,3);
|
Unit *pTarget = SelectTarget(SELECT_TARGET_RANDOM, 0, 200, true);
|
||||||
if (Creature *pAdd = m_creature->SummonCreature(CREATURE_ADDS, SpawnLocations[random][0], SpawnLocations[random][1], SpawnLocations[random][2], 0, TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN, 30000))
|
float x = std::max(500.0f, std::min(650.0f, pTarget->GetPositionX() + irand(-20,20))); // Safe range is between 500 and 650
|
||||||
if (Unit *pTarget = SelectTarget(SELECT_TARGET_RANDOM, 0, 200, true))
|
float y = std::max(-235.0f, std::min(-145.0f, pTarget->GetPositionY() + irand(-20,20))); // Safe range is between -235 and -145
|
||||||
pAdd->AI()->AttackStart(pTarget);
|
float z = m_creature->GetBaseMap()->GetHeight(x, y, MAX_HEIGHT); // Ground level
|
||||||
|
// TODO: Spawn drillers, then spawn adds 5 seconds later
|
||||||
|
if (Creature *pAdd = m_creature->SummonCreature(NPC_DARK_RUNE_SENTINEL, x, y, z, 0, TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN, 30000))
|
||||||
|
pAdd->AI()->AttackStart(pTarget);
|
||||||
}
|
}
|
||||||
SummonAddsTimer = 45000;
|
SummonAddsTimer = 45000;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void FlyPhase(uint8 Phase, const uint32 diff)
|
||||||
|
{
|
||||||
|
const float x = 587.54;
|
||||||
|
const float y = -174.92;
|
||||||
|
const float GroundLevel = m_creature->GetBaseMap()->GetHeight(x, y, MAX_HEIGHT);
|
||||||
|
const float FlightHeight = GroundLevel + 4.0f; // TODO: Fly out of range of attacks (442 is sufficient height for this), minus ~(10*number of harpoon gun chains attached to Razorscale)
|
||||||
|
|
||||||
|
if (Phase == 1) // Always flying during Phase 1
|
||||||
|
IsFlying = true;
|
||||||
|
|
||||||
|
m_creature->SetFlying(IsFlying);
|
||||||
|
m_creature->SendMovementFlagUpdate();
|
||||||
|
|
||||||
|
if (Phase == 1) // Flying Phase
|
||||||
|
{
|
||||||
|
if (m_creature->GetPositionZ() == FlightHeight) // Correct height, stop moving
|
||||||
|
m_creature->RemoveUnitMovementFlag(MOVEMENTFLAG_WALK_MODE);
|
||||||
|
else // Incorrect height
|
||||||
|
{
|
||||||
|
m_creature->AddUnitMovementFlag(MOVEMENTFLAG_WALK_MODE);
|
||||||
|
m_creature->GetMotionMaster()->MovePoint(0, x, y, FlightHeight);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else // Ground Phases
|
||||||
|
{
|
||||||
|
const float CurrentGroundLevel = m_creature->GetBaseMap()->GetHeight(m_creature->GetPositionX(), m_creature->GetPositionY(), MAX_HEIGHT);
|
||||||
|
//if (StunTimer == 30000) // Only fly around if not stunned.
|
||||||
|
//{
|
||||||
|
m_creature->AddUnitMovementFlag(MOVEMENTFLAG_WALK_MODE);
|
||||||
|
if (IsFlying && m_creature->GetPositionZ() > CurrentGroundLevel) // Fly towards the ground
|
||||||
|
m_creature->GetMotionMaster()->MovePoint(0, m_creature->GetPositionX(), m_creature->GetPositionY(), CurrentGroundLevel);
|
||||||
|
else
|
||||||
|
IsFlying = false; // Landed, no longer flying
|
||||||
|
//}
|
||||||
|
|
||||||
|
//if (!IsFlying &&Phase == 2 && CastSpellsTimer == 0 && StunTimer >= diff) // No longer flying, non-permanent ground phase, and not casting spells
|
||||||
|
//{
|
||||||
|
// TODO: Add stun here. 30 second stun after Razorscale is grounded by harpoon guns
|
||||||
|
//StunTimer -= diff;
|
||||||
|
//}
|
||||||
|
//else if (StunTimer != 30000 && (StunTimer < 0 || Phase == 3)) // Stun is active, and needs to end. Note: Stun breaks instantly if Phase 3 starts
|
||||||
|
//{
|
||||||
|
// TODO: Remove stun here.
|
||||||
|
//DoCast(SPELL_WINGBUFFET); // "Used in the beginning of the phase."
|
||||||
|
//WingBuffetTimer = urand(7000,14000);
|
||||||
|
//StunTimer = 30000; // Reinitialize the stun timer
|
||||||
|
//if (Phase == 2) // Non-permanent ground phase
|
||||||
|
// CastSpellsTimer = 5000; // Five seconds of casting before returning to Phase 1
|
||||||
|
//}
|
||||||
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
CreatureAI* GetAI_boss_razorscale(Creature* pCreature)
|
CreatureAI* GetAI_boss_razorscale(Creature* pCreature)
|
||||||
|
|||||||
Reference in New Issue
Block a user