Core/Movement: Fix LoS issue of NPCs chasing targets
Add Line of Sight checks to WorldObject::GetNearPoint(), fixing to TargetedMovementGenerator not reaching a point with valid LoS to the target and MotionMaster::MoveKnockbackFrom() knocking creatures inside walls. Remove unused code.
This commit is contained in:
1 parent
b717ce0eda
commit
8927a04253
2 files changed
+19
-103
No files matched your search
@@ -2489,125 +2489,36 @@ void WorldObject::GetNearPoint(WorldObject const* /*searcher*/, float &x, float
|
||||
{
|
||||
GetNearPoint2D(x, y, distance2d+searcher_size, absAngle);
|
||||
z = GetPositionZ();
|
||||
// Should "searcher" be used instead of "this" when updating z coordinate ?
|
||||
UpdateAllowedPositionZ(x, y, z);
|
||||
|
||||
/*
|
||||
// if detection disabled, return first point
|
||||
if (!sWorld->getIntConfig(CONFIG_DETECT_POS_COLLISION))
|
||||
{
|
||||
UpdateGroundPositionZ(x, y, z); // update to LOS height if available
|
||||
if (!sWorld->getBoolConfig(CONFIG_DETECT_POS_COLLISION))
|
||||
return;
|
||||
}
|
||||
|
||||
// or remember first point
|
||||
// return if the point is already in LoS
|
||||
if (IsWithinLOS(x, y, z))
|
||||
return;
|
||||
|
||||
// remember first point
|
||||
float first_x = x;
|
||||
float first_y = y;
|
||||
bool first_los_conflict = false; // first point LOS problems
|
||||
float first_z = z;
|
||||
|
||||
// prepare selector for work
|
||||
ObjectPosSelector selector(GetPositionX(), GetPositionY(), GetObjectSize(), distance2d+searcher_size);
|
||||
|
||||
// adding used positions around object
|
||||
// loop in a circle to look for a point in LoS using small steps
|
||||
for (float angle = M_PI / 8; angle < M_PI * 2; angle += M_PI / 8)
|
||||
{
|
||||
CellCoord p(Trinity::ComputeCellCoord(GetPositionX(), GetPositionY()));
|
||||
Cell cell(p);
|
||||
cell.SetNoCreate();
|
||||
|
||||
Trinity::NearUsedPosDo u_do(*this, searcher, absAngle, selector);
|
||||
Trinity::WorldObjectWorker<Trinity::NearUsedPosDo> worker(this, u_do);
|
||||
|
||||
TypeContainerVisitor<Trinity::WorldObjectWorker<Trinity::NearUsedPosDo>, GridTypeMapContainer > grid_obj_worker(worker);
|
||||
TypeContainerVisitor<Trinity::WorldObjectWorker<Trinity::NearUsedPosDo>, WorldTypeMapContainer > world_obj_worker(worker);
|
||||
|
||||
CellLock<GridReadGuard> cell_lock(cell, p);
|
||||
cell_lock->Visit(cell_lock, grid_obj_worker, *GetMap(), *this, distance2d);
|
||||
cell_lock->Visit(cell_lock, world_obj_worker, *GetMap(), *this, distance2d);
|
||||
}
|
||||
|
||||
// maybe can just place in primary position
|
||||
if (selector.CheckOriginal())
|
||||
{
|
||||
UpdateGroundPositionZ(x, y, z); // update to LOS height if available
|
||||
|
||||
if (IsWithinLOS(x, y, z))
|
||||
return;
|
||||
|
||||
first_los_conflict = true; // first point have LOS problems
|
||||
}
|
||||
|
||||
float angle; // candidate of angle for free pos
|
||||
|
||||
// special case when one from list empty and then empty side preferred
|
||||
if (selector.FirstAngle(angle))
|
||||
{
|
||||
GetNearPoint2D(x, y, distance2d, absAngle+angle);
|
||||
GetNearPoint2D(x, y, distance2d + searcher_size, absAngle + angle);
|
||||
z = GetPositionZ();
|
||||
UpdateGroundPositionZ(x, y, z); // update to LOS height if available
|
||||
|
||||
UpdateAllowedPositionZ(x, y, z);
|
||||
if (IsWithinLOS(x, y, z))
|
||||
return;
|
||||
}
|
||||
|
||||
// set first used pos in lists
|
||||
selector.InitializeAngle();
|
||||
|
||||
// select in positions after current nodes (selection one by one)
|
||||
while (selector.NextAngle(angle)) // angle for free pos
|
||||
{
|
||||
GetNearPoint2D(x, y, distance2d, absAngle+angle);
|
||||
z = GetPositionZ();
|
||||
UpdateGroundPositionZ(x, y, z); // update to LOS height if available
|
||||
|
||||
if (IsWithinLOS(x, y, z))
|
||||
return;
|
||||
}
|
||||
|
||||
// BAD NEWS: not free pos (or used or have LOS problems)
|
||||
// Attempt find _used_ pos without LOS problem
|
||||
|
||||
if (!first_los_conflict)
|
||||
{
|
||||
x = first_x;
|
||||
y = first_y;
|
||||
|
||||
UpdateGroundPositionZ(x, y, z); // update to LOS height if available
|
||||
return;
|
||||
}
|
||||
|
||||
// special case when one from list empty and then empty side preferred
|
||||
if (selector.IsNonBalanced())
|
||||
{
|
||||
if (!selector.FirstAngle(angle)) // _used_ pos
|
||||
{
|
||||
GetNearPoint2D(x, y, distance2d, absAngle+angle);
|
||||
z = GetPositionZ();
|
||||
UpdateGroundPositionZ(x, y, z); // update to LOS height if available
|
||||
|
||||
if (IsWithinLOS(x, y, z))
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// set first used pos in lists
|
||||
selector.InitializeAngle();
|
||||
|
||||
// select in positions after current nodes (selection one by one)
|
||||
while (selector.NextUsedAngle(angle)) // angle for used pos but maybe without LOS problem
|
||||
{
|
||||
GetNearPoint2D(x, y, distance2d, absAngle+angle);
|
||||
z = GetPositionZ();
|
||||
UpdateGroundPositionZ(x, y, z); // update to LOS height if available
|
||||
|
||||
if (IsWithinLOS(x, y, z))
|
||||
return;
|
||||
}
|
||||
|
||||
// BAD BAD NEWS: all found pos (free and used) have LOS problem :(
|
||||
// still not in LoS, give up and return first position found
|
||||
x = first_x;
|
||||
y = first_y;
|
||||
|
||||
UpdateGroundPositionZ(x, y, z); // update to LOS height if available
|
||||
*/
|
||||
z = first_z;
|
||||
}
|
||||
|
||||
void WorldObject::GetClosePoint(float &x, float &y, float &z, float size, float distance2d /*= 0*/, float angle /*= 0*/) const
|
||||
|
||||
@@ -159,10 +159,15 @@ bool TargetedMovementGeneratorMedium<T, D>::DoUpdate(T* owner, uint32 time_diff)
|
||||
if (TransportBase* transport = owner->GetDirectTransport())
|
||||
transport->CalculatePassengerPosition(dest.x, dest.y, dest.z);
|
||||
|
||||
// First check distance
|
||||
if (owner->GetTypeId() == TYPEID_UNIT && owner->ToCreature()->CanFly())
|
||||
targetMoved = !i_target->IsWithinDist3d(dest.x, dest.y, dest.z, allowed_dist);
|
||||
else
|
||||
targetMoved = !i_target->IsWithinDist2d(dest.x, dest.y, allowed_dist);
|
||||
|
||||
// then, if the target is in range, check also Line of Sight.
|
||||
if (!targetMoved)
|
||||
targetMoved = !i_target->IsWithinLOSInMap(owner);
|
||||
}
|
||||
|
||||
if (i_recalculateTravel || targetMoved)
|
||||
|
||||
Reference in new issue
Block a user