User:Pazako Karu/LinksetResizerWithMenu

From Second Life Wiki
Jump to navigation Jump to search

This script resizes a linkset in X,Y,Z as desired without any configuration.

On adding the script, it asks for a limit in case you don't want the true max.

I added this since the 'true max' of a small item would be hilariously large.

Its not rocket surgery

Code

// Linkset Resizer with Menu
// by: Pazako Karu
// This script resizes a linkset in X,Y,Z as desired without any configuration

float max_scale;
float min_scale;
vector scale = <1,1,1>;

list link_scales = [];
list link_positions = [];
integer X = TRUE;
integer Y = TRUE;
integer Z = TRUE;
integer SCANNED = FALSE;

//#include "dialog.lsl"
list DIALOG_DATA;

setDialog(key id, string caption, list buttons, integer context) 
{   getDialog(id); 
    if (llList2Integer(DIALOG_DATA, -4) > llGetTime())  
        cleanDialogs();
    else while (llGetListLength(DIALOG_DATA) >= 40)     
    {   llListenRemove(llList2Integer(DIALOG_DATA,2));        
        DIALOG_DATA = llList2List(DIALOG_DATA, 4, -1);  
    }
    integer channel = -(integer)llFrand(DEBUG_CHANNEL);
    DIALOG_DATA += [llGetTime()+60, id, llListen(channel, llKey2Name(id), id, ""), context]; 
    llDialog(id, caption, buttons, channel);
}

integer getDialog(key id)
{   integer index = llListFindList(DIALOG_DATA, [id]); 
    integer context = llList2Integer(DIALOG_DATA,index+2); 
    if (~index) 
    {   llListenRemove(llList2Integer(DIALOG_DATA, index+1)); 
        DIALOG_DATA = llDeleteSubList(DIALOG_DATA, index-1, index+2); 
    }
    else context = 0; 
    return context; 
}

cleanDialogs()
{   
    integer index; 
    for (index = 2; index < llGetListLength(DIALOG_DATA); index+=4)
        llListenRemove(llList2Integer(DIALOG_DATA,index));
    DIALOG_DATA=[];
}

makeMenu()
{
    list options = ["-1%","-5%","-10%","+1%","+5%","+10%"];
    if (X) options += ["[X]"]; else options += ["X"];
    if (Y) options += ["[Y]"]; else options += ["Y"];
    if (Z) options += ["[Z]"]; else options += ["Z"];
    options += ["Max", "Min", "More..."];
    setDialog(llGetOwner(), (string)[ "Max scale: ", max_scale, "\nMin scale: ", min_scale, "\n\nCurrent scale: ", scale], options, 1);
    llSetTimerEvent(120);
}

scanLinkset()
{
    integer links = llGetNumberOfPrims();
    integer link;
    integer offset = (links != 1); // add 1 if more than one prim (as linksets start numbering with 1)
    list params;

    for (link = 0; link < links; ++link)
    {
        params = llGetLinkPrimitiveParams(link + offset, [PRIM_POS_LOCAL, PRIM_SIZE]);
        link_positions += llList2Vector(params, 0);
        link_scales    += llList2Vector(params, 1);
    }
    if (max_scale == 0)
        max_scale = llGetMaxScaleFactor() * 0.999999;
    min_scale = llGetMinScaleFactor() * 1.000001;
    SCANNED = TRUE;
    llOwnerSay("Ready to use! Max scale set to " + (string)max_scale + "m");
}
resizeObject(vector scale)
{
    integer links = llGetNumberOfPrims();
    integer link;
    integer offset = (links != 1);
    
    // scale the root
    llSetLinkPrimitiveParamsFast(offset, [PRIM_SIZE, notDot(scale,llList2Vector(link_scales, 0))]);
    
    // scale all but the root
    for (link = 1; link < links; link++)
    {
        llSetLinkPrimitiveParamsFast(link + offset,
            [PRIM_SIZE,      notDot(scale, llList2Vector(link_scales,    link)),
             PRIM_POS_LOCAL, notDot(scale, llList2Vector(link_positions, link))]);
    }
}
vector notDot(vector A, vector B)
{
    return <A.x*B.x, A.y*B.y, A.z*B.z>;
}
float limit(float input)
{
    if (input > max_scale) return max_scale;
    if (input < min_scale) return min_scale;
    return input;
}
default
{
    state_entry()
    {
        setDialog(llGetOwner(), "Please define max scale, or leave blank to allow actual maximum, which may be very very large.", ["!!llTextBox!!"], 4);
    }
    touch_start(integer total)
    {
        if (llDetectedKey(0) == llGetOwner())
        {
            if (SCANNED == TRUE)
                makeMenu();
            else llResetScript();
        }
    }
    timer()
    {
        cleanDialogs();
        llSetTimerEvent(0);
    }
    listen(integer channel, string name, key id, string msg)
    {
        integer CONTEXT = getDialog(id);
        if (CONTEXT == 4)
        {
            max_scale = llFabs((float)msg);
            if (max_scale > llGetMaxScaleFactor() * 0.999999)
                max_scale = llGetMaxScaleFactor() * 0.999999;
            scanLinkset();
        }
        else if (SCANNED == TRUE)
        {
            if (CONTEXT == 1)
            {
                     if (msg == "[X]") X = FALSE;
                else if (msg == "[Y]") Y = FALSE;
                else if (msg == "[Z]") Z = FALSE;
                else if (msg ==  "X")  X = TRUE;
                else if (msg ==  "Y")  Y = TRUE;
                else if (msg ==  "Z")  Z = TRUE;
                else if (msg == "Max")      scale = max_scale * <1,1,1>;
                else if (msg == "Min")      scale = min_scale * <1,1,1>;
                else if (msg == "More...")  setDialog(id, "\nBonus options:", ["Delete", "Restore", "Back"], CONTEXT=2);
                else // Number chosen
                {
                    float factor = (float)msg/100;
                    if (factor > 0)
                    {
                        factor += 1; // 1.05
                        if (X) scale = notDot(scale, <factor,1,1>);
                        if (Y) scale = notDot(scale, <1,factor,1>);
                        if (Z) scale = notDot(scale, <1,1,factor>);
                    }
                    else
                    {
                        factor = 1/(1-factor);
                        if (X) scale = notDot(scale, <factor,1,1>);
                        if (Y) scale = notDot(scale, <1,factor,1>);
                        if (Z) scale = notDot(scale, <1,1,factor>);
                    }
                }
                // Limit scale to bounds
                scale = <limit(scale.x), limit(scale.y), limit(scale.z)>;
                
                resizeObject(scale);
                if (CONTEXT == 1)
                    makeMenu();
            }
            else if (CONTEXT == 2) // Bonus options
            { //"Delete", "Defaults", "Back"
                     if (msg == "Back") makeMenu();
                else if (msg == "Delete") setDialog(id, "\nAre you sure you want to delete the resizer script?", ["Yes", "No"], 3);
                else if (msg == "Restore")
                {
                    scale = <1,1,1>;
                    resizeObject(scale);
                    makeMenu();
                }
            }
            else if (CONTEXT == 3) // Delete confirm
            {
                if (msg == "Yes")
                {
                    llRegionSayTo(id, 0, "Script deleted");
                    llRemoveInventory(llGetScriptName());
                }
            }
        }
    }
}

License

You may use, abuse, and distribute this object in any way, other than simply repacking for sale. You may include this object as part of a sellable object in any form, including full permission. This was made using some firestorm preprocessing commands and is not given with any promise of readability or assistance with modification.