Change font size
It is currently Wed Aug 15, 2018 1:17 pm

Forum rules


{L_IMAGE}



Post a new topicPost a reply Page 1 of 2   [ 17 posts ]
Go to page 1, 2  Next
Author Message
 Post subject: NPC Controller Script, IN PROGRESS
PostPosted: Wed Oct 12, 2011 2:38 am 
Furious Typer
User avatar

Joined: Mon Apr 25, 2011 6:48 pm
Posts: 186
Location: OSgrid, of course!
I've been playing with the new NPCs and WOW!!! Hacked a couple of scripts and have this work in progress. Hope you enjoy! Comments, criticisms, and shameless plugs are welcome. :geek:

I'll post the code that I have, as it's rather fun, if not incomplete. It is lifted from the OSSL same for osNPCCreate, Haplo's NPC path recorder, and code from the Pointing Your Nose thread. The listen channel is at the top of the script, for easy access.

I put little markers where my 'locations' were. I then used the recorder script to walk paths between these markers, creating named locations in the process.

You can chat CREATE, REMOVE, AUTOPILOT, and a few other commands.

The bot controller script is dependent on several things:

--Any animations referenced in the script should be included in the controlling prims' inventory.
--The 'config' and 'locations' notecards are user created and must also be in the prims' inventory. Samples below.
--The script depends on path files that are recorded with the lslNPCPathRecorder script, using the naming convention outlined within that script. These path files are essentially notecards that contain a list of vectors.

The 'config' notecard.
{L_CODE}:
## Bot Configuration File
##
##This file contains basic configuration information for your NPC bot, such as first and last name, home starting location, and the name of a notecard defining
##routes for paths.
##
##Comments are delineated by a '##' at the beginning of the line.  There should be no blank or empty lines.
##
##Further information may be added in the future.
##
##Each line contains one setting, in the format 'Property=Value'.  Example below:
##
##fname=John
##lname=Smith
##home=<0.0,0.0,0.0>
##locations=locations
##
fname=Jane
lname=Doe
home=<128, 128, 24>
locations=locations


The 'locations' notecard.
{L_CODE}:
##locations card
##
##This card contains a list of locations known to the bot.  Each line of this file contains a location, in ALL CAPS, and a list of 'exits' from that location.
##The 'exits' are names of notecards that contain a recorded path of vectors that the bot will follow, leading to another location.
##
## Comments are delineated with a double ##.  Blank lines are not allowed.
BAR,BarToCounter
COUNTER,CounterToBar,CounterToFloor
FLOOR,FloorToCounter,FloorToFrontDoor,FloorToTable1,FloorToTable2,FloorToTable3
FRONTDOOR,FrontDoorToFloor
TABLE1,Table1ToFloor,Table1ToTable2
TABLE2,Table2ToFloor,Table2ToTable1
TABLE3,Table3ToFloor


The lslNPCPathRecorder script.
{L_CODE}:
//This script was originally created by Haplo Voss of OSGRID.  I, Shad MOrdre, also of OSGRID
//have modified in the following way.  Haplo's original script simply created a file called Path1.
//This modification will take anything typed on chat channel 12 as the name of a notecard.  This
//notecard should be named something reasonable, like Location1ToLocation2, as the path recorded
//by this script is simply a path between two points.

vector path_pos;
string path_write;
default
{
   
    state_entry()
    {
        llListen(12,"",llGetOwner(),"");
        llOwnerSay("When done creating the path, just type a name on channel 12.");
        llOwnerSay("Shorter routes are better as they can be combined for longer routes, and mixed with animations.");
    }
    touch_start(integer n)
    {
        path_pos = llDetectedPos(0);
        path_write += (string)path_pos+"\n";
    }
    listen(integer channel, string name, key id, string msg)
    {
        if (msg != "")
        {
            osMakeNotecard(msg,path_write);
            llOwnerSay("Notecard Created");
            path_write = "";
        }
    }
}


And the lslNPCBotController script.
{L_CODE}:
integer BOTCHAN = 101;

