Author Sticky: Post Working Scripts Here
ericksoa Posted: Tuesday, 16 July 12:59PM
NAME: Barmaid 1.1

USAGE: As described below. Make sure you have waypoints for "WP_<barmaidtag>_BAR" and "WP_<barmaidtag>_STA".

Use this on "onuserdefined":

NWScript:
//barmaid v1.1 - ericksoa, based on work by Rhodan.

//if you enhance this, and its useful, please post new version to nwn.bioware.com.  Thanx.

//also, it would be nice if you give credit to contributing authors as well :) 

//some behaviour consts

//drinking age switches

int NOMINORS_USE_DRINKING_AGE = FALSE;

int NOMINORS_DRINKING_AGE_HUMAN = 21;

int NOMINORS_DRINKING_AGE_ELF = 100;

int NOMINORS_DRINKING_AGE_HALFELF = 50;

int NOMINORS_DRINKING_AGE_GNOME = 50;

int NOMINORS_DRINKING_AGE_HALFLING = 50;

int NOMINORS_DRINKING_AGE_DWARF = 50;

int NOMINORS_DRINKING_AGE_HALFORC = 21;

string NOMINORS_GREETING = "Ah, what a cutie.  You know you are not old enough to drink the hard stuff now.";

//race service switches

int SERVE_HUMAN = TRUE;

int SERVE_ELF = TRUE;

int SERVE_HALFELF = TRUE;

int SERVE_GNOME = TRUE;

int SERVE_HALFLING = TRUE;

int SERVE_DWARF = TRUE;

int SERVE_HALFORC = FALSE;

string NO_SERVICE_RACE = "Sorry, this inn does not serve your race.  Begone!";

//reputation based service

int SERVE_ALL_REPUTATIONS = FALSE;

int REPUTATION_THRESHOLD = 30;

string NO_SERVICE_REPUTATION = "Please make yourself scarce.  You are not welcome here";

//sexual attraction switches

int WILL_FLIRT = TRUE; //determines whether barmaid/master will flirt w/customers

int ISA_HOMO = FALSE; //needs no explanation

int FLIRT_THRESHOLD1 = 15; //mild level flirting

int FLIRT_THRESHOLD2 = 18; //"wanna meet later tonight" - "meet me upstairs later" - "here's a key"

string FLIRT_HELLO1_1 = "Hello cutie :)   What can I do you for?";

string FLIRT_HELLO1_2 = "Nice to have you today.  Can I get you anything ::wink::?";

string FLIRT_HELLO1_3 = "It is my pleasure to serve you!  What would you like (besides me)?";

string FLIRT_HELLO2_1 = "Oh my god.  I have to say you are the best looking customer I have seen in these parts.  Your wish is my command.  ::whisper:: Meet me upstairs later... lets have some fun";

string FLIRT_HELLO2_2 = "I have a thing for people who look like you.  Lets meet tonight.  Can I get you a drink?";

string FLIRT_HELLO2_3 = ":::whisper::: for a good time, see me in my room tonight.  Can I get you anything?";

//repulsion switches

int WILL_BE_REPULSED = TRUE;

int REPULSION_THRESHOLD1 = 8; //ugh, can I get you a beer?

int REPULSION_THRESHOLD2 = 4; // ::barmaid throws up at the sight of you::

string REPULSED_1 = "Ugh, can I get you a drink?";

string REPULSED_2 = "Jeez, who hit you with the ugly wand.  I can see why you drink!  Let me help.";

//normal dialog

string GREETING_1 = "Is there anything I can get for you?";

string GREETING_2 = "How can I be of service?";

//available items

string ITEM1 = "Mosstone Ale";

string ITEM1_DESCRIPTION = "We have the local favorite, Mosstone Ale";

string ITEM1_TAG = "<custom item tag to be delivered>";

string ITEM2 = "Tethyrian Rum";

string ITEM2_DESCRIPTION = "If you can stand it, we also have Tethyrian Rum";

string ITEM2_TAG = "<custom item tag to be delivered>";

string ITEM3 = "Amnian Gin";

