Scripts/UtgardePinnacle: King Ymiron

- Updated to EventMaps
- Replaced manual summons with proper spells
- Fixed glitch where boss would resume fight/run back to his main target before the ancestor summon roleplay was over (it might still need few adjustments i.e fire on boat is currently missing)
- Implemented damage calculation for spell Dark Slash (http://www.wowhead.com/spell=48292) as previously the spell would do no damage and it's BasePoints is 0
This commit is contained in:
Nyeriah
2014-09-13 10:33:51 -03:00
parent 05aa0d51b1
commit 12e405bedd
3 changed files with 207 additions and 237 deletions

View File

@@ -0,0 +1,3 @@
DELETE FROM `spell_script_names` WHERE `spell_id` = 48292;
INSERT INTO `spell_script_names` (`spell_id`, `ScriptName`) VALUES
(48292, 'spell_ymiron_dark_slash');

View File

@@ -15,22 +15,16 @@
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/* Script Data Start
SDName: Boss ymiron
SDAuthor: LordVanMartin
SD%Complete:
SDComment:
SDCategory:
Script Data End */
#include "ScriptMgr.h"
#include "ScriptedCreature.h"
#include "utgarde_pinnacle.h"
#include "SpellInfo.h"
#include "SpellScript.h"
enum Spells
{
SPELL_BANE = 48294,
SPELL_BANE_HIT = 59203, // Checked for King's Bane achievement.
SPELL_DARK_SLASH = 48292,
SPELL_FETID_ROT = 48291,
SPELL_SCREAMS_OF_THE_DEAD = 51750,
@@ -47,8 +41,7 @@ enum Spells
SPELL_SPIRIT_FOUNT = 48380
};
//not in db
enum Yells
enum Texts
{
SAY_AGGRO = 0,
SAY_SLAY = 1,
@@ -59,18 +52,27 @@ enum Yells
SAY_SUMMON_TORGYN = 6
};
enum Creatures
enum Events
{
NPC_BJORN = 27303,
NPC_BJORN_VISUAL = 27304,
NPC_HALDOR = 27307,
NPC_HALDOR_VISUAL = 27310,
NPC_RANULF = 27308,
NPC_RANULF_VISUAL = 27311,
NPC_TORGYN = 27309,
NPC_TORGYN_VISUAL = 27312,
NPC_SPIRIT_FOUNT = 27339,
NPC_AVENGING_SPIRIT = 27386
EVENT_BANE = 1,
EVENT_FETID_ROT,
EVENT_DARK_SLASH,
EVENT_ANCESTORS_VENGEANCE,
EVENT_RESUME_COMBAT, // Handles react state and schedules the next event after roleplay ends.
EVENT_BJORN_SPIRIT_FOUNT,
EVENT_HALDOR_SPIRIT_STRIKE,
EVENT_RANULF_SPIRIT_BURST,
EVENT_TORGYN_SUMMON_AVENGING_SPIRITS
};
enum EventGroups
{
EVENT_GROUP_BASE_SPELLS = 1
};
enum MovePoints
{
POINT_BOAT
};
struct ActiveBoatStruct
@@ -78,14 +80,15 @@ struct ActiveBoatStruct
uint32 npc;
int32 say;
float MoveX, MoveY, MoveZ, SpawnX, SpawnY, SpawnZ, SpawnO;
uint32 event;
};
static ActiveBoatStruct ActiveBoat[4] =
{
{NPC_BJORN_VISUAL, SAY_SUMMON_BJORN, 404.379f, -335.335f, 104.756f, 413.594f, -335.408f, 107.995f, 3.157f},
{NPC_HALDOR_VISUAL, SAY_SUMMON_HALDOR, 380.813f, -335.069f, 104.756f, 369.994f, -334.771f, 107.995f, 6.232f},
{NPC_RANULF_VISUAL, SAY_SUMMON_RANULF, 381.546f, -314.362f, 104.756f, 370.841f, -314.426f, 107.995f, 6.232f},
{NPC_TORGYN_VISUAL, SAY_SUMMON_TORGYN, 404.310f, -314.761f, 104.756f, 413.992f, -314.703f, 107.995f, 3.157f}
{NPC_BJORN_VISUAL, SAY_SUMMON_BJORN, 404.379f, -335.335f, 104.756f, 413.594f, -335.408f, 107.995f, 3.157f, EVENT_BJORN_SPIRIT_FOUNT},
{NPC_HALDOR_VISUAL, SAY_SUMMON_HALDOR, 380.813f, -335.069f, 104.756f, 369.994f, -334.771f, 107.995f, 6.232f, EVENT_HALDOR_SPIRIT_STRIKE},
{NPC_RANULF_VISUAL, SAY_SUMMON_RANULF, 381.546f, -314.362f, 104.756f, 370.841f, -314.426f, 107.995f, 6.232f, EVENT_RANULF_SPIRIT_BURST},
{NPC_TORGYN_VISUAL, SAY_SUMMON_TORGYN, 404.310f, -314.761f, 104.756f, 413.992f, -314.703f, 107.995f, 3.157f, EVENT_TORGYN_SUMMON_AVENGING_SPIRITS}
};
enum Misc
@@ -103,89 +106,48 @@ public:
boss_ymironAI(Creature* creature) : BossAI(creature, DATA_KING_YMIRON)
{
Initialize();
// This ensures a random sequence of ancestors. Not sure if the order should change on reset or not, reason why this is left out of Initialize().
for (int i = 0; i < 4; ++i)
m_uiActiveOrder[i] = i;
ActiveOrder[i] = i;
for (int i = 0; i < 3; ++i)
{
int r = i + (rand32() % (4 - i));
int temp = m_uiActiveOrder[i];
m_uiActiveOrder[i] = m_uiActiveOrder[r];
m_uiActiveOrder[r] = temp;
int temp = ActiveOrder[i];
ActiveOrder[i] = ActiveOrder[r];
ActiveOrder[r] = temp;
}
}
void Initialize()
{
m_bIsWalking = false;
m_bIsPause = false;
m_bIsActiveWithBJORN = false;
m_bIsActiveWithHALDOR = false;
m_bIsActiveWithRANULF = false;
m_bIsActiveWithTORGYN = false;
kingsBane = true;
m_uiFetidRot_Timer = urand(8000, 13000);
m_uiBane_Timer = urand(18000, 23000);
m_uiDarkSlash_Timer = urand(28000, 33000);
m_uiAncestors_Vengeance_Timer = DUNGEON_MODE(60000, 45000);
m_uiPause_Timer = 0;
m_uiAbility_BJORN_Timer = 0;
m_uiAbility_HALDOR_Timer = 0;
m_uiAbility_RANULF_Timer = 0;
m_uiAbility_TORGYN_Timer = 0;
m_uiActivedNumber = 0;
m_uiHealthAmountModifier = 1;
m_uiHealthAmountMultipler = DUNGEON_MODE(20, 25);
m_uiActivedCreatureGUID = 0;
m_uiOrbGUID = 0;
ActivedNumber = 0;
HealthAmountModifier = 1;
HealthAmountMultipler = DUNGEON_MODE(20, 25);
ActiveAncestorGUID = 0;
SpiritFountGUID = 0;
}
bool m_bIsWalking;
bool m_bIsPause;
bool m_bIsActiveWithBJORN;
bool m_bIsActiveWithHALDOR;
bool m_bIsActiveWithRANULF;
bool m_bIsActiveWithTORGYN;
bool kingsBane; // Achievement King's Bane
uint8 m_uiActiveOrder[4];
uint8 m_uiActivedNumber;
uint32 m_uiFetidRot_Timer;
uint32 m_uiBane_Timer;
uint32 m_uiDarkSlash_Timer;
uint32 m_uiAncestors_Vengeance_Timer;
uint32 m_uiAbility_BJORN_Timer;
uint32 m_uiAbility_HALDOR_Timer;
uint32 m_uiAbility_RANULF_Timer;
uint32 m_uiAbility_TORGYN_Timer;
uint32 m_uiPause_Timer;
uint32 m_uiHealthAmountModifier;
uint32 m_uiHealthAmountMultipler;
uint64 m_uiActivedCreatureGUID;
uint64 m_uiOrbGUID;
void Reset() override
{
_Reset();
Initialize();
me->SetReactState(REACT_AGGRESSIVE);
}
void EnterCombat(Unit* /*who*/) override
{
_EnterCombat();
Talk(SAY_AGGRO);
events.ScheduleEvent(EVENT_BANE, urand(18000, 23000), EVENT_GROUP_BASE_SPELLS);
events.ScheduleEvent(EVENT_FETID_ROT, urand(8000, 13000), EVENT_GROUP_BASE_SPELLS);
events.ScheduleEvent(EVENT_DARK_SLASH, urand(28000, 33000), EVENT_GROUP_BASE_SPELLS);
events.ScheduleEvent(EVENT_ANCESTORS_VENGEANCE, DUNGEON_MODE(60000, 45000), EVENT_GROUP_BASE_SPELLS);
}
void SpellHitTarget(Unit* who, SpellInfo const* spell) override
{
if (who && who->GetTypeId() == TYPEID_PLAYER && spell->Id == 59302)
if (who && who->GetTypeId() == TYPEID_PLAYER && spell->Id == SPELL_BANE_HIT)
kingsBane = false;
}
@@ -197,161 +159,115 @@ public:
return 0;
}
void UpdateAI(uint32 diff) override
void MovementInform(uint32 type, uint32 pointId) override
{
if (m_bIsWalking)
{
if (m_uiPause_Timer <= diff)
{
Talk(ActiveBoat[m_uiActiveOrder[m_uiActivedNumber]].say);
DoCast(me, SPELL_CHANNEL_YMIRON_TO_SPIRIT); // should be on spirit
if (Creature* temp = me->SummonCreature(ActiveBoat[m_uiActiveOrder[m_uiActivedNumber]].npc, ActiveBoat[m_uiActiveOrder[m_uiActivedNumber]].SpawnX, ActiveBoat[m_uiActiveOrder[m_uiActivedNumber]].SpawnY, ActiveBoat[m_uiActiveOrder[m_uiActivedNumber]].SpawnZ, ActiveBoat[m_uiActiveOrder[m_uiActivedNumber]].SpawnO, TEMPSUMMON_CORPSE_DESPAWN, 0))
{
m_uiActivedCreatureGUID = temp->GetGUID();
temp->CastSpell(me, SPELL_CHANNEL_SPIRIT_TO_YMIRON, true);
temp->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NOT_SELECTABLE);
temp->SetDisableGravity(true);
switch (m_uiActiveOrder[m_uiActivedNumber])
{
case 0: m_bIsActiveWithBJORN = true; break;
case 1: m_bIsActiveWithHALDOR = true; break;
case 2: m_bIsActiveWithRANULF = true; break;
case 3: m_bIsActiveWithTORGYN = true; break;
}
}
m_bIsPause = true;
m_bIsWalking = false;
m_uiPause_Timer = 3000;
} else m_uiPause_Timer -= diff;
if (type != POINT_MOTION_TYPE)
return;
}
else if (m_bIsPause)
if (pointId == POINT_BOAT) // Check might not be needed.
{
if (m_uiPause_Timer <= diff)
Talk(ActiveBoat[ActiveOrder[ActivedNumber]].say);
if (Creature* ancestor = me->SummonCreature(ActiveBoat[ActiveOrder[ActivedNumber]].npc, ActiveBoat[ActiveOrder[ActivedNumber]].SpawnX, ActiveBoat[ActiveOrder[ActivedNumber]].SpawnY, ActiveBoat[ActiveOrder[ActivedNumber]].SpawnZ, ActiveBoat[ActiveOrder[ActivedNumber]].SpawnO, TEMPSUMMON_CORPSE_DESPAWN, 0))
{
m_uiAbility_BJORN_Timer = 5000;
m_uiAbility_HALDOR_Timer = 5000;
m_uiAbility_RANULF_Timer = 5000;
m_uiAbility_TORGYN_Timer = 5000;
m_bIsPause = false;
m_uiPause_Timer = 0;
} else m_uiPause_Timer -= diff;
return;
}
//Return since we have no target
if (!UpdateVictim())
return;
if (!m_bIsPause)
{
// Normal spells ------------------------------------------------------------------------
if (m_uiBane_Timer <= diff)
{
DoCast(me, SPELL_BANE);
m_uiBane_Timer = urand(20000, 25000);
} else m_uiBane_Timer -= diff;
if (m_uiFetidRot_Timer <= diff)
{
DoCastVictim(SPELL_FETID_ROT);
m_uiFetidRot_Timer = urand(10000, 15000);
} else m_uiFetidRot_Timer -= diff;
if (m_uiDarkSlash_Timer <= diff)
{
DoCastVictim(SPELL_DARK_SLASH);
m_uiDarkSlash_Timer = urand(30000, 35000);
} else m_uiDarkSlash_Timer -= diff;
if (m_uiAncestors_Vengeance_Timer <= diff)
{
DoCast(me, SPELL_ANCESTORS_VENGEANCE);
m_uiAncestors_Vengeance_Timer = DUNGEON_MODE(urand(60000, 65000), urand(45000, 50000));
} else m_uiAncestors_Vengeance_Timer -= diff;
// Abilities ------------------------------------------------------------------------------
if (m_bIsActiveWithBJORN && m_uiAbility_BJORN_Timer <= diff)
{
//DoCast(me, SPELL_SUMMON_SPIRIT_FOUNT); // works fine, but using summon has better control
if (Creature* temp = me->SummonCreature(NPC_SPIRIT_FOUNT, 385.0f + rand32() % 10, -330.0f + rand32() % 10, 104.756f, 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 180000))
{
temp->SetSpeed(MOVE_RUN, 0.4f);
temp->CastSpell(temp, SPELL_SPIRIT_FOUNT, true);
temp->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NOT_SELECTABLE);
temp->SetDisplayId(11686);
m_uiOrbGUID = temp->GetGUID();
}
m_bIsActiveWithBJORN = false; // only one orb
} else m_uiAbility_BJORN_Timer -= diff;
if (m_bIsActiveWithHALDOR && m_uiAbility_HALDOR_Timer <= diff)
{
DoCastVictim(SPELL_SPIRIT_STRIKE);
m_uiAbility_HALDOR_Timer = 5000; // overtime
} else m_uiAbility_HALDOR_Timer -= diff;
if (m_bIsActiveWithRANULF && m_uiAbility_RANULF_Timer <= diff)
{
DoCast(me, SPELL_SPIRIT_BURST);
m_uiAbility_RANULF_Timer = 10000; // overtime
} else m_uiAbility_RANULF_Timer -= diff;
if (m_bIsActiveWithTORGYN && m_uiAbility_TORGYN_Timer <= diff)
{
float x, y, z;
x = me->GetPositionX()-5;
y = me->GetPositionY()-5;
z = me->GetPositionZ();
for (uint8 i = 0; i < 4; ++i)
{
//DoCast(me, SPELL_SUMMON_AVENGING_SPIRIT); // works fine, but using summon has better control
if (Creature* temp = me->SummonCreature(NPC_AVENGING_SPIRIT, x + rand32() % 10, y + rand32() % 10, z, 0, TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT, 30000))
{
if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0))
{
temp->AddThreat(target, 0.0f);
temp->AI()->AttackStart(target);
}
}
}
m_uiAbility_TORGYN_Timer = 15000; // overtime
} else m_uiAbility_TORGYN_Timer -= diff;
// Health check -----------------------------------------------------------------------------
if (me->HealthBelowPct(100 - m_uiHealthAmountMultipler * m_uiHealthAmountModifier))
{
uint8 m_uiOrder = m_uiHealthAmountModifier - 1;
++m_uiHealthAmountModifier;
me->InterruptNonMeleeSpells(true);
DoCast(me, SPELL_SCREAMS_OF_THE_DEAD);
me->GetMotionMaster()->Clear();
me->StopMoving();
me->AttackStop();
me->GetMotionMaster()->MovePoint(0, ActiveBoat[m_uiActiveOrder[m_uiOrder]].MoveX, ActiveBoat[m_uiActiveOrder[m_uiOrder]].MoveY, ActiveBoat[m_uiActiveOrder[m_uiOrder]].MoveZ);
DespawnBoatGhosts(m_uiActivedCreatureGUID);
DespawnBoatGhosts(m_uiOrbGUID);
m_bIsActiveWithBJORN = false;
m_bIsActiveWithHALDOR = false;
m_bIsActiveWithRANULF = false;
m_bIsActiveWithTORGYN = false;
m_uiBane_Timer += 8000;
m_uiFetidRot_Timer += 8000;
m_uiDarkSlash_Timer += 8000;
m_uiAncestors_Vengeance_Timer += 8000;
m_uiActivedNumber = m_uiOrder;
m_bIsWalking = true;
m_uiPause_Timer = 2000;
return;
DoCast(ancestor, SPELL_CHANNEL_YMIRON_TO_SPIRIT);
ancestor->CastSpell(me, SPELL_CHANNEL_SPIRIT_TO_YMIRON, true);
ancestor->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NOT_SELECTABLE);
ancestor->SetDisableGravity(true);
ActiveAncestorGUID = ancestor->GetGUID();
}
DoMeleeAttackIfReady();
events.ScheduleEvent(EVENT_RESUME_COMBAT, 5000);
}
}
void JustSummoned(Creature* summon) override
{
switch (summon->GetEntry())
{
case NPC_SPIRIT_FOUNT:
summon->CastSpell(summon, SPELL_SPIRIT_FOUNT, true);
summon->SetDisplayId(11686);
SpiritFountGUID = summon->GetGUID();
break;
case NPC_AVENGING_SPIRIT:
if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0))
{
summon->AddThreat(target, 0.0f);
summon->AI()->AttackStart(target);
}
break;
default:
break;
}
summons.Summon(summon);
}
void DamageTaken(Unit* /*attacker*/, uint32& damage) override
{
if (me->HealthBelowPctDamaged(100 - HealthAmountMultipler * HealthAmountModifier, damage))
{
uint8 Order = HealthAmountModifier - 1;
++HealthAmountModifier;
me->InterruptNonMeleeSpells(true);
DoCast(me, SPELL_SCREAMS_OF_THE_DEAD);
me->AttackStop();
me->SetReactState(REACT_PASSIVE);
me->GetMotionMaster()->MovePoint(POINT_BOAT, ActiveBoat[ActiveOrder[Order]].MoveX, ActiveBoat[ActiveOrder[Order]].MoveY, ActiveBoat[ActiveOrder[Order]].MoveZ);
DespawnBoatGhosts(ActiveAncestorGUID);
DespawnBoatGhosts(SpiritFountGUID);
events.CancelEvent(ActiveBoat[ActiveOrder[ActivedNumber]].event); // Cancels the event started on the previous transition.
events.DelayEvents(10000, EVENT_GROUP_BASE_SPELLS);
ActivedNumber = Order;
}
}
void ExecuteEvent(uint32 eventId) override
{
switch (eventId)
{
case EVENT_BANE:
DoCast(SPELL_BANE);
events.ScheduleEvent(EVENT_BANE, urand(20000, 25000));
break;
case EVENT_FETID_ROT:
DoCastVictim(SPELL_FETID_ROT);
events.ScheduleEvent(EVENT_FETID_ROT, urand(10000, 15000));
break;
case EVENT_DARK_SLASH:
DoCastVictim(SPELL_DARK_SLASH);
events.ScheduleEvent(EVENT_DARK_SLASH, urand(30000, 35000));
break;
case EVENT_ANCESTORS_VENGEANCE:
DoCast(me, SPELL_ANCESTORS_VENGEANCE);
events.ScheduleEvent(EVENT_ANCESTORS_VENGEANCE, DUNGEON_MODE(urand(60000, 65000), urand(45000, 50000)));
break;
case EVENT_RESUME_COMBAT:
me->SetReactState(REACT_AGGRESSIVE);
events.ScheduleEvent(ActiveBoat[ActiveOrder[ActivedNumber]].event, 5000);
break;
case EVENT_BJORN_SPIRIT_FOUNT:
DoCast(SPELL_SUMMON_SPIRIT_FOUNT);
break;
case EVENT_HALDOR_SPIRIT_STRIKE:
DoCastVictim(SPELL_SPIRIT_STRIKE);
events.ScheduleEvent(EVENT_HALDOR_SPIRIT_STRIKE, 5000);
break;
case EVENT_RANULF_SPIRIT_BURST:
DoCast(me, SPELL_SPIRIT_BURST);
events.ScheduleEvent(EVENT_RANULF_SPIRIT_BURST, 10000);
break;
case EVENT_TORGYN_SUMMON_AVENGING_SPIRITS:
for (uint8 i = 0; i < 4; ++i)
DoCast(SPELL_SUMMON_AVENGING_SPIRIT);
events.ScheduleEvent(EVENT_TORGYN_SUMMON_AVENGING_SPIRITS, 15000);
break;
default:
break;
}
}
@@ -367,14 +283,24 @@ public:
Talk(SAY_SLAY);
}
void DespawnBoatGhosts(uint64& m_uiCreatureGUID)
void DespawnBoatGhosts(uint64& CreatureGUID)
{
if (m_uiCreatureGUID)
if (Creature* temp = ObjectAccessor::GetCreature(*me, m_uiCreatureGUID))
// @todo: fire visual after ancestor despawns.
if (CreatureGUID)
if (Creature* temp = ObjectAccessor::GetCreature(*me, CreatureGUID))
temp->DisappearAndDie();
m_uiCreatureGUID = 0;
CreatureGUID = 0;
}
private:
bool kingsBane; // Achievement King's Bane
uint8 ActiveOrder[4];
uint8 ActivedNumber;
uint32 HealthAmountModifier;
uint32 HealthAmountMultipler;
uint64 ActiveAncestorGUID;
uint64 SpiritFountGUID;
};
CreatureAI* GetAI(Creature* creature) const override
@@ -383,6 +309,34 @@ public:
}
};
// 48292 - Dark Slash
class spell_ymiron_dark_slash : public SpellScriptLoader
{
public:
spell_ymiron_dark_slash() : SpellScriptLoader("spell_ymiron_dark_slash") { }
class spell_ymiron_dark_slash_SpellScript : public SpellScript
{
PrepareSpellScript(spell_ymiron_dark_slash_SpellScript);
void HandleDamageCalc(SpellEffIndex /*effIndex*/)
{
if (Unit* target = GetHitUnit())
SetHitDamage(target->GetHealth() / 2);
}
void Register() override
{
OnEffectHitTarget += SpellEffectFn(spell_ymiron_dark_slash_SpellScript::HandleDamageCalc, EFFECT_0, SPELL_EFFECT_SCHOOL_DAMAGE);
}
};
SpellScript* GetSpellScript() const override
{
return new spell_ymiron_dark_slash_SpellScript();
}
};
class achievement_kings_bane : public AchievementCriteriaScript
{
public:
@@ -404,5 +358,6 @@ class achievement_kings_bane : public AchievementCriteriaScript
void AddSC_boss_ymiron()
{
new boss_ymiron();
new spell_ymiron_dark_slash();
new achievement_kings_bane();
}

View File

@@ -59,7 +59,19 @@ enum CreatureIds
NPC_RAVENOUS_FURBOLG = 26684,
NPC_MASSIVE_JORMUNGAR = 26685,
NPC_FEROCIOUS_RHINO = 26686,
NPC_PALEHOOF_ORB = 26688
NPC_PALEHOOF_ORB = 26688,
// Ymiron
NPC_BJORN = 27303,
NPC_BJORN_VISUAL = 27304,
NPC_HALDOR = 27307,
NPC_HALDOR_VISUAL = 27310,
NPC_RANULF = 27308,
NPC_RANULF_VISUAL = 27311,
NPC_TORGYN = 27309,
NPC_TORGYN_VISUAL = 27312,
NPC_SPIRIT_FOUNT = 27339,
NPC_AVENGING_SPIRIT = 27386
};
enum GameObjectIds