NPCs walking all over each other when they have the same waypoint, any way to let them settle at a distance?

I’m hoping I can set something where they are happy enough to be within 10 feet or something of the waypoint, so they aren’t constantly walking into each other. So far all scripts are defaults (nw_c2_default* or X2_def*).

I can use NWN:EE, but am currently sticking to NWN 1.68 for more players, but it’s probably not worth it at this point.

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)));
    }
}
2 Likes