string ITEM3_DESCRIPTION = "And finally, we recommend the Amnian Gin if you are headed out adventuring";

string ITEM1_MINOR = "Milk";

string ITEM1_MINOR_DESCRIPTION = "For such a young adventurer, a nice glass of Milk";

string ITEM1_MINOR_TAG = "<custom item tag to be delivered>";

//function declarations

void main();

//object BarmaidAquireTarget(object oBarmaid, float fDistance=10.0);

//object BarmaidGetBar(object oBarmaid);

//object BarmaidGetStation(object oBarmaid);

string GetBarmaidsOrderQuery(object oBarmaid, object oTarget);

string GetBarmaidsOrderQuery(object oBarmaid, object oTarget)

{

    //based on faction/alignment/charisma/whatever, do different

    //  responses here.



    int iRace = GetRacialType(oTarget);

    int iRaceBarmaid = GetRacialType(oTarget);

    int iGender = GetGender(oTarget);

    int iBarmaidGender = GetGender(oBarmaid);

    int iRep = GetReputation(oBarmaid, oTarget);

    int iCharisma = GetAbilityScore(oTarget, ABILITY_CHARISMA);

    int iAge = GetAge(oTarget);

    int iGenderWorks = FALSE;

    if ((iGender == iBarmaidGender) && ISA_HOMO) iGenderWorks = TRUE;

    if ((iGender != iBarmaidGender) && (ISA_HOMO == FALSE)) iGenderWorks = TRUE;

    if ((SERVE_ALL_REPUTATIONS==FALSE) && (iRep < REPUTATION_THRESHOLD))

    {

        SetLocalInt(oBarmaid, "REFUSE_CURRENT_CUSTOMER", TRUE);

        return(NO_SERVICE_REPUTATION);

    }

    if ((iRace == RACIAL_TYPE_HUMAN) && (SERVE_HUMAN == FALSE))

    {

        SetLocalInt(oBarmaid, "REFUSE_CURRENT_CUSTOMER", TRUE);

        return(NO_SERVICE_RACE + "We don't serve humans.");

    }

    if ((iRace == RACIAL_TYPE_ELF) && (SERVE_ELF == FALSE))

    {

        SetLocalInt(oBarmaid, "REFUSE_CURRENT_CUSTOMER", TRUE);

        return(NO_SERVICE_RACE + "We don't serve elves.");

    }

    if ((iRace == RACIAL_TYPE_HALFELF) && (SERVE_HALFELF == FALSE))

    {

        SetLocalInt(oBarmaid, "REFUSE_CURRENT_CUSTOMER", TRUE);

        return(NO_SERVICE_RACE + "We don't serve half-elves.");

    }

    if ((iRace == RACIAL_TYPE_GNOME) && (SERVE_GNOME == FALSE))

    {

        SetLocalInt(oBarmaid, "REFUSE_CURRENT_CUSTOMER", TRUE);

        return(NO_SERVICE_RACE + "We don't serve gnomes.");

    }

    if ((iRace == RACIAL_TYPE_HALFLING) && (SERVE_HALFLING == FALSE))

    {

        SetLocalInt(oBarmaid, "REFUSE_CURRENT_CUSTOMER", TRUE);

        return(NO_SERVICE_RACE + "We don't serve halflings.");

    }

    if ((iRace == RACIAL_TYPE_DWARF) && (SERVE_DWARF == FALSE))

    {

        SetLocalInt(oBarmaid, "REFUSE_CURRENT_CUSTOMER", TRUE);

        return(NO_SERVICE_RACE + "We don't serve dwarves.");

    }

    if ((iRace == RACIAL_TYPE_HALFORC) && (SERVE_HALFORC == FALSE))

    {

        SetLocalInt(oBarmaid, "REFUSE_CURRENT_CUSTOMER", TRUE);

        return(NO_SERVICE_RACE + "We don't serve halforcs.");

    }

    if(NOMINORS_USE_DRINKING_AGE)

    {

        if ((iRace == RACIAL_TYPE_HUMAN) && (iAge < NOMINORS_DRINKING_AGE_HUMAN))

        {

            SetLocalInt(oBarmaid, "KIDMENU_CURRENT_CUSTOMER", TRUE);

            return(NOMINORS_GREETING);

        }

        if ((iRace == RACIAL_TYPE_ELF) && (iAge < NOMINORS_DRINKING_AGE_ELF))

        {

            SetLocalInt(oBarmaid, "KIDMENU_CURRENT_CUSTOMER", TRUE);

            return(NOMINORS_GREETING);

        }

        if ((iRace == RACIAL_TYPE_HALFELF) && (iAge < NOMINORS_DRINKING_AGE_HALFELF))

        {

            SetLocalInt(oBarmaid, "KIDMENU_CURRENT_CUSTOMER", TRUE);

            return(NOMINORS_GREETING);

        }

        if ((iRace == RACIAL_TYPE_GNOME) && (iAge < NOMINORS_DRINKING_AGE_GNOME))

        {

            SetLocalInt(oBarmaid, "KIDMENU_CURRENT_CUSTOMER", TRUE);

            return(NOMINORS_GREETING);

        }

        if ((iRace == RACIAL_TYPE_HALFLING) && (iAge < NOMINORS_DRINKING_AGE_HALFLING))

        {

            SetLocalInt(oBarmaid, "KIDMENU_CURRENT_CUSTOMER", TRUE);

            return(NOMINORS_GREETING);

        }

        if ((iRace == RACIAL_TYPE_DWARF) && (iAge < NOMINORS_DRINKING_AGE_DWARF))

        {

            SetLocalInt(oBarmaid, "KIDMENU_CURRENT_CUSTOMER", TRUE);

            return(NOMINORS_GREETING);

        }

        if ((iRace == RACIAL_TYPE_HALFORC) && (iAge < NOMINORS_DRINKING_AGE_HALFORC))

        {

            SetLocalInt(oBarmaid, "KIDMENU_CURRENT_CUSTOMER", TRUE);

            return(NOMINORS_GREETING);

        }

    }

    if (WILL_FLIRT && (iCharisma >= FLIRT_THRESHOLD1) && (iRace == iRaceBarmaid) && iGenderWorks)

    {

        if (WILL_FLIRT && (iCharisma >= FLIRT_THRESHOLD2) && (iRace == iRaceBarmaid) && iGenderWorks)

        {

            int iRespNum = Random(2);

            switch(iRespNum)

            {

                case 0:

                    return(FLIRT_HELLO2_1);

                    break;

                case 1:

                    return(FLIRT_HELLO2_2);

                    break;

                case 2:

                    return(FLIRT_HELLO2_3);

                    break;

            }

        }

        else

        {

            //ok, perhaps we are repulsed

            if (WILL_BE_REPULSED && (iCharisma <= REPULSION_THRESHOLD2))

            {

                 return(REPULSED_2);

            }

            else

            {

                if (WILL_BE_REPULSED && (iCharisma <= REPULSION_THRESHOLD1))

                {

                    return(REPULSED_1);

                }

            }

        }

    }

    int iGreet = Random(1);

    switch(iGreet)

    {

        case 0:

            return(GREETING_1);

        case 1:

            return(GREETING_2);

    }

    return(GREETING_1);

}

