//::///////////////////////////////////////////////
//:: Generic Scripting Include v1.0
//:: NW_I0_GENERIC
//:: Copyright © 2001 Bioware Corp.
//::
//:: Modified by Pausanias to improve the Battle AI
//:: Searching for "Pausanias" should highlight the most important
//:: changes.
//::
//:: Important Definitions for Pausanias's Monster AI:
//:: Monster = Any creature who considers the first PC an enemy
//:: Enemy = Any creature who is hostile towards the creature
//:: running the script. The "enemy" of the PC is
//:: a monster and the "enemy" of a monster is the PC.
//:://////////////////////////////////////////////
//void main() {}
/*
********************************************
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
//:://////////////////////////////////////////////
//:: Modified 69MEH69 OCT2002 Removed BattleCry() from script
//:: NOV2002 Added command relay from radial menu
// Nifty's bardsong fix.
#include "nifty_i0_bard"
#include "69_battlecries"
// Array management routines.
// Generic Array Manipulation Routines
void SetIntArray(object oSource, string sName, int iElem, int iState)
{
string sFull = sName+IntToString(iElem);
SetLocalInt(oSource,sFull,iState);
}
void SetObjectArray(object oSource, string sName, int iElem, object oElem)
{
string sFull = sName+IntToString(iElem);
SetLocalObject(oSource,sFull,oElem);
}
object GetObjectArray(object oSource, string sName, int iElem)
{
string sFull = sName+IntToString(iElem);
return GetLocalObject(oSource,sFull);
}
int GetIntArray(object oSource, string sName, int iElem)
{
string sFull = sName+IntToString(iElem);
return GetLocalInt(oSource,sFull);
}
//GENERIC STRUCTURES
struct sEnemies
{
int FIGHTERS;
int FIGHTER_LEVELS;
int CLERICS;
int CLERIC_LEVELS;
int MAGES;
int MAGE_LEVELS;
int MONSTERS;
int MONTERS_LEVELS;
int TOTAL;
int TOTAL_LEVELS;
};
struct sSpellSelect
{
int RANGED;
int MELEE;
object GROUP_TARGET;
object MOB_TARGET;
object MELEE_TOUGHEST;
object TOUGHEST_TARGET;
int ENEMY_HD;
int ALLIED_HD;
};
// Threshold challange rating for buff spells
float PAUSANIAS_CHALLENGE_THRESHOLD = -2.0;
float PAUSANIAS_FAMILIAR_THRESHOLD = -2.0;
float PAUSANIAS_DISTANCE_THRESHOLD = 3.6;
//Flee and move constants
int NW_GENERIC_FLEE_EXIT_FLEE = 0;
int NW_GENERIC_FLEE_EXIT_RETURN = 1;
int NW_GENERIC_FLEE_TELEPORT_FLEE = 2;
int NW_GENERIC_FLEE_TELEPORT_RETURN = 3;
//Shout constants
int NW_GENERIC_SHOUT_I_WAS_ATTACKED = 1; // NOT USED
int NW_GENERIC_SHOUT_I_AM_DEAD = 12; //IN OnDeath Script
int NW_GENERIC_SHOUT_BACK_UP_NEEDED = 13; //IN TalentMeleeAttacked
int NW_GENERIC_SHOUT_BLOCKER = 2;
//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;
//Behavior Constants
int NW_FLAG_BEHAVIOR_SPECIAL = 0x00000001;
int NW_FLAG_BEHAVIOR_CARNIVORE = 0x00000002; //Will always attack regardless of faction
int NW_FLAG_BEHAVIOR_OMNIVORE = 0x00000004; //Will only attack if approached
int NW_FLAG_BEHAVIOR_HERBIVORE = 0x00000008; //Will never attack. Will alway flee.
//Talent Type Constants
int NW_TALENT_PROTECT = 1;
int NW_TALENT_ENHANCE = 2;
//PRIVATE FUNCTION DECLARATIONS
// Pausanias's Combined Challenge Rating of the encounter.
float GetEnemyChallenge(object oRelativeTo=OBJECT_SELF);
// Pausanias's Talent checking filter
int PausaniasUseTalent(talent tUse, object oTarget, int iDoQueue = FALSE);
// Pausanias's Melle Weapon Equipping routine (includes shields & dual-wield)
void PausaniasEquipMelee(object oTarget = OBJECT_INVALID);
// Pausanias: Is Object in the line of sight of the seer
int GetIsInLineOfSight(object oTarget,object oSeer=OBJECT_SELF);
// Pausanias: Is there a door in the line of sight of seer
int GetIsDoorInLineOfSight(object oTarget);
//Checks the target for a specific EFFECT_TYPE constant value
int GetHasEffect(int nEffectType, object oTarget = OBJECT_SELF);
//Adds all three of the class levels together. Used before GetHitDice became available
int GetCharacterLevel(object oTarget);
//Returns the number of persons who are considered friendly to the the target.
int CheckFriendlyFireOnTarget(object oTarget, float fDistance = 5.0);
//Returns the number of enemies on a target.
int CheckEnemyGroupingOnTarget(object oTarget, float fDistance = 5.0);
//Find a single target who is an enemy with 30m of self
object FindSingleRangedTarget();
//Calculate the number of people currently attacking self.
int GetNumberOfMeleeAttackers();
//Calculate the number of people attacking self from beyond 5m
int GetNumberOfRangedAttackers();
//Determine the percentage of HP object-self has left
int GetPercentageHPLoss(object oWounded);
//Determine the number of targets within 20m that are of the specified racial-type
int GetRacialTypeCount(int nRacial_Type);
//Returns the nearest object that can be seen, then checks for the nearest heard target.
object GetNearestSeenOrHeardEnemy();
//Sets a local variable for the last spell used
void SetLastGenericSpellCast(int nSpell);
//Returns a SPELL_ constant for the last spell used
int GetLastGenericSpellCast();
//Compares the current spell with the last one cast
int CompareLastSpellCast(int nSpell);
//If using ambient sleep this will remove the effect
void RemoveAmbientSleep();
//Does a check to determine if the NPC has an attempted spell or attack target
int GetIsFighting(object oFighting);
//Searches for the nearest locked object to the master
object GetLockedObject(object oMaster);
//Equip the weapon appropriate to enemy and position
void EquipAppropriateWeapons(object oTarget);
//Returns the henchmen to a commandable state of grace
void ResetHenchmenState();
//Returns true if self is a henchmen
int AssociateCheck(object oCheck);
//Returns true if the object has any posts or waypoints to walk
int GetIsPostOrWalking(object oWalker = OBJECT_SELF);
//Prints a log string with the ID of the passed in talent.
void DubugPrintTalentID(talent tTalent);
//Inserts a debug print string into the log.
void MyPrintString(string sString);
//MR: <new code>
object GetRealMaster(object henchman = OBJECT_SELF);
//MR: </new code>
//DETERMINE COMBAT ROUND SUB FUNCTIONS
int BashDoorCheck(object oIntruder = OBJECT_INVALID);
int DetermineClassToUse();
struct sEnemies DetermineEnemies();
string GetMostDangerousClass(struct sEnemies sCount);
int GetMatchCompatibility(talent tUse, string sClass, int nType);
int MatchCombatProtections(talent tUse);
int MatchSpellProtections(talent tUse);
int MatchElementalProtections(talent tUse);
talent StartProtectionLoop();
int GetAttackCompatibility(talent tUse, int nClass);
int MatchReflexAttacks(talent tUse);
int MatchFortAttacks(talent tUse);
object GetRangedAttackGroup(int bAllowFriendlyFire = FALSE);
object GetToughestMeleeAttacker();
object GetToughestAttacker();
struct sSpellSelect AnalyzeCombatSituation();
int GetAlliedHD();
int GetEnemyHD();
talent StartAttackLoop();
int VerifyDisarm(talent tUse, object oTarget);
int VerifyCombatMeleeTalent(talent tUse, object oTarget);
int UniversalSpellMatch(talent tUse);
//CURRENT TALENT FUNCTIONS
int TalentUseProtectionOnSelf();
int TalentUseProtectionOthers(object oTarget = OBJECT_INVALID,int iClearActions = TRUE);
int TalentEnhanceOthers(object oTarget = OBJECT_INVALID,
int iAvoidInvisibility = FALSE, int iClearActions = TRUE);
int TalentUseEnhancementOnSelf();
int TalentMeleeAttacked(object oIntruder = OBJECT_INVALID);
int TalentRangedAttackers(object oIntruder = OBJECT_INVALID);
int TalentRangedEnemies(object oIntruder = OBJECT_INVALID);
int TalentSummonAllies();
int TalentHealingSelf(); //Use spells and potions
int TalentHeal(int nForce = FALSE); //User spells only on others and self
int TalentMeleeAttack(object oIntruder = OBJECT_INVALID);
int TalentSneakAttack();
int TalentFlee(object oIntruder = OBJECT_INVALID);
int TalentUseTurning();
int TalentPersistentAbilities();
int TalentAdvancedBuff(float fDistance);
int TalentBuffSelf(); //Used for Potions of Enhancement and Protection
int TalentSeeInvisible();
int TalentCureCondition();
int TalentDragonCombat(object oIntruder = OBJECT_INVALID);
int TalentBardSong();
int TalentAdvancedProtectSelf();
int TalentSpellAttack(object oIntruder);
//CORE AI FUNCTIONS
void DetermineCombatRound(object oIntruder = OBJECT_INVALID, int nAI_Difficulty = 10);
void SetListeningPatterns();
void RespondToShout(object oShouter, int nShoutIndex, object oIntruder = OBJECT_INVALID);
void RunCircuit(int nTens, int nNum, int nRun = FALSE, float fPause = 1.0);
void WalkWayPoints(int nRun = FALSE, float fPause = 1.0);
void RunNextCircuit(int nRun = FALSE, float fPause = 1.0);
int CheckWayPoints(object oWalker = OBJECT_SELF);
//PLOT FUNCTIONS
void SetNPCWarningStatus(int nStatus = TRUE);
int GetNPCWarningStatus();
void SetSummonHelpIfAttacked();
void CreateSignPostNPC(string sTag, location lLocal);
void ActivateFleeToExit();
int GetFleeToExit();
//MASTER LOCAL FUNCTIONS
void SetSpawnInCondition(int nCondition, int bValid = TRUE);
int GetSpawnInCondition(int nCondition);
void SetSpawnInLocals(int nCondition);
//ASSOCIATE MASTER VARIABLE FUNCTIONS
void SetAssociateState(int nCondition, int bValid = TRUE);
int GetAssociateState(int nCondition);
//ASSOCIATE FUNCTIONS
int GetAssociateCRMax();
int GetAssociateHealMaster();
float GetFollowDistance();
void CheckIsUnlocked(object oLastObject);
void SetAssociateStartLocation();
location GetAssociateStartLocation();
//AMBIENT ANIMATION COMMANDS
void PlayMobileAmbientAnimations();
void PlayImmobileAmbientAnimations();
//BEHAVIOR LOCAL FUNCTIONS
void SetBehaviorState(int nCondition, int bValid = TRUE);
int GetBehaviorState(int nCondition);
void DetermineSpecialBehavior(object oIntruder = OBJECT_INVALID);
//::///////////////////////////////////////////////
//:: Master Local Get and Set
//:: FileName
//:: Copyright © 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));
}
}
//::///////////////////////////////////////////////
//:: DetermineCombatRound
//:: Copyright © 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)
{
int iAmHenchman,iAmFamiliar,iAmCompanion;
float fChallenge;
MyPrintString("********************** DETERMINE COMBAT ROUND START ****************************************");
MyPrintString("********************** " + GetTag(OBJECT_SELF) + " ****************************************");
if(GetAssociateState(NW_ASC_IS_BUSY))
{
return;
}
if(BashDoorCheck(oIntruder)) {return;}
int nClass = DetermineClassToUse();
// Herbivores should escape
if(GetBehaviorState(NW_FLAG_BEHAVIOR_HERBIVORE))
if (TalentFlee(oIntruder)) return;
object oMaster = GetRealMaster();
int iHP = GetPercentageHPLoss(OBJECT_SELF);
int iHaveMaster = GetIsObjectValid(oMaster);
int iAmMonster = GetIsEnemy(GetFirstPC());
object oClosest = GetNearestCreature(CREATURE_TYPE_REPUTATION, REPUTATION_TYPE_ENEMY,
OBJECT_SELF, 1, CREATURE_TYPE_PERCEPTION, PERCEPTION_SEEN);
object oFriend = GetNearestCreature(CREATURE_TYPE_REPUTATION, REPUTATION_TYPE_FRIEND,
OBJECT_SELF, 1);
// Pausanias sanity check: do not attack target if you share the same master.
if (iHaveMaster) {
if (GetMaster(oIntruder) == oMaster) {
if (GetMaster(oClosest) == oMaster)
return;
else
oIntruder = oClosest;
} else if (GetMaster(oClosest) == GetRealMaster())
oClosest = oIntruder;
}
// Pausanias: sanity check for various effects
if (GetHasEffect(EFFECT_TYPE_PARALYZE) ||
GetHasEffect(EFFECT_TYPE_STUNNED) ||
GetHasEffect(EFFECT_TYPE_FRIGHTENED) ||
GetHasEffect(EFFECT_TYPE_SLEEP) ||
GetHasEffect(EFFECT_TYPE_DAZED))
return;
if ((GetHasEffect(EFFECT_TYPE_CONFUSED) && d2() == 1) ||
GetHasEffect(EFFECT_TYPE_CHARMED)){
oClosest = oFriend;
oIntruder = oFriend;
}
float fDistance = GetDistanceToObject(oClosest);
int iDifficulty = GetGameDifficulty();
// The following tweaks are implemented via Pausanias's dialogue mods.
// Get challenge below which no defensive spells are cast
float fThresholdChallenge = GetLocalFloat(OBJECT_SELF,"NewHenchChallenge");
if (fThresholdChallenge == 0.0) {
if (nClass == CLASS_TYPE_WIZARD || nClass == CLASS_TYPE_SORCERER)
fThresholdChallenge = -3.;
else
fThresholdChallenge = PAUSANIAS_CHALLENGE_THRESHOLD;
}
// Get challenge above which familiar will run away
float fFamiliarChallenge = GetLocalFloat(OBJECT_SELF,"NewFamiliarChallenge");
if (fFamiliarChallenge == 0.0)
fFamiliarChallenge = PAUSANIAS_FAMILIAR_THRESHOLD;
// Get distance closer than which henchman will swap to melee.
float fThresholdDistance = GetLocalFloat(OBJECT_SELF,"HenchRange");
if (fThresholdDistance == 0.0)
fThresholdDistance = PAUSANIAS_DISTANCE_THRESHOLD;
// Signal to try to get some distance between self and the enemy.
int iBackAway = FALSE;
int nBackAway = GetLocalInt(OBJECT_SELF,"BackAway");
if (fThresholdDistance > 50.0) {
iBackAway = TRUE;
fThresholdDistance = PAUSANIAS_DISTANCE_THRESHOLD;
}
// Monsters and non-associates do not care about the challenge rating for now.
if (iAmMonster || !iHaveMaster)
fThresholdChallenge = -100.;
// Should I try to cast spells if monsters are nearby? Yes by default
int iCastMelee = TRUE;
if (GetLocalInt(OBJECT_SELF,"DoNotCastMelee"))
iCastMelee = FALSE;
int iHealMelee = TRUE;
if (GetLocalInt(OBJECT_SELF,"DoNotHealMelee"))
iHealMelee = FALSE;
//SpeakString(FloatToString(fThresholdChallenge)+" "+
// FloatToString(fFamiliarChallenge)+" "+
// FloatToString(fThresholdDistance)+" "+FloatToString(fChallenge)+
// IntToString(GetHitDice(oMaster)));
// HERE BEGIN PAUSANIAS'S MAJOR MODIFICATIONS
// Finish casting your spells if you've started.
if (GetCurrentAction() == ACTION_CASTSPELL) {
int nSkipped = GetLocalInt(OBJECT_SELF,"nRoundsSkipped");
++nSkipped;
SetLocalInt(OBJECT_SELF,"nRoundsSkipped",nSkipped);
if (nSkipped < 3)
return;
} else
SetLocalInt(OBJECT_SELF,"nRoundsSkipped",0);
// The FIRST PRIORITY: self-preservation
if (iHaveMaster) {
iAmHenchman = (GetHenchman(oMaster) == OBJECT_SELF);
iAmFamiliar = (GetAssociate(ASSOCIATE_TYPE_FAMILIAR,oMaster) == OBJECT_SELF);
iAmCompanion = (GetAssociate(ASSOCIATE_TYPE_ANIMALCOMPANION,oMaster) == OBJECT_SELF);
// Condition for immediate self-healing
if (iHP < 50) {
if (iAmHenchman || iAmFamiliar)
if (iHP < 25)
SpeakString("Help!");
if (d100() > iHP-20) {
ClearAllActions();
if (TalentHealingSelf()) return;
if (iAmHenchman || iAmFamiliar)
SpeakString("Help! I can't heal myself!");
}
}
} else if (iHP < 50 && iAmMonster) {
// Pausanias: Monsters get tougher for the harder game settings.
if (iDifficulty == GAME_DIFFICULTY_DIFFICULT &&
!GetHasEffect(EFFECT_TYPE_HASTE)) {
ApplyEffectToObject(DURATION_TYPE_TEMPORARY,EffectHaste(),OBJECT_SELF,60.);
}
int iChance = d10();
// Self healing below 50% if enemy is far, otherwise between 20% and 50% only
if (iHP < 20 &&
GetDistanceToObject(oClosest) < 4.0) iChance = 0;
if ((iDifficulty == GAME_DIFFICULTY_DIFFICULT && iChance > 2) ||
(iDifficulty == GAME_DIFFICULTY_CORE_RULES && iChance >
) {
switch (GetRacialType(OBJECT_SELF)) {
case RACIAL_TYPE_UNDEAD:
case RACIAL_TYPE_CONSTRUCT:
case RACIAL_TYPE_BEAST:
case RACIAL_TYPE_ANIMAL:
case RACIAL_TYPE_DRAGON:
case RACIAL_TYPE_MAGICAL_BEAST:
case RACIAL_TYPE_SHAPECHANGER:
case RACIAL_TYPE_VERMIN:
case RACIAL_TYPE_INVALID:
case RACIAL_TYPE_ABERRATION: break;
default: {
int nHeal = GetLocalInt(OBJECT_SELF,"GaveHealing");
if (nHeal < FloatToInt(IntToFloat(GetHitDice(OBJECT_SELF))/2.)) {
++nHeal;
SetLocalInt(OBJECT_SELF,"GaveHealing",nHeal);
ExecuteScript("henchpotion",OBJECT_SELF);
}
} break;
}
}
if (TalentHealingSelf()) {
return;
}
}
// NEXT priority: Heal master if needed.
if (GetAssociateHealMaster()) {
if (fDistance > fThresholdDistance || iHealMelee) {
if (TalentHeal()) return;
if (d10() > 6 &&
(nClass == CLASS_TYPE_BARD || nClass == CLASS_TYPE_CLERIC ||
nClass == CLASS_TYPE_DRUID || nClass == CLASS_TYPE_PALADIN))
SpeakString("Sorry, I can't heal you!");
} else
if (d10() > 6)
SpeakString("Should I heal you?");
}
// NEXT priority: follow or return to master for up to three rounds.
int nFollow = GetLocalInt(OBJECT_SELF,"FollowCount");
++nFollow;
if(iHaveMaster && !GetLocalInt(OBJECT_SELF,"RunningAway") &&
(!iBackAway || GetLocalInt(OBJECT_SELF,"Scouting")))
{
SetLocalInt(OBJECT_SELF,"Scouting",FALSE);
if(GetDistanceToObject(GetRealMaster()) > 15.0)
{
if(GetCurrentAction(GetRealMaster()) != ACTION_FOLLOW)
{
ClearAllActions();
//ActionAttack(OBJECT_INVALID);
MyPrintString("*****EXIT on follow master.*******");
ActionForceFollowObject(GetRealMaster(), GetFollowDistance());
//ActionForceMoveToObject(GetRealMaster(), TRUE, GetFollowDistance(), 5.0);
return;
} else if (nFollow < 4) return;
}
}
SetLocalInt(OBJECT_SELF,"FollowCount",0);
// Pausanias: Combat has finally begun, so we are no longer scouting
SetLocalInt(OBJECT_SELF,"Scouting",FALSE);
// NEXT: Do not attack if the master told you not to
if (GetLocalInt(OBJECT_SELF,"DoNotAttack")) {
if (d10() > 7) {
if (iAmHenchman)
SpeakString("Should I attack?");
else if (iAmFamiliar)
SpeakString("Be careful! Let me know if I should attack!");
else if (iAmCompanion)
SpeakString("<"+GetName(OBJECT_SELF)+" is waiting for you to give the command to attack.>");
else
SpeakString("<The "+GetName(OBJECT_SELF)+" patiently awaits your command to attack.>");
}
return;
}
//This check is to see if the master is being attacked and in need of help
if(GetAssociateState(NW_ASC_HAVE_MASTER))
{
if(GetAssociateState(NW_ASC_MODE_DEFEND_MASTER))
{
oIntruder = GetLastHostileActor(GetRealMaster());
if(!GetIsObjectValid(oIntruder))
{
oIntruder = GetGoingToBeAttackedBy(GetRealMaster());
if(!GetIsObjectValid(oIntruder))
{
oIntruder = GetLastHostileActor();
if(!GetIsObjectValid(oIntruder))
{
if (GetAssociateState(NW_ASC_USE_RANGED_WEAPON)) {
if (fDistance > 20.)
return;
} else
if (fDistance > 7.0)
return;
oIntruder = oClosest;
}
else if(!GetIsEnemy(oIntruder))
{
oIntruder = OBJECT_INVALID;
}
}
}
}
}
SetLocalInt(OBJECT_SELF,"RunningAway",FALSE);
SetLocalInt(OBJECT_SELF,"StartedCombat",TRUE);
int nOffense = d100();
MyPrintString("GENERIC SCRIPT DEBUG STRING ********** " + "Offense Roll " + IntToString(nOffense));
/// Pausanias's Combined Challenge Rating (CCR)
fChallenge = GetEnemyChallenge();
MyPrintString("-----------------------------Enemy challenge: "+FloatToString(fChallenge));
if(GetIsObjectValid(oIntruder) ||
GetIsObjectValid(oClosest) ||
(GetIsObjectValid(oIntruder) && GetIsObjectValid(GetRealMaster())))
{
// Idle monsters should try to distribute themselves amongst targets
if (iAmMonster && !GetIsObjectValid(oIntruder) && GetIsObjectValid(oClosest) &&
iDifficulty >= GAME_DIFFICULTY_CORE_RULES) {
object oFirstTarget = GetLocalObject(OBJECT_SELF,"FirstTarget");
if(!GetIsObjectValid(GetLastHostileActor()) &&
!GetIsObjectValid(oFirstTarget) &&
GetDistanceToObject(oClosest) > 3.0){
object oNextTarget = oClosest;
int iNth = 0;
int iLoop = 1;
// Get all enemies within 40 meters and store them in an array.
while (GetIsObjectValid(oNextTarget)) {
++iLoop;
if (!GetLocalInt(oNextTarget,"RunningAway") &&
GetDistanceToObject(oNextTarget) < 40.) {
++iNth;
SetObjectArray(OBJECT_SELF,"TargetList",iNth,oNextTarget);
}
oNextTarget = GetNearestCreature(CREATURE_TYPE_REPUTATION,
REPUTATION_TYPE_ENEMY, OBJECT_SELF, iLoop);
}
// Pick a random one to attack.
if (iNth > 1) {
int iWhichAttack = Random(iNth)+1;
oNextTarget = GetObjectArray(OBJECT_SELF,"TargetList",iWhichAttack);
//SpeakString("Switched Targets To "+GetName(oNextTarget));
SetLocalObject(OBJECT_SELF,"FirstTarget",oNextTarget);
oIntruder = oNextTarget;
} else
oIntruder = oClosest;
} else
// Keep on attacking the selected target unless you are
// being attacked by something else.
if (GetIsObjectValid(oFirstTarget) &&
!GetLocalInt(oFirstTarget,"RunningAway") &&
(GetLastHostileActor() == OBJECT_INVALID ||
GetLastHostileActor() == oFirstTarget))
oIntruder = oFirstTarget;
}
if (iHaveMaster &&
oClosest != OBJECT_INVALID) {
// I am a henchman
if (iAmHenchman) {
// 5% chance per round of speaking the relative challenge of the encounter.
if (d100() > 95) {
if (fChallenge < -3.) HenchmanTalk(1);
else if (fChallenge < -1.) HenchmanTalk(2);
else if (fChallenge < 2.) HenchmanTalk(3);
else HenchmanTalk(4);
}
if (fDistance < 8.0 && fDistance > 3.0)
// Try to get some distance for up to 3 rounds if told to do so.
if (iBackAway && nBackAway < 4) {
ClearAllActions();
ActionMoveAwayFromObject(oClosest,TRUE,15.0);
++nBackAway;
SetLocalInt(OBJECT_SELF,"BackAway",nBackAway);
return;
}
// Equip the appropriate weapon for the distance of the enemy.
if (fDistance < fThresholdDistance) {
// If I'm told to use a ranged weapon, and I'm in close range,
// AND I haven't already switched to melee, do so now.
if (GetAssociateState(NW_ASC_USE_RANGED_WEAPON) &&
!GetLocalInt(OBJECT_SELF,"SwitchedToMelee")) {
// ClearAllActions();
SpeakString("I'm switching to my melee weapon for now!");
SetLocalInt(OBJECT_SELF,"SwitchedToMelee",TRUE);
EquipAppropriateWeapons(oClosest);
}
} else
// If I'm not at close range, AND I was told to use a ranged
// weapon, BUT I switched to melee, switch back to missile.
if (GetAssociateState(NW_ASC_USE_RANGED_WEAPON))
{
// ClearAllActions();
if (GetLocalInt(OBJECT_SELF,"SwitchedToMelee")) {
SpeakString("I'm switching back to my missile weapon!");
SetLocalInt(OBJECT_SELF,"SwitchedToMelee",FALSE);
}
}
SetLocalInt(OBJECT_SELF,"BackAway",0);
// Logic: if we are at close range, and the encounter is tough
// Then Buff the PC up once, and then fight. Otherwise, if
// we are at close range, fight; else 20% chance of using
// the missile weapon. Sorcerors or wizards try to cast spells
// rather than fight.
if ((nClass != CLASS_TYPE_WIZARD && nClass != CLASS_TYPE_SORCERER) ||
!iCastMelee) {
if (fDistance < fThresholdDistance && iCastMelee) {
int iCloseBuff = GetLocalInt(OBJECT_SELF,"CloseRangeEnhanced");
if (fChallenge >= 0.0 && iCloseBuff == FALSE) {
++iCloseBuff;
SetLocalInt(OBJECT_SELF,"CloseRangeEnhanced",TRUE);
if (TalentEnhanceOthers()) return;
if (TalentUseProtectionOthers()) return;
}
} else
SetLocalInt(OBJECT_SELF,"CloseRangeEnhanced",FALSE);
// 30% chance of attacking weak opponents outright even if
// they are not at close range.
if (fDistance < fThresholdDistance ||
(fChallenge < -3. && d100() < 30))
if (TalentMeleeAttack(oClosest)) return;
// There's a 20% chance of attacking anyway if the missile weapon is equipped.
if (GetAssociateState(NW_ASC_USE_RANGED_WEAPON))
if (d100() < 20)
if (TalentMeleeAttack(oClosest)) return;
}
}
// I am a familiar
if (iAmFamiliar)
// Run away from tough enemies
if (fChallenge >= fFamiliarChallenge ||
iHP < 40) {
switch (d10()) {
case 1: SpeakString("Time for me to get out of here!"); return;
case 2: SpeakString("Eeeeek!"); break;
case 3: SpeakString("Make way, make way!"); break;
case 4: SpeakString("I'll be back!"); break;
}
ClearAllActions();
ActionMoveAwayFromObject(oClosest,TRUE,40.);
ActionMoveAwayFromObject(oClosest,TRUE,40.);
ActionMoveAwayFromObject(oClosest,TRUE,40.);
ActionMoveAwayFromObject(oClosest,TRUE,40.);
SetLocalInt(OBJECT_SELF,"RunningAway",TRUE);
return;
}
}
// HERE END PAUSANIAS'S MAJOR MODIFICATIONS
int nAlignment = GetAlignmentGoodEvil(OBJECT_SELF);
//AM I AN ARCANE SPELLCASTER?
if(nClass == CLASS_TYPE_WIZARD || nClass == CLASS_TYPE_SORCERER)
{
if(GetRacialType(OBJECT_SELF) != RACIAL_TYPE_ABERRATION ||
GetRacialType(OBJECT_SELF) != RACIAL_TYPE_BEAST ||
GetRacialType(OBJECT_SELF) != RACIAL_TYPE_ELEMENTAL ||
GetRacialType(OBJECT_SELF) != RACIAL_TYPE_VERMIN ||
GetRacialType(OBJECT_SELF) != RACIAL_TYPE_MAGICAL_BEAST ||
GetRacialType(OBJECT_SELF) != RACIAL_TYPE_UNDEAD ||
GetRacialType(OBJECT_SELF) != RACIAL_TYPE_DRAGON ||
GetRacialType(OBJECT_SELF) != RACIAL_TYPE_ANIMAL)
{
//Use healing potions to not die
if(TalentHealingSelf()) {return;}
}
//Use a defensive talent fire then offensive if that fails
if(nOffense > 75)
{
if (fChallenge > fThresholdChallenge || d100() < 2) {
if(TalentAdvancedProtectSelf()){return;} //******************************************//
//Use protections on Self
if(TalentUseProtectionOnSelf()) {return;}
//Use protection on allies
if(TalentUseProtectionOthers()) {return;}
//Check if the character can enhance themselves
if(TalentUseEnhancementOnSelf()) {return;}
//Use Enhancements on the part
if(TalentEnhanceOthers()) {return;}
}
if (fChallenge > fThresholdChallenge) {
//Check for Personal Attackers
if(TalentMeleeAttacked(oIntruder)) {return;}
//Check for Ranged Attackers
if(TalentRangedAttackers(oIntruder)) {return;}
//Check for Ranged Enemies
if(TalentRangedEnemies(oIntruder)) {return;}
//Check for Allies
if(TalentSummonAllies()) {return;}
//Spell Attack
/*if(TalentSpellAttack(oIntruder)) {
BattleCry();
return;
}*/
//Attack if out of spells
if(TalentBuffSelf()) {return;}
}
if(TalentMeleeAttack(oIntruder)) {return;}
}
else //Use a offensive talent only
{
if (fChallenge > fThresholdChallenge || d100() < 2) {
if(GetIsObjectValid(GetRealMaster()))
{
if(TalentUseProtectionOthers()) {return;}
if(TalentEnhanceOthers()) {return;}
}
}
if (fChallenge > fThresholdChallenge) {
//Check for Personal Attackers
if(TalentMeleeAttacked(oIntruder)) {return;}
//Check for Ranged Attackers
if(TalentRangedAttackers(oIntruder)) {return;}
//Check for Ranged Enemies
if(TalentRangedEnemies(oIntruder)) {return;}
//Summon Allies
if(TalentSummonAllies()) {return;}
//Spell Attack
/*if(TalentSpellAttack(oIntruder)) {
BattleCry();
return;
}*/
//Attack if out of spells
if(TalentBuffSelf()) {
return;
}
}
if(TalentMeleeAttack(oIntruder)) {return;}
}
return;
}
// Separate bard scripts by Pausanias.
if(nClass == CLASS_TYPE_BARD)
{
if(TalentHeal()) {return;}
if(GetRacialType(OBJECT_SELF) != RACIAL_TYPE_ABERRATION ||
GetRacialType(OBJECT_SELF) != RACIAL_TYPE_BEAST ||
GetRacialType(OBJECT_SELF) != RACIAL_TYPE_ELEMENTAL ||
GetRacialType(OBJECT_SELF) != RACIAL_TYPE_VERMIN ||
GetRacialType(OBJECT_SELF) != RACIAL_TYPE_MAGICAL_BEAST ||
GetRacialType(OBJECT_SELF) != RACIAL_TYPE_UNDEAD ||
GetRacialType(OBJECT_SELF) != RACIAL_TYPE_DRAGON ||
GetRacialType(OBJECT_SELF) != RACIAL_TYPE_ANIMAL)
{
//Use healing potions to not die
if(TalentHealingSelf()) {return;}
}
//Use a defensive talent fire then offensive if that fails
if(nOffense > 75)
{
if (fChallenge > fThresholdChallenge || d100() < 2) {
if(TalentBardSongFixed()) {return;}
if(TalentAdvancedProtectSelf()){return;} //******************************************//
//Use protections on Self
if(TalentUseProtectionOnSelf()) {return;}
//Use protection on allies
if(TalentUseProtectionOthers()) {return;}
//Check if the character can enhance themselves
if(TalentUseEnhancementOnSelf()) {return;}
//Use Enhancements on the part
if(TalentEnhanceOthers()) {return;}
//Check for Personal Attackers
if(TalentMeleeAttacked(oIntruder)) {return;}
//Check for Ranged Attackers
if(TalentRangedAttackers(oIntruder)) {return;}
//Check for Ranged Enemies
if(TalentRangedEnemies(oIntruder)) {return;}
//Check for Allies
if(TalentSummonAllies()) {return;}
//Spell Attack
if(TalentSpellAttack(oIntruder)) {return;}
//Attack if out of spells
if(TalentBuffSelf()) {return;}
}
if(TalentMeleeAttack(oIntruder)) {return;}
}
else //Use a offensive talent only
{
if (fChallenge > fThresholdChallenge || d100() < 2) {
if(TalentBardSongFixed()) {return;}
if(GetIsObjectValid(GetRealMaster()))
{
if(TalentUseProtectionOthers()) {return;}
if(TalentEnhanceOthers()) {return;}
}
//Check for Personal Attackers
if(TalentMeleeAttacked(oIntruder)) {return;}
//Check for Ranged Attackers
if(TalentRangedAttackers(oIntruder)) {return;}
//Check for Ranged Enemies
if(TalentRangedEnemies(oIntruder)) {return;}
//Summon Allies
if(TalentSummonAllies()) {return;}
//Spell Attack
if(TalentSpellAttack(oIntruder)) {return;}
//Attack if out of spells
if(TalentBuffSelf()) {return;}
}
if(TalentMeleeAttack(oIntruder)) {return;}
}
return;
}
else if((nClass == CLASS_TYPE_CLERIC || nClass == CLASS_TYPE_DRUID) && GetRacialType(OBJECT_SELF) != RACIAL_TYPE_UNDEAD)
{
//Cast spells specific to the main enemy I am facing.
if (fChallenge > fThresholdChallenge || d100() < 2)
if(TalentAdvancedProtectSelf()) {return;} //******************************************//
//Remove negative effects from allies
if(TalentCureCondition()) {return;}
//Turning check. Pausanias: Do not turn easy undead
if (fChallenge > -3.0 || iAmMonster || !iHaveMaster)
if(TalentUseTurning()) {return;}
//Check if allies or self are injured
if(TalentHeal()) {return;}
//Use healing potions to not die
if(TalentHealingSelf()) {return;}
if(nOffense > 75)
{
if(GetNumberOfMeleeAttackers() > 1)
{
if(TalentMeleeAttacked(oIntruder)) {return;}
if(TalentMeleeAttack(oIntruder)) {return;}
}
else if(GetNumberOfMeleeAttackers() == 1)
{
if(TalentMeleeAttack(oIntruder)) {return;}
}
else
{
if (fChallenge > fThresholdChallenge || d100() < 2) {
//Check if the character can enhance themselves
if(TalentUseEnhancementOnSelf()) {return;}
// Check for enhancements on party
if(TalentEnhanceOthers()) {return;}
//Cast general protection on self
if(TalentUseProtectionOnSelf()) {return;}
//Check for Allies
if(TalentUseProtectionOthers()) {return;}
//Check for Allies
if(TalentSummonAllies()) {return;}
//Check for Personal Attackers
if(Random(101) > 75)
{
if(TalentMeleeAttacked(oIntruder)) {return;}
}
//Check for Ranged Attackers
if(TalentRangedAttackers(oIntruder)) {return;}
//Check for Ranged Enemies
if(TalentRangedEnemies(oIntruder)) {return;}
//Attack if out of spells
if(TalentBuffSelf()) {return;}
}
if(TalentMeleeAttack(oIntruder)) {return;}
}
}
else
{
//Cast Summon Spells
if(TalentSummonAllies()) {return;}
//Check for Personal Attackers
if (fChallenge > fThresholdChallenge || d100() < 2) {
if(TalentMeleeAttacked(oIntruder)) {return;}
//Check for Ranged Attackers
if(TalentRangedAttackers(oIntruder)) {return;}
//Check for Ranged Enemies
if(TalentRangedEnemies(oIntruder)) {return;}
//Spell Attack
if(TalentSpellAttack(oIntruder)) {return;}
//Attack if out of spells
if(TalentBuffSelf()) {return;}
}
if(TalentMeleeAttack(oIntruder)) {return;}
}
return;
}
else if((nClass == CLASS_TYPE_CLERIC || nClass == CLASS_TYPE_DRUID) && GetRacialType(OBJECT_SELF) == RACIAL_TYPE_UNDEAD)
{
//Turning check
if(TalentUseTurning()) {return;}
if(nOffense > 75)
{
if(GetNumberOfMeleeAttackers() > 1)
{
if(TalentMeleeAttacked(oIntruder)) {return;}
if(TalentMeleeAttack(oIntruder)) {return;}
}
else if(GetNumberOfMeleeAttackers() == 1)
{
if(TalentMeleeAttack(oIntruder)) {return;}
}
else
{
if (fChallenge > fThresholdChallenge || d100() < 2) {
//Check if the character can enhance themselves
if(TalentUseEnhancementOnSelf()) {return;}
// Check for enhancements on party
if(TalentEnhanceOthers()) {return;}
//Cast general protection on self
if(TalentUseProtectionOnSelf()) {return;}
//Check for Allies
if(TalentUseProtectionOthers()) {return;}
//Check for Allies
if(TalentSummonAllies()) {return;}
//Check for Personal Attackers
if(Random(101) > 75)
{
if(TalentMeleeAttacked(oIntruder)) {return;}
}
//Check for Ranged Attackers
if(TalentRangedAttackers(oIntruder)) {return;}
//Check for Ranged Enemies
if(TalentRangedEnemies(oIntruder)) {return;}
//Attack if out of spells
if(TalentBuffSelf()) {return;}
}
if(TalentMeleeAttack(oIntruder)) {return;}
}
}
else
{
//Cast Summon Spells
if(TalentSummonAllies()) {return;}
//Check for Personal Attackers
if (fChallenge > fThresholdChallenge || d100() < 2) {
if(TalentMeleeAttacked(oIntruder)) {return;}
//Check for Ranged Attackers
if(TalentRangedAttackers(oIntruder)) {return;}
//Spell Attack
if(TalentSpellAttack(oIntruder)) {return;}
//Check for Ranged Enemies
if(TalentRangedEnemies(oIntruder)) {return;}
//Attack if out of spells
if(TalentBuffSelf()) {return;}
}
if(TalentMeleeAttack(oIntruder)) {return;}
}
return;
}
else if(nClass == CLASS_TYPE_FIGHTER ||
nClass == CLASS_TYPE_ROGUE ||
nClass == CLASS_TYPE_PALADIN ||
nClass == CLASS_TYPE_RANGER ||
nClass == CLASS_TYPE_MONK ||
nClass == CLASS_TYPE_BARBARIAN)
{
if(GetRacialType(OBJECT_SELF) != RACIAL_TYPE_ABERRATION ||
GetRacialType(OBJECT_SELF) != RACIAL_TYPE_BEAST ||
GetRacialType(OBJECT_SELF) != RACIAL_TYPE_ELEMENTAL ||
GetRacialType(OBJECT_SELF) != RACIAL_TYPE_VERMIN ||
GetRacialType(OBJECT_SELF) != RACIAL_TYPE_MAGICAL_BEAST ||
GetRacialType(OBJECT_SELF) != RACIAL_TYPE_UNDEAD ||
GetRacialType(OBJECT_SELF) != RACIAL_TYPE_DRAGON ||
GetRacialType(OBJECT_SELF) != RACIAL_TYPE_ANIMAL ||
GetRacialType(OBJECT_SELF) != RACIAL_TYPE_CONSTRUCT)
{
//Use healing potions to not die
if(TalentHealingSelf()) {return;}
//Use potions of enhancement and protection
if (fChallenge > fThresholdChallenge || d100() < 2)
if(TalentBuffSelf()) {return;}
}
//Check if the character can enhance themselves
if(TalentUseEnhancementOnSelf()) {return;}
//Check for Paladins who can turn undead
if(TalentUseTurning()) {return;}
//Sneak Attack Flanking attack
if(TalentSneakAttack()) {return;}
//Use melee skills and feats
if(TalentMeleeAttack(oIntruder)) {return;}
return;
}
else if(nClass == CLASS_TYPE_COMMONER)
{
if(TalentFlee(oIntruder)) {return;}
return;
}
else if(nClass == CLASS_TYPE_UNDEAD)
{
//SpeakString("Determining Combat Round Undead");
if(TalentPersistentAbilities()) {return;}
if(nOffense > 75)
{
if(TalentAdvancedProtectSelf()){return;}
//Check if the character can enhance themselves
if(TalentUseEnhancementOnSelf()) {return;}
// Check for enhancements on party
if(TalentEnhanceOthers()) {return;}
//Use protections on Self
if(TalentUseProtectionOnSelf()) {;return;};
//Check for Allies
if(TalentUseProtectionOthers()) {return;}
//Check for Allies
if(TalentSummonAllies()) {return;}
//Check for Personal Attackers
if(TalentMeleeAttacked(oIntruder)) {return;}
//Check for Ranged Attackers
if(TalentRangedAttackers(oIntruder)) {return;}
//Check for Ranged Enemies
if(TalentRangedEnemies(oIntruder)) {return;}
//Attack if out of spells
if(TalentMeleeAttack(oIntruder)) {return;}
}
else
{
if(TalentSummonAllies()) {return;}
//Check for Personal Attackers
if(TalentMeleeAttacked(oIntruder)) {return;}
//Check for Ranged Attackers
if(TalentRangedAttackers(oIntruder)) {return;}
//Check for Ranged Enemies
if(TalentRangedEnemies(oIntruder)) {return;}
//Spell Attack
if(TalentSpellAttack(oIntruder)) {return;}
//Attack if out of spells
if(TalentMeleeAttack(oIntruder)) {return;}
}
return;
}
else if(nClass == CLASS_TYPE_DRAGON)
{
//Use healing
if(TalentHeal()) {return;}
if(TalentCureCondition()) {return;}
if(d100() < 15)
{
if(TalentRangedEnemies(oIntruder)) {return;}
if(TalentMeleeAttacked(oIntruder)) {return;}
}
if(TalentPersistentAbilities()) {return;}
if(TalentAdvancedProtectSelf()){return;}
if(TalentUseProtectionOnSelf()) {return;}
if(TalentDragonCombat(oIntruder)) {return;}
}
else if (nClass == CLASS_TYPE_OUTSIDER)
{
if(TalentPersistentAbilities()) {return;}
if(TalentSummonAllies()) {return;}
if(d100() > 50)
{
if(TalentMeleeAttack(oIntruder)) {return;}
}
if(GetAlignmentGoodEvil(OBJECT_SELF) == ALIGNMENT_GOOD)
{
if(TalentHeal()) {return;}
}
if(TalentHealingSelf()) {return;}
if(TalentAdvancedProtectSelf()){return;}
if(TalentUseProtectionOnSelf()) {return;}
if(TalentUseEnhancementOnSelf()) {return;}
if(TalentMeleeAttacked(oIntruder)) {return;}
if(TalentRangedAttackers(oIntruder)) {return;}
if(TalentRangedEnemies(oIntruder)) {return;}
if(TalentSpellAttack(oIntruder)) {return;}
if(TalentMeleeAttack(oIntruder)) {return;}
}
else if (nClass == CLASS_TYPE_CONSTRUCT || nClass == CLASS_TYPE_ELEMENTAL)
{
if(TalentPersistentAbilities()) {return;}
if(TalentSummonAllies()) {return;}
if(d100() > 50)
{
if(TalentMeleeAttack(oIntruder)) {return;}
}
if(TalentAdvancedProtectSelf()){return;}
if(TalentUseProtectionOnSelf()) {return;}
if(TalentUseEnhancementOnSelf()) {return;}
if(TalentMeleeAttacked(oIntruder)) {return;}
if(TalentRangedAttackers(oIntruder)) {return;}
if(TalentRangedEnemies(oIntruder)) {return;}
if(TalentSpellAttack(oIntruder)) {return;}
if(TalentMeleeAttack(oIntruder)) {return;}
}
else
{
if(TalentPersistentAbilities()) {return;}
//Check if I am injured
if(TalentHeal()) {return;}
if(nOffense > 75)
{
if (fChallenge > fThresholdChallenge || d100() < 2) {
if(TalentAdvancedProtectSelf()){return;}
//Check if the character can enhance themselves
if(TalentUseEnhancementOnSelf()) {return;}
// Check for enhancements on party
if(TalentEnhanceOthers()) {return;}
//Use protections on Self
if(TalentUseProtectionOnSelf()) {return;}
//Check for Allies
if(TalentUseProtectionOthers()) {return;}
//Check for Allies
if(TalentMeleeAttacked(oIntruder)) {return;}
//Check for Ranged Attackers
if(TalentRangedAttackers(oIntruder)) {return;}
//Check for Ranged Enemies
if(TalentRangedEnemies(oIntruder)) {return;}
//Attack if out of spells
if(TalentBuffSelf()) {return;}
}
if(TalentSummonAllies()) {return;}
//Check for Personal Attackers
if(TalentMeleeAttack(oIntruder)) {return;}
}
else
{
if (fChallenge > fThresholdChallenge || d100() < 2) {
if(TalentSummonAllies()) {return;}
//Check for Personal Attackers
if(TalentMeleeAttacked(oIntruder)) {return;}
//Check for Ranged Attackers
if(TalentRangedAttackers(oIntruder)) {return;}
//Check for Ranged Enemies
if(TalentRangedEnemies(oIntruder)) {return;}
//Spell Attack
if(TalentSpellAttack(oIntruder)) {return;}
//Attack if out of spells
if(TalentBuffSelf()) {return;}
}
if(TalentMeleeAttack(oIntruder)) {return;}
}
return;
}
}
//This check is to make sure that people do not drop out of combat before they are supposed to.
object oTarget = GetNearestCreature(CREATURE_TYPE_REPUTATION, REPUTATION_TYPE_ENEMY, OBJECT_SELF, 1, CREATURE_TYPE_PERCEPTION, PERCEPTION_SEEN);
if(GetIsObjectValid(oTarget))
{
SpeakString("Danger Will Robinson Danger");
DetermineCombatRound(oTarget);
return;
}
//This is a call to the function which determines which way point to go back to.
ClearAllActions();
SetLocalObject(OBJECT_SELF, "NW_GENERIC_LAST_ATTACK_TARGET", OBJECT_INVALID);
WalkWayPoints();
}
//::///////////////////////////////////////////////
//:: SetListeningPatterns
//:: Copyright © 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()
{
//There is a 70% chance to make someone sleep if it is night.
//If they have no way points to walk.
if(GetIsNight() && !CheckWayPoints())
{
if(GetSpawnInCondition(NW_FLAG_SLEEPING_AT_NIGHT))
{
if(d10() <= 7)
{
int nRand = Random(361);
SetFacing(IntToFloat(nRand));
//effect eSleep = EffectSleep();
//ApplyEffectToObject(DURATION_TYPE_PERMANENT, eSleep, OBJECT_SELF);
}
}
}
if(GetSpawnInCondition(NW_FLAG_APPEAR_SPAWN_IN_ANIMATION))
{
MyPrintString("GENERIC SCRIPT DEBUG STRING ********** " + "USING SPAWN IN CONDITION NOW BASTARDO");
effect eAppear = EffectAppear();
ApplyEffectToObject(DURATION_TYPE_INSTANT, eAppear, OBJECT_SELF);
}
SetListening(OBJECT_SELF, TRUE);
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);
//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);
}
//::///////////////////////////////////////////////
//:: Respond To Shouts
//:: Copyright © 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");
object oHench;
object oFamiliar;
object oAnimal;
object oSummoned;
object oDominated;
int nHench;
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)
{
ActionAttack(GetLastHostileActor(oShouter));
}
else
{
DetermineCombatRound(oIntruder);
}
}
else
{
DetermineSpecialBehavior();
}
if(GetIsObjectValid(GetHenchman(OBJECT_SELF)) == TRUE)
{
oHench = GetAssociate(ASSOCIATE_TYPE_HENCHMAN, OBJECT_SELF);
AssignCommand(oHench, RespondToShout(OBJECT_SELF, 1));
}
if(GetAssociate(ASSOCIATE_TYPE_FAMILIAR, OBJECT_SELF) != OBJECT_INVALID)
{
oFamiliar = GetAssociate(ASSOCIATE_TYPE_FAMILIAR, OBJECT_SELF);
AssignCommand(oFamiliar, RespondToShout(OBJECT_SELF, 1));
}
if(GetAssociate(ASSOCIATE_TYPE_ANIMALCOMPANION, OBJECT_SELF) != OBJECT_INVALID)
{
oAnimal = GetAssociate(ASSOCIATE_TYPE_ANIMALCOMPANION, OBJECT_SELF);
AssignCommand(oAnimal, RespondToShout(OBJECT_SELF, 1));
}
if(GetAssociate(ASSOCIATE_TYPE_SUMMONED, OBJECT_SELF) != OBJECT_INVALID)
{
oSummoned = GetAssociate(ASSOCIATE_TYPE_SUMMONED, OBJECT_SELF);
AssignCommand(oSummoned, RespondToShout(OBJECT_SELF, 1));
}
if(GetAssociate(ASSOCIATE_TYPE_DOMINATED, OBJECT_SELF) != OBJECT_INVALID)
{
oDominated = GetAssociate(ASSOCIATE_TYPE_DOMINATED, OBJECT_SELF);
AssignCommand(oDominated, RespondToShout(OBJECT_SELF, 1));
}
}
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))
{