MLPV2 Ball Script with more flexible parameters

From Second Life Wiki
Jump to navigation Jump to search


// ~capture Script V1.01
// drop into a ball
//
//MLPV2.4z9
//Chaz edit 2012 to give control over (1) how visible adjusting beams are, (2) how high up balls rez, and (3) and over floating text on balls
//that's the only change, to make these parameters easily accessible and put them all in one section near top of script


// MLPV2 Version 2 by Learjeff Innis.  Based on
// MLP MULTI-LOVE-POSE V1.2 - Copyright (c) 2006, by Miffy Fluffy (BSD License)

// To make ball phantom, put "*" as the first character in the ball's description
// or just make the ball phantom (which really works better for HUDs).
// The rest of the description, if any, is used for the sit pie menu and floating text.
// To make this take effect, use STOP to unrez the balls, and then select any pose.

// v2.4j - cancel old listen on rez
// v2.4m - handle control keys! To enable, begin ~ball description with a plus sign ("+"), following "*" if any.
// v2.4p - page up & down to enable/disable adjustment
// v2.4x - moved SitTarget to top.

//chaz adjustable parameters start
float AdjustBeamTransparency = 0.4; //0.1 is practically invisible; 1.0 is solid (0.0 <= alpha <= 1.0) 
string BallFloatingText = "";//any floating text to display above the balls
vector  SitTarget       = <0.,0.,-.5>;   // Change this to <0.,0.,-.15> or lower, to raise balls above cushion
//chaz adjustable parameters end


vector  SitTargetRef    = <0.,0.,.1>;   // Don't change this, unless you're replacing earlier versions
                                        // with a custom SitTarget.  In that case, set to match SitTarget.

integer ADJUSTABLE  = FALSE;
float   DELTA       = 0.01;        // cm to move
float   EPSILON     = 0.005;       // cm position error tolerance, should be about half delta
vector  Offset;
vector  BallPos;
rotation BallRot;

key     NullKey = NULL_KEY;

integer Chan;
integer Group;
integer visible = TRUE;
integer Adjusting;
key     Avatar;
string  Name;
integer ListenHandle;

integer ControlsActive;

// 15 color support, thanks to Liz Silverstein
// Color is passed as a string by object chat (from menu via poser*)
    
list colors = [ <0.0,0.0,0.0>,          // 0 = HIDE
                <0.835,0.345,0.482>,    // 1 = PINK
                <0.353,0.518,0.827>,    // 2 = BLUE
                <0.635,0.145,0.282>,    // 3 = PINK2 - Dark pink
                <0.153,0.318,0.627>,    // 4 = BLUE2 - Dark blue
                <0.128,0.500,0.128>,    // 5 = GREEN
                <1.000,0.000,1.000>,    // 6 = MAGENTA
                <1.000,0.000,0.000>,    // 7 = RED
                <1.000,0.500,0.000>,    // 8 = ORANGE
                <1.000,1.000,1.000>,    // 9 = WHITE
                <0.0,0.0,0.0>,          // 10 = BLACK
                <1.0,1.0,0.0>,          // 11 = YELLOW
                <0.0,0.8,0.8>,          // 12 = CYAN
                <0.5,0.0,0.0>,          // 13 = RED2
                <0.0,0.5,0.5>,          // 14 = TEAL
                <0.0,0.25,0.25>];       // 15 = GREEN2



handle_control(key id, integer level, integer change) {

    if (Avatar == NullKey) {
        return;
    }
    
    if ((level & CONTROL_UP) && (level & CONTROL_DOWN)) {
        ControlsActive = ! ControlsActive;
        if (ControlsActive) {
            control_active();
        } else {
            control_ready();
        }
        return;
    }
    
    if (!ControlsActive) {
        return;
    }


    if (level & CONTROL_UP) {
        Offset.z += DELTA;
    } else if (level & CONTROL_DOWN) {
        Offset.z -= DELTA;
    } else if (level & CONTROL_LEFT) {
        Offset.y += DELTA;
    } else if (level & CONTROL_RIGHT) {
        Offset.y -= DELTA;
    } else if (level & CONTROL_FWD) {
        Offset.x += DELTA;
    } else if (level & CONTROL_BACK) {
        Offset.x -= DELTA;
    } else {
        return;
    }

    llSetPos(BallPos + Offset * BallRot + SitTargetRef - SitTarget);
}

// enter "control ready" state.
control_ready() {
    ControlsActive = 0;
    integer controls = CONTROL_UP | CONTROL_DOWN;

    llTakeControls(controls, TRUE, FALSE);
    llInstantMessage(Avatar, "Allow adjusting your position by pressing Pgup and Pgdn keys at the same time");
}

control_active() {
    integer controls = CONTROL_UP | CONTROL_DOWN | CONTROL_LEFT | CONTROL_RIGHT | CONTROL_FWD | CONTROL_BACK;

    llTakeControls(controls, TRUE, FALSE);
    llInstantMessage(Avatar, "Adjust your position using Pgup/Pgdn, Up/Down arrow, and shift-left/right arrow keys\nDisable by pressing Pgup and Pgdn keys at the same time");
    BallPos = llGetPos() + SitTarget - SitTargetRef;
    BallRot = llGetRot();
}



