mod-playerbots/src/strategy/actions/UseMeetingStoneAction.cpp
Alex Dcnh 9ae457d069
[BUG FIX] - Preserve buffs on summon by avoiding aura clears (#1958)
### Summary

- Add a preserveAuras flag to summon teleport helpers.
- Keep auras when using the summon command.
- Leave meeting stone behavior unchanged (auras can still be cleared
there).

### Motivation
Summon command was clearing buffs (e.g., Hellscream’s Warsong in ICC)
because auras were explicitly interrupted before teleporting. This
change keeps existing meeting stone behavior but preserves auras for the
summon path to avoid losing valid buffs.

### Details
Solve : 
https://github.com/mod-playerbots/mod-playerbots/issues/1862
https://github.com/mod-playerbots/mod-playerbots/issues/1942

### Testing
Go to ICC and téléport Bots
2026-01-07 15:24:41 +01:00

236 lines
7.6 KiB
C++

/*
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU AGPL v3 license, you may redistribute it
* and/or modify it under version 3 of the License, or (at your option), any later version.
*/
#include "UseMeetingStoneAction.h"
#include "CellImpl.h"
#include "Event.h"
#include "GridNotifiers.h"
#include "GridNotifiersImpl.h"
#include "NearestGameObjects.h"
#include "PlayerbotAIConfig.h"
#include "Playerbots.h"
#include "PositionValue.h"
bool UseMeetingStoneAction::Execute(Event event)
{
Player* master = GetMaster();
if (!master)
return false;
WorldPacket p(event.getPacket());
p.rpos(0);
ObjectGuid guid;
p >> guid;
if (master->GetTarget() && master->GetTarget() != bot->GetGUID())
return false;
if (!master->GetTarget() && master->GetGroup() != bot->GetGroup())
return false;
if (master->IsBeingTeleported())
return false;
if (bot->IsInCombat())
{
botAI->TellError("I am in combat");
return false;
}
Map* map = master->GetMap();
if (!map)
return false;
GameObject* gameObject = map->GetGameObject(guid);
if (!gameObject)
return false;
GameObjectTemplate const* goInfo = gameObject->GetGOInfo();
if (!goInfo || goInfo->entry != 179944)
return false;
return Teleport(master, bot, false);
}
bool SummonAction::Execute(Event event)
{
Player* master = GetMaster();
if (!master)
return false;
if (Pet* pet = bot->GetPet())
{
botAI->PetFollow();
}
if (master->GetSession()->GetSecurity() >= SEC_PLAYER)
{
// botAI->GetAiObjectContext()->GetValue<GuidVector>("prioritized targets")->Set({});
AI_VALUE(std::list<FleeInfo>&, "recently flee info").clear();
return Teleport(master, bot, true);
}
if (SummonUsingGos(master, bot, true) || SummonUsingNpcs(master, bot, true))
{
botAI->TellMasterNoFacing("Hello!");
return true;
}
if (SummonUsingGos(bot, master, true) || SummonUsingNpcs(bot, master, true))
{
botAI->TellMasterNoFacing("Welcome!");
return true;
}
return false;
}
bool SummonAction::SummonUsingGos(Player* summoner, Player* player, bool preserveAuras)
{
std::list<GameObject*> targets;
AnyGameObjectInObjectRangeCheck u_check(summoner, sPlayerbotAIConfig->sightDistance);
Acore::GameObjectListSearcher<AnyGameObjectInObjectRangeCheck> searcher(summoner, targets, u_check);
Cell::VisitObjects(summoner, searcher, sPlayerbotAIConfig->sightDistance);
for (GameObject* go : targets)
{
if (go->isSpawned() && go->GetGoType() == GAMEOBJECT_TYPE_MEETINGSTONE)
return Teleport(summoner, player, preserveAuras);
}
botAI->TellError(summoner == bot ? "There is no meeting stone nearby" : "There is no meeting stone near you");
return false;
}
bool SummonAction::SummonUsingNpcs(Player* summoner, Player* player, bool preserveAuras)
{
if (!sPlayerbotAIConfig->summonAtInnkeepersEnabled)
return false;
std::list<Unit*> targets;
Acore::AnyUnitInObjectRangeCheck u_check(summoner, sPlayerbotAIConfig->sightDistance);
Acore::UnitListSearcher<Acore::AnyUnitInObjectRangeCheck> searcher(summoner, targets, u_check);
Cell::VisitObjects(summoner, searcher, sPlayerbotAIConfig->sightDistance);
for (Unit* unit : targets)
{
if (unit && unit->HasNpcFlag(UNIT_NPC_FLAG_INNKEEPER))
{
if (!player->HasItemCount(6948, 1, false))
{
botAI->TellError(player == bot ? "I have no hearthstone" : "You have no hearthstone");
return false;
}
if (player->HasSpellCooldown(8690))
{
botAI->TellError(player == bot ? "My hearthstone is not ready" : "Your hearthstone is not ready");
return false;
}
// Trigger cooldown
SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(8690);
if (!spellInfo)
return false;
Spell spell(player, spellInfo, TRIGGERED_NONE);
spell.SendSpellCooldown();
return Teleport(summoner, player, preserveAuras);
}
}
botAI->TellError(summoner == bot ? "There are no innkeepers nearby" : "There are no innkeepers near you");
return false;
}
bool SummonAction::Teleport(Player* summoner, Player* player, bool preserveAuras)
{
// Player* master = GetMaster();
if (!summoner)
return false;
if (player->GetVehicle())
{
botAI->TellError("You cannot summon me while I'm on a vehicle");
return false;
}
if (!summoner->IsBeingTeleported() && !player->IsBeingTeleported())
{
float followAngle = GetFollowAngle();
for (float angle = followAngle - M_PI; angle <= followAngle + M_PI; angle += M_PI / 4)
{
uint32 mapId = summoner->GetMapId();
float x = summoner->GetPositionX() + cos(angle) * sPlayerbotAIConfig->followDistance;
float y = summoner->GetPositionY() + sin(angle) * sPlayerbotAIConfig->followDistance;
float z = summoner->GetPositionZ();
if (summoner->IsWithinLOS(x, y, z))
{
if (sPlayerbotAIConfig
->botRepairWhenSummon) // .conf option to repair bot gear when summoned 0 = off, 1 = on
bot->DurabilityRepairAll(false, 1.0f, false);
if (summoner->IsInCombat() && !sPlayerbotAIConfig->allowSummonInCombat)
{
botAI->TellError("You cannot summon me while you're in combat");
return false;
}
if (!summoner->IsAlive() && !sPlayerbotAIConfig->allowSummonWhenMasterIsDead)
{
botAI->TellError("You cannot summon me while you're dead");
return false;
}
if (bot->isDead() && !bot->HasPlayerFlag(PLAYER_FLAGS_GHOST) &&
!sPlayerbotAIConfig->allowSummonWhenBotIsDead)
{
botAI->TellError("You cannot summon me while I'm dead, you need to release my spirit first");
return false;
}
bool revive =
sPlayerbotAIConfig->reviveBotWhenSummoned == 2 ||
(sPlayerbotAIConfig->reviveBotWhenSummoned == 1 && !summoner->IsInCombat() && summoner->IsAlive());
if (bot->isDead() && revive)
{
bot->ResurrectPlayer(1.0f, false);
bot->SpawnCorpseBones();
botAI->TellMasterNoFacing("I live, again!");
botAI->GetAiObjectContext()->GetValue<GuidVector>("prioritized targets")->Reset();
}
player->GetMotionMaster()->Clear();
AI_VALUE(LastMovement&, "last movement").clear();
if (!preserveAuras)
player->RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_TELEPORTED |
AURA_INTERRUPT_FLAG_CHANGE_MAP);
player->TeleportTo(mapId, x, y, z, 0);
if (botAI->HasStrategy("stay", botAI->GetState()))
{
PositionMap& posMap = AI_VALUE(PositionMap&, "position");
PositionInfo stayPosition = posMap["stay"];
stayPosition.Set(x,y, z, mapId);
posMap["stay"] = stayPosition;
}
return true;
}
}
}
if (summoner != player)
botAI->TellError("Not enough place to summon");
return false;
}