This forum uses cookies
This forum makes use of cookies to store your login information if you are registered, and your last visit if you are not. Cookies are small text documents stored on your computer; the cookies set by this forum can only be used on this website and pose no security risk. Cookies on this forum also track the specific topics you have read and when you last read them. Please confirm whether you accept or reject these cookies being set.

A cookie will be stored in your browser regardless of choice to prevent you being asked this question again. You will be able to change your cookie settings at any time using the link in the footer.

Paramour Line Dancer Script für SL und Opensim in nicht OSSL Regionen
#1
Paramour Line Dancer Script für SL und Opensim in nicht OSSL Regionen

Folgendes Script basiert auf der Arbeit von Mata Hari / Aine Caoimhe.

Und ist unter folgenden Lizenzbedingungen einzusetzten:           https://creativecommons.org/licenses/by-nc-sa/4.0/

Das Original Script kennt jeder von uns, und es ist eine super Arbeit.
Es läuft sehr gut, hat aber Einschränkungen im Einsatzbereich auf einige Regionen in Opensim.

Diese sind folgendermaßen begründet:
- OSSL Befehle müssen im Grid aktiviert, und dem Parzellenbesitzer (und Rezzer des Danceliners) erlaubt sein.
- NPCs werden nur auf Sims korrekt gerezzt deren Zugang öffentlich ist.
- Die Art wie die Userzustimmung zur Animation eingeholt wird, ist nicht auf SL portabel.
- Die Bedienung ist ausschließlich dem Besitzer vorenthalten.

Ich habe mich daher entschlossen 2 aktualiserte Versionen bereitzustellen.

Eine die ganz ohne OSSL Befehle auskommt, und in Opensim wie auch in Sl lauffähig ist (Ohne NPCs). Diese dient Opensim Regionen die keine OSSL Freigabe haben.

Ausserdem eine weiterer Opensim Version die OSSL nutzt und NPCs im (neuen) Grupenkontext rezzt.
Dies ermöglicht auch den Einsatz in Regionen die für Öffentlichkeit gesperrt sind und nur mit gültiger Gruppe betreten werden können.

Beiden gemeinsam ist die Unterstützung eines einstellbaren Berechtigungs Systems wer den Poser per Menü kontrollieren darf: ( Eigentümer, ausgewählte Manager, Gruppe, oder jeder).
Die Manager werden per UUID unter "Zugangsliste" eingetragen. Im Muster sind 3 Manager als Demo drin.

Ausserdem neu ist ein Debug Modus. Dieser wird per Menü Ein/Aus geschalten.
Er dient zur Kontrole neu eingefügter Posen. Es erfolgt im Chat die Ausgabe der Posennamen, um fehlerafte Posen zu identifizieren.

Hier nun die Version für SL und OSSL freie Zonen:  (ohne NPC Unterstützung)

Code:
// P604 PARAMOUR LINE-DANCE CONTROLLER SL Adaption v3.4 VSL by Tron 11.2021
// original OSSL Version by Mata Hari / Aine Caoimhe November 2014
// Provided under Creative Commons Attribution-Non-Commercial-ShareAlike 4.0 International license.
// Please be sure you read and adhere to the terms of this license: https://creativecommons.org/licenses/by-nc-sa/4.0/
//
// Änderungen by Tron: Script für Funktionsfähigkeit in Sl und Opensim umgeschrieben.
// Hinzufügung eines umfangreichen Berechtigungs Systems. Entfernen des NPC Systems.
// Script funktioniert nun auch in Regionen die OSSL abgeschalten haben.
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
// USER SETTINGS - stuff that any user should feel comfortable setting
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
//
integer textanzeige =TRUE;                      // TRUE = show floaty text, FALSE = hide it
string  textmessage;                            // name to appear in floaty text above the line dance object. Read from Prim description
vector  textcolour =<1.000, 0.847, 0.200>;      // colour to use for the floaty text
//
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
// ADVANCED USER SETTINGS - a more advanced user might want to adjust these
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
integer  debug = FALSE;
list     ignoreNotecards=["*** READ ME ***"];    // list of any notecards in inventory that are not NPC notecards
integer  maxLineLength=5;                        // maximum number of dancers allowed in a single line
float    spacingX=1.5;                           // distance between each dancer in the line (side to side)
float    spacingY=-1.5;                          // when more than 1 line is needed, how far apart to space lines
vector   p1Pos=<0.0, 0.0, 1.25>;                 // sit target position for 1st dancer - all other dancers positioned relative to this position (and centered on it) <0.0, 0.0, -2.0>;
rotation p1Rot=ZERO_ROTATION;                    // sit target rotation for 1st dancer - making this non-zero could produce unusual results!
integer  randomOrder=FALSE;                      // TRUE = play dances in random order, FALSE = play in alphabetical order
float    danceTimer=60.0;                        // how long (in seconds) to play each line dance by default before moving on to the next one (owner can also change this via dialog)
//
//
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
// DON'T CHANGE ANYTHING BELOW HERE UNLESS YOU KNOW WHAT YOU'RE DOING!!!!!
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
string  baseAnim="*****base_DO NOT DELETE ME!";
list    animatliste;
integer animationsnr;
string  currentAn;
list    dancerliste;
string  myState="OFF";
integer myChannel;
integer handle;
integer closeHandle;

