Author: ericksoa
Author Website: n/a
Script Name: Barmaid 3
Description: Makes a barmaid go to all the NPCs in a given range of metres and forces them to have a beer.  This is a starting point, and a demonstration of state based processing for NPCs. You probably only need 1 or 2 of these in a room to really bog down processing, so be gentle with it.
Instructions on Use: This goes in the OnUserDefined of any NPC called BARMAID. You need waypoints labeled WP_BARMAID_BAR (for where the bar is) and WP_BARMAID_STA (for where she goes between customers).

She will visit only NPCs. Send a 2005 event at the end of any conversation (both aborted and not aborted) to make her activities survive interruption. Those are not included, but you can probably figure those out on your own.

Script 1 (OnUserDefined):

void main()

{

    // You need these outside the nEvent switch

    // So you can use the varnames in other signal events

    int STATUS_READY =10;

    int STATUS_BUSY=20; // do nothing-she's busy with actions

    int STATUS_FINISHED=30;

    int STAGE_AQUIRE =10; //case doesn't use vars

    int STAGE_GETORDER =20; //but put these here to

    int STAGE_WALKBAR =30; //remind you which values

    int STAGE_GETDRINK =40; //mean what

    int STAGE_DELIVERDRINK =50;

    int STAGE_GOSTATION =60;

    float BARMAID_DISTANCE_THRESHOLD=1000.0; //set this to the range you want the barmaid to work

    int nEvent=GetUserDefinedEventNumber();

    switch (nEvent)

    {

        case 2005:

            SetLocalInt(OBJECT_SELF,"MAID_STATUS",STATUS_READY);

            break;

        case 1001: // heartbeats

            int nStatus=GetLocalInt(OBJECT_SELF,"MAID_STATUS");

            int nStage=GetLocalInt(OBJECT_SELF,"MAID_STAGE");

            int iAquired = FALSE; //default, perhaps there is nobody to aquire

            //object oTarget=GetLocalObject(OBJECT_SELF,"MAID_TARGET");

            //  int STAGE_AQUIRE =10; case doesn't use vars

            //  int STAGE_GETORDER =20; but put these here to

            //  int STAGE_WALKBAR =30; remind you which values

            //  int STAGE_GETDRINK =40; mean what

            //  int STAGE_DELIVERDRINK =50;

            //  int STAGE_GOSTATION =60;

            if (nStatus==0) // Just started new module

            {

                nStatus=STATUS_READY;

                SetLocalInt(OBJECT_SELF,"MAID_STAGE",nStatus);

                nStage=STAGE_AQUIRE;

                SetLocalInt(OBJECT_SELF,"MAID_STAGE",nStage);

            }

            switch(nStage)

            {

                case 10: // STAGE_AQUIRE

                    if (nStatus==STATUS_READY)

                    {

                        SetLocalInt(OBJECT_SELF,"MAID_STATUS",STATUS_BUSY);

                        int iNth = GetLocalInt(OBJECT_SELF, "NTH_PATRON");

                        iNth++;

                        //object oTarget = GetNearestCreature(CREATURE_TYPE_IS_ALIVE, TRUE, OBJECT_SELF, iNth);

                        object oTarget = GetNearestCreature(CREATURE_TYPE_PLAYER_CHAR, PLAYER_CHAR_NOT_PC, OBJECT_SELF, iNth);

                        SpeakString("I am looking for the " + IntToString(iNth) + " potential customer");

                        if (GetStringLeft(GetTag(oTarget), 7) == "BARMAID")

                        {

                            SpeakString("arrgh, cant serve to miself");

                            //do not take orders from other barmaids

                            iNth++;

                            oTarget = GetNearestCreature(CREATURE_TYPE_IS_ALIVE, TRUE, OBJECT_SELF, iNth);

                        }

                        //other cases like this (e.g. dont serve to the inkeep, etc.) are possible...

                        //left out for simplicity the first time around

                        if (GetIsObjectValid(oTarget))

                        {

                            SpeakString("Master, object is valid");

                        }

                        else

                        {

                            SpeakString("Master, nearest object is not valid in my view");

                         }

                        if (GetIsObjectValid(oTarget) && (GetDistanceToObject(oTarget) <= BARMAID_DISTANCE_THRESHOLD))

                        {

                            SpeakString("Ahh, found a customer, the " + IntToString(iNth) + "th one");

                            iAquired = TRUE;

                            SetLocalObject(OBJECT_SELF,"MAID_TARGET",oTarget);

                            SetLocalInt(OBJECT_SELF, "NTH_PATRON", iNth);

                            ActionMoveToObject(oTarget);

                        }

                        else

                        {

                            //try setting iNth back to 1, cycling

                            SpeakString("Starting from the beginning");

                            iNth = 1;

                            oTarget = GetNearestCreature(CREATURE_TYPE_IS_ALIVE, TRUE, OBJECT_SELF, iNth);

                            if (GetIsObjectValid(oTarget) && (GetDistanceToObject(oTarget) <= BARMAID_DISTANCE_THRESHOLD))

                            {

                                //special case, we have cycled through all patrons

                                iAquired = TRUE;

                                SetLocalObject(OBJECT_SELF,"MAID_TARGET",oTarget);

                                SetLocalInt(OBJECT_SELF, "NTH_PATRON", iNth);

                                ActionMoveToObject(oTarget);

                            }

                            else

                            {

                                //Ok, so there is nobody here :)   

                                SpeakString("Beer here...  beer here...");

                                SetLocalInt(OBJECT_SELF, "NTH_PATRON", 0);

                            }

                        }

                        if (iAquired)

                            // we can move to finished and start serving someone only if there is

                            // someone to serve

                            ActionDoCommand(SetLocalInt(OBJECT_SELF,"MAID_STATUS",STATUS_FINISHED));

                        else

                            //otherwise, reset to ready and try again in 6 seconds

                            ActionDoCommand(SetLocalInt(OBJECT_SELF,"MAID_STATUS",STATUS_READY));

                    }

                    if (nStatus==STATUS_FINISHED)

                    {

                        SetLocalInt(OBJECT_SELF,"MAID_STATUS",STATUS_READY);

                        SetLocalInt(OBJECT_SELF,"MAID_STAGE",STAGE_GETORDER);

                    }

                    break;

                case 20: // STAGE_GETORDER

                    if (nStatus==STATUS_READY)

                    {

                        SetLocalInt(OBJECT_SELF,"MAID_STATUS",STATUS_BUSY);

                        object oTarget = GetLocalObject(OBJECT_SELF, "MAID_TARGET");

                        //do your animations etc

                        ActionDoCommand(SpeakString("We only serve beer here... deal with it"));

                        ActionDoCommand(SetLocalInt(OBJECT_SELF,"MAID_STATUS",STATUS_FINISHED));

                    }

                    if (nStatus==STATUS_FINISHED)

                    {

                        SetLocalInt(OBJECT_SELF,"MAID_STATUS",STATUS_READY);

                        SetLocalInt(OBJECT_SELF,"MAID_STAGE",STAGE_WALKBAR);

                    }

                    break;

                case 30: // STATE WALKBAR

                    if (nStatus==STATUS_READY)

                    {

                        SetLocalInt(OBJECT_SELF,"MAID_STATUS",STATUS_BUSY);

                        //Get a Waypoint for going to the bar, or if "object invalid", say that there is no bar, and that

                        //  perhaps the owner of the place should buy one

                        //if you make your bar waypoint in the manner of WP_<your waitresstag>_BAR you are in good shape

                        object oBarWP = GetObjectByTag("WP_" + GetTag(OBJECT_SELF) + "_BAR");

                        if (GetIsObjectValid(oBarWP)==FALSE)

                        {

                            ActionDoCommand(SpeakString("Perhaps the owner should buy a bar for this inn... and tag it WP_" + GetTag(OBJECT_SELF) + "_BAR"));

                        }

                        else

                        {

                            ActionMoveToObject(oBarWP);

                            ActionDoCommand(SetLocalInt(OBJECT_SELF,"MAID_STATUS",STATUS_FINISHED));

                        }

                    }

                    if (nStatus==STATUS_FINISHED)

                    {

                        SetLocalInt(OBJECT_SELF,"MAID_STATUS",STATUS_READY);

                        SetLocalInt(OBJECT_SELF,"MAID_STAGE",STAGE_GETDRINK);

                    }

                    break;

                case 40: //STAGE_GETDRINK

                    if (nStatus==STATUS_READY)

                    {

                        SetLocalInt(OBJECT_SELF,"MAID_STATUS",STATUS_BUSY);

                        object oTarget = GetLocalObject(OBJECT_SELF, "MAID_TARGET");

                        //do your animations etc

                        //at some point, this should do something like say "give me a <what they ordered>"

                        ActionDoCommand(SpeakString("Gimme a beer, bartender (or not)"));

                        ActionDoCommand(SetLocalInt(OBJECT_SELF,"MAID_STATUS",STATUS_FINISHED));

                    }

                    if (nStatus==STATUS_FINISHED)

                    {

                        SetLocalInt(OBJECT_SELF,"MAID_STATUS",STATUS_READY);

                        SetLocalInt(OBJECT_SELF,"MAID_STAGE",STAGE_DELIVERDRINK);

                    }

                    break;

                case 50: //STAGE_DELIVER_DRINK

                    if (nStatus==STATUS_READY)

                    {

                        SetLocalInt(OBJECT_SELF,"MAID_STATUS",STATUS_BUSY);

                        object oTarget = GetLocalObject(OBJECT_SELF, "MAID_TARGET");

                        ActionMoveToObject(oTarget);

                        // update to actually base the selection on what was selected...

                        ActionDoCommand(SpeakString("Here's your beer."));

                        ActionDoCommand(SetLocalInt(OBJECT_SELF,"MAID_STATUS",STATUS_FINISHED));

                    }

                    if (nStatus==STATUS_FINISHED)

                    {

                        SetLocalInt(OBJECT_SELF,"MAID_STATUS",STATUS_READY);

                        SetLocalInt(OBJECT_SELF,"MAID_STAGE",STAGE_GOSTATION);

                    }

                    break;

                case 60: //STAGE_GO_STATION

                    if (nStatus==STATUS_READY)

                    {

                        //Get a Waypoint for going to the station, or if "object invalid", say that there is no station, and that

                        //  perhaps the owner of the place should set one

                        //if you make your station waypoint in the manner of WP_<your waitresstag>_STA you are in good shape

                        object oStaWP = GetObjectByTag("WP_" + GetTag(OBJECT_SELF) + "_STA");

                        SetLocalInt(OBJECT_SELF,"MAID_STATUS",STATUS_BUSY);

                        if (GetIsObjectValid(oStaWP)==FALSE)

                        {

                            ActionDoCommand(SpeakString("Perhaps the owner should give me a station in this inn... and tag it WP_" + GetTag(OBJECT_SELF) + "_STA"));

                        }

                        else

                        {

                            ActionMoveToObject(oStaWP);

                            ActionDoCommand(SetLocalInt(OBJECT_SELF,"MAID_STATUS",STATUS_FINISHED));

                        }

                    }

                    if (nStatus==STATUS_FINISHED)

                    {

                        SetLocalInt(OBJECT_SELF,"MAID_STATUS",STATUS_READY);

                        SetLocalInt(OBJECT_SELF,"MAID_STAGE",STAGE_AQUIRE);

                    }

                    break;

        }

        break;

   }

}

