Author Sticky: Post Working Scripts Here
Rhone11 Posted: Saturday, 20 July 02:15AM
Hour-based WayPoint Walker version 1.1

This is an upgrade to my previously posted Hour-based Waypoint Walker. This update includes two enhancements:

1. The code no longer tries to find the nearest waypoint when deciding which waypoint to start with. Instead, it keeps track of which waypoint the NPC is going to, and if the NPC resumes walking waypoints after an interruption, he will continue toward the waypoint he was walking toward before. If the NPC has new waypoints to walk, then he will start at the first numerically.

2. The instructions now include setting up a userdefined event for running HourWayPoints, and use SignalEvent(OBJECT_SELF, EventUserDefined(2000)) in other scripts in place of HourWayPoints. This is so that NPCs that need to call HourWayPoints with different parameters can do so by only having one different script.

Instructions for setting it up are in the introductory comments. If you already installed version 1.0, here are instructions for upgrading:

1. Completely replace the old rh_inc_hrwpoints with the new script below.

2. Replace the OnHeartbeat script with the new one below.

3. Save the OnUserDefined script below as nw_c2_defaultd to use it as the default OnUserDefined script (different NPCs, of course, can and should have their own modified versions with their events added in).

4. In MY_I0_GENERIC (or whatever you saved the modified NW_I0_GENERIC as), where you replaced WalkWayPoints() with HourWayPoints(), now replace HourWayPoints() with SignalEvent(OBJECT_SELF, EventUserDefined(2000)).

5. In your NPCs' OnSpawn script, also replace HourWayPoints() with SignalEvent(OBJECT_SELF, EventUserDefined(2000)).