integer taenzeranzahl;

integer poserlinks;
integer taenzeraufposer;

key toucher;                    // UUID des Operator des Menüs

list zugangsliste = ["2338a1d0-0d7b-4ec1-b841-029c49c9d461","8998586e-b754-4032-856f-f4f4b122eb6e"]; // UUIDS berechtigter AVAs
integer groupaccess = TRUE;    // TRUE ore FALSE - darf die Gruppe steuern?
integer publicaccess = FALSE;   // TRUE ore FALSE - darf jeder steuern?


osAvatarPlayAnimation(key avatar, string animation)
{
    llStartAnimation(animation);
}


osAvatarStopAnimation(key avatar, string animation)
{
    llStopAnimation(animation);
}


integer berechtigungscheck(string clicker, integer selbegruppe)  // Zugangsberechtigung auswerten
     {
        integer zugang = FALSE;
        integer personalzugang = llGetListLength(zugangsliste);
        if (publicaccess)  { zugang = TRUE; if(debug)llSay(0,"Publiczugang erteilt"); }                     // Öffentlicher Zugang
        else if (selbegruppe && groupaccess) { zugang = TRUE; if(debug)llSay(0,"Gruppenzugang erteilt"); }  // Gruppen Zugang
        else if (clicker ==  llGetOwner()) { zugang = TRUE; if(debug)llSay(0,"Ownerzugang erteilt"); }      // Besitzer Zugang immer erlaubt
        else if (personalzugang)                                                                            // Persönlicher Zugang
        {
            string personal;
            do
            {  
                personal = llList2String(zugangsliste, personalzugang -1 );
                if( clicker ==  personal) { zugang = TRUE; if(debug)llSay(0,"Userzugang erteilt"); }
                personalzugang--;
            }       
            while ( (integer)personal && (!zugang));
        }
        return zugang;
     }


showMenu(key operator)
{
    myChannel=0x80000000 | (integer)("0x"+(string)operator);
    string txtDia="\nAutotimer value 60\n\nPLEASE CLICK DONE WHEN FINISHED!";
    list butDia=["DONE","NextDance","28 SEC","60 SEC","90 SEC","120 SEC","300 SEC","Debugmode"];
    handle=llListen(myChannel,"",operator,"");
    llDialog(operator,txtDia,butDia,myChannel);
    closeHandle=TRUE;
}


positionDancers()
{
    dancerliste=[];
    integer link=llGetNumberOfPrims();
    while (link>0)
    {
        if (llGetAgentSize(llGetLinkKey(link))!=ZERO_VECTOR) dancerliste=[]+[llGetLinkKey(link),link]+dancerliste;
        link--;
    }
    integer laufvar5;
    taenzeranzahl=llGetListLength(dancerliste);
    integer row;
    integer pos;
    integer thisLineCount;
    while (laufvar5 < taenzeranzahl)
    {
        vector thisPos=p1Pos;
        rotation thisRot=p1Rot;
        thisPos.y+=(pos*spacingX);
        thisPos.x+=(row*spacingY);
        llSetLinkPrimitiveParamsFast(llList2Integer(dancerliste,laufvar5+1),[PRIM_POS_LOCAL,thisPos,PRIM_ROT_LOCAL,thisRot]);
        thisLineCount++;
        if(thisLineCount>=maxLineLength)
        {
            thisLineCount=0;
            pos=0;
            if (row==0) row++;
            else if (row>0) row=row*-1;
            else row=(row*-1)+1;
        }
        else
        {
            if (pos==0) pos++;
            else if (pos>0) pos=pos*-1;
            else pos=(pos*-1)+1;
        }
        laufvar5 +=2;
    }
}


