Chat Painter

From Second Life Wiki
Jump to navigation Jump to search

This script allows to change such properties as texture, color, transparency, fullbright, glow and shiny of one special face or all faces ot one special prim or all prims in the linkset. The commands are received via chat and can be sent by the owner themselves (e.g. using an emote) or a device belonging to them, like a HUD. The script for the HUD or the emote are not provided, though.

The script supports up to 256 prims linkset, although changing "all prims" at once is not reccomended for large linksets because the changes will not be visible on all prims due capping the updates (I suspect it is an interest list problem and not a problem of this script.)

Can only address prims by name when no space or comma "," character is used in the prim name. When used, can only address the prim by number.

Usage

Put the script into the linkset under control. It will scan the linkset for the prim names and then tell it is ready.

To activate the script, touch the linkset at any prim. It will start the listen and tell the command to close the listen.

To reset the script, touch again and hold the mouse button for about 2 seconds (long touch.)

Rezzing the prim resets the script (needs touching again to open the listen.)

Changing the linkset by linking or delinking prims or sitting upon the object resets the script too.

Renaming prims in the linkset will not update the dictionary (this remembers the prim names and their numbers) so after renaming any prim a script reset is required, either manually or by taking into invntory and rezzing or by sitting upon the build.

Commands

The commands are sent on the channel denoted into the script, by default it is 1901. The command shema is

/channel prim face commandlist

prim is name or number of the addressed prim. Should be omitted when running in a single prim (no child prims in the linkset.) Special names and possible cases:

  • "all" means all prims are addressed in a single command (please avoid for large linksets, 200 prims and more.)
  • "set" means the prim running the script, mostly its the root prim.
  • Name (e.g. "door_bell") name of the prim to be changed. Must be lower-cased and contain no space " " and comma "," chars.
  • Number (e.g. "14") Number of the prim to change. Root prim has the number 1, child prims have higher numbers.


face is the name or number of the face to change. The face names are given into the script and can be changed due configuration. Names and possible cases:

  • "each" means all faces are changed.
  • Number (e.g. "2") is the face number. Face numbers go from 0 to 8.
  • -1 is the number used for "all faces", the same as using "each".
  • Name (e.g. "top") name of the face, given by the list FACE_NUMS in the script configuration.


commandlist list of the commands and values, separated by comma and space chars. The commands are

  • "color" hex - value is given by hexadecimal value like "A7B8C9", as known from HTML. You can obtain it from color editor in some viewers (e.g. Firestorm has it.)
  • "fullb" Y/N/1/0 - "Y" or "1" switch fullbright on, "N" or "0" switch off.
  • "shiny" 0..3 - "0" means no shiny, "1" means max shiny.
  • "image" key - Use the key of the image to assign.
  • "glow" float - The value goes from "0" (no glow) to "1" (max glow), e.g. "0.25".
  • "alpha" float - The value goes from "0" (opaque) to "1" (transparent.)

Examples

Given a single prim.

The script is installed and the listen is open (the prim is touched.)

a) To make the top face red, glowing, fullbright aktive and see-trough, use this command:

/1901 top color ff0000, glow .75, fullb Y, alpha 0.5
When the script says "no such face 'top'" than the name "top" is not assigned in the configuration.

b) This command puts a blank image on each face and sets it medium shiny:

/1901 each image ae52440b-478e-0af8-a249-e759ab0b744b, shiny 2

c) When we know the number of the face to change, we can use it directly:

/1901 2 shiny 0
This deactivates shiny on the face with the number 2.
Given a linkset with more than one prim.

The script is installed e.g. into the root prim and the listen is also open.

d) This command changes color only on the root prim (all faces) where the script is installed:

/1901 set each color ff0000

e) This commnd does the same with each prim of the linkset:

/1901 all each color ff0000

f) When there is a prim with name "Prim-15" into the linkset, this command changes that one:

/1901 prim-15 each color ff8040

g) Sometimes we want change a prim with given number, e.g. 15, for example when it's name has forbidden characters like "left door":

/1901 15 each color ff8040

Configuration

