Scripts/EndTime: implement Echo of Jaina encounter

This commit is contained in:
Ovahlord
2022-04-26 19:44:32 +02:00
parent fbd2ae1ee1
commit ff783b2388
6 changed files with 750 additions and 11 deletions

View File

@@ -0,0 +1,80 @@
UPDATE `gameobject_template` SET `ScriptName`= 'go_end_time_time_transit_device' WHERE `entry` IN (209441, 209442);
UPDATE `gameobject_template` SET `ScriptName`= 'go_end_time_fragment_of_jainas_staff' WHERE `entry`= 209318;
UPDATE `gossip_menu_option` SET `OptionType`= 1 WHERE `MenuId`= 13321;
UPDATE `creature_template` SET `unit_flags`= 33587968, `unit_flags2`= 2099200, `AIName`= 'NullCreatureAI' WHERE `entry`= 54641;
UPDATE `creature_template` SET `unit_flags`= 33554432, `flags_extra`= `flags_extra` | 128, `AIName`= 'NullCreatureAI' WHERE `entry`= 54639;
UPDATE `creature_template` SET `unit_flags`= 33554432, `flags_extra`= `flags_extra` | 128, `ScriptName`= 'npc_echo_of_jaina_blink_target' WHERE `entry`= 54542;
UPDATE `creature_template` SET `unit_flags`= 33554432, `unit_flags2`= 34816, `flags_extra`= `flags_extra` | 128, `AIName`= 'NullCreatureAI' WHERE `entry`= 54446;
DELETE FROM `spawn_group_template` WHERE `groupId`= 460;
INSERT INTO `spawn_group_template` (`groupId`, `groupName`, `groupFlags`) VALUES
(460, 'End Time - Echo of Jaina - Jaina', 4);
DELETE FROM `spawn_group` WHERE `groupId`= 460;
INSERT INTO `spawn_group` (`groupId`, `spawnType`, `spawnId`) VALUES
(460, 0, 341769);
UPDATE `creature_template` SET `unit_flags`= 33088, `unit_flags2`= 2099200, `ScriptName`= 'boss_echo_of_jaina' WHERE `entry`= 54445;
UPDATE `creature_template` SET `flags_extra`= `flags_extra` | 128, `AIName`= 'NullCreatureAI' WHERE `entry`= 54494;
DELETE FROM `creature_text` WHERE `CreatureID`= 54445;
INSERT INTO `creature_text` (`CreatureID`, `GroupID`, `ID`, `Text`, `Type`, `Language`, `Probability`, `Emote`, `Duration`, `Sound`, `BroadcastTextId`, `comment`) VALUES
(54445, 0, 0, 'I don\'t know who you are, but I\'ll defend this shrine with my life. Leave, now, before we come to blows.', 12, 0, 100, 0, 0, 25920, 56573, 'Echo of Jaina - Intro'),
(54445, 1, 0, 'You asked for it.', 14, 0, 100, 0, 0, 25917, 53040, 'Echo of Jaina - Aggro'),
(54445, 2, 0, 'Why won\'t you give up?!', 14, 0, 100, 0, 0, 25926, 56580, 'Echo of Jaina - Blink 1'),
(54445, 2, 1, 'Perhaps this will cool your heads...', 14, 0, 100, 0, 0, 25924, 56578, 'Echo of Jaina - Blink 2'),
(54445, 2, 2, 'A little ice ought to quench the fire in your hearts...', 14, 0, 100, 0, 0, 25925, 56579, 'Echo of Jaina - Blink 3'),
(54445, 3, 0, 'I understand, now. Farewell, and good luck.', 12, 0, 100, 0, 0, 25919, 56574, 'Echo of Jaina - Death'),
(54445, 4, 0, 'You forced my hand.', 14, 0, 100, 0, 0, 25921, 56575, 'Echo of Jaina - Slay 1'),
(54445, 4, 1, 'I didn\'t want to do that.', 14, 0, 100, 0, 0, 25922, 56576, 'Echo of Jaina - Slay 2'),
(54445, 4, 2, 'I wish you\'d surrendered.', 14, 0, 100, 0, 0, 25923, 56577, 'Echo of Jaina - Slay 3');
DELETE FROM `spell_script_names` WHERE `ScriptName` IN
('spell_echo_of_jaina_face_highest_threat_target',
'spell_echo_of_jaina_frost_blade',
'spell_echo_of_jaina_disable_stalker_search',
'spell_echo_of_jaina_blink',
'spell_echo_of_jaina_flarecore',
'spell_echo_of_jaina_flarecore_triggered',
'spell_echo_of_jaina_flarecore_periodic');
INSERT INTO `spell_script_names` (`spell_id`, `ScriptName`) VALUES
(107897, 'spell_echo_of_jaina_face_highest_threat_target'),
(101337, 'spell_echo_of_jaina_frost_blade'),
(101540, 'spell_echo_of_jaina_disable_stalker_search'),
(101812, 'spell_echo_of_jaina_blink'),
(101944, 'spell_echo_of_jaina_flarecore'),
(101616, 'spell_echo_of_jaina_flarecore_triggered'),
(101588, 'spell_echo_of_jaina_flarecore_periodic');
DELETE FROM `creature_template_movement` WHERE `CreatureId` IN (54494, 54446);
INSERT INTO `creature_template_movement` (`CreatureId`, `Ground`, `Swim`, `Flight`, `Rooted`) VALUES
(54494, 0, 0, 2, 0),
(54446, 0, 0, 2, 1);
DELETE FROM `conditions` WHERE `SourceEntry` IN (101812, 101540) AND `SourceTypeOrReferenceId`= 13;
INSERT INTO `conditions` (`SourceTypeOrReferenceId`, `SourceGroup`, `SourceEntry`, `SourceId`, `ElseGroup`, `ConditionTypeOrReference`, `ConditionTarget`, `ConditionValue1`, `ConditionValue2`, `ConditionValue3`, `NegativeCondition`, `ErrorType`, `ScriptName`, `Comment`) VALUES
(13, 1, 101812, 0, 0, 31, 0, 3, 54542, 0, 0, 0, '', 'Blink - Target Blink Target'),
(13, 2, 101540, 0, 0, 31, 0, 3, 54445, 0, 0, 0, '', 'Disable Stalker Search - Target Echo of Jaina');
DELETE FROM `creature_onkill_reward` WHERE `creature_id`= 54445;
INSERT INTO `creature_onkill_reward` (`creature_id`, `RewOnKillRepFaction1`, `MaxStanding1`, `IsTeamAward1`, `RewOnKillRepValue1`, `TeamDependent`, `CurrencyId1`, `CurrencyCount1`) VALUES
(54445, 1162, 7, 0, 250, 0, 395, 7000);
UPDATE `creature_template`SET `mingold`= 17000, `maxgold`= 23000 WHERE `entry`= 54445;
DELETE FROM `creature_loot_template` WHERE `Entry`= 54445;
INSERT INTO `creature_loot_template` (`Entry`, `Reference`, `Item`, `Chance`, `GroupId`, `MinCount`, `MaxCount`, `LootMode`) VALUES
(54445, 0, 72808, 20, 1, 1, 1, 1),
(54445, 0, 72809, 15, 1, 1, 1, 1),
(54445, 0, 72805, 5, 1, 1, 1, 1),
(54445, 0, 72801, 5, 1, 1, 1, 1),
(54445, 0, 72804, 5, 1, 1, 1, 1),
(54445, 0, 72802, 5, 1, 1, 1, 1),
(54445, 0, 72799, 5, 1, 1, 1, 1),
(54445, 0, 72803, 5, 1, 1, 1, 1),
(54445, 0, 72806, 5, 1, 1, 1, 1),
(54445, 0, 72798, 5, 1, 1, 1, 1),
(54445, 0, 72800, 5, 1, 1, 1, 1),
(54445, 0, 72807, 5, 1, 1, 1, 1);

