ActionCruise

What it does
ActionCruise is an action Similar to ActionRandomWalk, but it keeps the creature moving. If the focus object argument is given, it will be used to constrain the wanderings of the creature to with the specified distance (2nd argument) of the focus object.

The Script
// Tibrogargan's ActionCruise Script // October 2002 int TB_CRUISE_BIAS_ANGLE = 20; string TB_CRUISE_ADJUST = "tb.cruise.adjust"; string TB_CRUISE_LOCATION = "tb.cruise.location"; string TB_CRUISE_BIAS = "tb.cruise.bias"; // ActionCruise is an action Similar to ActionRandomWalk, but it keeps // the creature moving. If the focus object argument is given, it will // be used to constrain the wanderings of the creature to with the // specified distance (2nd argument) of the focus object void ActionCruise(object focus=OBJECT_INVALID, float fMaxDist = 40.0f) {   int bias = 1; float fDistToFocus; location loc; location locFocus; float facing = GetFacing(OBJECT_SELF); location locSelf = GetLocation(OBJECT_SELF); int nAngleAdjust = GetLocalInt(OBJECT_SELF, TB_CRUISE_ADJUST); float fDist = 25.0f; // this distance should be far enough so that the // creature will not stop between heartbeats, giving // a smooth transition // First, check to see if we're stuck on something if (locSelf == GetLocalLocation(OBJECT_SELF, TB_CRUISE_LOCATION)) {       nAngleAdjust += 30; // the longer we're stuck, the more we should // vary the angle we check for new locations SetLocalInt(OBJECT_SELF, TB_CRUISE_ADJUST, nAngleAdjust); }   else {       // we're not stuck anymore, zero the adjustment angle DeleteLocalInt(OBJECT_SELF, TB_CRUISE_ADJUST); }   // remember where we are for next time SetLocalLocation(OBJECT_SELF, TB_CRUISE_LOCATION, locSelf); // get our bias. If it doesn't exist, calculate it   // The bias causes the creature to tend to walk in circles, either // left or right. (They are very large circles, so the bias isn't   // pronounced) if (0 == (bias = GetLocalInt(OBJECT_SELF, TB_CRUISE_BIAS))) {       bias = (Random(2) * 2) - 1; SetLocalInt(OBJECT_SELF, TB_CRUISE_BIAS, bias); }   // if you don't clear all actions, the old moves get stuck in the queue // and make the creature try to complete them if it ever gets to the end // of the current move - this leads to bizarre changes in direction ClearAllActions; // if there's a valid focus, work out relevant factors if (GetIsObjectValid(focus)) {       locFocus = GetLocation(focus); fDistToFocus = GetDistanceBetweenLocations(locFocus, locSelf); }   do    { // calculate a new facing. Normally it will be within 45 degrees of       // the current facing, offset by the bias. If we're stuck, or too // far away from the focus, the potential angle grows int nAngle = 90 + nAngleAdjust + (bias * TB_CRUISE_BIAS_ANGLE) - 45; // if we let the angle go over 360, we could be making a stuck creature // stay stuck longer by increasing the chance they get a facing that is       // relatively forward if (nAngle > 360) {           nAngle = 360; }       float fNewFacing = IntToFloat((FloatToInt(facing) + Random(nAngle)) % 360); // only reason this is done is because the docs say facings are between // 0 and 360. It seems to work fine if using angles 360 if (fNewFacing < 0.0f) {           fNewFacing += 360.0; }       // generate the new location to move to        loc = Location(GetArea(OBJECT_SELF),                       GetPosition(OBJECT_SELF) +                            Vector(cos(fNewFacing) * fDist, sin(fNewFacing) * fDist, 0.0f),                      fNewFacing); // add to the adjustment angle nAngleAdjust += 30; // we can stop looking for a new location if   } while (GetIsObjectValid(focus) && // there's no focus             ((fDistToFocus > fMaxDist) && // we're too far from the focus and // the new location is closer to the focus than we are now (GetDistanceBetweenLocations(locFocus, loc) > fDistToFocus))); ActionMoveToLocation(loc); }