2022 lines
72 KiB
Plaintext
2022 lines
72 KiB
Plaintext
//::///////////////////////////////////////////////
|
|
//:: Generic Scripting Include v1.0
|
|
//:: NW_I0_GENERIC
|
|
//:: Copyright (c) 2001 Bioware Corp.
|
|
//:://////////////////////////////////////////////
|
|
/*
|
|
|
|
December 7 2002, Naomi Novik
|
|
Many functions removed to separate libraries:
|
|
|
|
x0_i0_anims
|
|
PlayMobileAmbientAnimations_NonAvian
|
|
PlayMobileAmbientAnimations_Avian
|
|
(with PlayMobileAmbientAnimations changed to
|
|
just a call to one of these two)
|
|
PlayImmobileAmbientAnimations
|
|
|
|
x0_i0_assoc
|
|
associate constants (NW_ASC_...)
|
|
GetPercentageHPLoss (only used in GetAssociateHealMaster)
|
|
SetAssociateState
|
|
GetAssociateState
|
|
ResetHenchmenState
|
|
AssociateCheck
|
|
GetAssociateHealMaster
|
|
GetFollowDistance
|
|
SetAssociateStartLocation
|
|
GetAssociateStartLocation
|
|
|
|
x0_i0_behavior
|
|
behavior constants
|
|
SetBehaviorState
|
|
GetBehaviorState
|
|
|
|
x0_i0_spawncond
|
|
OnSpawn condition constants
|
|
SetSpawnInCondition
|
|
GetSpawnInCondition
|
|
SetSpawnInLocals
|
|
SetListeningPatterns
|
|
|
|
x0_i0_walkway
|
|
WalkWayPoints
|
|
RunNextCircuit
|
|
RunCircuit
|
|
CheckWayPoints
|
|
GetIsPostOrWalking
|
|
|
|
x0_i0_talent
|
|
ALL the talent functions
|
|
|
|
x0_i0_equip
|
|
Equipping functions
|
|
|
|
x0_i0_match
|
|
Matching functions
|
|
|
|
x0_i0_debug
|
|
MyPrintString
|
|
DebugPrintTalentId
|
|
newdebug
|
|
|
|
x0_inc_generic
|
|
Pretty much everything else
|
|
|
|
***********************************************'
|
|
CHANGE SUMMARY
|
|
|
|
|
|
February 6 2003: Commented out the Henchman RespondToShout because now using
|
|
the newer bkRespondToShout function in x0_i0_henchman
|
|
|
|
|
|
September 18 2002: DetermineCombatRound broken into smaller functions
|
|
19 : Removed randomness from Talent system. You can't
|
|
have smart AI and random behavior. Only healing
|
|
has the possiblity of being random.
|
|
|
|
I may want to add the possibility of getting a
|
|
random talent only in the Talent filter if
|
|
something fails (*)
|
|
|
|
|
|
********************************************
|
|
WARNING THIS SCRIPT IS CHANGED AT YOUR PERIL
|
|
********************************************
|
|
|
|
This is the master generic script and currently
|
|
handles all combat and some plot behavior
|
|
within NWN. If this script is tampered
|
|
with there is a chance of introducing game
|
|
breaking bugs. But other than that enjoy.
|
|
*/
|
|
//:://////////////////////////////////////////////
|
|
//:: Created By: Preston Watamaniuk
|
|
//:: Created On: Sept 20, 2001
|
|
//:://////////////////////////////////////////////
|
|
|
|
//#include "x0_i0_assoc" - included in x0_inc_generic
|
|
//#include "x0_inc_generic" - included in x0_i0_talent
|
|
//#include "x0_i0_talent" - included in x0_i0_combat
|
|
|
|
//#include "x0_i0_combat" - include in x0_i0_anims
|
|
|
|
//#include "x0_i0_walkway" - include in x0_i0_anims
|
|
#include "x0_i0_behavior"
|
|
#include "x0_i0_anims"
|
|
|
|
|
|
/**********************************************************************
|
|
* CONSTANTS
|
|
**********************************************************************/
|
|
|
|
/**********************************************************************
|
|
* Flee and move constants
|
|
**********************************************************************/
|
|
|
|
const int NW_GENERIC_FLEE_EXIT_FLEE = 0;
|
|
const int NW_GENERIC_FLEE_EXIT_RETURN = 1;
|
|
const int NW_GENERIC_FLEE_TELEPORT_FLEE = 2;
|
|
const int NW_GENERIC_FLEE_TELEPORT_RETURN = 3;
|
|
|
|
/**********************************************************************
|
|
* Shout constants
|
|
**********************************************************************/
|
|
|
|
// NOT USED
|
|
const int NW_GENERIC_SHOUT_I_WAS_ATTACKED = 1;
|
|
|
|
//IN OnDeath Script
|
|
const int NW_GENERIC_SHOUT_I_AM_DEAD = 12;
|
|
|
|
//IN TalentMeleeAttacked
|
|
const int NW_GENERIC_SHOUT_BACK_UP_NEEDED = 13;
|
|
|
|
const int NW_GENERIC_SHOUT_BLOCKER = 2;
|
|
|
|
/**********************************************************************
|
|
* chooseTactics constants
|
|
**********************************************************************/
|
|
|
|
const int chooseTactics_MEMORY_OFFENSE_MELEE = 0;
|
|
const int chooseTactics_MEMORY_DEFENSE_OTHERS = 1;
|
|
const int chooseTactics_MEMORY_DEFENSE_SELF = 2;
|
|
const int chooseTactics_MEMORY_OFFENSE_SPELL = 3;
|
|
|
|
|
|
/**********************************************************************
|
|
* FUNCTION PROTOTYPES
|
|
**********************************************************************/
|
|
|
|
// * New Functions September - 2002
|
|
|
|
|
|
// * The class-specific tactics have been broken out from DetermineCombatRound
|
|
// * for readability. This function determines the actual tactics each class
|
|
// * will use.
|
|
int chooseTactics(object oIntruder);
|
|
|
|
// Adds all three of the class levels together. Used before
|
|
// GetHitDice became available
|
|
int GetCharacterLevel(object oTarget);
|
|
|
|
//If using ambient sleep this will remove the effect
|
|
void RemoveAmbientSleep();
|
|
|
|
//Searches for the nearest locked object to the master
|
|
object GetLockedObject(object oMaster);
|
|
|
|
/**********************************************************************
|
|
* DetermineCombatRound subfunctions
|
|
**********************************************************************/
|
|
|
|
// Used in DetermineCombatRound to keep a
|
|
// henchmen bashing doors.
|
|
int BashDoorCheck(object oIntruder = OBJECT_INVALID);
|
|
|
|
// Determines which of a NPCs three classes to
|
|
// use in DetermineCombatRound
|
|
int DetermineClassToUse();
|
|
|
|
|
|
/**********************************************************************
|
|
* Core AI Functions
|
|
**********************************************************************/
|
|
|
|
//::///////////////////////////////////////////////
|
|
//:: DetermineCombatRound
|
|
//:: Copyright (c) 2001 Bioware Corp.
|
|
//:://////////////////////////////////////////////
|
|
/*
|
|
This function is the master function for the
|
|
generic include and is called from the main
|
|
script. This function is used in lieu of
|
|
any actual scripting.
|
|
*/
|
|
//:://////////////////////////////////////////////
|
|
//:: Created By: Preston Watamaniuk
|
|
//:: Created On: Oct 16, 2001
|
|
//:://////////////////////////////////////////////
|
|
void DetermineCombatRound(object oIntruder = OBJECT_INVALID, int nAI_Difficulty = 10);
|
|
|
|
//::///////////////////////////////////////////////
|
|
//:: Respond To Shouts
|
|
//:: Copyright (c) 2001 Bioware Corp.
|
|
//:://////////////////////////////////////////////
|
|
// Allows the listener to react in a manner
|
|
// consistant with the given shout but only to one
|
|
// combat shout per round
|
|
//:://////////////////////////////////////////////
|
|
//:: Created By: Preston Watamaniuk
|
|
//:: Created On: Oct 25, 2001
|
|
//:://////////////////////////////////////////////
|
|
//NOTE ABOUT COMMONERS
|
|
// Commoners are universal cowards. If you attack anyone
|
|
// they will flee for 4 seconds away from the attacker.
|
|
// However to make the commoners into a mob, make a single
|
|
// commoner at least 10th level of the same faction.
|
|
// If that higher level commoner is attacked or killed then
|
|
// the commoners will attack the attacker. They will disperse again
|
|
// after some of them are killed. Should NOT make multi-class
|
|
// creatures using commoners.
|
|
//
|
|
//NOTE ABOUT BLOCKERS
|
|
// It should be noted that the Generic Script for On Dialogue
|
|
// attempts to get a local set on the shouter by itself.
|
|
// This object represents the LastOpenedBy object. It is this
|
|
// object that becomes the oIntruder within this function.
|
|
//
|
|
//NOTE ABOUT INTRUDERS
|
|
// The intruder object is for cases where a placable needs to
|
|
// pass a LastOpenedBy Object or a AttackMyAttacker
|
|
// needs to make his attacker the enemy of everyone.
|
|
void RespondToShout(object oShouter, int nShoutIndex, object oIntruder = OBJECT_INVALID);
|
|
|
|
|
|
//******** PLOT FUNCTIONS
|
|
|
|
// NPCs who have warning status set to TRUE will allow
|
|
// one 'free' attack by PCs from a non-hostile faction.
|
|
void SetNPCWarningStatus(int nStatus = TRUE);
|
|
|
|
// NPCs who have warning status set to TRUE will allow
|
|
// one 'free' attack by PCs from a non-hostile faction.
|
|
int GetNPCWarningStatus();
|
|
|
|
// * Presently Does not work with the current implementation
|
|
// * of encounter triggers!
|
|
//
|
|
// This function works in tandem with an encounter
|
|
// to spawn in guards to fight for the attacked
|
|
// NPC. MAKE SURE THE ENCOUNTER TAG IS SET TO:
|
|
//
|
|
// "ENC_" + NPC TAG
|
|
//:: Created By: Preston Watamaniuk
|
|
//:: Created On: Oct 29, 2001
|
|
void SetSummonHelpIfAttacked();
|
|
|
|
// The target object flees to the specified
|
|
// way point and then destroys itself, to be
|
|
// respawned at a later point. For unkillable
|
|
// sign post characters who are not meant to fight
|
|
// back.
|
|
// This function is used only because ActionDoCommand can
|
|
// only accept void functions.
|
|
void CreateSignPostNPC(string sTag, location lLocal);
|
|
|
|
// The target object flees to the specified
|
|
// way point and then destroys itself, to be
|
|
// respawned at a later point. For unkillable
|
|
// sign post characters who are not meant to fight
|
|
// back.
|
|
void ActivateFleeToExit();
|
|
|
|
// The target object flees to the specified
|
|
// way point and then destroys itself, to be
|
|
// respawned at a later point. For unkillable
|
|
// sign post characters who are not meant to fight
|
|
// back.
|
|
int GetFleeToExit();
|
|
|
|
// Checks that an item was unlocked.
|
|
//:: Created By: Preston Watamaniuk
|
|
//:: Created On: Nov 19, 2001
|
|
void CheckIsUnlocked(object oLastObject);
|
|
|
|
// This function is now just a wrapper around the functions
|
|
// PlayMobileAmbientAnimations_Nonavian() and
|
|
// PlayMobileAmbientAnimations_Avian(), in x0_i0_anims
|
|
void PlayMobileAmbientAnimations();
|
|
|
|
// 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.
|
|
void DetermineSpecialBehavior(object oIntruder = OBJECT_INVALID);
|
|
|
|
// * Am I in a invisible or stealth state or sanctuary?
|
|
int InvisibleTrue(object oSelf = OBJECT_SELF);
|
|
|
|
/**********************************************************************
|
|
* FUNCTION DEFINITIONS
|
|
**********************************************************************/
|
|
|
|
//::///////////////////////////////////////////////
|
|
//:: AdjustBehaviorVariable
|
|
//:: Copyright (c) 2001 Bioware Corp.
|
|
//:://////////////////////////////////////////////
|
|
/*
|
|
Overriding "behavior" variables.
|
|
If a variable has been stored on the creature it overrides the above
|
|
class defaults
|
|
*/
|
|
//:://////////////////////////////////////////////
|
|
//:: Created By:
|
|
//:: Created On:
|
|
//:://////////////////////////////////////////////
|
|
|
|
int AdjustBehaviorVariable(int nVar, string sVarName)
|
|
{
|
|
int nPlace =GetLocalInt(OBJECT_SELF, sVarName);
|
|
if (nPlace > 0)
|
|
{
|
|
return nPlace;
|
|
}
|
|
//return nVar; // * return the original value
|
|
return 0;
|
|
}
|
|
|
|
//::///////////////////////////////////////////////
|
|
//:: InvisibleBecome
|
|
//:: Copyright (c) 2003 Bioware Corp.
|
|
//:://////////////////////////////////////////////
|
|
/*
|
|
A more intelligent invisibility solution,
|
|
along the lines of the one used in
|
|
the various end-user AIs.
|
|
*/
|
|
//:://////////////////////////////////////////////
|
|
//:: Created By: Brent
|
|
//:: Created On: June 14, 2003
|
|
//:://////////////////////////////////////////////
|
|
int InvisibleBecome(object oSelf = OBJECT_SELF)
|
|
{
|
|
int iDarkness = FALSE;
|
|
if(GetHasSpell(SPELL_DARKNESS) && GetHasSpell(SPELL_DARKVISION)) iDarkness = TRUE;
|
|
if(GetHasSpell(SPELL_IMPROVED_INVISIBILITY) || GetHasSpell(SPELL_INVISIBILITY) ||
|
|
GetHasSpell(SPELL_INVISIBILITY_SPHERE) || (iDarkness) || GetHasSpell(SPELL_SANCTUARY)
|
|
|| GetHasSpell(SPELL_ETHEREALNESS)
|
|
|| GetHasFeat(FEAT_HIDE_IN_PLAIN_SIGHT, oSelf) == TRUE)
|
|
{
|
|
|
|
// * cannot already be invisible, otherwise what is the point
|
|
if(InvisibleTrue(oSelf) == FALSE)
|
|
{
|
|
// * this bit ported directly from Jasperre
|
|
// Can anyone see me? (has spell effects of X)
|
|
// * The point of this is to see if its even worthwhile to go invisbile
|
|
// * or will it be immediately dispeled.
|
|
object oSeeMe = GetNearestCreature(CREATURE_TYPE_REPUTATION, REPUTATION_TYPE_ENEMY, OBJECT_SELF, 1, CREATURE_TYPE_PERCEPTION, PERCEPTION_SEEN, CREATURE_TYPE_HAS_SPELL_EFFECT, SPELL_TRUE_SEEING);
|
|
if(!GetIsObjectValid(oSeeMe))
|
|
{
|
|
oSeeMe = GetNearestCreature(CREATURE_TYPE_REPUTATION, REPUTATION_TYPE_ENEMY, OBJECT_SELF, 1, CREATURE_TYPE_PERCEPTION, PERCEPTION_SEEN, CREATURE_TYPE_HAS_SPELL_EFFECT, SPELL_SEE_INVISIBILITY);
|
|
// if(!GetIsObjectValid(oSeeMe))
|
|
// {
|
|
// oSeeMe = GetNearestCreature(CREATURE_TYPE_REPUTATION, REPUTATION_TYPE_ENEMY, OBJECT_SELF, 1, CREATURE_TYPE_PERCEPTION, PERCEPTION_SEEN, CREATURE_TYPE_HAS_SPELL_EFFECT, SPELL_INVISIBILITY_PURGE);
|
|
// }
|
|
}
|
|
|
|
|
|
if(!GetIsObjectValid(oSeeMe))
|
|
{
|
|
int nDiff = GetCombatDifficulty(oSelf, TRUE);
|
|
//SpeakString(IntToString(nDiff));
|
|
if (nDiff > -1)
|
|
{
|
|
|
|
ClearActions(1001);
|
|
if (iDarkness==TRUE)
|
|
{
|
|
ActionCastSpellAtObject(SPELL_DARKVISION, oSelf);
|
|
ActionCastSpellAtObject(SPELL_DARKNESS, oSelf);
|
|
return TRUE;
|
|
}
|
|
// if (GetHasSpell(SPELL_IMPROVED_INVISIBILITY, oSelf) == TRUE)
|
|
if (GetHasSpell(SPELL_IMPROVED_INVISIBILITY, oSelf))
|
|
{
|
|
ActionCastSpellAtObject(SPELL_IMPROVED_INVISIBILITY, oSelf);
|
|
return TRUE;
|
|
}
|
|
else
|
|
// if (GetHasSpell(SPELL_INVISIBILITY, oSelf) == TRUE)
|
|
if (GetHasSpell(SPELL_INVISIBILITY, oSelf))
|
|
{
|
|
ActionCastSpellAtObject(SPELL_INVISIBILITY, oSelf);
|
|
return TRUE;
|
|
}
|
|
else
|
|
// if (GetHasSpell(SPELL_INVISIBILITY_SPHERE, oSelf) == TRUE)
|
|
if (GetHasSpell(SPELL_INVISIBILITY_SPHERE, oSelf))
|
|
{
|
|
ActionCastSpellAtObject(SPELL_INVISIBILITY_SPHERE, oSelf);
|
|
return TRUE;
|
|
}
|
|
else
|
|
// if (GetHasSpell(SPELL_ETHEREALNESS, oSelf) == TRUE)
|
|
if (GetHasSpell(SPELL_ETHEREALNESS, oSelf))
|
|
{
|
|
ActionCastSpellAtObject(SPELL_ETHEREALNESS, oSelf);
|
|
return TRUE;
|
|
}
|
|
else
|
|
// if (GetHasSpell(SPELL_SANCTUARY, oSelf) == TRUE)
|
|
if (GetHasSpell(SPELL_SANCTUARY, oSelf))
|
|
{
|
|
ActionCastSpellAtObject(SPELL_SANCTUARY, oSelf);
|
|
return TRUE;
|
|
}
|
|
else
|
|
if (GetHasFeat(FEAT_HIDE_IN_PLAIN_SIGHT, oSelf))
|
|
// * go into stealth mode
|
|
{
|
|
// SpeakString("Attempting stealth mode");
|
|
SetActionMode(OBJECT_SELF, ACTION_MODE_STEALTH, TRUE);
|
|
WrapperActionAttack(GetNearestEnemy());
|
|
return TRUE;
|
|
}
|
|
|
|
}
|
|
}
|
|
}// is NOT invisible
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
//::///////////////////////////////////////////////
|
|
//:: InvisibleTrue
|
|
//:: Copyright (c) 2003 Bioware Corp.
|
|
//:://////////////////////////////////////////////
|
|
/*
|
|
Returns TRUE if oSelf is hidden either
|
|
magically or via stealth
|
|
|
|
*/
|
|
//:://////////////////////////////////////////////
|
|
//:: Created By: Brent
|
|
//:: Created On: July 14, 2003
|
|
//:://////////////////////////////////////////////
|
|
|
|
int InvisibleTrue(object oSelf =OBJECT_SELF)
|
|
{
|
|
if(GetHasEffect(EFFECT_TYPE_INVISIBILITY, oSelf) || GetHasEffect(EFFECT_TYPE_IMPROVEDINVISIBILITY, oSelf)
|
|
|| (GetHasSpellEffect(SPELL_DARKNESS, oSelf) && GetHasSpellEffect(SPELL_DARKVISION, oSelf))
|
|
|| GetActionMode(oSelf, ACTION_MODE_STEALTH) || GetHasEffect(EFFECT_TYPE_SANCTUARY, oSelf)
|
|
|| GetHasEffect(EFFECT_TYPE_ETHEREAL, oSelf))
|
|
{
|
|
return TRUE;
|
|
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
// * Returns true if a wizard or sorcerer and wearing armor
|
|
int GetShouldNotCastSpellsBecauseofArmor(object oTarget, int nClass)
|
|
{
|
|
|
|
if (GetArcaneSpellFailure(oTarget) > 15 && (nClass == CLASS_TYPE_SORCERER || nClass == CLASS_TYPE_WIZARD))
|
|
{
|
|
return TRUE;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
//::///////////////////////////////////////////////
|
|
//:: chooseTactics
|
|
//:: Copyright (c) 2001 Bioware Corp.
|
|
//:://////////////////////////////////////////////
|
|
/*
|
|
Separated this function out from DetermineCombatRound
|
|
for readibility
|
|
*/
|
|
//:://////////////////////////////////////////////
|
|
//:: Created By: Brent
|
|
//:: Created On: September 2002
|
|
//:://////////////////////////////////////////////
|
|
|
|
int chooseTactics(object oIntruder)
|
|
{
|
|
|
|
// SELF PRESERVATION: Always attempt to heal self first
|
|
if(TalentHealingSelf() == TRUE) return 99; //Use spells and potions
|
|
|
|
// Next, try the special tactics routines
|
|
// specific to XP1
|
|
if (SpecialTactics(oIntruder)) return 99;
|
|
|
|
// * These constants in ChooseTactics routine
|
|
// * remember previous rounds choices
|
|
|
|
//moved to top of script, made into real constants
|
|
//int MEMORY_OFFENSE_MELEE = 0;
|
|
//int MEMORY_DEFENSE_OTHERS = 1;
|
|
//int MEMORY_DEFENSE_SELF = 2;
|
|
//int MEMORY_OFFENSE_SPELL = 3;
|
|
|
|
// * If defensive last round, try to be offensive this round
|
|
// * this is to prevent wasting time on multiple protections
|
|
int nPreviousMemory = GetLocalInt(OBJECT_SELF, "NW_L_MEMORY");
|
|
|
|
int nClass = DetermineClassToUse();
|
|
|
|
//This does not seem to be used, so no point declaring it...
|
|
//int nCrazy = 0;
|
|
|
|
// * Defaulted high so unspecified classes will not be cowards
|
|
int nOffense = 50;
|
|
|
|
int nCompassion = 25;
|
|
|
|
// * Defaulted this high because non standard creatures
|
|
// * with spells should try and use them.
|
|
int nMagic = 55;
|
|
|
|
// * setup base BEHAVIOR
|
|
switch (nClass)
|
|
{
|
|
case CLASS_TYPE_COMMONER:
|
|
// Commoners should run away from fights
|
|
//SpawnScriptDebugger();
|
|
nOffense = 0; nCompassion = 0; nMagic = 0; break;
|
|
case CLASS_TYPE_PALEMASTER:
|
|
case CLASS_TYPE_WIZARD:
|
|
case CLASS_TYPE_SORCERER:
|
|
// SpawnScriptDebugger();
|
|
nOffense = 40; nCompassion = 40; nMagic = 100; break;
|
|
case CLASS_TYPE_BARD:
|
|
case CLASS_TYPE_HARPER:
|
|
case CLASS_TYPE_DRAGONDISCIPLE:
|
|
{
|
|
if(TalentBardSong() == TRUE) return 99;
|
|
nOffense = 40; nCompassion = 42; nMagic = 43; break;
|
|
}
|
|
case CLASS_TYPE_CLERIC:
|
|
case CLASS_TYPE_DRUID:
|
|
case CLASS_TYPE_SHIFTER:
|
|
{
|
|
nOffense = 40;
|
|
nCompassion = 45;
|
|
nMagic = 44;
|
|
// * Clerics shouldn't constantly cast spells
|
|
if (nPreviousMemory != chooseTactics_MEMORY_OFFENSE_MELEE)
|
|
nMagic = Random(50) + 1;
|
|
break;
|
|
}
|
|
case CLASS_TYPE_PALADIN :
|
|
case CLASS_TYPE_RANGER :
|
|
nOffense = 40; nCompassion = 25; nMagic = Random(50) + 1; break;
|
|
case CLASS_TYPE_BARBARIAN:
|
|
{
|
|
// SpawnScriptDebugger();
|
|
// * GetHasFeat(...) does not work correctly with no-leveled up
|
|
// * characters. So for now, only Xanos gets to do this.
|
|
string sTag = GetTag(OBJECT_SELF);
|
|
//if (sTag == "x0_hen_xan" || sTag == "x2_hen_daelan")
|
|
//{
|
|
if (GetHasFeatEffect(FEAT_BARBARIAN_RAGE) == FALSE)
|
|
{
|
|
|
|
if (GetHasFeat(FEAT_BARBARIAN_RAGE) == TRUE)
|
|
{
|
|
ActionUseFeat(FEAT_BARBARIAN_RAGE, OBJECT_SELF);
|
|
return 99;
|
|
}
|
|
}
|
|
//}
|
|
nOffense = 50; nCompassion = 25; nMagic = 20; break;
|
|
// * set high magic to use rage
|
|
// * suggestion don't give barbarians lots of magic or else they will fight oddly
|
|
}
|
|
case CLASS_TYPE_WEAPON_MASTER:
|
|
case CLASS_TYPE_ARCANE_ARCHER:
|
|
case CLASS_TYPE_BLACKGUARD:
|
|
case CLASS_TYPE_SHADOWDANCER:
|
|
case CLASS_TYPE_DWARVENDEFENDER:
|
|
case CLASS_TYPE_ASSASSIN:
|
|
case CLASS_TYPE_FIGHTER:
|
|
case CLASS_TYPE_ROGUE : //SpawnScriptDebugger();
|
|
case CLASS_TYPE_MONK :
|
|
nOffense = 40; nCompassion = 0; nMagic = 0; break;
|
|
case CLASS_TYPE_UNDEAD:
|
|
nOffense = 40; nCompassion = 40; nMagic = 40; break;
|
|
case CLASS_TYPE_OUTSIDER:
|
|
{
|
|
nOffense = 40; nMagic = 40;
|
|
if (GetAlignmentGoodEvil(OBJECT_SELF) == ALIGNMENT_GOOD)
|
|
{
|
|
nCompassion = 40;
|
|
}
|
|
else nCompassion = 0;
|
|
break;
|
|
}
|
|
case CLASS_TYPE_CONSTRUCT:
|
|
case CLASS_TYPE_ELEMENTAL:
|
|
nOffense = 40; nCompassion = 0; nMagic = 40; break;
|
|
case CLASS_TYPE_DRAGON:
|
|
nOffense = 40; nCompassion = 20; nMagic = 40; break;
|
|
default:
|
|
nOffense = 50; nCompassion = 25; nMagic = 55; break;
|
|
}
|
|
|
|
//really minor optimization - since this bit doesn't rely on the variables set
|
|
//below, might as well check it before we do all those calculations
|
|
// * Dragon Disciple Breath
|
|
if (GetHasFeat(FEAT_DRAGON_DIS_BREATH) && Random(100) > 50)
|
|
{
|
|
ClearActions(2000);
|
|
ActionCastSpellAtObject(690, GetNearestEnemy(), METAMAGIC_ANY, TRUE);
|
|
DecrementRemainingFeatUses(OBJECT_SELF, FEAT_DRAGON_DIS_BREATH);
|
|
return 99;
|
|
}
|
|
|
|
|
|
// MyPrintString("Made it past the class-specific settings");
|
|
|
|
|
|
// ************************************
|
|
// * MODIFY BEHAVIOR FOR SPECIAL CASES
|
|
// ************************************
|
|
if (GetRacialType(OBJECT_SELF) == RACIAL_TYPE_UNDEAD)
|
|
nCompassion = nCompassion - 20;
|
|
|
|
// Randomize things a bit
|
|
//seems that nCrazy is always 0, so might as well comment them out
|
|
nOffense = Random(10 /*+ nCrazy*/) + nOffense;
|
|
nMagic = Random(10 /*+ nCrazy*/) + nMagic;
|
|
nCompassion = Random(10 /*+ nCrazy*/) + nCompassion;
|
|
|
|
|
|
|
|
// * if your opponent is close to you, then increase offense
|
|
// * as casting defensive abilities when enemies are close
|
|
// * is generally not a good idea.
|
|
// * Dec 18 2002: If you have Combat Casting, you'll still be more
|
|
// * liable to use defensive abilities
|
|
if (GetIsObjectValid(oIntruder) && !GetHasFeat(FEAT_COMBAT_CASTING))
|
|
{
|
|
if (GetDistanceToObject(oIntruder) <= 5.0) {
|
|
nOffense = nOffense + 20;
|
|
nMagic = nMagic - 20;
|
|
}
|
|
}
|
|
|
|
// * If enemies are further away, more chance of doing magic
|
|
if (GetDistanceToObject(oIntruder) > 3.0)
|
|
nMagic = nMagic + 15;
|
|
|
|
// * Dec 18 2002: Add your level to your magic rating
|
|
nMagic = nMagic + GetHitDice(OBJECT_SELF);
|
|
|
|
|
|
// **************************************
|
|
// * CHOOSE TALENT TO USE
|
|
// **************************************
|
|
|
|
//SpawnScriptDebugger();
|
|
|
|
// * If defensive last round, try to be offensive this round
|
|
// * this is to prevent wasting time on multiple protections
|
|
if ((nPreviousMemory == chooseTactics_MEMORY_DEFENSE_OTHERS)
|
|
|| (nPreviousMemory == chooseTactics_MEMORY_DEFENSE_SELF))
|
|
{
|
|
nOffense = nOffense + 40;
|
|
}
|
|
|
|
|
|
// April 2003
|
|
// If in rage should be almost no chance of doing magic
|
|
// * June 2003
|
|
// * If has more than 5% chance of spell failure don't try casting
|
|
// 5% chance changed to 15%
|
|
if (GetHasFeatEffect(FEAT_BARBARIAN_RAGE)== TRUE || GetShouldNotCastSpellsBecauseofArmor(OBJECT_SELF, nClass) == TRUE
|
|
|| GetLocalInt(OBJECT_SELF, "X2_L_STOPCASTING") == 10)
|
|
{
|
|
nMagic = 0;
|
|
}
|
|
|
|
|
|
|
|
|
|
// **************
|
|
// * JULY 12 2003
|
|
// * Overriding "behavior" variables.
|
|
// * If a variable has been stored on the creature it overrides the above
|
|
// * class defaults
|
|
// * JULY 28 2003
|
|
// * changed this so that its an additive process, not an overrwrite.
|
|
// * gives more flexiblity.
|
|
// **************
|
|
nMagic = nMagic + AdjustBehaviorVariable(nMagic, "X2_L_BEH_MAGIC");
|
|
nOffense = nOffense + AdjustBehaviorVariable(nOffense, "X2_L_BEH_OFFENSE");
|
|
nCompassion = nCompassion + AdjustBehaviorVariable(nCompassion, "X2_L_BEH_COMPASSION");
|
|
|
|
|
|
// * If invisbile of any sort, become Defensive and
|
|
// * magical to use any buffs you may have
|
|
// * This behavior variable setting should override all others
|
|
// * October 22 2003 - Lines 690 and 713 modified to only work if magic
|
|
// * setting has not been turned off. Nathyrra always going invisible
|
|
// * can be annoying.
|
|
if (InvisibleTrue(OBJECT_SELF) == TRUE && nMagic > 0)
|
|
{
|
|
// SpawnScriptDebugger();
|
|
// * if wounded at all take this time to heal self
|
|
// * since I am invisible there is little danger from doing this
|
|
if (GetCurrentHitPoints(OBJECT_SELF) < GetMaxHitPoints(OBJECT_SELF))
|
|
{
|
|
if(TalentHealingSelf(TRUE) == TRUE) return 99;
|
|
}
|
|
|
|
nOffense = 7;
|
|
nMagic = 100;
|
|
|
|
if (GetActionMode(OBJECT_SELF, ACTION_MODE_STEALTH) == TRUE)
|
|
{
|
|
nOffense = 100; // * if in stealth attempt sneak attacks
|
|
}
|
|
}
|
|
else
|
|
// **************
|
|
// * JULY 14 2003
|
|
// * Attempt To Go Invisible
|
|
// **************
|
|
if (InvisibleBecome() == TRUE && nMagic > 0)
|
|
return 99;
|
|
|
|
// PHYSICAL, NO OFFENSE
|
|
if (nOffense <= 5)
|
|
{
|
|
//SpawnScriptDebugger();
|
|
//SpeakString("fleeing");
|
|
if (TalentFlee(oIntruder) == TRUE) return 99;
|
|
}
|
|
|
|
// protect others: MAGICAL, DEFENSE, COMPASSION
|
|
if ((nOffense<= 50) && (nMagic > 50) && (nCompassion > 50))
|
|
{
|
|
SetLocalInt(OBJECT_SELF, "NW_L_MEMORY", chooseTactics_MEMORY_DEFENSE_OTHERS);
|
|
if (TalentHeal() == TRUE) return 99;
|
|
if (TalentCureCondition() == TRUE) return 99;
|
|
if (TalentUseProtectionOthers() == TRUE) return 99;
|
|
if (TalentEnhanceOthers() == TRUE) return 99;
|
|
|
|
// * Temporarily be non-compassionate to buff self
|
|
// * if we got to this point.
|
|
nCompassion = 0;
|
|
}
|
|
|
|
// protectself: MAGICAL, DEFENSE, NO COMPASSION
|
|
if ((nOffense<= 50) && (nMagic > 50) && (nCompassion <=50))
|
|
{
|
|
SetLocalInt(OBJECT_SELF, "NW_L_MEMORY", chooseTactics_MEMORY_DEFENSE_SELF);
|
|
|
|
/* Dec 19 2002:
|
|
Against spell-casters, cast protection spells more often
|
|
*/
|
|
int nClass = GetClassByPosition(1,oIntruder);
|
|
if (nClass == CLASS_TYPE_WIZARD || nClass == CLASS_TYPE_SORCERER
|
|
|| nClass == CLASS_TYPE_CLERIC || nClass == CLASS_TYPE_DRUID)
|
|
{
|
|
if (TalentSelfProtectionMantleOrGlobe())
|
|
return 99;
|
|
}
|
|
|
|
if(TalentUseProtectionOnSelf() == TRUE) return 99;
|
|
if(TalentUseEnhancementOnSelf() == TRUE) return 99;
|
|
if(TalentPersistentAbilities() == TRUE) return 99;
|
|
// int TalentAdvancedBuff(float fDistance);
|
|
|
|
//Used for Potions of Enhancement and Protection
|
|
if(TalentBuffSelf() == TRUE) return 99;
|
|
|
|
if(TalentAdvancedProtectSelf() == TRUE) return 99;
|
|
if(TalentSummonAllies() == TRUE) return 99;
|
|
if(TalentSeeInvisible() == TRUE) return 99;
|
|
if(TalentMeleeAttacked(oIntruder) == TRUE) return 99;
|
|
if(TalentRangedAttackers(oIntruder) == TRUE) return 99;
|
|
if(TalentRangedEnemies(oIntruder) == TRUE) return 99;
|
|
|
|
|
|
}
|
|
|
|
// MAGICAL, OFFENSE
|
|
if (nMagic > 50)
|
|
{
|
|
// // MyPrintString("in offensive spell");
|
|
// SpawnScriptDebugger();
|
|
SetLocalInt(OBJECT_SELF, "NW_L_MEMORY", chooseTactics_MEMORY_OFFENSE_SPELL);
|
|
if (TalentUseTurning() == TRUE) return 99;
|
|
if (TalentSpellAttack(oIntruder) == TRUE) return 99;
|
|
}
|
|
|
|
// If we got here, we're going to melee offense
|
|
SetLocalInt(OBJECT_SELF, "NW_L_MEMORY", chooseTactics_MEMORY_OFFENSE_MELEE);
|
|
|
|
// PHYSICAL, OFFENSE (if nothing else applies)
|
|
if (TryKiDamage(oIntruder) == TRUE) return 99;
|
|
if (TalentSneakAttack() == TRUE) return 99;
|
|
if (TalentDragonCombat(oIntruder)) {return 99;}
|
|
if (TalentMeleeAttack(oIntruder) == TRUE) return 99;
|
|
|
|
|
|
object oHostile = GetNearestSeenEnemy();
|
|
|
|
// * Feb 17 2003: This error could happen in the situation that someone
|
|
// * went into combat mode and their 'hostility' ended while going through ChooseTactics
|
|
if (GetIsObjectValid(oHostile) == TRUE)
|
|
{
|
|
|
|
// * BK if it returns this it means the AI found nothing
|
|
// * Appropriate to do
|
|
//SpeakString("BUG!!!!!!!!!!!!!!!!!!!!!!!! (Let Brent Knowles know about this. Supply savegame) Nothing valid to do !!!!!!!!!!!!!!!!!!!!!");
|
|
//SpeakString("BUG!! Magic " + IntToString(nMagic) + " Compassion " + IntToString(nCompassion) + " Offense " + IntToString(nOffense));
|
|
}
|
|
return 1;
|
|
|
|
} // * END of choosetactics
|
|
|
|
//::///////////////////////////////////////////////
|
|
//:: __InCombatRound
|
|
//:: Copyright (c) 2001 Bioware Corp.
|
|
//:://////////////////////////////////////////////
|
|
/*
|
|
Tests to see if already running a determine
|
|
combatround this round.
|
|
*/
|
|
//:://////////////////////////////////////////////
|
|
//:: Created By: Brent
|
|
//:: Created On: July 11 2003
|
|
//:://////////////////////////////////////////////
|
|
int __InCombatRound()
|
|
{
|
|
|
|
// * if just in attackaction, turn combat round off
|
|
// * if simply fighting it is okay to turn the combat round off
|
|
// * and try again because it doesn't hurt an attackaction
|
|
// * to be reiniated whereas it does break a spell
|
|
int nCurrentAction = GetCurrentAction(OBJECT_SELF);
|
|
if (nCurrentAction == ACTION_ATTACKOBJECT || nCurrentAction == ACTION_INVALID || nCurrentAction == ACTION_MOVETOPOINT)
|
|
{
|
|
return FALSE;
|
|
}
|
|
if (GetLocalInt(OBJECT_SELF, "X2_L_MUTEXCOMBATROUND") == TRUE)
|
|
{
|
|
//SpeakString("DEBUG:: In Combat Round, busy.");
|
|
return TRUE;
|
|
}
|
|
return FALSE;
|
|
}
|
|
//::///////////////////////////////////////////////
|
|
//:: __TurnCombatRoundOn
|
|
//:: Copyright (c) 2001 Bioware Corp.
|
|
//:://////////////////////////////////////////////
|
|
/*
|
|
Will set the exclusion variable on whether
|
|
in combat or not.
|
|
This is to prevent multiple firings
|
|
of determinecombatround in one round
|
|
*/
|
|
//:://////////////////////////////////////////////
|
|
//:: Created By: Brent
|
|
//:: Created On: July 11 2003
|
|
//:://////////////////////////////////////////////
|
|
|
|
void __TurnCombatRoundOn(int bBool)
|
|
{
|
|
if (bBool == TRUE)
|
|
{
|
|
SetLocalInt(OBJECT_SELF, "X2_L_MUTEXCOMBATROUND", TRUE);
|
|
}
|
|
else
|
|
{
|
|
// * delay it turning off like an action
|
|
ActionDoCommand(SetLocalInt(OBJECT_SELF, "X2_L_MUTEXCOMBATROUND", FALSE));
|
|
}
|
|
}
|
|
//::///////////////////////////////////////////////
|
|
//:: DetermineCombatRound
|
|
//:: Copyright (c) 2001 Bioware Corp.
|
|
//:://////////////////////////////////////////////
|
|
/*
|
|
This function is the master function for the
|
|
generic include and is called from the main
|
|
script. This function is used in lieu of
|
|
any actual scripting.
|
|
*/
|
|
//:://////////////////////////////////////////////
|
|
//:: Created By: Preston Watamaniuk
|
|
//:: Created On: Oct 16, 2001
|
|
//:://////////////////////////////////////////////
|
|
|
|
void DetermineCombatRound(object oIntruder = OBJECT_INVALID, int nAI_Difficulty = 10)
|
|
{
|
|
// MyPrintString("************** DETERMINE COMBAT ROUND START *************");
|
|
// MyPrintString("************** " + GetTag(OBJECT_SELF) + " ************");
|
|
|
|
// ----------------------------------------------------------------------------------------
|
|
// May 2003
|
|
// Abort out of here, if petrified
|
|
// ----------------------------------------------------------------------------------------
|
|
if (GetHasEffect(EFFECT_TYPE_PETRIFY, OBJECT_SELF) == TRUE)
|
|
{
|
|
return;
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------------------
|
|
// Oct 06/2003 - Georg Zoeller,
|
|
// Fix for ActionRandomWalk blocking the action queue under certain circumstances
|
|
// ----------------------------------------------------------------------------------------
|
|
if (GetCurrentAction() == ACTION_RANDOMWALK)
|
|
{
|
|
ClearAllActions();
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------------------
|
|
// July 27/2003 - Georg Zoeller,
|
|
// Added to allow a replacement for determine combat round
|
|
// If a creature has a local string variable named X2_SPECIAL_COMBAT_AI_SCRIPT
|
|
// set, the script name specified in the variable gets run instead
|
|
// see x2_ai_behold for details:
|
|
// ----------------------------------------------------------------------------------------
|
|
string sSpecialAI = GetLocalString(OBJECT_SELF,"X2_SPECIAL_COMBAT_AI_SCRIPT");
|
|
if (sSpecialAI != "")
|
|
{
|
|
SetLocalObject(OBJECT_SELF,"X2_NW_I0_GENERIC_INTRUDER", oIntruder);
|
|
ExecuteScript(sSpecialAI, OBJECT_SELF);
|
|
if (GetLocalInt(OBJECT_SELF,"X2_SPECIAL_COMBAT_AI_SCRIPT_OK"))
|
|
{
|
|
DeleteLocalInt(OBJECT_SELF,"X2_SPECIAL_COMBAT_AI_SCRIPT_OK");
|
|
return;
|
|
}
|
|
}
|
|
|
|
|
|
// ----------------------------------------------------------------------------------------
|
|
// DetermineCombatRound: EVALUATIONS
|
|
// ----------------------------------------------------------------------------------------
|
|
if(GetAssociateState(NW_ASC_IS_BUSY))
|
|
{
|
|
return;
|
|
}
|
|
|
|
if(BashDoorCheck(oIntruder)) {return;}
|
|
|
|
// ----------------------------------------------------------------------------------------
|
|
// BK: stop fighting if something bizarre that shouldn't happen, happens
|
|
// ----------------------------------------------------------------------------------------
|
|
|
|
if (bkEvaluationSanityCheck(oIntruder, GetFollowDistance()) == TRUE)
|
|
return;
|
|
|
|
// ** Store HOw Difficult the combat is for this round
|
|
int nDiff = GetCombatDifficulty();
|
|
SetLocalInt(OBJECT_SELF, "NW_L_COMBATDIFF", nDiff);
|
|
|
|
// MyPrintString("COMBAT: " + IntToString(nDiff));
|
|
|
|
// ----------------------------------------------------------------------------------------
|
|
// If no special target has been passed into the function
|
|
// then choose an appropriate target
|
|
// ----------------------------------------------------------------------------------------
|
|
if (GetIsObjectValid(oIntruder) == FALSE)
|
|
oIntruder = bkAcquireTarget();
|
|
|
|
|
|
if (GetIsDead(oIntruder) == TRUE)
|
|
{
|
|
// ----------------------------------------------------------------------------------------
|
|
// If for some reason my target is dead, then leave
|
|
// the poor guy alone. Jeez. What kind of monster am I?
|
|
// ----------------------------------------------------------------------------------------
|
|
return;
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------------------
|
|
/*
|
|
JULY 11 2003
|
|
If in combat round already (variable set) do not enter it again.
|
|
This is meant to prevent multiple calls to DetermineCombatRound
|
|
from happening during the *same* round.
|
|
|
|
This variable is turned on at the start of this function call.
|
|
It is turned off at each "return" point for this function
|
|
*/
|
|
// ----------------------------------------------------------------------------------------
|
|
if (__InCombatRound() == TRUE)
|
|
{
|
|
return;
|
|
}
|
|
|
|
__TurnCombatRoundOn(TRUE);
|
|
|
|
// ----------------------------------------------------------------------------------------
|
|
// DetermineCombatRound: ACTIONS
|
|
// ----------------------------------------------------------------------------------------
|
|
if(GetIsObjectValid(oIntruder))
|
|
{
|
|
|
|
if(TalentPersistentAbilities()) // * Will put up things like Auras quickly
|
|
{
|
|
__TurnCombatRoundOn(FALSE);
|
|
return;
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------------------
|
|
// BK September 2002
|
|
// If a succesful tactic has been chosen then
|
|
// exit this function directly
|
|
// ----------------------------------------------------------------------------------------
|
|
|
|
if (chooseTactics(oIntruder) == 99)
|
|
{
|
|
__TurnCombatRoundOn(FALSE);
|
|
return;
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------------------
|
|
// This check is to make sure that people do not drop out of
|
|
// combat before they are supposed to.
|
|
// ----------------------------------------------------------------------------------------
|
|
|
|
object oNearEnemy = GetNearestSeenEnemy();
|
|
DetermineCombatRound(oNearEnemy);
|
|
|
|
return;
|
|
}
|
|
__TurnCombatRoundOn(FALSE);
|
|
|
|
// ----------------------------------------------------------------------------------------
|
|
// This is a call to the function which determines which
|
|
// way point to go back to.
|
|
// ----------------------------------------------------------------------------------------
|
|
ClearActions(CLEAR_NW_I0_GENERIC_658);
|
|
SetLocalObject(OBJECT_SELF,
|
|
"NW_GENERIC_LAST_ATTACK_TARGET",
|
|
OBJECT_INVALID);
|
|
WalkWayPoints();
|
|
}
|
|
|
|
|
|
|
|
//::///////////////////////////////////////////////
|
|
//:: Respond To Shouts
|
|
//:: Copyright (c) 2001 Bioware Corp.
|
|
//:://////////////////////////////////////////////
|
|
/*
|
|
Allows the listener to react in a manner
|
|
consistant with the given shout but only to one
|
|
combat shout per round
|
|
*/
|
|
//:://////////////////////////////////////////////
|
|
//:: Created By: Preston Watamaniuk
|
|
//:: Created On: Oct 25, 2001
|
|
//:://////////////////////////////////////////////
|
|
|
|
//NOTE ABOUT COMMONERS
|
|
/*
|
|
Commoners are universal cowards. If you attack anyone they will flee for 4 seconds away from the attacker.
|
|
However to make the commoners into a mob, make a single commoner at least 10th level of the same faction.
|
|
If that higher level commoner is attacked or killed then the commoners will attack the attacker. They will disperse again
|
|
after some of them are killed. Should NOT make multi-class creatures using commoners.
|
|
*/
|
|
//NOTE ABOUT BLOCKERS
|
|
/*
|
|
It should be noted that the Generic Script for On Dialogue attempts to get a local set on the shouter by itself.
|
|
This object represents the LastOpenedBy object. It is this object that becomes the oIntruder within this function.
|
|
*/
|
|
|
|
//NOTE ABOUT INTRUDERS
|
|
/*
|
|
The intruder object is for cases where a placable needs to pass a LastOpenedBy Object or a AttackMyAttacker
|
|
needs to make his attacker the enemy of everyone.
|
|
*/
|
|
|
|
void RespondToShout(object oShouter, int nShoutIndex, object oIntruder = OBJECT_INVALID)
|
|
{
|
|
|
|
// Pausanias: Do not respond to shouts if you've surrendered.
|
|
int iSurrendered = GetLocalInt(OBJECT_SELF,"Generic_Surrender");
|
|
if (iSurrendered) return;
|
|
|
|
switch (nShoutIndex)
|
|
{
|
|
case 1://NW_GENERIC_SHOUT_I_WAS_ATTACKED:
|
|
{
|
|
object oTarget = oIntruder;
|
|
if(!GetIsObjectValid(oTarget))
|
|
{
|
|
oTarget = GetLastHostileActor(oShouter);
|
|
}
|
|
if(!GetBehaviorState(NW_FLAG_BEHAVIOR_SPECIAL))
|
|
{
|
|
if(!GetLevelByClass(CLASS_TYPE_COMMONER))
|
|
{
|
|
if(!GetIsObjectValid(GetAttemptedAttackTarget()) && !GetIsObjectValid(GetAttemptedSpellTarget()))
|
|
{
|
|
if(GetIsObjectValid(oTarget))
|
|
{
|
|
if(!GetIsFriend(oTarget) && GetIsFriend(oShouter))
|
|
{
|
|
RemoveAmbientSleep();
|
|
//DetermineCombatRound(oTarget);
|
|
DetermineCombatRound(GetLastHostileActor(oShouter));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else if (GetLevelByClass(CLASS_TYPE_COMMONER, oShouter) >= 10)
|
|
{
|
|
WrapperActionAttack(GetLastHostileActor(oShouter));
|
|
}
|
|
else
|
|
{
|
|
DetermineCombatRound(oIntruder);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
DetermineSpecialBehavior();
|
|
}
|
|
}
|
|
break;
|
|
|
|
case 2://NW_GENERIC_SHOUT_MOB_ATTACK:
|
|
{
|
|
if(!GetBehaviorState(NW_FLAG_BEHAVIOR_SPECIAL))
|
|
{
|
|
|
|
//Is friendly check to make sure that only like minded commoners attack.
|
|
if(GetIsFriend(oShouter))
|
|
{
|
|
WrapperActionAttack(GetLastHostileActor(oShouter));
|
|
}
|
|
//if(TalentMeleeAttack()) {return;}
|
|
}
|
|
else
|
|
{
|
|
DetermineSpecialBehavior();
|
|
}
|
|
}
|
|
break;
|
|
|
|
case 3://NW_GENERIC_SHOUT_I_AM_DEAD:
|
|
{
|
|
if(!GetBehaviorState(NW_FLAG_BEHAVIOR_SPECIAL))
|
|
{
|
|
//Use I was attacked script above
|
|
if(!GetLevelByClass(CLASS_TYPE_COMMONER))
|
|
{
|
|
if(!GetIsObjectValid(GetAttemptedAttackTarget()) && !GetIsObjectValid(GetAttemptedSpellTarget()))
|
|
{
|
|
if(GetIsObjectValid(GetLastHostileActor(oShouter)))
|
|
{
|
|
if(!GetIsFriend(GetLastHostileActor(oShouter)) && GetIsFriend(oShouter))
|
|
{
|
|
DetermineCombatRound(GetLastHostileActor(oShouter));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else if (GetLevelByClass(CLASS_TYPE_COMMONER, oShouter) >= 10)
|
|
{
|
|
WrapperActionAttack(GetLastHostileActor(oShouter));
|
|
}
|
|
else
|
|
{
|
|
DetermineCombatRound();
|
|
}
|
|
|
|
}
|
|
else
|
|
{
|
|
DetermineSpecialBehavior();
|
|
}
|
|
}
|
|
break;
|
|
//For this shout to work the object must shout the following
|
|
//string sHelp = "NW_BLOCKER_BLK_" + GetTag(OBJECT_SELF);
|
|
case 4: //BLOCKER OBJECT HAS BEEN DISTURBED
|
|
{
|
|
if(!GetLevelByClass(CLASS_TYPE_COMMONER))
|
|
{
|
|
if(!GetIsObjectValid(GetAttemptedAttackTarget()) && !GetIsObjectValid(GetAttemptedSpellTarget()))
|
|
{
|
|
if(GetIsObjectValid(oIntruder))
|
|
{
|
|
SetIsTemporaryEnemy(oIntruder);
|
|
DetermineCombatRound(oIntruder);
|
|
}
|
|
}
|
|
}
|
|
else if (GetLevelByClass(CLASS_TYPE_COMMONER, oShouter) >= 10)
|
|
{
|
|
WrapperActionAttack(oIntruder);
|
|
}
|
|
else
|
|
{
|
|
DetermineCombatRound();
|
|
}
|
|
}
|
|
break;
|
|
|
|
case 5: //ATTACK MY TARGET
|
|
{
|
|
AdjustReputation(oIntruder, OBJECT_SELF, -100);
|
|
if(GetIsFriend(oShouter))
|
|
{
|
|
SetIsTemporaryEnemy(oIntruder);
|
|
ClearActions(CLEAR_NW_I0_GENERIC_834);
|
|
DetermineCombatRound(oIntruder);
|
|
}
|
|
}
|
|
break;
|
|
|
|
case 6: //CALL_TO_ARMS
|
|
{
|
|
//This was once commented out.
|
|
DetermineCombatRound();
|
|
}
|
|
break;
|
|
|
|
//ASSOCIATE SHOUT RESPONSES ******************************************************************************
|
|
|
|
/* This was moved into X0_I0_HENCHMAN as bkRespondToHenchmenShout
|
|
case ASSOCIATE_COMMAND_ATTACKNEAREST: //Used to de-activate AGGRESSIVE DEFEND MODE
|
|
{
|
|
ResetHenchmenState();
|
|
SetAssociateState(NW_ASC_MODE_DEFEND_MASTER, FALSE);
|
|
SetAssociateState(NW_ASC_MODE_STAND_GROUND, FALSE);
|
|
DetermineCombatRound();
|
|
}
|
|
break;
|
|
|
|
case ASSOCIATE_COMMAND_FOLLOWMASTER: //Only used to retreat, or break free from Stand Ground Mode
|
|
{
|
|
ResetHenchmenState();
|
|
SetAssociateState(NW_ASC_MODE_STAND_GROUND, FALSE);
|
|
DelayCommand(2.5, VoiceCanDo());
|
|
|
|
if(GetAssociateState(NW_ASC_AGGRESSIVE_STEALTH))
|
|
{
|
|
//ActionUseSkill(SKILL_HIDE, OBJECT_SELF);
|
|
}
|
|
if(GetAssociateState(NW_ASC_AGGRESSIVE_SEARCH))
|
|
{
|
|
ActionUseSkill(SKILL_SEARCH, OBJECT_SELF);
|
|
}
|
|
ActionForceFollowObject(GetMaster(), GetFollowDistance());
|
|
SetAssociateState(NW_ASC_IS_BUSY);
|
|
DelayCommand(5.0, SetAssociateState(NW_ASC_IS_BUSY, FALSE));
|
|
}
|
|
break;
|
|
|
|
case ASSOCIATE_COMMAND_GUARDMASTER: //Used to activate AGGRESSIVE DEFEND MODE
|
|
{
|
|
ResetHenchmenState();
|
|
DelayCommand(2.5, VoiceCanDo());
|
|
//Companions will only attack the Masters Last Attacker
|
|
SetAssociateState(NW_ASC_MODE_DEFEND_MASTER);
|
|
SetAssociateState(NW_ASC_MODE_STAND_GROUND, FALSE);
|
|
if(GetIsObjectValid(GetLastHostileActor(GetMaster())))
|
|
{
|
|
DetermineCombatRound(GetLastHostileActor(GetMaster()));
|
|
}
|
|
}
|
|
break;
|
|
|
|
case ASSOCIATE_COMMAND_HEALMASTER: //Ignore current healing settings and heal me now
|
|
{
|
|
ResetHenchmenState();
|
|
//SetCommandable(TRUE);
|
|
if(TalentCureCondition()) {DelayCommand(2.0, VoiceCanDo()); return;}
|
|
if(TalentHeal(TRUE)) {DelayCommand(2.0, VoiceCanDo()); return;}
|
|
DelayCommand(2.5, VoiceCannotDo());
|
|
}
|
|
break;
|
|
|
|
case ASSOCIATE_COMMAND_MASTERFAILEDLOCKPICK: //Check local for Re-try locked doors and
|
|
{
|
|
if(!GetAssociateState(NW_ASC_MODE_STAND_GROUND))
|
|
{
|
|
if(GetAssociateState(NW_ASC_RETRY_OPEN_LOCKS))
|
|
{
|
|
int bValid = TRUE;
|
|
object oLastObject = GetLockedObject(GetMaster());
|
|
int nSkill = GetSkillRank(SKILL_OPEN_LOCK) - GetAbilityModifier(ABILITY_DEXTERITY);
|
|
|
|
if(GetIsObjectValid(oLastObject) && GetPlotFlag(oLastObject) == FALSE)
|
|
{
|
|
if(GetIsDoorActionPossible(oLastObject, DOOR_ACTION_KNOCK) || GetIsPlaceableObjectActionPossible(oLastObject, PLACEABLE_ACTION_KNOCK))
|
|
{
|
|
ClarAllActions();
|
|
VoiceCanDo();
|
|
ActionCastSpellAtObject(SPELL_KNOCK, oLastObject);
|
|
ActionWait(1.0);
|
|
bValid = FALSE;
|
|
}
|
|
else if (GetIsDoorActionPossible(oLastObject, DOOR_ACTION_UNLOCK)|| GetIsPlaceableObjectActionPossible(oLastObject, PLACEABLE_ACTION_UNLOCK))
|
|
{
|
|
ClarAllActions();
|
|
VoicePicklock();
|
|
ActionWait(1.0);
|
|
ActionUseSkill(SKILL_OPEN_LOCK,oLastObject);
|
|
bValid = FALSE;
|
|
}
|
|
else if(nSkill < 5 && GetAbilityScore(OBJECT_SELF, ABILITY_STRENGTH) >= 16 && GetSkillRank(SKILL_OPEN_LOCK) <= 0)
|
|
{
|
|
if(GetIsDoorActionPossible(oLastObject, DOOR_ACTION_BASH) || GetIsPlaceableObjectActionPossible(oLastObject, PLACEABLE_ACTION_BASH))
|
|
{
|
|
ClarAllActions();
|
|
VoiceCanDo();
|
|
ActionEquipMostDamagingMelee(oLastObject);
|
|
WrapperActionAttack(oLastObject);
|
|
SetLocalObject(OBJECT_SELF, "NW_GENERIC_DOOR_TO_BASH", oLastObject);
|
|
bValid = FALSE;
|
|
}
|
|
}
|
|
if(bValid == TRUE)
|
|
{
|
|
//ClarAllActions();
|
|
VoiceCannotDo();
|
|
}
|
|
else
|
|
{
|
|
ActionDoCommand(VoiceTaskComplete());
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
|
|
case ASSOCIATE_COMMAND_MASTERUNDERATTACK: //Check whether the master has you in AGGRESSIVE DEFEND MODE
|
|
{
|
|
if(!GetAssociateState(NW_ASC_MODE_STAND_GROUND))
|
|
{
|
|
//Check the henchmens current target
|
|
object oTarget = GetAttemptedAttackTarget();
|
|
if(!GetIsObjectValid(oTarget))
|
|
{
|
|
oTarget = GetAttemptedSpellTarget();
|
|
if(!GetIsObjectValid(oTarget))
|
|
{
|
|
if(GetAssociateState(NW_ASC_MODE_DEFEND_MASTER))
|
|
{
|
|
DetermineCombatRound(GetLastHostileActor(GetMaster()));
|
|
}
|
|
else
|
|
{
|
|
DetermineCombatRound();
|
|
}
|
|
}
|
|
}
|
|
//Switch targets only if the target is not attacking the master and is greater than 6.0 from
|
|
//the master.
|
|
if(GetAttackTarget(oTarget) != GetMaster() && GetDistanceBetween(oTarget, GetMaster()) > 6.0)
|
|
{
|
|
if(GetAssociateState(NW_ASC_MODE_DEFEND_MASTER) && GetIsObjectValid(GetLastHostileActor(GetMaster())))
|
|
{
|
|
DetermineCombatRound(GetLastHostileActor(GetMaster()));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
|
|
case ASSOCIATE_COMMAND_STANDGROUND: //No longer follow the master or guard him
|
|
{
|
|
SetAssociateState(NW_ASC_MODE_STAND_GROUND);
|
|
SetAssociateState(NW_ASC_MODE_DEFEND_MASTER, FALSE);
|
|
DelayCommand(2.0, VoiceCanDo());
|
|
WrapperActionAttack(OBJECT_INVALID);
|
|
ClarAllActions();
|
|
}
|
|
break;
|
|
|
|
case ASSOCIATE_COMMAND_MASTERSAWTRAP:
|
|
{
|
|
int nCheck = 0;
|
|
if(!GetIsInCombat())
|
|
{
|
|
if(!GetAssociateState(NW_ASC_MODE_STAND_GROUND))
|
|
{
|
|
object oTrap = GetLastTrapDetected();
|
|
if(GetIsObjectValid(oTrap))
|
|
{
|
|
int nTrapDC = GetTrapDisarmDC(oTrap);
|
|
int nSkill = GetSkillRank(SKILL_DISABLE_TRAP);
|
|
int nMod = GetAbilityModifier(ABILITY_DEXTERITY);
|
|
if((nSkill - nMod) > 0)
|
|
{
|
|
nSkill = nSkill + 20 - nTrapDC;
|
|
}
|
|
else
|
|
{
|
|
nSkill = 0;
|
|
nCheck = 1;
|
|
}
|
|
|
|
if(GetCurrentAction(OBJECT_SELF) != ACTION_DISABLETRAP && nSkill > 0)
|
|
{
|
|
VoiceStop();
|
|
if(GetHasSkill(SKILL_DISABLE_TRAP, OBJECT_SELF))
|
|
{
|
|
ClarAllActions();
|
|
ActionUseSkill(SKILL_DISABLE_TRAP, oTrap);
|
|
ActionDoCommand(SetCommandable(TRUE));
|
|
ActionDoCommand(VoiceTaskComplete());
|
|
SetCommandable(FALSE);
|
|
nCheck = 2;
|
|
}
|
|
}
|
|
else if(nCheck = 0 &&
|
|
GetSkillRank(SKILL_DISABLE_TRAP) > 0 &&
|
|
GetCurrentAction(OBJECT_SELF) != ACTION_DISABLETRAP)
|
|
{
|
|
VoiceCannotDo();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
|
|
case ASSOCIATE_COMMAND_MASTERATTACKEDOTHER:
|
|
{
|
|
if(!GetAssociateState(NW_ASC_MODE_STAND_GROUND))
|
|
{
|
|
if(!GetAssociateState(NW_ASC_MODE_DEFEND_MASTER))
|
|
{
|
|
if(!GetIsFighting(OBJECT_SELF))
|
|
{
|
|
object oAttack = GetAttackTarget(GetMaster());
|
|
if(GetIsObjectValid(oAttack) && GetObjectSeen(oAttack))
|
|
{
|
|
ClarAllActions();
|
|
DetermineCombatRound(oAttack);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
|
|
case ASSOCIATE_COMMAND_MASTERGOINGTOBEATTACKED:
|
|
{
|
|
if(!GetAssociateState(NW_ASC_MODE_STAND_GROUND))
|
|
{
|
|
if(!GetIsFighting(OBJECT_SELF))
|
|
{
|
|
object oAttacker = GetGoingToBeAttackedBy(GetMaster());
|
|
if(GetIsObjectValid(oAttacker) && GetObjectSeen(oAttacker))
|
|
{
|
|
ClarAllActions();
|
|
DetermineCombatRound(oAttacker);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
|
|
case ASSOCIATE_COMMAND_LEAVEPARTY:
|
|
{
|
|
object oMaster = GetMaster();
|
|
if(GetIsObjectValid(oMaster))
|
|
{
|
|
ClarAllActions();
|
|
if(GetAssociate(ASSOCIATE_TYPE_HENCHMAN, GetMaster()) == OBJECT_SELF)
|
|
{
|
|
AddJournalQuestEntry("Henchman",50,GetMaster(),FALSE,FALSE,TRUE);
|
|
}
|
|
SetLocalObject(OBJECT_SELF,"NW_L_FORMERMASTER", oMaster);
|
|
RemoveHenchman(oMaster, OBJECT_SELF);
|
|
}
|
|
|
|
}
|
|
break; */
|
|
}
|
|
}
|
|
|
|
//::///////////////////////////////////////////////
|
|
//:: Set and Get NPC Warning Status
|
|
//:: Copyright (c) 2001 Bioware Corp.
|
|
//:://////////////////////////////////////////////
|
|
/*
|
|
This function sets a local int on OBJECT_SELF
|
|
which will be checked in the On Attack, On
|
|
Damaged and On Disturbed scripts to check if
|
|
the offending party was a PC and was friendly.
|
|
The Get will return the status of the local.
|
|
*/
|
|
//:://////////////////////////////////////////////
|
|
//:: Created By: Preston Watamaniuk
|
|
//:: Created On: Oct 29, 2001
|
|
//:://////////////////////////////////////////////
|
|
|
|
// NPCs who have warning status set to TRUE will allow
|
|
// one 'free' attack by PCs from a non-hostile faction.
|
|
void SetNPCWarningStatus(int nStatus = TRUE)
|
|
{
|
|
SetLocalInt(OBJECT_SELF, "NW_GENERIC_WARNING_STATUS", nStatus);
|
|
}
|
|
|
|
// NPCs who have warning status set to TRUE will allow
|
|
// one 'free' attack by PCs from a non-hostile faction.
|
|
int GetNPCWarningStatus()
|
|
{
|
|
return GetLocalInt(OBJECT_SELF, "NW_GENERIC_WARNING_STATUS");
|
|
}
|
|
|
|
//::///////////////////////////////////////////////
|
|
//:: Set SummonHelpIfAttacked
|
|
//:: Copyright (c) 2001 Bioware Corp.
|
|
//:://////////////////////////////////////////////
|
|
/*
|
|
This function works in tandem with an encounter
|
|
to spawn in guards to fight for the attacked
|
|
NPC. MAKE SURE THE ENCOUNTER TAG IS SET TO:
|
|
|
|
"ENC_" + NPC TAG
|
|
*/
|
|
//:://////////////////////////////////////////////
|
|
//:: Created By: Preston Watamaniuk
|
|
//:: Created On: Oct 29, 2001
|
|
//:://////////////////////////////////////////////
|
|
|
|
//Presently Does not work with the current implementation of encounter trigger
|
|
void SetSummonHelpIfAttacked()
|
|
{
|
|
string sEncounter = "ENC_" + GetTag(OBJECT_SELF);
|
|
object oTrigger = GetObjectByTag(sEncounter);
|
|
|
|
if(GetIsObjectValid(oTrigger))
|
|
{
|
|
SetEncounterActive(TRUE, oTrigger);
|
|
}
|
|
}
|
|
|
|
//************************************************************************************************************************************
|
|
//************************************************************************************************************************************
|
|
//
|
|
// ESCAPE FUNCTIONS
|
|
//
|
|
//************************************************************************************************************************************
|
|
//************************************************************************************************************************************
|
|
|
|
//::///////////////////////////////////////////////
|
|
//:: Set, Get Activate,Flee to Exit
|
|
//:: Copyright (c) 2001 Bioware Corp.
|
|
//:://////////////////////////////////////////////
|
|
/*
|
|
The target object flees to the specified
|
|
way point and then destroys itself, to be
|
|
respawned at a later point. For unkillable
|
|
sign post characters who are not meant to fight
|
|
back.
|
|
*/
|
|
//:://////////////////////////////////////////////
|
|
//:: Created By: Preston Watamaniuk
|
|
//:: Created On: Oct 29, 2001
|
|
//:://////////////////////////////////////////////
|
|
|
|
//This function is used only because ActionDoCommand can only accept void functions
|
|
void CreateSignPostNPC(string sTag, location lLocal)
|
|
{
|
|
CreateObject(OBJECT_TYPE_CREATURE, sTag, lLocal);
|
|
}
|
|
|
|
void ActivateFleeToExit()
|
|
{
|
|
//minor optimizations - only grab these variables when actually needed
|
|
//can make for larger code, but it's faster
|
|
//object oExitWay = GetWaypointByTag("EXIT_" + GetTag(OBJECT_SELF));
|
|
//location lLocal = GetLocalLocation(OBJECT_SELF, "NW_GENERIC_START_POINT");
|
|
//string sTag = GetTag(OBJECT_SELF);
|
|
|
|
//I suppose having this as a variable made it easier to change at one point....
|
|
//but it never changes, and is only used twice, so we don't need it
|
|
//float fDelay = 6.0;
|
|
|
|
int nPlot = GetLocalInt(OBJECT_SELF, "NW_GENERIC_MASTER");
|
|
|
|
if(nPlot & NW_FLAG_TELEPORT_RETURN || nPlot & NW_FLAG_TELEPORT_LEAVE)
|
|
{
|
|
effect eVis = EffectVisualEffect(VFX_IMP_UNSUMMON);
|
|
ApplyEffectToObject(DURATION_TYPE_INSTANT, eVis, OBJECT_SELF);
|
|
if(nPlot & NW_FLAG_TELEPORT_RETURN)
|
|
{
|
|
location lLocal = GetLocalLocation(OBJECT_SELF, "NW_GENERIC_START_POINT");
|
|
string sTag = GetTag(OBJECT_SELF);
|
|
DelayCommand(6.0, ActionDoCommand(CreateSignPostNPC(sTag, lLocal)));
|
|
}
|
|
ActionDoCommand(DestroyObject(OBJECT_SELF, 0.75));
|
|
}
|
|
else
|
|
{
|
|
if(nPlot & NW_FLAG_ESCAPE_LEAVE)
|
|
{
|
|
object oExitWay = GetWaypointByTag("EXIT_" + GetTag(OBJECT_SELF));
|
|
ActionMoveToObject(oExitWay, TRUE);
|
|
ActionDoCommand(DestroyObject(OBJECT_SELF, 1.0));
|
|
}
|
|
else if(nPlot & NW_FLAG_ESCAPE_RETURN)
|
|
{
|
|
string sTag = GetTag(OBJECT_SELF);
|
|
object oExitWay = GetWaypointByTag("EXIT_" + sTag);
|
|
ActionMoveToObject(oExitWay, TRUE);
|
|
location lLocal = GetLocalLocation(OBJECT_SELF, "NW_GENERIC_START_POINT");
|
|
DelayCommand(6.0, ActionDoCommand(CreateSignPostNPC(sTag, lLocal)));
|
|
ActionDoCommand(DestroyObject(OBJECT_SELF, 1.0));
|
|
}
|
|
}
|
|
}
|
|
|
|
int GetFleeToExit()
|
|
{
|
|
int nPlot = GetLocalInt(OBJECT_SELF, "NW_GENERIC_MASTER");
|
|
if(nPlot & NW_FLAG_ESCAPE_RETURN)
|
|
{
|
|
return TRUE;
|
|
}
|
|
else if(nPlot & NW_FLAG_ESCAPE_LEAVE)
|
|
{
|
|
return TRUE;
|
|
}
|
|
else if(nPlot & NW_FLAG_TELEPORT_RETURN)
|
|
{
|
|
return TRUE;
|
|
}
|
|
else if(nPlot & NW_FLAG_TELEPORT_LEAVE)
|
|
{
|
|
return TRUE;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
|
|
//**********************************
|
|
//**********************************
|
|
//**********************************
|
|
// PRIVATE FUNCTIONS
|
|
//**********************************
|
|
//**********************************
|
|
//**********************************
|
|
|
|
//This is experimental and has not been looked at closely.
|
|
void ExitAOESpellArea(object oAOEObject)
|
|
{
|
|
ClearActions(CLEAR_NW_I0_GENERIC_ExitAOESpellArea);
|
|
ActionMoveAwayFromObject(oAOEObject, TRUE, 5.0);
|
|
AssignCommand(OBJECT_SELF, DetermineCombatRound());
|
|
}
|
|
|
|
|
|
//::///////////////////////////////////////////////
|
|
//:: Get Character Levels
|
|
//:: Copyright (c) 2001 Bioware Corp.
|
|
//:://////////////////////////////////////////////
|
|
/*
|
|
Returns the combined class levels of the
|
|
target.
|
|
*/
|
|
//:://////////////////////////////////////////////
|
|
//:: Created By: Preston Watamaniuk
|
|
//:: Created On: Oct 22, 2001
|
|
//:://////////////////////////////////////////////
|
|
|
|
int GetCharacterLevel(object oTarget)
|
|
{
|
|
return GetHitDice(oTarget);
|
|
}
|
|
|
|
|
|
|
|
|
|
//::///////////////////////////////////////////////
|
|
//:: Remove Ambient Sleep
|
|
//:: Copyright (c) 2001 Bioware Corp.
|
|
//:://////////////////////////////////////////////
|
|
/*
|
|
Checks if the NPC has sleep on them because
|
|
of ambient animations. Sleeping creatures
|
|
must make a DC 15 listen check.
|
|
*/
|
|
//:://////////////////////////////////////////////
|
|
//:: Created By: Preston Watamaniuk
|
|
//:: Created On: Feb 27, 2002
|
|
//:://////////////////////////////////////////////
|
|
|
|
void RemoveAmbientSleep()
|
|
{
|
|
if(GetHasEffect(EFFECT_TYPE_SLEEP))
|
|
{
|
|
effect eSleep = GetFirstEffect(OBJECT_SELF);
|
|
while(GetIsEffectValid(eSleep))
|
|
{
|
|
if(GetEffectCreator(eSleep) == OBJECT_SELF)
|
|
{
|
|
int nRoll = d20();
|
|
nRoll += GetSkillRank(SKILL_LISTEN);
|
|
nRoll += GetAbilityModifier(ABILITY_WISDOM);
|
|
if(nRoll > 15)
|
|
{
|
|
RemoveEffect(OBJECT_SELF, eSleep);
|
|
}
|
|
}
|
|
eSleep = GetNextEffect(OBJECT_SELF);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
//::///////////////////////////////////////////////
|
|
//:: Get Locked Object
|
|
//:: Copyright (c) 2001 Bioware Corp.
|
|
//:://////////////////////////////////////////////
|
|
/*
|
|
Finds the closest locked object to the object
|
|
passed in up to a maximum of 10 objects.
|
|
*/
|
|
//:://////////////////////////////////////////////
|
|
//:: Created By: Preston Watamaniuk
|
|
//:: Created On: March 15, 2002
|
|
//:://////////////////////////////////////////////
|
|
|
|
object GetLockedObject(object oMaster)
|
|
{
|
|
int nCnt = 1;
|
|
int bValid = TRUE;
|
|
object oLastObject = GetNearestObjectToLocation(OBJECT_TYPE_DOOR | OBJECT_TYPE_PLACEABLE, GetLocation(oMaster), nCnt);
|
|
while (GetIsObjectValid(oLastObject) && bValid == TRUE)
|
|
{
|
|
//COMMENT THIS BACK IN WHEN DOOR ACTION WORKS ON PLACABLE.
|
|
|
|
//object oItem = GetFirstItemInInventory(oLastObject);
|
|
if(GetLocked(oLastObject))
|
|
{
|
|
return oLastObject;
|
|
}
|
|
nCnt++;
|
|
if(nCnt == 10)
|
|
{
|
|
bValid = FALSE;
|
|
}
|
|
oLastObject = GetNearestObjectToLocation(OBJECT_TYPE_DOOR | OBJECT_TYPE_PLACEABLE, GetLocation(oMaster), nCnt);
|
|
}
|
|
return OBJECT_INVALID;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//::///////////////////////////////////////////////
|
|
//:: Check if an item is locked
|
|
//:: Copyright (c) 2001 Bioware Corp.
|
|
//:://////////////////////////////////////////////
|
|
/*
|
|
Checks that an item was unlocked.
|
|
*/
|
|
//:://////////////////////////////////////////////
|
|
//:: Created By: Preston Watamaniuk
|
|
//:: Created On: Nov 19, 2001
|
|
//:://////////////////////////////////////////////
|
|
|
|
void CheckIsUnlocked(object oLastObject)
|
|
{
|
|
if(GetLocked(oLastObject))
|
|
{
|
|
ActionDoCommand(VoiceCuss());
|
|
}
|
|
else
|
|
{
|
|
ActionDoCommand(VoiceCanDo());
|
|
}
|
|
}
|
|
|
|
|
|
//::///////////////////////////////////////////////
|
|
//:: Play Mobile Ambient Animations
|
|
//:: This function is now just a wrapper around
|
|
//:: code from x0_i0_anims.
|
|
//:://////////////////////////////////////////////
|
|
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();
|
|
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(!GetIsFriend(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);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else if(!IsInConversation(OBJECT_SELF))
|
|
{
|
|
bAttack = TRUE;
|
|
DetermineCombatRound(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);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else if(!IsInConversation(OBJECT_SELF))
|
|
{
|
|
ClearActions(CLEAR_NW_I0_GENERIC_DetermineSpecialBehavior2);
|
|
ActionRandomWalk();
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
//::///////////////////////////////////////////////
|
|
//:: Bash Doors
|
|
//:: Copyright (c) 2002 Bioware Corp.
|
|
//:://////////////////////////////////////////////
|
|
/*
|
|
Used in DetermineCombatRound to keep a
|
|
henchmen bashing doors.
|
|
*/
|
|
//:://////////////////////////////////////////////
|
|
//:: Created By: Preston Watamaniuk
|
|
//:: Created On: April 4, 2002
|
|
//:://////////////////////////////////////////////
|
|
|
|
int BashDoorCheck(object oIntruder = OBJECT_INVALID)
|
|
{
|
|
int bDoor = FALSE;
|
|
//This code is here to make sure that henchmen keep bashing doors and placables.
|
|
object oDoor = GetLocalObject(OBJECT_SELF, "NW_GENERIC_DOOR_TO_BASH");
|
|
|
|
// * MODIFICATION February 7 2003 BK
|
|
// * don't bash trapped doors.
|
|
if (GetIsTrapped(oDoor) ) return FALSE;
|
|
|
|
if(GetIsObjectValid(oDoor))
|
|
{
|
|
int nDoorMax = GetMaxHitPoints(oDoor);
|
|
int nDoorNow = GetCurrentHitPoints(oDoor);
|
|
int nCnt = GetLocalInt(OBJECT_SELF,"NW_GENERIC_DOOR_TO_BASH_HP");
|
|
if(!GetIsObjectValid(GetNearestCreature(CREATURE_TYPE_REPUTATION, REPUTATION_TYPE_ENEMY, OBJECT_SELF, 1, CREATURE_TYPE_PERCEPTION, PERCEPTION_SEEN))
|
|
|| (!GetIsObjectValid(oIntruder) && !GetIsObjectValid(GetMaster())))
|
|
{
|
|
if(GetLocked(oDoor))
|
|
{
|
|
if(nDoorMax == nDoorNow)
|
|
{
|
|
nCnt++;
|
|
SetLocalInt(OBJECT_SELF,"NW_GENERIC_DOOR_TO_BASH_HP", nCnt);
|
|
}
|
|
if(nCnt <= 0)
|
|
{
|
|
bDoor = TRUE;
|
|
if(GetHasFeat(FEAT_IMPROVED_POWER_ATTACK))
|
|
{
|
|
ActionUseFeat(FEAT_IMPROVED_POWER_ATTACK, oDoor);
|
|
}
|
|
else if(GetHasFeat(FEAT_POWER_ATTACK))
|
|
{
|
|
ActionUseFeat(FEAT_POWER_ATTACK, oDoor);
|
|
}
|
|
else
|
|
{
|
|
WrapperActionAttack(oDoor);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if(bDoor == FALSE)
|
|
{
|
|
VoiceCuss();
|
|
DeleteLocalObject(OBJECT_SELF, "NW_GENERIC_DOOR_TO_BASH");
|
|
DeleteLocalInt(OBJECT_SELF, "NW_GENERIC_DOOR_TO_BASH_HP");
|
|
}
|
|
}
|
|
return bDoor;
|
|
}
|
|
|
|
//::///////////////////////////////////////////////
|
|
//:: Determine Class to Use
|
|
//:: Copyright (c) 2002 Bioware Corp.
|
|
//:://////////////////////////////////////////////
|
|
/*
|
|
Determines which of a NPCs three classes to
|
|
use in DetermineCombatRound
|
|
*/
|
|
//:://////////////////////////////////////////////
|
|
//:: Created By: Preston Watamaniuk
|
|
//:: Created On: April 4, 2002
|
|
//:://////////////////////////////////////////////
|
|
|
|
int DetermineClassToUse()
|
|
{
|
|
int nClass;
|
|
int nTotal = GetHitDice(OBJECT_SELF);
|
|
|
|
//this is silly...
|
|
/*
|
|
float fTotal = IntToFloat(nTotal);
|
|
int nState1 = FloatToInt((IntToFloat(GetLevelByClass(GetClassByPosition(1))) / fTotal) * 100);
|
|
// MyPrintString(GetTag(OBJECT_SELF) + "Class: " + IntToString(GetClassByPosition(1)) + " %" + IntToString(nState1));
|
|
|
|
int nState2 = FloatToInt((IntToFloat(GetLevelByClass(GetClassByPosition(2))) / fTotal) * 100) + nState1;
|
|
// MyPrintString(GetTag(OBJECT_SELF) + "Class: " + IntToString(GetClassByPosition(2)) + " %" + IntToString(nState2));
|
|
|
|
int nState3 = FloatToInt((IntToFloat(GetLevelByClass(GetClassByPosition(3))) / fTotal) * 100) + nState2;
|
|
// MyPrintString(GetTag(OBJECT_SELF) + "Class: " + IntToString(GetClassByPosition(3)) + " %" + IntToString(nState3));
|
|
*/
|
|
int nClass1 = GetClassByPosition(1);
|
|
int nClass2 = GetClassByPosition(2);
|
|
|
|
int nState1 = GetLevelByClass(nClass1) * 100 / nTotal;
|
|
int nState2 = GetLevelByClass(nClass2) * 100 / nTotal;
|
|
// int nState3 = GetLevelByClass(GetClassByPosition(3)) * 100 / nTotal;
|
|
|
|
int nUseClass = d100();
|
|
// MyPrintString("D100 Roll " + IntToString(nUseClass));
|
|
|
|
if(nUseClass <= nState1)
|
|
{
|
|
nClass = nClass1;
|
|
}
|
|
else if(nUseClass > nState1 && nUseClass <= nState2)
|
|
{
|
|
nClass = nClass2;
|
|
}
|
|
else
|
|
{
|
|
nClass = GetClassByPosition(3);
|
|
}
|
|
// MyPrintString(GetName(OBJECT_SELF) + " Return Class = " + IntToString(nClass));
|
|
|
|
return nClass;
|
|
}
|
|
|
|
|
|
|
|
/* DO NOT CLOSE THIS TOP COMMENT!
|
|
This main() function is here only for compilation testing.
|
|
void main() {}
|
|
/* */
|