TBC

Painter Script

//----------------------------------------------------------------------------
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License as
// published by the Free Software Foundation; either version 3 of
// the License, or (at your option) any later version.
//
// You may ONLY redistribute this program with copy, mod and transfer
// permissions and ONLY if this preamble is not removed.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// 
// You should have received a copy of the GNU General Public License
// along with this program; if not, see <http://www.gnu.org/licenses/>.
//----------------------------------------------------------------------------

//----------------------------------------------------------------------------
//
// Script: ChatPainter
//
// Allows to change the texture and collor properties of named faces
// of named prims in a linkset by using chat commands.
//
//----------------------------------------------------------------------------
// Version:       1.0.0
// Contributors:  Jenna Felton - initial release
//----------------------------------------------------------------------------

// --- [ SETTINGS ] ----------------------------------------------------------

// Channel for chat commands
integer CHANNEL    = 1901;

// Face names and numbers. Format: Name, number, name, number...
// * Every face name must appear once, i.e. address one number.
// * More than one face name can address same face number.
// * Face names must use lower-case letters.
list    FACE_NUMS  = [
    // these names we can use for the one group of prims
    "top",    0,
    "front",  1,
    "right",  2,
    "back",   3,
    "left",   4,
    "bottom", 5,
    
    // and these names for the other group of prims
    "alpha",  0,
    "beta",   1,
    "gamma",  2,
    
    // this is also possible, but for addressing ALL_SIDES
    // we better use the special face name "each" instead
    "omega", -1 
    ];

// --- [ SETTINGS END ]  -----------------------------------------------------

key     kOwner     = NULL_KEY;
integer gPrims     = 0;

integer hListen    = 0;

list    lLinks     = [];

// --- -----------------------------------------------------------------------

// updates shiny on given face(s) of given link (only single prim)
// without touching the bump of the faces

changeShiny(integer link, integer face, integer shiny) {
    // result : [ integer shiny, integer bump ] per face.
    list bumps = llGetLinkPrimitiveParams(link, [PRIM_BUMP_SHINY, face]);
    
    if (face != ALL_SIDES) {
        llSetLinkPrimitiveParams(link,
            [PRIM_BUMP_SHINY, face, shiny, llList2Integer(bumps, 1)]);
    }
    else {
        integer num = llGetLinkNumberOfSides(link);
        for (face = 0 ; face < num ; face++) {
            llSetLinkPrimitiveParams(link,
                [PRIM_BUMP_SHINY, face, shiny, llList2Integer(bumps, face*2+1)]);
        }
    }
}

// --- -----------------------------------------------------------------------
 
