fix(Scripts/Ulduar): spawn keepers at Observation Ring on defeat (#25144)

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Andrew 2026-03-22 12:50:06 -03:00 committed by GitHub
parent 4e21de8d86
commit 11d4d01e7f
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 64 additions and 9 deletions

View file

@ -285,7 +285,6 @@ const Position KeepersPos[4] =
const uint32 TABLE_KEEPER_ENTRY[4] = {NPC_FREYA_KEEPER, NPC_HODIR_KEEPER, NPC_MIMIRON_KEEPER, NPC_THORIM_KEEPER};
const uint32 TABLE_GOSSIP_ENTRY[4] = {NPC_FREYA_GOSSIP, NPC_HODIR_GOSSIP, NPC_MIMIRON_GOSSIP, NPC_THORIM_GOSSIP};
const uint32 TABLE_KEEPER_TYPE[4] = {BOSS_FREYA, BOSS_HODIR, BOSS_MIMIRON, BOSS_THORIM};
static LocationsXY yoggPortalLoc[] =
{
@ -505,8 +504,17 @@ struct boss_yoggsaron_sara : public ScriptedAI
void DespawnGossipKeepers()
{
static uint32 const gossipData[] =
{
DATA_FREYA_GOSSIP, DATA_HODIR_GOSSIP,
DATA_MIMIRON_GOSSIP, DATA_THORIM_GOSSIP
};
for (uint8 i = KEEPER_FREYA; i <= KEEPER_THORIM; i++)
{
summons.DespawnEntry(TABLE_GOSSIP_ENTRY[i]);
if (Creature* keeper = m_pInstance->GetCreature(gossipData[i]))
keeper->DespawnOrUnsummon();
}
}
void UpdateKeeperSpawns()
@ -518,11 +526,6 @@ struct boss_yoggsaron_sara : public ScriptedAI
if (!summons.HasEntry(TABLE_KEEPER_ENTRY[i]))
me->SummonCreature(TABLE_KEEPER_ENTRY[i], KeepersPos[i]);
}
else if (m_pInstance->GetData(TABLE_KEEPER_TYPE[i]) == DONE)
{
if (!summons.HasEntry(TABLE_GOSSIP_ENTRY[i]))
me->SummonCreature(TABLE_GOSSIP_ENTRY[i], GossipKeepersPos[i]);
}
}
}

View file

