Linden text version 2
{
LLEmbeddedItems version 1
{
count 0
}
Text length 11503
OHN'S BASIC ACTION NPC - INSTRUCTION CARD 

The basic Action NPC prim includes everything required to demonstrate the capabilities of 
the script: an action card that defines things for the NPC to do, an objects2Rez 
card to rez seats at particular locations for the NPC to sit on, the objects to be rezzed, 
the animations for the NPC to be animated with, and an appearance card 
that creates the NPC to look like the Farmer boy from the Linda Kellie 
freebie mall. The NPC's default name is Moving Man.

!!!BEFORE you touch the NPC prim to try it out, you will probably want to edit vectors
in the configuration notecards to make sure the default location vectors won't cause the
NPC to get stuck behind/between/inside/under obstacles in your world. 
See MINIMUM STEPS TO TRY OUT DEFAULT NPC.

At this time (January 2013) in OpenSim, NPCs (as far as I know) only operate in the region 
they are rezzed in. And, I think they are still restricted to the root region in a mega region world.

WHAT THE BASIC ACTION NPC PRIM AND ITS CONTENTS DO
You can configure the NPC prim to rez objects for the NPC to sit on. And you can configure 
the NPC prim to cause the NPC to take actions, such as move, talk, animate, sit on an object. 
See the COMMAND INFO and REZ SEATS section below for more information.

The NPC prim comes with an appearance card already configured, but you can easily change 
that. See CHANGE NPC APPEARANCE. 

MINIMUM STEPS TO TRY OUT DEFAULT NPC
1. Open the actionCard and the objects2Rez notecards. 

2. Note that vectors in the objects2Rez notecard correspond to GOTO vectors in the actionCard
    notecard. 
    a. Make sure the GOTO vectors define a clear path.
    b. If you change a GOTO vector in the actionCard notecard, IF there is a corresponding 
        vector in the objects2Rez notecard, change that vector to be the same as the GOTO vector.
        (not required really, but the NPC actions will look a little more natural). 
3.    Leave everything else the same for the try-out. Save and close the notecards.

4. Touch the NPC prim. The objects should rez, then the NPC should rez. After a moment or two, 
    the NPC will begin cycling through the actions in the notecard. Once it goes through all the 
    actions, the NPC starts over. 
    
5. When you get bored watching that routine touch the prim again to remove the NPC. If it doesn't 
    remove the NPC after a couple of seconds, touch the prim again. I have a handy Remove ALL NPCs prim
    that is useful when I am experimenting with NPC scripts. If you are modifying the script and experimenting, 
    if you reset the script before you remove the NPC, it can be hard to get rid of. The Remove ALL NPCs prim
    should be available right next to the Action NPC prim on my freebie region.
    
Once the NPC is set up, and you rez it that first time, If you leave the region, and the region shuts down, 
when the region later restarts, the NPC will rez automatically.

CHANGE NPC APPEARANCE
The appearance of the NPC is configured by an npc_appearance notecard, IF present. If the card is not 
present, the appearance of the NPC will be that of the owner at the time the owner touches the NPC prim.

So, to change how the NPC looks, delete the default npc_appearance card from the prim. Get dressed up
in the skin, shape, clothes, and attachments that you want your NPC to have. Touch the prim. Voila, 
the NPC will look the way you do.

CHANGE NPC NAME
The NPC's first and last names are set inside the script, toward the top of the script. Under the comment
"//change these values as you wish" you will see the following two lines:
    string firstName = "Moving";//npc first name, change as you wish
    string lastName = "Man";//npc last name, change as you wish

Change the values between quotation markes in those two lines. Change "Moving" to the first name you want, 
and change "Man" to the last name you want.

REZ SEATS
In the COMMAND INFO section, you can see that the NPC can be told to sit on objects that the NPC prim rezzed.
Those objects have to be configured in the objects2rez notecard. In its original form, my NPC prim has 
that notecard configured with three objects, seat 1, seat 2, seat 3. The notecard defines the position 
vector where each of those objects are rezzed. Those position vectors (in my default setup) correspond
to position vectors in a few of the GOTO commands in the action card, so that the NPC moves to a 
particular location (GOTO) and the sits on an object I rezzed there (SIT). 
So, keep in mind, for example, if your 15th line in the action card is a GOTO===<128.0,142.0,29.6>
and the 16th line is a SIT===0, and the 0 line (first line) in your objects2rez notecard is 
crazy seat===<252.0, 222.0,29.6>, your NPC will look like it just disappeared from <128.0,142.0,29.6>
and reappeared to sit on the crazy seat object at <252.0, 222.0,29.6>. If intended, cool. If not, awkward ;)

COMMAND INFO (and actionCard note card)
The action card contains command/value pairs, such as GOTO with a vector value to move the npc to 
a particular location. 

The first command MUST be GOTO with a vector value that is to be the NPC's
home position. 