View File

@@ -0,0 +1,480 @@
/*
* This file is part of the TrinityCore Project. See AUTHORS file for Copyright information
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "end_time.h"
#include "InstanceScript.h"
#include "MotionMaster.h"
#include "PassiveAI.h"
#include "ScriptedCreature.h"
#include "ScriptMgr.h"
#include "Spell.h"
#include "SpellAuras.h"
#include "SpellAuraEffects.h"
#include "SpellScript.h"
enum Spells
{
// Echo of Jaina
SPELL_PYROBLAST = 101809,
SPELL_FROSTBOLT_VOLLEY = 101810,
SPELL_BLINK = 101812,
SPELL_FACE_HIGHEST_THREAT_TARGET = 107897,
SPELL_FROST_BLADES = 101339,
SPELL_FLARECORE = 101944,
// Frost Blades
SPELL_FROST_BLADES_PERIODIC = 101338,
// Blink Target
SPELL_DISABLE_STALKER_SEARCH = 101540,
// Flarecore
SPELL_FLARECORE_PERIODIC = 101588,
SPELL_FLARE_UP = 101589,
SPELL_UNSTABLE_FLARE = 101980,
SPELL_FLARE = 101587,
};
enum Events
{
// Echo of Jaina
EVENT_MAKE_ATTACKABLE = 1,
EVENT_PYROBLAST,
EVENT_FROSTBOLT_VOLLEY,
EVENT_BLINK,
EVENT_FACE_HIGHEST_THREAT_TARGET,
EVENT_FLARECORE,
// Blink Target
EVENT_DISABLE_STALKER_SEARCH
};
enum Actions
{
// Blink Target
ACTION_DISABLE_STALKER = 0
};
enum Phases
{
PHASE_INTRO = 1,
PHASE_COMBAT = 2
};
enum Texts
{
SAY_INTRO = 0,
SAY_AGGRO = 1,
SAY_BLINK = 2,
SAY_DEATH = 3,
SAY_SLAY = 4
};
enum Data
{
DATA_STALKER_DISABLED = 0
};
struct boss_echo_of_jaina : public BossAI
{
boss_echo_of_jaina(Creature* creature) : BossAI(creature, DATA_ECHO_OF_JAINA), _firstSpawn(false), _frostBladeCount(0), _frostboltVolleyCount(0) { }
void InitializeAI() override
{
_firstSpawn = instance->GetBossState(DATA_ECHO_OF_JAINA) == NOT_STARTED;
}
void JustAppeared() override
{
if (_firstSpawn)
{
Talk(SAY_INTRO);
events.SetPhase(PHASE_INTRO);
events.ScheduleEvent(EVENT_MAKE_ATTACKABLE, 9s, 0, PHASE_INTRO);
}
else
me->SetImmuneToPC(false);
}
void JustEngagedWith(Unit* who) override
{
BossAI::JustEngagedWith(who);
Talk(SAY_AGGRO, who);
instance->SendEncounterUnit(ENCOUNTER_FRAME_ENGAGE, me, 1);
events.SetPhase(PHASE_COMBAT);
events.ScheduleEvent(EVENT_PYROBLAST, 1ms);
events.ScheduleEvent(EVENT_FLARECORE, 15s);
events.ScheduleEvent(EVENT_BLINK, 19s);
}
void EnterEvadeMode(EvadeReason /*why*/) override
{
instance->SendEncounterUnit(ENCOUNTER_FRAME_DISENGAGE, me);
summons.DespawnAll();
_DespawnAtEvade();
}
void JustDied(Unit* killer) override
{
BossAI::JustDied(killer);
Talk(SAY_DEATH, killer);
instance->SendEncounterUnit(ENCOUNTER_FRAME_DISENGAGE, me);
}
void KilledUnit(Unit* victim) override
{
if (victim->IsPlayer())
Talk(SAY_SLAY, victim);
}
void JustSummoned(Creature* summon) override
{
summons.Summon(summon);
switch (summon->GetEntry())
{
case NPC_FROST_BLADE:
{
summon->CastSpell(nullptr, SPELL_FROST_BLADES_PERIODIC);
float stepSize = float(M_PI_2 / 3);
float angle = me->GetOrientation() - stepSize;
angle = Position::NormalizeOrientation(angle + stepSize * _frostBladeCount);
++_frostBladeCount;
float x = me->GetPositionX() + std::cos(angle) * 50.f;
float y = me->GetPositionY() + std::sin(angle) * 50.f;
summon->GetMotionMaster()->MovePoint(0, x, y, me->GetPositionZ(), false);
summon->DespawnOrUnsummon(6s + 500ms);
break;
}
case NPC_FLARECORE_EMBER:
summon->CastSpell(summon, SPELL_FLARECORE_PERIODIC);
break;
default:
break;
}
}
void UpdateAI(uint32 diff) override
{
if (!UpdateVictim() && !events.IsInPhase(PHASE_INTRO))
return;
events.Update(diff);
if (me->HasUnitState(UNIT_STATE_CASTING))
return;
while (uint32 eventId = events.ExecuteEvent())
{
switch (eventId)
{
case EVENT_MAKE_ATTACKABLE:
me->SetImmuneToPC(false);
break;
case EVENT_PYROBLAST:
DoCastVictim(SPELL_PYROBLAST);
events.Repeat(2s);
break;
case EVENT_FROSTBOLT_VOLLEY:
DoCastAOE(SPELL_FROSTBOLT_VOLLEY);
// Blink and Frost Blades have been pulled off, time to return to regular combat routine
me->SetReactState(REACT_AGGRESSIVE);
++_frostboltVolleyCount;
if (_frostboltVolleyCount < 3)
events.Repeat(1ms);
else
events.ScheduleEvent(EVENT_PYROBLAST, 1ms);
break;
case EVENT_BLINK:
me->AttackStop();
me->SetReactState(REACT_PASSIVE);
Talk(SAY_BLINK);
DoCastSelf(SPELL_BLINK);
_frostBladeCount = 0;
_frostboltVolleyCount = 0;
events.ScheduleEvent(EVENT_FACE_HIGHEST_THREAT_TARGET, 1ms);
events.ScheduleEvent(EVENT_FROSTBOLT_VOLLEY, 2s);
events.CancelEvent(EVENT_PYROBLAST);
events.Repeat(24s);
break;
case EVENT_FACE_HIGHEST_THREAT_TARGET:
DoCast(me->GetThreatManager().GetCurrentVictim(), SPELL_FACE_HIGHEST_THREAT_TARGET);
break;
case EVENT_FLARECORE:
DoCastAOE(SPELL_FLARECORE, CastSpellExtraArgs().AddSpellMod(SPELLVALUE_MAX_TARGETS, 1));
break;
default:
break;
}
if (me->HasUnitState(UNIT_STATE_CASTING))
return;
}
DoMeleeAttackIfReady();
}
private:
bool _firstSpawn;
uint8 _frostBladeCount;
uint8 _frostboltVolleyCount;
};
struct npc_echo_of_jaina_blink_target : public NullCreatureAI
{
npc_echo_of_jaina_blink_target(Creature* creature) : NullCreatureAI(creature), _disabled(false) { }
void JustAppeared() override
{
_events.ScheduleEvent(EVENT_DISABLE_STALKER_SEARCH, 2s + 500ms);
}
void DoAction(int32 action) override
{
switch (action)
{
case ACTION_DISABLE_STALKER:
_disabled = true;
break;
default:
break;
}
}
uint32 GetData(uint32 type) const override
{
switch (type)
{
case DATA_STALKER_DISABLED:
return _disabled ? 1 : 0;
default:
return 0;
}
}
void UpdateAI(uint32 diff) override
{
_events.Update(diff);
while (uint32 eventId = _events.ExecuteEvent())
{
switch (eventId)
{
case EVENT_DISABLE_STALKER_SEARCH:
_disabled = false;
DoCastAOE(SPELL_DISABLE_STALKER_SEARCH);
_events.Repeat(2s + 500ms);
break;
default:
break;
}
}
}
private:
EventMap _events;
bool _disabled;
};
class spell_echo_of_jaina_face_highest_threat_target : public SpellScript
{
bool Validate(SpellInfo const* /*spellInfo*/) override
{
return ValidateSpellInfo({ SPELL_FROST_BLADES });
}
void HandleDummyEffect(SpellEffIndex /*effIndex*/)
{
Unit* caster = GetCaster();
if (!caster)
return;
caster->SetFacingToObject(GetHitUnit());
caster->SetOrientationTowards(GetHitUnit()); // we need an updated orientation right now. No time to wait for the spline to update
for (uint8 i = 0; i < 3; ++i)
caster->CastSpell(caster, SPELL_FROST_BLADES);
}
void Register() override
{
OnEffectHitTarget.Register(&spell_echo_of_jaina_face_highest_threat_target::HandleDummyEffect, EFFECT_0, SPELL_EFFECT_DUMMY);
}
};
class spell_echo_of_jaina_frost_blade : public SpellScript
{
void FilterTargets(std::list<WorldObject*>& targets)
{
targets.remove_if([&](WorldObject const* target)
{
return target->GetExactDist2d(GetCaster()) > GetCaster()->GetCombatReach();
});
}
void Register() override
{
OnObjectAreaTargetSelect.Register(&spell_echo_of_jaina_frost_blade::FilterTargets, EFFECT_0, TARGET_UNIT_SRC_AREA_ENEMY);
}
};
class spell_echo_of_jaina_disable_stalker_search : public SpellScript
{
bool Validate(SpellInfo const* /*spellInfo*/) override
{
return ValidateSpellInfo({ SPELL_FROST_BLADES });
}
void HandleDummyEffect(SpellEffIndex /*effIndex*/)
{
Unit* caster = GetCaster();
if (!caster || !caster->IsCreature())
return;
if (CreatureAI* ai = caster->ToCreature()->AI())
ai->DoAction(ACTION_DISABLE_STALKER);
}
void Register() override
{
OnEffectHitTarget.Register(&spell_echo_of_jaina_disable_stalker_search::HandleDummyEffect, EFFECT_0, SPELL_EFFECT_DUMMY);
OnEffectHitTarget.Register(&spell_echo_of_jaina_disable_stalker_search::HandleDummyEffect, EFFECT_1, SPELL_EFFECT_DUMMY);
}
};
class spell_echo_of_jaina_blink : public SpellScript
{
void SetTarget(SpellDestination& target)
{
std::list<Creature*> blinkTargets;
GetCaster()->GetCreatureListWithEntryInGrid(blinkTargets, NPC_BLINK_TARGET, GetSpellInfo()->GetMaxRange());
if (blinkTargets.empty())
return;
blinkTargets.remove_if([](Creature const* creature)
{
if (CreatureAI const* ai = creature->AI())
if (ai->GetData(DATA_STALKER_DISABLED))
return true;
return false;
});
if (blinkTargets.size() > 1)
{
blinkTargets.sort(Trinity::ObjectDistanceOrderPred(GetCaster()));
blinkTargets.resize(1);
target = *blinkTargets.front();
}
}
void Register() override
{
OnDestinationTargetSelect.Register(&spell_echo_of_jaina_blink::SetTarget, EFFECT_0, TARGET_DEST_NEARBY_ENTRY);
}
};
class spell_echo_of_jaina_flarecore : public SpellScript
{
void HandleDummyEffect(SpellEffIndex /*effIndex*/)
{
if (Unit* caster = GetCaster())
caster->CastSpell(GetHitUnit(), GetEffectValue(), true);
}
void Register() override
{
OnEffectHitTarget.Register(&spell_echo_of_jaina_flarecore::HandleDummyEffect, EFFECT_0, SPELL_EFFECT_DUMMY);
}
};
class spell_echo_of_jaina_flarecore_triggered : public SpellScript
{
bool Validate(SpellInfo const* /*spellInfo*/) override
{
return ValidateSpellInfo({ SPELL_UNSTABLE_FLARE, SPELL_FLARECORE_PERIODIC });
}
void HandleDummyEffect(SpellEffIndex /*effIndex*/)
{
if (_detonated)
return;
Unit* caster = GetCaster();
if (!caster)
return;
caster->CastSpell(nullptr, SPELL_UNSTABLE_FLARE);
caster->RemoveAurasDueToSpell(SPELL_FLARECORE_PERIODIC);
_detonated = true;
}
void Register() override
{
OnEffectHitTarget.Register(&spell_echo_of_jaina_flarecore_triggered::HandleDummyEffect, EFFECT_0, SPELL_EFFECT_DUMMY);
}
private:
bool _detonated = false;
};
class spell_echo_of_jaina_flarecore_periodic : public AuraScript
{
bool Validate(SpellInfo const* /*spellInfo*/) override
{
return ValidateSpellInfo({ SPELL_FLARE_UP, SPELL_FLARE, SPELL_FLARECORE_PERIODIC });
}
void HandlePeriodic(AuraEffect const* aurEff)
{
if (!((aurEff->GetTickNumber() - 1) % 4))
GetTarget()->CastSpell(nullptr, SPELL_FLARE_UP);
}
void AfterRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/)
{
if (GetTargetApplication()->GetRemoveMode().HasFlag(AuraRemoveFlags::Expired))
{
GetTarget()->CastSpell(nullptr, SPELL_FLARE);
GetTarget()->RemoveAurasDueToSpell(SPELL_FLARECORE_PERIODIC);
}
if (Creature* creature = GetTarget()->ToCreature())
creature->DespawnOrUnsummon(5s + 500ms);
}
void Register() override
{
OnEffectPeriodic.Register(&spell_echo_of_jaina_flarecore_periodic::HandlePeriodic, EFFECT_0, SPELL_AURA_PERIODIC_TRIGGER_SPELL);
AfterEffectRemove.Register(&spell_echo_of_jaina_flarecore_periodic::AfterRemove, EFFECT_0, SPELL_AURA_PERIODIC_TRIGGER_SPELL, AURA_EFFECT_HANDLE_REAL);
}
};
void AddSC_boss_echo_of_jaina()
{
RegisterEndTimeCreatureAI(boss_echo_of_jaina);
RegisterEndTimeCreatureAI(npc_echo_of_jaina_blink_target);
RegisterSpellScript(spell_echo_of_jaina_face_highest_threat_target);
RegisterSpellScript(spell_echo_of_jaina_frost_blade);
RegisterSpellScript(spell_echo_of_jaina_disable_stalker_search);
RegisterSpellScript(spell_echo_of_jaina_blink);
RegisterSpellScript(spell_echo_of_jaina_flarecore);
RegisterSpellScript(spell_echo_of_jaina_flarecore_triggered);
RegisterSpellScript(spell_echo_of_jaina_flarecore_periodic);
}