key npc;
string scurloc;
string BOT_CONFIG = "config";
string keynote;
string movementanimation = "avatar_slowwalk";
string botfname;
string botlname;
vector bothome;
string locationsNoteCard;
list botlocations;

fncReadSettingsFromNotecard()
{
    integer notelength;
    integer idx;
    integer lineidx;
    string noteline;
    string settingname;
    string settingvalue;
   
    notelength = osGetNumberOfNotecardLines(BOT_CONFIG);
   
    for (idx=1; idx<=notelength; idx++)
    {
        noteline = osGetNotecardLine(BOT_CONFIG, idx);
        if (llStringLength(noteline) >= 0)
        {
            if (llGetSubString(noteline,0,1) != "##")
            {
                lineidx = llSubStringIndex(noteline,"=");
                settingname = llGetSubString(noteline,0,lineidx-1);
                settingvalue = llGetSubString(noteline,lineidx+1, -1);
               
                if (settingname == "fname")
                {
                    botfname = settingvalue;
                }
                else if (settingname == "lname")
                {
                    botlname = settingvalue;
                }
                else if (settingname == "home")
                {
                    bothome = (vector)settingvalue;
                }
                else if (settingname == "locations")
                {
                    locationsNoteCard = settingvalue;
                }
                else
                {
                    //Add functionality by creating a setting in the config file, and adding code as above.
                }
            }
        }
    }
}

fncGetLocationList()
{

        string noteline;
        integer notelength;
        integer lineidx;
        integer idx;

        noteline="";
        notelength = osGetNumberOfNotecardLines(locationsNoteCard);

        for(idx=1; idx<notelength; idx++)
        {
            noteline = osGetNotecardLine(locationsNoteCard, idx);
            if (llStringLength(noteline) >= 0)
            {
                if (llGetSubString(noteline,0,1) != "##")
                {
                    botlocations += noteline;
                }
                else
                {
                    //llOwnerSay("ERROR: locationsNoteCard '" + locationsNoteCard + "' is formatted incorrectly.");
                }
            }           
        }         
}

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

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

fncAvatarWalkPath(string notecard)
{
   
    //WALK PATH CODE
    vector curPos;
    vector vecTo_targ;
    vector nPos;
    list path;
    integer path_length;
    integer pad_Turn = 3; // Larger the number smoother the turn but less accurate
    //string notecard;      // Smaller the number more accurate but sharper noticeable stop/turn
   
    integer i;
    //notecard = "";          // Randomly chosen name of path vector notecard
       
    for(i=1; i<osGetNumberOfNotecardLines(notecard); i++)
    {
                    path += osGetNotecardLine(notecard, i);
    } // Grab path vectors from notecard and pack into list

    path_length=llGetListLength(path);

    integer x;
    for (x = 1; x < path_length; x++)
    {
        vecTo_targ = llList2Vector(path,x);
        nPos = osNpcGetPos(npc);       
        if (vecTo_targ.x > 1)
        {                           
               
            osAvatarPlayAnimation(npc,movementanimation);
            osNpcSetRot(npc, llRotBetween(<PI,PI,0>,llVecNorm(vecTo_targ - osNpcGetPos(npc))));
            osNpcMoveToTarget(npc, vecTo_targ, OS_NPC_NO_FLY);
           
            while (llFabs(llVecDist(vecTo_targ, nPos)) > pad_Turn)
            {
                    nPos = osNpcGetPos(npc);
                    llSleep(.5);
            } // Probably a lower lag way to do this with states or something
                // This also locks out the script until the loop is complete
                // Which I really really hate! :P
        }
        else
        {
                       
        }
    }
}

