EN6_PRC8/_module/nss/no_lib_bio.nss
Jaysyn904 a6f6db7303 Initial commit
Initial commit.  Updated release archive.
2024-06-13 15:08:33 -04:00

2174 lines
71 KiB
Plaintext

/*
====================
A subset of the Bioware functions included for use without including all of them.
Some changes have been made to these functions where necessary.
====================
*/
#include "x0_i0_behavior"
#include "x0_i0_modes"
#include "x0_i0_position"
#include "x0_i0_voice"
#include "no_inc_ptypes"
//Master Constants
int NW_FLAG_SPECIAL_CONVERSATION = 0x00000001;
int NW_FLAG_SHOUT_ATTACK_MY_TARGET = 0x00000002;
int NW_FLAG_STEALTH = 0x00000004;
int NW_FLAG_SEARCH = 0x00000008;
int NW_FLAG_SET_WARNINGS = 0x00000010;
int NW_FLAG_ESCAPE_RETURN = 0x00000020; //Failed
int NW_FLAG_ESCAPE_LEAVE = 0x00000040;
int NW_FLAG_TELEPORT_RETURN = 0x00000080; //Failed
int NW_FLAG_TELEPORT_LEAVE = 0x00000100;
int NW_FLAG_PERCIEVE_EVENT = 0x00000200;
int NW_FLAG_ATTACK_EVENT = 0x00000400;
int NW_FLAG_DAMAGED_EVENT = 0x00000800;
int NW_FLAG_SPELL_CAST_AT_EVENT = 0x00001000;
int NW_FLAG_DISTURBED_EVENT = 0x00002000;
int NW_FLAG_END_COMBAT_ROUND_EVENT = 0x00004000;
int NW_FLAG_ON_DIALOGUE_EVENT = 0x00008000;
int NW_FLAG_RESTED_EVENT = 0x00010000;
int NW_FLAG_DEATH_EVENT = 0x00020000;
int NW_FLAG_SPECIAL_COMBAT_CONVERSATION = 0x00040000;
int NW_FLAG_AMBIENT_ANIMATIONS = 0x00080000;
int NW_FLAG_HEARTBEAT_EVENT = 0x00100000;
int NW_FLAG_IMMOBILE_AMBIENT_ANIMATIONS = 0x00200000;
int NW_FLAG_DAY_NIGHT_POSTING = 0x00400000;
int NW_FLAG_AMBIENT_ANIMATIONS_AVIAN = 0x00800000;
int NW_FLAG_APPEAR_SPAWN_IN_ANIMATION = 0x01000000;
int NW_FLAG_SLEEPING_AT_NIGHT = 0x02000000;
int NW_FLAG_FAST_BUFF_ENEMY = 0x04000000;
//Additional constants for SoU animation craziness
const int CLEAR_DEBUG = FALSE;
string sAnimCondVarname = "NW_ANIM_CONDITION";
float ANIM_LOOPING_LENGTH = 4.0;
float ANIM_LOOPING_SPEED = 1.0;
string ANIM_CONVERSATION = "x0_npc_homeconv";
int NW_ANIM_FLAG_INITIALIZED = 0x00000001;
int NW_ANIM_FLAG_CONSTANT = 0x00000002;
int NW_ANIM_FLAG_CHATTER = 0x00000004;
int NW_ANIM_FLAG_IS_ACTIVE = 0x00000008;
int NW_ANIM_FLAG_IS_INTERACTING = 0x00000010;
int NW_ANIM_FLAG_IS_INSIDE = 0x00000020;
int NW_ANIM_FLAG_HAS_HOME = 0x00000040;
int NW_ANIM_FLAG_IS_TALKING = 0x00000080;
int NW_ANIM_FLAG_IS_MOBILE = 0x00000100;
int NW_ANIM_FLAG_IS_MOBILE_CLOSE_RANGE = 0x00000200;
int NW_ANIM_FLAG_IS_CIVILIZED = 0x00000400;
int NW_ANIM_FLAG_CLOSE_DOORS = 0x00001000;
const int CLEAR_NW_I0_GENERIC_DetermineSpecialBehavior1 = 11;
const int CLEAR_NW_I0_GENERIC_DetermineSpecialBehavior2 = 12;
const int CLEAR_X0_I0_ANIMS_PlayMobile = 16;
const int CLEAR_X0_I0_ANIMS_PlayRandomMobile = 17;
const int CLEAR_X0_I0_ANIMS_PlayRandomCloseRange1 = 18;
const int CLEAR_X0_I0_ANIMS_PlayRandomCloseRange2 = 19;
const int CLEAR_X0_I0_ANIMS_AnimActionPlayRandomMobile1 = 20;
const int CLEAR_X0_I0_ANIMS_AnimActionPlayRandomMobile2 = 21;
const int CLEAR_X0_I0_ANIMS_AnimActionPlayRandomUncivilized =22;
const int CLEAR_X0_I0_ANIMS_AnimActionGetUpFromChair = 23;
const int CLEAR_X0_I0_ANIMS_AnimActionGoToStop = 24;
const int CLEAR_X0_I0_ANIMS_AnimActionRest1 = 25;
const int CLEAR_X0_I0_ANIMS_AnimActionRest2 = 26;
const int CLEAR_X0_I0_ANIMS_GoHome = 27;
const int CLEAR_X0_I0_ANIMS_AnimActionLeaveHome = 28;
const int CLEAR_X0_I0_ANIMS_AnimActionChallengeIntruder = 29;
//::///////////////////////////////////////////////
//:: Master Local Get and Set
//:: FileName
//:: Copyright (c) 2001 Bioware Corp.
//:://////////////////////////////////////////////
/*
All On Spawn in conditions in the game are now
being stored within one local. The get and set
changed or checks the condition of this one
Hex local. The NW_FLAG_XXX variables above
allow for the user of these functions throughout
the generic scripts.
*/
//:://////////////////////////////////////////////
//:: Created By: Preston Watamaniuk
//:: Created On: Nov 14, 2001
//:://////////////////////////////////////////////
void SetSpawnInCondition(int nCondition, int bValid = TRUE)
{
int nPlot = GetLocalInt(OBJECT_SELF, "NW_GENERIC_MASTER");
if(bValid == TRUE)
{
nPlot = nPlot | nCondition;
SetSpawnInLocals(nCondition);
SetLocalInt(OBJECT_SELF, "NW_GENERIC_MASTER", nPlot);
}
else if (bValid == FALSE)
{
nPlot = nPlot & ~nCondition;
SetLocalInt(OBJECT_SELF, "NW_GENERIC_MASTER", nPlot);
}
}
int GetSpawnInCondition(int nCondition)
{
int nPlot = GetLocalInt(OBJECT_SELF, "NW_GENERIC_MASTER");
if(nPlot & nCondition)
{
return TRUE;
}
return FALSE;
}
void SetSpawnInLocals(int nCondition)
{
if(nCondition == NW_FLAG_SHOUT_ATTACK_MY_TARGET)
{
SetListenPattern(OBJECT_SELF, "NW_ATTACK_MY_TARGET", 5);
}
else if(nCondition == NW_FLAG_ESCAPE_RETURN)
{
SetLocalLocation(OBJECT_SELF, "NW_GENERIC_START_POINT", GetLocation(OBJECT_SELF));
}
else if(nCondition == NW_FLAG_TELEPORT_LEAVE)
{
SetLocalLocation(OBJECT_SELF, "NW_GENERIC_START_POINT", GetLocation(OBJECT_SELF));
}
}
//::///////////////////////////////////////////////
//:: SetListeningPatterns
//:: Copyright (c) 2001 Bioware Corp.
//:://////////////////////////////////////////////
/*
Sets the correct listen checks on the NPC by
determining what talents they possess or what
class they use.
This is also a good place to set up all of
the sleep and appear disappear animations for
various models.
*/
//:://////////////////////////////////////////////
//:: Created By: Preston Watamaniuk
//:: Created On: Oct 24, 2001
//:://////////////////////////////////////////////
void SetListeningPatterns()
{
if(GetSpawnInCondition(NW_FLAG_APPEAR_SPAWN_IN_ANIMATION))
{
effect eAppear = EffectAppear();
ApplyEffectToObject(DURATION_TYPE_INSTANT, eAppear, OBJECT_SELF);
}
SetListening(OBJECT_SELF, TRUE);
//NO: Broadcast listen patterns
SetListenPattern( OBJECT_SELF, "BC_DEAD", 691 );
SetListenPattern( OBJECT_SELF, "BC_FIGHTING", 699 );
SetListenPattern(OBJECT_SELF, "NW_I_WAS_ATTACKED", 1);
//This sets the commoners listen pattern to mob under
//certain conditions
if(GetLevelByClass(CLASS_TYPE_COMMONER) > 0)
{
SetListenPattern(OBJECT_SELF, "NW_MOB_ATTACK", 2);
}
SetListenPattern(OBJECT_SELF, "NW_I_AM_DEAD", 3);
SetListenPattern(OBJECT_SELF, "inventory",101);
//Set a custom listening pattern for the creature so that placables with
//"NW_BLOCKER" + Blocker NPC Tag will correctly call to their blockers.
string sBlocker = "NW_BLOCKER_BLK_" + GetTag(OBJECT_SELF);
SetListenPattern(OBJECT_SELF, sBlocker, 4);
SetListenPattern(OBJECT_SELF, "NW_CALL_TO_ARMS", 6);
}
//************************************************************************************************************************************
//************************************************************************************************************************************
//
//WAY POINT WALK FUNCTIONS
//
//************************************************************************************************************************************
//************************************************************************************************************************************
//::///////////////////////////////////////////////
//:: 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 WalkWayPoints(int nRun = FALSE, float fPause = 1.0) //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);
}
}
RunCircuit(nTens, nNum, nRun, fPause); //***************************************
ActionWait(fPause);
ActionDoCommand(RunNextCircuit(nRun, fPause));
//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 RunNextCircuit(int nRun = FALSE, float fPause = 1.0)
{
RunCircuit(0,1, nRun, fPause); //***************************************
ActionWait(fPause);
ActionDoCommand(RunNextCircuit(nRun, fPause));
//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 RunCircuit(int nTens, int nNum, int nRun = FALSE, float fPause = 1.0)
{
// 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 = GetWaypointByTag(sWay + GetTag(OBJECT_SELF) + "_" + IntToString(nTens) +IntToString(nNum));
while(GetIsObjectValid(oTargetPoint))
{
ActionWait(fPause);
ActionMoveToObject(oTargetPoint, nRun);
nNum++;
if (nNum > 9)
{
nTens++;
nNum = 0;
}
oTargetPoint = GetWaypointByTag(sWay + GetTag(OBJECT_SELF) + "_" + IntToString(nTens) +IntToString(nNum));
}
// 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))
{
ActionWait(fPause);
ActionMoveToObject(oTargetPoint, nRun);
nNum--;
if (nNum < 0)
{
nTens--;
nNum = 9;
}
oTargetPoint = GetWaypointByTag(sWay + GetTag(OBJECT_SELF) + "_" + IntToString(nTens) +IntToString(nNum));
}
}
//::///////////////////////////////////////////////
//:: Check Walkways
//:: Copyright (c) 2001 Bioware Corp.
//:://////////////////////////////////////////////
/*
This function checks the passed in object to
see if they are supposed to be walking to
day or night postings.
*/
//:://////////////////////////////////////////////
//:: Created By: Preston Watamaniuk
//:: Created On: Feb 26, 2002
//:://////////////////////////////////////////////
int CheckWayPoints(object oWalker = OBJECT_SELF)
{
object oWay1;
object oWay2;
object oWay3;
object oWay4;
string sTag = GetTag(oWalker);
if(GetSpawnInCondition(NW_FLAG_DAY_NIGHT_POSTING))
{
oWay2 = GetWaypointByTag("NIGHT_" + sTag);
oWay4 = GetWaypointByTag("WN_" + sTag + "_01");
}
oWay1 = GetWaypointByTag("POST_" + sTag);
oWay3 = GetWaypointByTag("WP_" + sTag + "_01");
if(GetIsObjectValid(oWay2) || GetIsObjectValid(oWay4) || GetIsObjectValid(oWay1) || GetIsObjectValid(oWay3))
{
return TRUE;
}
return FALSE;
}
//::///////////////////////////////////////////////
//:: Check for Walkways
//:: Copyright (c) 2001 Bioware Corp.
//:://////////////////////////////////////////////
/*
This function checks if the passed in object
has waypoints using their tag.
*/
//:://////////////////////////////////////////////
//:: Created By: Preston Watamaniuk
//:: Created On: MAy 13, 2002
//:://////////////////////////////////////////////
/*
if(GetSpawnInCondition(NW_FLAG_DAY_NIGHT_POSTING))
{
DayWayString = "WP_";
NightWayString = "WN_";
DayPostString = "POST_";
NightPostString = "NIGHT_";
}
else
{
DayWayString = "WP_";
NightWayString = "WP_";
DayPostString = "POST_";
NightPostString = "POST_";
}
*/
int GetIsPostOrWalking(object oWalker = OBJECT_SELF)
{
string sTag = GetTag(oWalker);
object oPost = GetWaypointByTag("POST_" + sTag);
if(!GetIsObjectValid(oPost))
{
oPost = GetWaypointByTag("NIGHT_" + sTag);
if(!GetIsObjectValid(oPost))
{
oPost = GetWaypointByTag("WP_" + sTag + "_01");
if(!GetIsObjectValid(oPost))
{
oPost = GetWaypointByTag("WN_" + sTag + "_01");
if(!GetIsObjectValid(oPost))
{
return FALSE;
}
}
}
}
return TRUE;
}
//:://////////////////////////////////////////////////////////////////////////////////////////////
//:: Special Behavior Functions
//:: Copyright (c) 2001 Bioware Corp.
//:://///////////////////////////////////////////////////////////////////////////////////////////
/*
These commands handle the setting and getting of the Behavioral Master
If these special behaviors are used they will override the normal behavior expected
the animals normal Neutral Faction.
*/
//:://///////////////////////////////////////////////////////////////////////////////////////////
//:: Created By: Preston Watamaniuk
//:: Created On: Dec 10, 2001
//:://///////////////////////////////////////////////////////////////////////////////////////////
/*
void SetBehaviorState(int nCondition, int bValid = TRUE)
{
int nPlot = GetLocalInt(OBJECT_SELF, "NW_BEHAVIOR_MASTER");
if(bValid == TRUE)
{
nPlot = nPlot | nCondition;
SetLocalInt(OBJECT_SELF, "NW_BEHAVIOR_MASTER", nPlot);
}
else if (bValid == FALSE)
{
nPlot = nPlot & ~nCondition;
SetLocalInt(OBJECT_SELF, "NW_BEHAVIOR_MASTER", nPlot);
}
}
int GetBehaviorState(int nCondition)
{
int nPlot = GetLocalInt(OBJECT_SELF, "NW_BEHAVIOR_MASTER");
if(nPlot & nCondition)
{
return TRUE;
}
return FALSE;
}
*/
//::///////////////////////////////////////////////
//:: Play Mobile Ambient Animations
//:: Copyright (c) 2001 Bioware Corp.
//:://////////////////////////////////////////////
/*
Used for spawned creatures to not look like
zombies
*/
//:://////////////////////////////////////////////
//:: Created By: Preston Watamaniuk
//:: Created On: Nov 23, 2001
//:://////////////////////////////////////////////
void PlayMobileAmbientAnimations()
{
if(!GetSpawnInCondition(NW_FLAG_AMBIENT_ANIMATIONS_AVIAN)) {
// not a bird
PlayMobileAmbientAnimations_NonAvian();
} else {
// a bird
PlayMobileAmbientAnimations_Avian();
}
}
//::///////////////////////////////////////////////
//:: Determine Special Behavior
//:: Copyright (c) 2001 Bioware Corp.
//:://////////////////////////////////////////////
/*
Determines the special behavior used by the NPC.
Generally all NPCs who you want to behave differently
than the defualt behavior.
For these behaviors, passing in a valid object will
cause the creature to become hostile the the attacker.
MODIFIED February 7 2003:
- Rearranged logic order a little so that the creatures
will actually randomwalk when not fighting
*/
//:://////////////////////////////////////////////
//:: Created By: Preston Watamaniuk
//:: Created On: Dec 14, 2001
//:://////////////////////////////////////////////
void DetermineSpecialBehavior(object oIntruder = OBJECT_INVALID)
{
//object oTarget = GetNearestSeenEnemy();
object oTarget = GetTarget();
if(GetBehaviorState(NW_FLAG_BEHAVIOR_OMNIVORE))
{
int bAttack = FALSE;
if(!GetIsObjectValid(oIntruder))
{
if(!GetIsObjectValid(GetAttemptedAttackTarget()) &&
!GetIsObjectValid(GetAttemptedSpellTarget()) &&
!GetIsObjectValid(GetAttackTarget()))
{
if(GetIsObjectValid(oTarget) && GetDistanceToObject(oTarget) <= 8.0)
{
if(GetIsEnemy(oTarget))
{
if(GetLevelByClass(CLASS_TYPE_DRUID, oTarget) == 0 && GetLevelByClass(CLASS_TYPE_RANGER, oTarget) == 0)
{
SetIsTemporaryEnemy(oTarget, OBJECT_SELF, FALSE, 20.0);
bAttack = TRUE;
//DetermineCombatRound(oTarget);
InitCombat(oTarget);
}
}
}
}
}
else if(!IsInConversation(OBJECT_SELF))
{
bAttack = TRUE;
//DetermineCombatRound(oIntruder);
InitCombat(oIntruder);
}
// * if not attacking, the wander
if (bAttack == FALSE)
{
ClearActions(CLEAR_NW_I0_GENERIC_DetermineSpecialBehavior1);
ActionRandomWalk();
return;
}
}
else if(GetBehaviorState(NW_FLAG_BEHAVIOR_HERBIVORE))
{
if(!GetIsObjectValid(GetAttemptedAttackTarget()) &&
!GetIsObjectValid(GetAttemptedSpellTarget()) &&
!GetIsObjectValid(GetAttackTarget()))
{
if(GetIsObjectValid(oTarget) && GetDistanceToObject(oTarget) <= 6.0)
{
if(!GetIsFriend(oTarget))
{
if(GetLevelByClass(CLASS_TYPE_DRUID, oTarget) == 0 && GetLevelByClass(CLASS_TYPE_RANGER, oTarget) == 0)
{
//TalentFlee(oTarget);
DoAvoidEnemies();
}
}
}
}
else if(!IsInConversation(OBJECT_SELF))
{
ClearActions(CLEAR_NW_I0_GENERIC_DetermineSpecialBehavior2);
ActionRandomWalk();
return;
}
}
}
//::///////////////////////////////////////////////
//:: ClearActions
//:: Copyright (c) 2001 Bioware Corp.
//:://////////////////////////////////////////////
/*
This is a wrapper for ClearAllActions.
Added to try and track down some bugs in
the AI.
*/
//:://////////////////////////////////////////////
//:: Created By: Brent
//:: Created On: February 6, 2003
//:://////////////////////////////////////////////
void ClearActions(int nClearConstant=0, int bClearCombat=FALSE)
{
// SpeakString ("Clearing Action # " + IntToString(bClearConstant));
if (CLEAR_DEBUG == TRUE)
{
SpeakString("Clearing all actions in State # " + IntToString(nClearConstant));
}
ClearAllActions(bClearCombat);
}
/**********************************************************************
* FUNCTION DEFINITIONS
**********************************************************************/
// Debugging function. Will be commented out for final.
void AnimDebug(string sMsg)
{
//ActionSpeakString("ANIM: " + GetName(OBJECT_SELF) + " " + sMsg);
//SpeakString("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()
{
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.
if (CheckCurrentAction() && (nCurrentAction != ACTION_MOVETOPOINT)&& (nCurrentAction != ACTION_WAIT)) {
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);
effect eBird;
int nBird = d4();
ClearActions(CLEAR_X0_I0_ANIMS_PlayMobile);
if(GetIsObjectValid(oFriend)) {
if(nBird == 1) {
ActionMoveToObject(oFriend, TRUE);
} else if (nBird == 2 || nBird == 3) {
AnimActionRandomMoveAway(oFriend, 100.0);
} else {
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();
UseStealthMode();
UseDetectMode();
// 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;
}