startDancing(key who)
{
    llRequestPermissions(who, PERMISSION_TRIGGER_ANIMATION );
    key doNotStop=llGetInventoryKey(baseAnim);
    osAvatarPlayAnimation(who,baseAnim);
    list anToStop=llGetAnimationList(who);
    integer avacount=llGetListLength(anToStop);
    while (--avacount>=0) { if (llList2Key(anToStop,avacount)!=doNotStop) osAvatarStopAnimation(who,llList2Key(anToStop,avacount)); }
    osAvatarPlayAnimation(who,currentAn);
}


nextDance(integer tanzwechsel)
{
     animationsnr++;
   
    if (animationsnr>=llGetListLength(animatliste))
    {
        if (randomOrder) animatliste=[]+llListRandomize(animatliste,1);
        animationsnr=0;
    }
    string nextDance=llList2String(animatliste,animationsnr);
    taenzeranzahl=llGetListLength(dancerliste);  
    if (debug) llWhisper(0,"Starting " +(string)animationsnr +". Animation:  "  +nextDance+"  Stopping: "+currentAn );
    integer i;
    while (i<taenzeranzahl)
    {
        key who=llList2Key(dancerliste,i);
        llRequestPermissions(who, PERMISSION_TRIGGER_ANIMATION );
        osAvatarStopAnimation(who,currentAn);
        osAvatarPlayAnimation(who,nextDance);
        i+=2;
    }
    currentAn=nextDance;
    positionDancers();
    llSetTimerEvent(danceTimer);
}


showText(integer anzeige)
{
    if (anzeige)
    { 
        if (myState=="ERROR") { llSetText("ERROR - owner needs to fix and reset",textcolour,1.0);}
        else llSetText(textmessage,textcolour,1.0);
    }
    else llSetText("",textcolour,0.0);
}


buildAnimList()
{
    animatliste=[];
    integer l=llGetInventoryNumber(INVENTORY_ANIMATION);
    while (--l>=0) { if (llGetInventoryName(INVENTORY_ANIMATION,l)!=baseAnim) animatliste=[]+[llGetInventoryName(INVENTORY_ANIMATION,l)]+animatliste; }
    if (llGetListLength(animatliste)==0)
    {
        llWhisper(0,"ERROR! No dance animations in inventory!");
        myState="ERROR";
    }
    else if (llGetListLength(animatliste)>1)
    {
        if (randomOrder) animatliste=[]+llListRandomize(animatliste,1);
        else animatliste=[]+llListSort(animatliste,1,TRUE);
    }
    animationsnr=-1;
}


