Themabewertung:
  • 0 Bewertung(en) - 0 im Durchschnitt
  • 1
  • 2
  • 3
  • 4
  • 5
Einfache, leicht erweiterbare NPC Steuerung
#4
Hier kommt Teil zwei vom NPC System. Die Checkpoints und der Schalter können bleiben wie sie sind. Hinzu kommt ein Shutdown resistenter NPC Rezzer
Er kopiert bei Aktivierung den Avatar zum NPC und schreibt die Daten in eine Notecard, die beim Regionsstart gelesen wird. Das Skript kommt in ein Gegenstand in der Region, welcher den NPC rezzen soll

Code:
// NPC Steuerungssystem
// MoniTill 4.14 V1
// Lizenz: Gemeinfrei (Public Domain)

// Script für Objekt welches den NPC rezzt



string vorname = "Fritze";
string nachname = "Flink";
vector posit = <1,0,0>;        //Position relativ vom NPC Rezz-Objekt
integer rezkanal = 3486;

integer npcon = FALSE;
key npc ;


default
{

  changed(integer change)
    {
       if (change & CHANGED_REGION_START)
       {
        npcon = FALSE;
        llResetScript();
        }
    }



state_entry() {

                
   string notecard = llGetInventoryName(INVENTORY_NOTECARD, 0);
   if (notecard != ""   && npcon == FALSE) {
      npc = osNpcCreate(vorname, nachname,llGetPos()+posit, "appearance");
      npcon = TRUE;
      }

                
                
   llListen(rezkanal, "", NULL_KEY, "");
                
}



listen(integer channel, string name, key id, string msg) {






if (llToLower(msg) == "npcstart" && llGetOwnerKey(id) == llGetOwner()&& npcon == FALSE) {
  osAgentSaveAppearance(llGetOwner(), "appearance");
npc = osNpcCreate(vorname, nachname,llGetPos()+posit, "appearance");
npcon = TRUE;
}

if (llToLower(msg) == "npckill" && llGetOwnerKey(id) == llGetOwner()) {  
  osNpcRemove(npc);
   llRemoveInventory("appearance");
npcon = FALSE;
}


if (llToLower(msg) == "npcsweiter" && npcon == FALSE) {
  
npc = osNpcCreate(vorname, nachname,llGetPos()+posit, "appearance");
npcon = TRUE;
}





if (llToLower(msg) == "npcsstop" ) {  
  osNpcRemove(npc);
  
npcon = FALSE;
}



}
}





Da man aber die Steuerung trägt, die ja mitkopiert werden soll, rennt man wie Hein Blöd von Checkpoint zu Checkpoint und hat kaum eine Chance den Rezzer zu starten. Deshalb läuft die Bedienung über Regionsay . Dafür steckt man das folgende Script in einen Würfel, den man sich ans HUD hängt.

Code:
// NPC Steuerungssystem
// MoniTill 4.14 V1
// Lizenz: Gemeinfrei (Public Domain)

// Script für HUD vom zukünftigen NPC, welches den Rezzer steuert.



integer rezkanal = 3486;

integer menu_handler;
integer menu_channel;
menu(key user,string title,list buttons)
{
    llListenRemove(menu_handler);
    menu_channel = (integer)(llFrand(999999.0) * -1);
    menu_handler = llListen(menu_channel,"","","");
    llDialog(user,title,buttons,menu_channel);
    llSetTimerEvent(30);
}






default
{
    state_entry()
    {
      
    }


  touch_start(integer total_number)
    {
//       llSay(0, "HUD 2");

            menu(llDetectedKey(0),"\nKommandos für NPC Rezzer\n",
            ["npcstart","npckill","npcsweiter","npcsstop"]);

                  
            


}
     listen(integer channel,string name,key id,string msg)
{
            
  if(msg != "") {   llRegionSay(rezkanal,msg);}    
  
    
      }    
    


}

Die Notcard bietet folgende Möglichkeiten:
npcstart Kopiert den Avatar und speichert seine Daten für einen Regions Neustart
npckill Entfernt den NPC und löscht die Daten. Beim Neustart der Region erscheint er dann nicht mehr

npcsstop Entfernt alle NPCs in der Region erhält aber ihre Daten.
npcsweiter Das Gegenstück ruft sie wieder herbei

Das ist praktisch für Wartungsarbeiten, oder auch für einen Sensor der die NPCs nur aktiviert wenn ein Ava erscheint. Der setzt dann auf dem gewählten Kanal einfach die beiden Befehle ab...

Und zum Schluss die neue NPC Steuerung, die man sich in ein Objekt am Körper packt.
Code:
// NPC Steuerungssystem
// MoniTill 9.13 V1.1
// Lizenz: Gemeinfrei (Public Domain)

// Script für Objekt am Avatar/NPC
// V1.1:  Erweitert um Hook u. Aktions-Checkpoint



key zielchkp = "36b14c59-9b4d-4653-9d2b-995d66109eae"; // Den ersten Checkpoint nach dem Rezzen ansteuern
//  Diese Zeile muss angepasst werden. Der Rest nur bei Bedarf


integer NPCkanal = 15432; // Der Kanal für das System
integer hookKanaldesNPC =16001;

vector ziel;
vector altziel;
float maxZeit = 60 ; //Wenn in 60 Sek. noch nicht am Ziel, wird er wohl aufgehalten, also Teleport und fertig^^
float startzeit;
integer fragenzaehler;  // Wenn er zurück soll, fragt er mehrmals (5x) nach.
                            // Falls dann immer noch der alte Checkpoint kommt,
                            // steckt er wohl in einer Sackgasse u. muss wirklich zurück


