aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorNaddley <64811442+Naddley@users.noreply.github.com>2024-08-02 22:58:12 +0200
committerGitHub <noreply@github.com>2024-08-02 22:58:12 +0200
commit05046536edebed2a6a74e72dfa3dca774da74bb5 (patch)
tree488e3f945c3a6cc00aa453e8437d255501a2f856 /src
parent51872d50ff250df0bad130ab7843b69ea921a1f1 (diff)
Scripts/KingsRest: Implement The Golden Serpent encounter (#30100)
Diffstat (limited to 'src')
-rw-r--r--src/server/scripts/Zandalar/KingsRest/boss_golden_serpent.cpp365
-rw-r--r--src/server/scripts/Zandalar/KingsRest/instance_kings_rest.cpp31
-rw-r--r--src/server/scripts/Zandalar/KingsRest/kings_rest.cpp3
-rw-r--r--src/server/scripts/Zandalar/KingsRest/kings_rest.h8
-rw-r--r--src/server/scripts/Zandalar/zandalar_script_loader.cpp2
5 files changed, 405 insertions, 4 deletions
diff --git a/src/server/scripts/Zandalar/KingsRest/boss_golden_serpent.cpp b/src/server/scripts/Zandalar/KingsRest/boss_golden_serpent.cpp
new file mode 100644
index 00000000000..ed7f8433e33
--- /dev/null
+++ b/src/server/scripts/Zandalar/KingsRest/boss_golden_serpent.cpp
@@ -0,0 +1,365 @@
+/*
+ * 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 "AreaTrigger.h"
+#include "AreaTriggerAI.h"
+#include "CreatureAI.h"
+#include "CreatureAIImpl.h"
+#include "InstanceScript.h"
+#include "Map.h"
+#include "MotionMaster.h"
+#include "ObjectAccessor.h"
+#include "ScriptMgr.h"
+#include "ScriptedCreature.h"
+#include "SpellAuraEffects.h"
+#include "SpellScript.h"
+#include "SpellAuras.h"
+#include "SharedDefines.h"
+#include "TemporarySummon.h"
+#include "kings_rest.h"
+
+enum GoldenSerpentSpells
+{
+ SPELL_SPIT_GOLD = 265773,
+ SPELL_SERPENTINE_GUST = 265781,
+ SPELL_TAIL_TRASH = 265910,
+ SPELL_LUCRES_CALL = 265923,
+ SPELL_MOLTEN_GOLD_DAMAGE = 265914,
+ SPELL_MOLTEN_GOLD_AURA = 265915,
+ SPELL_LUSTER = 265991,
+ SPELL_BREAK_PLAYER_TARGETTING = 140562,
+ SPELL_GOLDEN_SERPENT_EMERGE_STATE = 271598
+};
+
+enum GoldenSerpentEvents
+{
+ EVENT_SPIT_GOLD = 1,
+ EVENT_SERPENTINE_GUST,
+ EVENT_TAIL_TRASH,
+ EVENT_LUCRES_CALL
+};
+
+enum GoldenSerpentTexts
+{
+ SAY_ANNOUNCE_ABSORB_ANIMATED_GOLD = 0
+};
+
+enum GoldenSerpentActions
+{
+ ACTION_ANNOUNCE_ABSORB_ANIMATED_GOLD = 1
+};
+
+enum GoldenSerpentNPCs
+{
+ NPC_ANIMATED_GOLD = 135406
+};
+
+enum GoldenSerpentMisc
+{
+ DISPLAY_INVISIBLE = 11686
+};
+
+enum GoldenSerpentPaths
+{
+ PATH_GOLDEN_SERPENT_SUBMERGE = 13532200,
+ PATH_GOLDEN_SERPENT_FLYING = 13532201,
+ PATH_GOLDEN_SERPENT_LANDING = 13532202,
+};
+
+constexpr Position GoldenSerpentRespawnPos = { -1058.8403f, 2615.1667f, 810.1519f, 5.113396f };
+
+// 135322 - The Golden Serpent
+struct boss_the_golden_serpent : public BossAI
+{
+ boss_the_golden_serpent(Creature* creature) : BossAI(creature, DATA_GOLDEN_SERPENT), _announcedLuster(false) { }
+
+ void JustAppeared() override
+ {
+ if (instance->GetBossState(DATA_GOLDEN_SERPENT) == NOT_STARTED)
+ {
+ me->SetDisableGravity(true, true);
+ me->SetAnimTier(AnimTier::Fly, true);
+ me->SetPlayHoverAnim(true);
+ me->SetFaction(FACTION_FRIENDLY);
+ me->SetUnitFlag(UnitFlags(UNIT_FLAG_UNINTERACTIBLE));
+ DoCast(SPELL_GOLDEN_SERPENT_EMERGE_STATE);
+ me->GetMotionMaster()->MovePath(PATH_GOLDEN_SERPENT_SUBMERGE, false);
+ }
+ }
+
+ void InitializeAI() override
+ {
+ if (instance->GetBossState(DATA_GOLDEN_SERPENT) != NOT_STARTED)
+ me->Relocate(GoldenSerpentRespawnPos);
+ }
+
+ void JustDied(Unit* /*killer*/) override
+ {
+ _JustDied();
+ instance->SendEncounterUnit(ENCOUNTER_FRAME_DISENGAGE, me);
+ }
+
+ void EnterEvadeMode(EvadeReason /*why*/) override
+ {
+ instance->SendEncounterUnit(ENCOUNTER_FRAME_DISENGAGE, me);
+
+ summons.DespawnAll();
+ _EnterEvadeMode();
+ _DespawnAtEvade();
+ }
+
+ void Reset() override
+ {
+ _announcedLuster = false;
+ }
+
+ void JustEngagedWith(Unit* who) override
+ {
+ BossAI::JustEngagedWith(who);
+ instance->SendEncounterUnit(ENCOUNTER_FRAME_ENGAGE, me, 1);
+ events.ScheduleEvent(EVENT_SPIT_GOLD, 9s);
+ events.ScheduleEvent(EVENT_SERPENTINE_GUST, 12s + 500ms);
+ events.ScheduleEvent(EVENT_TAIL_TRASH, 15s + 500ms);
+ events.ScheduleEvent(EVENT_LUCRES_CALL, 40s);
+ }
+
+ void WaypointPathEnded(uint32 /*nodeId*/, uint32 pathId) override
+ {
+ if (pathId == PATH_GOLDEN_SERPENT_SUBMERGE)
+ {
+ me->RemoveAurasDueToSpell(SPELL_GOLDEN_SERPENT_EMERGE_STATE);
+ me->GetMotionMaster()->MovePath(PATH_GOLDEN_SERPENT_FLYING, false);
+ }
+ else if (pathId == PATH_GOLDEN_SERPENT_FLYING)
+ me->GetMotionMaster()->MovePath(PATH_GOLDEN_SERPENT_LANDING, false);
+ else if (pathId == PATH_GOLDEN_SERPENT_LANDING)
+ {
+ me->SetAnimTier(AnimTier::Ground, true);
+ me->SetPlayHoverAnim(false);
+ me->SetFaction(FACTION_MONSTER_2);
+ me->RemoveUnitFlag(UnitFlags(UNIT_FLAG_UNINTERACTIBLE));
+ me->SetDisableGravity(false);
+ }
+ }
+
+ void DoAction(int32 action) override
+ {
+ if (action == ACTION_ANNOUNCE_ABSORB_ANIMATED_GOLD)
+ {
+ if (!_announcedLuster)
+ {
+ Talk(SAY_ANNOUNCE_ABSORB_ANIMATED_GOLD);
+ _announcedLuster = true;
+ }
+ }
+ }
+
+ void UpdateAI(uint32 diff) override
+ {
+ scheduler.Update(diff);
+
+ if (!UpdateVictim())
+ return;
+
+ events.Update(diff);
+
+ if (me->HasUnitState(UNIT_STATE_CASTING))
+ return;
+
+ while (uint32 eventId = events.ExecuteEvent())
+ {
+ switch (eventId)
+ {
+ case EVENT_SPIT_GOLD:
+ if (Unit* target = SelectTarget(SelectTargetMethod::Random, 0, 300.0f, true))
+ DoCast(target, SPELL_SPIT_GOLD);
+ events.ScheduleEvent(EVENT_SPIT_GOLD, 11s);
+ break;
+ case EVENT_SERPENTINE_GUST:
+ DoCastSelf(SPELL_SERPENTINE_GUST);
+ events.ScheduleEvent(EVENT_SERPENTINE_GUST, 21s + 500ms);
+ break;
+ case EVENT_TAIL_TRASH:
+ DoCastVictim(SPELL_TAIL_TRASH);
+ events.ScheduleEvent(EVENT_TAIL_TRASH, 17s);
+ break;
+ case EVENT_LUCRES_CALL:
+ DoCastSelf(SPELL_LUCRES_CALL);
+ _announcedLuster = false;
+ events.ScheduleEvent(EVENT_LUCRES_CALL, 41s + 500ms);
+ break;
+ default:
+ break;
+ }
+
+ if (me->HasUnitState(UNIT_STATE_CASTING))
+ return;
+ }
+ }
+private:
+ bool _announcedLuster;
+};
+
+// 135406 - Animated Gold
+struct npc_animated_gold : public ScriptedAI
+{
+ npc_animated_gold(Creature* creature) : ScriptedAI(creature), _isMoltenGoldCast(false) { }
+
+ void JustAppeared() override
+ {
+ DoCastSelf(SPELL_BREAK_PLAYER_TARGETTING);
+ me->SetReactState(REACT_PASSIVE);
+ }
+
+ void SpellHit(WorldObject* /*caster*/, SpellInfo const* spellInfo) override
+ {
+ if (spellInfo->Id == SPELL_LUCRES_CALL)
+ {
+ _scheduler.Schedule(3s, [this](TaskContext)
+ {
+ if (!me->HasAura(SPELL_MOLTEN_GOLD_AURA))
+ {
+ Creature* goldenSerpent = me->GetInstanceScript()->GetCreature(DATA_GOLDEN_SERPENT);
+ if (!goldenSerpent)
+ return;
+
+ me->GetMotionMaster()->Clear();
+ me->SetWalk(true);
+ me->GetMotionMaster()->MoveFollow(goldenSerpent, 2.0f, {}, {}, true);
+ _isMoltenGoldCast = false;
+ }
+ });
+ }
+ }
+
+ void DamageTaken(Unit* /*attacker*/, uint32& damage, DamageEffectType /*damageType*/, SpellInfo const* /*spellInfo = nullptr*/) override
+ {
+ if (me->GetHealth() <= damage)
+ {
+ damage = me->GetHealth() - 1;
+
+ if (!_isMoltenGoldCast)
+ {
+ me->CastSpell(nullptr, SPELL_MOLTEN_GOLD_AURA, false);
+ me->GetMotionMaster()->Clear();
+ me->StopMoving();
+ _isMoltenGoldCast = true;
+ }
+ }
+ }
+
+ void MovementInform(uint32 type, uint32 /*pointId*/) override
+ {
+ if (type == FOLLOW_MOTION_TYPE)
+ {
+ Creature* goldenSerpent = me->GetInstanceScript()->GetCreature(DATA_GOLDEN_SERPENT);
+ if (!goldenSerpent)
+ return;
+
+ if (!goldenSerpent->IsAIEnabled())
+ return;
+
+ me->DespawnOrUnsummon(4s);
+ me->GetMotionMaster()->Clear();
+ me->StopMoving();
+ me->CastSpell(nullptr, SPELL_LUSTER, true);
+ goldenSerpent->AI()->DoAction(ACTION_ANNOUNCE_ABSORB_ANIMATED_GOLD);
+ me->SetDisplayId(DISPLAY_INVISIBLE);
+ me->SetUnitFlag(UnitFlags(UNIT_FLAG_UNINTERACTIBLE));
+ }
+ }
+
+ void UpdateAI(uint32 diff) override
+ {
+ _scheduler.Update(diff);
+ }
+
+private:
+ TaskScheduler _scheduler;
+ bool _isMoltenGoldCast;
+};
+
+// 17570 - Molten Gold - Areatrigger
+struct at_kings_rest_molten_gold : AreaTriggerAI
+{
+ at_kings_rest_molten_gold(AreaTrigger* areatrigger) : AreaTriggerAI(areatrigger) { }
+
+ void OnUnitEnter(Unit* unit) override
+ {
+ if (!unit->IsPlayer())
+ return;
+
+ unit->CastSpell(nullptr, SPELL_MOLTEN_GOLD_DAMAGE , false);
+ }
+
+ void OnUnitExit(Unit* unit) override
+ {
+ unit->RemoveAurasDueToSpell(SPELL_MOLTEN_GOLD_DAMAGE);
+ }
+};
+
+// 265773 - Spit Gold
+class spell_kings_rest_spit_gold : public AuraScript
+{
+ void OnRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/)
+ {
+ if (GetTargetApplication()->GetRemoveMode() != AURA_REMOVE_BY_DEATH && GetTargetApplication()->GetRemoveMode() != AURA_REMOVE_BY_EXPIRE)
+ return;
+
+ if (Unit* caster = GetCaster())
+ caster->SummonCreature(NPC_ANIMATED_GOLD, GetTarget()->GetPosition());
+ }
+
+ void Register() override
+ {
+ AfterEffectRemove += AuraEffectRemoveFn(spell_kings_rest_spit_gold::OnRemove, EFFECT_0, SPELL_AURA_PERIODIC_DAMAGE, AURA_EFFECT_HANDLE_REAL);
+ }
+};
+
+// 265915 - Molten Gold
+class spell_kings_rest_molten_gold : public AuraScript
+{
+ void OnApply(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/)
+ {
+ GetTarget()->SetUnitFlag(UnitFlags(UNIT_FLAG_IMMUNE_TO_PC | UNIT_FLAG_UNINTERACTIBLE));
+ }
+
+ void OnRemove(AuraEffect const* /*aurEff*/, AuraEffectHandleModes /*mode*/)
+ {
+ GetTarget()->RemoveUnitFlag(UnitFlags(UNIT_FLAG_IMMUNE_TO_PC | UNIT_FLAG_UNINTERACTIBLE));
+ }
+
+ void Register() override
+ {
+ AfterEffectApply += AuraEffectRemoveFn(spell_kings_rest_molten_gold::OnApply, EFFECT_1, SPELL_AURA_TRANSFORM, AURA_EFFECT_HANDLE_REAL);
+ AfterEffectRemove += AuraEffectRemoveFn(spell_kings_rest_molten_gold::OnRemove, EFFECT_1, SPELL_AURA_TRANSFORM, AURA_EFFECT_HANDLE_REAL);
+ }
+};
+
+void AddSC_boss_golden_serpent()
+{
+ // Creature
+ RegisterKingsRestCreatureAI(boss_the_golden_serpent);
+ RegisterKingsRestCreatureAI(npc_animated_gold);
+
+ // Areatrigger
+ RegisterAreaTriggerAI(at_kings_rest_molten_gold);
+
+ // Spells
+ RegisterSpellScript(spell_kings_rest_spit_gold);
+ RegisterSpellScript(spell_kings_rest_molten_gold);
+}
diff --git a/src/server/scripts/Zandalar/KingsRest/instance_kings_rest.cpp b/src/server/scripts/Zandalar/KingsRest/instance_kings_rest.cpp
index 3b9e119505d..7e3d942edfd 100644
--- a/src/server/scripts/Zandalar/KingsRest/instance_kings_rest.cpp
+++ b/src/server/scripts/Zandalar/KingsRest/instance_kings_rest.cpp
@@ -15,7 +15,9 @@
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+#include "Creature.h"
#include "InstanceScript.h"
+#include "Map.h"
#include "ScriptMgr.h"
#include "kings_rest.h"
@@ -65,7 +67,36 @@ public:
LoadObjectData(creatureData, objectData);
LoadDoorData(doorData);
LoadDungeonEncounterData(encounters);
+
+ _serpentTempleSpawns = 0;
+ }
+
+ void OnCreatureCreate(Creature* creature) override
+ {
+ InstanceScript::OnCreatureCreate(creature);
+
+ if (creature->HasStringId("TempleEvent"))
+ _serpentTempleSpawns++;
}
+
+ void OnUnitDeath(Unit* unit) override
+ {
+ Creature* creature = unit->ToCreature();
+ if (!creature)
+ return;
+
+ if (creature->HasStringId("TempleEvent"))
+ {
+ _serpentTempleSpawns--;
+ if (_serpentTempleSpawns > 0)
+ return;
+
+ instance->SpawnGroupSpawn(SPAWN_GROUP_SERPENT_BOSS);
+ }
+ }
+
+ private:
+ uint8 _serpentTempleSpawns;
};
InstanceScript* GetInstanceScript(InstanceMap* map) const override
diff --git a/src/server/scripts/Zandalar/KingsRest/kings_rest.cpp b/src/server/scripts/Zandalar/KingsRest/kings_rest.cpp
index dcd18da9c40..00d545b3d3f 100644
--- a/src/server/scripts/Zandalar/KingsRest/kings_rest.cpp
+++ b/src/server/scripts/Zandalar/KingsRest/kings_rest.cpp
@@ -48,9 +48,6 @@ enum KingsRestData
// Conversation
CONV_ZUL_KINGS_REST_INTRO = 7690,
- // Spawngroups
- SPAWN_GROUP_PRE_FIRST_BOSS = 1255,
-
// Spells
SPELL_ZUL_SHADOWFORM = 269058,
SPELL_ZUL_TRASH_EVENT_STATE = 269905,
diff --git a/src/server/scripts/Zandalar/KingsRest/kings_rest.h b/src/server/scripts/Zandalar/KingsRest/kings_rest.h
index 6f6c69bd620..3a3b6e3dee2 100644
--- a/src/server/scripts/Zandalar/KingsRest/kings_rest.h
+++ b/src/server/scripts/Zandalar/KingsRest/kings_rest.h
@@ -28,7 +28,7 @@ uint32 const EncounterCount = 4;
enum KingsRestDataTypes
{
// Encounters
- DATA_GOLDEN_SERPENT = 0,
+ DATA_GOLDEN_SERPENT = 0,
DATA_MCHIMBA_THE_EMBALMER,
DATA_COUNCIL_OF_TRIBES,
DATA_KING_DAZAR,
@@ -61,6 +61,12 @@ enum KingsRestGameObjectIds
GO_KINGS_REST_LIQUID_GOLD_POOL = 289347
};
+enum KingsRestSpawnGroups
+{
+ SPAWN_GROUP_PRE_FIRST_BOSS = 1255,
+ SPAWN_GROUP_SERPENT_BOSS = 1256
+};
+
template <class AI, class T>
inline AI* GetKingsRestAI(T* obj)
{
diff --git a/src/server/scripts/Zandalar/zandalar_script_loader.cpp b/src/server/scripts/Zandalar/zandalar_script_loader.cpp
index bc16599fbb8..8145d99f20e 100644
--- a/src/server/scripts/Zandalar/zandalar_script_loader.cpp
+++ b/src/server/scripts/Zandalar/zandalar_script_loader.cpp
@@ -25,6 +25,7 @@ void AddSC_boss_cragmaw_the_infested();
// KingsRest
void AddSC_instance_kings_rest();
void AddSC_kings_rest();
+void AddSC_boss_golden_serpent();
// The name of this function should match:
// void Add${NameOfDirectory}Scripts()
@@ -38,4 +39,5 @@ void AddZandalarScripts()
//KingsRest
AddSC_instance_kings_rest();
AddSC_kings_rest();
+ AddSC_boss_golden_serpent();
}