Jaysyn904 66a0a3e043 Initial commit
Initial commit.
2024-08-03 14:13:18 -04:00

2273 lines
76 KiB
Plaintext

//:://////////////////////////////////////////////////
//:: X0_I0_ANIMS
/*
Library for playing random animations.
*/
//:://////////////////////////////////////////////////
//:: Copyright (c) 2002 Floodgate Entertainment
//:: Created By: Naomi Novik
//:: Created On: 12/07/2002
//:://////////////////////////////////////////////////
// Library for positioning
#include "x0_i0_position"
// Library for stealth/detect modes
#include "x0_i0_modes"
// Library for Voiceset functionality. All voice calls go through here
#include "x0_i0_voice"
// Library for walkways (need to pass it this way to get access to ClearActiosn in x0_i0_assoc
#include "x0_i0_walkway"
/**********************************************************************
* CONSTANTS
**********************************************************************/
// Animation length and speed
const float ANIM_LOOPING_LENGTH = 4.0;
const float ANIM_LOOPING_SPEED = 1.0;
// Conversation file that holds the random one-liners for
// NPCs to speak when a PC comes into their home.
const string ANIM_CONVERSATION = "x0_npc_homeconv";
// Variable that holds the animation flags
const string sAnimCondVarname = "NW_ANIM_CONDITION";
// *** Available animation flags *** //
// If set, the NPC has been initialized
const int NW_ANIM_FLAG_INITIALIZED = 0x00000001;
// If set, the NPC will animate on every OnHeartbeat event.
// Otherwise, the NPC will animate only on every OnPerception event.
const int NW_ANIM_FLAG_CONSTANT = 0x00000002;
// If set, the NPC will use voicechats
const int NW_ANIM_FLAG_CHATTER = 0x00000004;
// If set, the NPC has been triggered and should be animating
const int NW_ANIM_FLAG_IS_ACTIVE = 0x00000008;
// If set, the NPC is currently interacting with a placeable
const int NW_ANIM_FLAG_IS_INTERACTING = 0x00000010;
// If set, the NPC has gone inside an interior area.
const int NW_ANIM_FLAG_IS_INSIDE = 0x00000020;
// If set, the NPC has a home waypoint
const int NW_ANIM_FLAG_HAS_HOME = 0x00000040;
// If set, the NPC is currently talking
const int NW_ANIM_FLAG_IS_TALKING = 0x00000080;
// If set, the NPC is mobile
const int NW_ANIM_FLAG_IS_MOBILE = 0x00000100;
// If set, the NPC is mobile in a close-range
const int NW_ANIM_FLAG_IS_MOBILE_CLOSE_RANGE = 0x00000200;
// If set, the NPC is civilized
const int NW_ANIM_FLAG_IS_CIVILIZED = 0x00000400;
// If set, the NPC will close doors
const int NW_ANIM_FLAG_CLOSE_DOORS = 0x00001000;
// int NW_ANIM_FLAG_ = 0x00000000;
/**********************************************************************
* FUNCTION PROTOTYPES
**********************************************************************/
// Debugging function. Will be commented out for final.
void AnimDebug(string sMsg);
// TRUE if the given creature has the given condition set
int GetAnimationCondition(int nCondition, object oCreature=OBJECT_SELF);
// Mark that the given creature has the given condition set
void SetAnimationCondition(int nCondition, int bValid=TRUE, object oCreature=OBJECT_SELF);
// Returns TRUE if the creature is busy talking or interacting
// with a placeable.
int GetIsBusyWithAnimation(object oCreature);
// Get a random nearby friend.
// OBJECT_INVALID will be returned if the friend is a PC,
// is busy with another animation, is in conversation or combat,
// or is further away than the distance limit.
//
object GetRandomFriend(float fMaxDistance);
// Get a random nearby object within the specified distance with
// the specified tag.
object GetRandomObjectByTag(string sTag, float fMaxDistance);
// Get a random nearby object within the specified distance with
// the specified type.
// nObjType: Any of the OBJECT_TYPE_* constants
object GetRandomObjectByType(int nObjType, float fMaxDistance);
// Get a random "NW_STOP" object in the area.
// If fMaxDistance is non-zero, will return OBJECT_INVALID
// if the stop is too far away.
// The first time this is called in a given area, it cycles
// through all the stops in the area and stores them.
object GetRandomStop(float fMaxDistance);
// Check for a waypoint marked NW_HOME in the area; if it
// exists, mark it as the caller's home waypoint.
void SetCreatureHomeWaypoint();
// Get a creature's home waypoint; returns OBJECT_INVALID if none set.
object GetCreatureHomeWaypoint();
// Set a specific creature (or OBJECT_INVALID to clear) as the caller's "friend"
void SetCurrentFriend(object oFriend);
// Get the caller's current friend, if set; OBJECT_INVALID otherwise
object GetCurrentFriend();
// Set an object (or OBJECT_INVALID to clear) as the caller's interactive
// target.
void SetCurrentInteractionTarget(object oTarget);
// Get the caller's current interaction target, if set; OBJECT_INVALID otherwise
object GetCurrentInteractionTarget();
// Mark the caller as civilized based on its racialtype.
// This will not unset the NW_ANIM_FLAG_IS_CIVILIZED flag
// if it was set outside.
void CheckIsCivilized();
// Check to see if we should switch on detect/stealth mode
void CheckCurrentModes();
// Check if the creature should be active and turn off if not,
// returning FALSE. This respects the NW_ANIM_FLAG_CONSTANT
// setting.
int CheckIsAnimActive(object oCreature);
// Check to see if we're in the middle of some action
// so we don't interrupt or pile actions onto the queue.
// Returns TRUE if in the middle of an action, FALSE otherwise.
int CheckCurrentAction();
// General initialization for animations.
// Called from all the Play_* functions.
void AnimInitialization();
/**********************************************************************
* MASTER ANIMATION FUNCTIONS
* These are the functions called from OnSpawn/OnHeartbeat scripts
* based on the appropriate spawn-in conditions.
**********************************************************************/
// This function should be used for mobile NPCs and monsters
// other than avian ones. It should be called by the creature
// that you want to perform the animations.
//
// Creatures will move randomly between objects in their
// area that have the tag "NW_STOP". Injured creatures will
// go to the nearest "NW_SAFE" waypoint and rest there.
// If at any point a creature gets to an "NW_DETECT" or
// "NW_STEALTH" waypoint, they will toggle on/off detect or
// stealth mode as appropriate.
//
// Humanoid creatures will also perform the following actions
// (you can set the NW_ANIM_FLAG_IS_CIVILIZED flag in script
// on non-humanoid creatures to make them use these behaviors):
//
// Creatures who are spawned in an area with the "NW_HOME" tag
// will mark that area as their home, leave during the day,
// and return at night.
//
// Creatures who are spawned in an outdoor area (for instance,
// in city streets) will go inside areas that have one of the
// interior waypoints (NW_TAVERN, NW_SHOP), if those areas
// are connected by an unlocked door. They will come back out
// as well.
//
// Mobile creatures will also have all the behaviors of immobile
// creatures, just tending to move around more.
//
void PlayMobileAmbientAnimations_NonAvian();
// Avian creatures will fly around randomly.
void PlayMobileAmbientAnimations_Avian();
// This function should be used for any NPCs that should
// not move around. It should be called by the creature
// that you want to perform the animations.
//
// Creatures who call this function will never leave the
// area they spawned in.
//
// Injured creatures will rest at their starting location.
//
// Creatures who have the NW_ANIM_FLAG_IS_MOBILE_CLOSE_RANGE
// flag set will move around slightly within the area.
// Creatures in an area with an "interior" waypoint (NW_HOME,
// NW_SHOP, NW_TAVERN) will be set to have this flag automatically.
//
// Close-range creatures will move around the area, frequently
// returning to their starting point, interacting with other
// creatures and placeables. They will visit NW_STOP waypoints
// in their immediate vicinity, and they will close opened doors.
//
// In all other cases, the creature will not move from its starting
// position. They will turn around randomly, turn to and 'talk' to
// other NPCs in their immediate vicinity, and interact with
// placeables in their immediate vicinity.
//
void PlayImmobileAmbientAnimations();
/**********************************************************************
* ANIM ACTION FUNCTIONS
* These functions are scripted, but they use the hardcoded "Action"
* functions to enter activities into the action queue. They assume
* that the caller is a valid creature.
**********************************************************************/
// Perform a strictly immobile action.
// Includes:
// - play a random animation
// - turn towards a nearby unoccupied friend and 'talk'
// - turn towards a nearby placeable and interact
// - turn around randomly
void AnimActionPlayRandomImmobile();
// Perform a random close-range action.
// This will include:
// - go to a nearby placeable and interact with it
// - go to a nearby friend and interact with them
// - play a random animation
// - walk to a nearby 'NW_STOP' waypoint
// - close an open door and return
// - go back to starting position
// - fall through to ActionPlayRandomImmobile
void AnimActionPlayRandomCloseRange();
// Perform a mobile action.
// Includes:
// - walk to an 'NW_STOP' waypoint in the area
// - walk to an area door and possibly go inside
// - go outside if previously went inside
// - fall through to ActionPlayRandomCloseRange
void AnimActionPlayRandomMobile();
// Perform a mobile action for an uncivilized creature.
// Includes:
// - perform random limited animations
// - walk to an 'NW_STOP' waypoint in the area
// - random walk if none available
void AnimActionPlayRandomUncivilized();
// Start interacting with a placeable object
void AnimActionStartInteracting(object oPlaceable);
// Stop interacting with a placeable object
void AnimActionStopInteracting();
// Start talking with a friend
void AnimActionStartTalking(object oFriend, int nHDiff=0);
// Stop talking to the given friend
void AnimActionStopTalking(object oFriend, int nHDiff=0);
// Play a greeting animation and possibly voicechat.
// If a negative difference is passed in, caller will bow.
void AnimActionPlayRandomGreeting(int nHDiff);
// Play a random farewell animation and possibly voicechat.
// If a negative difference is passed in, caller will bow.
void AnimActionPlayRandomGoodbye(int nHDiff);
// Randomly move away from an object the specified distance.
// This is mainly because ActionMoveAwayFromLocation isn't working.
void AnimActionRandomMoveAway(object oSource, float fDistance);
// Play animation of shaking head "no" to left and right
void AnimActionShakeHead();
// Play animation of looking around to left and right
void AnimActionLookAround();
// Turn around to face a random direction
void AnimActionTurnAround();
// Interact with a placeable object.
// This will activate/deactivate the placeable object if a valid
// one is passed in.
// KLUDGE: If a placeable object without an inventory should
// still be opened/shut instead of de/activated, set
// its Will Save to 1.
void AnimActionPlayRandomInteractAnimation(object oPlaceable);
// Play a random talk gesture animation.
// If a hit dice difference (should be the hit dice of the talker
// minus the hit dice of the person being talked to) is passed in,
// slightly different animations will play based on this.
void AnimActionPlayRandomTalkAnimation(int nHDiff);
// Play a random animation that all creatures should have.
// This is a very small set.
// Currently only has: get mid, taunt
void AnimActionPlayRandomBasicAnimation();
// Play a random animation.
// This animation will be chosen from a different set
// based on whether a special waypoint or placeable
// is in the vicinity.
void AnimActionPlayRandomAnimation();
/**********************************************************************
* The following AnimAction functions are special, because they may fail
* (for instance, AnimActionsSitInChair() will only work if an actual
* chair object was found to sit in).
*
* They all return TRUE on success, FALSE on failure. This allows for
* trying an action and doing something else if it failed.
*
* Unfortunately, that means they cannot be easily used with
* DelayCommand / AssignAction, but the tradeoff is worth it, IMO.
**********************************************************************/
// If there's an open door nearby, possibly go close it,
// then come back to our current spot.
// Returns TRUE on success, FALSE on failure.
int AnimActionCloseRandomDoor();
// Sit in a random nearby chair if available.
// Looks for items with tag: NW_SEAT
// Returns TRUE on success, FALSE on failure.
int AnimActionSitInChair(float fMaxDistance);
// Get up from a chair if we're sitting.
// Returns TRUE on success, FALSE on failure.
int AnimActionGetUpFromChair();
// Go through a nearby door if appropriate.
// This will be done if the door is unlocked and
// the area the door leads to contains a waypoint
// with one of these tags:
// NW_TAVERN, NW_SHOP
// Returns TRUE on success, FALSE on failure.
int AnimActionGoInside();
// Leave area if appropriate.
// This only works for NPCs that entered an area that
// has a waypoint with one of these tags:
// NW_TAVERN, NW_SHOP
// If the NPC entered through a door, they will exit through
// that door.
// Returns TRUE on success, FALSE on failure.
int AnimActionGoOutside();
// Go to a nearby waypoint or placeable marked with the
// tag "NW_STOP".
// Returns TRUE on success, FALSE on failure.
int AnimActionGoToStop(float fMaxDistance=20.0);
// Find a friend within the given distance and talk to them.
// Returns TRUE on success, FALSE on failure.
int AnimActionFindFriend(float fMaxDistance);
// Find a placeable within the given distance and interact
// with it.
// Returns TRUE on success, FALSE on failure.
int AnimActionFindPlaceable(float fMaxDistance);
// If injured and mobile, find the nearest NW_SAFE waypoint,
// go to it, and rest. If injured and immobile, go to starting
// location if not already there, and rest.
// Returns TRUE on success, FALSE on failure.
int AnimActionRest();
// If it is night, go back to our home waypoint, if we have one.
// This is only meaningful for mobile NPCs who would have left
// their homes during the day.
// Returns TRUE on success, FALSE on failure.
int AnimActionGoHome();
// If it is day, leave our home area, if we have one.
// This is only meaningful for mobile NPCs.
// Returns TRUE on success, FALSE on failure.
int AnimActionLeaveHome();
// If a PC is in the NPC's home and has not been challenged before,
// challenge them.
// This involves speaking a one-liner conversation from the
// conversation file ANIM_CONVERSATION, set above.
int AnimActionChallengeIntruder();
/**********************************************************************
* FUNCTION DEFINITIONS
**********************************************************************/
// Debugging function. Will be commented out for final.
void AnimDebug(string sMsg)
{
//ActionSpeakString("ANIM: " + GetName(OBJECT_SELF) + " " + sMsg);
//PrintString("ANIM: " + GetName(OBJECT_SELF) + ": " + sMsg);
}
// TRUE if the given creature has the given condition set
int GetAnimationCondition(int nCondition, object oCreature=OBJECT_SELF)
{
return (GetLocalInt(oCreature, sAnimCondVarname) & nCondition);
}
// Mark that the given creature has the given condition set
void SetAnimationCondition(int nCondition, int bValid=TRUE, object oCreature=OBJECT_SELF)
{
int nCurrentCond = GetLocalInt(oCreature, sAnimCondVarname);
if (bValid) {
SetLocalInt(oCreature, sAnimCondVarname, nCurrentCond | nCondition);
} else {
SetLocalInt(oCreature, sAnimCondVarname, nCurrentCond & ~nCondition);
}
}
// Returns TRUE if the creature is busy talking or interacting
// with a placeable.
int GetIsBusyWithAnimation(object oCreature)
{
int bReturn = GetAnimationCondition(NW_ANIM_FLAG_IS_TALKING, oCreature)
|| GetAnimationCondition(NW_ANIM_FLAG_IS_INTERACTING, oCreature)
|| GetCurrentAction(oCreature) != ACTION_INVALID;
// if (bReturn == TRUE) AssignCommand(oCreature, SpeakString("Busy with anim"));
return bReturn;
}
// Get a random nearby friend within the specified distance limit,
// that isn't busy doing something else.
object GetRandomFriend(float fMaxDistance)
{
object oFriend = GetNearestCreature(CREATURE_TYPE_REPUTATION,
REPUTATION_TYPE_FRIEND,
OBJECT_SELF, d2(),
CREATURE_TYPE_PERCEPTION,
PERCEPTION_SEEN);
if (GetIsObjectValid(oFriend)
&& !GetIsPC(oFriend)
//&& !GetIsBusyWithAnimation(oFriend) BK Feb 2003: There's not enough talking happening
&& GetAnimationCondition(NW_ANIM_FLAG_IS_ACTIVE, oFriend)
&& !IsInConversation(oFriend)
&& !GetIsInCombat(oFriend)
&& GetDistanceToObject(oFriend) <= fMaxDistance)
{
return oFriend;
}
return OBJECT_INVALID;
}
// Get a random nearby object within the specified distance with
// the specified tag.
object GetRandomObjectByTag(string sTag, float fMaxDistance)
{
int nNth;
if (fMaxDistance == DISTANCE_SHORT) {
nNth = d2();
} else if (fMaxDistance == DISTANCE_MEDIUM) {
nNth = d4();
} else {
nNth = d6();
}
object oObj = GetNearestObjectByTag(sTag, OBJECT_SELF, nNth);
if (GetIsObjectValid(oObj) && GetDistanceToObject(oObj) <= fMaxDistance)
return oObj;
return OBJECT_INVALID;
}
// Get a random nearby object within the specified distance with
// the specified type.
// nObjType: Any of the OBJECT_TYPE_* constants
object GetRandomObjectByType(int nObjType, float fMaxDistance)
{
int nNth;
if (fMaxDistance == DISTANCE_SHORT) {
nNth = d2();
} else if (fMaxDistance == DISTANCE_LARGE) {
nNth = d4();
} else {
nNth = d6();
}
//AnimDebug("looking for random object: " + IntToString(nNth));
object oObj = GetNearestObject(nObjType, OBJECT_SELF, nNth);
if (GetIsObjectValid(oObj) && GetDistanceToObject(oObj) <= fMaxDistance)
return oObj;
return OBJECT_INVALID;
}
// Get a random "NW_STOP" object in the area.
// If fMaxDistance is non-zero, will return OBJECT_INVALID
// if the stop is too far away.
// The first time this is called in a given area, it cycles
// through all the stops in the area and stores them.
object GetRandomStop(float fMaxDistance)
{
object oStop;
object oArea = GetArea(OBJECT_SELF);
if (! GetLocalInt(oArea, "ANIM_STOPS_INITIALIZED") ) {
//AnimDebug("Initializing stops in area " + GetName(oArea));
// first time -- look up all the stops in the area and store them
int nNth = 1;
oStop = GetNearestObjectByTag("NW_STOP");
while (GetIsObjectValid(oStop)) {
//AnimDebug("Stop found");
SetLocalObject(oArea, "ANIM_STOP_" + IntToString(nNth), oStop);
nNth++;
oStop = GetNearestObjectByTag("NW_STOP", OBJECT_SELF, nNth);
}
SetLocalInt(oArea, "ANIM_STOPS", nNth-1);
SetLocalInt(oArea, "ANIM_STOPS_INITIALIZED", TRUE);
}
int nStop = Random(GetLocalInt(oArea, "ANIM_STOPS")) + 1;
oStop = GetLocalObject(oArea, "ANIM_STOP_" + IntToString(nStop));
//AnimDebug("Stop: " + IntToString(nStop)
// + ": " + GetTag(oStop)
// + ": " + FloatToString(GetDistanceToObject(oStop)));
if (GetIsObjectValid(oStop) && GetDistanceToObject(oStop) <= fMaxDistance)
return oStop;
return OBJECT_INVALID;
}
// Check for a waypoint marked NW_HOME in the area; if it
// exists, mark it as the caller's home waypoint.
void SetCreatureHomeWaypoint()
{
object oHome = GetNearestObjectByTag("NW_HOME");
if (GetIsObjectValid(oHome)) {
SetAnimationCondition(NW_ANIM_FLAG_HAS_HOME);
SetLocalObject(OBJECT_SELF, "NW_ANIM_HOME", oHome);
}
}
// Get a creature's home waypoint; returns OBJECT_INVALID if none set.
object GetCreatureHomeWaypoint()
{
if (GetAnimationCondition(NW_ANIM_FLAG_HAS_HOME)) {
return GetLocalObject(OBJECT_SELF, "NW_ANIM_HOME");
}
return OBJECT_INVALID;
}
// Set a specific creature (or OBJECT_INVALID to clear) as the caller's "friend"
void SetCurrentFriend(object oFriend)
{
if (!GetIsObjectValid(oFriend)) {
DeleteLocalObject(OBJECT_SELF, "NW_ANIM_FRIEND");
} else {
SetLocalObject(OBJECT_SELF, "NW_ANIM_FRIEND", oFriend);
}
}
// Get the caller's current friend, if set; OBJECT_INVALID otherwise
object GetCurrentFriend()
{
return GetLocalObject(OBJECT_SELF, "NW_ANIM_FRIEND");
}
// Set an object (or OBJECT_INVALID to clear) as the caller's interactive
// target.
void SetCurrentInteractionTarget(object oTarget)
{
if (!GetIsObjectValid(oTarget)) {
DeleteLocalObject(OBJECT_SELF, "NW_ANIM_TARGET");
} else {
SetLocalObject(OBJECT_SELF, "NW_ANIM_TARGET", oTarget);
}
}
// Get the caller's current interaction target, if set; OBJECT_INVALID otherwise
object GetCurrentInteractionTarget()
{
return GetLocalObject(OBJECT_SELF, "NW_ANIM_TARGET");
}
// Mark the caller as civilized based on its racialtype.
// This will not unset the NW_ANIM_FLAG_IS_CIVILIZED flag
// if it was set outside.
void CheckIsCivilized()
{
int nRacialType = GetRacialType(OBJECT_SELF);
switch (nRacialType) {
case RACIAL_TYPE_ELF :
case RACIAL_TYPE_GNOME :
case RACIAL_TYPE_HALFELF :
case RACIAL_TYPE_HALFLING :
case RACIAL_TYPE_HALFORC :
case RACIAL_TYPE_HUMAN :
case RACIAL_TYPE_HUMANOID_GOBLINOID :
case RACIAL_TYPE_HUMANOID_REPTILIAN :
case RACIAL_TYPE_HUMANOID_ORC:
SetAnimationCondition(NW_ANIM_FLAG_IS_CIVILIZED);
}
}
// Check to see if we should switch on detect/stealth mode
void CheckCurrentModes()
{
//wSpeakString("running check current modes");
object oWay = GetNearestObject(OBJECT_TYPE_WAYPOINT);
string sTag = GetTag(oWay);
if (sTag == "NW_STEALTH")
{
if (GetModeActive(NW_MODE_STEALTH))
{
// turn off stealth mode
SetModeActive(NW_MODE_STEALTH, FALSE);
}
else
{
// turn on stealth mode
SetModeActive(NW_MODE_STEALTH);
}
}
else if (sTag == "NW_DETECT")
{
if (GetModeActive(NW_MODE_DETECT))
{
// turn off detect mode
SetModeActive(NW_MODE_DETECT);
}
else
{
// turn on detect mode
SetModeActive(NW_MODE_DETECT);
}
}
}
// Check if the creature should be active and turn off if not,
// returning FALSE. This respects the NW_ANIM_FLAG_CONSTANT
// setting.
int CheckIsAnimActive(object oCreature)
{
// Unless we're set to be constant, turn off if there's
// no PC in the area
if ( ! GetAnimationCondition(NW_ANIM_FLAG_CONSTANT)) {
object oPC = GetNearestCreature(CREATURE_TYPE_PLAYER_CHAR,
PLAYER_CHAR_IS_PC);
if ( !GetIsObjectValid(oPC) || GetArea(oPC) != GetArea(OBJECT_SELF)) {
// turn off
SetAnimationCondition(NW_ANIM_FLAG_IS_ACTIVE, FALSE);
return FALSE;
}
}
return TRUE;
}
// Check to see if we're in the middle of some action
// so we don't interrupt or pile actions onto the queue.
// Returns TRUE if in the middle of an action, FALSE otherwise.
int CheckCurrentAction()
{
int nAction = GetCurrentAction();
if (nAction == ACTION_SIT) {
// low prob of getting up, so we don't bop up and down constantly
if (Random(10) == 0) {
AnimActionGetUpFromChair();
}
return TRUE;
} else if (nAction != ACTION_INVALID) {
// we're doing *something*, don't switch
//AnimDebug("performing action");
return TRUE;
}
return FALSE;
}
// General initialization for animations.
// Called from all the Play_* functions.
void AnimInitialization()
{
// If we've been set to be constant, flag us as
// active.
// if (GetAnimationCondition(NW_ANIM_FLAG_CONSTANT))
SetAnimationCondition(NW_ANIM_FLAG_IS_ACTIVE);
// Set our home, if we have one
SetCreatureHomeWaypoint();
// Mark whether we're civilized or not
CheckIsCivilized();
SetAnimationCondition(NW_ANIM_FLAG_INITIALIZED);
}
// This function should be used for mobile NPCs and monsters
// other than avian ones. It should be called by the creature
// that you want to perform the animations.
//
// Creatures will interact with each other and move around,
// possibly even moving between areas.
//
// Creatures who are spawned in an area with the "NW_HOME" tag
// will mark that area as their home, leave from the nearest
// door during the day, and return at night.
//
// Injured creatures will go to the nearest "NW_SAFE" waypoint
// in their immediate area and rest there.
//
// If at any point the nearest waypoint is "NW_DETECT" or
// "NW_STEALTH", the creature will toggle search/stealth mode
// respectively.
//
// Creatures who are spawned in an outdoor area (for instance,
// in city streets) will go inside areas that have one of the
// interior waypoints (NW_TAVERN, NW_SHOP), if those areas
// are connected by an unlocked door. They will come back out
// as well.
//
// Creatures will also move randomly between objects in their
// area that have the tag "NW_STOP".
//
// Mobile creatures will have all the same behaviors as immobile
// creatures, just tending to move around more.
void PlayMobileAmbientAnimations_NonAvian()
{
if (!GetAnimationCondition(NW_ANIM_FLAG_INITIALIZED)) {
// General initialization
AnimInitialization();
// Mark us as mobile
SetAnimationCondition(NW_ANIM_FLAG_IS_MOBILE);
}
// Short-circuit everything if we're not active yet
if (!GetAnimationCondition(NW_ANIM_FLAG_IS_ACTIVE))
return;
//AnimDebug("currently active");
// Check if we should turn off
if (!CheckIsAnimActive(OBJECT_SELF))
return;
//AnimDebug("staying active");
//SpawnScriptDebugger();
int nCurrentAction = GetCurrentAction();
// Check current actions so we don't interrupt something in progress
// Feb 14 2003: Because of the random walkthere needs to be a chance
// to stop walking.
// May 26 2004: Added ACTION_RANDOMWALK to the exclusion list.
if (CheckCurrentAction() && (nCurrentAction != ACTION_MOVETOPOINT)&& (nCurrentAction != ACTION_WAIT) && (nCurrentAction != ACTION_RANDOMWALK)) {
return;
}
// Go someplace safe and rest if we are hurt
if (AnimActionRest()) {
//AnimDebug("resting");
return;
}
// Check if current modes should change
CheckCurrentModes();
//UseStealthMode();
//UseDetectMode();
int bIsCivilized = GetAnimationCondition(NW_ANIM_FLAG_IS_CIVILIZED);
if (bIsCivilized)
{
// Challenge an intruding PC
if (AnimActionChallengeIntruder()) {
return;
}
// Check if we should go home
if (AnimActionGoHome()) {
//AnimDebug("going home");
return;
}
// Check if we should leave home
if (AnimActionLeaveHome()) {
//AnimDebug("leaving home");
return;
}
// Otherwise, do something random
AnimActionPlayRandomMobile();
} else
{
//AnimDebug("uncivilized");
AnimActionPlayRandomUncivilized();
}
}
// Avian creatures will fly around randomly.
void PlayMobileAmbientAnimations_Avian()
{
int nRoll = d4();
object oFriend = GetNearestCreature(CREATURE_TYPE_REPUTATION,
REPUTATION_TYPE_FRIEND,
OBJECT_SELF,
nRoll,
CREATURE_TYPE_PERCEPTION,
PERCEPTION_SEEN);
ClearActions(CLEAR_X0_I0_ANIMS_PlayMobile);
if(GetIsObjectValid(oFriend)) {
int nBird = d4();
if(nBird == 1) {
ActionMoveToObject(oFriend, TRUE);
} else if (nBird == 2 || nBird == 3) {
AnimActionRandomMoveAway(oFriend, 100.0);
} else {
effect eBird = EffectDisappearAppear(GetLocation(oFriend));
ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eBird, OBJECT_SELF, 4.0);
AnimActionRandomMoveAway(oFriend, 100.0);
}
} else {
ActionRandomWalk();
}
}
// This function should be used for any NPCs that should
// not move around. It should be called by the creature
// that you want to perform the animations.
//
// Creatures who call this function will never leave the
// area they spawned in.
//
// Injured creatures will rest at their starting location.
//
// Creatures who have the NW_ANIM_FLAG_IS_MOBILE_CLOSE_RANGE
// flag set will move around slightly within the area.
// Creatures in an area with an "interior" waypoint (NW_HOME,
// NW_SHOP, NW_TAVERN) will be set to have this flag automatically.
//
// Close-range creatures will move around the area, frequently
// returning to their starting point, interacting with other
// creatures and placeables. They will visit NW_STOP waypoints
// in their immediate vicinity, and they will close opened doors.
//
// In all other cases, the creature will not move from its starting
// position. They will turn around randomly, turn to and 'talk' to
// other NPCs in their immediate vicinity, and interact with
// placeables in their immediate vicinity.
//
void PlayImmobileAmbientAnimations()
{
if (!GetAnimationCondition(NW_ANIM_FLAG_INITIALIZED)) {
// General initialization
AnimInitialization();
// if we are at home, make us mobile in close-range
if (GetIsObjectValid(GetCreatureHomeWaypoint())) {
SetAnimationCondition(NW_ANIM_FLAG_IS_MOBILE_CLOSE_RANGE);
}
// also save our starting location
SetLocalLocation(OBJECT_SELF,
"ANIM_START_LOCATION",
GetLocation(OBJECT_SELF));
}
// Short-circuit everything if we're not active yet
if (!GetAnimationCondition(NW_ANIM_FLAG_IS_ACTIVE))
return;
//AnimDebug("currently active");
// Check if we should turn off
if (!CheckIsAnimActive(OBJECT_SELF))
return;
//AnimDebug("staying active");
// Check current actions so we don't interrupt something in progress
if (CheckCurrentAction()) {
return;
}
// First check: go back to starting position and rest if we are hurt
if (AnimActionRest()) {
//AnimDebug("resting");
return;
}
// Check if current modes should change
CheckCurrentModes();
// Challenge an intruding PC
if (AnimActionChallengeIntruder()) {
return;
}
int bIsCivilized = GetAnimationCondition(NW_ANIM_FLAG_IS_CIVILIZED);
if (GetAnimationCondition(NW_ANIM_FLAG_IS_MOBILE_CLOSE_RANGE)) {
//AnimDebug("close range");
AnimActionPlayRandomCloseRange();
} else {
//AnimDebug("immobile");
AnimActionPlayRandomImmobile();
}
}
// Perform a strictly immobile action.
// Includes:
// - turn towards a nearby unoccupied friend and 'talk'
// - turn towards a nearby placeable and interact
// - turn around randomly
// - play a random animation
void AnimActionPlayRandomImmobile()
{
int nRoll = Random(12);
//SpawnScriptDebugger();
// If we're talking, either keep going or stop.
// Low prob of stopping, since both parties have
// a chance and conversations are cool.
if (GetAnimationCondition(NW_ANIM_FLAG_IS_TALKING)) {
object oFriend = GetCurrentFriend();
int nHDiff = GetHitDice(OBJECT_SELF) - GetHitDice(oFriend);
if (nRoll == 0) {
AnimActionStopTalking(oFriend, nHDiff);
} else {
AnimActionPlayRandomTalkAnimation(nHDiff);
}
return;
}
// If we're interacting with a placeable, either keep going or
// stop. High probability of stopping, since looks silly to
// constantly turn something on-and-off.
if (GetAnimationCondition(NW_ANIM_FLAG_IS_INTERACTING)) {
if (nRoll < 4) {
AnimActionStopInteracting();
} else {
AnimActionPlayRandomInteractAnimation(GetCurrentInteractionTarget());
}
return;
}
// If we got here, we're not busy at the moment.
// Clean out the action queue
ClearActions(CLEAR_X0_I0_ANIMS_PlayRandomMobile);
if (nRoll <=9) {
if (AnimActionFindFriend(DISTANCE_LARGE))
return;
}
if (nRoll > 9) {
// Try and interact with a nearby placeable
if (AnimActionFindPlaceable(DISTANCE_SHORT))
return;
}
// Default: clear our action queue and play a random animation
if ( nRoll < 5 ) {
// Turn around and play a random animation
// BK Feb 2003: I got rid of this because I've never seen it look appropriate
// it always looks out of place and unrealistic
AnimActionTurnAround();
AnimActionPlayRandomAnimation();
} else {
// Just play a random animation
AnimActionPlayRandomAnimation();
}
}
// Perform a random close-range action.
// This will include:
// - any of the immobile actions
// - close any nearby doors, then return to current position
// - go to a nearby placeable and interact with it
// - go to a nearby friend and interact with them
// - walk to a nearby 'NW_STOP' waypoint
// - going back to starting point
void AnimActionPlayRandomCloseRange()
{
if (GetIsBusyWithAnimation(OBJECT_SELF)) {
// either we're already in conversation or
// interacting with something, so continue --
// all handled already in RandomImmobile.
AnimActionPlayRandomImmobile();
return;
}
// If we got here, we're not busy
// Clean out the action queue
ClearActions(CLEAR_X0_I0_ANIMS_PlayRandomCloseRange1);
// Possibly close open doors
if (GetAnimationCondition(NW_ANIM_FLAG_CLOSE_DOORS) && AnimActionCloseRandomDoor()) {
return;
}
// For the rest of these, we check for specific rolls,
// to ensure that we don't do a lot of lookups on any one
// given pass.
int nRoll = Random(6);
// Possibly start talking to a friend
if (nRoll == 0 || nRoll == 1) {
if (AnimActionFindFriend(DISTANCE_LARGE))
return;
// fall through to default
}
// Possibly start fiddling with a placeable
if (nRoll == 2) {
if (AnimActionFindPlaceable(DISTANCE_LARGE))
return;
// fall through if no placeable found
}
// Possibly sit down
if (nRoll == 3) {
if (AnimActionSitInChair(DISTANCE_LARGE))
return;
}
// Go to a nearby stop
if (nRoll == 4) {
if (AnimActionGoToStop(DISTANCE_LARGE)) {
return;
}
// No stops, so do a random walk and then come back
// to our current location
ClearActions(CLEAR_X0_I0_ANIMS_PlayRandomCloseRange2);
location locCurr = GetLocation(OBJECT_SELF);
ActionRandomWalk();
ActionMoveToLocation(locCurr);
}
if (nRoll == 5 && !GetAnimationCondition(NW_ANIM_FLAG_IS_MOBILE)) {
// Move back to starting point, saved at initialization
ActionMoveToLocation(GetLocalLocation(OBJECT_SELF,
"ANIM_START_LOCATION"));
return;
}
// Default: do a random immobile animation
AnimActionPlayRandomImmobile();
}
// Perform a mobile action.
// Includes:
// - walk to an 'NW_STOP' waypoint in the area
// - walk to an area door and possibly go inside
// - go outside if previously went inside
// - fall through to AnimActionPlayRandomCloseRange
void AnimActionPlayRandomMobile()
{
if (GetIsBusyWithAnimation(OBJECT_SELF)) {
// either we're already in conversation or
// interacting with something, so continue --
// all handled already in RandomImmobile.
AnimActionPlayRandomImmobile();
return;
}
// If we got here, we're not busy
// Clean out the action queue
ClearActions(CLEAR_X0_I0_ANIMS_AnimActionPlayRandomMobile1);
int nRoll = Random(9);
if (nRoll == 0) {
// If we're inside, possibly leave
if (AnimActionGoOutside())
return;
}
if (nRoll == 1) {
// Possibly go into an interior area
if (AnimActionGoInside())
return;
}
// If we fell through or got a random number
// less than 7, go to a stop waypoint, or random
// walk if no stop waypoints were found.
if (nRoll < 5) {
// Pass in a huge number so any stop will be valid
if (AnimActionGoToStop(1000.0))
return;
// If no stops, do a random walk
ClearActions(CLEAR_X0_I0_ANIMS_AnimActionPlayRandomMobile2);
ActionRandomWalk();
return;
}
// Default: do something close-range
// AnimActionPlayRandomCloseRange();
// MODIFIED February 14 2003. Will play an immobile animation, if nothing else found to do
PlayImmobileAmbientAnimations();
}
// Perform a mobile action for an uncivilized creature.
// Includes:
// - perform random limited animations
// - walk to an 'NW_STOP' waypoint in the area
// - random walk if none available
void AnimActionPlayRandomUncivilized()
{
int nRoll = Random(6);
if (nRoll != 5) {
if (AnimActionGoToStop(1000.0))
return;
// no stops, so random walk
ClearActions(CLEAR_X0_I0_ANIMS_AnimActionPlayRandomUncivilized);
ActionRandomWalk();
}
// Play one of our few random animations
AnimActionPlayRandomBasicAnimation();
}
/**********************************************************************
**********************************************************************
* NOTE * NOTE * NOTE * NOTE * NOTE * NOTE * NOTE * NOTE * NOTE * NOTE
* The functions below here are building blocks used in the main
* functions above.
* NOTE * NOTE * NOTE * NOTE * NOTE * NOTE * NOTE * NOTE * NOTE * NOTE
**********************************************************************
**********************************************************************/
// Start interacting with a placeable object
void AnimActionStartInteracting(object oPlaceable)
{
SetAnimationCondition(NW_ANIM_FLAG_IS_INTERACTING);
if (GetAnimationCondition(NW_ANIM_FLAG_IS_MOBILE)
|| GetAnimationCondition(NW_ANIM_FLAG_IS_MOBILE_CLOSE_RANGE))
{
ActionMoveToObject(oPlaceable, FALSE, DISTANCE_TINY);
}
ActionDoCommand(SetFacingPoint(GetPosition(oPlaceable)));
SetCurrentInteractionTarget(oPlaceable);
AnimActionPlayRandomInteractAnimation(oPlaceable);
}
// Stop interacting with a placeable object
void AnimActionStopInteracting()
{
if (GetAnimationCondition(NW_ANIM_FLAG_IS_MOBILE)) {
AnimActionRandomMoveAway(GetCurrentInteractionTarget(), DISTANCE_LARGE);
}
SetCurrentInteractionTarget(OBJECT_INVALID);
SetAnimationCondition(NW_ANIM_FLAG_IS_INTERACTING, FALSE);
AnimActionTurnAround();
AnimActionPlayRandomAnimation();
}
// Start talking with a friend
void AnimActionStartTalking(object oFriend, int nHDiff=0)
{
//AnimDebug("started talking to " + GetName(oFriend));
object oMe = OBJECT_SELF;
// Say hello and move to each other if we're not immobile
if (GetAnimationCondition(NW_ANIM_FLAG_IS_MOBILE)
|| GetAnimationCondition(NW_ANIM_FLAG_IS_MOBILE_CLOSE_RANGE))
{
ActionMoveToObject(oFriend, FALSE, DISTANCE_TINY);
AnimActionPlayRandomGreeting(nHDiff);
}
if (GetAnimationCondition(NW_ANIM_FLAG_IS_MOBILE, oFriend)
|| GetAnimationCondition(NW_ANIM_FLAG_IS_MOBILE_CLOSE_RANGE, oFriend))
{
AssignCommand(oFriend,
ActionMoveToObject(oMe, FALSE, DISTANCE_TINY));
AssignCommand(oFriend, AnimActionPlayRandomGreeting(0 - nHDiff));
}
SetCurrentFriend(oFriend);
AssignCommand(oFriend, SetCurrentFriend(oMe));
ActionDoCommand(SetFacingPoint(GetPosition(oFriend)));
AssignCommand(oFriend, ActionDoCommand(SetFacingPoint(GetPosition(oMe))));
SetAnimationCondition(NW_ANIM_FLAG_IS_TALKING);
SetAnimationCondition(NW_ANIM_FLAG_IS_TALKING, TRUE, oFriend);
}
// Stop talking to the given friend
void AnimActionStopTalking(object oFriend, int nHDiff=0)
{
//AnimDebug("stopped talking to " + GetName(oFriend));
object oMe = OBJECT_SELF;
// Say goodbye and move away if we're not immobile
if (GetAnimationCondition(NW_ANIM_FLAG_IS_MOBILE)) {
AnimActionPlayRandomGoodbye(nHDiff);
AnimActionRandomMoveAway(oFriend, DISTANCE_LARGE);
} else {
AnimActionTurnAround();
AnimActionPlayRandomAnimation();
}
if (GetAnimationCondition(NW_ANIM_FLAG_IS_MOBILE, oFriend)) {
AssignCommand(oFriend, AnimActionPlayRandomGoodbye(0 - nHDiff));
AssignCommand(oFriend,
AnimActionRandomMoveAway(oMe, DISTANCE_HUGE));
} else {
AssignCommand(oFriend, AnimActionTurnAround());
AssignCommand(oFriend, AnimActionPlayRandomAnimation());
}
SetAnimationCondition(NW_ANIM_FLAG_IS_TALKING, FALSE);
SetAnimationCondition(NW_ANIM_FLAG_IS_TALKING, FALSE, oFriend);
}
// Play a greeting animation and possibly voicechat.
// If a negative hit dice difference (HD caller - HD greeted) is
// passed in, the caller will bow.
void AnimActionPlayRandomGreeting(int nHDiff=0)
{
if (Random(2) == 0 && GetAnimationCondition(NW_ANIM_FLAG_CHATTER)) {
VoiceHello();
}
if (nHDiff < 0 || Random(4) == 0)
ActionPlayAnimation(ANIMATION_FIREFORGET_BOW);
else
ActionPlayAnimation(ANIMATION_FIREFORGET_GREETING);
}
// Play a random farewell animation and possibly voicechat.
// If a negative hit dice difference is passed in, the
// caller will bow.
void AnimActionPlayRandomGoodbye(int nHDiff)
{
if (Random(2) == 0 && GetAnimationCondition(NW_ANIM_FLAG_CHATTER)) {
VoiceGoodbye();
}
if (nHDiff < 0 || Random(4) == 0)
ActionPlayAnimation(ANIMATION_FIREFORGET_BOW);
else
ActionPlayAnimation(ANIMATION_FIREFORGET_GREETING);
}
// Randomly move away from an object the specified distance.
// This is mainly because ActionMoveAwayFromLocation isn't working.
void AnimActionRandomMoveAway(object oSource, float fDistance)
{
location lTarget = GetRandomLocation(GetArea(OBJECT_SELF),
oSource,
fDistance);
ActionMoveToLocation(lTarget);
}
// Play animation of shaking head "no" to left & right
void AnimActionShakeHead()
{
ActionPlayAnimation(ANIMATION_FIREFORGET_HEAD_TURN_LEFT, 3.0);
ActionPlayAnimation(ANIMATION_FIREFORGET_HEAD_TURN_RIGHT, 3.0);
}
// Play animation of looking to left and right
void AnimActionLookAround()
{
ActionPlayAnimation(ANIMATION_FIREFORGET_HEAD_TURN_LEFT, 0.75);
ActionPlayAnimation(ANIMATION_FIREFORGET_HEAD_TURN_RIGHT, 0.75);
}
// Turn around to face a random direction
void AnimActionTurnAround()
{
// BK Feb 2003: This never looks good. Don't do it.
// ActionDoCommand(SetFacing(IntToFloat(Random(360))));
}
// Go through a door and close it behind you,
// then walk a short distance away.
// This assumes the door exists, is unlocked, etc.
void AnimActionGoThroughDoor(object oDoor)
{
//AnimDebug("going through door " + GetTag(oDoor));
SetLocalInt(oDoor, "BEING_CLOSED", TRUE);
object oDest = GetTransitionTarget(oDoor);
ActionMoveToObject(oDest);
ActionDoCommand(AssignCommand(oDest, ActionCloseDoor(oDest)));
ActionDoCommand(AssignCommand(oDoor, ActionCloseDoor(oDoor)));
ActionDoCommand(SetLocalInt(oDoor, "BEING_CLOSED", FALSE));
DelayCommand(10.0, SetLocalInt(oDoor, "BEING_CLOSED", FALSE));
AnimActionRandomMoveAway(oDest, DISTANCE_MEDIUM);
}
/**********************************************************************
* The following AnimAction functions have a possibility of failing
* and not assigning any actions.
* They return TRUE on success, FALSE on failure. See notes up in the
* prototype section for details.
**********************************************************************/
// If there's an open door nearby, possibly go close it,
// then come back to our current spot.
int AnimActionCloseRandomDoor()
{
if (Random(4) != 0) return FALSE;
int nNth = 1;
object oDoor = GetNearestObject(OBJECT_TYPE_DOOR);
location locCurrent = GetLocation(OBJECT_SELF);
while (GetIsObjectValid(oDoor)) {
// make sure everyone doesn't run to close the same door
if (GetIsOpen(oDoor) && !GetLocalInt(oDoor, "BEING_CLOSED")) {
//AnimDebug("closing door: " + GetTag(oDoor));
SetLocalInt(oDoor, "BEING_CLOSED", TRUE);
ActionCloseDoor(oDoor);
ActionDoCommand(SetLocalInt(oDoor, "BEING_CLOSED", FALSE));
ActionMoveToLocation(locCurrent);
return TRUE;
}// else {
// AnimDebug("closed or being closed: " + GetTag(oDoor));
//}
nNth++;
oDoor = GetNearestObject(OBJECT_TYPE_DOOR, OBJECT_SELF, nNth);
}
return FALSE;
}
// Sit in a random nearby chair if available.
// Looks for items with tag: Chair
int AnimActionSitInChair(float fMaxDistance)
{
object oChair = GetRandomObjectByTag("Chair", fMaxDistance);
if (GetIsObjectValid(oChair) && !GetIsObjectValid(GetSittingCreature(oChair))) {
ActionSit(oChair);
SetAnimationCondition(NW_ANIM_FLAG_IS_INTERACTING);
return TRUE;
}
return FALSE;
}
// Get up from a chair if we're sitting
int AnimActionGetUpFromChair()
{
//AnimDebug("getting up from chair");
if (GetCurrentAction() == ACTION_SIT) {
ClearActions(CLEAR_X0_I0_ANIMS_AnimActionGetUpFromChair);
SetAnimationCondition(NW_ANIM_FLAG_IS_INTERACTING, FALSE);
AnimActionRandomMoveAway(GetNearestObject(OBJECT_TYPE_PLACEABLE), DISTANCE_SHORT);
//AnimDebug("got up from chair");
return TRUE;
}
return FALSE;
}
// Go through a nearby door if appropriate.
// This will be done if the door is unlocked and
// the area the door leads to contains a waypoint
// with one of these tags:
// NW_TAVERN, NW_SHOP
int AnimActionGoInside()
{
// Don't go inside a second area, since we'll never get
// back to our original one if we do that.
if (GetAnimationCondition(NW_ANIM_FLAG_IS_INSIDE)) {
//AnimDebug("is inside already");
return FALSE;
}
object oDoor = GetRandomObjectByType(OBJECT_TYPE_DOOR, 1000.0);
if (!GetIsObjectValid(oDoor) || GetLocked(oDoor)) {
//AnimDebug("Failed to enter door: " + GetTag(oDoor));
return FALSE;
}
object oDest = GetTransitionTarget(oDoor);
//AnimDebug("Destination: " + GetTag(oDest));
object oWay = GetNearestObjectByTag("NW_TAVERN", oDest);
if (!GetIsObjectValid(oWay))
oWay = GetNearestObjectByTag("NW_SHOP", oDest);
if (GetIsObjectValid(oWay)) {
//AnimDebug("Valid waypoint found: " + GetTag(oWay));
AnimActionGoThroughDoor(oDoor);
SetAnimationCondition(NW_ANIM_FLAG_IS_INSIDE);
SetLocalObject(OBJECT_SELF, "NW_ANIM_DOOR", oDest);
return TRUE;
}
return FALSE;
}
// Leave area if appropriate.
// This only works for NPCs that entered an area that
// has a waypoint with one of these tags:
// NW_TAVERN, NW_SHOP
// If the NPC entered through a door, they will exit through
// that door.
int AnimActionGoOutside()
{
if (GetAnimationCondition(NW_ANIM_FLAG_IS_INSIDE)) {
object oDoor = GetLocalObject(OBJECT_SELF, "NW_ANIM_DOOR");
if (GetIsObjectValid(oDoor)) {
DeleteLocalObject(OBJECT_SELF, "NW_ANIM_DOOR");
AnimActionGoThroughDoor(oDoor);
SetAnimationCondition(NW_ANIM_FLAG_IS_INSIDE, FALSE);
return TRUE;
}
}
return FALSE;
}
// Go to a nearby waypoint or placeable marked with the
// tag "NW_STOP".
int AnimActionGoToStop(float fMaxDistance)
{
object oStop = GetRandomStop(fMaxDistance);
if (GetIsObjectValid(oStop)) {
ClearActions(CLEAR_X0_I0_ANIMS_AnimActionGoToStop);
ActionMoveToObject(oStop, FALSE, DISTANCE_SHORT);
return TRUE;
}
return FALSE;
}
// Find a friend within the given distance and talk to them.
// Returns TRUE on success, FALSE on failure.
int AnimActionFindFriend(float fMaxDistance)
{
// If we had a friend recently, make sure we don't start talking
// again right away
// if (GetIsObjectValid(GetCurrentFriend())) {
// SetCurrentFriend(OBJECT_INVALID);
// } else
{
// Try and find a friend to talk to
object oFriend = GetRandomFriend(fMaxDistance);
if (GetIsObjectValid(oFriend) && !GetIsBusyWithAnimation(oFriend)) {
int nHDiff = GetHitDice(OBJECT_SELF) - GetHitDice(oFriend);
AnimActionStartTalking(oFriend, nHDiff);
return 1;
}
}
return 0;
}
// Find a placeable within the given distance and interact
// with it.
// Returns TRUE on success, FALSE on failure.
int AnimActionFindPlaceable(float fMaxDistance)
{
object oPlaceable = GetRandomObjectByTag("NW_INTERACTIVE", DISTANCE_SHORT);
if (GetIsObjectValid(oPlaceable)) {
AnimActionStartInteracting(oPlaceable);
return 1;
}
return 0;
}
// If injured, find the nearest "NW_SAFE" object,
// go to it, and rest.
// Returns TRUE on success, FALSE on failure.
int AnimActionRest()
{
if (GetCurrentHitPoints() < GetMaxHitPoints()) {
object oSafe = GetNearestObjectByTag("NW_SAFE");
if (GetAnimationCondition(NW_ANIM_FLAG_IS_MOBILE) && GetIsObjectValid(oSafe)) {
ClearActions(CLEAR_X0_I0_ANIMS_AnimActionRest1);
ActionMoveToObject(oSafe);
//ActionRest();
return TRUE;
} else {
location lStart = GetLocalLocation(OBJECT_SELF, "ANIM_START_LOCATION");
ClearActions(CLEAR_X0_I0_ANIMS_AnimActionRest2);
ActionMoveToLocation(lStart);
//ActionRest();
return TRUE;
}
}
return FALSE;
}
// If it is night, go back to our home waypoint, if we have one.
// This is only meaningful for mobile NPCs who would have left
// their homes during the day.
// Returns TRUE on success, FALSE on failure.
int AnimActionGoHome()
{
object oHome = GetCreatureHomeWaypoint();
if ( GetIsObjectValid(oHome) && !GetIsDay() && GetArea(OBJECT_SELF) != GetArea(oHome)) {
ClearActions(CLEAR_X0_I0_ANIMS_GoHome);
AnimActionGoOutside();
AnimActionGoThroughDoor(GetLocalObject(OBJECT_SELF,
"NW_ANIM_DOOR_HOME"));
return TRUE;
}
return FALSE;
}
// If it is day, leave our home area, if we have one.
// This is only meaningful for mobile NPCs.
// Returns TRUE on success, FALSE on failure.
int AnimActionLeaveHome()
{
object oHome = GetCreatureHomeWaypoint();
if ( GetIsObjectValid(oHome) && GetIsDay() && GetArea(OBJECT_SELF) == GetArea(oHome)) {
// Find the nearest door and walk out
ClearActions(CLEAR_X0_I0_ANIMS_AnimActionLeaveHome);
object oDoor = GetNearestObject(OBJECT_TYPE_DOOR);
if (!GetIsObjectValid(oDoor) || GetLocked(oDoor))
return FALSE;
object oDest = GetTransitionTarget(oDoor);
if (GetIsObjectValid(oDest)) {
SetLocalObject(OBJECT_SELF, "NW_ANIM_DOOR_HOME", oDest);
AnimActionGoThroughDoor(oDoor);
return TRUE;
}
}
return FALSE;
}
// If a PC is in the NPC's home and has not been challenged before,
// challenge them.
// This involves speaking a one-liner conversation from the
// conversation file ANIM_CONVERSATION, set above.
// Returns TRUE on success, FALSE on failure.
int AnimActionChallengeIntruder()
{
object oHome = GetCreatureHomeWaypoint();
if (GetIsObjectValid(oHome) && GetArea(OBJECT_SELF) == GetArea(oHome)) {
object oPC = GetNearestCreature(CREATURE_TYPE_PLAYER_CHAR, PLAYER_CHAR_IS_PC);
if (GetIsObjectValid(oPC) && !GetLocalInt(OBJECT_SELF, GetName(oPC) + "_CHALLENGED")) {
ClearActions(CLEAR_X0_I0_ANIMS_AnimActionChallengeIntruder);
ActionDoCommand(SetFacingPoint(GetPosition(oPC)));
ActionDoCommand(SpeakOneLinerConversation(ANIM_CONVERSATION, oPC));
SetLocalInt(OBJECT_SELF, GetName(oPC) + "_CHALLENGED", TRUE);
return TRUE;
}
}
return FALSE;
}
/**********************************************************************
**********************************************************************
* NOTE * NOTE * NOTE * NOTE * NOTE * NOTE * NOTE * NOTE * NOTE * NOTE
* The functions stuck below here are generally just big ugly
* switch statements to choose between a bunch of random
* animations.
* NOTE * NOTE * NOTE * NOTE * NOTE * NOTE * NOTE * NOTE * NOTE * NOTE
**********************************************************************
**********************************************************************/
// Interact with a placeable object.
// This will activate/deactivate the placeable object if a valid
// one is passed in.
// KLUDGE: If a placeable object without an inventory should
// still be opened/shut instead of de/activated, set
// its Will Save to 1.
void AnimActionPlayRandomInteractAnimation(object oPlaceable)
{
int nRoll = Random(5);
if (nRoll == 0) {
ActionPlayAnimation(ANIMATION_FIREFORGET_PAUSE_SCRATCH_HEAD);
return;
}
// See where the placeable is in relation to us, height-wise
vector vPos = GetPosition(oPlaceable);
vector vMyPos = GetPosition(OBJECT_SELF);
float fZDiff = vMyPos.z - vPos.z;
if ( fZDiff > 0.0 ) {
// we're above the placeable
ActionPlayAnimation(ANIMATION_LOOPING_GET_LOW,
ANIM_LOOPING_SPEED,
ANIM_LOOPING_LENGTH);
} else {
ActionPlayAnimation(ANIMATION_LOOPING_GET_MID,
ANIM_LOOPING_SPEED,
ANIM_LOOPING_LENGTH);
}
// KLUDGE! KLUDGE! KLUDGE!
// Because of placeables like the trap doors, etc, that should be
// "opened" rather than "activated", but don't have an inventory,
// we use this ugly hack: set the "Will" saving throw of a placeable
// to the value 1 if it should be opened rather than activated.
if (GetHasInventory(oPlaceable) || GetWillSavingThrow(oPlaceable) == 1) {
if (GetIsOpen(oPlaceable)) {
AssignCommand(oPlaceable,
DelayCommand(ANIM_LOOPING_LENGTH,
ActionPlayAnimation(ANIMATION_PLACEABLE_CLOSE)));
} else {
AssignCommand(oPlaceable,
DelayCommand(ANIM_LOOPING_LENGTH,
ActionPlayAnimation(ANIMATION_PLACEABLE_OPEN)));
}
} else {
int bIsActive = GetLocalInt(oPlaceable, "NW_ANIM_PLACEABLE_ACTIVE");
if (bIsActive) {
AssignCommand(oPlaceable,
DelayCommand(ANIM_LOOPING_LENGTH,
ActionPlayAnimation(ANIMATION_PLACEABLE_DEACTIVATE)));
SetLocalInt(oPlaceable, "NW_ANIM_PLACEABLE_ACTIVE", FALSE);
} else {
AssignCommand(oPlaceable,
DelayCommand(ANIM_LOOPING_LENGTH,
ActionPlayAnimation(ANIMATION_PLACEABLE_ACTIVATE)));
SetLocalInt(oPlaceable, "NW_ANIM_PLACEABLE_ACTIVE", TRUE);
}
}
return;
}
// Play a random talk gesture animation.
// If a hit dice difference (should be the hit dice of the caller
// minus the hit dice of the person being talked to) is passed in,
// the caller will play slightly different animations if they are
// weaker.
void AnimActionPlayRandomTalkAnimation(int nHDiff)
{
int nRoll = Random(9);
//SpeakString("Talk " + IntToString(nRoll));
switch (nRoll) {
case 0:
if (GetAnimationCondition(NW_ANIM_FLAG_CHATTER)) {
VoiceYes();
}
// deliberate fall-through!
case 1:
ActionPlayAnimation(ANIMATION_LOOPING_LISTEN,
ANIM_LOOPING_SPEED,
ANIM_LOOPING_LENGTH);
break;
case 2:
case 3:
ActionPlayAnimation(ANIMATION_LOOPING_TALK_NORMAL,
ANIM_LOOPING_SPEED,
ANIM_LOOPING_LENGTH);
break;
case 4:
if (nHDiff < 0)
ActionPlayAnimation(ANIMATION_LOOPING_TALK_PLEADING,
ANIM_LOOPING_SPEED,
ANIM_LOOPING_LENGTH);
else {
if (Random(2) == 0 && GetAnimationCondition(NW_ANIM_FLAG_CHATTER)) {
VoiceLaugh();
}
ActionPlayAnimation(ANIMATION_LOOPING_TALK_LAUGHING,
ANIM_LOOPING_SPEED,
ANIM_LOOPING_LENGTH);
}
break;
case 5:
// BK Feb 2003 Salutes look stupid
// if (nHDiff < 0)
// ActionPlayAnimation(ANIMATION_FIREFORGET_SALUTE, 0.75);
// else
ActionPlayAnimation(ANIMATION_LOOPING_TALK_FORCEFUL,
ANIM_LOOPING_SPEED,
ANIM_LOOPING_LENGTH);
break;
case 6:
if (GetAnimationCondition(NW_ANIM_FLAG_CHATTER)) {
VoiceNo();
}
// deliberate fall-through!
case 7:
AnimActionShakeHead();
break;
case 8:
if (nHDiff > 0)
ActionPlayAnimation(ANIMATION_FIREFORGET_TAUNT);
else {
if (Random(2) == 0 && GetAnimationCondition(NW_ANIM_FLAG_CHATTER)) {
VoiceLaugh();
}
ActionPlayAnimation(ANIMATION_LOOPING_TALK_LAUGHING,
ANIM_LOOPING_SPEED,
ANIM_LOOPING_LENGTH);
}
break;
}
return;
}
// Play a random animation that all creatures should have.
void AnimActionPlayRandomBasicAnimation()
{
int nRoll = Random(2);
switch (nRoll) {
case 0:
// BK Feb 2003: This always looks dumb
// ActionPlayAnimation(ANIMATION_LOOPING_GET_MID,
// ANIM_LOOPING_SPEED,
// ANIM_LOOPING_LENGTH);
break;
case 1:
ActionPlayAnimation(ANIMATION_FIREFORGET_TAUNT);
break;
}
}
// Play a random animation.
void AnimActionPlayRandomAnimation()
{
int nRoll;
int bInTavern=FALSE;
int bInHome=FALSE;
int bNearAltar=FALSE;
object oWay = GetNearestObjectByTag("NW_TAVERN");
if (GetIsObjectValid(oWay)) {
bInTavern = TRUE;
} else {
oWay = GetNearestObjectByTag("NW_HOME");
if (GetIsObjectValid(oWay)) {
bInHome = TRUE;
} else {
oWay = GetNearestObjectByTag("NW_ALTAR");
if (GetIsObjectValid(oWay) && GetDistanceToObject(oWay) < DISTANCE_SHORT) {
bNearAltar = TRUE;
}
}
}
if (bInTavern) {
nRoll = Random(15);
switch (nRoll) {
case 0:
case 1:
ActionPlayAnimation(ANIMATION_FIREFORGET_DRINK); break;
case 2:
if (GetAnimationCondition(NW_ANIM_FLAG_CHATTER)) {
VoicePoisoned();
}
ActionPlayAnimation(ANIMATION_LOOPING_PAUSE_DRUNK,
ANIM_LOOPING_SPEED,
ANIM_LOOPING_LENGTH);
break;
case 3:
ActionPlayAnimation(ANIMATION_LOOPING_PAUSE_DRUNK,
ANIM_LOOPING_SPEED,
ANIM_LOOPING_LENGTH);
break;
case 4:
ActionPlayAnimation(ANIMATION_FIREFORGET_VICTORY1); break;
case 5:
ActionPlayAnimation(ANIMATION_FIREFORGET_VICTORY2); break;
case 6:
ActionPlayAnimation(ANIMATION_FIREFORGET_VICTORY3); break;
case 7:
case 8:
if (GetAnimationCondition(NW_ANIM_FLAG_CHATTER)) {
VoiceLaugh();
}
ActionPlayAnimation(ANIMATION_LOOPING_TALK_LAUGHING,
ANIM_LOOPING_SPEED,
ANIM_LOOPING_LENGTH);
break;
case 9:
case 10:
ActionPlayAnimation(ANIMATION_FIREFORGET_PAUSE_BORED); break;
case 11:
ActionPlayAnimation(ANIMATION_FIREFORGET_PAUSE_SCRATCH_HEAD); break;
case 12:
case 13:
ActionPlayAnimation(ANIMATION_LOOPING_PAUSE_TIRED,
ANIM_LOOPING_SPEED,
ANIM_LOOPING_LENGTH);
break;
case 14:
AnimActionLookAround(); break;
}
} else if (bNearAltar) {
nRoll = Random(10);
switch (nRoll) {
case 0:
ActionPlayAnimation(ANIMATION_FIREFORGET_READ); break;
case 1:
case 2:
case 3:
ActionPlayAnimation(ANIMATION_LOOPING_MEDITATE,
ANIM_LOOPING_SPEED,
ANIM_LOOPING_LENGTH * 2);
break;
case 4:
case 5:
ActionPlayAnimation(ANIMATION_LOOPING_WORSHIP,
ANIM_LOOPING_SPEED,
ANIM_LOOPING_LENGTH * 2);
break;
case 6:
ActionPlayAnimation(ANIMATION_LOOPING_LISTEN,
ANIM_LOOPING_SPEED,
ANIM_LOOPING_LENGTH);
break;
case 7:
ActionPlayAnimation(ANIMATION_LOOPING_PAUSE,
ANIM_LOOPING_SPEED,
ANIM_LOOPING_LENGTH);
break;
case 8:
ActionPlayAnimation(ANIMATION_LOOPING_PAUSE2,
ANIM_LOOPING_SPEED,
ANIM_LOOPING_LENGTH);
break;
case 9:
AnimActionLookAround(); break;
}
} else if (bInHome) {
nRoll = Random(6);
switch (nRoll) {
case 0:
ActionPlayAnimation(ANIMATION_LOOPING_PAUSE,
ANIM_LOOPING_SPEED,
ANIM_LOOPING_LENGTH);
break;
case 1:
ActionPlayAnimation(ANIMATION_LOOPING_PAUSE2,
ANIM_LOOPING_SPEED,
ANIM_LOOPING_LENGTH);
break;
case 2:
ActionPlayAnimation(ANIMATION_LOOPING_PAUSE_TIRED,
ANIM_LOOPING_SPEED,
ANIM_LOOPING_LENGTH);
break;
case 3:
ActionPlayAnimation(ANIMATION_FIREFORGET_PAUSE_BORED); break;
case 4:
ActionPlayAnimation(ANIMATION_FIREFORGET_PAUSE_SCRATCH_HEAD); break;
case 5:
AnimActionLookAround(); break;
}
} else {
// generic set, for the street
nRoll = Random(8);
switch (nRoll) {
case 0:
ActionPlayAnimation(ANIMATION_LOOPING_PAUSE,
ANIM_LOOPING_SPEED,
ANIM_LOOPING_LENGTH);
break;
case 1:
ActionPlayAnimation(ANIMATION_LOOPING_PAUSE2,
ANIM_LOOPING_SPEED,
ANIM_LOOPING_LENGTH);
break;
case 2:
/* Bk Feb 2003: Looks dumb
ActionPlayAnimation(ANIMATION_LOOPING_GET_LOW,
ANIM_LOOPING_SPEED,
ANIM_LOOPING_LENGTH);
break;*/
case 3:
ActionPlayAnimation(ANIMATION_FIREFORGET_PAUSE_BORED); break;
case 4:
ActionPlayAnimation(ANIMATION_FIREFORGET_PAUSE_SCRATCH_HEAD); break;
case 5:
ActionPlayAnimation(ANIMATION_LOOPING_PAUSE_TIRED,
ANIM_LOOPING_SPEED,
ANIM_LOOPING_LENGTH);
break;
case 6:
ActionPlayAnimation(ANIMATION_LOOPING_LOOK_FAR,
ANIM_LOOPING_SPEED,
ANIM_LOOPING_LENGTH);
break;
case 7:
AnimActionLookAround(); break;
}
}
return;
}
//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
//
// Adam's Improved Waypoint Walker
// July 2, 2002
//
// USAGE:
//
// ATS_WalkWayPoints( int nRun, float fPause, int nWalkType );
//
// PARAMETERS:
//
// nRun - Use TRUE or FALSE for running or walking. Defaults to FALSE;
// fPause - A floating point number for the length of pause at each stop. Defaults to 1.0f
// nWalkType - Type of walking to do:
// 1 - Default. Back and forth pattern. (Waypoints 1, 2, 3, 4, 3, 2, 1, 2...)
// 2 - Circular (Waypoints 1, 2, 3, 4, 1, 2...)
// 3 or more - Random. Give the number of waypoints possible (say, 7), and
// the character will choose one at random.
//
// EXAMPLES:
//
//
// In your NPC's OnSpawn script, make sure that at the top you have the
// following two lines:
//
// #include "NW_I0_GENERIC" // this line will already be there
// #include "ats_waypoints" // add this line after the previous one
//
// Then, instead of using the default WalkWayPoints(), replace it with something like:
//
// ATS_WalkWayPoints(); // Use all the defaults. Walk, 1 second pause, back-and-forth.
// ATS_WalkWayPoints(FALSE, 1.0f, 2); // Walk, 1 second pause, circular path
// ATS_WalkWayPoints(TRUE, 5.0f, 8); // Run around the 8 waypoints randomly, with a 5 second pause
// // at each.
//
//
// Note that this script will give an error if you try to compile it.
// That's fine. Just save it, and #include it in other scripts to use it.
//
// ADDITIONAL NOTES:
//
// If you create a script with the same name as one of the waypoints, that
// script will be executed by the NPC when they walk to that waypoint.
//
// For example, if your waypoints are tagged WP_GUARD_01, WP_GUARD_02, etc...
// and at WP_GUARD_05 you want him to bow and say "Hello m'lord!", then
// create a script called "wp_guard_05" (in lower case).
// That script should look like this:
//
// void main()
// {
// ActionPlayAnimation(ANIMATION_FIREFORGET_BOW);
// ActionDoCommand(SpeakString("Hello m'lord!")));
// }
//
//
// Please note that the script for the waypoints should contain ONLY
// actions. Luckily, you can do any arbitrary command (I think)
// as an action by wrapping it in a ActionDoCommand(...) function call
// (like the SpeakString above).
//
//
// As with the default WalkWayPoints(), it is easily interrupted if you
// start a conversation with the NPC, or otherwise call ClearAllActions();
// To restart the NPC, issue another call to ATS_WalkWayPoints() as necessary
// after a conversation or whatever.
//
// Please give me your comments!
// Please use this in your mods!
// Please give me credit and/or thanks if you like it!
//
// Adam Spragg
// aspragg@yahoo.com
//
// DISCLAIMER!
// This script has been tested on my setup, and works very well.
// That does not mean, however, that it won't completely screw your own
// stuff up. Use at your own risk.
//void ATS_WalkWayPoints(int nRun = FALSE, float fPause = 1.0, int nWalkType = 1);
//
// Edited Bioware functions
void RunCircuit2(int nTens, int nNum, int nRun = FALSE, float fPause = 1.0, int nWalkType = 1);
void WalkWayPoints2(int nRun = FALSE, float fPause = 1.0, int nWalkType = 1);
void RunNextCircuit2(int nRun = FALSE, float fPause = 1.0, int nWalkType = 1);
//************************************************************************************************************************************
//************************************************************************************************************************************
//
//WAY POINT WALK FUNCTIONS
//
//************************************************************************************************************************************
//************************************************************************************************************************************
void ATS_WalkWayPoints( int nRun = FALSE, float fPause = 1.0, int nWalkType = 1)
{
WalkWayPoints2(nRun, fPause, nWalkType);
}
//::///////////////////////////////////////////////
//:: Walk Way Point Path
//:: Copyright (c) 2001 Bioware Corp.
//:://////////////////////////////////////////////
/*
Allows specified person walk a waypoint path
*/
//:://////////////////////////////////////////////
//:: Created By: Aidan Scanlan
//:: Created On: July 10, 2001
//:://////////////////////////////////////////////
void WalkWayPoints2(int nRun = FALSE, float fPause = 1.0, int nWalkType = 1) //Run first circuit
{
ClearAllActions();
string DayWayString;
string NightWayString;
string DayPostString;
string NightPostString;
string sWay;
string sPost;
//The block of code below deals with night and day cycle for postings and walkway points.
if(GetSpawnInCondition(NW_FLAG_DAY_NIGHT_POSTING))
{
DayWayString = "WP_";
NightWayString = "WN_";
DayPostString = "POST_";
NightPostString = "NIGHT_";
}
else
{
DayWayString = "WP_";
NightWayString = "WP_";
DayPostString = "POST_";
NightPostString = "POST_";
}
if(GetIsDay() || GetIsDawn())
{
SetLocalString(OBJECT_SELF, "NW_GENERIC_WALKWAYS_PREFIX", DayWayString);
SetLocalString(OBJECT_SELF, "NW_GENERIC_POSTING_PREFIX", DayPostString);
}
else
{
SetLocalString(OBJECT_SELF, "NW_GENERIC_WALKWAYS_PREFIX", NightWayString);
SetLocalString(OBJECT_SELF, "NW_GENERIC_POSTING_PREFIX", NightPostString);
}
sWay = GetLocalString(OBJECT_SELF, "NW_GENERIC_WALKWAYS_PREFIX");
sPost = GetLocalString(OBJECT_SELF, "NW_GENERIC_POSTING_PREFIX");
//I have now determined what the prefixs for the current walkways and postings are and will use them instead
// of POST_ and WP_
if(GetSpawnInCondition(NW_FLAG_STEALTH))
{
//MyPrintString("GENERIC SCRIPT DEBUG STRING ********** " + "Attempting to Activate Stealth");
ActionUseSkill(SKILL_HIDE, OBJECT_SELF);
}
if(GetSpawnInCondition(NW_FLAG_SEARCH))
{
//MyPrintString("GENERIC SCRIPT DEBUG STRING ********** " + "Attempting to Activate Search");
ActionUseSkill(SKILL_SEARCH, OBJECT_SELF);
}
//Test if OBJECT_SELF has waypoints to walk
string sWayTag = GetTag( OBJECT_SELF );
sWayTag = sWay + sWayTag + "_01";
object oWay1 = GetNearestObjectByTag(sWayTag);
if(!GetIsObjectValid(oWay1))
{
oWay1 = GetObjectByTag(sWayTag);
}
if(GetIsObjectValid(oWay1) && GetSpawnInCondition(NW_FLAG_AMBIENT_ANIMATIONS))
{
//turn off the ambient animations if the creature should walk way points.
SetSpawnInCondition(NW_FLAG_AMBIENT_ANIMATIONS, FALSE);
SetSpawnInCondition(NW_FLAG_IMMOBILE_AMBIENT_ANIMATIONS, FALSE);
}
if(GetIsObjectValid(oWay1))
{
int nNth = 1;
int nTens;
int nNum;
object oNearest = GetNearestObject(OBJECT_TYPE_WAYPOINT, OBJECT_SELF, nNth);
while (GetIsObjectValid(oNearest))
{
string sNearestTag = GetTag(oNearest);
//removes the first 3 and last three characters from the waypoint's tag
//and checks it against his own tag. Waypoint tag format is WP_MyTag_XX.
if( GetSubString( sNearestTag, 3, GetStringLength( sNearestTag ) - 6 ) == GetTag( OBJECT_SELF ) )
{
string sTens = GetStringRight(GetTag(oNearest),2);
nTens = StringToInt(sTens)/10;
nNum= StringToInt(GetStringRight(GetTag(oNearest),1));
oNearest = OBJECT_INVALID;
}
else
{
nNth++;
oNearest = GetNearestObject(OBJECT_TYPE_WAYPOINT,OBJECT_SELF,nNth);
}
}
RunCircuit2(nTens, nNum, nRun, fPause, nWalkType); //***************************************
ActionWait(fPause);
ActionDoCommand(RunNextCircuit2(nRun, fPause, nWalkType));
//ActionDoCommand(SignalEvent(OBJECT_SELF,EventUserDefined(2)));
}
else
{
sWayTag = GetTag( OBJECT_SELF );
sWayTag = sPost + sWayTag;
oWay1 = GetNearestObjectByTag(sWayTag);
if(!GetIsObjectValid(oWay1))
{
oWay1 = GetObjectByTag(sWayTag);
}
if(GetIsObjectValid(oWay1))
{
ActionForceMoveToObject(oWay1, nRun, 1.0, 60.0);
float fFacing = GetFacing(oWay1);
ActionDoCommand(SetFacing(fFacing));
}
}
if(GetIsObjectValid(oWay1) && GetSpawnInCondition(NW_FLAG_AMBIENT_ANIMATIONS))
{
SetSpawnInCondition(NW_FLAG_AMBIENT_ANIMATIONS, FALSE);
SetSpawnInCondition(NW_FLAG_IMMOBILE_AMBIENT_ANIMATIONS, FALSE);
}
}
void RunNextCircuit2(int nRun = FALSE, float fPause = 1.0, int nWalkType = 1)
{
if(nWalkType >= 3)
{
int nRand = Random(nWalkType) + 1;
int nTens = nRand/10;
int nNum= nRand - (nTens * 10);
RunCircuit2(nTens,nNum, nRun, fPause, nWalkType); //***************************************
}
else
RunCircuit2(0,1, nRun, fPause, nWalkType); //***************************************
ActionWait(fPause);
ActionDoCommand(RunNextCircuit2(nRun, fPause, nWalkType));
//ActionDoCommand(SignalEvent(OBJECT_SELF,EventUserDefined(2)));
}
//::///////////////////////////////////////////////
//:: Run Circuit
//:: Copyright (c) 2001 Bioware Corp.
//:://////////////////////////////////////////////
/*
Calculates the proper path to follow along a
predetermined set of way points
*/
//:://////////////////////////////////////////////
//:: Created By: Aidan Scanlan
//:: Created On: July 10, 2001
//:://////////////////////////////////////////////
void RunCircuit2(int nTens, int nNum, int nRun = FALSE, float fPause = 1.0, int nWalkType = 1)
{
// starting at a given way point, move sequentialy through incrementally
// increasing points until there are no more valid ones.
string sWay = GetLocalString(OBJECT_SELF, "NW_GENERIC_WALKWAYS_PREFIX");
object oTargetPoint;
if ( nWalkType >= 3 )
{
int nRand = Random(nWalkType) + 1;
nTens = nRand/10;
nNum= nRand - (nTens * 10);
oTargetPoint = GetWaypointByTag(sWay + GetTag(OBJECT_SELF) + "_" + IntToString(nTens) +IntToString(nNum));
ActionMoveToObject(oTargetPoint, nRun);
ActionWait(fPause);
ExecuteScript(GetStringLowerCase(GetTag(oTargetPoint)), OBJECT_SELF);
return;
}
oTargetPoint = GetWaypointByTag(sWay + GetTag(OBJECT_SELF) + "_" + IntToString(nTens) +IntToString(nNum));
while(GetIsObjectValid(oTargetPoint))
{
ActionMoveToObject(oTargetPoint, nRun);
ActionWait(fPause);
ExecuteScript(GetStringLowerCase(GetTag(oTargetPoint)), OBJECT_SELF);
nNum++;
if (nNum > 9)
{
nTens++;
nNum = 0;
}
oTargetPoint = GetWaypointByTag(sWay + GetTag(OBJECT_SELF) + "_" + IntToString(nTens) +IntToString(nNum));
}
// ATS
// If walktype is 2 (Circlular), then return at this point...
if ( nWalkType == 2 )
return;
// once there are no more waypoints available, decriment back to the last
// valid point.
nNum--;
if (nNum < 0)
{
nTens--;
nNum = 9;
}
// start the cycle again going back to point 01
oTargetPoint = GetWaypointByTag(sWay + GetTag(OBJECT_SELF) + "_" + IntToString(nTens) +IntToString(nNum));
while(GetIsObjectValid(oTargetPoint))
{
ActionMoveToObject(oTargetPoint, nRun);
ActionWait(fPause);
ExecuteScript(GetStringLowerCase(GetTag(oTargetPoint)), OBJECT_SELF);
nNum--;
if (nNum < 0)
{
nTens--;
nNum = 9;
}
oTargetPoint = GetWaypointByTag(sWay + GetTag(OBJECT_SELF) + "_" + IntToString(nTens) +IntToString(nNum));
}
}
/* DO NOT CLOSE THIS TOP COMMENT!
This main() function is here only for compilation testing.
void main() {}
/* */