Command and value are separated by 3 equal signs "===". The following 
are the commands, purpose and their value types:
    GOTO: move the NPC to a location, vector value
    ANIMATE: animate the NPC, string value, name of animation in npc prim
    STOPANIMATE: stop animating the NPC, string value, name of animation in npc prim
    PAUSE: do nothing for a period of time, float value, number of seconds. This is 
            useful if you want the NPC to continue an animation or continue to sit for a while.
            It is also useful after giving the TALK command, to give people time to read what the 
            NPC said.
    TALK: get the NPC to say something, string value, text for NPC to say. 
            (tip: there are also ossl functions for an NPC to shout and whisper, and to talk on 
                a particular channel.)
    SIT: get the NPC to sit on one of the rezzed items, integer value, the notecard line number beginning
            with 0 (zero) in the objects2rez notecard
    STAND: get the NPC to stand, string value (not used right now, i just set it to "NOW"), use after a 
            SIT command before getting the NPC to move somewhere else.


SOME INFO ABOUT THE SCRIPT AND HOW IT WORKS
--Managed by states---
This script uses states to manage the different types of actions, such as moving, pausing, animating, etc.
The default state is only used to set stuff up at the very beginning, once you have configured
any objects you want rezzed for the npc to sit on, and configured the actions in the actionCard. 

The default state is where the NPC is first created by the owner touching the prim. 
As soon as that happens, the script transitions to the NPCidle state, and from there, 
cycles through the actions in the actionCard. 

Each type of action (move, pause, sit, stand, say, etc.) is managed by a state.
E.g. moving is managed in the NPCgoto state. Once an action is complete, the script 
transitions back to NPCidle to figure out what to do next.

That should make it easy to use this script to make far, far fancier scripts ;)

For example, you could add an NPCtouch state to make the NPC touch scripted items.
OR you could add an NPCinteract state and make the NPC interact with avs, like Q&A stuff.

===========
--Adding a new state for a new action type--
Adding a new state, involves (1)adding the new state AND adding support for it in NPCidle.
Triggering the new state is done using a command for it in the action notecard. 
Within the script, the command name is contained in the curActionCmd variable and the command value 
is contained in the curActionValue variable. Both are strings, though you can cast the command 
value to whatever you like (take a look at other states for examples).

FIRST:
Use the following as a template for your new state (change NPCnewsTate to a friendly state name), 
replacing [do stuff here] with your custom scripts. Keep the rest of the stuff in the timer, 
touch_end, and changed events, UNLESS you are experienced and really intend for things to happen
differently.  

state NPCnewstate
{
    state_entry()
    {
        llSetTimerEvent(0);//cancels any existing timers set in other states

        [DO STUFF HERE]
        
        llSetTimerEvent(0.1);//triggers the timer event

    }
    timer()
    {
        updateLastAction();//increments/resets the count of last action taken
        state NPCidle;//transitions to NPCidle to figure out what to do next
    }
    touch_end(integer number)
    {
        removeNpc(llDetectedKey(0), npcKey);//when in a state other than default, deletes NPC
        state default;//transitions to the default state
    
    }//end touch end
    changed(integer mask)
    {   
        if(mask & CHANGED_OWNER)
        {
            llResetScript();//resets script when owner changes
        }
        if(mask & CHANGED_REGION_START) {
            createNpc(ownerKey);//automatically creates the NPC again on region restart
            state NPCidle;//transitions to the NPCidle state to figure out what to do next

        }

    }//end changed

}

NEXT:
Once you have added your new fancy state, you need to support it in the NPCidle state.
Inside that state, scroll down to just above the final "else" statement, and add a new "else if"
statement. In the example below, you would replace "NEWCOMMAND" with the command that will be 
used to trigger transition to your new state (used in the action notecard), replace 
"NPCnewstate" with the name of your new state, and IF applicable, replace the bracketed 
text with script you want to happen prior to transitioning to your new state.

        else if(curActionCmd == "NEWCOMMAND") {
            [ DO STUFF HERE ]
            state NPCnewstate;

        }

With those two steps completed, you will just need to use the command in the action card.

===========
--Debugging chat to owner--
By now you may have already noticed that there is the following line toward the top of the script:

integer debug = FALSE;

And, noticed that there are if(debug){ [DO SOMETHING] } script snippets throughout the script.

if you change that line to read:

integer debug = TRUE;

when you rez the NPC, you should be slammed by lots of messages that are telling you things that 
the script is doing. This is very useful while testing! Any chat commands you write that are solely for your 
debugging efforts should use the if(debug) convention. It is so easy to turn those chats off (change TRUE to FALSE) if
you do use it. If you don't use something like that, you have to comment out or remove each debugging chat
snippet.

===========
--leftover thoughts---
This script is written to handle only one action card, but it could easily be rewritten to cycle through many 
many action cards. Perhaps a notecard that lists the names of the action cards, a variable that identifies 
the current line number in that notecard and increments to cycle through the action card names. 

This script doesn't have any listens or sensors, and using the default notecards and 
npc appearance card, the NPC doesn't wear any special scripted items, but you could 
certainly do that.
Currently this script has a function to rez and position seats based on the objects2rez card.
You could customize the script to rez other objects, such as scripted objects for the npc to touch.}
 