/* from failed attempt to "non-heartbeaat" this script

object BarmaidGetBar(object oBarmaid)

{

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

    return(oBarWP);

}

object BarmaidGetStation(object oBarmaid)

{

    object oBarWP = GetObjectByTag("WP_" + GetTag(oBarmaid) + "_STA");

    return(oBarWP);

}

object BarmaidAquireTarget(object oBarmaid, float fDistance=10.0)

{

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

    object oInvalid;

    iNth++;

    //Get this gets the iNth nearest NPC

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

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

    //do not take orders from other barmaids

    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, oBarmaid, 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) && (GetDistanceBetween(oBarmaid, oTarget) <= fDistance))

    {

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

        //iAquired = TRUE;

        //SetLocalObject(oBarmaid,"MAID_TARGET",oTarget);

        SetLocalInt(oBarmaid, "NTH_PATRON", iNth);

        return(oTarget);

                            //ActionMoveToObject(oTarget);

    }

    else

    {

        //try setting iNth back to 1, cycling

        //SpeakString("Starting from the beginning");

        iNth = 1;

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

        if (GetIsObjectValid(oTarget) && (GetDistanceBetween(oBarmaid, oTarget) <= fDistance))

        {

              //special case, we have cycled through all patrons

              //iAquired = TRUE;

              //SetLocalObject(OBJECT_SELF,"MAID_TARGET",oTarget);

              SetLocalInt(oBarmaid, "NTH_PATRON", iNth);

              return(oTarget);

              //ActionMoveToObject(oTarget);

        }

        else

        {

              //Ok, so there is nobody here :) 

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

              SetLocalInt(oBarmaid, "NTH_PATRON", 0);

              return(oInvalid);

        }

    }

    //if you got to here, you got too far!

    return(oInvalid);

}

*/

