//  Camera Follower
//  Created by Water Rogers for IBM/Opensource
 
//  Purpose
//  --------------------------------------------------------------
//  This script shows you how you can make an object physical, and
//  have it follow your camera around.
 
//  Requirements
//  --------------------------------------------------------------
//  A single prim is all that is necessary for this example.
 
//  Usage
//  --------------------------------------------------------------
//  Permissions to track your camera are required for it to work
//  correctly.  Type "follow" to track the camera.  Type "stop" to
//  stop tracking the camera.  Touching the object will also start
//  tracking the camera.
 
//  GLOBALS
//  --------------------------------------------------------------
integer     g_ListenChannel = 0;        //  This is the listen channel
float       g_Timer         = 0.10;     //  This is the timer call rate
 
//  FUNCTIONS
//  --------------------------------------------------------------
permissions()
{
    //  Since this block of code is used more then once in the main
    //  loop, it's a good idea to make it a function.
 
    //  Get the permissions
    if(llGetPermissions() & PERMISSION_TRACK_CAMERA)
    {
        //  Permissions were passed, so we make the object physical
        //  and start the timer
        llSetStatus(STATUS_PHYSICS, TRUE);
        llSetTimerEvent(g_Timer);
    }
    else
    {
        //  Permissions were not passed, so we make the object static,
        //  set the timer to 0, and Request permissions.
        llSetStatus(STATUS_PHYSICS, FALSE);
        llSetTimerEvent(FALSE);
        llRequestPermissions(llGetOwner(), PERMISSION_TRACK_CAMERA);
    }
}
 
//  EVENTS
//  --------------------------------------------------------------
default
{
    state_entry()
    {
        //  Collision Sounds and Sprites can be replaced.  We make them
        //  empty strings so there are no sounds or sprites if the camera
        //  happens to knock up against a wall.
        llCollisionSound("", 0);
        llCollisionSprite("");
 
        //  Make a listener to listen for commands the owner may use.
        llListen(g_ListenChannel, "", llGetOwner(), "");
 
        //  Call the permissions() function block
        permissions();
    }
 
    on_rez(integer start_param)
    {
        //  The object was just rezzed out of inventory, so call up the
        //  permissions() function block
        permissions();
    }
 
    touch_start(integer num_detected)
    {
        //  The object was touched, so first we make sure that the owner
        //  touched the object, and if so... call the permissions()
        //  function block
        if(llDetectedKey(0) == llGetOwner()) permissions();
    }
 
    listen(integer channel, string name, key id, string message)
    {
        //  Turn all commands into lowercase using llToLower()
        message = llToLower(message);
        if(message == "stop")
        {
            //  The owner said "stop", so we'll turn off the object by
            //  making the object static, and setting the timer to 0
            llSetStatus(STATUS_PHYSICS, FALSE);
            llSetTimerEvent(FALSE);
        }
        else if(message == "follow")
        {
            //  The owner said "follow", so we call up the permissions()
            //  function block
            permissions();
        }
    }
 
    run_time_permissions(integer perm)
    {
        //  Permissions were requested through the permissions() function
        //  block.  Remember to use bitwise opperands when dealing with
        //  conditional statements for permissions.
        if(perm & PERMISSION_TRACK_CAMERA)
        {
            //  The owner granted permissions, so we set the object to
            //  physical, and fire up the timer.
            llSetStatus(STATUS_PHYSICS,TRUE);
            llSetTimerEvent(g_Timer);
        }
    }
 
    timer()
    {
        //  Here the timer uses llMoveToTarget() which simply moves the
        //  object to wherever the owner's camera is, and about 1 meter
        //  above (as to not obtruct the owner's view.  The owner will
        //  not be able to see the object under most circumstances, so if
        //  the owner wants to get rid of the object, they must first say
        //  "stop" in chat to make the object stop moving.  Then they can
        //  click on the object a lot easier to delete or take.
        llMoveToTarget(llGetCameraPos() + <0.0, 0.0, 1.0>, 0.20);
 
        //  Since the object looks a bit awkward only moving to position and
        //  not rotating properly, we call a simple sensor looking for the
        //  owner's current position.
        llSensor("", llGetOwner(), AGENT, 96, PI);
    }
 
    sensor(integer num_detected)
    {
        //  After we get the owner's position, we'll have the object just
        //  look at the owner using it's forward axis.  This gives a nice
        //  effect.  If you wanted to track the owners actual camera rotations
        //  then you would have to use llGetCameraRot() and make the correct
        //  calculations.  We do it this way for simplicity.
        llLookAt(llDetectedPos(0), 0.32, 0.32);
    }
}