Pyramidopolo: lo script per distribuire gratis molti oggetti con un solo prim…

Ho finalmente realizzato (avevo già un KIT) un sistema abbastanza elegante, valido sia in SL che in OpenSim per riuscire a “progettare” gli hotspot, vale a dire le aree rettangolari che quando vengono cliccate possono determinare un’azione diversa. Questa è una tecnica simile a quella già impiegata sul web per poter cliccare su una immagine in punti diversi, tecnica chiamata “Image Mapping” (http://www.javascriptkit.com/howto/imagemap.shtml), noi usiamo una versione leggermente più semplice che usa dei rettangoli.

Workflow di uso:

Una volta avuto l’oggetto padre ci depositiamo la nostra texture su cui vogliamo calcolare gli HOT SPOTS. Nota bene: in fase di progetto l’oggetto e i suoi marker dovranno tutti avere rotazione ZERO altrimenti il giochetto non funziona !!!

Se lo script è resettato cliccando abbiamo le seguenti opzioni:

  • DELETE per cancellare tutti i marker
  • MARKER per rezzare al centro un marker trasparente che dovrà essere poi editato e cambiato il nome
  • NOTECARD per far leggere le coordinate degli HOT SPOTS definiti nella notecard
  • DUMP per scaricare le informazioni dedotte da tutti i marker attuali come messaggi IM all’owner
  • RUN per “chiudere” il progetto e passare all’atto reale di uso da parte degli utenti finali
  • RESET per resettare
Il (i) vari marker dovranno essere editati (tasto destro edit/modifica) in modo da spostarli nelle posizioni volute.
I marker dovranno anche essere toccati per avere una finestra di dialogo che consente di specificarne il nome (funziona con il viewer 2, kirstens e firestorm, ma NON imprudence).
QUando si sono definiti tutti gli hotspot si clicca su DUMP per ottenere in chat l’elenco voluto da inserire nella notecard.
Se si sposta su un altro piramidopolo basta spostare la notecard.

In questo modo appare abbastanza semplice configurare o aggiornare gli hotspot.

Una volta modificato è sufficiente mettere nella funzione HANDLE il necessario comando lsl per elaborare ad esempio

llGiveInventory(k,str); per consegnare un oggetto dell’inventory del Piramidopolo.

Dettagli interni:

Cominciamo a costruire un pannello “padre” che chiamiamo Pyramidopoli su cui applichiamo una texture opportuna come ad esempio la mappa dell’italia. (Il pannello è un cubo con una delle dimensioni messa a ZERO).

Poi dobbiamo costruire un oggetto chiamato MARKER che dovremo infilare dentro al nostro oggetto principale.

Ed infine dobbiamo mettere una notecard chiamata CONFIG dentro all’oggetto principale.

Gli script sono DUE ed eccoli:

Oggetto principale

Dentro l’oggetto principale mettiamo il seguente script:

integer status=1; // 1 = design 2=runtime
list names;
list values;
list uuids;

string NCNAME;
integer NCLINE;
integer door;

handle(key k,string str)
{
    llSay(0,"Handle "+str);
}
sendInfo()
{
    // inform of my pos, rot and scale
    llSay(1000,llList2CSV([llGetPos(),llGetRot(),llGetScale()]));
}
default
{
    state_entry()
    {
        llSay(0, "Reset");
        llListen(1001,"",NULL_KEY,"");
        sendInfo();
    }
    listen(integer channel,string name,key id,string str)
    {
        list pieces=llParseStringKeepNulls(str,["|"],[]);
        if(llList2String(pieces,0)=="SET")
        {
            float topleftx=llList2Float(pieces,1);
            float topleftz=llList2Float(pieces,2);
            float bottomrightx=llList2Float(pieces,3);
            float bottomrightz=llList2Float(pieces,4);

            // check if we already have noted this area
            integer pos=llListFindList(uuids,[id]);
            if(pos>=0)
            {
                uuids=llDeleteSubList(uuids,pos,pos);
                names=llDeleteSubList(names,pos,pos);
                values=llDeleteSubList(values,pos,pos);
            }

            uuids+=[id];
            names+=llGetObjectDetails( id, [OBJECT_NAME]);
            values+=[ <topleftx,topleftz,bottomrightx,bottomrightz> ];

            return;
        }
        else if(str=="tellme") sendInfo();
        else if(str=="RUN")
        {
            status=2;
            llSay(0,"Now in run state");
        }
        else if(str=="DESIGN")
        {
            status=1;
            llSay(0,"Now in design state");
        }
        else if(str=="RESET")
        {
            llResetScript();
            return;
        }
        else if(str=="MARKER")
        {
            llRezAtRoot("MARKER",llGetPos(),ZERO_VECTOR,llGetRot(),0);
        }
        else if(str=="NOTECARD")
        {
            state notecard;
        }
        else if(str=="DUMP")
        {
            integer l=0;
            for(l=0;l<llGetListLength(names);l++)
            {
                llOwnerSay("|SET|"+llList2String(names,l)+"|"+
                            llList2String(values,l));
            }
        }
            else if(str=="DELETE") llSay(1000,"DELETE");

    }
    touch_end(integer total_number)
    {
            if((llGetUnixTime()-door)> 3) llResetScript();
    }

    touch_start(integer total_number)
    {
        integer t=0; door=llGetUnixTime();
        for(t=0;t<total_number;t++)
        {
            key touchedby=llDetectedKey(t);
            // if runtime loops over all values to understand what to do
            if(status==2)
            {

                vector st=llDetectedTouchST(0);
                integer i=0;
                for(i=0;i<llGetListLength(uuids);i++)
                {
                    rotation r=(rotation)(llList2String(values,i));
                    if( (st.x>= /* bottomright.x */ r.z) &&
                        (st.x<= /* topleft.x */ r.x) &&
                        (st.y>= /* topleft.z */ r.y) &&
                        (st.y<= /* bottomright.z */ r.s)
                        )
                    {
                        handle(touchedby,llList2String(names,i));
                        return;
                    }
                }
                handle(touchedby,"MISSING");
            }
            else
            {
                llDialog(touchedby,"Scegli",["RUN","DESIGN","RESET","MARKER","NOTECARD","DUMP","DELETE" ],1001);
            }
        }

        //llSay(0,"ORIGINAL ST: "+(string)st);
        //sendInfo();
    }
    changed(integer change)
    {
        if(change & CHANGED_SCALE)
        {
            // send the scale info to all children
            sendInfo();
        }
    }
}
state notecard
{
    state_entry()
    {
        NCNAME="CONFIG";
        NCLINE=0;
        llGetNotecardLine(NCNAME,NCLINE);
    }
    dataserver(key id,string str)
    {
        if(str==EOF)
        {
            llSay(0,"Finished notecard read "+(string)NCLINE + " lines");
            state default;
            return;
        }

        list pieces=llParseStringKeepNulls(str,["|"],[]);
        integer p=0;
        for(p=0;p<llGetListLength(pieces);p++)
        {
            if(llList2String(pieces,p)=="SET")
            {
                uuids+=[ NULL_KEY ];
                names+=[llList2String(pieces,p+1)];
                values+=[ (rotation)llList2String(pieces,p+2) ];
            }
        }
        llSay(0,"reading line "+(string)NCLINE);
        NCLINE++;
        llGetNotecardLine(NCNAME,NCLINE);

    }
}

 Dentro il MARKER mettiamo questo script:

// Salahzar stenvaag July 2011
// this script is acting as a map area marker
// it must be scaled to represent a proper area on basic screeb
// if touched you can set its name

integer LISTENER;

vector x1=ZERO_VECTOR;
rotation r1=ZERO_ROTATION;
vector s1=ZERO_VECTOR;
vector f=ZERO_VECTOR;

vector topleft;
vector bottomright;

// not really to 2 digits, but it can do that
string to2digits(float x)
{
    return (string)x;
    integer y=(integer)(x*100+.5); // round it
    string ret=(string)y;
    if(y<10) return "0"+ret;
    else return ret;

}

say()
{

    if(x1==ZERO_VECTOR)
    {
        llSay(1001,"tellme");
        // llSay(0,"Must transmit localrootscale");
        return;
    }

    vector x2=llGetPos();
    vector s2=llGetScale();

    topleft=(x2-(s2/2.0))-f;
    topleft.x=1-topleft.x/s1.x;
    topleft.z=topleft.z/s1.z;

    bottomright=x2+(s2/2.0)-f;
    bottomright.x=1-bottomright.x/s1.x;
    bottomright.z=bottomright.z/s1.z;

    //llSay(0, " x1: "+(string)x1+" x2: "+(string)x2+" s1: "+(string)s1+" s2: "+(string)s2);

    //llSay(0,"if( (st.x>="+(string)bottomright.x+") && (st.x<="+(string)topleft.x+") && (st.y>="+(string)topleft.z+") && (st.y<="+(string)bottomright.z+")");
    llSay(1001,"SET|"+to2digits(topleft.x)+"|"+to2digits(topleft.z)+"|"+to2digits(bottomright.x)+"|"+to2digits(bottomright.z));

}
default
{
    state_entry()
    {
        //llSay(0, "Reset!");
        llListen(1000,"",NULL_KEY,"");
        llSetObjectName("<clicca per nome>");
        llSetText(llGetObjectName(),<1,1,1>,1);
    }

    touch_start(integer number)
    {
        LISTENER=llListen(-1,"",NULL_KEY,"");

        llTextBox(llDetectedKey(0),"Dai un nome a questo oggetto",-1);
        llSetTimerEvent(20);
        llSetColor(<1,0,0>,ALL_SIDES);
    }
    timer()
        {
            llListenRemove(LISTENER);
            llSetTimerEvent(0);
            llSetColor(<1,1,1>,ALL_SIDES);
        }

    changed(integer change)
    {
        say();
    }
    listen(integer channel, string name, key id, string str)
    {
        if(channel==-1)
        {
            llSetTimerEvent(0);
            llSetColor(<1,1,1>,ALL_SIDES);
            llSetObjectName(str);
            llSetText(str,<1,1,1>,1);
            llListenRemove(LISTENER);
            return;
        }
        if(str=="DELETE") llDie();

        list recvd=llCSV2List(str);

        x1=(vector)llList2String(recvd,0);
        r1=(rotation)llList2String(recvd,1);
        s1=(vector)llList2String(recvd,2);

        f=x1-s1/2;

        say();
        //llSay(0,"Received x1:"+(string)x1+" r1:"+(string)r1+" s1:"+(string)s1);
    }
}
Advertisements
This entry was posted in LSL, Scripting avanzato. Bookmark the permalink.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s