View File

@@ -16,6 +16,8 @@
*/
#include "end_time.h"
#include "GameObject.h"
#include "GameObjectAI.h"
#include "InstanceScript.h"
#include "PassiveAI.h"
#include "Player.h"
@@ -50,7 +52,7 @@ enum Texts
SAY_ENCOUNTER_OUTRO_4 = 4
};
enum GossipMenus
enum GossipMenuIds
{
GOSSIP_MENU_ID_NOZDORMU = 13360,
GOSSIP_MENU_OPTION_ID_WELL_OF_ETERNITY = 0
@@ -152,7 +154,101 @@ private:
bool _introDone;
};
enum TimeTransitDeviceAreaIds
{
AREA_ID_ENTRYWAY_OF_TIME = 5796
};
enum TimeTransitDeviceSpells
{
SPELL_TELEPORT_TO_ENTRANCE = 102564,
SPELL_TELEPORT_TO_BLUE_DRAGONSHRINE = 102126
};
enum TimeTransitGossipMenuIds
{
GOSSIP_MENU_ID_SELECT_YOUR_DESTINATION = 13321
};
enum TimeTransitGossipIndexes
{
GOSSIP_INDEX_TELEPORT_TO_ENTRYWAY_OF_TIME = 0,
GOSSIP_INDEX_TELEPORT_TO_BLUE_DRAGONSHRINE_FIRST_ECHO = 3,
GOSSIP_INDEX_TELEPORT_TO_BLUE_DRAGONSHRINE_SECOND_ECHO = 7
};
static std::unordered_map<uint32 /*gossipMenuId*/, uint32 /*teleportSpellId*/> TransitDeviceTeleportSpells =
{
{ GOSSIP_INDEX_TELEPORT_TO_ENTRYWAY_OF_TIME, SPELL_TELEPORT_TO_ENTRANCE },
{ GOSSIP_INDEX_TELEPORT_TO_BLUE_DRAGONSHRINE_FIRST_ECHO, SPELL_TELEPORT_TO_BLUE_DRAGONSHRINE },
{ GOSSIP_INDEX_TELEPORT_TO_BLUE_DRAGONSHRINE_SECOND_ECHO, SPELL_TELEPORT_TO_BLUE_DRAGONSHRINE }
};
struct go_end_time_time_transit_device : public GameObjectAI
{
go_end_time_time_transit_device(GameObject* gameObject) : GameObjectAI(gameObject), _instance(nullptr) { }
void InitializeAI() override
{
_instance = me->GetInstanceScript();
}
bool GossipHello(Player* player) override
{
if (!_instance)
return false;
if (player->GetAreaId() != AREA_ID_ENTRYWAY_OF_TIME)
AddGossipItemFor(player, GOSSIP_MENU_ID_SELECT_YOUR_DESTINATION, GOSSIP_INDEX_TELEPORT_TO_ENTRYWAY_OF_TIME, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + GOSSIP_INDEX_TELEPORT_TO_ENTRYWAY_OF_TIME);
// @todo: world state based menu generation
AddGossipItemFor(player, GOSSIP_MENU_ID_SELECT_YOUR_DESTINATION, GOSSIP_INDEX_TELEPORT_TO_BLUE_DRAGONSHRINE_FIRST_ECHO, GOSSIP_SENDER_MAIN, GOSSIP_ACTION_INFO_DEF + GOSSIP_INDEX_TELEPORT_TO_BLUE_DRAGONSHRINE_FIRST_ECHO);
SendGossipMenuFor(player, player->GetGossipTextId(GOSSIP_MENU_ID_SELECT_YOUR_DESTINATION, me), me->GetGUID());
return true;
}
bool GossipSelect(Player* player, uint32 /*gossipMenuId*/, uint32 action) override
{
uint32 index = player->PlayerTalkClass->GetGossipOptionAction(action) - GOSSIP_ACTION_INFO_DEF;
player->CastSpell(player, TransitDeviceTeleportSpells[index]);
ClearGossipMenuFor(player);
return true;
}
private:
InstanceScript* _instance;
};
struct go_end_time_fragment_of_jainas_staff : public GameObjectAI
{
go_end_time_fragment_of_jainas_staff(GameObject* gameObject) : GameObjectAI(gameObject), _instance(nullptr) { }
void InitializeAI() override
{
_instance = me->GetInstanceScript();
}
bool GossipHello(Player* /*player*/) override
{
if (!_instance)
return false;
_instance->SetData(DATA_COLLECTED_FRAGMENT_OF_JAINAS_STAFF, 0);
me->DespawnOrUnsummon();
return true;
}
private:
InstanceScript* _instance;
};
void AddSC_end_time()
{
RegisterEndTimeCreatureAI(npc_end_time_nozdormu);
RegisterGameObjectAI(go_end_time_time_transit_device);
RegisterGameObjectAI(go_end_time_fragment_of_jainas_staff);
}