default
{
    on_rez (integer foo) {llResetScript();}


    state_entry()
    {
        poserlinks = llGetNumberOfPrims();  // Primzahl leeren Posers ermittlen und speichern
        textmessage  = llGetObjectDesc();   // Prim Beschreibungsfeld auslesen
        llSetSitText(textmessage);
        llSitTarget(<0.0,0.0,0.0001>,ZERO_ROTATION);
        if (llGetInventoryType(baseAnim)!=INVENTORY_ANIMATION) {llWhisper(0,"ERROR! Unable to locate the base animation which MUST be in the ball."); myState="ERROR";}
        buildAnimList();
        if (myState!="ERROR")
        {
            myState="READY";
            dancerliste=[];
            animationsnr=0;
            currentAn=llList2String(animatliste,animationsnr);
        }
        showText(textanzeige);
    }

   
    changed (integer change)
    {
        if (change & CHANGED_REGION_START) llResetScript();
        if (change & CHANGED_OWNER) llResetScript();
        if (change & CHANGED_LINK)
        {
            list newDancerslist;
            integer aktlinkzahl=llGetNumberOfPrims();
            taenzeraufposer = aktlinkzahl - poserlinks;  // Tänzerzahl aus Primdifferenz ermitteln und speichern
            if(taenzeraufposer) {showText(FALSE);} else {if(textanzeige) showText(TRUE);}
            if(debug) llWhisper(0,"Aktuelle Tänzerzahl auf Poser: "+ (string)taenzeraufposer);

            while (aktlinkzahl>0)  // Taenzer abzählen und Liste erstellen
            {
                if (llGetAgentSize(llGetLinkKey(aktlinkzahl))!=ZERO_VECTOR) newDancerslist=[]+newDancerslist+[llGetLinkKey(aktlinkzahl),aktlinkzahl];
                aktlinkzahl--;
            }
            taenzeranzahl =llGetListLength(dancerliste);      
            integer laufvar1;
            while (laufvar1 < taenzeranzahl)
            {
                key who=llList2Key(dancerliste,laufvar1);
                integer ind=llListFindList(newDancerslist,[who]);
                if (ind>=0) // jemand sitzt neu
                {
                    dancerliste=[]+llListReplaceList(dancerliste,[llList2Integer(newDancerslist,ind+1)],laufvar1+1,laufvar1+1);
                    newDancerslist=[]+llDeleteSubList(newDancerslist,ind,ind+1);
                }
                else // jemand steht auf
                {
                    osAvatarPlayAnimation(who,"stand");
                    osAvatarStopAnimation(who,currentAn);
                    osAvatarStopAnimation(who,baseAnim);
                    dancerliste=[]+llDeleteSubList(dancerliste,laufvar1,laufvar1+1);
                }
                laufvar1+=2;
            }

            integer neutaenzer =llGetListLength(newDancerslist);  // Anzahl neuer Tänzer ermitteln- Achtung gibt doppelte Zahl aus.
            integer laufvar2 =0;

            while (laufvar2<neutaenzer)
            {
                startDancing(llList2Key(newDancerslist,laufvar2));
                laufvar2+=2;
            }

            dancerliste=[]+dancerliste+newDancerslist;
            if (llGetListLength(dancerliste)==0)
            {
                myState="READY";
                llSetTimerEvent(0.0);
            }
            else
            {
                if (myState=="READY") myState="ON";
                nextDance(FALSE);    // have to advance dance to keep them all synched and to trigger positioning
            }
        }
    }


    touch_start(integer dummy)  // Menü Zugriff regeln
     {
        toucher = llDetectedKey(0);
        integer gruppei = llDetectedGroup(0);
        integer access;
        access = berechtigungscheck(toucher,gruppei);
        if(access) {if(debug) llInstantMessage(toucher,"Menü Zugriff gewährt"); showMenu(toucher);}
     }


    listen(integer channel, string name, key who, string message)
    {
        llListenRemove(handle);
        closeHandle=FALSE;
        if (message=="DONE") return;
        else if (llSubStringIndex(message," SEC")>=0)
        {
            danceTimer=(float)(llGetSubString(message,0,llSubStringIndex(message," MIN")-1));
            llInstantMessage(toucher,"Dance timer now set to "+message);
            if (myState=="ON")
            {
                llSetTimerEvent(danceTimer);
                nextDance(TRUE);
            }
            showMenu(toucher);
        }
        else if (message == "Debugmode") { debug = !debug; llInstantMessage(toucher,"Debugmodus [1 an / 0 aus] = "+(string)debug);}
        else if (message == "NextDance") if (myState=="ON") nextDance(TRUE);
    }


    timer()
    {
        if(closeHandle)
        {
            closeHandle++;
            if (closeHandle>2)
            {
                closeHandle=0;
                llInstantMessage(toucher, "Dialog has timed out...touch me again to re-active the dialog menu");
                llListenRemove(handle);
            }
        }
        if (myState=="ON") nextDance(TRUE);
        else llSetTimerEvent(0.0);
    }
}



Die Anwendung erfolgt wie gewohnt:

Sie erfordert eine Basis Animation "*****base_DO NOT DELETE ME!" sowie dieses Script im Rootprim.
Dies ist eine Standard T-Pose Animation mit niedrigster Priorität 1.
Derartige Basis Animationen finden sich auch im PMAC Poser.

Ansonsten zieht eure eigenen Animationen hinein.
Sobald eine neue Animation erkannt wird, erfolgt ein Reset des Scriptes automatisch.

Die Animationen werden in Sortier-Reihenfolge automatisch als Endlosschleife abgespielt.
Per Menü kann auf Posen und Laufzeit Einfluss genommen werden.

Änderung in Version 3.4:
Der Eintrag in der Prim Beschreibung wird als Text über der Tanzfläche angezeigt wenn keiner tanzt.
Das Script muss resettet werden damit diese Anzeige aktualisiert wird.

Die Opensim Versionen mit NPCs kommen später.

Viel Spaß

Tron
Zitieren
#2
oh da hatte sich ein Fehler eingeschlichen, ich habe den am 3.11. bereinigt
Zitieren
#3
Super!
All done!
Zitieren


Gehe zu:


Benutzer, die gerade dieses Thema anschauen: 1 Gast/Gäste