fix(Scripts/DTK): Fix Oh Novos! achievement (#23539) (#23718)

This commit is contained in:
Traesh
2025-11-15 21:35:07 +01:00
committed by GitHub
parent 68694d145b
commit 8c963a11ce
4 changed files with 242 additions and 229 deletions

View File

@@ -0,0 +1,2 @@
DELETE FROM `smart_scripts` WHERE `entryorguid` = 27598 AND `source_type` = 0;
UPDATE `creature_template` SET `AIName` = '' WHERE `entry` = 27598;

View File

@@ -77,198 +77,216 @@ std::unordered_map<uint32, std::tuple <uint32, Position>> const npcSummon =
{ ROOM_STAIRS, { NPC_CRYSTAL_CHANNEL_TARGET, { -378.40f, -813.13f, 59.74f, 0.0f } } }, { ROOM_STAIRS, { NPC_CRYSTAL_CHANNEL_TARGET, { -378.40f, -813.13f, 59.74f, 0.0f } } },
}; };
class boss_novos : public CreatureScript // 26631
struct boss_novos : public BossAI
{ {
public: boss_novos(Creature* creature) : BossAI(creature, DATA_NOVOS)
boss_novos() : CreatureScript("boss_novos") { }
struct boss_novosAI : public BossAI
{ {
boss_novosAI(Creature* creature) : BossAI(creature, DATA_NOVOS)
{
}
void Reset() override
{
BossAI::Reset();
instance->SetBossState(DATA_NOVOS_CRYSTALS, IN_PROGRESS);
instance->SetBossState(DATA_NOVOS_CRYSTALS, NOT_STARTED);
_crystalCounter = 0;
_summonTargetRightGUID.Clear();
_summonTargetLeftGUID.Clear();
_stage = 0;
me->SetUnitFlag(UNIT_FLAG_DISABLE_MOVE);
me->RemoveUnitFlag(UNIT_FLAG_NON_ATTACKABLE);
me->RemoveUnitFlag(UNIT_FLAG_NOT_SELECTABLE);
_achievement = true;
}
uint32 GetData(uint32 data) const override
{
if (data == me->GetEntry())
return uint32(_achievement);
return 0;
}
void SetData(uint32 type, uint32) override
{
if (type == me->GetEntry())
_achievement = false;
}
void MoveInLineOfSight(Unit* /*who*/) override { }
void JustEngagedWith(Unit* who) override
{
Talk(SAY_AGGRO);
BossAI::JustEngagedWith(who);
events.ScheduleEvent(EVENT_SUMMON_FETID_TROLL, 3s);
events.ScheduleEvent(EVENT_SUMMON_SHADOWCASTER, 9s);
events.ScheduleEvent(EVENT_SUMMON_HULKING_CORPSE, 30s);
events.ScheduleEvent(EVENT_SUMMON_CRYSTAL_HANDLER, 20s);
events.ScheduleEvent(EVENT_CHECK_PHASE, 80s);
me->CastSpell(me, SPELL_ARCANE_BLAST, true);
me->CastSpell(me, SPELL_ARCANE_FIELD, true);
me->CastSpell(me, SPELL_DESPAWN_CRYSTAL_HANDLER, true);
for (auto& itr : npcSummon)
{
uint32 summonEntry;
Position summonPos;
std::tie(summonEntry, summonPos) = itr.second;
if (Creature* creature = me->SummonCreature(summonEntry, summonPos))
switch (itr.first)
{
case ROOM_LEFT:
_summonTargetLeftGUID = creature->GetGUID();
break;
case ROOM_RIGHT:
_summonTargetRightGUID = creature->GetGUID();
break;
}
}
me->SetGuidValue(UNIT_FIELD_TARGET, ObjectGuid::Empty);
me->RemoveAllAuras();
me->SetUnitFlag(UNIT_FLAG_NON_ATTACKABLE);
me->SetUnitFlag(UNIT_FLAG_NOT_SELECTABLE);
}
void JustDied(Unit* killer) override
{
Talk(SAY_DEATH);
BossAI::JustDied(killer);
instance->SetBossState(DATA_NOVOS_CRYSTALS, DONE);
}
void KilledUnit(Unit* /*victim*/) override
{
if (!events.HasTimeUntilEvent(EVENT_KILL_TALK))
{
Talk(SAY_KILL);
events.ScheduleEvent(EVENT_KILL_TALK, 6s);
}
}
void JustSummoned(Creature* summon) override
{
summons.Summon(summon);
if (me->HasUnitFlag(UNIT_FLAG_NOT_SELECTABLE) && summon->GetEntry() != NPC_CRYSTAL_CHANNEL_TARGET && summon->GetEntry() != NPC_CRYSTAL_HANDLER)
summon->SetReactState(REACT_DEFENSIVE);
else if (summon->GetEntry() != NPC_CRYSTAL_CHANNEL_TARGET)
summon->SetInCombatWithZone();
}
void UpdateAI(uint32 diff) override
{
if (!UpdateVictim())
return;
events.Update(diff);
switch (events.ExecuteEvent())
{
case EVENT_SUMMON_FETID_TROLL:
if (Creature* trigger = summons.GetCreatureWithEntry(NPC_CRYSTAL_CHANNEL_TARGET))
trigger->CastSpell(trigger, SPELL_SUMMON_FETID_TROLL_CORPSE, true, nullptr, nullptr, me->GetGUID());
events.ScheduleEvent(EVENT_SUMMON_FETID_TROLL, 3s);
break;
case EVENT_SUMMON_HULKING_CORPSE:
if (Creature* trigger = summons.GetCreatureWithEntry(NPC_CRYSTAL_CHANNEL_TARGET))
trigger->CastSpell(trigger, SPELL_SUMMON_HULKING_CORPSE, true, nullptr, nullptr, me->GetGUID());
events.ScheduleEvent(EVENT_SUMMON_HULKING_CORPSE, 30s);
break;
case EVENT_SUMMON_SHADOWCASTER:
if (Creature* trigger = summons.GetCreatureWithEntry(NPC_CRYSTAL_CHANNEL_TARGET))
trigger->CastSpell(trigger, SPELL_SUMMON_RISEN_SHADOWCASTER, true, nullptr, nullptr, me->GetGUID());
events.ScheduleEvent(EVENT_SUMMON_SHADOWCASTER, 10s);
break;
case EVENT_SUMMON_CRYSTAL_HANDLER:
if (_crystalCounter++ < 4)
{
Talk(SAY_SUMMONING_ADDS);
Talk(EMOTE_SUMMONING_ADDS);
if (Creature* target = ObjectAccessor::GetCreature(*me, _stage ? _summonTargetLeftGUID : _summonTargetRightGUID))
target->CastSpell(target, SPELL_SUMMON_CRYSTAL_HANDLER, true, nullptr, nullptr, me->GetGUID());
_stage = _stage ? 0 : 1;
events.ScheduleEvent(EVENT_SUMMON_CRYSTAL_HANDLER, 20s);
}
break;
case EVENT_CHECK_PHASE:
if (me->HasAura(SPELL_BEAM_CHANNEL))
{
events.ScheduleEvent(EVENT_CHECK_PHASE, 2s);
break;
}
events.Reset();
events.ScheduleEvent(EVENT_CAST_OFFENSIVE_SPELL, 3s);
events.ScheduleEvent(EVENT_SPELL_SUMMON_MINIONS, 10s);
me->RemoveUnitFlag(UNIT_FLAG_NON_ATTACKABLE);
me->RemoveUnitFlag(UNIT_FLAG_NOT_SELECTABLE);
me->InterruptNonMeleeSpells(false);
break;
case EVENT_CAST_OFFENSIVE_SPELL:
if (!me->HasUnitState(UNIT_STATE_CASTING))
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 100, true))
me->CastSpell(target, RAND(SPELL_BLIZZARD, SPELL_FROSTBOLT, SPELL_TOUCH_OF_MISERY), false);
events.ScheduleEvent(EVENT_CAST_OFFENSIVE_SPELL, 500ms);
break;
case EVENT_SPELL_SUMMON_MINIONS:
if (me->HasUnitState(UNIT_STATE_CASTING))
{
me->CastSpell(me, SPELL_SUMMON_MINIONS, false);
events.ScheduleEvent(EVENT_SPELL_SUMMON_MINIONS, 15s);
break;
}
events.ScheduleEvent(EVENT_SPELL_SUMMON_MINIONS, 500ms);
break;
}
}
bool CheckEvadeIfOutOfCombatArea() const override
{
return !SelectTargetFromPlayerList(80.0f);
}
private:
uint8 _crystalCounter;
uint8 _stage;
ObjectGuid _summonTargetRightGUID;
ObjectGuid _summonTargetLeftGUID;
bool _achievement;
};
CreatureAI* GetAI(Creature* creature) const override
{
return GetDraktharonKeepAI<boss_novosAI>(creature);
} }
void Reset() override
{
BossAI::Reset();
instance->SetBossState(DATA_NOVOS_CRYSTALS, IN_PROGRESS);
instance->SetBossState(DATA_NOVOS_CRYSTALS, NOT_STARTED);
_crystalCounter = 0;
_summonTargetRightGUID.Clear();
_summonTargetLeftGUID.Clear();
_stage = 0;
me->SetUnitFlag(UNIT_FLAG_DISABLE_MOVE);
me->RemoveUnitFlag(UNIT_FLAG_NON_ATTACKABLE);
me->RemoveUnitFlag(UNIT_FLAG_NOT_SELECTABLE);
_achievement = true;
}
uint32 GetData(uint32 data) const override
{
if (data == me->GetEntry())
return uint32(_achievement);
return 0;
}
void SetData(uint32 type, uint32) override
{
if (type == me->GetEntry())
_achievement = false;
}
void MoveInLineOfSight(Unit* /*who*/) override { }
void JustEngagedWith(Unit* who) override
{
Talk(SAY_AGGRO);
BossAI::JustEngagedWith(who);
events.ScheduleEvent(EVENT_SUMMON_FETID_TROLL, 3s);
events.ScheduleEvent(EVENT_SUMMON_SHADOWCASTER, 9s);
events.ScheduleEvent(EVENT_SUMMON_HULKING_CORPSE, 30s);
events.ScheduleEvent(EVENT_SUMMON_CRYSTAL_HANDLER, 20s);
events.ScheduleEvent(EVENT_CHECK_PHASE, 80s);
me->CastSpell(me, SPELL_ARCANE_BLAST, true);
me->CastSpell(me, SPELL_ARCANE_FIELD, true);
me->CastSpell(me, SPELL_DESPAWN_CRYSTAL_HANDLER, true);
for (auto& itr : npcSummon)
{
uint32 summonEntry;
Position summonPos;
std::tie(summonEntry, summonPos) = itr.second;
if (Creature* creature = me->SummonCreature(summonEntry, summonPos))
switch (itr.first)
{
case ROOM_LEFT:
_summonTargetLeftGUID = creature->GetGUID();
break;
case ROOM_RIGHT:
_summonTargetRightGUID = creature->GetGUID();
break;
}
}
me->SetGuidValue(UNIT_FIELD_TARGET, ObjectGuid::Empty);
me->RemoveAllAuras();
me->SetUnitFlag(UNIT_FLAG_NON_ATTACKABLE);
me->SetUnitFlag(UNIT_FLAG_NOT_SELECTABLE);
}
void JustDied(Unit* killer) override
{
Talk(SAY_DEATH);
BossAI::JustDied(killer);
instance->SetBossState(DATA_NOVOS_CRYSTALS, DONE);
}
void KilledUnit(Unit* /*victim*/) override
{
if (!events.HasTimeUntilEvent(EVENT_KILL_TALK))
{
Talk(SAY_KILL);
events.ScheduleEvent(EVENT_KILL_TALK, 6s);
}
}
void JustSummoned(Creature* summon) override
{
summons.Summon(summon);
// Phase 1
if (me->HasUnitFlag(UNIT_FLAG_NOT_SELECTABLE))
{
if (summon->GetEntry() != NPC_CRYSTAL_CHANNEL_TARGET && summon->GetEntry() != NPC_CRYSTAL_HANDLER)
summon->SetReactState(REACT_DEFENSIVE);
if (summon->GetEntry() == NPC_FETID_TROLL_CORPSE)
summon->GetMotionMaster()->MovePoint(1, -373.56f, -770.86f, 28.59f);
}
// Phase 2
else if (summon->GetEntry() != NPC_CRYSTAL_CHANNEL_TARGET)
summon->SetInCombatWithZone();
}
void SummonedCreatureDies(Creature* summon, Unit* /*killer*/) override
{
if (summon->GetEntry() == NPC_FETID_TROLL_CORPSE)
summon->DespawnOrUnsummon(10s);
}
void SummonMovementInform(Creature* summon, uint32 movementType, uint32 pathId) override
{
if (movementType == POINT_MOTION_TYPE && pathId == 1)
{
if (summon->GetEntry() == NPC_FETID_TROLL_CORPSE)
{
DoZoneInCombat(summon);
_achievement = false;
}
}
}
void UpdateAI(uint32 diff) override
{
if (!UpdateVictim())
return;
events.Update(diff);
switch (events.ExecuteEvent())
{
case EVENT_SUMMON_FETID_TROLL:
if (Creature* trigger = summons.GetCreatureWithEntry(NPC_CRYSTAL_CHANNEL_TARGET))
trigger->CastSpell(trigger, SPELL_SUMMON_FETID_TROLL_CORPSE, true, nullptr, nullptr, me->GetGUID());
events.ScheduleEvent(EVENT_SUMMON_FETID_TROLL, 3s);
break;
case EVENT_SUMMON_HULKING_CORPSE:
if (Creature* trigger = summons.GetCreatureWithEntry(NPC_CRYSTAL_CHANNEL_TARGET))
trigger->CastSpell(trigger, SPELL_SUMMON_HULKING_CORPSE, true, nullptr, nullptr, me->GetGUID());
events.ScheduleEvent(EVENT_SUMMON_HULKING_CORPSE, 30s);
break;
case EVENT_SUMMON_SHADOWCASTER:
if (Creature* trigger = summons.GetCreatureWithEntry(NPC_CRYSTAL_CHANNEL_TARGET))
trigger->CastSpell(trigger, SPELL_SUMMON_RISEN_SHADOWCASTER, true, nullptr, nullptr, me->GetGUID());
events.ScheduleEvent(EVENT_SUMMON_SHADOWCASTER, 10s);
break;
case EVENT_SUMMON_CRYSTAL_HANDLER:
if (_crystalCounter++ < 4)
{
Talk(SAY_SUMMONING_ADDS);
Talk(EMOTE_SUMMONING_ADDS);
if (Creature* target = ObjectAccessor::GetCreature(*me, _stage ? _summonTargetLeftGUID : _summonTargetRightGUID))
target->CastSpell(target, SPELL_SUMMON_CRYSTAL_HANDLER, true, nullptr, nullptr, me->GetGUID());
_stage = _stage ? 0 : 1;
events.ScheduleEvent(EVENT_SUMMON_CRYSTAL_HANDLER, 20s);
}
break;
case EVENT_CHECK_PHASE:
if (me->HasAura(SPELL_BEAM_CHANNEL))
{
events.ScheduleEvent(EVENT_CHECK_PHASE, 2s);
break;
}
events.Reset();
events.ScheduleEvent(EVENT_CAST_OFFENSIVE_SPELL, 3s);
events.ScheduleEvent(EVENT_SPELL_SUMMON_MINIONS, 10s);
me->RemoveUnitFlag(UNIT_FLAG_NON_ATTACKABLE);
me->RemoveUnitFlag(UNIT_FLAG_NOT_SELECTABLE);
me->InterruptNonMeleeSpells(false);
break;
case EVENT_CAST_OFFENSIVE_SPELL:
if (!me->HasUnitState(UNIT_STATE_CASTING))
if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 100, true))
me->CastSpell(target, RAND(SPELL_BLIZZARD, SPELL_FROSTBOLT, SPELL_TOUCH_OF_MISERY), false);
events.ScheduleEvent(EVENT_CAST_OFFENSIVE_SPELL, 500ms);
break;
case EVENT_SPELL_SUMMON_MINIONS:
if (me->HasUnitState(UNIT_STATE_CASTING))
{
me->CastSpell(me, SPELL_SUMMON_MINIONS, false);
events.ScheduleEvent(EVENT_SPELL_SUMMON_MINIONS, 15s);
break;
}
events.ScheduleEvent(EVENT_SPELL_SUMMON_MINIONS, 500ms);
break;
}
}
bool CheckEvadeIfOutOfCombatArea() const override
{
return !SelectTargetFromPlayerList(80.0f);
}
private:
uint8 _crystalCounter;
uint8 _stage;
ObjectGuid _summonTargetRightGUID;
ObjectGuid _summonTargetLeftGUID;
bool _achievement;
}; };
// 51403
class spell_novos_despawn_crystal_handler : public SpellScript class spell_novos_despawn_crystal_handler : public SpellScript
{ {
PrepareSpellScript(spell_novos_despawn_crystal_handler); PrepareSpellScript(spell_novos_despawn_crystal_handler);
@@ -290,6 +308,7 @@ class spell_novos_despawn_crystal_handler : public SpellScript
} }
}; };
// 47336
class spell_novos_crystal_handler_death_aura : public AuraScript class spell_novos_crystal_handler_death_aura : public AuraScript
{ {
PrepareAuraScript(spell_novos_crystal_handler_death_aura); PrepareAuraScript(spell_novos_crystal_handler_death_aura);
@@ -307,6 +326,7 @@ class spell_novos_crystal_handler_death_aura : public AuraScript
} }
}; };
// 59910
class spell_novos_summon_minions : public SpellScript class spell_novos_summon_minions : public SpellScript
{ {
PrepareSpellScript(spell_novos_summon_minions); PrepareSpellScript(spell_novos_summon_minions);
@@ -328,6 +348,7 @@ class spell_novos_summon_minions : public SpellScript
} }
}; };
// 2057
class achievement_oh_novos : public AchievementCriteriaScript class achievement_oh_novos : public AchievementCriteriaScript
{ {
public: public:
@@ -341,7 +362,7 @@ public:
void AddSC_boss_novos() void AddSC_boss_novos()
{ {
new boss_novos(); RegisterCreatureAIWithFactory(boss_novos, GetDraktharonKeepAI);
RegisterSpellScript(spell_novos_despawn_crystal_handler); RegisterSpellScript(spell_novos_despawn_crystal_handler);
RegisterSpellScript(spell_novos_crystal_handler_death_aura); RegisterSpellScript(spell_novos_crystal_handler_death_aura);
RegisterSpellScript(spell_novos_summon_minions); RegisterSpellScript(spell_novos_summon_minions);

View File

@@ -39,6 +39,7 @@ enum Creatures
NPC_KURZEL = 26664, NPC_KURZEL = 26664,
NPC_DRAKKARI_GUARDIAN = 26620, NPC_DRAKKARI_GUARDIAN = 26620,
NPC_RISEN_DRAKKARI_WARRIOR = 26635, NPC_RISEN_DRAKKARI_WARRIOR = 26635,
NPC_FETID_TROLL_CORPSE = 27598,
}; };
enum GameObjects enum GameObjects

View File

@@ -31,50 +31,39 @@ DoorData const doorData[] =
{ 0, 0, DOOR_TYPE_ROOM } { 0, 0, DOOR_TYPE_ROOM }
}; };
class instance_drak_tharon_keep : public InstanceMapScript struct instance_drak_tharon_keep : public InstanceScript
{ {
public: instance_drak_tharon_keep(Map* map) : InstanceScript(map)
instance_drak_tharon_keep() : InstanceMapScript("instance_drak_tharon_keep", MAP_DRAK_THARON_KEEP) { }
struct instance_drak_tharon_keep_InstanceScript : public InstanceScript
{ {
instance_drak_tharon_keep_InstanceScript(Map* map) : InstanceScript(map) SetHeaders(DataHeader);
{ SetBossNumber(MAX_ENCOUNTERS);
SetHeaders(DataHeader); LoadDoorData(doorData);
SetBossNumber(MAX_ENCOUNTERS); }
LoadDoorData(doorData);
}
void OnGameObjectCreate(GameObject* go) override void OnGameObjectCreate(GameObject* go) override
{
switch (go->GetEntry())
{
case GO_NOVOS_CRYSTAL_1:
case GO_NOVOS_CRYSTAL_2:
case GO_NOVOS_CRYSTAL_3:
case GO_NOVOS_CRYSTAL_4:
AddDoor(go);
break;
}
}
void OnGameObjectRemove(GameObject* go) override
{
switch (go->GetEntry())
{
case GO_NOVOS_CRYSTAL_1:
case GO_NOVOS_CRYSTAL_2:
case GO_NOVOS_CRYSTAL_3:
case GO_NOVOS_CRYSTAL_4:
RemoveDoor(go);
break;
}
}
};
InstanceScript* GetInstanceScript(InstanceMap* map) const override
{ {
return new instance_drak_tharon_keep_InstanceScript(map); switch (go->GetEntry())
{
case GO_NOVOS_CRYSTAL_1:
case GO_NOVOS_CRYSTAL_2:
case GO_NOVOS_CRYSTAL_3:
case GO_NOVOS_CRYSTAL_4:
AddDoor(go);
break;
}
}
void OnGameObjectRemove(GameObject* go) override
{
switch (go->GetEntry())
{
case GO_NOVOS_CRYSTAL_1:
case GO_NOVOS_CRYSTAL_2:
case GO_NOVOS_CRYSTAL_3:
case GO_NOVOS_CRYSTAL_4:
RemoveDoor(go);
break;
}
} }
}; };
@@ -121,7 +110,7 @@ class spell_dtk_summon_random_drakkari : public SpellScript
void AddSC_instance_drak_tharon_keep() void AddSC_instance_drak_tharon_keep()
{ {
new instance_drak_tharon_keep(); RegisterInstanceScript(instance_drak_tharon_keep, MAP_DRAK_THARON_KEEP);
RegisterSpellScript(spell_dtk_raise_dead_aura); RegisterSpellScript(spell_dtk_raise_dead_aura);
RegisterSpellScript(spell_dtk_summon_random_drakkari); RegisterSpellScript(spell_dtk_summon_random_drakkari);
} }