mirror of
https://github.com/mod-playerbots/mod-playerbots
synced 2025-11-29 15:58:20 +08:00
181 lines
5.9 KiB
C++
181 lines
5.9 KiB
C++
/*
|
|
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU GPL v2 license, you may redistribute it and/or modify it under version 2 of the License, or (at your option), any later version.
|
|
*/
|
|
|
|
#include "FleeManager.h"
|
|
#include "Playerbots.h"
|
|
#include "ServerFacade.h"
|
|
|
|
FleeManager::FleeManager(Player* bot, float maxAllowedDistance, float followAngle, bool forceMaxDistance, WorldPosition startPosition) :
|
|
bot(bot), maxAllowedDistance(maxAllowedDistance), followAngle(followAngle), forceMaxDistance(forceMaxDistance), startPosition(startPosition ? startPosition : WorldPosition(bot))
|
|
{
|
|
}
|
|
|
|
void FleeManager::calculateDistanceToCreatures(FleePoint *point)
|
|
{
|
|
point->minDistance = -1.0f;
|
|
point->sumDistance = 0.0f;
|
|
PlayerbotAI* botAI = GET_PLAYERBOT_AI(bot);
|
|
if (!botAI) {
|
|
return;
|
|
}
|
|
GuidVector units = *botAI->GetAiObjectContext()->GetValue<GuidVector>("possible targets no los");
|
|
for (GuidVector::iterator i = units.begin(); i != units.end(); ++i)
|
|
{
|
|
Unit* unit = botAI->GetUnit(*i);
|
|
if (!unit)
|
|
continue;
|
|
|
|
float d = sServerFacade->GetDistance2d(unit, point->x, point->y);
|
|
point->sumDistance += d;
|
|
if (point->minDistance < 0 || point->minDistance > d)
|
|
point->minDistance = d;
|
|
}
|
|
}
|
|
|
|
bool intersectsOri(float angle, std::vector<float>& angles, float angleIncrement)
|
|
{
|
|
for (std::vector<float>::iterator i = angles.begin(); i != angles.end(); ++i)
|
|
{
|
|
float ori = *i;
|
|
if (abs(angle - ori) < angleIncrement)
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
void FleeManager::calculatePossibleDestinations(std::vector<FleePoint*> &points)
|
|
{
|
|
PlayerbotAI* botAI = GET_PLAYERBOT_AI(bot);
|
|
if (!botAI) {
|
|
return;
|
|
}
|
|
Unit* target = *botAI->GetAiObjectContext()->GetValue<Unit*>("current target");
|
|
|
|
float botPosX = startPosition.getX();
|
|
float botPosY = startPosition.getY();
|
|
float botPosZ = startPosition.getZ();
|
|
|
|
FleePoint start(botAI, botPosX, botPosY, botPosZ);
|
|
calculateDistanceToCreatures(&start);
|
|
|
|
std::vector<float> enemyOri;
|
|
GuidVector units = *botAI->GetAiObjectContext()->GetValue<GuidVector>("possible targets no los");
|
|
for (GuidVector::iterator i = units.begin(); i != units.end(); ++i)
|
|
{
|
|
Unit* unit = botAI->GetUnit(*i);
|
|
if (!unit)
|
|
continue;
|
|
|
|
float ori = bot->GetAngle(unit);
|
|
enemyOri.push_back(ori);
|
|
}
|
|
|
|
float distIncrement = std::max(sPlayerbotAIConfig->followDistance, (maxAllowedDistance - sPlayerbotAIConfig->tooCloseDistance) / 10.0f);
|
|
for (float dist = maxAllowedDistance; dist >= sPlayerbotAIConfig->tooCloseDistance ; dist -= distIncrement)
|
|
{
|
|
float angleIncrement = std::max(M_PI / 20, M_PI / 4 / (1.0 + dist - sPlayerbotAIConfig->tooCloseDistance));
|
|
for (float add = 0.0f; add < M_PI / 4 + angleIncrement; add += angleIncrement)
|
|
{
|
|
for (float angle = add; angle < add + 2 * static_cast<float>(M_PI) + angleIncrement; angle += static_cast<float>(M_PI) / 4)
|
|
{
|
|
if (intersectsOri(angle, enemyOri, angleIncrement))
|
|
continue;
|
|
|
|
float x = botPosX + cos(angle) * maxAllowedDistance, y = botPosY + sin(angle) * maxAllowedDistance, z = botPosZ + CONTACT_DISTANCE;
|
|
if (forceMaxDistance && sServerFacade->IsDistanceLessThan(sServerFacade->GetDistance2d(bot, x, y), maxAllowedDistance - sPlayerbotAIConfig->tooCloseDistance))
|
|
continue;
|
|
|
|
bot->UpdateAllowedPositionZ(x, y, z);
|
|
|
|
Map* map = startPosition.getMap();
|
|
if (map && map->IsInWater(bot->GetPhaseMask(), x, y, z, bot->GetCollisionHeight()))
|
|
continue;
|
|
|
|
if (!bot->IsWithinLOS(x, y, z) || (target && !target->IsWithinLOS(x, y, z)))
|
|
continue;
|
|
|
|
FleePoint* point = new FleePoint(botAI, x, y, z);
|
|
calculateDistanceToCreatures(point);
|
|
|
|
if (sServerFacade->IsDistanceGreaterOrEqualThan(point->minDistance - start.minDistance, sPlayerbotAIConfig->followDistance))
|
|
points.push_back(point);
|
|
else
|
|
delete point;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void FleeManager::cleanup(std::vector<FleePoint*> &points)
|
|
{
|
|
for (std::vector<FleePoint*>::iterator i = points.begin(); i != points.end(); i++)
|
|
{
|
|
delete *i;
|
|
}
|
|
|
|
points.clear();
|
|
}
|
|
|
|
bool FleeManager::isBetterThan(FleePoint* point, FleePoint* other)
|
|
{
|
|
return point->sumDistance - other->sumDistance > 0;
|
|
}
|
|
|
|
FleePoint* FleeManager::selectOptimalDestination(std::vector<FleePoint*> &points)
|
|
{
|
|
FleePoint* best = nullptr;
|
|
for (std::vector<FleePoint*>::iterator i = points.begin(); i != points.end(); i++)
|
|
{
|
|
FleePoint* point = *i;
|
|
if (!best || isBetterThan(point, best))
|
|
best = point;
|
|
}
|
|
|
|
return best;
|
|
}
|
|
|
|
bool FleeManager::CalculateDestination(float* rx, float* ry, float* rz)
|
|
{
|
|
std::vector<FleePoint*> points;
|
|
calculatePossibleDestinations(points);
|
|
|
|
FleePoint* point = selectOptimalDestination(points);
|
|
if (!point)
|
|
{
|
|
cleanup(points);
|
|
return false;
|
|
}
|
|
|
|
*rx = point->x;
|
|
*ry = point->y;
|
|
*rz = point->z;
|
|
|
|
cleanup(points);
|
|
return true;
|
|
}
|
|
|
|
bool FleeManager::isUseful()
|
|
{
|
|
PlayerbotAI* botAI = GET_PLAYERBOT_AI(bot);
|
|
if (!botAI) {
|
|
return false;
|
|
}
|
|
GuidVector units = *botAI->GetAiObjectContext()->GetValue<GuidVector>("possible targets no los");
|
|
for (GuidVector::iterator i = units.begin(); i != units.end(); ++i)
|
|
{
|
|
Creature* creature = botAI->GetCreature(*i);
|
|
if (!creature)
|
|
continue;
|
|
|
|
if (startPosition.sqDistance(WorldPosition(creature)) < creature->GetAttackDistance(bot) * creature->GetAttackDistance(bot))
|
|
return true;
|
|
|
|
// float d = sServerFacade->GetDistance2d(unit, bot);
|
|
// if (sServerFacade->IsDistanceLessThan(d, sPlayerbotAIConfig->aggroDistance)) return true;
|
|
}
|
|
|
|
return false;
|
|
}
|