View File

@@ -32,7 +32,7 @@ enum ETDataTypes
{
// Bosses
DATA_ECHO_OF_BAINE = 0,
DATA_ECHO_OF_JANA = 1,
DATA_ECHO_OF_JAINA = 1,
DATA_ECHO_OF_SYLVANAS = 2,
DATA_ECHO_OF_TYRANDE = 3,
DATA_MUROZOND = 4,
@@ -40,19 +40,27 @@ enum ETDataTypes
// Additional Data
DATA_HOURGLASS_OF_TIME,
DATA_MUROZOND_INTRO,
DATA_NOZDORMU_BRONZE_DRAGON_SHRINE
DATA_NOZDORMU_BRONZE_DRAGON_SHRINE,
DATA_ARCANE_CIRCLE,
DATA_COLLECTED_FRAGMENT_OF_JAINAS_STAFF,
};
enum ETCreatures
{
// Bosses
BOSS_MUROZOND = 54432,
BOSS_MUROZOND = 54432,
// Encounter Related Creatures
/*Murozond*/
NPC_INFINITE_WARDEN = 54923,
NPC_INFINITE_SUPRESSOR = 54920,
NPC_NOZDORMU_DRAGON_SHRINES = 54751
NPC_INFINITE_WARDEN = 54923,
NPC_INFINITE_SUPRESSOR = 54920,
NPC_NOZDORMU_DRAGON_SHRINES = 54751,
/*Echo of Jaina*/
NPC_ARCANE_CIRCLE = 54639,
NPC_FROST_BLADE = 54494,
NPC_BLINK_TARGET = 54542,
NPC_FLARECORE_EMBER = 54446
};
enum ETGameObjectIds

