written by Northwest Portland

 

This is your basic don't push me script . Useful if you're around places where someone might take it into their head to run over, shoot, or otherwise molest you. You know, places like SL! It has no configuration but it really doesn't need any. It shouldn't interfere with regular movement at all.

 

When you stop moving, it kicks in, when you move yourself (rather than someone else doing it for you) it lets go. Only requirement is that it needs to be in an attachment.

integer attached = FALSE;
integer key_pressed = FALSE;
integer movement_locked = FALSE;
vector lock_position = ZERO_VECTOR;

lock()
{
    movement_locked = TRUE;
    
    // Basic move lock consists of an llMoveToTarget.
    lock_position = llGetPos();
    llMoveToTarget(lock_position, 0.05);
    
    // This is a bit of a hack, but the idea is to set friction on an avatar.
    // The only way to do that is to make the avatar a vehicle, so we do.
    llSetVehicleType(VEHICLE_TYPE_SLED);
    llSetVehicleVectorParam(VEHICLE_LINEAR_FRICTION_TIMESCALE, <0.05, 0.05, 0.05>);
}

unlock()
{
    movement_locked = FALSE;
    
    llStopMoveToTarget();
    
    // We have to make sure that we remove the vehicle status from the avatar
    // when moving, instead of just removing the friction.  Being a vehicle
    // has strange side effects on a moving avatar.
    llSetVehicleType(VEHICLE_TYPE_NONE);
}

move_lock()
{
    if (!attached) return;
    
    // Collect some relevant information about what that avatar is doing.
    vector velocity = llGetVel();
    integer agent_info = llGetAgentInfo(llGetOwner());
    integer is_flying = ((agent_info & AGENT_FLYING) != 0);
    integer is_falling = ((agent_info & AGENT_IN_AIR) != 0) && !is_flying;
    string animation = llGetAnimation(llGetOwner());
    
    if (movement_locked)
    {
        // If the agent is sitting, or pressing keys, or trying to fall
        // straight down, or starting to jump, then unlock.
        if ((agent_info & AGENT_SITTING) != 0 || key_pressed || (llVecMag(velocity) < 0.1 && is_falling) || animation == "PreJumping")
        {
            unlock();
        }
        // If something has managed to push the avatar over 10 meters from
        // where the lock was set, then the move to target will probably have
        // lost it's effect, and it needs to be reset.
        else if (llVecDist(lock_position, llGetPos()) > 10.0)
        {
            // Relock if the lock was broken.
            lock();
        }
    }
    else
    {
        // If the avatar is not sitting, not jumping, moving slower than
        // 0.1 m/s on the ground or hovering, then lock position.
        if ((agent_info & AGENT_SITTING) == 0 && animation != "PreJumping")
        {
            if (llVecMag(velocity) < 0.1 || (is_flying && llVecMag() < 0.25 && velocity.z > -4.0 && velocity.z < 0.25))
            {
                lock();
            }
        }
    }
}

initialize()
{
    llOwnerSay("Initializing Move Lock...");
    
    attached = TRUE;
    
    llRequestPermissions(llGetOwner(), PERMISSION_TAKE_CONTROLS);
}

finalize()
{
    attached = FALSE;
    
    llReleaseControls();
    llSetTimerEvent(0.0);
    
    unlock();
    
    llOwnerSay("Move Lock Finalized.");
}

default
{
    state_entry()
    {
        if (llGetAttached() != 0)
        {
            initialize();
        }
    }
    
    on_rez(integer sparam)
    {
        // If for some reason detach didn't stop move lock and then it was
        // rezzed but NOT attached, then there could be bad things happening.
        // To avoid that, check on rez to see if it's attached and if not then
        // make sure that move lock is off.
        if (llGetAttached() == 0)
        {
            finalize();
        }
    }
    
    attach(key id)
    {
        // Start when attached and stop when detached.
        if (id != NULL_KEY)
        {
            initialize();
        }
        else
        {
            finalize();
        }
    }
    
    run_time_permissions(integer perms)
    {
        if ((perms & PERMISSION_TAKE_CONTROLS) != 0)
        {
            llTakeControls(CONTROL_FWD | CONTROL_BACK | CONTROL_LEFT | CONTROL_RIGHT | CONTROL_UP | CONTROL_DOWN, TRUE, TRUE);
            llSetTimerEvent(0.2);
            
            llOwnerSay("Move Lock Initialized.");
        }
    }
    
    control(key id, integer level, integer edge)
    {
        if (level != 0)
        {
            if (!key_pressed)
            {
                key_pressed = TRUE;
                
                // When a key is pressed, cancel the timer and just use the
                // control event to check the move lock state.  The control
                // event would fire every 0.05 seconds on it's own which is way
                // too fast and unnecessary, so limit it to 0.2 with
                // llMinEventDelay.
                llSetTimerEvent(0.0);
                llMinEventDelay(0.2);
                
                // if keys are pressed we should always be unlocked, so just
                // skip the check and unlock.
                unlock();
            }
        }
        else
        {
            if (key_pressed)
            {
                key_pressed = FALSE;
                
                // Restore the timer since this is the last time the control
                // event will fire.  Restore the minimum event delay so that
                // the next time you push a key it is caught immediately.
                llSetTimerEvent(0.2);
                llMinEventDelay(0.0);
                
                // Check move lock state immediately rather than waiting for
                // the next timer tick.
                move_lock();
            }
        }
    }
    
    timer()
    {
        move_lock();
    }
}