User:Yumi Murakami/Weaver Spell Grid

From Second Life Wiki
Jump to: navigation, search

One of the things I always wanted to make but never managed to was a magic wand, because I couldn't think of original things to put in it! This was an early experiment with something to go in it, but it became rather over the top, not least because it involves a HUD with 200 prims.

This HUD basically allows you to draw simple shapes on a grid. In order to use it, you'll need a fairly complex prim shape (too big to actually provide a script to build! If anyone knows of a good prim parameter extractor/dumper that works for huge objects let me know and I'll use it). Here's what it must include:

  • 100 prims arranged in a 10x10 grid with each grid cell being 0.0033 units along each axis, and named as follows: an @ sign, followed by the coordinates of the cell in the grid as two numbers separated by a comma, and with 0,0 being the center. So the center prim would be named "@0,0", the top left would be named "@-5,-5", and so on.
  • 16 prims used for color selection named t0, t1, t2, t3.. up to t15.
  • One prim called "CurrentColor" used for indicating the current color.
  • Some number of prims used to select the depth of angle when drawing curves. These should have a name starting with an "=" followed by the ratio of the curve. So there should usually be an =0 for straight lines, plus others with different values - up to you.
  • One prim called "button" which is used to start the generator.
  • 50+ or more (depending on how complex you want it to be) prims named "nano" which are used for the actual drawing. THey can be bare plywood cubes and don't have to be in any particular position.

This works, but is by no means complete.

list nanoes;
list nanofree;
list weave;
float bendy;
integer tintNo;
 
 
integer currentColorPrim;
integer nanocount;
integer lastPrimNumber;
integer bendySelectPrim;
 
list tints = [<0,0,0>,<1,0,0>,<0,1,0>,<0,0,1>,<1,1,0>,<1,0,1>,<1,1,0>,<1,1,1>,
        <0.5,0.5,0.5>,<1,0.5,0.5>,<0,0.5,0>,<0.5,0.5,1>,<0.5,0.5,0>,<0.5,0,0.5>,<0.5,0.5,0>,<0.75,0.75,0.75>];
 
list prefixes = [ 
            "br","ch","dr","fl","gr","kr","pr","ph","sr","sh","tr","th","wh","bh","cr","fr","kh",
            "gh","wr","zh","zr","jh","jr","b","c","d","f","g","h","j","k","l","m","n","p","q","r","s","t","v","w","x","z"];
list vowels = ["a","e","i","o","u","y"];
 
float unitsize = 0.033;
 
vector tint;
string element;
 
integer lineInProgress;
vector lastCoordSet;
vector lastWeaveLoc;
 
integer encodePrim(vector weaveLocA, vector weaveLocB, float bendy, integer tint) {
    integer ibend = (integer)(bendy*4); // 0 - 7 , 3 bits
    integer fx = (integer)(weaveLocA.x) + 5;
    integer fy = (integer)(weaveLocA.y) + 5;
    integer sx = (integer)(weaveLocB.x) + 5;
    integer sy = (integer)(weaveLocB.y) + 5;
    integer code;
    code = fx;
    code += fy << 4;
    code += sx << 8;
    code += sy << 12;
    code += ibend << 16;
    code += tint << 19;
    return code;
}
 
string codeToEnc(integer code) {
    integer tcode = code;
    string enc = "";
    while (tcode > 0) {
        integer section = tcode & 255;
        tcode = tcode >> 8;
        integer vowel = (integer)(section / 42);
        integer cons = section % 42;
        enc = enc + (llList2String(prefixes,cons) + llList2String(vowels,vowel)); 
    }
    return enc;
 
}
 
