//////////////////////////////////////////////////////////////////////////////// // cai_caster - Custom Combat AI - Caster Mode // By Deva Bryson Winblood. 11/2004 //////////////////////////////////////////////////////////////////////////////// #include "cai_inc_hos" #include "nw_i0_generic" #include "prc_inc_racial" int fnClassIsSpellCaster(int nPos,object oNPC) { // tell me if this class is a spell caster int nClass=GetClassByPosition(nPos,oNPC); int bRet=FALSE; switch(nClass) { case CLASS_TYPE_ARCANE_ARCHER: case CLASS_TYPE_BARD: case CLASS_TYPE_CLERIC: case CLASS_TYPE_DRUID: case CLASS_TYPE_FEY: case CLASS_TYPE_DRAGONDISCIPLE: case CLASS_TYPE_PALADIN: case CLASS_TYPE_PALEMASTER: case CLASS_TYPE_RANGER: case CLASS_TYPE_SHADOWDANCER: case CLASS_TYPE_SHIFTER: case CLASS_TYPE_SORCERER: case CLASS_TYPE_WIZARD: { bRet=TRUE; break; } default: { break; } } return bRet; } // fnClassIsSpellCaster() int fnCanCastSpells(object oNPC) { if (fnClassIsSpellCaster(1,oNPC)) return TRUE; else if (fnClassIsSpellCaster(2,oNPC)) return TRUE; else if (fnClassIsSpellCaster(3,oNPC)) return TRUE; return FALSE; } int fnCanAnyNearbyEnemiesCastSpells() { object oMe=OBJECT_SELF; int nN; float fD; object oOb; oOb=GetNearestCreature(CREATURE_TYPE_REPUTATION,REPUTATION_TYPE_ENEMY,oMe,nN,CREATURE_TYPE_PERCEPTION,PERCEPTION_SEEN,CREATURE_TYPE_IS_ALIVE,TRUE); fD=GetDistanceBetween(oMe,oOb); while(GetIsObjectValid(oOb)&&fD<25.0) { // enemy spell casters if (fnCanCastSpells(oOb)) return TRUE; nN++; oOb=GetNearestCreature(CREATURE_TYPE_REPUTATION,REPUTATION_TYPE_ENEMY,oMe,nN,CREATURE_TYPE_PERCEPTION,PERCEPTION_SEEN,CREATURE_TYPE_IS_ALIVE,TRUE); fD=GetDistanceBetween(oMe,oOb); } // enemy spell casters return FALSE; } // fnCanAnyNearbyEnemiesCastSpells() object fnGetBestTarget(int nRace) { // tell me who my best target is at the moment object oRet=OBJECT_INVALID; int nN; float fD; int nVal; object oOb; int nThis; int nC; nN=1; oOb=GetNearestCreature(CREATURE_TYPE_REPUTATION,REPUTATION_TYPE_ENEMY,OBJECT_SELF,nN,CREATURE_TYPE_IS_ALIVE,TRUE,CREATURE_TYPE_PERCEPTION,PERCEPTION_SEEN); fD=GetDistanceBetween(oOb,OBJECT_SELF); while(oOb!=OBJECT_INVALID) { // check all nearby targets nThis=1; nN++; if (fD<20.0) nThis++; if (fD<15.0) nThis++; if (fD<10.0) nThis++; if (fD<8.0) nThis++; if (fD<5.0) nThis++; fD=IntToFloat(GetCurrentHitPoints(oOb))/IntToFloat(GetMaxHitPoints(oOb)); if (fD<0.51) nThis++; if (fD<0.31) nThis++; if (fD<0.11) nThis++; if (nRace==RACIAL_TYPE_UNDEAD) { // see if target is a cleric nC=GetClassByPosition(1,oOb); if (nC==CLASS_TYPE_CLERIC||nC==CLASS_TYPE_PALADIN) nThis=nThis+3; nC=GetClassByPosition(2,oOb); if (nC==CLASS_TYPE_CLERIC||nC==CLASS_TYPE_PALADIN) nThis=nThis+3; nC=GetClassByPosition(3,oOb); if (nC==CLASS_TYPE_CLERIC||nC==CLASS_TYPE_PALADIN) nThis=nThis+3; } // see if target is a cleric if (fnClassIsSpellCaster(1,oOb)) nThis++; if (fnClassIsSpellCaster(2,oOb)) nThis++; if (fnClassIsSpellCaster(3,oOb)) nThis++; if (nThis>nVal) { // new best target oRet=oOb; nVal=nThis; } // new best target oOb=GetNearestCreature(CREATURE_TYPE_REPUTATION,REPUTATION_TYPE_ENEMY,OBJECT_SELF,nN,CREATURE_TYPE_IS_ALIVE,TRUE,CREATURE_TYPE_PERCEPTION,PERCEPTION_SEEN); fD=GetDistanceBetween(oOb,OBJECT_SELF); } // check all nearby targets return oRet; } // tell me who my best target is at the moment void main() { object oMe=OBJECT_SELF; object oTarget=GetAttackTarget(); float fF; int nN; int nMyRace=MyPRCGetRacialType(oMe); object oBest=fnGetBestTarget(nMyRace); int bTargetChanged=FALSE; int nState=GetLocalInt(oMe,"nCAIState"); if (oBest!=oTarget) { oTarget=oBest; bTargetChanged=TRUE; } if (GetIsObjectValid(oTarget)) { // target is valid if (fnCanAnyNearbyEnemiesCastSpells()) { // defend SetLocalInt(oMe,"bCAISPELLCASTERS",TRUE); } // defend else { DeleteLocalInt(oMe,"bCAISPELLCASTERS"); nState=3; } nState++; if (nState>4) nState=1; if (nState==1) { // defensive spells nN=caiGetAvailableDefensiveSpell(oMe,oMe); if (nN==0) nState=2; else { // cast this spell AssignCommand(oMe,ActionCastSpellAtObject(nN,oMe)); } // cast this spell } // defensive spells if (nState==2) { // summon spell if (GetIsObjectValid(GetAssociate(ASSOCIATE_TYPE_SUMMONED,oMe,1))==FALSE) { // no summoned critters nN=caiGetAvailableSummonSpell(oTarget); if (nN!=0) { // summon AssignCommand(oMe,ActionCastSpellAtLocation(nN,GetLocation(oMe))); } // summon else { nState=3; } } // no summoned critters else { nState=3; } } // summon spell if (nState>2) { // combat spell nN=caiGetAvailableCombatSpell(oMe,oTarget); if (nN!=0) { // spell found AssignCommand(oMe,ActionCastSpellAtObject(nN,oTarget)); } // spell found else { // DetermineCombatRound(oTarget); } // } // combat spell } // target is valid // check need to heal self and remove negative spells // set up sentinel for resting if (GetLocalInt(oMe,"bCAIRESTSENTINEL")!=TRUE) { // trigger the sentinel SetLocalInt(oMe,"bCAIRESTSENTINEL",TRUE); caiRestSentinel(oMe); } // trigger the sentinel }