fix(Scripts/BlackrockDepths): script the Black Vault warder event (#26973)

Co-authored-by: Claude Fable 5 <[email protected]>
Co-authored-by: sudlud <[email protected]>
Co-authored-by: Xfurry <[email protected]>
Co-authored-by: Tobschinski <[email protected]>
This commit is contained in:
Øyvind
2026-09-16 19:59:08 +02:00
committed by GitHub
co-authored by Claude Fable 5 sudlud Xfurry Tobschinski
parent 4d4ae4f957
commit a7ba226a68
4 changed files with 107 additions and 5 deletions
@@ -0,0 +1,6 @@
--
-- The four Warbringer Constructs in the Black Vault's Relic Coffer room must not
-- re-apply Stoned (10255) from creature_addon on every evade (CreatureAI::_EnterEvadeMode
-- reloads addon auras), or they would turn back into statues after the vault event has
-- awakened them. The instance script casts the aura once on spawn instead.
UPDATE `creature_addon` SET `auras` = NULL WHERE `guid` IN (46608, 46610, 46611, 46612);
@@ -0,0 +1,10 @@
-- Watchman Doomgrip: the vault event completion (Secret Door + Secret Safe) is handled by the
-- instance script when all four vault warders and Doomgrip are dead, so drop the old on-death
-- shortcut that opened both on his death alone. The on-aggro unfreeze of nearby Warbringer
-- Constructs is dead code too: the instance script awakens them when the 12th Relic Coffer
-- door opens, before Doomgrip spawns. Keep his combat spells and his aggro yell.
DELETE FROM `smart_scripts` WHERE `entryorguid` = 9476 AND `source_type` = 0;
INSERT INTO `smart_scripts` (`entryorguid`, `source_type`, `id`, `link`, `event_type`, `event_phase_mask`, `event_chance`, `event_flags`, `event_param1`, `event_param2`, `event_param3`, `event_param4`, `event_param5`, `event_param6`, `action_type`, `action_param1`, `action_param2`, `action_param3`, `action_param4`, `action_param5`, `action_param6`, `target_type`, `target_param1`, `target_param2`, `target_param3`, `target_param4`, `target_x`, `target_y`, `target_z`, `target_o`, `comment`) VALUES
(9476,0,0,0,0,0,100,0,1000,1000,6000,8000,0,0,11,11971,0,0,0,0,0,2,0,0,0,0,0,0,0,0,'Watchman Doomgrip - In Combat - Cast Sunder Armor'),
(9476,0,1,0,2,0,100,0,0,60,30000,30000,0,0,11,15504,0,0,0,0,0,1,0,0,0,0,0,0,0,0,'Watchman Doomgrip - Between 0-60% Health - Cast Drink Healing Potion'),
(9476,0,2,0,4,0,100,513,0,0,0,0,0,0,1,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,'Watchman Doomgrip - On Aggro - Say Line 0');
@@ -106,6 +106,7 @@ enum Creatures
NPC_RAGEREAVER_GOLEM = 8906,
NPC_WRATH_HAMMER_CONSTRUCT = 8907,
NPC_GOLEM_LORD_ARGELMACH = 8983,
NPC_WARBRINGER_CONSTRUCT = 8905,
NPC_COREN_DIREBREW = 23872,
@@ -33,7 +33,8 @@ enum Timers
enum Distances
{
RADIUS_RING_OF_LAW = 80,
DISTANCE_EMPEROR_ROOM = 125
DISTANCE_EMPEROR_ROOM = 125,
DISTANCE_VAULT_WARDER = 15
};
enum PrincessQuests
@@ -65,6 +66,8 @@ enum GameObjects
GO_THRONE_ROOM = 170575, // Throne door
GO_SPECTRAL_CHALICE = 164869,
GO_CHEST_SEVEN = 169243,
GO_SECRET_DOOR = 174553,
GO_SECRET_SAFE = 161495,
};
enum MiscData
@@ -147,6 +150,12 @@ struct instance_blackrock_depths : public InstanceScript
GuidList ArgelmachAdds;
ObjectGuid ArgelmachGUID;
// The four Warbringer Constructs in the Relic Coffer room and Watchman Doomgrip
GuidList VaultWarderGUIDs;
ObjectGuid GoSecretDoorGUID;
ObjectGuid GoSecretSafeGUID;
Position VaultWarderCenter = Position(813.5f, -348.0f);
TempSummon* TempSummonGrimstone = nullptr;
Position GrimstonePositon = Position(625.559f, -205.618f, -52.735f, 2.609f);
time_t timeRingFail = 0;
@@ -280,7 +289,9 @@ struct instance_blackrock_depths : public InstanceScript
break;
case NPC_ARENA_SPECTATOR:
ArenaSpectators.push_back(creature->GetGUID());
if (encounter[TYPE_RING_OF_LAW] == DONE) // added for crashes
// note: reads GetData, not encounter[TYPE_RING_OF_LAW]: the types are 1-based
// while the array is 0-based, so the raw index would hit the vault slot
if (GetData(TYPE_RING_OF_LAW) == DONE) // added for crashes
{
creature->SetFaction(FACTION_NEUTRAL);
creature->SetReactState(REACT_DEFENSIVE);
@@ -290,7 +301,9 @@ struct instance_blackrock_depths : public InstanceScript
case NPC_SHADOWFORCE_CITIZEN: // both do the same
if (creature->GetDistance2d(CenterOfRingOfLaw.GetPositionX(), CenterOfRingOfLaw.GetPositionY()) < (float)RADIUS_RING_OF_LAW)
ArenaSpectators.push_back(creature->GetGUID());
if (encounter[TYPE_RING_OF_LAW] == DONE) // added for crashes
// note: reads GetData, not encounter[TYPE_RING_OF_LAW]: the types are 1-based
// while the array is 0-based, so the raw index would hit the vault slot
if (GetData(TYPE_RING_OF_LAW) == DONE) // added for crashes
{
creature->SetFaction(FACTION_NEUTRAL);
creature->SetReactState(REACT_DEFENSIVE);
@@ -302,6 +315,32 @@ struct instance_blackrock_depths : public InstanceScript
if (creature->GetDistance2d(EmperorSpawnPos.GetPositionX(), EmperorSpawnPos.GetPositionY()) < (float)DISTANCE_EMPEROR_ROOM)
EmperorSenatorsVector.push_back(creature->GetGUID());
break;
case NPC_WARBRINGER_CONSTRUCT:
// only the four constructs in the Relic Coffer room belong to the vault event,
// the rest of the Black Vault spawns are regular trash
if (creature->GetDistance2d(VaultWarderCenter.GetPositionX(), VaultWarderCenter.GetPositionY()) > (float)DISTANCE_VAULT_WARDER)
break;
// dead spawns with a pending respawn are loaded too: a corpse must not be frozen or
// counted, or the restarted event could not complete until its respawn timer expires
if (!creature->IsAlive())
break;
// frozen until all 12 Relic Coffers have been opened. Stoned (statue visual) is cast
// here instead of creature_addon on purpose: addon auras get re-applied on every
// evade, which would turn the constructs back into statues after the event has started.
if (GetData(TYPE_VAULT) == NOT_STARTED)
{
creature->CastSpell(creature, SPELL_STONED, true);
creature->SetImmuneToPC(true);
// untargetable while inert: the reference video (https://youtu.be/KE1nElNN1YY)
// shows the statues cannot be targeted until activated; vmangos likewise clears
// UNIT_FLAG_NOT_SELECTABLE on them when Doomgrip aggroes
creature->SetUnitFlag(UNIT_FLAG_NOT_SELECTABLE);
creature->SetReactState(REACT_PASSIVE);
}
[[fallthrough]];
case NPC_WATCHMAN_DOOMGRIP:
VaultWarderGUIDs.push_back(creature->GetGUID());
break;
default:
break;
}
@@ -378,6 +417,17 @@ struct instance_blackrock_depths : public InstanceScript
case GO_SPECTRAL_CHALICE:
GoSpectralChaliceGUID = go->GetGUID();
break;
case GO_SECRET_DOOR:
GoSecretDoorGUID = go->GetGUID();
if (GetData(TYPE_VAULT) == DONE)
HandleGameObject(ObjectGuid::Empty, true, go);
break;
case GO_SECRET_SAFE:
GoSecretSafeGUID = go->GetGUID();
// non-interactable via gameobject_template_addon flags until the vault event is done
if (GetData(TYPE_VAULT) == DONE)
go->RemoveGameObjectFlag(GO_FLAG_NOT_SELECTABLE);
break;
}
}
@@ -395,6 +445,17 @@ struct instance_blackrock_depths : public InstanceScript
case NPC_MAGMUS:
SetData(TYPE_IRON_HALL, DONE);
break;
case NPC_WARBRINGER_CONSTRUCT:
case NPC_WATCHMAN_DOOMGRIP:
if (GetData(TYPE_VAULT) == IN_PROGRESS)
{
// regular Black Vault trash shares the entry but is not in the list,
// remove() is a no-op for it
VaultWarderGUIDs.remove(unit->GetGUID());
if (VaultWarderGUIDs.empty())
SetData(TYPE_VAULT, DONE);
}
break;
case NPC_SHADOWFORGE_SENATOR:
deadSenators = 1; //hacky, but we cannot count the unit that just died through its state because OnUnitDeath() is called before the state is set.
for (auto const& senatorGUID: EmperorSenatorsVector)
@@ -458,6 +519,13 @@ struct instance_blackrock_depths : public InstanceScript
break;
case TYPE_VAULT:
encounter[1] = data;
if (data == DONE)
{
// vault cleared: open the secret door and make the Secret Safe lootable
HandleGameObject(GoSecretDoorGUID, true);
if (GameObject* safe = instance->GetGameObject(GoSecretSafeGUID))
safe->RemoveGameObjectFlag(GO_FLAG_NOT_SELECTABLE);
}
break;
case TYPE_BAR:
if (data == SPECIAL)
@@ -510,9 +578,26 @@ struct instance_blackrock_depths : public InstanceScript
break;
case DATA_OPEN_COFFER_DOORS:
OpenedCoofers += 1;
if (OpenedCoofers == 12)
// the coffer doors reset on every map load while the vault state persists: reopening
// them after the event has started must not restart it or summon a second Doomgrip
if (OpenedCoofers == 12 && GetData(TYPE_VAULT) == NOT_STARTED)
{
Position pos = {812.15f, -348.91f, -50.579f, 0.7f};
SetData(TYPE_VAULT, IN_PROGRESS);
// awaken the Warbringer Constructs guarding the vault
for (ObjectGuid const& warderGUID : VaultWarderGUIDs)
{
if (Creature* warder = instance->GetCreature(warderGUID))
{
warder->RemoveAurasDueToSpell(SPELL_STONED);
warder->SetImmuneToPC(false);
warder->RemoveUnitFlag(UNIT_FLAG_NOT_SELECTABLE);
warder->SetReactState(REACT_AGGRESSIVE);
}
}
// spawns at the room entrance, not amidst the constructs (position from cmangos)
Position pos = {821.905f, -338.382f, -50.134f, 3.78736f};
if (TempSummon* summon = instance->SummonCreature(NPC_WATCHMAN_DOOMGRIP, pos))
summon->SetTempSummonType(TEMPSUMMON_MANUAL_DESPAWN);
}