fncAutoPilot()
{
   
    //AUTOPILOT CODE
    string slocation;
    string spath;
    string listitem;
    string notecard;
    integer rnum;
    integer idx1;
    integer numberofexits;
    list locationexits;
    list tempexits;
    integer listlength;
    string currentloc;
               
    listlength=llGetListLength(botlocations);
               
    for (idx1=0; idx1<listlength; idx1++)
    {
        listitem = llList2String(botlocations,idx1);
        slocation = llToUpper(llGetSubString(listitem,0,llSubStringIndex(listitem,",")-1));
                   
        tempexits = llCSV2List(listitem);
       
        numberofexits = llGetListLength(tempexits)-1;
                   
        if (llToUpper(slocation) == llToUpper(scurloc))
        {
            locationexits=llList2List(tempexits,1,-1);

            idx1=listlength;
               
            listlength = llGetListLength(locationexits);
               
            if (listlength > 0)
            {
                rnum = fncRandIntBetween(1, listlength);
                       
                notecard = llList2String(tempexits,rnum);

                fncAvatarWalkPath(notecard);

                currentloc = llGetSubString(notecard, llSubStringIndex(notecard, "To")+2, -1);
                       
                scurloc = llToUpper(currentloc);

            }
        }
    }
   
}

default
{
    state_entry()
    {
       
        llListen(BOTCHAN,"",NULL_KEY,"");
        fncReadSettingsFromNotecard();
        fncGetLocationList();
       
    } 

    listen(integer channel, string name, key id, string msg)
    {
        if (msg != "")
        {
            if (msg == "create")
            {
                keynote = "key-AD__" + llGetTimestamp();
                osOwnerSaveAppearance("appearance-BOT");
                npc = osNpcCreate(botfname, botlname, bothome, "appearance-BOT");
                osMakeNotecard(keynote,(string)npc);
                scurloc = "COUNTER";
                llSleep(5);
                osNpcSay(npc, botfname + " " + botlname + ", at your service.  How may I help you.");
                osAvatarPlayAnimation(npc, "avatar_curtsy");
                llSleep(3);
                osAvatarStopAnimation(npc, "avatar_curtsy");
               
            }   
            else if (msg == "remove" && npc != NULL_KEY)
            {
                osNpcSay(npc, "You will pay for this with your liiiiiivvveeessss!!!.....");
                osNpcRemove (npc);
            }   
            else if (msg == "kill")
            {
                if (npc != NULL_KEY)
                {
                    osNpcSay(npc, "I will never forget that you tried to kill me!!!.....");
                    osNpcSay(npc, "You will pay for this with your life!!!.....");
                    osNpcSay(npc, "Just type 'remove' on channel 5 if you really want to get rid of me!!!");
                }
                else
                {
                    key deadnpc;
                    llOwnerSay((string)npc);
                    deadnpc = (key)osGetNotecardLine(keynote, 1);
                    llOwnerSay((string)deadnpc);
                    osNpcRemove (deadnpc);
                }
            }
            else if (msg == "killbots")
            {
                list avatars = llList2ListStrided(osGetAvatarList(), 0, -1, 3);
                integer i;
                llSay(0,"NPC Removal: No avatars will be harmed or removed in this process!");
                for (i=0; i<llGetListLength(avatars); i++)
                {
                    string target = llList2String(avatars, i);
                    osNpcRemove(target);
                    llSay(0,"NPC Removal: Target "+target);
                }
            }
            else if (msg == "say" && npc != NULL_KEY)
            {
                osNpcSay(npc, "I am your worst Nightmare!!!!");
            }   
            else if (msg == "move" && npc != NULL_KEY)
            {
                osNpcMoveTo(npc, llGetPos() + <9,9,0>);
            }   
            else if (msg == "autopilot" && npc != NULL_KEY)
            {
               
                fncAutoPilot();
               
            }
            else if (msg == "movetarget" && npc != NULL_KEY)
            {
                osNpcMoveToTarget(npc, llGetPos() + <9,9,5>, OS_NPC_FLY|OS_NPC_LAND_AT_TARGET);
            }
            else if (msg == "movetargetnoland" && npc != NULL_KEY)
            {
                osNpcMoveToTarget(npc, llGetPos() + <9,9,5>, OS_NPC_FLY);
            }           
            else if (msg == "movetargetwalk" && npc != NULL_KEY)
            {
                osNpcMoveToTarget(npc, llGetPos() + <9,9,0>, OS_NPC_NO_FLY);               
            }
            else if (msg == "rot" && npc != NULL_KEY)
            {
                vector xyz_angles = <0,0,45>; // This is to define a 45 degree change
                vector angles_in_radians = xyz_angles * DEG_TO_RAD; // Change to Radians
                rotation rot_xyzq = llEuler2Rot(angles_in_radians); // Change to a Rotation               
                rotation rot = osNpcGetRot(npc);
                osNpcSetRot(npc, rot * rot_xyzq);
            }
            else if (msg == "animate" && npc != NULL_KEY)
            {
                osAvatarPlayAnimation(npc, "avatar_nyanya");
                llSleep(3);
                osAvatarStopAnimation(npc, "avatar_nyanya");
            }   
            else if (msg == "load OWNER" && npc != NULL_KEY)
            {
                osNpcLoadAppearance(npc, "appearance-OWNER");
            }
            else if (msg == "load BOT" && npc != NULL_KEY)
            {
                osNpcLoadAppearance(npc, "appearance-BOT");
            }
            else if (msg == "clone")
            {
                osOwnerSaveAppearance("appearance-OWNER");
            }
            else if (msg == "stop" && npc != NULL_KEY)
            {
                osNpcStopMoveToTarget(npc);
            }
            else
            {
                llOwnerSay("I don't understand [" + msg + "]");
            }
        }   
    }   
}


