EDIT: there was a mistake in the code (ActionForceMoveToObject() in the “positive” mode needed); I fixed it, but then I realized this can be improved further to stop at random locations on an annulus instead of a circle; size of exclusion zone near the center is controlled with fNear parameter.
Try this code. It has two modes:
- stop at constant random distance on the way towards target (useful when NPCs converge from scattered starting points)
- move to random location near the target (useful when NPCs move from similar starting points)
// Causes caller (OBJECT_SELF) to get close to the location of oTarget.
// * |fNear| must not be larger than |fFar| (absolute value comparison)
// * if fFar >= 0.0, caller stops at random location within [|fNear|, |fFar|]
// range from oTarget (point on the shortest path to oTarget)
// * if fFar < 0.0, caller stops at random location within [|fNear|, |fFar|]
// range from oTarget (point on a ring centered at oTarget)
// * iRun = if caller should run to oTarget (TRUE/FALSE)
// * oFace = object caller should face after arrival (can be oTarget)
void NWSH_MoveCloseToObject(object oTarget, float fFar=0.0, float fNear=0.0, int iRun=TRUE, object oFace=OBJECT_INVALID)
{
location lTarget;
int iNegative;
iNegative = fFar < 0.0;
fFar = fabs(fFar);
fNear = fabs(fNear);
if(fNear > fFar || GetArea(oTarget) != GetArea(OBJECT_SELF))
{
return;
}
fNear += (fFar - fNear) * Random(32768) / 32768.0;
if(iNegative)
{
lTarget = Location(GetArea(oTarget), GetPosition(oTarget) +
AngleToVector(IntToFloat(Random(360))) * fNear,
GetFacing(oTarget));
ActionForceMoveToLocation(lTarget, iRun);
}
else
{
ActionForceMoveToObject(oTarget, iRun, fNear);
}
if(GetIsObjectValid(oFace))
{
ActionDoCommand(SetFacingPoint(GetPosition(oFace)));
}
}