default {
    // --- administration ----------------------------------------------------
    
    state_entry() {
        kOwner  = llGetOwner();
        gPrims  = llGetNumberOfPrims();
        
        // fill up the dictionary
        integer link;
        integer links = llGetNumberOfPrims();
        lLinks        = [];
        for (link = 0 ; link <= links ; link++) {
            lLinks += llToLower(llGetLinkName(link));
        }

        llOwnerSay("Painter started. Touch to open listen, long touch to reset");
        
        //// 256 prims, 63 chars -> 52 kB used
        //// 256 prims, 8 chars  -> 23 kB used
        //// 1 prim,    63 chars -> 14 kB used
        //llOwnerSay("state_entry: used "+(string)llGetUsedMemory()+" Bytes");
    }
    
    on_rez(integer param) {
        llResetScript();
    }

    touch_start(integer number) {
        if (llDetectedKey(0) != kOwner) return;
        llResetTime();
    }

    touch_end(integer number) {
        if (llDetectedKey(0) != kOwner) return;

        if (llGetTime() > 1.5) llResetScript();
        
        else if (hListen == 0) {
            hListen = llListen(CHANNEL, "", NULL_KEY, "");
            llOwnerSay("listen open (/"+(string)CHANNEL+"close to close again)");
        }
    }

    changed(integer change) {
        if (change & CHANGED_LINK) llResetScript();
    }
    
    // --- chat interface ----------------------------------------------------

    listen(integer channel, string name, key id, string message) {
        if (llGetOwnerKey(id) != kOwner) return;
        message = llToLower(llStringTrim(message, STRING_TRIM));

        // 1. Supercommand "close"
        
        if (message == "close") {
            llListenRemove(hListen);
            hListen = 0;
            llOwnerSay("listen closed (touch to open again)");
            return;
        }

        // 2. Regular command "prim face commandlist"
        //    while prim is "set", "all" or a prim number or name.
        //                  Omitted for a single prim build
        //    and   face is "each", face number or face name from da list
        
        list    cmds = llParseString2List(message, [" ", ",", ";"], []);
        integer link;
        integer face;
        if (gPrims > 1) {
            name     = llList2String(cmds, 0);  // prim
            message  = llList2String(cmds, 1);  // face
            cmds     = llDeleteSubList(cmds, 0, 1);
        }
        else {
            name     = "set";                   // prim
            message  = llList2String(cmds, 0);  // face
            cmds     = llDeleteSubList(cmds, 0, 0);
        }

        // a. testing face is faster

        if      (message == "each") face = ALL_SIDES;
        else if (message == "0")    face = 0;
        else {
            face = (integer)message;
            if (face == 0) {
                face  = llListFindList(FACE_NUMS, [message]);
                if (face < 0) {
                    llOwnerSay("No such face: '"+message+"'");
                    return;
                }
                else {
                    face = llList2Integer(FACE_NUMS, face+1);
                }
            }
        }

        // b. testing target prim "set", "all" or number
        
        if      (name == "set") link  = LINK_THIS;
        else if (name == "all") link  = LINK_SET;
        else if (name == "0")   link  = 0;
        else {
            link = (integer)name;
            if (link == 0) {
                link = llListFindList(lLinks, [name]);
                if (link < 0) {
                    llOwnerSay("No such link: '"+name+"'");
                    return;
                }
            }
        }

        // 3. processing commandlist
        //    List : color A7B8C9, fullb Y/N/1/0, shiny num,
        //           image key, glow value, alpha value
        //    

        while (cmds != []) {
            name     = llList2String(cmds, 0);  // command
            message  = llList2String(cmds, 1);  // parameter
            cmds     = llDeleteSubList(cmds, 0, 1);

            // color hex-value
            if (name == "color") {
                message   = "0x"+message;
                channel   = (integer)message;

                integer r = (channel>>16)&0xFF;
                integer g = (channel>>8)&0xFF;
                integer b = channel&0xFF;

                llSetLinkColor(link,
                    <(float)r, (float)g, (float)b>/255.0, face);
            }

            // alpha float
            else if (name == "alpha") {
                float val = (float)message;
                if      (val < 0.0) val = 0.0;
                else if (val > 1.0) val = 1.0;
                
                llSetLinkAlpha(link, val, face);
            }

            // glow float
            else if (name == "glow") {
                float val = (float)message;
                if      (val < 0.0) val = 0.0;
                else if (val > 1.0) val = 1.0;
                
                llSetLinkPrimitiveParamsFast(link,
                    [PRIM_GLOW, face, val]);
            }

            // shiny 0..3
            else if (name == "shiny") {
                channel = (integer)message;
                if      (channel < 0) channel = 0;
                else if (channel > 3) channel = 3;

                // Work on entire linkset
                if (link == LINK_SET) {
                    for (link = 1 ; link <= gPrims ; link++) {
                        changeShiny(link, face, channel);
                    }
                }

                // Only a single prim
                else {
                    changeShiny(link, face, channel);
                }
            }

            // fullb boolean
            else if (name == "fullb") {
                if      (message == "y") channel = 1;
                else if (message == "n") channel = 0;
                else                     channel = (integer)message;
                
                llSetLinkPrimitiveParamsFast(link,
                    [PRIM_FULLBRIGHT, face, channel]);
            }

            // image key
            else if (name == "image") {
                llSetLinkTexture(link, message, face);
            }

            else llOwnerSay("No such command: '"+name+"'");

        }
    }
}

// --- ------------------------------------------