Script 2 (OnSpawn):

//::///////////////////////////////////////////////

//:: Default: On Spawn In

//:: NW_C2_DEFAULT9

//:: Copyright (c) 2001 Bioware Corp.

//:://////////////////////////////////////////////

/*

    Determines the course of action to be taken

    after having just been spawned in

*/

//:://////////////////////////////////////////////

//:: Created By: Preston Watamaniuk

//:: Created On: Oct 25, 2001

//:://////////////////////////////////////////////

#include "NW_O2_CONINCLUDE"

#include "NW_I0_GENERIC"

void main()

{

// OPTIONAL BEHAVIORS (Comment In or Out to Activate ) ****************************************************************************

     //SetSpawnInCondition(NW_FLAG_SPECIAL_CONVERSATION);

     //SetSpawnInCondition(NW_FLAG_SPECIAL_COMBAT_CONVERSATION);

                // This causes the creature to say a special greeting in their conversation file

                // upon Perceiving the player. Attach the [NW_D2_GenCheck.nss] script to the desired

                // greeting in order to designate it. As the creature is actually saying this to

                // himself, don't attach any player responses to the greeting.

     //SetSpawnInCondition(NW_FLAG_SHOUT_ATTACK_MY_TARGET);

                // This will set the listening pattern on the NPC to attack when allies call

     //SetSpawnInCondition(NW_FLAG_STEALTH);

                // If the NPC has stealth and they are a rogue go into stealth mode

     //SetSpawnInCondition(NW_FLAG_SEARCH);

                // If the NPC has Search go into Search Mode

     //SetSpawnInCondition(NW_FLAG_SET_WARNINGS);

                // This will set the NPC to give a warning to non-enemies before attacking

     //SetSpawnInCondition(NW_FLAG_SLEEP);

                //Creatures that spawn in during the night will be asleep.

     //SetSpawnInCondition(NW_FLAG_DAY_NIGHT_POSTING);

     //SetSpawnInCondition(NW_FLAG_APPEAR_SPAWN_IN_ANIMATION);

     //SetSpawnInCondition(NW_FLAG_IMMOBILE_AMBIENT_ANIMATIONS);

     //SetSpawnInCondition(NW_FLAG_AMBIENT_ANIMATIONS);

                //This will play Ambient Animations until the NPC sees an enemy or is cleared.

                //NOTE that these animations will play automatically for Encounter Creatures.

    // NOTE: ONLY ONE OF THE FOLOOWING ESCAPE COMMANDS SHOULD EVER BE ACTIVATED AT ANY ONE TIME.

    //SetSpawnInCondition(NW_FLAG_ESCAPE_RETURN);    // OPTIONAL BEHAVIOR (Flee to a way point and return a short time later.)

    //SetSpawnInCondition(NW_FLAG_ESCAPE_LEAVE);     // OPTIONAL BEHAVIOR (Flee to a way point and do not return.)

    //SetSpawnInCondition(NW_FLAG_TELEPORT_LEAVE);   // OPTIONAL BEHAVIOR (Teleport to safety and do not return.)

    //SetSpawnInCondition(NW_FLAG_TELEPORT_RETURN);  // OPTIONAL BEHAVIOR (Teleport to safety and return a short time later.)

// CUSTOM USER DEFINED EVENTS

/*

    The following settings will allow the user to fire one of the blank user defined events in the NW_D2_DefaultD.  Like the

    On Spawn In script this script is meant to be customized by the end user to allow for unique behaviors.  The user defined

    events user 1000 - 1010

*/

    SetSpawnInCondition(NW_FLAG_HEARTBEAT_EVENT);        //OPTIONAL BEHAVIOR - Fire User Defined Event 1001

    //SetSpawnInCondition(NW_FLAG_PERCIEVE_EVENT);         //OPTIONAL BEHAVIOR - Fire User Defined Event 1002

    //SetSpawnInCondition(NW_FLAG_ATTACK_EVENT);           //OPTIONAL BEHAVIOR - Fire User Defined Event 1005

    //SetSpawnInCondition(NW_FLAG_DAMAGED_EVENT);          //OPTIONAL BEHAVIOR - Fire User Defined Event 1006

    //SetSpawnInCondition(NW_FLAG_DISTURBED_EVENT);        //OPTIONAL BEHAVIOR - Fire User Defined Event 1008

    //SetSpawnInCondition(NW_FLAG_END_COMBAT_ROUND_EVENT); //OPTIONAL BEHAVIOR - Fire User Defined Event 1003

    //SetSpawnInCondition(NW_FLAG_ON_DIALOGUE_EVENT);      //OPTIONAL BEHAVIOR - Fire User Defined Event 1004

    //SetSpawnInCondition(NW_FLAG_DEATH_EVENT);            //OPTIONAL BEHAVIOR - Fire User Defined Event 1007

    SetSpawnInCondition(2005); // for "barmaid is ready" event after some *** bothers her.

// DEFAULT GENERIC BEHAVIOR (DO NOT TOUCH) *****************************************************************************************

    SetListeningPatterns();    // Goes through and sets up which shouts the NPC will listen to.

    WalkWayPoints();           // Optional Parameter: void WalkWayPoints(int nRun = FALSE, float fPause = 1.0)

                               // 1. Looks to see if any Way Points in the module have the tag "WP_" + NPC TAG + "_0X", if so walk them

                               // 2. If the tag of the Way Point is "POST_" + NPC TAG the creature will return this way point after

                               //    combat.

    GenerateNPCTreasure();     //* Use this to create a small amount of treasure on the creature

}