154 lines
4.8 KiB
Plaintext
154 lines
4.8 KiB
Plaintext
////////////////////////////////////////////////////////////////////////////////
|
|
// cai_summon - Custom Combat AI - Summon 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 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;
|
|
if (nState==1)
|
|
{ // 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=2; }
|
|
} // no summoned critters
|
|
else { nState=2; }
|
|
} // summon spell
|
|
if (nState==2)
|
|
{ // defensive spells
|
|
nN=caiGetAvailableDefensiveSpell(oMe,oMe);
|
|
if (nN==0) nState=3;
|
|
else
|
|
{ // cast this spell
|
|
AssignCommand(oMe,ActionCastSpellAtObject(nN,oMe));
|
|
} // cast this spell
|
|
} // defensive spells
|
|
if (nState==3)
|
|
{ // combat spell
|
|
nN=caiGetAvailableCombatSpell(oMe,oTarget);
|
|
if (nN!=0)
|
|
{ // spell found
|
|
AssignCommand(oMe,ActionCastSpellAtObject(nN,oTarget));
|
|
} // spell found
|
|
else
|
|
{ //
|
|
nState=4;
|
|
} //
|
|
} // combat spell
|
|
if (nState==4)
|
|
{ // summon spell
|
|
if (GetIsObjectValid(GetAssociate(ASSOCIATE_TYPE_SUMMONED,oMe,2))==FALSE)
|
|
{ // no summoned critters
|
|
nN=caiGetAvailableSummonSpell(oTarget);
|
|
if (nN!=0)
|
|
{ // summon
|
|
AssignCommand(oMe,ActionCastSpellAtLocation(nN,GetLocation(oMe)));
|
|
} // summon
|
|
else { DetermineCombatRound(oTarget); }
|
|
} // no summoned critters
|
|
} // summon 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
|
|
}
|