@ -39,6 +39,32 @@ DoorData const doorData[] =
{ 0, 0, DOOR_TYPE_ROOM }
};
// Observation Ring keeper positions, indexed by KEEPER_* constants
static Position const ObservationRingKeepersPos[4] =
{
{1945.6823f, 33.342014f, 411.44083f, 5.270895f}, // Freya
{1945.7609f, -81.52171f, 411.4407f, 1.029744f}, // Hodir
{2028.7656f, 17.42014f, 411.44458f, 3.857178f}, // Mimiron
{2028.8219f, -65.73573f, 411.44257f, 2.460914f} // Thorim
};
static uint32 const ObservationRingKeeperEntry[4] =
{
NPC_FREYA_GOSSIP, NPC_HODIR_GOSSIP,
NPC_MIMIRON_GOSSIP, NPC_THORIM_GOSSIP
};
static uint32 const ObservationRingKeeperData[4] =
{
DATA_FREYA_GOSSIP, DATA_HODIR_GOSSIP,
DATA_MIMIRON_GOSSIP, DATA_THORIM_GOSSIP
};
static uint32 const ObservationRingKeeperBoss[4] =
{
BOSS_FREYA, BOSS_HODIR, BOSS_MIMIRON, BOSS_THORIM
};
ObjectData const creatureData[] =
{
{ NPC_LEVIATHAN, BOSS_LEVIATHAN },
@ -69,6 +95,11 @@ ObjectData const creatureData[] =
// Yogg-Saron helpers
{ NPC_SARA, DATA_SARA },
{ NPC_BRAIN_OF_YOGG_SARON, DATA_BRAIN_OF_YOGG_SARON },
// Observation Ring Keepers
{ NPC_FREYA_GOSSIP, DATA_FREYA_GOSSIP },
{ NPC_HODIR_GOSSIP, DATA_HODIR_GOSSIP },
{ NPC_MIMIRON_GOSSIP, DATA_MIMIRON_GOSSIP },
{ NPC_THORIM_GOSSIP, DATA_THORIM_GOSSIP },
// Algalon helpers
{ NPC_BRANN_BRONZBEARD_ALG, DATA_BRANN_BRONZEBEARD_ALG },
{ NPC_BRANN_BASE_CAMP, DATA_BRANN_BASE_CAMP },
@ -173,7 +204,6 @@ public:
// Shared
EventMap _events;
bool m_mimironTramUsed;
ObjectGuid m_keepersGossipGUID[4];
void Initialize() override
{
@ -227,6 +257,15 @@ public:
}
}
// Spawn Observation Ring keepers for defeated bosses
for (uint8 i = KEEPER_FREYA; i <= KEEPER_THORIM; ++i)
if (IsBossDone(ObservationRingKeeperBoss[i])
&& !(m_watchersMask & (1 << i))
&& !GetObjectGuid(ObservationRingKeeperData[i]))
instance->SummonCreature(
ObservationRingKeeperEntry[i],
ObservationRingKeepersPos[i]);
if (!GetObjectGuid(BOSS_ALGALON) && m_algalonTimer && (m_algalonTimer <= 60 || m_algalonTimer == TIMER_ALGALON_TO_SUMMON))
{
TempSummon* algalon = instance->SummonCreature(NPC_ALGALON, AlgalonLandPos);
@ -303,7 +342,7 @@ public:
case BOSS_HODIR:
case BOSS_THORIM:
case BOSS_FREYA:
if (GetBossState(BOSS_MIMIRON) == DONE && GetBossState(BOSS_FREYA) == DONE && GetBossState(BOSS_HODIR) == DONE && GetBossState(BOSS_THORIM) == DONE)
if (AllBossesDone({BOSS_MIMIRON, BOSS_FREYA, BOSS_HODIR, BOSS_THORIM}))
{
scheduler.Schedule(45s, [this](TaskContext /*context*/)
{
@ -317,6 +356,13 @@ public:
}
if (type == BOSS_HODIR && state == DONE)
setChestsLootable(BOSS_HODIR);
if (state == DONE)
{
uint8 keeperIdx = type - BOSS_FREYA;
instance->SummonCreature(
ObservationRingKeeperEntry[keeperIdx],
ObservationRingKeepersPos[keeperIdx]);
}
break;
case BOSS_ALGALON:
if (GameObject* go = GetGameObject(DATA_SIGILDOOR_03))
@ -563,7 +609,7 @@ public:
OpenIfDone(BOSS_ASSEMBLY, gameObject, GO_STATE_ACTIVE);
break;
case GO_KEEPERS_GATE:
if (GetBossState(BOSS_MIMIRON) == DONE && GetBossState(BOSS_FREYA) == DONE && GetBossState(BOSS_HODIR) == DONE && GetBossState(BOSS_THORIM) == DONE)
if (AllBossesDone({BOSS_MIMIRON, BOSS_FREYA, BOSS_HODIR, BOSS_THORIM}))
gameObject->RemoveGameObjectFlag(GO_FLAG_LOCKED);
break;
// Mimiron, Hodir, Vezax

View file

@ -143,6 +143,12 @@ enum UlduarData
DATA_BRANN_MEMOTESAY = 801,
DATA_BRANN_EASY_MODE = 802,
DATA_BRANN_BASE_CAMP = 803,
// Observation Ring Keepers
DATA_FREYA_GOSSIP = 810,
DATA_HODIR_GOSSIP = 811,
DATA_MIMIRON_GOSSIP = 812,
DATA_THORIM_GOSSIP = 813,
};
enum UlduarNPCs