/////// #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; }