Last edited by Shad MOrdre on Sat Oct 15, 2011 1:18 am, edited 1 time in total.

Top
 Profile  
 
 Post subject: Re: NPC Controller Script, IN PROGRESS
PostPosted: Wed Oct 12, 2011 6:01 pm 

Joined: Sat Jul 24, 2010 5:07 pm
Posts: 20
I wonder why you have the script complain about blank lines in the notecard. Why not simply silently discard them and move on to the next line?


Top
 Profile  
 
 Post subject: Re: NPC Controller Script, IN PROGRESS
PostPosted: Sat Oct 15, 2011 1:28 am 
Furious Typer
User avatar

Joined: Mon Apr 25, 2011 6:48 pm
Posts: 186
Location: OSgrid, of course!
Fritigern,

The code is a work in progress, and that was more for debug purposes. Thanks for pointing that out. I can imagine it's been annoying. I've edited those out.

Let me know how it's working. I'll try to keep updating what I'm coding. With a newborn, my time is very limited though.

As always, suggestions and comments are welcome.

Shad MOrdre


Top
 Profile  
 
 Post subject: Re: NPC Controller Script, IN PROGRESS
PostPosted: Mon Oct 17, 2011 10:12 pm 

Joined: Sat Jul 24, 2010 5:07 pm
Posts: 20
I too often use debug lines, though in most cases i take them out before making the code "official" as i call it.
In cases where i want to keep the debug code, set up a debug mode:

I first set a global:
{L_CODE}:
integer debug = true;


Then, suppose i want to know what the value a certain variable is, this could be the original line:
{L_CODE}:
llOwnerSay("Value of SomeVal is "+(string)SomeVal);

I will instead make the line conditional:
{L_CODE}:
if(debug) llOwnerSay("Value of SomeVal is "+(string)SomeVal);

..or, if there are more lines..
{L_CODE}:
if(debug) {
              llOwnerSay("Value of SomeVal is "+(string)SomeVal);
              llOwnerSay("Value of AnotherVal is "+(string)AnotherVal);
          }

This will allow me to only have debug messages to display if debug mode is explicitly enabled. If you set debug=FALSE; it behaves all stealthily :-)
It adds a little bit of code, but is oh so useful.


Top
 Profile  
 
 Post subject: Re: NPC Controller Script, IN PROGRESS
PostPosted: Wed Oct 19, 2011 12:49 pm 
Furious Typer
User avatar

Joined: Mon Apr 25, 2011 6:48 pm
Posts: 186
Location: OSgrid, of course!
Thanks for sharing that Fritigern, I'll use that scheme as I progress.

Please keep in mind, nothing is official yet, as this is a work in progress.