render() {
    if (!visible || (Avatar != NullKey && !Adjusting)) {
        // hidden
        llSetScale(<0.01,0.01,0.01>);
        llSetAlpha(0.0, ALL_SIDES);
        llSetText(BallFloatingText,<1.0,1.0,1.0>,0.0);    
    } else if (Avatar != NullKey && Adjusting) {
        // sitting and adjusting
        llSetAlpha(AdjustBeamTransparency,ALL_SIDES);
        llSetText("Adjust",<1.0,1.0,1.0>,1.0);
        llSetScale(<0.1,0.1,5.0>);
    } else {
        // shown
        llSetAlpha(1.0, ALL_SIDES);
        llSetScale(<0.2,0.2,0.2>);
        if (Adjusting) {
            llSetText("Adjust",<1.0,1.0,1.0>,1.0);
        } else {
            //chaz edit
            llSetText(BallFloatingText,<1.0,1.0,1.0>,1.0);
        }
    }
}

show() {
    visible = TRUE;
    render();
}

hide() {
    visible = FALSE;
    render();
}

default {
    on_rez(integer channel) {
        Name = llGetObjectDesc();
        if (Name == "" || Name == "(No Description)") {
            //chaz edit
            Name = "";
        } else {
            if (llSubStringIndex(Name, "*") == 0) {
                llSetPrimitiveParams([PRIM_PHANTOM, TRUE]);
                Name = llGetSubString(Name, 1, -1);
            }
            if (llSubStringIndex(Name, "+") == 0) {
                ADJUSTABLE = TRUE;
                Name = llGetSubString(Name, 1, -1);
            }
            if (Name == "none") {
                Name = "";
            }
        }
        llSitTarget(SitTarget, ZERO_ROTATION);
        if (Name != "") {
            llSetSitText(Name);
        } else {
            llSetSitText("");
        }
        Avatar = NullKey;
        Chan = channel;
        Group = 0;
        
        if (ListenHandle) {
            llListenRemove(ListenHandle);
            ListenHandle = 0;
        }

        if (Chan != 0) {
            ListenHandle = llListen(Chan,"",NullKey,"");
            // start timer unless ball was dragged from inv
            llSetTimerEvent(180.0);
        }
        
        if (llGetObjectDesc() == "ADJUSTABLE") {
            ADJUSTABLE = TRUE;
        }
    }

    changed(integer change) {
        if (change != CHANGED_LINK) return;
        Avatar = llAvatarOnSitTarget();
        if (Avatar != NullKey) {

            if (Group) {
                if (!llSameGroup(Avatar)) {
                    llUnSit(Avatar);
                    llWhisper(0,"no permission to use poseball");
                    return;
                }
            }
            if (ADJUSTABLE) {
                llRequestPermissions(Avatar, PERMISSION_TAKE_CONTROLS);
            }
        }
        llSay(Chan+8,(string)Avatar);     //requests perm, sets animation
        render();
        
    }

    listen(integer channel, string name, key object, string str) {
        integer ix;
        ix = llSubStringIndex(str,">");    
        if (ix != -1) {
            BallPos = (vector)llGetSubString(str,0,ix);
            BallRot = (rotation)llGetSubString(str,ix+1,-1);
            llSetPos(BallPos + SitTargetRef - SitTarget);
            llSetRot(BallRot);
        } else if (str == "0") {    //HIDE
            hide();
        } else if (str == "SHOW") { //SHOW
            show();
        } else if (str == "ADJUST|1") {
            Adjusting = TRUE;
            render();
        } else if (str == "ADJUST|0") {
            Adjusting = FALSE;
            render();
        } else if (str == "SAVE") {
            llSay(Chan+16,(string)(llGetPos() + SitTarget - SitTargetRef)+(string)llGetRot());
        } else if (str == "GROUP") {
            Group = 1;
        } else if (str == "ALL") {
            Group = 0;
        } else if (str == "DIE") {
            llSay(Chan+8, (string)NullKey);    //msg to poser (don't reanimate after STOP)
            llDie();
        } else if (str == "LIVE") {
            llSetTimerEvent(180.0);
            // llSay(Chan+8,"ALIVE");    //msg to poser -> to menu
        } else {
            list ldata = llParseString2List(str, ["|"], []);
            integer colorIx = (integer) llList2String(ldata,0);
            string ballIx = llList2String(ldata,1);
            Adjusting = (integer) llList2String(ldata,2);
            if ((colorIx > 0) && (colorIx < 16)) { // this must be a color setting  
                llSetColor(llList2Vector(colors, colorIx),ALL_SIDES);     //pull the color out of the list
                render();
                llSetObjectName("~ball" + ballIx);
                BallPos = llGetPos() + SitTarget - SitTargetRef;
                BallRot = llGetRot();
            }
        }
    }

    timer() {                       //not heard "LIVE" from menu for a while: suicide
        llDie();
    }

    run_time_permissions(integer perm) 
    { 
        if (llKey2Name(Avatar) == "") {
            return;
        }
        if (Avatar != llGetPermissionsKey()) {
            return;
        }

        if (perm & PERMISSION_TAKE_CONTROLS) {
            control_ready();
        }
    }

    moving_end() {
        vector newpos = llGetPos() + SitTarget - SitTargetRef;
        if (llVecMag(newpos - (BallPos + Offset)) > EPSILON) {
            // we didn't move it, someone else did.  Deal with it.
            BallPos = newpos;
        }
        BallRot = llGetRot();
    }

    control(key id, integer level, integer change) {
        handle_control(id, level, change);
    }
}