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

Published on

in

,

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);
    }
}

Leave a comment


Benvenuto su Salahzar.com

Qui trovi analisi critiche sull’intelligenza artificiale e le sue implicazioni sociali, scritte da chi viene da una impostazione umanistica e ha passato vent’anni a costruire mondi virtuali prima che diventassero “metaverso”.

Niente hype da Silicon Valley o entusiasmi acritici: sul tavolo ci sono le contraddizioni dell’innovazione tecnologica, i suoi miti fondativi, le narrazioni che usiamo per darle senso. Dai diari ucronici (storie alternative come strumento per capire i nostri bias cognitivi) alle newsletter settimanali sugli sviluppi dell’AI che richiedono aggiornamenti continui perché i trimestri sono già preistoria.

Se cerchi guide su come “fare soldi con ChatGPT” o liste di prompt miracolosi, sei nel posto sbagliato. Se invece ti interessa capire cosa sta succedendo davvero – tra hype, opportunità concrete e derive distopiche – sei nel posto giusto.

Umanesimo digitale senza retorica, analisi senza paternalismi, ironia senza cinismo.


Join the Club

Stay updated with our latest tips and other news by joining our newsletter.