drawLine(integer nano, vector weaveLocA, vector weaveLocB) {
    vector realCoordA = <unitsize + (nano * 0.001),weaveLocA.x * unitsize,weaveLocA.y * unitsize>;
    vector realCoordB = <unitsize + (nano * 0.001),weaveLocB.x * unitsize,weaveLocB.y * unitsize>;
    vector realDiff = realCoordB - realCoordA;
    vector realDir = llVecNorm(realDiff);
    float realMag = llVecMag(realDiff);
    vector coords = realCoordA + (realDiff / 2);
    coords.z = -coords.z;
    rotation rot = llAxes2Rot(<1,0,0>, realDir, <1,0,0> % realDir);
    vector size = <0.01,realMag,0.01>;
    integer actualPrim = llList2Integer(nanoes,nano);
    nanofree = llListReplaceList(nanofree,[FALSE],nano,nano); // shazbot
    weave = llListReplaceList(weave,[encodePrim(weaveLocA,weaveLocB,0.0,tintNo)],nano,nano);
    llSetLinkPrimitiveParams(actualPrim,[PRIM_TYPE, PRIM_TYPE_BOX, 0, <0.0, 1.0, 0.0>, 0.0, <0.0, 0.0, 0.0>, <1.0, 1.0, 0.0>, <0.0, 0.0, 0.0>, PRIM_POSITION,coords,PRIM_ROTATION,rot,PRIM_SIZE,size,PRIM_COLOR,ALL_SIDES,tint,1.0]);
}
 
drawArc(integer nano, float bendy, vector weaveLocA, vector weaveLocB) {
    vector realCoordA = <unitsize + (nano * 0.001),weaveLocA.x * unitsize,weaveLocA.y * unitsize>;
    vector realCoordB = <unitsize + (nano * 0.001),weaveLocB.x * unitsize,weaveLocB.y * unitsize>;
    vector realDiff = realCoordB - realCoordA;
    vector realDir = llVecNorm(realDiff);
    float realMag = llVecMag(realDiff);
    realMag += 0.01;
    vector coords = realCoordA + (realDiff / 2);
    coords.z = -coords.z;
    rotation rot = llAxes2Rot(realDir, <1,0,0> % realDir, <1,0,0>);
    vector size = <realMag,realMag * bendy,0.01>;
    integer actualPrim = llList2Integer(nanoes,nano);
    float hollowScale = 1 - (0.02 / realMag);
    nanofree = llListReplaceList(nanofree,[FALSE],nano,nano); // shazbot
    weave = llListReplaceList(weave,[encodePrim(weaveLocA,weaveLocB,bendy,tintNo)],nano,nano);
    llSetLinkPrimitiveParams(actualPrim,[PRIM_TYPE, PRIM_TYPE_CYLINDER, 0, <0.0, 0.5, 0.0>, hollowScale, <0.0, 0.0, 0.0>, <1.0, 1.0, 0.0>, <0.0, 0.0, 0.0>, PRIM_POSITION,coords,PRIM_ROTATION,rot,PRIM_SIZE,size,PRIM_COLOR,ALL_SIDES,tint,1.0]);
 
}
 
 
 