6. If you put HourWayPoints() in any other script (an End Conversation script for your NPCs' conversations, perhaps), change it to SignalEvent(OBJECT_SELF, EventUserDefined(2000)).

Here are the scripts, starting with rh_inc_hrwpoints:

NWScript:
/*

Name:      Rhone's Hour-based WayPoint Walker

Author:    Thomas J. Hamman (Rhone)

E-Mail:    hammant@panther.adelphi.edu

Filename:  RH_INC_HRWPOINTS

Version:   1.1

_Changelog_

    _v1.0 (7-18-02)_

Original release.

    _v1.1 (7-19-02)_

1.  NPCs now keep track of which waypoint they were walking toward with a local

    variable.  After an interruption, they will resume heading toward the next

    waypoint instead of simply going toward the nearest waypoint.

2.  The directions (see below the description) have been changed to instruct users

    to use SignalEvent(OBJECT_SELF, UserDefinedEvent(2000)) in place of

    HourWayPoints in their scripts.  Now, to have different NPCs use HourWayPoints

    with different parameters, only their OnUserDefined scripts need to be different.

    The OnHeartbeat script provided incorporates this change, and a default

    OnUserDefined script is included now as well.

_Description_

This is a complete rewrite of the waypoint walking system in NW_I0_GENERIC,

using the original as a rough guide.  Here are its advantages:

1.  Hour-based waypoints--the main feature.  It allows for NPCs to easily be

    given daily schedules.  The tags for hour-based waypoints and posts

    (respectively) use this format:

        WP_XX_NPCTag_YY

        POST_XX_NPCTag

    Where XX is the hour -- 01 through 24 -- and YY is the order number for the

    waypoint.  NPCTag is, of course, the tag of the NPC who uses the waypoint.

    24-hour waypoints can still be used, with "00" in place of XX, and Day/Night

    waypoints can still be used with DY (for day) and NT (for night) in place of

    XX.  You must choose one system for each NPC, though--if Bob has the waypoint

    WP_00_Bob_01 then the script will never check for day/night or hour-based

    waypoints for Bob, since that wouldn't make sense.  Likewise, if Bob has

    POST_DY_Bob then the script will not check for hour-based waypoints for

    him.

2.  Circular waypoints--follow the waypoints as, for example, 1 2 3 4 1 2 3 4,

    instead of 1 2 3 4 3 2 1.  To use this, have any script for the NPC that

    runs HourWayPoints call it with the nCircle parameter TRUE, e.g.:

        HourWayPoints(FALSE, 1.0, TRUE);

3.  Terminal waypoints--i.e. follow the waypoints through to the end once, and

    then stop.  This is done by having waypoints and a post for the same time;

    the NPC will go through the waypoints once, ending and stopping at the post.

4.  The ability to run a script at each waypoint.  This is done by putting

    a script in the NPC's OnUserDefined event, with event numbers in this format:

        9XXYY

    XX is the hour of the waypoint (01 through 24 -- or 00 for 24-hour waypoints,

    25 for day waypoints, and 26 for night waypoints), and YY is the order

    number for the waypoint (use 00 for posts).  Here are some examples:

        91200   A noon post.

        90503   The third waypoint at 5am.

        90005   The fifth 24-hour waypoint.

        92501   The first day waypoint.

        92600   An all-night post.

    This opens up a world of possibilities, starting with very simple but fun

    things like having Bob go to POST_16_Bob, which triggers his 91600 event

    that has him sit in a chair.

    Note that only "actions" should go in the userdefined events, so they will

    properly fit into the action queue.  It is often useful to write the commands

    in a separate function and wrap it inside an ActionDoCommand().

5.  A workaround for the current bug in the GetFacing function, which allows NPC's

    to face the correct direction at their posts.  The workaround will be harmless

    when GetFacing is fixed.

6.  NPCs remember the last waypoint they were walking toward and now walk toward

    it (rather than simply the nearest waypoint) when they resume waypoints after

    an interruption.

_Current Possible Bugs/Problems_

I spent a lot of time testing and debugging it, but I doubt this is necessarily

coded in the most efficient way possible.  My testing has been with small numbers

of NPCs, so I don't yet know whether having dozens of NPCs with hour-based

waypoints will slow things down.

There are some issues that exist with the current WalkWayPoints as well, since

they aren't related directly to WalkWayPoints.  For example, NPCs aren't as

active when there is no PC in the area.  Their ActionMoveTo commands often don't

kick in until a PC enters the area.  ActionForceMoveTo (which is used for going

to posts but not waypoints, in both the original function and in mine) alleviates

this a little bit, as it will jump the NPC to its post after a certain amount of

time.  If you wish to try this with the waypoints as well, it can be done with

a small change in HourRunCircuit.  Replace...

    ActionMoveToObject(oWP, nRun);

with...

    ActionForceMoveToObject(oWP, nRun, 1.0, 60.0);

The 60.0 is how many seconds to wait before giving up the NPC and just jumping

him to the destination.  Change it if you like, keeping in mind that time is

passing slower in areas with no PC.

There's also a friendly little bug I can take no credit for which causes NPCs

walking waypoints to sometimes head southwest after an area transition until they

bump into something, at which point they _then_ head to a waypoint/post.  One

workaround is to use an OnEnter script for your areas which checks to see if the

entering object isn't the PC, and if so, to run HourWayPoints() for the NPC to

send it in the right direction.

_INSTRUCTIONS for using the code_

Considering this has to replace a function in a standard include file that is

included by many default scripts (several of which call the WalkWayPoints function

which we're trying to replace), the instructions unfortunately cannot be as

simple as "just put this script in this place and you're all set."  If you're

trying this in an existing module you're working on, consider making a backup

copy first.  With that aside, here is a set of steps to follow:

1.  Save this script in the script editor with whatever name you like.  For the

    rest of these instructions I'll assume you saved it as rh_inc_hrwpoints.

2.  Open nw_i0_generic in the script editor (you'll have to click on All Resources

    for it to show up).  Yes, we must tamper with this very important include file.

    After the comments and before any of the code, put in this line:

//        #include "RH_INC_HRWPOINTS"

    (Don't include the slashes--for some reason when I try saving this the

    compiler reads the #include as if it's not commented unless I use a C++ style

    comment with it.)



3.  Still in nw_i0_generic, scroll down to the end of the DetermineCombatRounds

    function, right before the SetListeningPatterns function, and look for code

    that looks like this:

        ClearAllActions();

        SetLocalObject(OBJECT_SELF, "NW_GENERIC_LAST_ATTACK_TARGET", OBJECT_INVALID);

        WalkWayPoints();

    The line numbers where this is should be in the 750's.  Running a Find on

    "WalkWayPoints()" (without the quotes) should find it.  What you need to

    do there is change the WalkWayPoints(); line to this:

        SignalEvent(OBJECT_SELF, EventUserDefined(2000));

    Now DetermineCombatRound will use the new function to return NPCs to their

    waypoints/posts after they finish combat.  (The purpose of using SignalEvent

    will be explained.)

4.  Save the edited nw_i0_generic under a new name--for the rest of these

    instructions I'll assume you saved it as my_i0_generic.

5.  Now what's important is that any script which calls WalkWayPoints() needs to

    be changed so that it runs SignalEvent(OBJECT_SELF, EventUserDefined(2000))

    instead, and includes my_i0_generic instead of nw_i0_generic.  In particular

    you need to edit these default NPC scripts:

    nw_c2_default9:  This is the default OnSpawn script for NPCs.

                     Just change WalkWayPoints() (near the end) to the SignalEvent

                     command given above and replace the include line for

                     NW_I0_GENERIC with one that includes MY_I0_GENERIC instead.

    nw_c2_default3:  This is the default OnCombatRoundEnd script.  Just change

                     the include from NW_I0_GENERIC to MY_I0_GENERIC.

6.  Save those files.  If you are going to use the new waypoint script for just

    a few NPCs and want to use the default WalkWayPoints for the rest, then save

    those files under a new name and use those in place of the defaults for the

    appropriate NPCs.  If you want all NPCs with waypoints to use the new waypoint

    script then don't be shy about saving those files with the default names so that

    they are used automatically when you create new NPCs.  This WILL NOT hurt the

    original scripts.  The toolset's built-in scripts are kept separate from your

    own scripts, and you can easily revert to the original scripts by deleting the

    new ones of the same name.  Your "overriding" scripts also don't affect other

    modules.

7.  The OnHeartbeat script for NPCs needs some added code.  A modified OnHeartbeat

    script should be included in the Post/Archive/Whatever where you found this.

    Save that as nw_c2_default1 to use it as the default OnHeartbeat for NPCs.

8.  Now that we are using SignalEvent to trigger a userdefined event, we need to

    put event number 2000 into the OnUserDefined script.  Included where you found

    this script should be a sample OnUserDefined script; save that as nw_c2_defaultd

    to use it as the default OnUserDefined for NPCs.  Then, for any NPC that you

    want using different HourWayPoints parameters, you only have to change his

    OnUserDefined.

9.  Don't forget that NPCs need an End Conversation Script that calls

    SignalEvent(OBJECT_SELF, EventUserDefined(2000)) to have them resume their

    waypoints after conversations.



Have fun with the script, I hope it works well for everyone who tries it. :) 

*/

void HourWayPoints(int nRun = FALSE, float fPause = 1.0, int nCircle = FALSE);

void HourRunCircuit(string sPrefix, int nWPStart = 1, int nReverse = FALSE, int nRun=FALSE, float fPause = 1.0, int nCircle = FALSE);

void HourGoToPost(object oPost, int nRun = FALSE);

int GetEventForWP(object oWP, int nNum);

string PosIntTo2DigitString(int nNum);

float GetFacingCorrectly(object oTarget);

//This should be called in place of WalkWayPoints.  There is one extra parameter

//(nCircle), which allows NPCs to walk in a circle instead of back and forth.

void HourWayPoints(int nRun = FALSE, float fPause = 1.0, int nCircle = FALSE)

{

    //nDontWalkWP can be set in scripts to temporarily disable waypoint walking

    //for a particular NPC.

    if (GetLocalInt(OBJECT_SELF, "nDontWalkWP"))

        return;

    string sWalker = GetTag(OBJECT_SELF);

    string sWPPrefix;

    string sPostPrefix;

    int nWPStart = GetLocalInt(OBJECT_SELF, "nNextWP");

    int nDay;

    object oWP;

    object oPost;

    ClearAllActions();

    //Before we start checking the hour and day/night status, let's see if the

    //NPC uses "00" (24-hour) waypoints/post.

    sWPPrefix = "WP_00_";

    sPostPrefix = "POST_00_";

    oWP = GetObjectByTag(sWPPrefix + sWalker + "_01");

    oPost = GetObjectByTag(sPostPrefix + sWalker);

    //If the NPC has a "00" WP, then start going to first WP or next WP if resuming.

    if (GetIsObjectValid(oWP)) {

        if (!nWPStart)

            nWPStart = 1;

        HourRunCircuit(sWPPrefix, nWPStart, FALSE, nRun, fPause, nCircle);

        return;

    }

    //If the NPC has no WP but a "00" Post, send him to it.

    if (GetIsObjectValid(oPost)) {

        HourGoToPost(oPost, nRun);

        return;

    }

    //No "00" waypoints or posts, so let's try night/day.

    if (GetIsDay() || GetIsDawn()) {

        sWPPrefix = "WP_DY_";

        sPostPrefix = "POST_DY_";

        nDay = 1;

    } else {

        sWPPrefix = "WP_NT_";

        sPostPrefix = "POST_NT_";

        nDay = 2;

    }

    oWP = GetObjectByTag(sWPPrefix + sWalker + "_01");

    oPost = GetObjectByTag(sPostPrefix + sWalker);

    //If NPC has day/night wayposts, find current one and send him on his way.

    if (GetIsObjectValid(oWP)) {

        int nOldDay = GetLocalInt(OBJECT_SELF, "nDayPoints");

        if (!(nWPStart && nOldDay && nOldDay == nDay)) {

            SetLocalInt(OBJECT_SELF, "nDayPoints", nDay);

            nWPStart = 1;

        }

        HourRunCircuit(sWPPrefix, nWPStart, FALSE, nRun, fPause, nCircle);

        return;

    }

    //If the NPC has no waypoints but a day/night post, send him to it.

    if (GetIsObjectValid(oPost)) {

        SetLocalInt(OBJECT_SELF, "nDayPoints", nDay);

        HourGoToPost(oPost);

        return;

    }

    //Code for hour-based waypoints starts here.

    int nHour = GetTimeHour();

    sWPPrefix = "WP_" + PosIntTo2DigitString(nHour) + "_";

    sPostPrefix = "POST_" + PosIntTo2DigitString(nHour) + "_";

    oWP = GetObjectByTag(sWPPrefix + sWalker + "_01");

    oPost = GetObjectByTag(sPostPrefix + sWalker);

    //The important thing we're doing in the following loop is checking every hour,

    //starting with the current hour and counting backwards, until we either find

    //an hour for which the NPC has waypoints to walk (so an NPC with 8am waypoints

    //will keep walking them for every hour until the next hour he has waypoints

    //set for) or we reach nLastHourWalked (at which point we don't need to look

    //back any further).

    //

    //If the NPC is running HourWayPoints for the first time (e.g. he just spawned)

    //then nLastHourWalked isn't set yet, so we set it to an hour ahead of the

    //current time--that way, every hour can be checked for waypoints.

    //

    //nLastHourChecked is being set for use in the OnHeartbeat script.

    if (!GetLocalInt(OBJECT_SELF, "nLastHourWalked"))

        SetLocalInt(OBJECT_SELF, "nLastHourWalked", nHour + 1);

    while (nHour != GetLocalInt(OBJECT_SELF, "nLastHourWalked")) {

        if (GetIsObjectValid(oWP)) {

            nWPStart = 1;

            SetLocalInt(OBJECT_SELF, "nLastHourWalked", nHour);

            SetLocalInt(OBJECT_SELF, "nLastHourChecked", GetTimeHour());

            HourRunCircuit(sWPPrefix, nWPStart, FALSE, nRun, fPause, nCircle);

            return;

        } else if (GetIsObjectValid(oPost)) {

            SetLocalInt(OBJECT_SELF, "nLastHourWalked", nHour);

            SetLocalInt(OBJECT_SELF, "nLastHourChecked", GetTimeHour());

            HourGoToPost(oPost, nRun);

            return;

        } else {

            nHour--;

            if (nHour == 0)

                nHour = 24;

            sWPPrefix = "WP_" + PosIntTo2DigitString(nHour) + "_";

            sPostPrefix = "POST_" + PosIntTo2DigitString(nHour) + "_";

            oWP = GetObjectByTag(sWPPrefix + sWalker + "_01");

            oPost = GetObjectByTag(sPostPrefix + sWalker);

        }

    }

    //If we reach nLastHourWalked before finding waypoints for later hours, we

    //check to make sure that there are valid waypoints/posts for that hour and

    //send the NPC to them if so.

    if (GetIsObjectValid(oWP)) {

        SetLocalInt(OBJECT_SELF, "nLastHourWalked", nHour);

        SetLocalInt(OBJECT_SELF, "nLastHourChecked", GetTimeHour());

        HourRunCircuit(sWPPrefix, nWPStart, FALSE, nRun, fPause, nCircle);

        return;

    }

    if (GetIsObjectValid(oPost)) {

        SetLocalInt(OBJECT_SELF, "nLastHourWalked", nHour);

        SetLocalInt(OBJECT_SELF, "nLastHourChecked", GetTimeHour());

        HourGoToPost(oPost, nRun);

        return;

    }

}

//This is the replacement for the original RunCircuit (it does not use a

//RunNextCircuit equivalent), which sends the NPC to his waypoints in order.

//

//It was originally designed with a while loop to loop through the waypoints,

//but I had to change it to loop by recursion instead.  Using a while loop, I

//was unable to get the UserDefined actions (triggered by the SignalEvent at

//each waypoint) to fit in their correct place in the action queue.  No matter

//what I tried, the scripted actions for every waypoint would run at the end of

//the circuit (right before the function called itself again).  So, I made the

//function call itself again for every waypoint, and viola, the userdefined

//actions take place when they should.

//

//Note that this functions allows for circular waypoint walking through a function

//parameter (filtered down from HourWayPoints), and it also allows for waypoints

//and a post to be set for the same time--what happens then is that the NPC walks

//his waypoints once and then goes to his post, where he stays.

void HourRunCircuit(string sPrefix, int nNext = 1, int nReverse=FALSE, int nRun=FALSE, float fPause = 1.0, int nCircle = FALSE)

{

    string sWalker = GetTag(OBJECT_SELF);

    object oWP = GetWaypointByTag(sPrefix + sWalker + "_" + PosIntTo2DigitString(nNext));

    object oPost = GetWaypointByTag("POST_" + GetSubString(sPrefix, 3, 3) + sWalker);

    if (GetIsObjectValid(oWP)) {

        SetLocalInt(OBJECT_SELF, "nNextWP", nNext);

        ActionMoveToObject(oWP, nRun);

        SignalEvent(OBJECT_SELF, EventUserDefined(GetEventForWP(oWP, nNext)));

        ActionWait(fPause);

        if (!nReverse)

            nNext++;

        else

            nNext--;

    } else if (GetIsObjectValid(oPost)) {

        ActionDoCommand(HourGoToPost(oPost, nRun));

        return;

    } else {

        if (nCircle) {

            nReverse = FALSE;

            nNext = 1;

        } else {

            nReverse = !nReverse;

            if (!nReverse)

                nNext += 2;

            else

                nNext -= 2;

        }

    }

    ActionDoCommand(HourRunCircuit(sPrefix, nNext, nReverse, nRun, fPause, nCircle));

}

//Go to a Post.

void HourGoToPost(object oPost, int nRun = FALSE)

{

    SetLocalInt(OBJECT_SELF, "nNextWP", 100);

    ActionForceMoveToObject(oPost, nRun, 1.0, 60.0);

    float fFacing = GetFacingCorrectly(oPost);

    ActionDoCommand(SetFacing(fFacing));

    SignalEvent(OBJECT_SELF, EventUserDefined(GetEventForWP(oPost, 0)));

}



//Convert 1, 2, 3 ... 9 into 01, 02, 03 ... 09.

string PosIntTo2DigitString(int nNum)

{

    string sString;

    if (nNum > 9)

        return IntToString(nNum);

    else if (nNum < 10 && nNum >= 0)

        return ("0" + IntToString(nNum));

    else

        return "This function is not for negative numbers.";

}

//A workaround for GetFacing, which is currently broken.  This will cease to

//be necessary when/if Bioware fixes GetFacing, but it won't break anything.

float GetFacingCorrectly(object oTarget)

{

    float fFacing;

    fFacing = GetFacing(oTarget);

    if (fFacing >= 360.0)

        fFacing = 720.0 - fFacing;

    return fFacing;

}

//This is the function for putting together a number for an event to trigger in

//the NPC's OnUserDefined script.

int GetEventForWP(object oWP, int nNum)

{

    string sTime;

    string sNum;

    string sEventNum;

    int nEventNum;

    if (!nNum) {

        sNum = "00";

        sTime = GetSubString(GetTag(oWP), 5, 2);

    }

    else {

        sNum = GetStringRight(GetTag(oWP), 2);

        sTime = GetSubString(GetTag(oWP), 3, 2);

    }

    if (sTime == "DY")

        sTime = "25";

    else if (sTime == "NT")

        sTime = "26";

    sEventNum = "9" + sTime + sNum;

    nEventNum = StringToInt(sEventNum);

    return nEventNum;

}



And here is the OnHeartbeat script:

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

//:: Default On Heartbeat

//:: NW_C2_DEFAULT1

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

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

/*

    This script will have people perform default

    animations.

*/

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

//:: Created By: Preston Watamaniuk

//:: Created On: Nov 23, 2001

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

//This script has been altered for use with Rhone's Hour-Based Waypoint Walker.

//Default WalkWayPoints-related code has been removed and replaced with new

//code for HourWayPoints.

//

//The new code handles rerunning HourWayPoints() (through the userdefined event)

//at the appropriate times for NPCs with day/night waypoints or hour-based waypoints.

//--Rhone

#include "MY_I0_GENERIC"

void main()

{

    if(GetSpawnInCondition(NW_FLAG_FAST_BUFF_ENEMY))

    {

        if(TalentAdvancedBuff(40.0))

        {

            SetSpawnInCondition(NW_FLAG_FAST_BUFF_ENEMY, FALSE);

            return;

        }

    }

    //If nDay has been set, and it's not equal to the current day/night status,

    //check to see if the NPC has new waypoints/posts to walk.

    if (GetLocalInt(OBJECT_SELF, "nDayPoints")) {

        int nDay;

        if (GetIsDay() || GetIsDawn())

            nDay = 1;

        else

            nDay = 2;

        if (GetLocalInt(OBJECT_SELF, "nDayPoints") != nDay)

            SignalEvent(OBJECT_SELF, EventUserDefined(2000));

    }

    //If nLastHourChecked hasn't been set for the NPC, then he's probably not

    //walking hour-based waypoints and we don't do anything else.  If it is

    //checked, and it's not equal to the current hour, we check to see if there

    //are new waypoints.  nLastHourChecked will end up being set to the current

    //hour so OnHearbeat knows not to bother checking for new waypoints again

    //until the next hour.

    int nHour = GetTimeHour();

    int nLastHourChecked = GetLocalInt(OBJECT_SELF, "nLastHourChecked");

    if (nLastHourChecked && nHour != nLastHourChecked) {

        string sWalker = GetTag(OBJECT_SELF);

        object oNewWP;

        object oNewPost;

        while (nHour != nLastHourChecked) {

            oNewWP = GetObjectByTag("WP_" + PosIntTo2DigitString(nHour) + "_" + sWalker + "_01");

            oNewPost = GetObjectByTag("POST_" + PosIntTo2DigitString(nHour) + "_" + sWalker);

            if (GetIsObjectValid(oNewWP) || GetIsObjectValid(oNewPost)) {

                nHour = GetTimeHour();

                nLastHourChecked = nHour;

            }

            else {

                nHour--;

                if (nHour == 0)

                    nHour = 24;

            }

        }

        if (GetIsObjectValid(oNewWP) || GetIsObjectValid(oNewPost))

            SignalEvent(OBJECT_SELF, EventUserDefined(2000));

        else

            SetLocalInt(OBJECT_SELF, "nLastHourChecked", GetTimeHour());

    }

    if(!GetHasEffect(EFFECT_TYPE_SLEEP))

    {

        if(!GetIsPostOrWalking())

        {

            if(!GetIsObjectValid(GetAttemptedAttackTarget()) && !GetIsObjectValid(GetAttemptedSpellTarget()))

            {

                if(!GetIsObjectValid(GetNearestCreature(CREATURE_TYPE_REPUTATION, REPUTATION_TYPE_ENEMY, OBJECT_SELF, 1, CREATURE_TYPE_PERCEPTION, PERCEPTION_SEEN)))

                {

                    if(!GetBehaviorState(NW_FLAG_BEHAVIOR_SPECIAL) && !IsInConversation(OBJECT_SELF))

                    {

                        if(GetSpawnInCondition(NW_FLAG_AMBIENT_ANIMATIONS) || GetSpawnInCondition(NW_FLAG_AMBIENT_ANIMATIONS_AVIAN))

                        {

                            PlayMobileAmbientAnimations();

                        }

                        else if(GetIsEncounterCreature() &&

                        !GetIsObjectValid(GetNearestCreature(CREATURE_TYPE_REPUTATION, REPUTATION_TYPE_ENEMY, OBJECT_SELF, 1, CREATURE_TYPE_PERCEPTION, PERCEPTION_SEEN)))

                        {

                            PlayMobileAmbientAnimations();

                        }

                        else if(GetSpawnInCondition(NW_FLAG_IMMOBILE_AMBIENT_ANIMATIONS) &&

                           !GetIsObjectValid(GetNearestCreature(CREATURE_TYPE_REPUTATION, REPUTATION_TYPE_ENEMY, OBJECT_SELF, 1, CREATURE_TYPE_PERCEPTION, PERCEPTION_SEEN)))

                        {

                            PlayImmobileAmbientAnimations();

                        }

                    }

                    else

                    {

                        DetermineSpecialBehavior();

                    }

                }

                else

                {

                    //DetermineCombatRound();

                }

            }

        }

    }

    else

    {

        if(GetSpawnInCondition(NW_FLAG_SLEEPING_AT_NIGHT))

        {

            effect eVis = EffectVisualEffect(VFX_IMP_SLEEP);

            if(d10() > 6)

            {

                ApplyEffectToObject(DURATION_TYPE_INSTANT, eVis, OBJECT_SELF);

            }

        }

    }

    if(GetSpawnInCondition(NW_FLAG_HEARTBEAT_EVENT))

    {

        SignalEvent(OBJECT_SELF, EventUserDefined(1001));

    }

}



And here is the OnUserDefined script:

NWScript:
//This is a simple default OnUserDefined script meant for use with Rhone's

//Hour-based Waypoint Walker code.

//--Rhone

#include "MY_I0_GENERIC"

void main()

{

    int nEvent = GetUserDefinedEventNumber();

    switch(nEvent)

    {

        case 2000:

            HourWayPoints(FALSE, 1.0, FALSE);

            break;

    }

}



Enjoy!