feat(Core/Wintergrasp): aura-driven resurrect queue (#26002)

Co-authored-by: Balrok <balrok@getmangos.com>
Co-authored-by: Xfurry <xfurry.cmangos@outlook.com>
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Andrew
2026-05-27 22:44:54 -03:00
committed by GitHub
parent e588638749
commit 0a9c55f308
5 changed files with 53 additions and 117 deletions

View File

@@ -629,34 +629,22 @@ GraveyardStruct const* Battlefield::GetClosestGraveyard(Player* player)
return nullptr; return nullptr;
} }
void Battlefield::AddPlayerToResurrectQueue(ObjectGuid npcGuid, ObjectGuid playerGuid) void Battlefield::AddPlayerToResurrectQueue(ObjectGuid /*npcGuid*/, ObjectGuid playerGuid)
{ {
for (BfGraveyard* gy : GraveyardList) Player* player = ObjectAccessor::FindPlayer(playerGuid);
{ if (!player)
if (!gy) return;
continue;
if (gy->HasNpc(npcGuid)) player->CastSpell(player, SPELL_WAITING_FOR_RESURRECT, true);
{
gy->AddPlayer(playerGuid);
break;
}
}
} }
void Battlefield::RemovePlayerFromResurrectQueue(ObjectGuid playerGuid) void Battlefield::RemovePlayerFromResurrectQueue(ObjectGuid playerGuid)
{ {
for (BfGraveyard* gy : GraveyardList) Player* player = ObjectAccessor::FindPlayer(playerGuid);
{ if (!player)
if (!gy) return;
continue;
if (gy->HasPlayer(playerGuid)) player->RemoveAurasDueToSpell(SPELL_WAITING_FOR_RESURRECT);
{
gy->RemovePlayer(playerGuid);
break;
}
}
} }
void Battlefield::SendAreaSpiritHealerQueryOpcode(Player* player, ObjectGuid const& guid) void Battlefield::SendAreaSpiritHealerQueryOpcode(Player* player, ObjectGuid const& guid)
@@ -702,80 +690,9 @@ float BfGraveyard::GetDistance(Player* player)
return player->GetDistance2d(safeLoc->x, safeLoc->y); return player->GetDistance2d(safeLoc->x, safeLoc->y);
} }
void BfGraveyard::AddPlayer(ObjectGuid playerGuid)
{
if (!ResurrectQueue.count(playerGuid))
{
ResurrectQueue.insert(playerGuid);
if (Player* player = ObjectAccessor::FindPlayer(playerGuid))
player->CastSpell(player, SPELL_WAITING_FOR_RESURRECT, true);
}
}
void BfGraveyard::RemovePlayer(ObjectGuid playerGuid)
{
ResurrectQueue.erase(ResurrectQueue.find(playerGuid));
if (Player* player = ObjectAccessor::FindPlayer(playerGuid))
player->RemoveAurasDueToSpell(SPELL_WAITING_FOR_RESURRECT);
}
void BfGraveyard::Resurrect()
{
if (ResurrectQueue.empty())
return;
for (ObjectGuid const& guid : ResurrectQueue)
{
// Get player object from his guid
Player* player = ObjectAccessor::FindPlayer(guid);
if (!player)
continue;
// Check if the player is in world and on the good graveyard
if (player->IsInWorld())
if (Unit* spirit = ObjectAccessor::GetCreature(*player, SpiritGuide[ControlTeam]))
spirit->CastSpell(spirit, SPELL_SPIRIT_HEAL, true);
// Resurrect player
player->CastSpell(player, SPELL_RESURRECTION_VISUAL, true);
player->ResurrectPlayer(1.0f);
player->CastSpell(player, 6962, true);
player->CastSpell(player, SPELL_SPIRIT_HEAL_MANA, true);
player->SpawnCorpseBones(false);
}
ResurrectQueue.clear();
}
// For changing graveyard control
void BfGraveyard::GiveControlTo(TeamId team) void BfGraveyard::GiveControlTo(TeamId team)
{ {
ControlTeam = team; ControlTeam = team;
// Teleport to other graveyard, players which were on this graveyard
RelocateDeadPlayers();
}
void BfGraveyard::RelocateDeadPlayers()
{
GraveyardStruct const* closestGrave = nullptr;
for (ObjectGuid const& guid : ResurrectQueue)
{
Player* player = ObjectAccessor::FindPlayer(guid);
if (!player)
continue;
if (closestGrave)
player->TeleportTo(player->GetMapId(), closestGrave->x, closestGrave->y, closestGrave->z, player->GetOrientation());
else
{
closestGrave = Bf->GetClosestGraveyard(player);
if (closestGrave)
player->TeleportTo(player->GetMapId(), closestGrave->x, closestGrave->y, closestGrave->z, player->GetOrientation());
}
}
} }
Creature* Battlefield::SpawnCreature(uint32 entry, Position pos, TeamId teamId) Creature* Battlefield::SpawnCreature(uint32 entry, Position pos, TeamId teamId)

View File

