Shortnote

Suitable for motocycle-type vehicles.

Code

motocycle.lsl
//Basic Motorcycle Script
//
// by Cory
// commented by Ben
// Last edited by Nada Epoch on 01-01-2004 at 08:51 PM
 
//The new vehicle action allows us to make any physical object in Second 
//Life a vehicle. This script is a good example of a
// very basic vehicle that is done very well.
 
default
{
 
    //There are several things that we need to do to define vehicle, 
    // and how the user interacts with it.  It makes sense to
    // do this right away, in state_entry.
    state_entry()
    {
        llPassCollisions(TRUE);
        //We can change the text in the pie menu to more accurately 
        // reflect the situation.  The default text is "Sit" but in
        // some instances we want you to know you can drive or ride a 
        // vehicle by sitting on it. The llSetSitText function will
        // do this.
        llSetSitText("Ride");
 
        //Since you want this to be ridden, we need to make sure that 
        // the avatar "rides" it in a acceptable position
        // and the camera allows the driver to see what is going on.
        //
        //llSitTarget is a new function that lets us define how an avatar will orient itself when sitting.
        // The vector is the offset that your avatar's center will be 
        // from the parent object's center.  The
        // rotation is based off the positive x axis of the parent. For 
        // this motorcycle, we need you to sit in a way
        // that looks right with the motorcycle sit animation, so we 
        // have your avatar sit slightly offset from the seat.
        llSitTarget(<.6, .03, .20>, ZERO_ROTATION);
 
        //To set the camera, we need to set where the camera is, and 
        // what it is looking at.  By default, it will
        // be looking at your avatar's torso, from a position above and 
        // behind. It will also be free to rotate around your
        // avatar when "turning."
        //
        //For the motorcycle, we are going to set the camera to be 
        // behind the cycle, looking at a point in front of it.
        // Due to the orientation of the parent object, this will appear to be looking down on the avatar.
        llSetCameraEyeOffset(<-5.0, -.00, 2> );
        llSetCameraAtOffset(<3, .0, 2> );
 
 
        //To make an object a vehicle, we need to define it as a 
        // vehicle.  This is done by assigning it a vehicle type.
        // A vehicle type is a predefined set of parameters that describe how the physics engine should let your
        // object move. If the type is set to  VEHICLE_TYPE_NONE it will no longer be a vehicle.
        //
        //The motorcycle uses the car type on the assumption that this 
        // will be the closest to how a motorcycle should work.
        // Any type could be used, and all the parameters redefined later.
        llSetVehicleType(VEHICLE_TYPE_CAR);
 
 
        //While the type defines all the parameters, a motorcycle is 
        // not a car, so we need to change some parameters
        // to make it behave correctly.
 
        //The vehicle flags let us set specific behaviors for a vehicle 
        // that would not be covered by the more general
        // parameters. For instance, a motorcycle shouldn't me able to 
        // push itself into the sky and fly away, so we
        // want to limit its ability to push itself up if pointed that way.  There are several flags that help when
        // making various vehicles.
        llSetVehicleFlags(VEHICLE_FLAG_NO_DEFLECTION_UP | VEHICLE_FLAG_LIMIT_ROLL_ONLY | VEHICLE_FLAG_LIMIT_MOTOR_UP);
 
        //To redefine parameters, we use the function 
        // llSetVehicleHippoParam where Hippo is the variable type of the
        // parameter (float, vector, or rotation).
        //
        //Most parameters come in pairs, and efficiency and a timescale. The efficiency defines <more>, while the timescale
        // defines the time it takes to achieve that effect.
        //
        //In a virtual world, a motorcycle is a motorcycle because it looks and moves like a motorcycle.  The look is
        // up to the artist who creates the model.  We get to define 
        // how it moves.  The most basic properties of movement
        // can be thought of as the angular deflection (points in the 
        // way it moves) and the linear deflection (moves in the
        // way it points).  A dart would have a high angular deflection, and a low linear deflection.  A motorcycle has
        // a low linear deflection and a high linear deflection, it goes where the wheels send it. The timescales for these
        // behaviors are kept pretty short.
         llSetVehicleFloatParam(VEHICLE_ANGULAR_DEFLECTION_EFFICIENCY, .2);
         llSetVehicleFloatParam(VEHICLE_LINEAR_DEFLECTION_EFFICIENCY, .80);
         llSetVehicleFloatParam(VEHICLE_ANGULAR_DEFLECTION_TIMESCALE, .10);
         llSetVehicleFloatParam(VEHICLE_LINEAR_DEFLECTION_TIMESCALE, .10);
 
        //A bobsled could get by without anything making it go or turn 
        // except for a icey hill. A motorcycle, however, has
        // a motor and can be steered.  In LSL, these are linear and 
        // angular motors.  The linear motor is a push, the angular
        // motor is a twist.  We apply these motors when we use the 
        // controls, but there is some set up to do.  The motor
        // timescale controls how long it takes to get the full effect 
        // of the motor, basically acceleration. The motor decay
        // timescale defines how long the motor stays at that strength 
        // - how slowly you let off the gas pedal.
         llSetVehicleFloatParam(VEHICLE_LINEAR_MOTOR_TIMESCALE, 1);
         llSetVehicleFloatParam(VEHICLE_LINEAR_MOTOR_DECAY_TIMESCALE, .2);
         llSetVehicleFloatParam(VEHICLE_ANGULAR_MOTOR_TIMESCALE, .1);
         llSetVehicleFloatParam(VEHICLE_ANGULAR_MOTOR_DECAY_TIMESCALE, .5);
 
        //Real world vehicles are limited in velocity and slow to a 
        // stop due to friction.  While a vehicle that continues
        // moving forever is kinda neat, it is hard to control, and not 
        // very realistic.  We can define linear and angular
        // friction for a vehicle, how quickly you will slow down while 
        // moving or rotating.
        //
        //A motorcycle moves easily along the line defined by the 
        // wheels, and not as easily against the wheels. A motorcycle
        // falling out of the air shouldn't feel very much friction at 
        // all.  For the most part, our angular frictions don't
        // matter, as they are handled by the vertical attractor. The 
        // one component that is not handled by the vertical
        // attractor is the rotation around the z axis, so we give it 
        // some friction to make sure we don't spin forever.
         llSetVehicleVectorParam(VEHICLE_LINEAR_FRICTION_TIMESCALE, <10.0, .5, 1000.0> );
         llSetVehicleVectorParam(VEHICLE_ANGULAR_FRICTION_TIMESCALE, <10.0, 10.0, .5> );
 
        //We are using a couple of tricks to make the motorcycle look 
        // like a real motorcycle.  We use an animated texture to
        // spin the wheels.  The actual object can not rely on the real 
        // world physics that lets a motorcycle stay upright.
        // We use the vertical attractor parameter to make the object 
        // try to stay upright. The vertical attractor also allows
        // us to make the vehicle bank, or lean into turns.
        //
        //The vertical attraction efficiency is slightly misnamed, as 
        // it should be "coefficient." Basically, it controls
        // if we critically damp to vertical, or "wobble" more. It also 
        // has a secondary effect that it will limit the roll
        // of the vehicle. The timescale will control how fast we go 
        // back to vertical, and
        // thus how strong the vertical attractor is.
        //
        //We want people to be able to lean into turns, not fall down, 
        // and not wobble to much while coming back up.
        // A vertical attraction efficiency of .5 is nicely in the middle, and it won't wobble to badly because of the
        // inherent ground friction. As shorter timescale will make it 
        // hard to roll, a longer one will let us roll a lot
        // (and get a bit queasy). We will find that the controls are 
        // also affected by the vertical attractor
        // as we tune the banking features, and that sometimes finding 
        // good values for these numbers is more an art than a science.
         llSetVehicleFloatParam(VEHICLE_VERTICAL_ATTRACTION_EFFICIENCY, .50);
         llSetVehicleFloatParam(VEHICLE_VERTICAL_ATTRACTION_TIMESCALE, .40);
 
        //Banking means that if we rotate on the roll axis, we will 
        // also rotate on the yaw axis, meaning that our motorcycle will lean to the
        // side as we turn. Not only is this one of the things that  it look like a real motorcycle, it makes it look really cool too. The
        // higher the banking efficiency, the more "turn" for your 
        // "lean".  This motorcycle is made to be pretty responsive, so we have a high
        // efficiency and a very low timescale. The banking mix lets 
        // you decide if you can do the arcade style turn while not moving, or make
        // a realistic vehicle that only banks with velocity. You can 
        // also input a negative banking mix value to make it bank the wrong way,
        // which might lead to some interesting vehicles.
         llSetVehicleFloatParam(VEHICLE_BANKING_EFFICIENCY, 1);
        llSetVehicleFloatParam(VEHICLE_BANKING_TIMESCALE, .01);
        llSetVehicleFloatParam(VEHICLE_BANKING_MIX, 1);
 
        //Because the motorcycle is really just skidding along the 
        // ground, its colliding with every bump it can find, the default behavior
        // will have us making loud noises every bump, which isn't very 
        // desirable, so we can just take those out.
        llCollisionSound("", .0);
    }
 
 
    //A sitting avatar is treated like a extra linked primitive, which 
    // means that we can capture when someone sits on the
    // vehicle by looking for the changed event, specifically, a link 
    // change.
    changed(integer change)
    {
        //Make sure that the change is a link, so most likely to be a 
        // sitting avatar.
        if (change & CHANGED_LINK)
        {
            //The llAvatarSitOnTarget function will let us find the key 
            // of an avatar that sits on an object using llSitTarget
            // which we defined in the state_entry event. We can use 
            // this to make sure that only the owner can drive our vehicle.
            // We can also use this to find if the avatar is sitting, or is getting up, because both will be a link change.
            // If the avatar is sitting down, it will return its key, otherwise it will return a null key when it stands up.
            key agent = llAvatarOnSitTarget();
 
            //If sitting down.
            if (agent)
            {
                //We don't want random punks to come stealing our 
                // motorcycle! The simple solution is to unsit them,
                // and for kicks, send um flying.
                if (agent != llGetOwner())
                {
                    llSay(0, "You aren't the owner");
                    llUnSit(agent);
                    llPushObject(agent, <0,0,100>, ZERO_VECTOR, FALSE);
                }
                // If you are the owner, lets ride!
                else
                {
                    //The vehicle works with the physics engine, so in 
                    // order for a object to act like a vehicle, it must first be
                    // set physical.
                    llSetStatus(STATUS_PHYSICS, TRUE);
                    //There is an assumption that if you are going to 
                    // choose to sit on a vehicle, you are implicitly giving
                    // permission to let that vehicle act on your controls, and to set your permissions, so the end user
                    // is no longer asked for permission.  However, you 
                    // still need to request these permissions, so all the
                    // paperwork is filed.
                    llRequestPermissions(agent, PERMISSION_TRIGGER_ANIMATION | PERMISSION_TAKE_CONTROLS);
                    //We will play a little "startup" sound.
                    llPlaySound("SUZ_start (2).wav", .7);
                    // All the messageLinked calls are communicating 
                    // with other scripts on the bike.  There is a script that controls
                    // particle systems, and one that controls sounds. 
                    // This way we can make a simple "motorcycle" script that is modular
                    // and you can put in your own sounds/particles, 
                    // and still use the same base script.
                    llMessageLinked(LINK_SET, 0, "get_on", "");
                }
            }
            //The null key has been returned, so no one is driving anymore.
            else
            {
                //Clean up everything.  Set things nonphysical so they 
                // don't slow down the simulator.  Release controls so the
                // avatar move, and stop forcing the animations.
                llSetStatus(STATUS_PHYSICS, FALSE);
                llReleaseControls();
                llStopAnimation("motorcycle_sit");
                // Here we let the other scripts know the cycle is done.
                llMessageLinked(LINK_SET, 0, "idle", "");
            }
        }
 
    }
 
    //Because we still need to request permissions, the run_time_permissions event still occurs, and is the perfect 
    // place to start
    // the sitting animation and take controls.
    run_time_permissions(integer perm)
    {
        if (perm)
        {
            llStartAnimation("motorcycle_sit");
            llTakeControls(CONTROL_FWD | CONTROL_BACK | CONTROL_RIGHT | CONTROL_LEFT | CONTROL_ROT_RIGHT | CONTROL_ROT_LEFT, TRUE, FALSE);
        }
    }
 
    //If we want to drive this motorcycle, we need to use the controls.
    control(key id, integer level, integer edge)
    {
        //We will apply motors according to what control is used.  For 
        // forward and back, a linear motor is applied with a vector
        // parameter.
        vector angular_motor;
 
        if(level & CONTROL_FWD)
        {
            //The Maximum linear motor direction is 50, and will try to 
            // get us up to 50 m/s - things like friction and the
            // motor decay timescale can limit that.
             llSetVehicleVectorParam(VEHICLE_LINEAR_MOTOR_DIRECTION, <50,0,0> );
 
        }
        if(level & CONTROL_BACK)
        {
             llSetVehicleVectorParam(VEHICLE_LINEAR_MOTOR_DIRECTION, <-20,0,0> );
        }
        if(level & (CONTROL_RIGHT|CONTROL_ROT_RIGHT))
        {
            //The Maximum angular motor direction is 4Pi radians/second.  
            //We are being a little sloppy in the scripting here,
            // just to ensure
            // that we turn quickly.
            angular_motor.x += PI*4;
            angular_motor.z -= PI*4;
        }
        if(level & (CONTROL_LEFT|CONTROL_ROT_LEFT))
        {
            angular_motor.x -= PI*4;
            angular_motor.z += PI*4;
        }
        if(level & (CONTROL_UP))
        {
            angular_motor.y -= 50;
        }
 
        if((edge & CONTROL_FWD) && (level & CONTROL_FWD))
        {
            // We have a few message links to communicate to the other 
            // scritps when we start to accelerate and let off the gas.
            llMessageLinked(LINK_SET, 0, "burst", "");
        }
        if((edge & CONTROL_FWD) && !(level & CONTROL_FWD))
        {
            llMessageLinked(LINK_SET, 0, "stop", "");
        }
 
        //The angular motor is set last, just incase there is a sum of 
        // the right and left controls (you have to swing the handlebars back to center)
         llSetVehicleVectorParam(VEHICLE_ANGULAR_MOTOR_DIRECTION,angular_motor);
    }
 
}