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 Opensim in OSSL Regionen mit NPC Unterstützung
#2
UPDATE des Paramour Line Dancer Script für Opensim in OSSL Regionen mit NPC Unterstützung auf Version 3.8


Die Version 3.7 wählte die zu rezzenden NPCs per Zufall aus.
Das ist ok, wenn man nur wenige NPCs rezzen will, aber viele in den Poser eingestellt hat.

Aber es konnte vorkommen das NPCs doppelt gerezzt wurden, dafür Andere gar nicht.

Ich habe das Scirpt nun auf die Version 3.8 erweitert um die NPC Auswahl wahlweise sequentiell oder per Zufall zu erlauben.

Verantwortlich ist nun dafür die Zeile 18:

integer randomselectNPC = FALSE;                // rezzt NPCs sequentiell bis alle auf dem Poser stehen. Dann wird wieder beim Ersten angefangen

integer randomselectNPC = TRUE;                 // rezzt NPCs per Zufall, dies entspricht dem Verhalten der Version 3.7



Code:
// P604 PARAMOUR LINE-DANCE CONTROLLER OSSL v3.8 VSL by Tron 10.2023
// 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/
//
// *** Dieses Script benötigt Regionen in denen OSSL Befehle freigeschalten sind, und der Scriptbesitzer diese Rechte hat***
//
// Unbedingt darauf achten das Prim dieses Scriptes im Kontext der erlaubten Simgruppe zu rezzen,
// ansonsten kommt es zu NPC Fehlern wenn der öffentliche Zugang abgeschalten wird!
//
// Diverse Änderungen: NPCs rezzen nnun Fehlerfrei auf gesperrten Sims wenn sie die erlaubte Gruppe haben
// Änderungen by Tron: Script für Funktionsfähigkeit in Sl und Opensim umgeschrieben.
// Hinzufügung eines umfangreichen Berechtigungs Systems.
// Änderung Version 3.8 NPC AUswahl nun schaltbar ob sequentiell oder random
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
// USER SETTINGS - stuff that any user should feel comfortable setting
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
//
integer randomselectNPC = FALSE;                // Sollen NPCs per Zufall [TRUE] oder sequentiell [FALSE] gewählt werden
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;
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;              // Liste von Avataren UND NPCs auf dem Poser
string  myState="OFF";
integer myChannel;
integer handle;
integer closeHandle;
list    npcList;
integer npcToRez;
integer taenzeranzahl;            // Integer! Anzahl der aktuellen Tänzer

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?

list    npccardlist;
list    npcnamelist;
integer lastrezzednpc = -1;
integer npcanzahl;

integer berechtigungscheck(string clicker, integer selbegruppe)  // Zugangsberechtigung auswerten
     {
        integer zugang = FALSE;
        integer personalzugang = llGetListLength(zugangsliste);
        if (publicaccess)  { zugang = TRUE;}                     // Öffentlicher Zugang
        else if (selbegruppe && groupaccess) { zugang = TRUE;}   // Gruppen Zugang
        else if (clicker ==  llGetOwner()) { zugang = TRUE;}     // Besitzer Zugang immer erlaubt
        else if (personalzugang)                                 // Persönlicher Zugang über UUID Liste
        {
            string personal;
            do
            {  
                personal = llList2String(zugangsliste, personalzugang -1 );
                if( clicker ==  personal) { zugang = TRUE; }
                personalzugang--;
            }       
            while ( (integer)personal && (!zugang));
        }
        return zugang;
     }


showMenu(key operator)
{
    myChannel=0x80000000 | (integer)("0x"+(string)operator);
    string txtDia="Danceliner Optionen Menü: ADD/Kill NPCs, Animationswechel, Ändern der Tanzdauer";
    list butDia=["ABBRUCH","NextDance","Add NPC","Kill NPC","Kill ALL","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()
{
    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);
    }
    if(debug) llSay(0,"Animations Liste: "+ (string)animatliste);
    animationsnr=-1;
}


integer buildNPClist()
{
    npccardlist = [];
    npcnamelist = [];
    integer npczahl;
    integer notecardzahl = llGetInventoryNumber(INVENTORY_NOTECARD);
    while (notecardzahl)
    {
        notecardzahl--;                                              // Anzahl ist 1 höher als Adressierung.
        string notecardname = llGetInventoryName(INVENTORY_NOTECARD,notecardzahl);
        if (llSubStringIndex(notecardname,".NPC")==0)               // Testen ob sie eine .NPC Notecard ist
        {
            string npc_name = llGetSubString(notecardname,8,-1);     // npc_namen ermitteln
            if(debug) llSay(0,"NPC Namen: " + npc_name );
            npccardlist += notecardname;                            // Liste mit NPC enthaltenden Notecards erstellen
            npcnamelist += npc_name;                                // Liste mit NPC Namen erstellen
            npczahl++;
        }
    }
    if(debug) llSay(0,"NPC Zahl: "+ (string)npczahl +"  NPC Liste: "+(string) npcnamelist);
    return (npczahl);
}


npc_alive_check()                                                    // Check ob die vorher gerezzten NPCs noch leben
{
    integer npczahl = llGetListLength(npcList);
    list    restnpcList = [];
    integer laufvar;
    while (laufvar < npczahl)
    {
        key npctocheck = llList2Key(npcList,laufvar);                // Check ob NPC Key noch vorhanden- als Lebenszeichen
        if (osIsNpc(npctocheck)) { restnpcList += npctocheck;}        // Rest NPC Liste erstellen
        laufvar++;
    }
    npcList = [] + restnpcList;                                        // NPC Liste aktualisieren
    if(debug) llSay(0,"Lebendige NPCs: "+ (string)npczahl +" UUID Liste gerezzter NPCs: "+(string) npcList);
}