default
{
    state_entry()
    {
        if (llGetLinkNumber() != 1) {
            llOwnerSay("GAK!  I'm NOT THE ROOT!  Stopping before I break EVERYTHING!!");
            state dead;
        }
        integer t;
        llOwnerSay("Factory Reset!");
        llOwnerSay("Doing first time initialisation.  This takes about 20 seconds.  Please bear with me.");
        currentColorPrim = -1;
        nanoes = [];
        nanofree = [];
        weave = [];
        // Linked prims are daft, and start counting at 1.
        for (t=1; t<=llGetNumberOfPrims(); t++) {
            string name = llGetLinkName(t);
            if (name == "nano") {
                nanoes += [t];
                nanofree += [TRUE];
                weave += -1;
                llSetLinkPrimitiveParams(t,[PRIM_POSITION,<-0.1,0,0>,PRIM_SIZE,<0.01,0.01,0.01>]);
            }
            if (name == "CurrentColor") {
                currentColorPrim = t;
            }
            if (llGetSubString(name,0,0) == "=") {
                if (name == "=0.0") {
                    llSetLinkColor(t,<1,1,1>,ALL_SIDES);
                    bendySelectPrim = t;
                } else {
                    llSetLinkColor(t,<0.25,0.25,0.25>,ALL_SIDES);
                }
            }
            if (llGetSubString(name,0,0) == "t") {
                integer num = (integer)(llGetSubString(name,1,-1));
                llSetLinkColor(t,llList2Vector(tints,num),ALL_SIDES);
            }
        }
        nanocount = llGetListLength(nanoes);
        llOwnerSay("Found " + (string)nanocount + " nanoes");
        if (llGetListLength(nanoes) == 0) {
            llOwnerSay(".. which is bad!  Very bad!");
            state dead;
        }
        if (currentColorPrim == -1) {
            llOwnerSay("Missing colour signal!");
            state dead;
        }
 
        bendy = 0;
        tint = <0,0,0>;
        tintNo = 0;
        llSetLinkColor(currentColorPrim,tint,ALL_SIDES);
        lineInProgress = FALSE;
    }
 
    touch_start(integer total_number)
    {
        integer linknumber = llDetectedLinkNumber(0);
        llOwnerSay("Touched link " + (string)linknumber);
        string name = llGetLinkName(linknumber);
        if (llGetSubString(name,0,0) != "@") {
            integer t;
            if (llGetSubString(name,0,0) == "t") {
                integer num = (integer)(llGetSubString(name,1,-1));
                tint = llList2Vector(tints,num);
                tintNo = num;
                llSetLinkColor(currentColorPrim,tint,ALL_SIDES);
                return;
            }
            if (llGetSubString(name,0,0) == "=") {
                llSetLinkColor(bendySelectPrim,<0.25,0.25,0.25>,ALL_SIDES);
                bendy = (float)(llGetSubString(name,1,-1));
                bendySelectPrim = linknumber;
                llSetLinkColor(bendySelectPrim,<1,1,1>,ALL_SIDES);
                return;
            }
            for (t=0; t<llGetListLength(nanoes); t++) {
                if (llList2Integer(nanoes,t) == linknumber) {
                    llSetLinkPrimitiveParams(linknumber,[PRIM_POSITION,<-0.1,0,0>,PRIM_SIZE,<0.01,0.01,0.01>]);
                    nanofree = llListReplaceList(nanofree,[TRUE],t,t);
                    weave = llListReplaceList(weave,[-1],t,t);
                }
            }
            if (name == "button") {
                list out = [];
                llOwnerSay((string)weave);
                for (t=0; t<llGetListLength(nanoes); t++) {
                    integer w = llList2Integer(weave,t);
                    if (w != -1) out += codeToEnc(w);
                }
                out = llListSort(out,1,TRUE);
                llOwnerSay(llDumpList2String(out,", "));
            }
            return;
        }
        name = llGetSubString(name,1,-1);
        list lcoords = llParseString2List(name,[","],[]);
        vector weaveLoc = <llList2Integer(lcoords,0),llList2Integer(lcoords,1),0>;
        float diff;
        vector size;
        if (lineInProgress) {    
            llSetLinkColor(lastPrimNumber,<1,1,1>,ALL_SIDES);
            lineInProgress = FALSE;
            integer t=0;
            while (llList2Integer(nanofree,t) == FALSE) {
                t++;
                if (t > (nanocount - 1)) {
                    llOwnerSay("No free nanoes!!");
                    return;
                }
            } 
            if (bendy == 0.0) drawLine(t,weaveLoc,lastWeaveLoc); else drawArc(t,bendy,weaveLoc,lastWeaveLoc);
        } else {
            lastPrimNumber = linknumber;
            llSetLinkColor(linknumber,tint,ALL_SIDES);
            lineInProgress = TRUE;
            lastWeaveLoc = weaveLoc;
        }
 
    }
}
 
state dead {
    state_entry() {
    }
}

Pressing the "button" prim will cause the grid to spit out a list of "magic words" which can be used to recreate the object. Here's the scripts for the prim object you need to be able to rez objects in this way. This script goes in the root:


integer nanoesoutstanding;
 