@@ -169,18 +169,6 @@ public:
// Set spirit service for the graveyard // Set spirit service for the graveyard
void SetSpirit(Creature* spirit, TeamId team); void SetSpirit(Creature* spirit, TeamId team);
// Add a player to the graveyard
void AddPlayer(ObjectGuid playerGuid);
// Remove a player from the graveyard
void RemovePlayer(ObjectGuid playerGuid);
// Resurrect players
void Resurrect();
// Move players waiting to that graveyard on the nearest one
void RelocateDeadPlayers();
// Check if this graveyard has a spirit guide // Check if this graveyard has a spirit guide
bool HasNpc(ObjectGuid guid) bool HasNpc(ObjectGuid guid)
{ {
@@ -190,8 +178,7 @@ public:
return (SpiritGuide[0] == guid || SpiritGuide[1] == guid); return (SpiritGuide[0] == guid || SpiritGuide[1] == guid);
} }
// Check if a player is in this graveyard's resurrect queue ObjectGuid GetSpiritGuide(TeamId team) const { return SpiritGuide[team]; }
bool HasPlayer(ObjectGuid guid) const { return ResurrectQueue.find(guid) != ResurrectQueue.end(); }
// Get the graveyard's ID. // Get the graveyard's ID.
uint32 GetGraveyardId() const { return GraveyardId; } uint32 GetGraveyardId() const { return GraveyardId; }
@@ -200,7 +187,6 @@ protected:
TeamId ControlTeam; TeamId ControlTeam;
uint32 GraveyardId; uint32 GraveyardId;
ObjectGuid SpiritGuide[2]; ObjectGuid SpiritGuide[2];
GuidUnorderedSet ResurrectQueue;
Battlefield* Bf; Battlefield* Bf;
}; };

View File

@@ -193,9 +193,39 @@ bool BattlefieldWG::SetupBattlefield()
_scheduler.Schedule(Milliseconds(RESURRECTION_INTERVAL), _scheduler.Schedule(Milliseconds(RESURRECTION_INTERVAL),
BATTLEFIELD_TIMER_GROUP_RESURRECT, [this](TaskContext context) BATTLEFIELD_TIMER_GROUP_RESURRECT, [this](TaskContext context)
{ {
for (BfGraveyard* gy : GraveyardList) ForEachPlayerInZone([this](Player* player)
if (gy) {
gy->Resurrect(); if (!player->HasAura(SPELL_WAITING_FOR_RESURRECT))
return;
TeamId team = player->GetTeamId();
Unit* closestSpirit = nullptr;
float closestDist = -1.0f;
for (BfGraveyard* gy : GraveyardList)
{
if (!gy)
continue;
Unit* spirit = ObjectAccessor::GetCreature(*player, gy->GetSpiritGuide(team));
if (!spirit)
continue;
float dist = player->GetDistance(spirit);
if (closestDist < 0.0f || dist < closestDist)
{
closestDist = dist;
closestSpirit = spirit;
}
}
if (closestSpirit)
closestSpirit->CastSpell(closestSpirit, SPELL_SPIRIT_HEAL, true);
player->CastSpell(player, SPELL_RESURRECTION_VISUAL, true);
player->ResurrectPlayer(1.0f);
player->CastSpell(player, 6962, true);
player->CastSpell(player, SPELL_SPIRIT_HEAL_MANA, true);
player->SpawnCorpseBones(false);
player->RemoveAurasDueToSpell(SPELL_WAITING_FOR_RESURRECT);
});
context.Repeat(); context.Repeat();
}); });

View File

@@ -5344,13 +5344,10 @@ void AuraEffect::HandleAuraDummy(AuraApplication const* aurApp, uint8 mode, bool
{ {
case 2584: // Waiting to Resurrect case 2584: // Waiting to Resurrect
// Waiting to resurrect spell cancel, we must remove player from resurrect queue // Waiting to resurrect spell cancel, we must remove player from resurrect queue
// bf branch omitted: it would cascade back into this handler.
if (target->IsPlayer()) if (target->IsPlayer())
{
if (Battleground* bg = target->ToPlayer()->GetBattleground()) if (Battleground* bg = target->ToPlayer()->GetBattleground())
bg->RemovePlayerFromResurrectQueue(target->ToPlayer()); bg->RemovePlayerFromResurrectQueue(target->ToPlayer());
if (Battlefield* bf = sBattlefieldMgr->GetBattlefieldToZoneId(target->GetZoneId()))
bf->RemovePlayerFromResurrectQueue(target->GetGUID());
}
break; break;
case 43681: // Inactive case 43681: // Inactive
{ {

View File

@@ -215,13 +215,19 @@ public:
bool OnGossipHello(Player* player, Creature* creature) override bool OnGossipHello(Player* player, Creature* creature) override
{ {
if (creature->IsQuestGiver())
player->PrepareQuestMenu(creature->GetGUID());
Battlefield* wintergrasp = sBattlefieldMgr->GetBattlefieldByBattleId(BATTLEFIELD_BATTLEID_WG); Battlefield* wintergrasp = sBattlefieldMgr->GetBattlefieldByBattleId(BATTLEFIELD_BATTLEID_WG);
if (!wintergrasp) if (!wintergrasp)
return true; return true;
if (!player->IsAlive())
{
wintergrasp->SendAreaSpiritHealerQueryOpcode(player, creature->GetGUID());
player->CastSpell(player, SPELL_WAITING_FOR_RESURRECT, true);
}
if (creature->IsQuestGiver())
player->PrepareQuestMenu(creature->GetGUID());
GraveyardVect graveyard = wintergrasp->GetGraveyardVector(); GraveyardVect graveyard = wintergrasp->GetGraveyardVector();
for (uint8 i = 0; i < graveyard.size(); i++) for (uint8 i = 0; i < graveyard.size(); i++)
if (graveyard[i]->GetControlTeamId() == player->GetTeamId()) if (graveyard[i]->GetControlTeamId() == player->GetTeamId())