void main()

{

    // You need these outside the nEvent switch

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

    string sMe = GetTag(OBJECT_SELF);

    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 IS_BARMAID_EFFICIENT = TRUE;

    object oTarget;

    object oBarWP;

    object oStaWP;

    int nEvent=GetUserDefinedEventNumber();

    switch (nEvent)

    {

        case 2005:

            //set state ready

            //SendMessageToPC(GetFirstPC(), "BARMAID - Status is ready");

            SetLocalInt(OBJECT_SELF,"MAID_STATUS",STATUS_READY);

            break;

        case 2006:

            //set state busy

            //SendMessageToPC(GetFirstPC(), "BARMAID - Status is busy");

            SetLocalInt(OBJECT_SELF,"MAID_STATUS",STATUS_BUSY);

            break;

        case 2007:

            //set state finished

            //SendMessageToPC(GetFirstPC(), "BARMAID - Status is done");

            SetLocalInt(OBJECT_SELF,"MAID_STATUS",STATUS_FINISHED);

            break;



        /*  if you can get this to work, w/o heartbeat, re-post!

        case 2100:

            SendMessageToPC(GetFirstPC(), "BARMAID - Aquire Target");

            //start stage 1 - Get to the next customer

            //Set busy state

            ActionDoCommand(SignalEvent(OBJECT_SELF, EventUserDefined(2006)));

            //Set the stage

            ActionDoCommand(SetLocalInt(OBJECT_SELF,"MAID_STAGE",STAGE_AQUIRE));

            //Find the customer

            oTarget = BarmaidAquireTarget(OBJECT_SELF, BARMAID_DISTANCE_THRESHOLD);

            //If valid customer is found?

            if (GetIsObjectValid(oTarget))

            {

                SendMessageToPC(GetFirstPC(), "BARMAID - Found customer");

                //we found a valid customer... set a flag saying we found one

                SetLocalInt(OBJECT_SELF,"FOUND_FIRST_CUSTOMER", TRUE);

                //Set the current target

                SetLocalObject(OBJECT_SELF,"MAID_TARGET",oTarget);

                //Move to the target

                ActionMoveToObject(oTarget, IS_BARMAID_EFFICIENT);

                //Face the target

                ActionDoCommand(SetFacingPoint(GetPositionFromLocation(GetLocation(oTarget))));

            }

            //Signal that we are finished once she clears her queue

            DelayCommand(4.0, SignalEvent(OBJECT_SELF, EventUserDefined(2007)));

            //ActionDoCommand(SignalEvent(OBJECT_SELF, EventUserDefined(2007)));

            //After signaling finished, signal that we are ready for the next phase

            ActionDoCommand(SignalEvent(OBJECT_SELF, EventUserDefined(2005)));

            //Start the next phase if the oTarget was valid

            if (GetIsObjectValid(oTarget))

            {

                ActionDoCommand(SignalEvent(OBJECT_SELF, EventUserDefined(2101)));

            }

            //Done and done

            break;

        case 2101:

            SendMessageToPC(GetFirstPC(), "BARMAID - Get Order");

            //start stage 2 - GetOrder

            //Set busy state

            ActionDoCommand(SignalEvent(OBJECT_SELF, EventUserDefined(2006)));

            //Set the stage

            ActionDoCommand(SetLocalInt(OBJECT_SELF,"MAID_STAGE",STAGE_GETORDER));

            //Start talking

            DelayCommand(4.0, ActionPlayAnimation(ANIMATION_LOOPING_TALK_NORMAL, 1.0, 2.0));

            //Say some words

            ActionDoCommand(SpeakString("Can I take your order, sir?"));

            //Signal that we are finished once she clears her queue

            DelayCommand(4.0, SignalEvent(OBJECT_SELF, EventUserDefined(2007)));

            //ActionDoCommand(SignalEvent(OBJECT_SELF, EventUserDefined(2007)));

            //After signaling finished, signal that we are ready for the next phase

            ActionDoCommand(SignalEvent(OBJECT_SELF, EventUserDefined(2005)));

            //After taking the order, start the next phase

            ActionDoCommand(SignalEvent(OBJECT_SELF, EventUserDefined(2102)));

            //Done and done

            break;

        case 2102:

            SendMessageToPC(GetFirstPC(), "BARMAID - Walk Bar");

            //start stage 3 - WalkBar

            //Set busy state

            ActionDoCommand(SignalEvent(OBJECT_SELF, EventUserDefined(2006)));

            //Set the stage

            ActionDoCommand(SetLocalInt(OBJECT_SELF,"MAID_STAGE",STAGE_WALKBAR));

            //Get the bar

            oBarWP = BarmaidGetBar(OBJECT_SELF);

            if (GetIsObjectValid(oBarWP))

            {

                ActionMoveToObject(oBarWP, IS_BARMAID_EFFICIENT);

                SendMessageToPC(GetFirstPC(), "BARMAID - Walk Bar");

            }

            else

            {

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

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

            }

            //Signal that we are finished once she clears her queue

            DelayCommand(4.0, SignalEvent(OBJECT_SELF, EventUserDefined(2007)));

            //ActionDoCommand(SignalEvent(OBJECT_SELF, EventUserDefined(2007)));

            //After signaling finished, signal that we are ready for the next phase

            ActionDoCommand(SignalEvent(OBJECT_SELF, EventUserDefined(2005)));

            //After taking the order, start the next phase

            ActionDoCommand(SignalEvent(OBJECT_SELF, EventUserDefined(2103)));

            //Done and done

            break;

        case 2103:

            SendMessageToPC(GetFirstPC(), "BARMAID - Get Drink");

            //start stage 4 - GetDrink

            //Set busy state

            ActionDoCommand(SignalEvent(OBJECT_SELF, EventUserDefined(2006)));

            //Set the stage

            ActionDoCommand(SetLocalInt(OBJECT_SELF,"MAID_STAGE",STAGE_GETDRINK));

            //Say something witty at the bar

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

            //Signal that we are finished once she clears her queue

            DelayCommand(4.0, SignalEvent(OBJECT_SELF, EventUserDefined(2007)));

            //ActionDoCommand(SignalEvent(OBJECT_SELF, EventUserDefined(2007)));

            //After signaling finished, signal that we are ready for the next phase

            ActionDoCommand(SignalEvent(OBJECT_SELF, EventUserDefined(2005)));

            //After taking the order, start the next phase

            ActionDoCommand(SignalEvent(OBJECT_SELF, EventUserDefined(2104)));

            //Done and done

            break;

        case 2104:

            SendMessageToPC(GetFirstPC(), "BARMAID - Deliver Drink");

            //start stage 5 - DeliverDrink

            //Set busy state

            ActionDoCommand(SignalEvent(OBJECT_SELF, EventUserDefined(2006)));

            //Set the stage

            ActionDoCommand(SetLocalInt(OBJECT_SELF,"MAID_STAGE",STAGE_DELIVERDRINK));

            //Get the customer

            oTarget = GetLocalObject(OBJECT_SELF, "MAID_TARGET");

            //Go to the target (dont run, you have beer)

            ActionMoveToObject(oTarget);

            //Face the target

            ActionDoCommand(SetFacingPoint(GetPositionFromLocation(GetLocation(oTarget))));

            //Play a "give stuff" animation

            ActionPlayAnimation(ANIMATION_LOOPING_GET_MID, 1.0, 2.0);

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

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

            //Signal that we are finished once she clears her queue

            DelayCommand(4.0, SignalEvent(OBJECT_SELF, EventUserDefined(2007)));

            //ActionDoCommand(SignalEvent(OBJECT_SELF, EventUserDefined(2007)));

            //After signaling finished, signal that we are ready for the next phase

            ActionDoCommand(SignalEvent(OBJECT_SELF, EventUserDefined(2005)));

            //After taking the order, start the next phase

            ActionDoCommand(SignalEvent(OBJECT_SELF, EventUserDefined(2105)));

            //Done and done

            break;

        case 2105:

            //start stage 6 - GoBackToStation

            //Set busy state

            ActionDoCommand(SignalEvent(OBJECT_SELF, EventUserDefined(2006)));

            //Set the stage

            ActionDoCommand(SetLocalInt(OBJECT_SELF,"MAID_STAGE",STAGE_GOSTATION));

            //Get the station

            oStaWP = BarmaidGetStation(OBJECT_SELF);

            if (GetIsObjectValid(oStaWP))

            {

                ActionMoveToObject(oStaWP, IS_BARMAID_EFFICIENT);

                SendMessageToPC(GetFirstPC(), "BARMAID - Go Station");

            }

            else

            {

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

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

            }

            //Signal that we are finished once she clears her queue

            DelayCommand(4.0, SignalEvent(OBJECT_SELF, EventUserDefined(2007)));

            //ActionDoCommand(SignalEvent(OBJECT_SELF, EventUserDefined(2007)));

            //After signaling finished, signal that we are ready for the next phase

            ActionDoCommand(SignalEvent(OBJECT_SELF, EventUserDefined(2005)));

            //ClearAllActions();

            //After taking the order, start the next phase

            ActionDoCommand(SignalEvent(OBJECT_SELF, EventUserDefined(2100)));

            //Done and done

            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

            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, "REFUSE_CURRENT_CUSTOMER", FALSE);

                        SetLocalInt(OBJECT_SELF, "KIDMENU_CURRENT_CUSTOMER", FALSE);

                        SetLocalInt(OBJECT_SELF,"MAID_STATUS",STATUS_BUSY);

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

                        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);

                        }

                        if (GetStringLeft(GetTag(oTarget), 9) == "BARTENDER")

                        {

                            //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);

                            ActionForceMoveToObject(oTarget, IS_BARMAID_EFFICIENT);

                            ActionDoCommand(SetFacingPoint(GetPositionFromLocation(GetLocation(oTarget))));

                            AssignCommand(oTarget, ActionWait(5.0));

                            AssignCommand(oTarget, SetFacingPoint(GetPositionFromLocation(GetLocation(GetObjectByTag(sMe)))));

                        }

                        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);

                                ActionForceMoveToObject(oTarget, IS_BARMAID_EFFICIENT);

                                ActionDoCommand(SetFacingPoint(GetPositionFromLocation(GetLocation(oTarget))));

                                AssignCommand(oTarget, ActionWait(5.0));

                                AssignCommand(oTarget, SetFacingPoint(GetPositionFromLocation(GetLocation(GetObjectByTag(sMe)))));

                            }

                            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

                        ActionPlayAnimation(ANIMATION_LOOPING_TALK_NORMAL, 1.0, 2.0);

                        ActionDoCommand(SpeakString(GetBarmaidsOrderQuery(OBJECT_SELF, oTarget)));

                        //mention the items as appropriate

                        if (GetLocalInt(OBJECT_SELF,"REFUSE_CURRENT_CUSTOMER"))

                        {

                            //set it up as if we already delivered the drink

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

                            ActionDoCommand(SetLocalInt(OBJECT_SELF,"MAID_STAGE",STAGE_DELIVERDRINK));

                        }

                        else

                        {

                            //do more stuff

                            //mention the items as appropriate

                            if (GetLocalInt(OBJECT_SELF,"KIDMENU_CURRENT_CUSTOMER"))

                            {

                                ActionDoCommand(SpeakString(ITEM1_MINOR_DESCRIPTION));

                            }

                            else

                            {

                                ActionWait(3.0);

                                ActionDoCommand(SpeakString(ITEM1_DESCRIPTION));

                                ActionWait(3.0);

                                ActionDoCommand(SpeakString(ITEM2_DESCRIPTION));

                                ActionWait(3.0);

                                ActionDoCommand(SpeakString(ITEM3_DESCRIPTION));

                                ActionWait(3.0);

                                int iDrink = Random(2);

                                AssignCommand(oTarget, ActionWait(8.0));

                                switch(iDrink)

                                {

                                    case 0:

                                        AssignCommand(oTarget, DelayCommand(8.0, SpeakString("I'll have " + ITEM1)));

                                        break;

                                    case 1:

                                        AssignCommand(oTarget, DelayCommand(8.0, SpeakString("A " + ITEM2 + " sounds good!")));

                                        break;

                                    case 2:

                                        AssignCommand(oTarget, DelayCommand(8.0, SpeakString("Please bring me a " + ITEM3)));

                                        break;

                                }

                                SetLocalInt(OBJECT_SELF, "DRINK_CHOSEN", iDrink);

                                ActionWait(3.0);

                                ActionDoCommand(SpeakString("Coming right up!"));

                            }

                            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

                        {

                            ActionForceMoveToObject(oBarWP, IS_BARMAID_EFFICIENT);

                            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>"

                        int iDrinkChosen = GetLocalInt(OBJECT_SELF, "DRINK_CHOSEN");

                        switch(iDrinkChosen)

                        {

                            case 0:

                                ActionDoCommand(SpeakString("Please give me a " + ITEM1));

                                break;

                            case 1:

                                ActionDoCommand(SpeakString("I need a " + ITEM2));

                                break;

                            case 2:

                                ActionDoCommand(SpeakString("Load me up with a " + ITEM3));

                                break;

                        }

                        ActionWait(2.0);

                        ActionPlayAnimation(ANIMATION_LOOPING_GET_MID, 1.0, 2.0);

                        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");

                        ActionForceMoveToObject(oTarget);

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

                        ActionPlayAnimation(ANIMATION_LOOPING_GET_MID, 1.0, 2.0);

                        int iDrinkChosen = GetLocalInt(OBJECT_SELF, "DRINK_CHOSEN");

                        switch(iDrinkChosen)

                        {

                            case 0:

                                ActionDoCommand(SpeakString("Here's your " + ITEM1));

                                break;

                            case 1:

                                ActionDoCommand(SpeakString("Enjoy your " + ITEM2));

                                break;

                            case 2:

                                ActionDoCommand(SpeakString("Your " + ITEM3 + " is ready!"));

                                break;

                        }

                        int iTargetSits = GetLocalInt(oTarget, "SITS_DOWN");

                        if (iTargetSits)

                        {

                            object oMychair = GetNearestObjectByTag("chair", oTarget);

                            AssignCommand(oTarget, DelayCommand(4.0, ActionSit(oMychair)));

                        }

                        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

                        {

                            ActionForceMoveToObject(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;

   }

}



Use this on "onspawn":

NWScript:
//::///////////////////////////////////////////////

//:: 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.

    SetSpawnInCondition(2006);

    SetSpawnInCondition(2007);

    //SetSpawnInCondition(2100);

    //SetSpawnInCondition(2101);

    //SetSpawnInCondition(2102);

    //SetSpawnInCondition(2103);

    //SetSpawnInCondition(2104);

    //SetSpawnInCondition(2105);

// 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

    //DelayCommand(5.0, ActionDoCommand(SignalEvent(OBJECT_SELF, EventUserDefined(2005))));

    //ActionDoCommand(SignalEvent(OBJECT_SELF, EventUserDefined(2100)));

}



And this in the abort and end conversation events in the barmaids dialog:

NWScript:
void main()

{

    SignalEvent(OBJECT_SELF, EventUserDefined(2005));

}



And that should do it. Please excuse the cheesy dialog.