As again, comments, suggestions, and shameless plugs are welcome.


Top
 Profile  
 
 Post subject: Re: NPC Controller Script, IN PROGRESS
PostPosted: Mon Oct 24, 2011 2:06 pm 

Joined: Thu Dec 10, 2009 4:28 am
Posts: 3
how do you sit a clone? is it possible?
how to loop an animation? in the opensim example it is set to do it twice...I would like to set a "switcher"
do clones die when opensim console is shutdown? how to make them a permanent part of the sim?

else if (msg == "animate" && npc != NULL_KEY)
{
osAvatarPlayAnimation(npc, "stabbed+die_2");
llSleep(3);
osAvatarStopAnimation(npc, "stabbed+die_2");

good job for the pathfinder clone! keep improving it.


Top
 Profile  
 
 Post subject: Re: NPC Controller Script, IN PROGRESS
PostPosted: Mon Oct 24, 2011 7:36 pm 
OSG Elite
User avatar

Joined: Sat Jun 14, 2008 12:28 am
Posts: 384
Location: Australia
To opensimmer linuxplorer,
I havent yet played with NPCs but I can extrapolate the following
{L_QUOTE}:
how do you sit a clone? is it possible?
I would assume you can use your choice of sit animations.
{L_QUOTE}:
how to loop an animation? in the opensim example it is set to do it twice..
{L_QUOTE}:
osAvatarPlayAnimation(npc, "stabbed+die_2");
llSleep(3);
osAvatarStopAnimation(npc, "stabbed+die_2");
note that here the anim is played once then stopped once. To loop the anim, I suggest remove the stop command and leave him in the last frame of the played anim.
{L_QUOTE}:
do clones die when opensim console is shutdown? how to make them a permanent part of the sim?
baring in mind that when the console is shut down, then the sim shuts down also, so naturally all action ceases.
Regards
Cam


Top
 Profile  
 
 Post subject: Re: NPC Controller Script, IN PROGRESS
PostPosted: Mon Oct 24, 2011 10:42 pm 
Site Admin

Joined: Sun Jul 04, 2010 8:20 pm
Posts: 474
Besides playing animations, you can use osNpcSit and osNpcStand.

{L_CODE}:
Format is osNpcSit(<npc-uuid>, <target-uuid>, OS_NPC_SIT_NOW)
e.g. osNpcSit(npc, llGetKey(), OS_NPC_SIT_NOW);
At the moment, sit only succeeds if the part has a sit target set.
NPC immediately sits on the target even if miles away - they do not walk up to it.
This method is in development - it may change so please don't trust it yet.


(I actually edited that... since OS_NPC_SIT_NOW used to be OS_NPC_SIT_IMMEDIATE)

{L_CODE}:
Implement osNpcStand(<npc-id>)

Allows you to stand an NPC that has sat.


this will work with any build on or after r/16919 (oct 17 2011)

dan


Top
 Profile  
 
 Post subject: Re: NPC Controller Script, IN PROGRESS
PostPosted: Tue Oct 25, 2011 6:08 am 

Joined: Sat Jul 24, 2010 5:07 pm
Posts: 20
Please note that osNpcSit and osNpcStand are currently still under development, and is NOT guaranteed to work!

See also http://opensimulator.org/wiki/OsNpcSit


Top
 Profile  
 
 Post subject: Re: NPC Controller Script, IN PROGRESS
PostPosted: Tue Oct 25, 2011 8:04 pm 
Site Admin

Joined: Sun Jul 04, 2010 8:20 pm
Posts: 474
fritigern, they maybe under development but they do work. I've been using the functions since the they were added :)

If there are any future changes to the syntax or the way they work I may end up having to edit my scripts but for the time being these functions do work.

dan


Top
 Profile  
 
Display posts from previous:  Sort by  
Post a new topicPost a reply Page 1 of 2   [ 17 posts ]
Go to page 1, 2  Next


Who is online

Users browsing this forum: No registered users and 5 guests


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Jump to:  


Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group
610nm Style by Daniel St. Jules of Gamexe.net