integer flag;
integer warteFlag = TRUE;
integer aktionsFlag;
integer aktionsZeit;


integer randInt(integer n)
{
      return (integer)llFrand(n + 1);
}

integer randIntBetween(integer min, integer max)
{
      return min + randInt(max - min);
}



default
{


on_rez(integer p)
    {
        llResetScript();
    }




state_entry()
    {


        llSetStatus(STATUS_PHYSICS, TRUE);
      
        llSleep(10);
    llResetTime();
        list checkpointPOSstr = llGetObjectDetails(zielchkp,[OBJECT_POS]);
    ziel = llList2Vector(checkpointPOSstr,0);
  
  
    llSetTimerEvent(0.5);    
    llListen( NPCkanal, "", NULL_KEY, "" );
    llListen( hookKanaldesNPC, "", NULL_KEY, "" );
    }

    timer()
    {
    
    key  npc=llGetOwner();

    if (osIsNpc(npc) == TRUE)
    {

      if (warteFlag == TRUE)
      {
        //Wenn er als echter NPC unterwegs ist, gilt diese Zeile....
        osNpcMoveToTarget(npc,ziel, OS_NPC_NO_FLY) ;
      }
      else
      {
        osNpcStopMoveToTarget(npc);
      }
        
     }
        
     else
     {
       if (warteFlag == TRUE)
       {
          //..und beim Test mit Viewer gilt diese.
         llMoveToTarget(ziel,0.05);    
      
       }
       else
       {
          llStopMoveToTarget();
       }

     }  



    
    

    if (llVecDist(ziel,llGetPos()) < 1.5 && warteFlag == TRUE)
    {

    if (aktionsFlag == 1)
    {
    aktionsFlag =0;
llResetTime();
startzeit=llGetTime();
llSay (NPCkanal,"*aktionende*");
    
    }
    
    
    flag= 1;
        llWhisper(NPCkanal,"*ziel*");
        llResetTime();
        startzeit=llGetTime();
    }
  
  

  // Zu lange unterwegs od aufgehalten, dann teleportieren
  if (startzeit +maxZeit < llGetTime() && warteFlag == TRUE )
    {
        osTeleportOwner(ziel,ZERO_VECTOR);
        // Bei Verwendung in SL muss dieser Befehl ersetzt werden
    }
// Zeit für sit od. touch Aktion ist um. weiter gehts....
if (startzeit + aktionsZeit < llGetTime() && aktionsFlag == 1)
{

warteFlag = TRUE;


}    
    
    
    
    
    
    }

  
  
  
   listen( integer channel, string name, key id, string msg)  
   {  
      list checkpointPOSstr = llGetObjectDetails(id,[OBJECT_POS]);
      vector checkpointPOS = llList2Vector(checkpointPOSstr,0);
      float distanz = llVecDist(checkpointPOS,llGetPos());
key  npc=llGetOwner();
      
            if (flag == 0 && msg == "*warte*" && channel == hookKanaldesNPC )
            {
      warteFlag = FALSE;
      }
      
            if (flag == 0 && msg == "*weiter*" && channel == hookKanaldesNPC )
            {
      warteFlag = TRUE;
        llResetTime();
        startzeit=llGetTime();
      }
      
      
      if (flag == 1 && llGetSubString(msg, 0, 6)== "*nutze*" && distanz < 1.5)
      {
      warteFlag = FALSE;
aktionsFlag = 1;
      string xx =llGetSubString(msg, 7, -1);
       list paraliste = llParseString2List(xx,[","],[" "]);
key aktionsObjekt =(key)llList2String(paraliste,0) ;
string was =llList2String(paraliste,1) ;      
aktionsZeit  = randIntBetween((integer)llList2String(paraliste,2),(integer)llList2String(paraliste,3));

if (was="s" )
{
if (osIsNpc(npc) == TRUE)
{
osNpcSit(npc, aktionsObjekt, OS_NPC_SIT_NOW);
}
else
{
llOwnerSay("sit:"+aktionsObjekt+" Dauer in Sek. "+(string)aktionsZeit);
}

}
else
{
if (osIsNpc(npc) == TRUE)
{
osNpcTouch(npc, aktionsObjekt,  LINK_ROOT) ;
}
else
{
llOwnerSay("touch:"+aktionsObjekt+" Dauer in Sek. "+(string)aktionsZeit);
}



}




       }
    
    
      if (flag == 1 && llGetSubString(msg, 0, 5)== "*gehe*" && distanz < 1.5)
      {
        vector msgz =(vector)llGetSubString(msg, 6, -1);
  
        if (msgz != altziel  || fragenzaehler > 4 )
        {
            //llWhisper(0,(string)fragenzaehler + (string)ziel+ (string)altziel);
            altziel = ziel;
            ziel = msgz;
            flag= 0;


            fragenzaehler = 0;
        }
        else
        {
            fragenzaehler += 1;
        }
  
      }  
  
   }
}


Neu hinzugekommen ist ein Hook, an dem andere Scripte die Steuerung unbegrenzte Zeit unterbrechen können. Beispielsweise ein Chatscript, ein Follover oder eine Animation.... Sie setzten einfach auf dem Hookkanal (16001) „*warte*“ bzw. "*weiter*" ab.
Die andere Neuerung mit dem Aktions-Checkpoint, da soll der NPC an ausgesuchten Objekten Sit u. Touch Aktionen durchführen, läuft noch nicht richtig.

Wenn was klemmt oder unklar ist, bitte melden! Wink
Zitieren


Nachrichten in diesem Thema
RE: Einfache, leicht erweiterbare NPC Steuerung - von MoniTill - 09.04.2014, 18:51

Gehe zu:


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