//////////////////////////////////////////////////////////////////////////////// // cai_Support - Custom Combat AI - Support Mode // By Deva Bryson Winblood. 11/2004 //////////////////////////////////////////////////////////////////////////////// #include "cai_inc_hos" #include "nw_I0_generic" 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() 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&&fD<30.0) { // check all nearby targets nThis=0; 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 bMUST=FALSE; int nMyRace=GetRacialType(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 nState++; if (nState>4) nState=1; oBest=GetNearestCreature(CREATURE_TYPE_REPUTATION,REPUTATION_TYPE_ENEMY,oMe,1,CREATURE_TYPE_IS_ALIVE,TRUE,CREATURE_TYPE_PERCEPTION,PERCEPTION_SEEN); if (GetIsObjectValid(oBest)) { // there are enemies if (GetDistanceBetween(oMe,oBest)<5.1) { // enemy too close DetermineCombatRound(oBest); } // enemy too close else { // not close oBest=GetNearestCreature(CREATURE_TYPE_REPUTATION,REPUTATION_TYPE_FRIEND,oMe,1,CREATURE_TYPE_IS_ALIVE,TRUE); if (GetIsObjectValid(oBest)) { // there are friends if (GetDistanceBetween(oMe,oBest)<10.1) { // friends are close nN=1; oBest=GetNearestCreature(CREATURE_TYPE_REPUTATION,REPUTATION_TYPE_FRIEND,oMe,d6(),CREATURE_TYPE_IS_ALIVE,TRUE); while((GetIsObjectValid(oBest)==FALSE||(GetDistanceBetween(oBest,oMe)<10.1&&GetDistanceBetween(oBest,oMe)!=0.0))&&nN<4) { // find friend nN++; oBest=GetNearestCreature(CREATURE_TYPE_REPUTATION,REPUTATION_TYPE_FRIEND,oMe,d6(),CREATURE_TYPE_IS_ALIVE,TRUE); } // find friend if (GetIsObjectValid(oBest)==FALSE) oBest=GetNearestCreature(CREATURE_TYPE_REPUTATION,REPUTATION_TYPE_FRIEND,oMe,1,CREATURE_TYPE_IS_ALIVE,TRUE); if (GetIsObjectValid(oBest)) { // friend to help found nN=GetMaxHitPoints(oBest)-GetCurrentHitPoints(oBest); if ((nN>0||GetIsDead(oBest))&&nState!=4) { // healing needed if (GetIsPC(oBest)) nN=caiGetAvailableHealPC(oMe,oBest); else if (GetIsDead(oBest)==FALSE) { nN=caiGetAvailableHeal(oMe,nN); } if (nN!=0) { // heal AssignCommand(oMe,ActionCastSpellAtObject(nN,oBest)); } // heal else { // combat DetermineCombatRound(oTarget); } // combat } // healing needed else if (GetMaxHitPoints(oMe)-GetCurrentHitPoints(oMe)>0) { // heal self bMUST=FALSE; if ((IntToFloat(GetCurrentHitPoints(oMe))/IntToFloat(GetMaxHitPoints(oMe)))<0.51) bMUST=TRUE; nN=caiGetAvailableHeal(oMe,nN,bMUST); if (nN!=0) { // heal self AssignCommand(oMe,ActionCastSpellAtObject(nN,oBest)); } // heal self else { // combat DetermineCombatRound(oTarget); } // combat } // heal self else if (nState!=4) { // defense, buff if (nState==1) { // defense nN=caiGetAvailableDefensiveSpell(oMe,oBest); if (nN!=0) { // spell AssignCommand(oMe,ActionCastSpellAtObject(nN,oBest)); } // spell else { // combat DetermineCombatRound(oTarget); } // combat } // defense else { // buff nN=caiGetAvailableBuff(oMe,oBest); if (nN!=0) { // spell AssignCommand(oMe,ActionCastSpellAtObject(nN,oBest)); } // spell else { // combat DetermineCombatRound(oTarget); } // combat } // buff } // defense, buff else { // combat DetermineCombatRound(oTarget); } // combat } // friend to help found } // friends are close else { // I am alone if (nState==1) { // defensive spell nN=caiGetAvailableDefensiveSpell(oMe,oMe); if (nN!=0) { // spell AssignCommand(oMe,ActionCastSpellAtObject(nN,oMe)); } // spell else { // combat DetermineCombatRound(oMe); } // combat } // defensive spell else if (nState==2||nState==4) { // combat DetermineCombatRound(oMe); } // combat else if (nState==3) { // buff spell nN=caiGetAvailableBuff(oMe,oMe); if (nN!=0) { // spell AssignCommand(oMe,ActionCastSpellAtObject(nN,oMe)); } // spell else { // combat DetermineCombatRound(oMe); } // combat } // buff spell } // I am alone } // there are friends else { // I am alone if (nState==1) { // defensive spell nN=caiGetAvailableDefensiveSpell(oMe,oMe); if (nN!=0) { // spell AssignCommand(oMe,ActionCastSpellAtObject(nN,oMe)); } // spell else { // combat DetermineCombatRound(oMe); } // combat } // defensive spell else if (nState==2||nState==4) { // combat DetermineCombatRound(oMe); } // combat else if (nState==3) { // buff spell nN=caiGetAvailableBuff(oMe,oMe); if (nN!=0) { // spell AssignCommand(oMe,ActionCastSpellAtObject(nN,oMe)); } // spell else { // combat DetermineCombatRound(oMe); } // combat } // buff spell } // I am alone } // not close } // there are enemies } // 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 }