mirror of
https://github.com/mod-playerbots/azerothcore-wotlk.git
synced 2026-01-18 19:35:42 +00:00
feat(Core/CreatureAI): improve npc position during the combat (#3369)
+ tangent equation to find correct angle and distance when moving + implemented proper backward * Improved performance + random angle margin * chore: add tollerance calculation in instance * improved LOS checks with movements * implemented collisions using raycast (imported by TC) + improved collision detection for CanReachPositionAndGetCoords + improved collision check + set correct flags for the backward movement + first implementation of slope angle (to improve) Co-authored-by: Yehonal <yehonal.azeroth@gmail.com>
This commit is contained in:
@@ -5,6 +5,7 @@
|
||||
*/
|
||||
|
||||
#include "Map.h"
|
||||
#include "Geometry.h"
|
||||
#include "Battleground.h"
|
||||
#include "CellImpl.h"
|
||||
#include "DynamicTree.h"
|
||||
@@ -710,7 +711,7 @@ void Map::Update(const uint32 t_diff, const uint32 s_diff, bool /*thread*/)
|
||||
{
|
||||
if (t_diff)
|
||||
_dynamicTree.update(t_diff);
|
||||
|
||||
|
||||
/// update worldsessions for existing players
|
||||
for (m_mapRefIter = m_mapRefManager.begin(); m_mapRefIter != m_mapRefManager.end(); ++m_mapRefIter)
|
||||
{
|
||||
@@ -3391,3 +3392,121 @@ void Map::SetZoneOverrideLight(uint32 zoneId, uint32 lightId, uint32 fadeInTime)
|
||||
player->SendDirectMessage(&data);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* \param maxDeviationAngle the maximum deviation that a creature can take to reach the destination
|
||||
*
|
||||
*/
|
||||
bool Map::CanReachPositionAndGetCoords(Unit* who, PathGenerator path, bool checkCollision /*= true */, float maxHeight/* = 3.0f */, float maxSlopeAngle/* = M_PI/2 */, float maxDeviationAngle /*= M_PI*2 */) const
|
||||
{
|
||||
double deviation = 0.0f;
|
||||
G3D::Vector3 prevPath = path.GetStartPosition();
|
||||
for (auto & vector : path.GetPath())
|
||||
{
|
||||
float x = vector.x;
|
||||
float y = vector.y;
|
||||
float z = vector.z;
|
||||
|
||||
deviation += who->GetRelativeAngle(x, y);
|
||||
|
||||
// to reach the position the Unit must deviate
|
||||
// the straight path with a higher margin than the one desired
|
||||
// in this case we return false
|
||||
if (deviation > maxDeviationAngle)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
float ang = getAngle(prevPath.x, prevPath.y, x, y);
|
||||
|
||||
if (CanReachPositionAndGetCoords(who, prevPath.x, prevPath.y, prevPath.z, ang, x, y, z, checkCollision, maxHeight, maxSlopeAngle))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
prevPath = vector;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Map::CanReachPositionAndGetCoords(Unit* who, float &destX, float &destY, float &destZ, bool checkCollision /*= true */, float maxHeight/* = 3.0f */, float maxSlopeAngle/* = M_PI/2 */) const
|
||||
{
|
||||
return CanReachPositionAndGetCoords(who, who->GetPositionX(), who->GetPositionY(), who->GetPositionZ(), who->GetOrientation(), destX, destY, destZ, checkCollision, maxHeight, maxSlopeAngle);
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief validate the new destination
|
||||
*
|
||||
* Check if a given unit can reach a specific point and set the correct Z coord based on difference in height
|
||||
*
|
||||
* \param maxHeight the desired max Height for the calculated Z coord. If the new Z exceed the maxHeight, this method returns false
|
||||
|
||||
* \return true if the destination is valid, false otherwise
|
||||
*
|
||||
**/
|
||||
bool Map::CanReachPositionAndGetCoords(Unit* who, float startX, float startY, float startZ, float startAngle, float &destX, float &destY, float &destZ, bool checkCollision /*= true */, float maxHeight/* = 3.0f */, float maxSlopeAngle/* = M_PI/2 */) const
|
||||
{
|
||||
acore::NormalizeMapCoord(destX);
|
||||
acore::NormalizeMapCoord(destY);
|
||||
|
||||
const Map* _map = who->GetBaseMap();
|
||||
|
||||
// check map geometry for possible collision
|
||||
if (checkCollision)
|
||||
{
|
||||
Position pos = Position(startX, startY, startZ, startAngle);
|
||||
|
||||
auto distance = pos.GetExactDist2d(destX,destY);
|
||||
|
||||
auto collided = who->MovePositionToFirstCollision(pos, distance, pos.GetRelativeAngle(destX,destY));
|
||||
|
||||
destX = pos.GetPositionX();
|
||||
destY = pos.GetPositionY();
|
||||
destZ = pos.GetPositionZ();
|
||||
|
||||
if (collided)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// otherwise calculate a new z
|
||||
destZ = _map->GetHeight(who->GetPhaseMask(), destX, destY, destZ, true);
|
||||
}
|
||||
|
||||
|
||||
if (destZ <= INVALID_HEIGHT || (destZ - startZ) > maxHeight)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
float slopeAngle = getSlopeAngleAbs(startX, startY, startZ, destX, destY, destZ);
|
||||
|
||||
if (slopeAngle > maxSlopeAngle)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// if water environment
|
||||
bool is_water_now = _map->IsInWater(startX, startY, startZ);
|
||||
|
||||
if (!isInLineOfSight(startX, startY, startZ, destX, destY, destZ, who->GetPhaseMask(), LINEOFSIGHT_ALL_CHECKS))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool is_water_next = _map->IsInWater(destX, destY, destZ);
|
||||
|
||||
// if not compatible inhabit type for the next position, return false
|
||||
if ((is_water_now && !is_water_next && who->GetTypeId() == TYPEID_UNIT && !((Creature*)who)->CanWalk()) ||
|
||||
(!is_water_now && is_water_next && !who->CanSwim()))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// finally
|
||||
return true;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user