Battledale_PRC8/_module/nss/jw_talents_inc.nss
Jaysyn904 e5b3f6ad61 Finished PRC8 integration
Finished PRC8 integration.  Moved creature abilities to top hak.  Setup tooling.  Created release archive
2024-03-12 21:27:23 -04:00

3001 lines
102 KiB
Plaintext

///////
#include "jw_combsubs_inc"
#include "jw_custom_spells"
#include "prc_inc_spells"
// Bitwise constants for negative conditions we might want to try to cure
/* int COND_CURSE = 0x00000001;
int COND_POISON = 0x00000002;
int COND_DISEASE = 0x00000004;
int COND_ABILITY = 0x00000008;
int COND_DRAINED = 0x00000010;
int COND_BLINDDEAF = 0x00000020;
// NEW */
// * Wrapper function so that I could add a variable to allow randomization
// * to the AI.
// * WARNING: This will make the AI cast spells badly if they have a bad
// * spell selection (i.e., only turn randomization on if you know what you are doing
// *
// * nCRMax only applies if bRandom is FALSE
// * oCreature is the creature checking to see if it has the talent
talent GetCreatureTalent(int nCategory, int nCRMax, int bRandom=FALSE, object oCreature = OBJECT_SELF);
// * Tries to do the Ki Damage ability
int TryKiDamage(object oTarget);
// Try a spell to produce a particular spell effect.
// This will only cast the spell if the target DOES NOT already have the
// given spell effect, and the caster possesses the spell.
//
// Returns TRUE on success, FALSE on failure.
int TrySpell(int nSpell, object oTarget=OBJECT_SELF, object oCaster=OBJECT_SELF);
// Try a spell corresponding to a particular effect.
// This will only cast the spell if the target DOES have the
// given effect, and the caster possesses the spell.
//
// Returns TRUE on success, FALSE on failure.
int TrySpellForEffect(int nSpell, int nEffect, object oTarget=OBJECT_SELF, object oCaster=OBJECT_SELF);
// Try a given talent.
// This will only cast spells and feats if the targets do not already
// have the effects of those feats, and will funnel all talents
// through bkTalentFilter for a final check.
int TryTalent(talent tUse, object oTarget=OBJECT_SELF, object oCaster=OBJECT_SELF);
//// This function simply attempts to get the best protective
// talent that the caller has, the protective talents as
// follows:
// TALENT_CATEGORY_BENEFICIAL_PROTECTION_SELF
// TALENT_CATEGORY_BENEFICIAL_PROTECTION_SINGLE
// TALENT_CATEGORY_BENEFICIAL_PROTECTION_AREAEFFECT
talent StartProtectionLoop();
// Does rdaius damage - used for throwtree and mimicattack. Leave int nKnockDC at 0 to now have any knockdown effect
void DoRadiusDamage(int iSpell, location lLoc, int iExplosion, int iDamage, int iDamageType, float fRadius, int nKnockDC=0);
//CURRENT TALENT FUNCTIONS
// int TalentBlackguardAura(object oIntruder); Not used on BD
int TalentCurseSong (object oIntruder = OBJECT_INVALID);
int TalentBlindSpit (object oIntruder = OBJECT_INVALID);
int TalentFlyToEnemy (object oIntruder = OBJECT_INVALID);
int TalentGarotte (object oIntruder = OBJECT_INVALID);
int TalentMimicCombat (object oIntruder = OBJECT_INVALID);
int TalentThrowTree (object oIntruder = OBJECT_INVALID);
int TalentWingBlast(object oIntruder = OBJECT_INVALID);
int TalentDismissal(object oIntruder = OBJECT_INVALID);
int TalentDispelEffects(object oIntruder = OBJECT_INVALID);
int TalentUseProtectionOnSelf();
int TalentUseProtectionOthers(object oDefault=OBJECT_INVALID);
int TalentEnhanceOthers();
int TalentUseEnhancementOnSelf();
int TalentMeleeAttacked(object oIntruder = OBJECT_INVALID);
int TalentRangedAttackers(object oIntruder = OBJECT_INVALID);
int TalentRangedEnemies(object oIntruder = OBJECT_INVALID);
int TalentSummonAllies();
// HEAL SELF WITH POTIONS AND SPELLS
// Returns TRUE on successful use of such a talent, FALSE otherwise.
int TalentHealingSelf(int bForce = FALSE); //Use spells and potions
// HEAL ALL ALLIES
// BK: Added an optional parameter for object.
int TalentHeal(int nForce = FALSE, object oTarget = OBJECT_SELF);
int TalentMeleeAttack(object oIntruder = OBJECT_INVALID);
int TalentSneakAttack();
int TalentFlee(object oIntruder = OBJECT_INVALID);
int TalentUseTurning();
int TalentPersistentAbilities();
int TalentAdvancedBuff(float fDistance, int bInstant = TRUE);
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);
int TalentHealUndead(object oTarget = OBJECT_SELF);
//:://///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//:: Talent checks and use functions
//:: Copyright (c) 2001 Bioware Corp.
//:://///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/*
This is a series of functions that check
if a particular type of talent is available and
if so then use that talent.
*/
//:://///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//:: Created By: Preston Watamaniuk
//:: Created On: Oct 16, 2001
//:://///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/*
int TalentBlackguardAura(object oIntruder)
{
if (GetLevelByClass(CLASS_TYPE_BLACKGUARD)<1)
{
return FALSE;
}
if (GetLocalInt(OBJECT_SELF,"doneblackaura")==TRUE)
{
return FALSE;
}
object oSymbol=CreateItemOnObject("jw_unholy_sym");
ClearAllActions();
ActionEquipItem(oSymbol,INVENTORY_SLOT_LEFTHAND);
PlayVoiceChat(VOICE_CHAT_PAIN2);
DelayCommand(2.0,UseUnHolySymbol());
SetLocalInt(OBJECT_SELF,"doneblackaura",TRUE);
SetCommandable(FALSE);
DelayCommand(4.0,SetCommandable(TRUE));
DelayCommand(4.1,bkEquipAppropriateWeapons(oIntruder,FALSE,FALSE));
return TRUE;
}
*/
// Talent curse song
// Written by Palmer as mobs don't seem to use this ability
int TalentCurseSong (object oIntruder)
{
if (!GetHasFeat(FEAT_BARD_SONGS, OBJECT_SELF))
{
// no more bardsong uses left
return FALSE;
}
if (PRCGetHasEffect(EFFECT_TYPE_SILENCE,OBJECT_SELF))
{
// not useable when silenced
return FALSE;
}
// Check if has feat
if (!GetHasFeat(FEAT_CURSE_SONG))
{
return FALSE;
}
if (GetHasFeatEffect(871,oIntruder))
{
return FALSE;
}
// Range is 10 ft
if (GetDistanceToObject(oIntruder)>9.0)
{
return FALSE;
}
// okay everything should be set up
ActionUseFeat(FEAT_CURSE_SONG,OBJECT_SELF);
return TRUE;
}
// PROTECT SELF
int TalentUseProtectionOnSelf()
{
//MyPrintString("GENERIC SCRIPT DEBUG STRING ********** " + "TalentUseProtectionOnSelf Enter");
talent tUse;
int nType, nIndex;
int bValid = FALSE;
int nCR = GetAssociateCRMax();
tUse = GetCreatureTalentBest(TALENT_CATEGORY_BENEFICIAL_PROTECTION_SELF, 40);
if(!GetIsTalentValid(tUse))
{
tUse = GetCreatureTalentBest(TALENT_CATEGORY_BENEFICIAL_PROTECTION_SINGLE, 40);
if(GetIsTalentValid(tUse))
{
//MyPrintString("GENERIC SCRIPT DEBUG STRING ********** " + "I have found a way to protect my self");
bValid = TRUE;
}
}
else
{
//MyPrintString("GENERIC SCRIPT DEBUG STRING ********** " + "I have found a way to protect my self");
bValid = TRUE;
}
if(bValid == TRUE)
{
nType = GetTypeFromTalent(tUse);
nIndex = GetIdFromTalent(tUse);
if(nType == TALENT_TYPE_SPELL)
{
if(!GetHasSpellEffect(nIndex))
{
ClearAllActions();
//MyPrintString("GENERIC SCRIPT DEBUG STRING ********** " + "TalentUseProtectionOnSelf Successful Exit");
ActionUseTalentOnObject(tUse, OBJECT_SELF);
return TRUE;
}
}
else if(nType == TALENT_TYPE_FEAT)
{
if(!GetHasFeatEffect(nIndex))
{
ClearAllActions();
//MyPrintString("GENERIC SCRIPT DEBUG STRING ********** " + "TalentUseProtectionOnSelf Successful Exit");
ActionUseTalentOnObject(tUse, OBJECT_SELF);
return TRUE;
}
}
else
{
//MyPrintString("GENERIC SCRIPT DEBUG STRING ********** " + "TalentUseProtectionOnSelf Successful Exit");
ActionUseTalentOnObject(tUse, OBJECT_SELF);
return TRUE;
}
}
//MyPrintString("GENERIC SCRIPT DEBUG STRING ********** " + "TalentUseProtectionOnSelf Failed Exit");
return FALSE;
}
//PROTECT PARTY
int TalentUseProtectionOthers(object oDefault=OBJECT_INVALID)
{
//MyPrintString("GENERIC SCRIPT DEBUG STRING ********** " + "TalentUseProtectionOthers Enter");
talent tUse, tMass;
int nType, nFriends, nIndex;
int nCnt = 1;
int bValid = FALSE;
int nCR = 40;
object oTarget = GetNearestCreature(CREATURE_TYPE_REPUTATION, REPUTATION_TYPE_FRIEND, OBJECT_SELF, 1, CREATURE_TYPE_PERCEPTION, PERCEPTION_SEEN);
tUse = GetCreatureTalentBest(TALENT_CATEGORY_BENEFICIAL_PROTECTION_SINGLE, nCR);
tMass = GetCreatureTalentBest(TALENT_CATEGORY_BENEFICIAL_PROTECTION_AREAEFFECT, nCR);
//Override the nearest target if the master wants aggressive buff spells
if(GetAssociateState(NW_ASC_AGGRESSIVE_BUFF) && GetAssociateState(NW_ASC_HAVE_MASTER))
{
oTarget = GetMaster();
}
while(GetIsObjectValid(oTarget))
{
if(GetIsTalentValid(tMass))
{
if(CheckFriendlyFireOnTarget(oTarget) > 2)
{
nType = GetTypeFromTalent(tMass);
nIndex = GetIdFromTalent(tMass);
if(nType == TALENT_TYPE_SPELL)
{
if(!GetHasSpellEffect(nIndex, oTarget))
{
MyPrintString("GENERIC SCRIPT DEBUG STRING ********** " + "TalentUseProtectionOthers Successful Exit");
ClearAllActions();
ActionUseTalentOnObject(tMass, oTarget);
return TRUE;
}
}
else if(nType == TALENT_TYPE_FEAT)
{
if(!GetHasFeatEffect(nIndex, oTarget))
{
ClearAllActions();
MyPrintString("GENERIC SCRIPT DEBUG STRING ********** " + "TalentUseProtectionOthers Successful Exit");
ActionUseTalentOnObject(tUse, OBJECT_SELF);
return TRUE;
}
}
else
{
MyPrintString("GENERIC SCRIPT DEBUG STRING ********** " + "TalentUseProtectionOthers Successful Exit");
ClearAllActions();
ActionUseTalentOnObject(tMass, oTarget);
return TRUE;
}
}
}
if(GetIsTalentValid(tUse))
{
nType = GetTypeFromTalent(tUse);
nIndex = GetIdFromTalent(tUse);
if(nType == TALENT_TYPE_SPELL)
{
MyPrintString("GENERIC SCRIPT DEBUG STRING ********** " + "Has Effects from Spell ID " + IntToString(nIndex) + " is: " + IntToString(GetHasSpellEffect(nIndex)));
if(!GetHasSpellEffect(nIndex, oTarget))
{
MyPrintString("GENERIC SCRIPT DEBUG STRING ********** " + "TalentUseProtectionOthers Successful Exit");
ClearAllActions();
ActionUseTalentOnObject(tUse, oTarget);
return TRUE;
}
}
else if(nType == TALENT_TYPE_FEAT)
{
MyPrintString("GENERIC SCRIPT DEBUG STRING ********** " + "Has Effects from Feat ID " + IntToString(nIndex) + " is: " + IntToString(GetHasSpellEffect(nIndex)));
if(!GetHasFeatEffect(nIndex, oTarget))
{
MyPrintString("GENERIC SCRIPT DEBUG STRING ********** " + "TalentUseProtectionOthers Successful Exit");
ClearAllActions();
ActionUseTalentOnObject(tUse, OBJECT_SELF);
return TRUE;
}
}
else
{
MyPrintString("GENERIC SCRIPT DEBUG STRING ********** " + "TalentUseProtectionOthers Successful Exit");
ClearAllActions();
ActionUseTalentOnObject(tUse, oTarget);
return TRUE;
}
}
nCnt++;
oTarget = GetNearestCreature(CREATURE_TYPE_REPUTATION, REPUTATION_TYPE_FRIEND, OBJECT_SELF, nCnt, CREATURE_TYPE_PERCEPTION, PERCEPTION_SEEN);
}
MyPrintString("GENERIC SCRIPT DEBUG STRING ********** " + "TalentUseProtectionOthers Failed Exit");
return FALSE;
}
// Use wingblastattack
int TalentWingBlast(object oIntruder)
{
int nBlasts=GetWingblast();
// if it doesn't have the skill, or d4!=1, return. One in your chance of not blasting
if ((nBlasts<1)||(d4()!=1))
{
return FALSE;
}
// check we haven't just done it
int nDoneWing=GetLocalInt(OBJECT_SELF,"nDoneWing");
if (nDoneWing==1)
{
SetLocalInt(OBJECT_SELF,"nDoneWing",2);
return FALSE;
}
else
if (nDoneWing==2)
{
SetLocalInt(OBJECT_SELF,"nDoneWing",0);
return FALSE;
}
object oVictim=oIntruder;
if ((GetDistanceToObject(oVictim)<=8.0)&&GetDistanceToObject(oVictim)!=-1.0)
{
// in this situation, everything is in place to do the blast
effect eAppear;
effect eKnockDown = EffectKnockdown();
int nHP;
int nCurrent = 0;
object oVict;
int nDamage = GetHitDice(OBJECT_SELF);
int nDC = 5+nDamage;
if (nDamage>12)
{
nDamage=12;
}
nDamage = d2(nDamage) + 5;
effect eDam = EffectDamage(nDamage, DAMAGE_TYPE_BLUDGEONING);
effect eVis = EffectVisualEffect(VFX_IMP_PULSE_WIND);
ApplyEffectToObject(DURATION_TYPE_INSTANT, eVis, OBJECT_SELF);
//Get first target in spell area
object oTarget = GetFirstObjectInShape(SHAPE_SPHERE, RADIUS_SIZE_GARGANTUAN, GetLocation(OBJECT_SELF));
while(GetIsObjectValid(oTarget))
{
if(!GetIsReactionTypeFriendly(oTarget))
{
if(GetCreatureSize(oTarget) != CREATURE_SIZE_HUGE)
{
if(!ReflexSave(oTarget, nDC))
{
ApplyEffectToObject(DURATION_TYPE_INSTANT, eDam, oTarget);
ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eKnockDown, oTarget, 6.0);
}
}
}
//Get next target in spell area
oTarget = GetNextObjectInShape(SHAPE_SPHERE, RADIUS_SIZE_GARGANTUAN, GetLocation(OBJECT_SELF));
}
location lLocal;
lLocal = GetLocation(OBJECT_SELF);
//Apply the VFX impact and effects
eAppear = EffectDisappearAppear(lLocal);
ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eAppear, OBJECT_SELF, 6.0);
SetWingblast (nBlasts-1);
SetLocalInt(OBJECT_SELF,"nDoneWing",1);
return TRUE;
}
return FALSE;
}
// ENHANCE OTHERS
int TalentEnhanceOthers()
{
//MyPrintString("TalentEnhanceOthers Enter");
talent tUse, tMass;
int nType, nFriends, nIndex;
int nCnt = 1;
int bValid = FALSE;
int nCR = 40;
object oTarget = GetNearestSeenFriend();
tUse = GetCreatureTalent(TALENT_CATEGORY_BENEFICIAL_ENHANCEMENT_SINGLE, nCR);
tMass = GetCreatureTalent(TALENT_CATEGORY_BENEFICIAL_ENHANCEMENT_AREAEFFECT, nCR);
//Override the nearest target if the master wants aggressive buff spells
if(GetAssociateState(NW_ASC_AGGRESSIVE_BUFF)
&& GetAssociateState(NW_ASC_HAVE_MASTER))
{
oTarget = GetMaster();
}
while(GetIsObjectValid(oTarget)) {
if(GetIsTalentValid(tMass)) {
if(CheckFriendlyFireOnTarget(oTarget) > 2)
{
nType = GetTypeFromTalent(tMass);
nIndex = GetIdFromTalent(tMass);
if(nType == TALENT_TYPE_SPELL)
{
MyPrintString("GENERIC SCRIPT DEBUG STRING ********** " + "Has Effects from Spell ID " + IntToString(nIndex) + " is: " + IntToString(GetHasSpellEffect(nIndex)));
if(!GetHasSpellEffect(nIndex, oTarget))
{
MyPrintString("GENERIC SCRIPT DEBUG STRING ********** " + "TalentUseProtectionOthers Successful Exit");
ClearAllActions();
ActionUseTalentOnObject(tMass, oTarget);
return TRUE;
}
}
else if(nType == TALENT_TYPE_FEAT)
{
MyPrintString("GENERIC SCRIPT DEBUG STRING ********** " + "Has Effects from Feat ID " + IntToString(nIndex) + " is: " + IntToString(GetHasSpellEffect(nIndex)));
if(!GetHasFeatEffect(nIndex, oTarget))
{
MyPrintString("GENERIC SCRIPT DEBUG STRING ********** " + "TalentUseProtectionOthers Successful Exit");
ClearAllActions();
ActionUseTalentOnObject(tMass, OBJECT_SELF);
return TRUE;
}
}
}
}
if(GetIsTalentValid(tUse)) {
nType = GetTypeFromTalent(tUse);
nIndex = GetIdFromTalent(tUse);
if(nType == TALENT_TYPE_SPELL)
{
MyPrintString("GENERIC SCRIPT DEBUG STRING ********** " + "Has Effects from Spell ID " + IntToString(nIndex) + " is: " + IntToString(GetHasSpellEffect(nIndex)));
if(!GetHasSpellEffect(nIndex, oTarget))
{
MyPrintString("GENERIC SCRIPT DEBUG STRING ********** " + "TalentUseProtectionOthers Successful Exit");
ClearAllActions();
ActionUseTalentOnObject(tUse, oTarget);
return TRUE;
}
}
else if(nType == TALENT_TYPE_FEAT)
{
MyPrintString("GENERIC SCRIPT DEBUG STRING ********** " + "Has Effects from Feat ID " + IntToString(nIndex) + " is: " + IntToString(GetHasSpellEffect(nIndex)));
if(!GetHasFeatEffect(nIndex, oTarget))
{
MyPrintString("GENERIC SCRIPT DEBUG STRING ********** " + "TalentUseProtectionOthers Successful Exit");
ClearAllActions();
ActionUseTalentOnObject(tUse, OBJECT_SELF);
return TRUE;
}
}
}
nCnt++;
oTarget = GetNearestSeenFriend(OBJECT_SELF, nCnt);
}
//MyPrintString("TalentEnhanceOthers Failed Exit");
return FALSE;
}
// ENHANCE SELF
int TalentUseEnhancementOnSelf()
{
//MyPrintString("TalentUseEnhancementOnSelf Enter");
talent tUse;
int nType;
int bValid = FALSE;
int nIndex;
int nCR = 40;
object oTarget=OBJECT_SELF;
tUse = GetCreatureTalent(TALENT_CATEGORY_BENEFICIAL_ENHANCEMENT_SELF,
40);
if(!GetIsTalentValid(tUse)) {
tUse = GetCreatureTalent(TALENT_CATEGORY_BENEFICIAL_ENHANCEMENT_SINGLE,
40);
if(GetIsTalentValid(tUse)) {
bValid = TRUE;
}
} else {
bValid = TRUE;
}
if(bValid == TRUE) {
if (GetIdFromTalent(tUse) == SPELL_INVISIBILITY && Random(2) == 0) {
//MyPrintString("Decided not to use Invisibility");
return FALSE; // BRENT JULY 2002: There is a 50% chance that
// they will not use invisibility if they have it
}
nType = GetTypeFromTalent(tUse);
nIndex = GetIdFromTalent(tUse);
if(nType == TALENT_TYPE_SPELL)
{
MyPrintString("GENERIC SCRIPT DEBUG STRING ********** " + "Has Effects from Spell ID " + IntToString(nIndex) + " is: " + IntToString(GetHasSpellEffect(nIndex)));
if(!GetHasSpellEffect(nIndex, oTarget))
{
MyPrintString("GENERIC SCRIPT DEBUG STRING ********** " + "TalentUseProtectionOthers Successful Exit");
ClearAllActions();
ActionUseTalentOnObject(tUse, oTarget);
return TRUE;
}
}
else if(nType == TALENT_TYPE_FEAT)
{
MyPrintString("GENERIC SCRIPT DEBUG STRING ********** " + "Has Effects from Feat ID " + IntToString(nIndex) + " is: " + IntToString(GetHasSpellEffect(nIndex)));
if(!GetHasFeatEffect(nIndex, oTarget))
{
MyPrintString("GENERIC SCRIPT DEBUG STRING ********** " + "TalentUseProtectionOthers Successful Exit");
ClearAllActions();
ActionUseTalentOnObject(tUse, OBJECT_SELF);
return TRUE;
}
}
}
//MyPrintString("TalentUseEnhancementOnSelf Failed Exit");
return FALSE;
}
/*
// ENHANCE OTHERS
int TalentEnhanceOthers()
{
MyPrintString("GENERIC SCRIPT DEBUG STRING ********** " + "TalentEnhanceOthers Enter");
talent tUse, tMass;
int nType, nFriends, nIndex;
int nCnt = 1;
int bValid = FALSE;
if ((!GetHasSpell(SPELL_HASTE))&&(!GetHasSpell(SPELL_MASS_HASTE)))
{
return FALSE;
}
object oTarget = GetNearestCreature(CREATURE_TYPE_REPUTATION, REPUTATION_TYPE_FRIEND, OBJECT_SELF, 1, CREATURE_TYPE_PERCEPTION, PERCEPTION_SEEN);
//Override the nearest target if the master wants aggressive buff spells
if(GetAssociateState(NW_ASC_AGGRESSIVE_BUFF) && GetAssociateState(NW_ASC_HAVE_MASTER))
{
oTarget = GetMaster();
}
while(GetIsObjectValid(oTarget))
{
if (GetIsObjectValid(oTarget)&&(GetHasSpell(SPELL_MASS_HASTE))&&(!GetHasSpellEffect(SPELL_MASS_HASTE,oTarget)))
{
ClearAllActions();
ActionCastSpellAtObject(SPELL_MASS_HASTE,oTarget);
return TRUE;
}
if (GetIsObjectValid(oTarget)&&(GetHasSpell(SPELL_HASTE))&&(!GetHasSpellEffect(SPELL_HASTE,oTarget)))
{
ClearAllActions();
ActionCastSpellAtObject(SPELL_HASTE,oTarget);
return TRUE;
}
nCnt++;
oTarget = GetNearestCreature(CREATURE_TYPE_REPUTATION, REPUTATION_TYPE_FRIEND, OBJECT_SELF, nCnt, CREATURE_TYPE_PERCEPTION, PERCEPTION_SEEN);
}
MyPrintString("GENERIC SCRIPT DEBUG STRING ********** " + "TalentEnhanceOthers Failed Exit");
return FALSE;
}
// ENHANCE SELF
int TalentUseEnhancementOnSelf()
{
object oTarget=OBJECT_SELF;
if (GetIsObjectValid(oTarget)&&(GetHasSpell(SPELL_MASS_HASTE))&&(!GetHasSpellEffect(SPELL_MASS_HASTE,oTarget)))
{
ClearAllActions();
ActionCastSpellAtObject(SPELL_MASS_HASTE,oTarget);
return TRUE;
}
if (GetIsObjectValid(oTarget)&&(GetHasSpell(SPELL_HASTE))&&(!GetHasSpellEffect(SPELL_HASTE,oTarget)))
{
ClearAllActions();
ActionCastSpellAtObject(SPELL_HASTE,oTarget);
return TRUE;
}
MyPrintString("GENERIC SCRIPT DEBUG STRING ********** " + "TalentUseEnhancementOnSelf Failed Exit");
return FALSE;
}
/*
// SPELL CASTER MELEE ATTACKED
//::///////////////////////////////////////////////
//:: genericDoHarmfulRangedAttack
//:: Copyright (c) 2001 Bioware Corp.
//:://////////////////////////////////////////////
/*
Wrote this function so I could do further
checks such as making them not cast
Dispel Magic.
// * Possible Issue (brent): It may get stuck on
// * dispel magics...trying to cast them
// * and not proceed down Area Of Effect Discriminants...
SOLUTION: If this function returns true the TalentMeleeAttacked routine
will exit, however if it returns false, it will try and find some
other ability to use.
*/
//:://////////////////////////////////////////////
//:: Created By: Brent
//:: Created On: July 2002
//:://////////////////////////////////////////////
int genericDoHarmfulRangedAttack(talent tUse, object oTarget)
{
//MyPrintString("BK: genericDoharmfulRangedAttack");
int bConditionsMet = FALSE;
// * check to see if this talent is a spell talent
if (GetTypeFromTalent(tUse) == TALENT_TYPE_SPELL)
{
int nSpellID = GetIdFromTalent(tUse);
// * Check to see if Dispel Magic and similar spells should *not* be cast
if (nSpellID == SPELL_DISPEL_MAGIC || nSpellID == SPELL_MORDENKAINENS_DISJUNCTION
|| nSpellID == SPELL_LESSER_DISPEL || nSpellID == SPELL_GREATER_DISPELLING)
{
//MyPrintString("BK: inside of dispel magic");
effect eEffect = GetFirstEffect(oTarget);
while (GetIsEffectValid(eEffect) == TRUE)
{
//MyPrintString("BK: Valid effect");
int nEffectID = GetEffectSpellId(eEffect);
// * JULY 14 2003
// * If the effects originated from me (i.e., I cast
// * a disabling effect on you. Then I will not
// * dispel that effect
if (GetEffectCreator(eEffect) == OBJECT_SELF)
{
bConditionsMet = FALSE;
break;
}
else
// * this effect was applied from a spell if it
// * isn't -1
// * dispel magic should only attempt to remove spell
// * granted effects
if (nEffectID == -1)
{
//MyPrintString("BK: conditions NOT met");
}
else
{
//MyPrintString("BK: conditions met");
bConditionsMet = TRUE;
}
eEffect = GetNextEffect(oTarget);
}
} else {
// if not a special condition spell then conditions are met auto.
bConditionsMet = TRUE;
}
}
// * only returns true if all of the conditions are met.
if (bConditionsMet == TRUE)
{
//MyPrintString("BK: bCOnditionsMet == TRUE");
//DebugPrintTalentID(tUse);
//MyPrintString("TalentMeleeAttacked Successful Exit");
bkTalentFilter(tUse, oTarget);
return TRUE;
}
return FALSE;
}
//::///////////////////////////////////////////////
//:: genericAttemptHarmfulRanged
//:: Copyright (c) 2001 Bioware Corp.
//:://////////////////////////////////////////////
/*
Will return true if it succesfully
used a harmful ranged talent.
BK: Wrapper function to encapsulate some
commonly used behavior in these
scripts.
*/
//:://////////////////////////////////////////////
//:: Created By: Brent
//:: Created On: July 2002
//:://////////////////////////////////////////////
int genericAttemptHarmfulRanged(talent tUse, object oTarget)
{
//SpawnScriptDebugger();
if( GetTypeFromTalent(tUse) != TALENT_TYPE_SPELL
||
(GetTypeFromTalent(tUse) == TALENT_TYPE_SPELL
&& !GetHasSpellEffect(GetIdFromTalent(tUse), oTarget)
&& !CompareLastSpellCast(GetIdFromTalent(tUse)) )
)
{
//MyPrintString("2164: Can try to do a DoHarmfulRangedAttack");
if (genericDoHarmfulRangedAttack(tUse, oTarget)) {
if( GetTypeFromTalent(tUse) == TALENT_TYPE_SPELL) {
SetLastGenericSpellCast(GetIdFromTalent(tUse));
}
return TRUE;
}
}
else
// MODIFIED
// Try to find a suitable second choice (up to 5 tries to find one)
{
int nSteps = 0;
int bDone = FALSE;
while (bDone == FALSE)
{
if (nSteps >= 5)
bDone = TRUE;
nSteps++;
tUse = GetCreatureTalentRandom(TALENT_CATEGORY_HARMFUL_RANGED);
if (GetTypeFromTalent(tUse) != TALENT_TYPE_SPELL
||
(GetTypeFromTalent(tUse) == TALENT_TYPE_SPELL
&& !GetHasSpellEffect(GetIdFromTalent(tUse), oTarget)
&& !CompareLastSpellCast(GetIdFromTalent(tUse)) )
)
{
if (genericDoHarmfulRangedAttack(tUse, oTarget))
{
if( GetTypeFromTalent(tUse) == TALENT_TYPE_SPELL)
{
SetLastGenericSpellCast(GetIdFromTalent(tUse));
}
return TRUE;
}
}
}
// * End modification to loop through available talents
}
// else
//MyPrintString("BK: Harmful Ranged will return false");
return FALSE;
}
int TalentMeleeAttacked(object oIntruder = OBJECT_INVALID)
{
//MyPrintString("TalentMeleeAttacked Enter");
talent tUse;
int nMelee = GetNumberOfMeleeAttackers();
object oTarget = oIntruder;
int nCR = 40;
if(!GetIsObjectValid(oIntruder) && GetIsObjectValid(GetLastHostileActor()))
{
oTarget = GetLastHostileActor();
}
else
{
return FALSE;
}
/*
ISSUE 1: The check in this function to use a random ability
after failing to use best will fail in the following
case. The creature is unable to affect the target with
the spell and has only 1 spell of that type. This can
be eliminated with a check in the else to the effect of :
else if(!CompareLastSpellCast(GetIdFromTalent(tUse)))
This check was not put in in version 1.0 due to time constraints.
ISSUE 2: Given the Spell Attack is the drop out check the
else statements in this talent should be cut.
*/
if(nMelee == 1)
{
tUse = GetCreatureTalent(TALENT_CATEGORY_HARMFUL_TOUCH, nCR,TRUE);
if(GetIsTalentValid(tUse))
{
if( (GetTypeFromTalent(tUse) == TALENT_TYPE_SPELL &&
!GetHasSpellEffect(GetIdFromTalent(tUse), oTarget) &&
!CompareLastSpellCast(GetIdFromTalent(tUse)) ) ||
GetTypeFromTalent(tUse) != TALENT_TYPE_SPELL )
{
if( GetTypeFromTalent(tUse) == TALENT_TYPE_SPELL)
{
SetLastGenericSpellCast(GetIdFromTalent(tUse));
}
//DebugPrintTalentID(tUse);
//MyPrintString("TalentMeleeAttacked HARMFUL TOUCH Successful Exit");
bkTalentFilter(tUse, oTarget);
return TRUE;
}
}
tUse = GetCreatureTalent(TALENT_CATEGORY_HARMFUL_RANGED, nCR,TRUE);
if(GetIsTalentValid(tUse))
{
// * BK: July 2002: Wrapped up harmful ranged into
// * a function to make it easier to make global
// * changes to the decision making process.
if (genericAttemptHarmfulRanged(tUse, oTarget) == TRUE)
{
return TRUE;
}
}
tUse = GetCreatureTalent(TALENT_CATEGORY_HARMFUL_AREAEFFECT_DISCRIMINANT, nCR,TRUE);
if(GetIsTalentValid(tUse))
{
if( (GetTypeFromTalent(tUse) == TALENT_TYPE_SPELL &&
!GetHasSpellEffect(GetIdFromTalent(tUse), oTarget) &&
!CompareLastSpellCast(GetIdFromTalent(tUse)) ) ||
GetTypeFromTalent(tUse) != TALENT_TYPE_SPELL )
{
if( GetTypeFromTalent(tUse) == TALENT_TYPE_SPELL)
{
SetLastGenericSpellCast(GetIdFromTalent(tUse));
}
//DebugPrintTalentID(tUse);
//MyPrintString("TalentMeleeAttacked AREAEFFECT D Successful Exit");
bkTalentFilter(tUse, oTarget);
return TRUE;
}
}
}
else if (nMelee > 1)
{
tUse = GetCreatureTalent(TALENT_CATEGORY_HARMFUL_AREAEFFECT_DISCRIMINANT, nCR,TRUE);
if(GetIsTalentValid(tUse))
{
if( (GetTypeFromTalent(tUse) == TALENT_TYPE_SPELL &&
!GetHasSpellEffect(GetIdFromTalent(tUse), oTarget) &&
!CompareLastSpellCast(GetIdFromTalent(tUse)) ) ||
GetTypeFromTalent(tUse) != TALENT_TYPE_SPELL )
{
if( GetTypeFromTalent(tUse) == TALENT_TYPE_SPELL)
{
SetLastGenericSpellCast(GetIdFromTalent(tUse));
}
//DebugPrintTalentID(tUse);
//MyPrintString("TalentMeleeAttacked AREA EFFECT DSuccessful Exit");
bkTalentFilter(tUse, oTarget);
return TRUE;
}
}
tUse = GetCreatureTalent(TALENT_CATEGORY_HARMFUL_TOUCH, nCR,TRUE);
if(GetIsTalentValid(tUse))
{
if( (GetTypeFromTalent(tUse) == TALENT_TYPE_SPELL &&
!GetHasSpellEffect(GetIdFromTalent(tUse), oTarget) &&
!CompareLastSpellCast(GetIdFromTalent(tUse)) ) ||
GetTypeFromTalent(tUse) != TALENT_TYPE_SPELL )
{
if( GetTypeFromTalent(tUse) == TALENT_TYPE_SPELL)
{
SetLastGenericSpellCast(GetIdFromTalent(tUse));
}
//DebugPrintTalentID(tUse);
//MyPrintString("TalentMeleeAttacked HARMFUL TOUCH Successful Exit");
bkTalentFilter(tUse, oTarget);
return TRUE;
}
}
tUse = GetCreatureTalent(TALENT_CATEGORY_HARMFUL_RANGED, nCR,TRUE);
if(GetIsTalentValid(tUse))
{
// * BK: July 2002: Wrapped up harmful ranged into
// * a function to make it easier to make global
// * changes to the decision making process.
if (genericAttemptHarmfulRanged(tUse, oTarget) == TRUE)
{
//MyPrintString("TalentMeleeAttacked HARMFUL RANGED Successful Exit");
return TRUE;
}
}
}
//MyPrintString("TalentMeleeAttacked Failed Exit");
return FALSE;
}
// SPELL CASTER RANGED ATTACKED
int TalentRangedAttackers(object oIntruder = OBJECT_INVALID)
{
//MyPrintString("TalentRangedAttackers Enter");
//Check for Single Ranged Targets
talent tUse;
object oTarget = oIntruder;
int nCR = 40;
if(!GetIsObjectValid(oIntruder))
{
oTarget = GetLastHostileActor();
}
if(GetIsObjectValid(oTarget) && GetDistanceBetween(oTarget, OBJECT_SELF) > 5.0)
{
if(CheckFriendlyFireOnTarget(oTarget) > 0)
{
tUse = GetCreatureTalent(TALENT_CATEGORY_HARMFUL_AREAEFFECT_DISCRIMINANT, nCR,TRUE);
if(GetIsTalentValid(tUse))
{
if( (GetTypeFromTalent(tUse) == TALENT_TYPE_SPELL &&
!GetHasSpellEffect(GetIdFromTalent(tUse), oTarget) &&
!CompareLastSpellCast(GetIdFromTalent(tUse)) ) ||
GetTypeFromTalent(tUse) != TALENT_TYPE_SPELL )
{
if( GetTypeFromTalent(tUse) == TALENT_TYPE_SPELL)
{
SetLastGenericSpellCast(GetIdFromTalent(tUse));
}
// DebugPrintTalentID(tUse);
//MyPrintString("TalentRangedAttackers Successful Exit");
bkTalentFilter(tUse, oTarget);
return TRUE;
}
}
}
else if(CheckEnemyGroupingOnTarget(oTarget) > 0)
{
tUse = GetCreatureTalent(TALENT_CATEGORY_HARMFUL_AREAEFFECT_INDISCRIMINANT, nCR,TRUE);
if(GetIsTalentValid(tUse))
{
//MyPrintString("2346 : Choose Talent here " + IntToString(nCR));
if( (GetTypeFromTalent(tUse) == TALENT_TYPE_SPELL &&
!GetHasSpellEffect(GetIdFromTalent(tUse), oTarget) &&
!CompareLastSpellCast(GetIdFromTalent(tUse)) ) ||
GetTypeFromTalent(tUse) != TALENT_TYPE_SPELL )
{
if( GetTypeFromTalent(tUse) == TALENT_TYPE_SPELL)
{
SetLastGenericSpellCast(GetIdFromTalent(tUse));
}
// DebugPrintTalentID(tUse);
//MyPrintString("TalentRangedAttackers Successful Exit");
ClearActions(CLEAR_X0_I0_TALENT_RangedAttackers);
ActionUseTalentAtLocation(tUse, GetLocation(oTarget));
return TRUE;
}
}
}
else
{
tUse = GetCreatureTalent(TALENT_CATEGORY_HARMFUL_RANGED, nCR,TRUE);
if(GetIsTalentValid(tUse))
{
// * BK: July 2002: Wrapped up harmful ranged into
// * a function to make it easier to make global
// * changes to the decision making process.
if (genericAttemptHarmfulRanged(tUse, oTarget) == TRUE)
{
return TRUE;
}
}
}
}
//MyPrintString("TalentRangedAttackers Failed Exit");
return FALSE;
}
// SPELL CASTER WITH RANGED ENEMIES
int TalentRangedEnemies(object oIntruder = OBJECT_INVALID)
{
//MyPrintString("TalentRangedEnemies Enter");
talent tUse;
object oTarget = oIntruder;
int nCR = 40;
if(!GetIsObjectValid(oIntruder))
{
oTarget = GetNearestSeenEnemy();
}
if(GetIsObjectValid(oTarget))
{
int nEnemy = CheckEnemyGroupingOnTarget(oTarget);
if(CheckFriendlyFireOnTarget(oTarget) > 0 && nEnemy > 0)
{
tUse = GetCreatureTalent(TALENT_CATEGORY_HARMFUL_AREAEFFECT_DISCRIMINANT,
nCR,TRUE);
if(GetIsTalentValid(tUse))
{
if( (GetTypeFromTalent(tUse) == TALENT_TYPE_SPELL &&
!GetHasSpellEffect(GetIdFromTalent(tUse), oTarget) &&
!CompareLastSpellCast(GetIdFromTalent(tUse)) ) ||
GetTypeFromTalent(tUse) != TALENT_TYPE_SPELL )
{
if( GetTypeFromTalent(tUse) == TALENT_TYPE_SPELL)
{
SetLastGenericSpellCast(GetIdFromTalent(tUse));
}
// DebugPrintTalentID(tUse);
//MyPrintString("TalentRangedEnemies Successful Exit");
// * ONLY TalentFilter not to have a ClarAllActions before it(February 6 2003)
bkTalentFilter(tUse, oTarget);
return TRUE;
}
}
}
else if(nEnemy > 0)
{
tUse = GetCreatureTalent(TALENT_CATEGORY_HARMFUL_AREAEFFECT_INDISCRIMINANT, nCR,TRUE);
if(GetIsTalentValid(tUse))
{
//MyPrintString("2428 : Choose Talent here " + IntToString(nCR));
if( (GetTypeFromTalent(tUse) == TALENT_TYPE_SPELL &&
!GetHasSpellEffect(GetIdFromTalent(tUse), oTarget) &&
!CompareLastSpellCast(GetIdFromTalent(tUse)) ) ||
GetTypeFromTalent(tUse) != TALENT_TYPE_SPELL )
{
if( GetTypeFromTalent(tUse) == TALENT_TYPE_SPELL)
{
SetLastGenericSpellCast(GetIdFromTalent(tUse));
}
// DebugPrintTalentID(tUse);
//MyPrintString("TalentRangedEnemies Successful Exit");
ClearActions(CLEAR_X0_I0_TALENT_RangedEnemies);
ActionUseTalentAtLocation(tUse, GetLocation(oTarget));
return TRUE;
}
}
else
{
tUse = GetCreatureTalent(TALENT_CATEGORY_HARMFUL_AREAEFFECT_DISCRIMINANT,
nCR,TRUE);
if(GetIsTalentValid(tUse))
{
if( (GetTypeFromTalent(tUse) == TALENT_TYPE_SPELL &&
!GetHasSpellEffect(GetIdFromTalent(tUse), oTarget) &&
!CompareLastSpellCast(GetIdFromTalent(tUse)) ) ||
GetTypeFromTalent(tUse) != TALENT_TYPE_SPELL )
{
if( GetTypeFromTalent(tUse) == TALENT_TYPE_SPELL)
{
SetLastGenericSpellCast(GetIdFromTalent(tUse));
}
// DebugPrintTalentID(tUse);
//MyPrintString("TalentRangedEnemies Successful Exit");
bkTalentFilter(tUse, oTarget);
return TRUE;
}
}
}
}
else if(GetDistanceToObject(oTarget) > 5.0)
{
tUse = GetCreatureTalent(TALENT_CATEGORY_HARMFUL_RANGED, nCR,TRUE);
if(GetIsTalentValid(tUse))
{
// * BK: July 2002: Wrapped up harmful ranged into
// * a function to make it easier to make global
// * changes to the decision making process.
if (genericAttemptHarmfulRanged(tUse, oTarget) == TRUE)
{
return TRUE;
}
}
}
}
//MyPrintString("TalentRangedEnemies Failed Exit");
return FALSE;
}
/*
ISSUE 1: The check in this function to use a random ability after failing to use best will fail in the following
case. The creature is unable to affect the target with the spell and has only 1 spell of that type. This can
be eliminated with a check in the else to the effect of :
else if(!CompareLastSpellCast(GetIdFromTalent(tUse)))
This check was not put in in version 1.0 due to time constraints.
May cause an AI loop in some Mages with limited spell selection.
*/
int TalentSpellAttack(object oIntruder)
{
//MyPrintString("Talent Spell Attack Enter");
talent tUse;
object oTarget = oIntruder;
if(!GetIsObjectValid(oTarget) || GetArea(oTarget) != GetArea(OBJECT_SELF) || GetPlotFlag(OBJECT_SELF) == TRUE)
{
oTarget = GetLastHostileActor();
//MyPrintString("Last Hostile Attacker: " + ObjectToString(oTarget));
if(!GetIsObjectValid(oTarget)
|| GetIsDead(oTarget)
|| GetArea(oTarget) != GetArea(OBJECT_SELF)
|| GetPlotFlag(OBJECT_SELF) == TRUE)
{
oTarget = GetNearestSeenEnemy();
//MyPrintString("Get Nearest Seen or Heard: " + ObjectToString(oTarget));
if(!GetIsObjectValid(oTarget))
{
return FALSE;
}
}
}
//Attack chosen target
int bValid = FALSE;
tUse = GetCreatureTalent(TALENT_CATEGORY_HARMFUL_AREAEFFECT_DISCRIMINANT,
40,TRUE);
if (GetIsTalentValid(tUse) == FALSE)
{
//MyPrintString("Discriminant AOE not valid");
//newdebug("Discriminant AOE not valid");
// * November 2002
// * if there are no allies near the target
// * then feel free to grab an indiscriminant spell instead
int nFriends = CheckFriendlyFireOnTarget(oIntruder) ;
if (nFriends <= 1)
{
//newdebug("no friendly fire");
tUse = GetCreatureTalent(TALENT_CATEGORY_HARMFUL_AREAEFFECT_INDISCRIMINANT,
40,TRUE);
}
if (GetIsTalentValid(tUse) == FALSE)
{
//newdebug("SpellAttack: INDiscriminant AOE not valid");
}
}
if(GetIsTalentValid(tUse))
{
if( (GetTypeFromTalent(tUse) == TALENT_TYPE_SPELL
&& !GetHasSpellEffect(GetIdFromTalent(tUse), oTarget)) )
{
//newdebug("Valid talent found AREA OF EFFECT DISCRIMINANT");
//MyPrintString("Spell Attack Discriminate Chosen");
bValid = TRUE;
}
}
if(bValid == FALSE)
{
tUse = GetCreatureTalent(TALENT_CATEGORY_HARMFUL_RANGED,
40,TRUE);
if(GetIsTalentValid(tUse))
{ // SpawnScriptDebugger();
// * BK: July 2002: Wrapped up harmful ranged into
// * a function to make it easier to make global
// * changes to the decision making process.
if (genericAttemptHarmfulRanged(tUse, oTarget) == TRUE)
{
//MyPrintString("Spell Attack Harmful Ranged Chosen");
bValid = FALSE; // * Keep bValid false because we have chosen
// * to actually cast the spell here.
return TRUE;
}
}
}
if(bValid == FALSE)
{
tUse = GetCreatureTalent(TALENT_CATEGORY_HARMFUL_TOUCH,
40,TRUE);
if(GetIsTalentValid(tUse))
{
if( (GetTypeFromTalent(tUse) == TALENT_TYPE_SPELL
&& !GetHasSpellEffect(GetIdFromTalent(tUse), oTarget)) )
{
//MyPrintString("Spell Attack Harmful Ranged Chosen");
bValid = TRUE;
}
}
}
if (bValid == TRUE)
{
if( GetTypeFromTalent(tUse) == TALENT_TYPE_SPELL)
{
SetLastGenericSpellCast(GetIdFromTalent(tUse));
}
// DebugPrintTalentID(tUse);
//MyPrintString("Talent Spell Attack Successful Exit");
// Use a final filter to avoid problems
if (bkTalentFilter(tUse, oTarget) == TRUE)
return TRUE;
}
//MyPrintString("Talent Spell Attack Failed Exit");
/* JULY 2003
At this point grab a random spell attack to use, not just "best"
*/
//SpawnScriptDebugger();
tUse = GetCreatureTalentRandom(TALENT_CATEGORY_HARMFUL_AREAEFFECT_DISCRIMINANT);
if (GetIsTalentValid(tUse) == FALSE || bkTalentFilter(tUse, oTarget, TRUE)==FALSE)
{
tUse = GetCreatureTalentRandom(TALENT_CATEGORY_HARMFUL_RANGED);
}
if (GetIsTalentValid(tUse) == FALSE || bkTalentFilter(tUse, oTarget, TRUE)==FALSE)
{
tUse = GetCreatureTalentRandom(TALENT_CATEGORY_HARMFUL_AREAEFFECT_INDISCRIMINANT);
}
if (GetIsTalentValid(tUse) == FALSE || bkTalentFilter(tUse, oTarget, TRUE)==FALSE)
{
tUse = GetCreatureTalentRandom(TALENT_CATEGORY_HARMFUL_TOUCH);
}
// * if something was valid, attempt to use that something intelligently
if (GetIsTalentValid(tUse) == TRUE)
{
if (!GetHasSpellEffect(GetIdFromTalent(tUse), oTarget))
{
// * so far, so good
// Use a final filter to avoid problems
if (bkTalentFilter(tUse, oTarget) == TRUE)
return TRUE;
}
}
/* End July 11 Mods BK */
return FALSE;
}
// SUMMON ALLIES
int TalentSummonAllies()
{
if(GetIsObjectValid(GetAssociate(ASSOCIATE_TYPE_SUMMONED)))
{
return FALSE;
}
//MyPrintString("TalentSummonAllies Enter");
talent tUse;
int nCR = 40;
object oTarget;
location lSelf;
if(!GetIsObjectValid(GetAssociate(ASSOCIATE_TYPE_SUMMONED)))
{
tUse = GetCreatureTalent(TALENT_CATEGORY_BENEFICIAL_OBTAIN_ALLIES, 40);
if(GetIsTalentValid(tUse))
{
oTarget = FindSingleRangedTarget();
if(GetIsObjectValid(oTarget))
{
vector vTarget = GetPosition(oTarget);
vector vSource = GetPosition(OBJECT_SELF);
vector vDirection = vTarget - vSource;
float fDistance = VectorMagnitude(vDirection) / 2.0f;
vector vPoint = VectorNormalize(vDirection) * fDistance + vSource;
lSelf = Location(GetArea(OBJECT_SELF), vPoint, GetFacing(OBJECT_SELF));
//lSelf = GetLocation(oTarget);
}
else
{
lSelf = GetLocation(OBJECT_SELF);
}
ClearActions(CLEAR_X0_I0_TALENT_SummonAllies);
//This is for henchmen wizards, so they do no run off and get killed
//summoning in allies.
if(GetIsObjectValid(GetMaster()))
{
//MyPrintString("TalentSummonAllies Successful Exit");
ActionUseTalentAtLocation(tUse, GetLocation(GetMaster()));
}
else
{
//MyPrintString("TalentSummonAllies Successful Exit");
ActionUseTalentAtLocation(tUse, lSelf);
}
return TRUE;
}
// else
//MyPrintString("No valid Talent for summoning Allies with Difficulty " + IntToString(GetLocalInt(OBJECT_SELF,"NW_L_COMBATDIFF")));
}
//MyPrintString("TalentSummonAllies Failed Exit");
return FALSE;
}
// HEAL SELF WITH POTIONS AND SPELLS
// * July 14 2003: If bForce=TRUE then force a heal
int TalentHealUndead(object oTarget = OBJECT_SELF)
{
// Mob will attempt to use the harm spell to heal undead
// creatures including itself
// Creatures need the healundead int to do this
int nHeals=GetLocalInt(OBJECT_SELF,"healundead");
if (nHeals<1)
{
//SpeakString("don't have any undead heals");
return FALSE;
}
// Heal self first
int nCurrent = GetCurrentHitPoints(OBJECT_SELF) * 2;
int nBase = GetMaxHitPoints(OBJECT_SELF);
if((nCurrent < nBase)&&(GetRacialType(OBJECT_SELF)==RACIAL_TYPE_UNDEAD))
{
//SpeakString("attempting to heal self");
ActionCastSpellAtObject(SPELL_HARM,OBJECT_SELF,METAMAGIC_ANY,TRUE);
SetLocalInt(OBJECT_SELF,"healundead",nHeals-1);
return TRUE;
}
// Check for undead allies
oTarget = GetNearestCreature(CREATURE_TYPE_REPUTATION, REPUTATION_TYPE_FRIEND,OBJECT_SELF,1,CREATURE_TYPE_RACIAL_TYPE,RACIAL_TYPE_UNDEAD);
int i = 0;
while (GetIsObjectValid(oTarget))
{
nCurrent = GetCurrentHitPoints(oTarget)*2;
nBase = GetMaxHitPoints(oTarget);
if(nCurrent < nBase && !GetIsDead(oTarget))
{
//SpeakString("attempting to heal others");
ActionCastSpellAtObject(SPELL_HARM,oTarget,METAMAGIC_ANY,TRUE);
SetLocalInt(OBJECT_SELF,"healundead",nHeals-1);
return TRUE;
}
i++;
oTarget = GetNearestCreature(CREATURE_TYPE_REPUTATION, REPUTATION_TYPE_FRIEND,OBJECT_SELF,i,CREATURE_TYPE_RACIAL_TYPE,RACIAL_TYPE_UNDEAD);
}
//SpeakString("found nobody to heal");
return FALSE;
}
// HEAL SELF WITH POTIONS AND SPELLS
int TalentHealingSelf(int bForce = FALSE)
{
if ((GetRacialType(OBJECT_SELF)==RACIAL_TYPE_UNDEAD)||(GetRacialType(OBJECT_SELF)==RACIAL_TYPE_ANIMAL)||(GetRacialType(OBJECT_SELF)==RACIAL_TYPE_VERMIN))
{
return FALSE;
}
MyPrintString("GENERIC SCRIPT DEBUG STRING ********** " + "TalentHealingSelf Enter");
talent tUse;
int nCurrent = GetCurrentHitPoints(OBJECT_SELF) * 2;
int nBase = GetMaxHitPoints(OBJECT_SELF);
if(nCurrent < nBase)
{
tUse = GetCreatureTalentRandom(TALENT_CATEGORY_BENEFICIAL_HEALING_TOUCH);
if(GetIsTalentValid(tUse))
{
MyPrintString("GENERIC SCRIPT DEBUG STRING ********** " + "TalentHealingSelf Successful Exit");
ClearAllActions();
ActionUseTalentOnObject(tUse, OBJECT_SELF);
return TRUE;
}
else
{
tUse = GetCreatureTalentRandom(TALENT_CATEGORY_BENEFICIAL_HEALING_POTION);
if(GetIsTalentValid(tUse))
{
MyPrintString("GENERIC SCRIPT DEBUG STRING ********** " + "TalentHealingSelf Successful Exit");
ClearAllActions();
ActionUseTalentOnObject(tUse, OBJECT_SELF);
return TRUE;
}
else
// Palmer - added in mass heal spells
if (GetHasSpell(SPELL_MASS_HEAL))
{
ActionCastSpellAtObject(SPELL_MASS_HEAL,OBJECT_SELF);
return TRUE;
}
else
if (GetHasSpell(SPELL_HEALING_CIRCLE))
{
ActionCastSpellAtObject(SPELL_HEALING_CIRCLE,OBJECT_SELF);
return TRUE;
}
}
}
MyPrintString("GENERIC SCRIPT DEBUG STRING ********** " + "TalentHealingSelf Failed Exit");
return FALSE;
}
// HEAL ALL ALLIES
// BK: Added an optional parameter for object.
int TalentHeal(int nForce = FALSE, object oTarget = OBJECT_SELF)
{
//MyPrintString("TalentHeal Enter");
talent tUse;
int nCurrent = GetCurrentHitPoints(oTarget);
if (nForce == TRUE)
nCurrent = nCurrent;
else
nCurrent = GetCurrentHitPoints(oTarget)*2;
int nBase = GetMaxHitPoints(oTarget);
int nCR;
tUse = GetCreatureTalent(TALENT_CATEGORY_BENEFICIAL_HEALING_TOUCH, 40);
/***************REMOVED**********************
// * New henchmen scripts will be calling this directly
// * in the determine combat round.
// * redundant.
if(GetAssociateHealMaster() || nForce == TRUE)
{
tUse = GetCreatureTalentBest(TALENT_CATEGORY_BENEFICIAL_HEALING_TOUCH, TALENT_ANY);
if(GetIsTalentValid(tUse) && !GetIsDead(GetMaster()))
{
//MyPrintString("TalentHeal Successful Exit");
return TRUE;
}
}
*/
int bValid = GetIsTalentValid(tUse);
// * BK: force a heal
if (bValid && oTarget != OBJECT_SELF && GetCurrentHitPoints(oTarget) < nBase)
{
bkTalentFilter(tUse, oTarget);
//MyPrintString("TalentHeal (MASTER) Successful Exit");
return TRUE;
}
// * Heal self
if(nCurrent < nBase)
{
if(GetRacialType(oTarget) == RACIAL_TYPE_UNDEAD)
{
//MyPrintString("TalentHeal Failed Exit");
return FALSE;
}
tUse = GetCreatureTalent(TALENT_CATEGORY_BENEFICIAL_HEALING_TOUCH, 40);
if(GetIsTalentValid(tUse))
{
//MyPrintString("TalentHeal Successful Exit");
bkTalentFilter(tUse, oTarget);
return TRUE;
}
}
// * change target
// * find nearest friend to heal.
oTarget = GetNearestCreature(CREATURE_TYPE_REPUTATION, REPUTATION_TYPE_FRIEND);
int i = 0;
while (GetIsObjectValid(oTarget))
{
if(GetRacialType(oTarget) == RACIAL_TYPE_UNDEAD)
{
//MyPrintString("TalentHeal Failed Exit");
}
else
{
if (nForce == TRUE)
nCurrent = GetCurrentHitPoints(oTarget);
else
nCurrent = GetCurrentHitPoints(oTarget)*2;
nBase = GetMaxHitPoints(oTarget);
if(nCurrent < nBase && !GetIsDead(oTarget))
{
tUse = GetCreatureTalent(TALENT_CATEGORY_BENEFICIAL_HEALING_TOUCH, 40);
// Palmer - added in mass heal spells
if (GetHasSpell(SPELL_MASS_HEAL))
{
ActionCastSpellAtObject(SPELL_MASS_HEAL,oTarget);
return TRUE;
}
else
if (GetHasSpell(SPELL_HEALING_CIRCLE))
{
ActionCastSpellAtObject(SPELL_HEALING_CIRCLE,oTarget);
return TRUE;
}
else
if(GetIsTalentValid(tUse))
{
//MyPrintString("TalentHeal Successful Exit");
bkTalentFilter(tUse, oTarget);
return TRUE;
}
}
}
i++;
oTarget = GetNearestCreature(CREATURE_TYPE_REPUTATION, REPUTATION_TYPE_FRIEND, OBJECT_SELF, i);
}
//MyPrintString("TalentHeal Failed Exit");
return FALSE;
}
// MELEE ATTACK OTHERS
/*
ISSUE 1: Talent Melee Attack should set the Last Spell Used to 0 so that melee casters can use
a single special ability.
*/
int WhirlwindGetNumberOfMeleeAttackers(float fDist=5.0)
{
object oOne = GetNearestEnemy(OBJECT_SELF, 1);
if (GetIsObjectValid(oOne) == TRUE)
{
object oTwo = GetNearestEnemy(OBJECT_SELF, 2);
if (GetDistanceToObject(oOne) <= fDist && GetIsObjectValid(oTwo) == TRUE)
{
if (GetDistanceToObject(oTwo) <= fDist)
{
// * DO NOT WHIRLWIND if any of the targets are "large" or bigger
// * it seldom works against such large opponents.
// * Though its okay to use Improved Whirlwind against these targets
// * October 13 - Brent
if (GetHasFeat(FEAT_IMPROVED_WHIRLWIND))
{
return TRUE;
}
else
if (GetCreatureSize(oOne) < CREATURE_SIZE_LARGE && GetCreatureSize(oTwo) < CREATURE_SIZE_LARGE)
{
return TRUE;
}
return FALSE;
}
}
}
return FALSE;
}
// * Returns true if the creature's variable
// * set on it rolled against a d100
// * says it is okay to whirlwind.
// * Added this because it got silly to see creatures
// * constantly whirlwinded
int GetOKToWhirl(object oCreature)
{
// Creatures whirlwind one in 4
int nWhirl = 25;
if (nWhirl == 0 || nWhirl == 100)
{
return TRUE; // 0 or 100 is 100%
}
else
{
if (Random(100) + 1 <= nWhirl)
{
return TRUE;
}
}
return FALSE;
}
int UseRangedFeats (object oIntruder)
{
// Palmer - added in use ranged feats
if (!GetIsWieldingRanged(OBJECT_SELF))
{
return FALSE;
}
if (GetHasFeat(FEAT_CALLED_SHOT,OBJECT_SELF)&&(d2()==1))
{
ActionUseFeat(FEAT_CALLED_SHOT,oIntruder);
return TRUE;
}
else
if (GetHasFeat(FEAT_PRESTIGE_HAIL_OF_ARROWS,OBJECT_SELF)&&(d2()==1))
{
ActionUseFeat(FEAT_PRESTIGE_HAIL_OF_ARROWS,oIntruder);
return TRUE;
}
return FALSE;
}
int TalentMeleeAttack(object oIntruder = OBJECT_INVALID)
{
//MyPrintString("GENERIC SCRIPT DEBUG STRING ********** " + "TalentMeleeAttack Enter");
//MyPrintString("GENERIC SCRIPT DEBUG STRING ********** " + "Intruder: " + ObjectToString(oIntruder));
object oTarget = oIntruder;
if(!GetIsObjectValid(oTarget) || GetArea(oTarget) != GetArea(OBJECT_SELF))
{
oTarget = GetAttemptedAttackTarget();
//MyPrintString("GENERIC SCRIPT DEBUG STRING ********** " + "Attempted Attack Target: " + ObjectToString(oTarget));
if(!GetIsObjectValid(oTarget) || GetIsDead(oTarget) ||
(!GetObjectSeen(oTarget) && !GetObjectHeard(oTarget))
|| GetArea(oTarget) != GetArea(OBJECT_SELF))
{
oTarget = GetLastHostileActor();
MyPrintString("GENERIC SCRIPT DEBUG STRING ********** " + "Last Attacker: " + ObjectToString(oTarget));
if(!GetIsObjectValid(oTarget)
|| GetIsDead(oTarget)
|| GetArea(oTarget) != GetArea(OBJECT_SELF))
{
oTarget = GetNearestPerceivedEnemy();
//MyPrintString("GENERIC SCRIPT DEBUG STRING ********** " + "Get Nearest Seen or Heard: " + ObjectToString(oTarget));
if(!GetIsObjectValid(oTarget))
{
return FALSE;
}
}
}
}
else
{
//MyPrintString("GENERIC SCRIPT DEBUG STRING ********** " + "My Target is valid off of oIntruder");
}
//MyPrintString("GENERIC SCRIPT DEBUG STRING ********** " + "Selected Target: " + ObjectToString(oTarget));
talent tUse;
int nAC = GetAC(oTarget);
float fAttack;
int nAttack = GetHitDice(OBJECT_SELF);
fAttack = (IntToFloat(nAttack) * 0.75) + IntToFloat(GetAbilityModifier(ABILITY_STRENGTH));
//fAttack = IntToFloat(nAttack) + GetAbilityModifier(ABILITY_STRENGTH);
int nDiff = nAC - nAttack;
//MyPrintString("GENERIC SCRIPT DEBUG STRING ********** " + "nDiff = " + IntToString(nDiff));
// * only the playable races have whirlwind attack
// * Attempt to Use Whirlwind Attack
int bOkToWhirl = GetOKToWhirl(OBJECT_SELF);
int bHasFeat = GetHasFeat(FEAT_WHIRLWIND_ATTACK);
int jwHasImpFeat = GetHasFeat(FEAT_IMPROVED_WHIRLWIND);
int bNumberofAttackers = WhirlwindGetNumberOfMeleeAttackers();
// Palmer - added in improved whirlwind
if (bOkToWhirl == TRUE && jwHasImpFeat == TRUE
&& bNumberofAttackers == TRUE)
{
ClearActions(CLEAR_X0_I0_TALENT_MeleeAttack1);
ActionUseFeat(FEAT_IMPROVED_WHIRLWIND, OBJECT_SELF);
return TRUE;
}
else
if (bOkToWhirl == TRUE && bHasFeat == TRUE
&& bNumberofAttackers == TRUE)
{
ClearActions(CLEAR_X0_I0_TALENT_MeleeAttack1);
ActionUseFeat(FEAT_WHIRLWIND_ATTACK, OBJECT_SELF);
return TRUE;
}
else
// * Try using expertise
if (GetHasFeat(FEAT_EXPERTISE) && nDiff < 12)
{
ClearActions(CLEAR_X0_I0_TALENT_MeleeAttack1);
SetActionMode(OBJECT_SELF, ACTION_MODE_EXPERTISE, TRUE);
ClearAllActions();
EquipAppropriateWeapons(oTarget);
ActionAttack(oTarget);
return TRUE;
}
else
// * Try using expertise
if (GetHasFeat(FEAT_IMPROVED_EXPERTISE) && nDiff < 15)
{
ClearActions(CLEAR_X0_I0_TALENT_MeleeAttack1);
SetActionMode(OBJECT_SELF, ACTION_MODE_IMPROVED_EXPERTISE, TRUE);
ClearAllActions();
EquipAppropriateWeapons(oTarget);
ActionAttack(oTarget);
return TRUE;
}
else
if(nDiff < 10)
{
ClearAllActions();
EquipAppropriateWeapons(oTarget);
if (UseRangedFeats(oTarget))
{
return TRUE;
}
tUse = GetCreatureTalentRandom(TALENT_CATEGORY_HARMFUL_MELEE);
//MyPrintString("GENERIC SCRIPT DEBUG STRING ********** " + "Melee Talent Valid = " + IntToString(GetIsTalentValid(tUse)));
//MyPrintString("GENERIC SCRIPT DEBUG STRING ********** " + "Feat ID = " + IntToString(GetIdFromTalent(tUse)));
if(GetIsTalentValid(tUse) && VerifyDisarm(tUse, oTarget) && VerifyCombatMeleeTalent(tUse, oTarget))
{
//MyPrintString("GENERIC SCRIPT DEBUG STRING ********** " + "TalentMeleeAttack: Talent Use Successful");
ActionUseTalentOnObject(tUse, oTarget);
return TRUE;
}
else
{
//MyPrintString("GENERIC SCRIPT DEBUG STRING ********** " + "TalentMeleeAttack Successful Exit");
ActionAttack(oTarget);
return TRUE;
}
}
else
{
//MyPrintString("GENERIC SCRIPT DEBUG STRING ********** " + "TalentMeleeAttack Successful Exit");
ClearAllActions();
EquipAppropriateWeapons(oTarget);
ActionAttack(oTarget);
return TRUE;
}
//MyPrintString("GENERIC SCRIPT DEBUG STRING ********** " + "TALENT MELEE ATTACK FAILURE EXIT - THIS IS VERY BAD");
return FALSE;
}
// SNEAK ATTACK OTHERS
int TalentSneakAttack()
{
//MyPrintString("TalentSneakAttack Enter");
if(GetHasFeat(FEAT_SNEAK_ATTACK))
{
object oFriend = GetNearestSeenFriend();
if (GetIsObjectValid(oFriend)) {
object oTarget = GetLastHostileActor(oFriend);
if(GetIsObjectValid(oTarget)
&& !GetIsDead(oTarget)
&& !GetAssociateState(NW_ASC_MODE_DYING, oTarget)) {
//MyPrintString("TalentSneakAttack Successful Exit");
TalentMeleeAttack(oTarget);
return TRUE;
}
}
}
//MyPrintString("TalentSneakAttack Failed Exit");
return FALSE;
}
// FLEE COMBAT AND HOSTILES
int TalentFlee(object oIntruder = OBJECT_INVALID)
{
//MyPrintString("TalentFlee Enter");
object oTarget = oIntruder;
if(!GetIsObjectValid(oIntruder))
{
oTarget = GetLastHostileActor();
if(!GetIsObjectValid(oTarget) || GetIsDead(oTarget))
{
oTarget = GetNearestSeenEnemy();
float fDist = GetDistanceBetween(OBJECT_SELF, oTarget);
if(!GetIsObjectValid(oTarget))
{
//MyPrintString("TalentFlee Failed Exit");
return FALSE;
}
}
}
//MyPrintString("TalentFlee Successful Exit");
ClearActions(CLEAR_X0_I0_TALENT_TalentFlee);
//Look at this to remove the delay
ActionMoveAwayFromObject(oTarget, TRUE, 10.0f);
DelayCommand(4.0, ClearActions(CLEAR_X0_I0_TALENT_TalentFlee2));
return TRUE;
}
// TURN UNDEAD
int TalentUseTurning()
{
//MyPrintString("TalentUseTurning Enter");
int nCount;
if(GetHasFeat(FEAT_TURN_UNDEAD))
{
object oUndead = GetNearestPerceivedEnemy();
int nHD = GetHitDice(oUndead);
if(PRCGetHasEffect(EFFECT_TYPE_TURNED, oUndead)
|| GetHitDice(OBJECT_SELF) <= nHD)
{
return FALSE;
}
int nElemental = GetHasFeat(FEAT_AIR_DOMAIN_POWER)
+ GetHasFeat(FEAT_EARTH_DOMAIN_POWER)
+ GetHasFeat(FEAT_FIRE_DOMAIN_POWER)
+ GetHasFeat(FEAT_FIRE_DOMAIN_POWER);
int nVermin = GetHasFeat(FEAT_PLANT_DOMAIN_POWER)
+ GetHasFeat(FEAT_ANIMAL_COMPANION);
int nConstructs = GetHasFeat(FEAT_DESTRUCTION_DOMAIN_POWER);
int nOutsider = GetHasFeat(FEAT_GOOD_DOMAIN_POWER)
+ GetHasFeat(FEAT_EVIL_DOMAIN_POWER)
+ GetHasFeat(854); // planar turning
if(nElemental == TRUE)
nCount += GetRacialTypeCount(RACIAL_TYPE_ELEMENTAL);
if(nVermin == TRUE)
nCount += GetRacialTypeCount(RACIAL_TYPE_VERMIN);
if(nOutsider == TRUE)
nCount += GetRacialTypeCount(RACIAL_TYPE_OUTSIDER);
if(nConstructs == TRUE)
nCount += GetRacialTypeCount(RACIAL_TYPE_CONSTRUCT);
nCount += GetRacialTypeCount(RACIAL_TYPE_UNDEAD);
if(nCount > 0)
{
//MyPrintString("TalentUseTurning Successful Exit");
ClearActions(CLEAR_X0_I0_TALENT_UseTurning);
//ActionCastSpellAtObject(SPELLABILITY_TURN_UNDEAD, OBJECT_SELF);
ActionUseFeat(FEAT_TURN_UNDEAD, OBJECT_SELF);
return TRUE;
}
}
//MyPrintString("TalentUseTurning Failed Exit");
return FALSE;
}
// ACTIVATE AURAS
int TalentPersistentAbilities()
{
//MyPrintString("TalentPersistentAbilities Enter");
talent tUse = GetCreatureTalent(TALENT_CATEGORY_PERSISTENT_AREA_OF_EFFECT, 40);
int nSpellID;
if(GetIsTalentValid(tUse))
{
nSpellID = GetIdFromTalent(tUse);
if(!GetHasSpellEffect(nSpellID))
{
//MyPrintString("TalentPersistentAbilities Successful Exit");
bkTalentFilter(tUse, OBJECT_SELF);
return TRUE;
}
}
//MyPrintString("TalentPersistentAbilities Failed Exit");
return FALSE;
}
// FAST BUFF SELF
// * Dec 19 2002: Added the instant parameter so this could be used for 'legal' spellcasting as well
int TalentAdvancedBuff(float fDistance, int bInstant = TRUE)
{
//MyPrintString("TalentAdvancedBuff Enter");
object oPC = GetNearestCreature(CREATURE_TYPE_PLAYER_CHAR, PLAYER_CHAR_IS_PC, OBJECT_SELF, 1, CREATURE_TYPE_REPUTATION, REPUTATION_TYPE_ENEMY);
if(GetIsObjectValid(oPC))
{
if(GetDistanceToObject(oPC) <= fDistance)
{
if(!GetIsFighting(OBJECT_SELF))
{
ClearActions(CLEAR_X0_I0_TALENT_AdvancedBuff);
//Combat Protections
if(GetHasSpell(SPELL_PREMONITION) && !GetHasSpellEffect(SPELL_PREMONITION))
{
ActionCastSpellAtObject(SPELL_PREMONITION, OBJECT_SELF, METAMAGIC_NONE, FALSE, 0, PROJECTILE_PATH_TYPE_DEFAULT, bInstant);
}
else if(GetHasSpell(SPELL_GREATER_STONESKIN)&& !GetHasSpellEffect(SPELL_GREATER_STONESKIN))
{
ActionCastSpellAtObject(SPELL_GREATER_STONESKIN, OBJECT_SELF, METAMAGIC_NONE, 0, FALSE, PROJECTILE_PATH_TYPE_DEFAULT, bInstant);
}
else if(GetHasSpell(SPELL_STONESKIN)&& !GetHasSpellEffect(SPELL_STONESKIN))
{
ActionCastSpellAtObject(SPELL_STONESKIN, OBJECT_SELF, METAMAGIC_NONE, FALSE, 0, PROJECTILE_PATH_TYPE_DEFAULT, bInstant);
}
//Visage Protections
if(GetHasSpell(SPELL_SHADOW_SHIELD)&& !GetHasSpellEffect(SPELL_SHADOW_SHIELD))
{
ActionCastSpellAtObject(SPELL_SHADOW_SHIELD, OBJECT_SELF, METAMAGIC_NONE, FALSE, 0, PROJECTILE_PATH_TYPE_DEFAULT, bInstant);
}
else if(GetHasSpell(SPELL_ETHEREAL_VISAGE)&& !GetHasSpellEffect(SPELL_ETHEREAL_VISAGE))
{
ActionCastSpellAtObject(SPELL_ETHEREAL_VISAGE, OBJECT_SELF, METAMAGIC_NONE, FALSE, 0, PROJECTILE_PATH_TYPE_DEFAULT, bInstant);
}
else if(GetHasSpell(SPELL_GHOSTLY_VISAGE)&& !GetHasSpellEffect(SPELL_GHOSTLY_VISAGE))
{
ActionCastSpellAtObject(SPELL_GHOSTLY_VISAGE, OBJECT_SELF, METAMAGIC_NONE, FALSE, 0, PROJECTILE_PATH_TYPE_DEFAULT, bInstant);
}
//Mantle Protections
if(GetHasSpell(SPELL_GREATER_SPELL_MANTLE)&& !GetHasSpellEffect(SPELL_GREATER_SPELL_MANTLE))
{
ActionCastSpellAtObject(SPELL_GREATER_SPELL_MANTLE, OBJECT_SELF, METAMAGIC_NONE, FALSE, 0, PROJECTILE_PATH_TYPE_DEFAULT, bInstant);
}
else if(GetHasSpell(SPELL_SPELL_MANTLE)&& !GetHasSpellEffect(SPELL_SPELL_MANTLE))
{
ActionCastSpellAtObject(SPELL_SPELL_MANTLE, OBJECT_SELF, METAMAGIC_NONE, FALSE, 0, PROJECTILE_PATH_TYPE_DEFAULT, bInstant);
}
else if(GetHasSpell(SPELL_LESSER_SPELL_BREACH)&& !GetHasSpellEffect(SPELL_LESSER_SPELL_BREACH))
{
ActionCastSpellAtObject(SPELL_LESSER_SPELL_BREACH, OBJECT_SELF, METAMAGIC_NONE, FALSE, 0, PROJECTILE_PATH_TYPE_DEFAULT, bInstant);
}
// Globes
if(GetHasSpell(SPELL_GLOBE_OF_INVULNERABILITY)&& !GetHasSpellEffect(SPELL_GLOBE_OF_INVULNERABILITY))
{
ActionCastSpellAtObject(SPELL_GLOBE_OF_INVULNERABILITY, OBJECT_SELF, METAMAGIC_NONE, FALSE, 0, PROJECTILE_PATH_TYPE_DEFAULT, bInstant);
}
else if(GetHasSpell(SPELL_MINOR_GLOBE_OF_INVULNERABILITY)&& !GetHasSpellEffect(SPELL_MINOR_GLOBE_OF_INVULNERABILITY))
{
ActionCastSpellAtObject(SPELL_MINOR_GLOBE_OF_INVULNERABILITY, OBJECT_SELF, METAMAGIC_NONE, FALSE, 0, PROJECTILE_PATH_TYPE_DEFAULT, bInstant);
}
//Misc Protections
if(GetHasSpell(SPELL_ELEMENTAL_SHIELD)&& !GetHasSpellEffect(SPELL_ELEMENTAL_SHIELD))
{
ActionCastSpellAtObject(SPELL_ELEMENTAL_SHIELD, OBJECT_SELF, METAMAGIC_NONE, FALSE, 0, PROJECTILE_PATH_TYPE_DEFAULT, bInstant);
}
else if (GetHasSpell(SPELL_MESTILS_ACID_SHEATH)&& !GetHasSpellEffect(SPELL_MESTILS_ACID_SHEATH))
{
ActionCastSpellAtObject(SPELL_MESTILS_ACID_SHEATH, OBJECT_SELF, METAMAGIC_NONE, FALSE, 0, PROJECTILE_PATH_TYPE_DEFAULT, bInstant);
}
else if (GetHasSpell(SPELL_DEATH_ARMOR)&& !GetHasSpellEffect(SPELL_DEATH_ARMOR))
{
ActionCastSpellAtObject(SPELL_DEATH_ARMOR, OBJECT_SELF, METAMAGIC_NONE, FALSE, 0, PROJECTILE_PATH_TYPE_DEFAULT, bInstant);
}
//Elemental Protections
if(GetHasSpell(SPELL_PROTECTION_FROM_ELEMENTS)&& !GetHasSpellEffect(SPELL_PROTECTION_FROM_ELEMENTS))
{
ActionCastSpellAtObject(SPELL_PROTECTION_FROM_ELEMENTS, OBJECT_SELF, METAMAGIC_NONE, FALSE, 0, PROJECTILE_PATH_TYPE_DEFAULT, bInstant);
}
else if(GetHasSpell(SPELL_RESIST_ELEMENTS)&& !GetHasSpellEffect(SPELL_RESIST_ELEMENTS))
{
ActionCastSpellAtObject(SPELL_RESIST_ELEMENTS, OBJECT_SELF, METAMAGIC_NONE, FALSE, 0, PROJECTILE_PATH_TYPE_DEFAULT, bInstant);
}
else if(GetHasSpell(SPELL_ENDURE_ELEMENTS)&& !GetHasSpellEffect(SPELL_ENDURE_ELEMENTS))
{
ActionCastSpellAtObject(SPELL_ENDURE_ELEMENTS, OBJECT_SELF, METAMAGIC_NONE, FALSE, 0, PROJECTILE_PATH_TYPE_DEFAULT, bInstant);
}
//Mental Protections
if(GetHasSpell(SPELL_MIND_BLANK)&& !GetHasSpellEffect(SPELL_MIND_BLANK))
{
ActionCastSpellAtObject(SPELL_MIND_BLANK, OBJECT_SELF, METAMAGIC_NONE, FALSE, 0, PROJECTILE_PATH_TYPE_DEFAULT, bInstant);
}
else if(GetHasSpell(SPELL_LESSER_MIND_BLANK)&& !GetHasSpellEffect(SPELL_LESSER_MIND_BLANK))
{
ActionCastSpellAtObject(SPELL_LESSER_MIND_BLANK, OBJECT_SELF, METAMAGIC_NONE, FALSE, 0, PROJECTILE_PATH_TYPE_DEFAULT, bInstant);
}
else if(GetHasSpell(SPELL_CLARITY)&& !GetHasSpellEffect(SPELL_CLARITY))
{
ActionCastSpellAtObject(SPELL_CLARITY, OBJECT_SELF, METAMAGIC_NONE, FALSE, 0, PROJECTILE_PATH_TYPE_DEFAULT, bInstant);
}
//Summon Ally
if(GetHasSpell(SPELL_BLACK_BLADE_OF_DISASTER))
{
ActionCastSpellAtLocation(SPELL_BLACK_BLADE_OF_DISASTER, GetLocation(OBJECT_SELF), METAMAGIC_NONE, FALSE, PROJECTILE_PATH_TYPE_DEFAULT, bInstant);
}
else if(GetHasSpell(SPELL_SUMMON_CREATURE_IX))
{
ActionCastSpellAtLocation(SPELL_SUMMON_CREATURE_IX, GetLocation(OBJECT_SELF), METAMAGIC_NONE, FALSE, PROJECTILE_PATH_TYPE_DEFAULT, bInstant);
}
else if(GetHasSpell(SPELL_SUMMON_CREATURE_VIII))
{
ActionCastSpellAtLocation(SPELL_SUMMON_CREATURE_VIII, GetLocation(OBJECT_SELF), METAMAGIC_NONE, FALSE, PROJECTILE_PATH_TYPE_DEFAULT, bInstant);
}
else if(GetHasSpell(SPELL_SUMMON_CREATURE_VII))
{
ActionCastSpellAtLocation(SPELL_SUMMON_CREATURE_VII, GetLocation(OBJECT_SELF), METAMAGIC_NONE, FALSE, PROJECTILE_PATH_TYPE_DEFAULT, bInstant);
}
else if(GetHasSpell(SPELL_SUMMON_CREATURE_VI))
{
ActionCastSpellAtLocation(SPELL_SUMMON_CREATURE_VI, GetLocation(OBJECT_SELF), METAMAGIC_NONE, FALSE, PROJECTILE_PATH_TYPE_DEFAULT, bInstant);
}
else if(GetHasSpell(SPELL_SUMMON_CREATURE_V))
{
ActionCastSpellAtLocation(SPELL_SUMMON_CREATURE_V, GetLocation(OBJECT_SELF), METAMAGIC_NONE, FALSE, PROJECTILE_PATH_TYPE_DEFAULT, bInstant);
}
else if(GetHasSpell(SPELL_SUMMON_CREATURE_IV))
{
ActionCastSpellAtLocation(SPELL_SUMMON_CREATURE_IV, GetLocation(OBJECT_SELF), METAMAGIC_NONE, FALSE, PROJECTILE_PATH_TYPE_DEFAULT, bInstant);
}
else if(GetHasSpell(SPELL_SUMMON_CREATURE_III))
{
ActionCastSpellAtLocation(SPELL_SUMMON_CREATURE_III, GetLocation(OBJECT_SELF), METAMAGIC_NONE, FALSE, PROJECTILE_PATH_TYPE_DEFAULT, bInstant);
}
else if(GetHasSpell(SPELL_SUMMON_CREATURE_II))
{
ActionCastSpellAtLocation(SPELL_SUMMON_CREATURE_II, GetLocation(OBJECT_SELF), METAMAGIC_NONE, FALSE, PROJECTILE_PATH_TYPE_DEFAULT, bInstant);
}
else if(GetHasSpell(SPELL_SUMMON_CREATURE_I))
{
ActionCastSpellAtLocation(SPELL_SUMMON_CREATURE_I, GetLocation(OBJECT_SELF), METAMAGIC_NONE, FALSE, PROJECTILE_PATH_TYPE_DEFAULT, bInstant);
}
//MyPrintString("TalentAdvancedBuff Successful Exit");
return TRUE;
}
}
}
//MyPrintString("TalentAdvancedBuff Failed Exit");
return FALSE;
}
// USE POTIONS
int TalentBuffSelf()
{
//MyPrintString("TalentBuffSelf Enter");
talent tUse;
int nType;
int bValid = FALSE;
int nIndex;
tUse = GetCreatureTalent(TALENT_CATEGORY_BENEFICIAL_PROTECTION_POTION,
40);
if(!GetIsTalentValid(tUse)) {
tUse = GetCreatureTalent(TALENT_CATEGORY_BENEFICIAL_ENHANCEMENT_POTION,
40);
if(!GetIsTalentValid(tUse))
return FALSE;
}
nType = GetTypeFromTalent(tUse);
nIndex = GetIdFromTalent(tUse);
if(nType == TALENT_TYPE_SPELL && !GetHasSpellEffect(nIndex)) {
//MyPrintString("TalentBuffSelf Successful Exit");
bkTalentFilter(tUse, OBJECT_SELF);
return TRUE;
}
//MyPrintString("TalentBuffSelf Failed Exit");
return FALSE;
}
// USE SPELLS TO DEFEAT INVISIBLE CREATURES
// THIS TALENT IS NOT USED
int TalentSeeInvisible()
{
//MyPrintString("TalentSeeInvisible Enter");
int nSpell;
int bValid = FALSE;
if(GetHasSpell(SPELL_TRUE_SEEING))
{
nSpell = SPELL_TRUE_SEEING;
bValid = TRUE;
}
else if(GetHasSpell(SPELL_INVISIBILITY_PURGE))
{
nSpell = SPELL_INVISIBILITY_PURGE;
bValid = TRUE;
}
else if(GetHasSpell(SPELL_SEE_INVISIBILITY))
{
nSpell = SPELL_SEE_INVISIBILITY;
bValid = TRUE;
}
else if(GetHasSpell(SPELL_CLAIRAUDIENCE_AND_CLAIRVOYANCE))
{
nSpell = SPELL_CLAIRAUDIENCE_AND_CLAIRVOYANCE;
bValid = TRUE;
}
if(bValid == TRUE)
{
//MyPrintString("TalentSeeInvisible Successful Exit");
ClearActions(CLEAR_X0_I0_TALENT_SeeInvisible);
ActionCastSpellAtObject(nSpell, OBJECT_SELF);
}
//MyPrintString("TalentSeeInvisible Failed Exit");
return bValid;
}
// Utility function for TalentCureCondition
// Checks to see if the creature has the given condition in the
// given condition value.
// To use, you must first calculate the nCurrentConditions value
// with GetCurrentNegativeConditions.
// The value of nCondition can be any of the COND_* constants
// declared in x0_i0_talent.
int GetHasNegativeCondition(int nCondition, int nCurrentConditions)
{
return (nCurrentConditions & nCondition);
}
// Utility function for TalentCureCondition
// Returns an integer with bitwise flags set that represent the
// current negative conditions on the creature.
// To be used with GetHasNegativeCondition.
int GetCurrentNegativeConditions(object oCreature)
{
int nSum = 0;
int nType=-1;
effect eEffect = GetFirstEffect(oCreature);
while(GetIsEffectValid(eEffect)) {
nType = GetEffectType(eEffect);
switch (nType) {
case EFFECT_TYPE_DISEASE: nSum = nSum | COND_DISEASE; break;
case EFFECT_TYPE_POISON: nSum = nSum | COND_POISON; break;
case EFFECT_TYPE_CURSE: nSum = nSum | COND_CURSE; break;
case EFFECT_TYPE_NEGATIVELEVEL: nSum = nSum | COND_DRAINED; break;
case EFFECT_TYPE_ABILITY_DECREASE: nSum = nSum | COND_ABILITY; break;
case EFFECT_TYPE_BLINDNESS:
case EFFECT_TYPE_DEAF: nSum = nSum | COND_BLINDDEAF; break;
}
eEffect = GetNextEffect(oCreature);
}
return nSum;
}
// CURE DISEASE, POISON ETC
int TalentCureCondition()
{
//MyPrintString("TalentCureCondition Enter");
int nSum;
int nCond;
int nSpell;
effect eEffect;
object oTarget = GetFirstObjectInShape(SHAPE_SPHERE, RADIUS_SIZE_HUGE, GetLocation(OBJECT_SELF));
while(GetIsObjectValid(oTarget))
{
if(GetIsFriend(oTarget)) {
nSpell = 0;
nSum = GetCurrentNegativeConditions(oTarget);
if (nSum != 0) {
// friend has negative effects -- try and heal them
// These effects will be healed in reverse order if
// we have the spells for them and don't have
// restoration.
if (GetHasNegativeCondition(COND_POISON, nSum)) {
nCond++;
if (GetHasSpell(SPELL_NEUTRALIZE_POISON))
nSpell = SPELL_NEUTRALIZE_POISON;
}
if (GetHasNegativeCondition(COND_DISEASE, nSum)) {
nCond++;
if (GetHasSpell(SPELL_REMOVE_DISEASE))
nSpell = SPELL_REMOVE_DISEASE;
}
if (GetHasNegativeCondition(COND_CURSE, nSum)) {
nCond++;
if (GetHasSpell(SPELL_REMOVE_CURSE))
nSpell = SPELL_REMOVE_CURSE;
}
if (GetHasNegativeCondition(COND_BLINDDEAF, nSum)) {
nCond++;
if (GetHasSpell(SPELL_REMOVE_BLINDNESS_AND_DEAFNESS))
nSpell = SPELL_REMOVE_BLINDNESS_AND_DEAFNESS;
}
// For the conditions that can only be cured by
// restoration, we add 2
if (GetHasNegativeCondition(COND_DRAINED, nSum)) {
nCond += 2;
}
if (GetHasNegativeCondition(COND_ABILITY, nSum)) {
nCond += 2;
}
// If we have more than one condition or a condition
// that can only be cured by restoration, try one of
// those spells first if we have them.
if (nCond > 1) {
if (GetHasSpell(SPELL_GREATER_RESTORATION)) {
nSpell = SPELL_GREATER_RESTORATION;
} else if (GetHasSpell(SPELL_RESTORATION)) {
nSpell = SPELL_RESTORATION;
} else if (GetHasSpell(SPELL_LESSER_RESTORATION)) {
nSpell = SPELL_LESSER_RESTORATION;
}
}
if(nSpell != 0) {
//MyPrintString("TalentCureCondition Successful Exit");
ClearActions(CLEAR_X0_I0_TALENT_AdvancedBuff);
ActionCastSpellAtObject(nSpell, oTarget);
return TRUE;
}
}
}
oTarget = GetNextObjectInShape(SHAPE_SPHERE, RADIUS_SIZE_HUGE, GetLocation(OBJECT_SELF));
}
//MyPrintString("TalentCureCondition Failed Exit");
return FALSE;
}
// DRAGON COMBAT
// * February 2003: Cut the melee interaction (BK)
int TalentDragonCombat(object oIntruder = OBJECT_INVALID)
{
//MyPrintString("TalentDragonCombat Enter");
object oTarget = oIntruder;
if(!GetIsObjectValid(oTarget))
{
oTarget = GetAttemptedAttackTarget();
if(!GetIsObjectValid(oTarget) || GetIsDead(oTarget))
{
oTarget = GetLastHostileActor();
if(!GetIsObjectValid(oTarget) || GetIsDead(oTarget))
{
oTarget = GetNearestPerceivedEnemy();
if(!GetIsObjectValid(oTarget))
{
return FALSE;
}
}
}
}
talent tUse;
int nCnt = GetLocalInt(OBJECT_SELF, "NW_GENERIC_DRAGONS_BREATH");
tUse = GetCreatureTalent(TALENT_CATEGORY_DRAGONS_BREATH, 40);
//SpeakString(IntToString(nCnt));
if(GetIsTalentValid(tUse) && d2()==1)
{
//MyPrintString("TalentDragonCombat Successful Exit");
bkTalentFilter(tUse, oTarget);
nCnt = 0;
SetLocalInt(OBJECT_SELF, "NW_GENERIC_DRAGONS_BREATH", nCnt);
return TRUE;
}
// * breath weapons only happen every 3 rounds
nCnt++;
SetLocalInt(OBJECT_SELF, "NW_GENERIC_DRAGONS_BREATH", nCnt);
//MyPrintString("TalentDragonCombat Failed Exit");
SetLocalInt(OBJECT_SELF, "NW_GENERIC_DRAGONS_BREATH", nCnt);
return FALSE;
}
// BARD SONG
// * July 15 2003: Improving so its more likely
// * to work with non creature wizard designed creatures
// * GZ: Capped bardsong at level 20 so we don't overflow into
// other feats
int TalentBardSong()
{
int iMyBardFeat;
//MyPrintString("TalentBardSong Enter");
int iMyBardLevel = GetLevelByClass(CLASS_TYPE_BARD, OBJECT_SELF);
if (iMyBardLevel < 1)
{
// Palmer - edited this to cheat and let mobs
// cast bard song if they have the feat and are not bards
iMyBardLevel = GetHitDice(OBJECT_SELF);
}
//BARD SONG CONSTANT PENDING
if ( iMyBardLevel == 1 )
{
iMyBardFeat = 257;
}
else
{
if (iMyBardLevel >20)
{
iMyBardLevel = 20;
}
iMyBardFeat = 353 + iMyBardLevel;
}
if(!GetHasSpellEffect(411))
{
if(GetHasFeat(iMyBardFeat) == TRUE)
{
//MyPrintString("TalentBardSong Successful Exit");
ClearActions(CLEAR_X0_I0_TALENT_BardSong);
ActionUseFeat(iMyBardFeat, OBJECT_SELF);
return TRUE;
}
}
//MyPrintString("TalentBardSong Failed Exit");
return FALSE;
}
//************************************************************************************************************************************
//************************************************************************************************************************************
//************************************************************************************************************************************
// VERSION 2.0 TALENTS
//************************************************************************************************************************************
//************************************************************************************************************************************
//************************************************************************************************************************************
// ADVANCED PROTECT SELF Talent 2.0
// This will use the class specific defensive spells first and leave the rest for the normal defensive AI
//**********************************
//**********************************
//**********************************
// VERSION 2.0 TALENTS
//**********************************
//**********************************
//**********************************
//**********************************
//**********************************
//**********************************
// VERSION 2.0 TALENTS
//**********************************
//**********************************
//**********************************
// ADVANCED PROTECT SELF Talent 2.0
// This will use the class specific defensive spells first and
// leave the rest for the normal defensive AI
int TalentAdvancedProtectSelf()
{
//MyPrintString("TalentAdvancedProtectSelf Enter");
talent tUse;
struct sEnemies sCount = DetermineEnemies();
int bValid = FALSE;
int nCnt;
string sClass = GetMostDangerousClass(sCount);
tUse = StartProtectionLoop();
while(GetIsTalentValid(tUse) && nCnt < 10)
{
///MyPrintString("TalentAdvancedProtectSelf Search Self");
tUse = GetCreatureTalent(TALENT_CATEGORY_BENEFICIAL_PROTECTION_SELF,
40);
if(GetIsTalentValid(tUse)
&& GetMatchCompatibility(tUse, sClass, NW_TALENT_PROTECT))
{
bValid = TRUE;
nCnt = 11;
} else {
//MyPrintString(" TalentAdvancedProtectSelfSearch Single");
tUse =
GetCreatureTalent(TALENT_CATEGORY_BENEFICIAL_PROTECTION_SINGLE,
40);
if(GetIsTalentValid(tUse)
&& GetMatchCompatibility(tUse, sClass, NW_TALENT_PROTECT))
{
bValid = TRUE;
nCnt = 11;
} else {
//MyPrintString("TalentAdvancedProtectSelf Search Area");
tUse =
GetCreatureTalent(TALENT_CATEGORY_BENEFICIAL_PROTECTION_AREAEFFECT,
40);
if(GetIsTalentValid(tUse)
&& GetMatchCompatibility(tUse, sClass, NW_TALENT_PROTECT))
{
bValid = TRUE;
nCnt = 11;
}
}
}
nCnt++;
}
if(bValid == TRUE)
{
int nType = GetTypeFromTalent(tUse);
int nIndex = GetIdFromTalent(tUse);
if(nType == TALENT_TYPE_SPELL)
{
if(!GetHasSpellEffect(nIndex)) {
//MyPrintString("TalentAdvancedProtectSelf Successful Exit");
bkTalentFilter(tUse, OBJECT_SELF);
return TRUE;
}
} else if(nType == TALENT_TYPE_FEAT) {
if(!GetHasFeatEffect(nIndex)) {
//MyPrintString("TalentAdvancedProtectSelf Successful Exit");
bkTalentFilter(tUse, OBJECT_SELF);
return TRUE;
}
} else {
//MyPrintString("TalentAdvancedProtectSelf Successful Exit");
bkTalentFilter(tUse, OBJECT_SELF);
return TRUE;
}
}
//MyPrintString("TalentAdvancedProtectSelf Failed Exit");
return FALSE;
}
// Cast a spell mantle or globe of invulnerability protection on
// yourself.
int TalentSelfProtectionMantleOrGlobe()
{
//Mantle Protections
if (TrySpell(SPELL_GREATER_SPELL_MANTLE))
return TRUE;
if (TrySpell(SPELL_SPELL_MANTLE))
return TRUE;
if (TrySpell(SPELL_GLOBE_OF_INVULNERABILITY))
return TRUE;
if (TrySpell(SPELL_MINOR_GLOBE_OF_INVULNERABILITY))
return TRUE;
return FALSE;
}
//// This function simply attempts to get the best protective
// talent that the caller has, the protective talents as
// follows:
// TALENT_CATEGORY_BENEFICIAL_PROTECTION_SELF
// TALENT_CATEGORY_BENEFICIAL_PROTECTION_SINGLE
// TALENT_CATEGORY_BENEFICIAL_PROTECTION_AREAEFFECT
talent StartProtectionLoop()
{
talent tUse;
tUse = GetCreatureTalent(TALENT_CATEGORY_BENEFICIAL_PROTECTION_SELF,
40);
if(GetIsTalentValid(tUse))
return tUse;
tUse = GetCreatureTalent(TALENT_CATEGORY_BENEFICIAL_PROTECTION_SINGLE,
40);
if(GetIsTalentValid(tUse))
return tUse;
tUse = GetCreatureTalent(TALENT_CATEGORY_BENEFICIAL_PROTECTION_AREAEFFECT,
40);
return tUse;
}
int TalentDismissal(object oPet)
{
int nSpell=FALSE;
if(GetHasSpell(SPELL_BANISHMENT))
{
nSpell=SPELL_BANISHMENT;
}
else
if(GetHasSpell(SPELL_DISMISSAL))
{
nSpell=SPELL_DISMISSAL;
}
if (nSpell==FALSE)
{
return FALSE;
}
int nSearch=TRUE;
int nFound=FALSE;
int nIdx=1;
object oVictim=GetNearestCreature(CREATURE_TYPE_REPUTATION,REPUTATION_TYPE_ENEMY,OBJECT_SELF,nIdx,CREATURE_TYPE_PERCEPTION,PERCEPTION_SEEN);
while (nSearch==TRUE)
{
if (!GetIsObjectValid(oVictim))
{
nSearch=FALSE;
return FALSE;
}
else
if (GetIsObjectValid(GetMaster(oVictim)))
{
nFound=TRUE;
nSearch=FALSE;
}
else
{
nIdx=nIdx+1;
oVictim=GetNearestCreature(CREATURE_TYPE_REPUTATION,REPUTATION_TYPE_ENEMY,OBJECT_SELF,nIdx,CREATURE_TYPE_PERCEPTION,PERCEPTION_SEEN);
}
}
if (nFound==FALSE)
{
return FALSE;
}
else
{
ClearAllActions();
ActionCastSpellAtObject(nSpell, oVictim);
return TRUE;
}
return FALSE;
}
int TalentDispelEffects(object oIntruder=OBJECT_INVALID)
{
// BD version - low level mobs usually act stupid
if ((GetHitDice(OBJECT_SELF)<13)&&(d4()!=1))
{
return FALSE;
}
int nSpell;
int bValid = FALSE;
if(GetHasSpell(SPELL_MORDENKAINENS_DISJUNCTION))
{
nSpell = SPELL_MORDENKAINENS_DISJUNCTION;
bValid = TRUE;
}
else if(GetHasSpell(SPELL_GREATER_DISPELLING))
{
nSpell = SPELL_GREATER_DISPELLING;
bValid = TRUE;
}
else if(GetHasSpell(SPELL_GREATER_SPELL_BREACH))
{
nSpell = SPELL_GREATER_SPELL_BREACH;
bValid = TRUE;
}
else if(GetHasSpell(SPELL_DISPEL_MAGIC))
{
nSpell = SPELL_DISPEL_MAGIC;
bValid = TRUE;
}
else if(GetHasSpell(SPELL_LESSER_SPELL_BREACH))
{
nSpell = SPELL_GREATER_SPELL_BREACH;
bValid = TRUE;
}
else if(GetHasSpell(SPELL_LESSER_DISPEL))
{
nSpell = SPELL_LESSER_DISPEL;
bValid = TRUE;
}
if (bValid==FALSE)
{
return FALSE;
}
int nSearch=TRUE;
int nFound=FALSE;
int nIdx=1;
object oVictim=GetNearestCreature(CREATURE_TYPE_REPUTATION,REPUTATION_TYPE_ENEMY,OBJECT_SELF,nIdx,CREATURE_TYPE_PERCEPTION,PERCEPTION_SEEN);
while (nSearch==TRUE)
{
if (!GetIsObjectValid(oVictim))
{
nSearch=FALSE;
return FALSE;
}
else
if (CheckHasPositiveEffect(oVictim))
{
nFound=TRUE;
nSearch=FALSE;
}
else
{
nIdx=nIdx+1;
oVictim=GetNearestCreature(CREATURE_TYPE_REPUTATION,REPUTATION_TYPE_ENEMY,OBJECT_SELF,nIdx,CREATURE_TYPE_PERCEPTION,PERCEPTION_SEEN);
}
}
if (nFound==FALSE)
{
return FALSE;
}
else
{
ClearAllActions();
ActionCastSpellAtObject(nSpell, oVictim);
return (TRUE);
}
return FALSE;
}
// * Tries to do the Ki Damage ability
int TryKiDamage(object oTarget)
{
if (GetIsObjectValid(oTarget) == FALSE)
{
return FALSE;
}
if (GetHasFeat(FEAT_KI_DAMAGE) == TRUE)
{
// * Evaluation:
// * Must have > 40 hitpoints AND (damage reduction OR damage resistance)
// * Or just have over 200 hitpoints
int bHasDamageReduction = FALSE;
int bHasDamageResistance = FALSE;
int bHasHitpoints = FALSE;
int bHasMassiveHitpoints = FALSE;
int bOutNumbered = FALSE;
int nCurrentHP = GetCurrentHitPoints(oTarget);
if (nCurrentHP > 40)
bHasHitpoints = TRUE;
if (nCurrentHP > 200)
bHasMassiveHitpoints = TRUE;
if (PRCGetHasEffect(EFFECT_TYPE_DAMAGE_REDUCTION, oTarget) == TRUE)
bHasDamageReduction = TRUE;
if (PRCGetHasEffect(EFFECT_TYPE_DAMAGE_RESISTANCE, oTarget) == TRUE)
bHasDamageResistance = TRUE;
if (GetIsObjectValid(GetNearestEnemy(OBJECT_SELF, 3)) == TRUE)
{
bOutNumbered = TRUE;
}
if ( (bHasHitpoints && (bHasDamageReduction || bHasDamageResistance) ) || (bHasMassiveHitpoints) || (bHasHitpoints && bOutNumbered) )
{
ClearAllActions();
ActionUseFeat(FEAT_KI_DAMAGE, oTarget);
return TRUE;
}
}
return FALSE;
}
// Try a spell to produce a particular spell effect.
// This will only cast the spell if the target DOES NOT already have the
// given spell effect, and the caster possesses the spell.
//
// Returns TRUE on success, FALSE on failure.
int TrySpell(int nSpell, object oTarget=OBJECT_SELF, object oCaster=OBJECT_SELF)
{
if (GetHasSpell(nSpell, oCaster) && !GetHasSpellEffect(nSpell, oTarget)) {
AssignCommand(oCaster,
ActionCastSpellAtObject(nSpell, oTarget));
return TRUE;
}
return FALSE;
}
// Try a spell corresponding to a particular effect.
// This will only cast the spell if the target DOES have the
// given effect, and the caster possesses the spell.
//
// Returns TRUE on success, FALSE on failure.
int TrySpellForEffect(int nSpell, int nEffect, object oTarget=OBJECT_SELF, object oCaster=OBJECT_SELF)
{
if (GetHasSpell(nSpell, oCaster) && PRCGetHasEffect(nEffect, oTarget)) {
AssignCommand(oCaster,
ActionCastSpellAtObject(nSpell, oTarget));
return TRUE;
}
return FALSE;
}
// Try a given talent.
// This will only cast spells and feats if the targets do not already
// have the effects of those feats, and will funnel all talents
// through bkTalentFilter for a final check.
int TryTalent(talent tUse, object oTarget=OBJECT_SELF, object oCaster=OBJECT_SELF)
{
int nType = GetTypeFromTalent(tUse);
int nIndex = GetIdFromTalent(tUse);
if(nType == TALENT_TYPE_SPELL && GetHasSpellEffect(nIndex, oTarget))
{
return FALSE;
}
else if(nType == TALENT_TYPE_FEAT && GetHasFeatEffect(nIndex, oTarget))
{
return FALSE;
}
// MODIFIED February 7 2003. Implicit else, implies success.
bkTalentFilter(tUse, OBJECT_SELF);
//MyPrintString("TryTalent Successful Exit");
return TRUE;
return FALSE;
}
// * Wrapper function so that I could add a variable to allow randomization
// * to the AI.
// * WARNING: This will make the AI cast spells badly if they have a bad
// * spell selection (i.e., only turn randomization on if you know what you are doing
// *
// * nCRMax only applies if bRandom is FALSE
// * oCreature is the creature checking to see if it has the talent
talent GetCreatureTalent(int nCategory, int nCRMax, int bRandom=FALSE, object oCreature = OBJECT_SELF)
{
// * bRandom can be overridden by the variable X2_SPELL_RANDOM = 1
if (bRandom == FALSE)
{
bRandom = GetLocalInt(OBJECT_SELF, "X2_SPELL_RANDOM");
}
if (bRandom == FALSE)
{
return GetCreatureTalentBest(nCategory, nCRMax, oCreature);
}
else
// * randomize it
{
return GetCreatureTalentRandom(nCategory, oCreature);
}
}
int TalentThrowTree (object oIntruder = OBJECT_INVALID)
{
int nTrees=GetLocalInt(OBJECT_SELF,"throwtree");
if (nTrees<1)
{
return FALSE;
}
if (GetDistanceToObject(oIntruder)<5.0)
{
return FALSE;
}
location lLoc = GetLocation(oIntruder);
vector vPos = GetPosition(oIntruder);
int iSpell;
int iExplosion;
int iDamage;
int iDamageType;
float fRadius;
float fDelay;
iSpell = 752;
iExplosion = 9999;
iDamageType = DAMAGE_TYPE_PIERCING;
fRadius = 6.0;
int nDice = GetHitDice(OBJECT_SELF) / 3;
if (nDice <1)
{
nDice =1;
}
int nDamageAdjustment = GetAbilityModifier (ABILITY_STRENGTH,OBJECT_SELF);
iDamage = d6(nDice) + nDamageAdjustment;
fDelay =GetDistanceBetweenLocations(GetLocation(OBJECT_SELF), lLoc)/12;
// Start the throw actions.
ClearAllActions();
ActionCastFakeSpellAtLocation(iSpell, lLoc);
DelayCommand(1.6 + fDelay, DoRadiusDamage(iSpell, lLoc, iExplosion, iDamage, iDamageType, fRadius, 5+nDice));
SetCommandable(FALSE);
DelayCommand(4.0,SetCommandable(TRUE));
SetLocalInt(OBJECT_SELF,"throwtree",nTrees-1);
return TRUE;
}
void DoRadiusDamage(int iSpell, location lLoc, int iExplosion, int iDamage, int iDamageType, float fRadius, int nKnockDC=0)
{
object oDamaged = GetFirstObjectInShape(SHAPE_SPHERE, fRadius, lLoc, FALSE, OBJECT_TYPE_CREATURE | OBJECT_TYPE_PLACEABLE);
string sRes = "plc_treeautumn";
effect eEffect;
int nPower=DAMAGE_POWER_PLUS_ONE;
if (GetHitDice(OBJECT_SELF)>4)
{
nPower=DAMAGE_POWER_PLUS_TWO;
}
if (GetHitDice(OBJECT_SELF)>9)
{
nPower=DAMAGE_POWER_PLUS_THREE;
}
if (GetHitDice(OBJECT_SELF)>14)
{
nPower=DAMAGE_POWER_PLUS_FOUR;
}
int nDamage;
int nDC=10+GetHitDice(OBJECT_SELF);
DelayCommand(0.3, ApplyEffectAtLocation(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_FNF_SCREEN_BUMP), lLoc));
DelayCommand(0.3, ApplyEffectAtLocation(DURATION_TYPE_INSTANT, EffectVisualEffect(354), lLoc));
// Damage.
while(GetIsObjectValid(oDamaged))
{
if (GetIsReactionTypeHostile(oDamaged))
{
nDamage = PRCGetReflexAdjustedDamage(iDamage, oDamaged, nDC, SAVING_THROW_TYPE_NONE);
DelayCommand(0.5, ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectDamage(nDamage, iDamageType, nPower), oDamaged));
if (nKnockDC>0)
{
if (GetIsSkillSuccessful(oDamaged,SKILL_DISCIPLINE,nKnockDC) == 0)
{
effect eKnock = EffectKnockdown();
DelayCommand(0.5,ApplyEffectToObject(DURATION_TYPE_TEMPORARY,eKnock,oDamaged,RoundsToSeconds(1)));
}
}
}
oDamaged = GetNextObjectInShape(SHAPE_SPHERE, fRadius, lLoc, FALSE, OBJECT_TYPE_CREATURE | OBJECT_TYPE_PLACEABLE);
}
}
// Mimic combat routine
int TalentMimicCombat (object oIntruder = OBJECT_INVALID)
{
// only mimics can do this, and a 1 in 2 chance of just doing normal combat
if ((GetAppearanceType(OBJECT_SELF)!=469))
{
return FALSE;
}
// Fire bolt if enemy is far away
if(GetDistanceToObject(oIntruder) > 5.0)
{
location lLoc=GetLocation(oIntruder);
int nSpell=749;
if (d2()==1)
{
//nSpell=620; // this should be flying debris
//nSpell=773; // some type of boulder
nSpell=748;
}
ClearActions(CLEAR_X0_I0_TALENT_RangedEnemies);
ActionCastFakeSpellAtObject(nSpell,oIntruder,PROJECTILE_PATH_TYPE_HOMING);
float fDelay =GetDistanceBetweenLocations(GetLocation(OBJECT_SELF), lLoc)/12;
DelayCommand(1.6 + fDelay, DoRadiusDamage(999, lLoc, 999, d2(GetHitDice(OBJECT_SELF)), DAMAGE_TYPE_MAGICAL, 4.0));
SetCommandable(FALSE);
DelayCommand(4.0,SetCommandable(TRUE));
return TRUE;
}
else
{
if (d2()==1)
{
return FALSE;
}
ClearActions(CLEAR_X0_I0_TALENT_MeleeAttack1);
PlayAnimation(ANIMATION_LOOPING_SPASM,1.0,1.0);
ActionCastSpellAtObject(504,oIntruder,METAMAGIC_ANY,TRUE,GetHitDice(OBJECT_SELF),PROJECTILE_PATH_TYPE_HOMING);
return TRUE;
}
}
int TalentGarotte (object oIntruder = OBJECT_INVALID)
{
int nGarotte=GetLocalInt(OBJECT_SELF,"garotte");
if (nGarotte<1)
{
return FALSE;
}
if (GetDistanceToObject(oIntruder)<4.0)
{
return FALSE;
}
if (d3()!=1)
{
return FALSE;
}
int nStrength=GetHitDice(OBJECT_SELF)/4;
if (nStrength<1)
{
nStrength=1;
}
if (nStrength>4)
{
nStrength=4;
}
garrote(oIntruder,nStrength);
SetLocalInt(OBJECT_SELF,"garotte",nGarotte-1);
return TRUE;
}
int TalentFlyToEnemy (object oIntruder = OBJECT_INVALID)
{
int nFly=GetLocalInt(OBJECT_SELF,"flytoenemy");
if (nFly<1)
{
return FALSE;
}
if (GetDistanceToObject(oIntruder)<8.0)
{
return FALSE;
}
ApplyEffectToObject(DURATION_TYPE_TEMPORARY,EffectDisappearAppear(GetLocation(oIntruder)),OBJECT_SELF,4.0);
SetLocalInt(OBJECT_SELF,"flytoenemy",nFly-1);
return TRUE;
}
int TalentBlindSpit (object oIntruder = OBJECT_INVALID)
{
int nSpit=GetLocalInt(OBJECT_SELF,"spitspider");
if (nSpit<1)
{
return FALSE;
}
if (d4()!=1)
{
return FALSE;
}
ClearAllActions();
vector vPosition=GetPosition(oIntruder);
SetFacingPoint(vPosition);
effect eArrow = EffectVisualEffect(245);
ApplyEffectToObject(DURATION_TYPE_INSTANT, eArrow, oIntruder);
ApplyEffectToObject(DURATION_TYPE_INSTANT,EffectVisualEffect(VFX_IMP_ACID_S),OBJECT_SELF);
float fDist = GetDistanceToObject(oIntruder);
float fDelay = (fDist/25.0);//(3.0 * log(fDist) + 2.0);
if (ReflexSave(oIntruder,20,SAVING_THROW_REFLEX)==0)
{
DelayCommand(fDelay,ApplyEffectToObject(DURATION_TYPE_TEMPORARY,EffectBlindness(),oIntruder,20.0));
DelayCommand(fDelay,ApplyEffectToObject(DURATION_TYPE_TEMPORARY,EffectVisualEffect(VFX_DUR_BLIND),oIntruder,20.0));
DelayCommand(fDelay,ApplyEffectToObject(DURATION_TYPE_TEMPORARY,EffectPoison(POISON_HUGE_SPIDER_VENOM),oIntruder,20.0));
DelayCommand(fDelay,ApplyEffectToObject(DURATION_TYPE_TEMPORARY,EffectVisualEffect(VFX_IMP_POISON_S),oIntruder,20.0));
}
SetLocalInt(OBJECT_SELF,"spitspider",nSpit-1);
return TRUE;
}