View File

@@ -27,8 +27,9 @@
ObjectData const creatureData[] =
{
{ BOSS_MUROZOND, DATA_MUROZOND },
{ 0, 0 } // END
{ BOSS_MUROZOND, DATA_MUROZOND },
{ NPC_ARCANE_CIRCLE, DATA_ARCANE_CIRCLE },
{ 0, 0 } // END
};
ObjectData const gameobjectData[] =
@@ -48,7 +49,8 @@ enum Events
enum SpawnGroups
{
SPAWN_GROUP_ID_MUROZOND_CHEST = 437
SPAWN_GROUP_ID_MUROZOND_CHEST = 437,
SPAWN_GROUP_ID_ECHO_OF_JAINA = 460
};
enum AreaIds
@@ -56,6 +58,22 @@ enum AreaIds
AREA_ID_BRONZE_DRAGON_SHRINE = 5795
};
enum WorldStates
{
WORLD_STATE_ID_SHOW_COLLECTED_STAVE_FRAGMENTS = 6046,
WORLD_STATE_ID_COLLECTED_STAVE_FRAGMENTS = 6025
};
enum MapEvents
{
MAP_EVENT_AZURE_DRAGONSHRINE_ENTERED = 29225
};
enum Spells
{
SPELL_SUMMON_PHANTOM = 102200
};
std::array<Position const, 2> MurozondSpawnPositions =
{
Position(4288.125f, -456.40277f, 160.4989f, 2.98451f), // Initial spawn position
@@ -69,7 +87,8 @@ public:
struct instance_end_time_InstanceMapScript : public InstanceScript
{
instance_end_time_InstanceMapScript(InstanceMap* map) : InstanceScript(map), _killedInfiniteDragonkins(0)
instance_end_time_InstanceMapScript(InstanceMap* map) : InstanceScript(map),
_killedInfiniteDragonkins(0), _collectedStaffFragments(0)
{
SetHeaders(DataHeader);
SetBossNumber(EncounterCount);
@@ -77,6 +96,25 @@ public:
LoadObjectData(creatureData, gameobjectData);
}
void ProcessEvent(WorldObject* /*obj*/, uint32 eventId) override
{
if (_executedMapEvents.find(eventId) != _executedMapEvents.end())
return;
switch (eventId)
{
case MAP_EVENT_AZURE_DRAGONSHRINE_ENTERED:
if (GetBossState(DATA_ECHO_OF_JAINA) == DONE)
break;
instance->SetWorldState(WORLD_STATE_ID_SHOW_COLLECTED_STAVE_FRAGMENTS, 1);
break;
default:
break;
}
_executedMapEvents.insert(eventId);
}
void Create() override
{
InstanceScript::Create();
@@ -157,6 +195,14 @@ public:
else if (state == DONE)
instance->SpawnGroupSpawn(SPAWN_GROUP_ID_MUROZOND_CHEST);
break;
case DATA_ECHO_OF_JAINA:
if (state == IN_PROGRESS)
{
instance->SetWorldState(WORLD_STATE_ID_SHOW_COLLECTED_STAVE_FRAGMENTS, 0);
if (Creature* circle = GetCreature(DATA_ARCANE_CIRCLE))
circle->DespawnOrUnsummon();
}
break;
default:
break;
}
@@ -164,6 +210,30 @@ public:
return true;
}
void SetData(uint32 type, uint32 /*value*/) override
{
switch (type)
{
case DATA_COLLECTED_FRAGMENT_OF_JAINAS_STAFF:
if (GetBossState(DATA_ECHO_OF_JAINA) == DONE)
break;
++_collectedStaffFragments;
instance->SetWorldState(WORLD_STATE_ID_COLLECTED_STAVE_FRAGMENTS, _collectedStaffFragments);
if (_collectedStaffFragments < 16)
{
if (Creature* circle = GetCreature(DATA_ARCANE_CIRCLE))
circle->CastSpell(nullptr, SPELL_SUMMON_PHANTOM);
}
else
instance->SpawnGroupSpawn(SPAWN_GROUP_ID_ECHO_OF_JAINA);
break;
default:
break;
}
}
void Update(uint32 diff) override
{
_events.Update(diff);
@@ -184,6 +254,9 @@ public:
private:
EventMap _events;
uint8 _killedInfiniteDragonkins;
uint8 _collectedStaffFragments;
std::unordered_set<uint32> _executedMapEvents;
};
InstanceScript* GetInstanceScript(InstanceMap* map) const override

View File

@@ -49,6 +49,7 @@ void AddSC_culling_of_stratholme();
void AddSC_instance_culling_of_stratholme();
void AddSC_end_time(); //CoT End Time
void AddSC_boss_murozond();
void AddSC_boss_echo_of_jaina();
void AddSC_instance_end_time();
void AddSC_instance_well_of_eternity(); //CoT Well of Eternity
void AddSC_instance_hour_of_twilight(); //CoT Hour of Twilight
@@ -187,6 +188,7 @@ void AddKalimdorScripts()
AddSC_instance_culling_of_stratholme();
AddSC_end_time(); //CoT End Time
AddSC_boss_murozond();
AddSC_boss_echo_of_jaina();
AddSC_instance_end_time();
AddSC_instance_well_of_eternity(); //CoT Well of Eternity
AddSC_instance_hour_of_twilight(); //CoT Hour of Twilight