key npc_rezzer(key sittarget, vector npcPos, string npcnotecard, string npc_name)    // NPC im GRUPPENKONTEXT rezzen, damit der auf Sims geht die öffentlich gesperrt, aber für Gruppe frei ist
{
    key npctorez = osNpcCreate(npc_name, "" , npcPos, npcnotecard, 8 | OS_NPC_NOT_OWNED | OS_NPC_SENSE_AS_AGENT | OS_NPC_OBJECT_GROUP );
    llSleep(0.5);
    osNpcSit(npctorez,sittarget,OS_NPC_SIT_NOW);
    if (llGetInventoryKey(".bild " + npc_name)) osNpcSetProfileImage(npctorez,".bild "+ npc_name);                   // Testen ob Profilbild vorhanden - dann laden
    if (llGetInventoryKey(".info " + npc_name) != (string)NULL_KEY )
    {
        string info = (string) osGetNotecard(".info " + npc_name);
        osNpcSetProfileAbout(npctorez, info);  // Testen ob Profilinfo Notecard vorhanden - dann laden
    }
    if(debug) llSay(0," NPC gerezzt: " + npc_name + " mit UUID: " + (string)npctorez);
    llSleep(1.0);
    osAvatarPlayAnimation(npctorez,currentAn);
    return npctorez;
}


npc_rez_selector(list npccardlist, list npcnamelist )    // NPC auswählen der gerezzt werden soll
{
    key sittarget = llGetKey();
    vector npcPos = llGetPos();
    integer randomnpc;
   
    if(randomselectNPC)
    {
        randomnpc = llFloor(llFrand(llGetListLength(npccardlist)));
    }
    else
    {
        lastrezzednpc++;
        if (lastrezzednpc >= npcanzahl) lastrezzednpc = 0;
        randomnpc = lastrezzednpc;
    }
    if(debug) llSay(0,"gewählter NPC:"+(string)randomnpc);

    string  npcnotecard = llList2String(npccardlist,randomnpc);
    string  npc_name    = llList2String(npcnamelist,randomnpc);
    if(debug) llSay(0,"NPC Selector: NPC "+ (string) llGetListLength(npccardlist) + " per Zufall gewählt: " + (string)randomnpc + "  " + npc_name);
    key npc = npc_rezzer(sittarget, npcPos, npcnotecard, npc_name);
    npcList=[]+npcList+[npc];
}


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();
        npcanzahl = buildNPClist();
        if (debug) llSay(0, "Anzahl gefundenen NPCs: "+(string)npcanzahl );
        if (myState!="ERROR")
        {
            myState="READY";
            dancerliste=[];
            animationsnr=0;
            currentAn=llList2String(animatliste,animationsnr);
        }
        showText(textanzeige); // dient auch zum Löschen
    }

   
    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 {showText(textanzeige);}
            if(debug) llWhisper(0,"Aktuelle Tänzerzahl auf Poser: "+ (string)taenzeraufposer);
            npc_alive_check(); // Testen ob NPCs verschwunden sind, und NPC Liste bereinigen.
            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";}   // have to advance dance to keep them all synched and to trigger positioning
            nextDance();
        }
    }


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


    listen(integer channel, string name, key who, string message)
    {
        llListenRemove(handle);
        if(debug) llSay(0,"Message enpfangen: " + message);
        closeHandle=FALSE;
   
        if (message=="ABBRUCH") return;

        else if (message == "NextDance") {if (myState=="ON") nextDance();}

        else if (message == "Add NPC")
        {
            if (llGetInventoryNumber(INVENTORY_NOTECARD)<1) { llInstantMessage(toucher,"I can't find any NPC notecards to use!");}
            else { npc_rez_selector(npccardlist, npcnamelist ); llSetTimerEvent(2.0); ;
            }
        }

        else if (message == "Kill NPC")
        {
            osNpcRemove(llList2Key(npcList,-1));
            npcList=[]+llDeleteSubList(npcList,-1,-1);
            showMenu(toucher);
        }

        else if (message == "Kill ALL")
        {
            while(llGetListLength(npcList))
            {
                osNpcRemove(llList2Key(npcList,-1));
                npcList=[]+llDeleteSubList(npcList,-1,-1);
            }
        }

        else if (llSubStringIndex(message," SEC")>=0)
        {
            danceTimer=(float)(llGetSubString(message,0,llSubStringIndex(message," MIN")-1));
            llInstantMessage(toucher,"Animations Dauer ist nun auf " + message + " gestellt");
            if (myState=="ON")
            {
                llSetTimerEvent(danceTimer);
                nextDance();
            }
            showMenu(toucher);
        }

        else if (message == "Debugmode") { debug = !debug; llInstantMessage(toucher,"Debugmodus [1 an / 0 aus] = "+(string)debug);}
    }
   
   
    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(); }
        else llSetTimerEvent(0.0);
    }
}


Weiterhin viel Spaß


Tron
Zitieren


Nachrichten in diesem Thema
UPDATE Paramour Line Dancer Script für Opensim in OSSL Regionen mit NPC Unterstützung - von Tron Mcp - 30.10.2023, 20:29

Gehe zu:


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