Car Code

Written by Kitsune
float theta_func()
{
    if (speed < 1) return 0.02;
    if (speed < 4) return 0.1;
    if (speed < 6) return .4;
    if (speed < 10) return .6;
    if (speed < 15) return .5;
    if (speed < 20) return .5;
    if (speed < 25) return .4;
     return .3;
    
}  

float power_curve()
{
    if (speed < 1) return 15.0;
    if (speed < 4) return 15.0;
    if (speed < 6) return 15.0;
    if (speed < 10) return 15.0;
    if (speed < 15) return 10.0;
    if (speed < 20) return 4.0;
    if (speed < 30) return 2.0;
    return 2.0;
}
 

float THROTTLE = 1.2;
float STEERING = 1;
float TIMER = .05;
float ANGULAR_TAU = .1;            // decrease for faster turn
float ANGULAR_DAMPING = 3;        // not sure what this should be yet
float THETA_INCREMENT = 0.05;        // increase for bigger turn response


//float C_FRICTION = 40;
//float FRONTAL_AREA = 20;
//float TOT_FRICTION;


float mass;
float speed;
vector velocity;


float turn;
float counter = 0;
float brake = 1;
// linear constants


integer a = 10;


integer LEVELS = 0;                 // we'll set this later

// global variables
vector gTargetPos;
float gTargetTheta;
key gToucher;


default
{
    state_entry()
    {
        llSay(0,"car starting");
        llSetStatus(STATUS_PHYSICS, FALSE);
        llSetStatus(STATUS_ROTATE_X | STATUS_ROTATE_Y, FALSE);
        llCollisionFilter("", "", TRUE);
        llStopSound();
        mass = llGetMass();
        
        
        llSleep(0.1);
        //SetHoverHeight(1,1,10);
        llSetStatus(STATUS_ROTATE_X | STATUS_ROTATE_Y | STATUS_ROTATE_Z , TRUE);
        
        llMoveToTarget(llGetPos() + <0,0,1>, 0);
        llRotLookAt(llGetRot(), 0, 0);
        
        
        LEVELS = CONTROL_FWD | CONTROL_BACK | CONTROL_ROT_LEFT | CONTROL_ROT_RIGHT | CONTROL_UP | CONTROL_DOWN | CONTROL_LEFT | CONTROL_RIGHT;
    }
    
    
    touch_start(integer total_number)
    {
        
        llStopSound();
        gToucher = llDetectedKey(0);
        integer perm = llGetPermissions();
        
        
        if (perm)
        {
            llReleaseControls();
        }
        else
        {
            state StateDriving;
        }
    }
}

state StateDriving
{
    state_entry()
    {
        llSetTimerEvent(TIMER);
        brake = 1;
        
        llSetStatus(STATUS_PHYSICS, TRUE);
        llSetStatus(STATUS_ROTATE_X | STATUS_ROTATE_Y | STATUS_ROTATE_Z , TRUE);
        llWhisper(0, "StateDriving");
        //llSetHoverHeight(a,1,.4);
        llRequestPermissions(gToucher, PERMISSION_TAKE_CONTROLS);
        //llMoveToTarget(llGetPos(), LINEAR_TAU);
        llRotLookAt(llGetRot(), ANGULAR_TAU, 1.0);        
    }
    touch_start(integer total_number)
    {
        llWhisper(0, "Touched.");
        integer perm = llGetPermissions();
        if (perm)
        {
            llReleaseControls();
        }
        state default;
    }
    run_time_permissions(integer perm)
    {
        if (perm == PERMISSION_TAKE_CONTROLS)
        {
            llTakeControls(LEVELS, TRUE, FALSE);        }
        else
        {
             state default;
        }
    }
    control(key driver, integer levels, integer edges)
    {
//llWhisper(0, "l = " + (string)levels + "  e = " + (string)edges);
        // linear control
        //llSetHoverHeight(a,1,.4);
        
        integer nudge = FALSE;
        float direction = 0;
        gTargetTheta *= theta_func();
        
        
        if (levels & CONTROL_FWD)
        {
            direction = 1;
            brake = 0;
        }
        if (levels & CONTROL_BACK)
        {
            direction = -.1;
            brake = 5;
            gTargetTheta *= 2;
        }
        if (levels & CONTROL_LEFT)
        {
            
        }
        if (levels & CONTROL_RIGHT)
        {
           
        }
        if (levels & CONTROL_UP)
        {
            a +=1;
        }
        if (levels & CONTROL_DOWN)
        {
           a-=1;
        }
        // angular control
        if (levels & CONTROL_ROT_LEFT)
        {
            if (gTargetTheta < 0)
            {
                gTargetTheta = 0;
            }
            else
            {
                gTargetTheta += THETA_INCREMENT;
            }
            nudge = TRUE;
        }
        if (levels & CONTROL_ROT_RIGHT)
        {
            if (gTargetTheta > 0)
            {
                gTargetTheta = 0;
            }
            else
            {
                gTargetTheta -= THETA_INCREMENT;
            }
            nudge = TRUE;
        }
        
        if (direction)
        {
            //sound control
            if (speed < 24) { llLoopSound("car accel", .4);}
            else { llLoopSound("car go",.4); }
            
            //applies forward boost
            
           // llSay( 0, (string) power + "  " + (string) direction + "  " + (string) mass + (string) power_curve() + (string) theta_func() );
            
            
            llApplyImpulse( <1,0,0> * direction * mass * power_curve()* THROTTLE , 1);
            
        }
    
        if (direction == 0)
        
        {llLoopSound("geardown", .4);
        }
        
        if (nudge)
        {
                
            // angular motion -- we compute the raw quaternion about z-axis
            counter++;
            float st = 0.5 * llSin(gTargetTheta*STEERING);
            float ct = 0.5 * llCos(gTargetTheta*STEERING);
            rotation rot = <0,0,st, ct> * llGetRot(); 
            llRotLookAt(rot, ANGULAR_TAU, ANGULAR_DAMPING);
        }
        
        else {counter = 0;}
    }

land_collision(vector position)
    {
      //llApplyImpulse( <0,0, .5> * mass, 1 );
     }

    
collision (integer total_number)
    {
      // llWhisper( 0, "collision 2");
       //llSetHoverHeight(4,1,.2);
    }
    

timer() //side ways supression
    {
    
      vector pos = llGetPos();
       
     if (llGround(<0,0,0>) > (pos.z - 3) )
    {
        velocity = llGetVel();
        speed = llVecMag(velocity);
        
        float l_speed = llRot2Left( llGetRot() ) * velocity;
        float f_speed = llRot2Fwd( llGetRot() ) * velocity;
      
      
        if (  l_speed > 8 || (brake > 1 && speed > 8) )   llTriggerSound("tires burn",10);
        if (speed < 1) llStopSound();
        
        
        if (counter * speed > 100)
        { 
         l_speed /= 4;
         brake = 2;
        }
        if (speed > 4) brake = 2;
        f_speed *= brake;
        
      
        llApplyImpulse( <0,-1,0> * l_speed * mass *.8, 1 );
        llApplyImpulse( <-1,0,0> * f_speed * mass *.05, 1 );
       }
     
    }
        
}