Finished PRC8 integration. Moved creature abilities to top hak. Setup tooling. Created release archive
3001 lines
102 KiB
Plaintext
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;
|
|
}
|