mirror of
https://github.com/liyunfan1223/mod-playerbots.git
synced 2026-06-20 23:49:25 +02:00
## Pull Request Description Bots will now engage with outdoor pvp targets when in an area with them. I carved this out of the guildrpg system Im working on since it should work just fine as a standalone. Note this requires a core update https://github.com/azerothcore/azerothcore-wotlk/pull/25103 ## Feature Evaluation Its not expensive. the status checks are fairly light and simple. Should be on par with current rpg system actions ## How to Test the Changes You can try to use selfbot to enable this while in EPL, or set the probability of all other rpg actions to 0. ## Impact Assessment <!-- As a generic test, before and after measure of pmon (playerbot pmon tick) can help you here. --> - Does this change increase per-bot/per-tick processing or risk scaling poorly with thousands of bots? - [ ] No, not at all - [x] Minimal impact (**explain below**) - [ ] Moderate impact (**explain below**) There is some impact, but should be minimal overall. - Does this change modify default bot behavior? - [ ] No - [x] Yes (**explain why**) It will activate automatically based on default config. - Does this change add new decision branches or increase maintenance complexity? - [ ] No - [x] Yes (**explain below**) ## AI Assistance Was AI assistance used while working on this change? - [ ] No - [x] Yes (**explain below**) <!-- If yes, please specify: - Purpose of usage (e.g. brainstorming, refactoring, documentation, code generation). - Which parts of the change were influenced or generated, and whether it was thoroughly reviewed. --> Nothing beyond search functionality and autocomplete. ## Final Checklist - [x] Stability is not compromised. - [x] Performance impact is understood, tested, and acceptable. - [x] Added logic complexity is justified and explained. - [x] Documentation updated if needed (Conf comments, WiKi commands). ## Notes for Reviewers <!-- Anything else that's helpful to review or test your pull request. --> --------- Co-authored-by: bash <hermensb@gmail.com> Co-authored-by: Revision <tkn963@gmail.com> Co-authored-by: kadeshar <kadeshar@gmail.com>
129 lines
4.5 KiB
C++
129 lines
4.5 KiB
C++
#include "NewRpgOutdoorPvP.h"
|
|
#include "OutdoorPvP.h"
|
|
#include "OutdoorPvPMgr.h"
|
|
|
|
bool NewRpgOutdoorPvpAction::Execute(Event event)
|
|
{
|
|
if (!bot->IsPvP())
|
|
{
|
|
botAI->rpgInfo.ChangeToIdle();
|
|
return false;
|
|
}
|
|
if (IsWaitingForLastMove(MovementPriority::MOVEMENT_NORMAL) || !bot->IsOutdoorPvPActive())
|
|
return false;
|
|
|
|
uint32 zoneId = bot->GetZoneId();
|
|
OutdoorPvP* outdoorPvP = sOutdoorPvPMgr->GetOutdoorPvPToZoneId(zoneId);
|
|
if (!outdoorPvP || zoneId == AREA_NAGRAND)
|
|
{
|
|
botAI->rpgInfo.ChangeToIdle();
|
|
return false;
|
|
}
|
|
|
|
OutdoorPvP::OPvPCapturePointMap const& capturePointMap = outdoorPvP->GetCapturePoints();
|
|
|
|
NewRpgInfo& info = botAI->rpgInfo;
|
|
auto* dataPtr = std::get_if<NewRpgInfo::OutdoorPvP>(&info.data);
|
|
if (!dataPtr)
|
|
return false;
|
|
auto& data = *dataPtr;
|
|
// Re-resolve stored spawn ID from the capture point map each tick (avoids dangling pointers)
|
|
OPvPCapturePoint* objective = nullptr;
|
|
if (data.capturePointSpawnId && !capturePointMap.empty())
|
|
{
|
|
auto it = capturePointMap.find(data.capturePointSpawnId);
|
|
if (it != capturePointMap.end())
|
|
{
|
|
OPvPCapturePoint* capturePoint = it->second;
|
|
if (capturePoint && capturePoint->_capturePoint)
|
|
{
|
|
float threshold = capturePoint->GetMinValue();
|
|
float slider = capturePoint->GetSlider();
|
|
uint8 faction = bot->GetTeamId();
|
|
LOG_DEBUG("playerbots", "[NEW RPG] Bot {} with faction {} is evaluating existing RPG objective {} with threshold {} and slider value {}", bot->GetName(), faction, capturePoint->_capturePoint->GetName(), threshold, slider);
|
|
if ((faction == TEAM_HORDE && slider >= -threshold) ||
|
|
(faction == TEAM_ALLIANCE && slider <= threshold))
|
|
objective = capturePoint;
|
|
}
|
|
}
|
|
if (!objective)
|
|
data.capturePointSpawnId = 0;
|
|
}
|
|
|
|
if (!objective)
|
|
{
|
|
objective = SelectNewObjective(capturePointMap);
|
|
if (!objective)
|
|
{
|
|
botAI->rpgInfo.ChangeToIdle();
|
|
return true;
|
|
}
|
|
data.capturePointSpawnId = objective->m_capturePointSpawnId;
|
|
LOG_DEBUG("playerbots","[NEW RPG] Bot {} selected OutDoorPvP target capturePointSpawnId {}", bot->GetName(), data.capturePointSpawnId);
|
|
}
|
|
|
|
GameObject* objectiveGO = objective->_capturePoint;
|
|
if (!objectiveGO)
|
|
return false;
|
|
|
|
if (objectiveGO->GetGoType() != GAMEOBJECT_TYPE_CAPTURE_POINT)
|
|
return false;
|
|
|
|
float radius = objectiveGO->GetGOInfo()->capturePoint.radius / 2.0f;
|
|
if (!objectiveGO->IsWithinDistInMap(bot, radius))
|
|
return MoveFarTo(WorldPosition(objectiveGO));
|
|
|
|
return PatrolCapturePoint(objectiveGO, radius);
|
|
}
|
|
|
|
OPvPCapturePoint* NewRpgOutdoorPvpAction::SelectNewObjective(OutdoorPvP::OPvPCapturePointMap const& capturePointMap)
|
|
{
|
|
OPvPCapturePoint* objective = nullptr;
|
|
uint8 faction = bot->GetTeamId();
|
|
std::vector<OPvPCapturePoint*> candidateObjectives;
|
|
|
|
if (capturePointMap.empty())
|
|
{
|
|
botAI->rpgInfo.ChangeToIdle();
|
|
return objective;
|
|
}
|
|
for (auto const& [guid, point] : capturePointMap)
|
|
{
|
|
GameObject* capturePointObject = point->_capturePoint;
|
|
if (!capturePointObject)
|
|
continue;
|
|
|
|
float threshold = point->GetMinValue();
|
|
float slider = point->GetSlider();
|
|
if (faction == TEAM_HORDE && slider > -threshold)
|
|
candidateObjectives.push_back(point);
|
|
else if (faction == TEAM_ALLIANCE && slider < threshold)
|
|
candidateObjectives.push_back(point);
|
|
}
|
|
if (candidateObjectives.empty())
|
|
{
|
|
LOG_DEBUG("playerbots", "[New RPG] Bot {} found no valid outdoor PVP objectives to capture", bot->GetName());
|
|
botAI->rpgInfo.ChangeToIdle();
|
|
return objective;
|
|
}
|
|
int randomIndex = urand(0, candidateObjectives.size() - 1);
|
|
objective = candidateObjectives[randomIndex];
|
|
return objective;
|
|
}
|
|
|
|
bool NewRpgOutdoorPvpAction::PatrolCapturePoint(GameObject* objectiveGO, float radius)
|
|
{
|
|
if (IsWaitingForLastMove(MovementPriority::MOVEMENT_NORMAL))
|
|
return false;
|
|
|
|
// Randomly pause at the current spot before picking a new patrol point
|
|
if (urand(0, 2) == 0)
|
|
return ForceToWait(urand(3000, 6000));
|
|
|
|
float patrolRadius = radius * 0.8f;
|
|
if (MoveRandomNear(patrolRadius, MovementPriority::MOVEMENT_NORMAL, objectiveGO))
|
|
return true;
|
|
|
|
return ForceToWait(urand(3000, 6000));
|
|
}
|