default
{
    state_entry()
    {
        llListen(100,"",llGetOwner(),"");
    }
 
    listen(integer channel, string name, key speaker, string message) {
        list bits = llParseString2List(message,[" "],[]);
        integer t;
        nanoesoutstanding = 0;
        for (t=0; t<llGetListLength(bits); t++) {
            llMessageLinked((t+2),0,llList2String(bits,t),(key)"1.0");
            nanoesoutstanding++;
        }
    }
 
    link_message(integer sender, integer intnum, string strnum, key keymsg) {
        if (intnum == 2) nanoesoutstanding--;
        if (nanoesoutstanding == 0) {
            llOwnerSay("Go!");
            llMessageLinked(LINK_ALL_CHILDREN,1,"",NULL_KEY);
        }
    }
 
 
}


This also needs some number of "nano" prims, at least as many as were in the grid you used. This script goes in each nano (yes, I know that's awkward, but I wanted to do the decoding as fast as possible):

list prefixes = [ 
            "br","ch","dr","fl","gr","kr","pr","ph","sr","sh","tr","th","wh","bh","cr","fr","kh",
            "gh","wr","zh","zr","jh","jr","b","c","d","f","g","h","j","k","l","m","n","p","q","r","s","t","v","w","x","z"];
list vowels = ["a","e","i","o","u","y"];
 
vector tint;
list tints = [<0,0,0>,<1,0,0>,<0,1,0>,<0,0,1>,<1,1,0>,<1,0,1>,<1,1,0>,<1,1,1>,
        <0.5,0.5,0.5>,<1,0.5,0.5>,<0,0.5,0>,<0.5,0.5,1>,<0.5,0.5,0>,<0.5,0,0.5>,<0.5,0.5,0>,<0.75,0.75,0.75>];
list becomer;
 
integer dfx;
integer dfy;
integer dsx;
integer dsy;
integer dtint;
float dbend;
 
float unitsize = 1.0;
 
decodePrim(integer code) {
    dfx = - ((code & 15) - 5);
    dfy = ((code & 240) >> 4) - 5;
    dsx = - (((code & 3840) >> 8) - 5);
    dsy = (((code & 61440) >> 12) - 5);
    integer ibendy = ((code & 458752) >> 16);
    dbend = ((float)ibendy) / 4.0;
    dtint = ((code & 7864320) >> 19);
}
 
 
becomeLine(integer nano,vector weaveLocA, vector weaveLocB) {
    vector realCoordA = <(nano * 0.001),(weaveLocA.x * unitsize) + (nano * 0.001),(weaveLocA.y * unitsize) + (nano * 0.001)>;
    vector realCoordB = <(nano * 0.001),(weaveLocB.x * unitsize) + (nano * 0.001),(weaveLocB.y * unitsize) + (nano * 0.001)>;
    vector realDiff = realCoordB - realCoordA;
    vector realDir = llVecNorm(realDiff);
    float realMag = llVecMag(realDiff);
    vector coords = realCoordA + (realDiff / 2);
    coords.z = -coords.z;
    rotation rot = llAxes2Rot(<1,0,0>, realDir, <1,0,0> % realDir);
    vector size = <unitsize / 3,realMag,unitsize / 3>;
    becomer = [PRIM_TYPE, PRIM_TYPE_BOX, 0, <0.0, 1.0, 0.0>, 0.0, <0.0, 0.0, 0.0>, <1.0, 1.0, 0.0>, <0.0, 0.0, 0.0>, PRIM_POSITION,coords,PRIM_ROTATION,rot,PRIM_SIZE,size,PRIM_COLOR,ALL_SIDES,tint,1.0];
}
 
becomeArc(integer nano, float bendy, vector weaveLocA, vector weaveLocB) {
    vector realCoordA = <(nano * 0.001),(weaveLocA.x * unitsize) + (nano * 0.001),(weaveLocA.y * unitsize) + (nano * 0.001)>;
    vector realCoordB = <(nano * 0.001),(weaveLocB.x * unitsize) + (nano * 0.001),(weaveLocB.y * unitsize) + (nano * 0.001)>;
    vector realDiff = realCoordB - realCoordA;
    vector realDir = llVecNorm(realDiff);
    float realMag = llVecMag(realDiff);
    realMag += (unitsize / 3);
    vector coords = realCoordA + (realDiff / 2);
    coords.z = -coords.z;
    rotation rot = llAxes2Rot(realDir, <1,0,0> % realDir, <1,0,0>);
    vector size = <realMag,realMag * bendy,(unitsize / 3)>;
    float hollowScale = 1 - (0.02 / realMag);
    becomer = [PRIM_TYPE, PRIM_TYPE_CYLINDER, 0, <0.0, 0.5, 0.0>, hollowScale, <0.0, 0.0, 0.0>, <1.0, 1.0, 0.0>, <0.0, 0.0, 0.0>, PRIM_POSITION,coords,PRIM_ROTATION,rot,PRIM_SIZE,size,PRIM_COLOR,ALL_SIDES,tint,1.0];
}
 
integer encToCode(string enc) {
    integer code = 0;
    integer shift = 0;
    string tenc = enc;
    while (tenc != "") {
       llOwnerSay(tenc);
       integer pt = 0;
       integer matchlen = 0;
       string prefix;
       integer ok = FALSE;
       integer matchPref;
       integer matchLen;
       integer prefixLength;
       while (!ok) {
           prefix = llList2String(prefixes,pt);
           prefixLength = llStringLength(prefix);
           if (llGetSubString(tenc,0,(prefixLength - 1)) == prefix) {
               ok = TRUE;
               matchPref = pt;
               matchLen = prefixLength;
           } else {
               pt++;
               if (pt > llGetListLength(prefixes)) return -1;
           }
       }
       tenc = llGetSubString(tenc,matchLen,-1);
       string vowel = llGetSubString(tenc,0,0);
       if (llStringLength(tenc) > 1) 
           tenc = llGetSubString(tenc,1,-1);
        else
           tenc = ""; // HACK
       integer vowelno = llListFindList(vowels,[vowel]);
       if (vowelno == -1) return -1;
       code = code + ( ((vowelno * 42) + matchPref) << shift);
       shift = shift + 8;
    }
    return code;
}     
 
default
{
    state_entry() {
        if (llGetNumberOfPrims() < 2) return;
        llSetPrimitiveParams([PRIM_TYPE, PRIM_TYPE_BOX, 0, <0.0, 1.0, 0.0>, 0.0, <0.0, 0.0, 0.0>, <1.0, 1.0, 0.0>, <0.0, 0.0, 0.0>, PRIM_POSITION, <0.0,0.0,0.0>,PRIM_ROTATION,ZERO_ROTATION,PRIM_SIZE,<0.01,0.01,0.01>,PRIM_COLOR,ALL_SIDES,<0.0,0.0,0.0>,1.0]);
    }
 
    link_message(integer sender, integer intmsg, string strmsg, key keymsg) {
        if (intmsg == 0) {
            unitsize = (float)((string)keymsg);  // BLEEEAAAUUUUCH
            integer x = encToCode(strmsg);
            decodePrim(x);
            tint = llList2Vector(tints,dtint);
            if (dbend == 0.0) becomeLine(llGetLinkNumber(),<dfx,dfy,0>,<dsx,dsy,0>); 
                      else    becomeArc(llGetLinkNumber(),dbend,<dfx,dfy,0>,<dsx,dsy,0>);
            llMessageLinked(LINK_ROOT,2,"",NULL_KEY);
        }
        if (intmsg == 1) {
            llSetPrimitiveParams(becomer);
        }
    }    
}

When this object is around, saying a series of magic words on channel 101 should recreate the object that generated them.

Here's a few sets to try to see if you have it working (!):

crewhesa pritesa rikira sretresa teprisa tresresa whecresa

bradra daxa flichisra gogoca jhoxesra pasre pragra prawhe pre sikrica srepre srodrisra trasra tregra whetre xafre