328 lines
13 KiB
Plaintext
328 lines
13 KiB
Plaintext
// rts_ai_guard - Guard command Version 2.0
|
|
// nParm = Guard mode, 0=Where you stand, 1-3 = object, 4=mana, 5 = throne
|
|
// fGX = Guard X, fGY = Guard Y, fGZ = Guard Z, oGArea=Area of location
|
|
#include "rts_pathing"
|
|
#include "rts_header"
|
|
#include "antistuck_h"
|
|
#include "prc_inc_util"
|
|
|
|
///////////////////////////
|
|
// PROTOTYPES
|
|
///////////////////////////
|
|
void fnSpeak(string sSay); // speak a message if intelligence >8
|
|
object fnFindHealTarget(); //
|
|
int fnHasHealSpells();
|
|
|
|
////////////////////////////////////////////////////////////////////// MAIN
|
|
void main()
|
|
{
|
|
object oMe=OBJECT_SELF;
|
|
int nState=GetLocalInt(oMe,"nSState");
|
|
int nParm=GetLocalInt(oMe,"nParm");
|
|
string sID=GetLocalString(oMe,"sTeamID");
|
|
object oVault=GetWaypointByTag(sID+"_VAULT");
|
|
object oThrone=GetWaypointByTag(sID+"_START");
|
|
object oOb;
|
|
object oWP;
|
|
int nN;
|
|
int nN2;
|
|
float fF;
|
|
object oMove;
|
|
int nErr;
|
|
location lLoc;
|
|
float fGX=GetLocalFloat(oMe,"fGX");
|
|
float fGY=GetLocalFloat(oMe,"fGY");
|
|
float fGZ=GetLocalFloat(oMe,"fGZ");
|
|
float fFacing=GetLocalFloat(oMe,"fGFacing");
|
|
object oGArea=GetLocalObject(oMe,"oGArea");
|
|
object oMod=GetModule();
|
|
int nRun=GetLocalInt(oMe,"nRun");
|
|
vector vV;
|
|
int nSeekTime=GetLocalInt(oMe,"nSeekTime");
|
|
object oNew=GetLocalObject(oMe,"oNewDest");
|
|
location lGLoc=GetLocalLocation(oMe,"lLocation");
|
|
object oEnemy=GetNearestCreature(CREATURE_TYPE_IS_ALIVE,TRUE,oMe,1,CREATURE_TYPE_REPUTATION,REPUTATION_TYPE_ENEMY,CREATURE_TYPE_PERCEPTION,PERCEPTION_SEEN);
|
|
if (GetIsInCombat(oMe)==FALSE&&IsInConversation(oMe)==FALSE&&oEnemy==OBJECT_INVALID)
|
|
{ // okay to guard
|
|
if (nParm>0&&nParm<4) oGArea=GetAreaFromLocation(lGLoc);
|
|
//SendMessageToPC(GetFirstPC(),"["+GetName(oMe)+"]nS:"+IntToString(nState)+" nP:"+IntToString(nParm)+" oV:"+GetName(oVault)+" oT:"+GetName(oThrone)+" ID:"+sID);
|
|
switch(nState)
|
|
{ // main switch
|
|
case 0: { // initial decisions
|
|
DeleteLocalInt(oMe,"nSeekTime");
|
|
if (nParm==0)
|
|
{ // where you stand
|
|
if (GetArea(oMe)==oGArea) { nState=3; fnSpeak("Going to my guard post."); }
|
|
else if (oGArea==GetArea(oThrone)) { nState=1; fnSpeak("Returning to the lair."); }
|
|
else { nState=2; fnSpeak("Seeking the area where my guard post is located."); }
|
|
} // where you stand
|
|
else if (nParm==4)
|
|
{ // mana vault
|
|
if (GetArea(oMe)==GetArea(oVault)) { nState=3; fnSpeak("Going to my guard post."); }
|
|
else { nState=1; fnSpeak("Returning to the lair.");}
|
|
} // mana vault
|
|
else if (nParm==5)
|
|
{ // throne room
|
|
if (GetArea(oMe)==GetArea(oThrone)) { nState=3; fnSpeak("Going to my guard post."); }
|
|
else { nState=1; fnSpeak("Returning to the lair.");}
|
|
} // throne room
|
|
else
|
|
{ // guard point
|
|
if (GetArea(oMe)==oGArea) { nState=3; fnSpeak("Going to my guard post."); }
|
|
else if (oGArea==GetArea(oThrone)) { nState=1; fnSpeak("Returning to the lair."); }
|
|
else { nState=2; fnSpeak("Seeking the area where my guard post is located."); }
|
|
} // guard point
|
|
break;
|
|
} // initial decisions
|
|
case 1: { // return to lair
|
|
SetAILevel(oMe,AI_LEVEL_NORMAL);
|
|
nErr=0;
|
|
if (GetArea(oMe)!=GetArea(oVault))
|
|
{
|
|
if (sID=="SPID") nErr=3;
|
|
else if (sID=="DWF") nErr=2;
|
|
else if (sID=="UNC") nErr=1;
|
|
else if (sID=="UND") nErr=3;
|
|
if (GetIsDay()==TRUE&&GetLocalInt(oMod,GetResRef(oMe)+"_light")==2) nErr=4; // light fatal
|
|
oMove=fnPathNextDestination(GetArea(oMe),sID,nErr);
|
|
if (oMove!=OBJECT_INVALID)
|
|
AssignCommand(oMe,ASActionMoveToObject(oMove,nRun,8.0));
|
|
}
|
|
else { nState=3; fnSpeak("Going to my guard post."); }
|
|
break;
|
|
} // return to lair
|
|
case 2: { // seek out guard location outside of lair
|
|
SetAILevel(oMe,AI_LEVEL_NORMAL);
|
|
nSeekTime++;
|
|
if (nSeekTime==1&&nParm==0)
|
|
{ // create object to move to
|
|
vV.x=fGX; vV.y=fGY; vV.z=fGZ;
|
|
lLoc=Location(oGArea,vV,GetFacing(oMe));
|
|
oNew=CreateObject(OBJECT_TYPE_PLACEABLE,"selfdplc",lLoc);
|
|
SetLocalObject(oNew,"oOwner",oMe);
|
|
SetLocalObject(oMe,"oNewDest",oNew);
|
|
} // create object to move to
|
|
if (nParm==0) oOb=oNew;
|
|
else {
|
|
oOb=OBJECT_INVALID;
|
|
}
|
|
if (nSeekTime<300&&oOb!=OBJECT_INVALID)
|
|
{ // keep trying to get there
|
|
if (nSeekTime==1) nErr=fnMoveToDestination(oOb,TRUE);
|
|
else { nErr=fnMoveToDestination(oOb,FALSE); }
|
|
if (GetArea(oMe)==GetArea(oOb))
|
|
{ // same area
|
|
if (nParm==0) { DestroyObject(oNew); DeleteLocalObject(oMe,"oNewDest"); }
|
|
nState=3;
|
|
} // same area
|
|
} // keep trying to get there
|
|
else if (nParm>0&&nParm<4)
|
|
{ // location
|
|
if (GetArea(oMe)!=GetArea(oGArea))
|
|
{ // not in same location
|
|
if (GetCurrentAction(oMe)!=ACTION_MOVETOPOINT)
|
|
{ // move
|
|
AssignCommand(oMe,ClearAllActions(TRUE));
|
|
AssignCommand(oMe,ActionForceMoveToLocation(lGLoc,TRUE,480.0));
|
|
} // move
|
|
} // not in same location
|
|
else
|
|
{ // arrived
|
|
nState=3;
|
|
} // arrived
|
|
} // location
|
|
else { // teleport when no PCs are present at either location
|
|
if (GetNearestCreature(CREATURE_TYPE_PLAYER_CHAR,PLAYER_CHAR_IS_PC,oOb,1)==OBJECT_INVALID&&GetNearestCreature(CREATURE_TYPE_PLAYER_CHAR,PLAYER_CHAR_IS_PC,oMe,1)==OBJECT_INVALID)
|
|
{ // let's move
|
|
AssignCommand(oMe,ClearAllActions(TRUE));
|
|
AssignCommand(oMe,JumpToObject(oOb));
|
|
if (nParm==0) { DestroyObject(oNew); DeleteLocalObject(oMe,"oNewDest"); }
|
|
nState=3;
|
|
} // let's move
|
|
} // teleport when no PCs are present at either location
|
|
SetLocalInt(oMe,"nSeekTime",nSeekTime);
|
|
break;
|
|
} // seek out guard location outside of lair
|
|
case 3: { // go to guard location
|
|
SetAILevel(oMe,AI_LEVEL_NORMAL);
|
|
DeleteLocalInt(oMe,"nSeekTime");
|
|
if (nParm==0)
|
|
{ // location specific
|
|
vV.x=fGX;
|
|
vV.y=fGY;
|
|
vV.z=fGZ;
|
|
lLoc=Location(oGArea,vV,GetFacing(oMe));
|
|
} // location specific
|
|
else if (nParm==4) lLoc=GetLocation(oVault);
|
|
else if (nParm==5) lLoc=GetLocation(oThrone);
|
|
else
|
|
{ // guard point
|
|
lLoc=lGLoc;
|
|
} // guard point
|
|
fF=GetDistanceBetweenLocations(GetLocation(oMe),lLoc);
|
|
if (fF<=3.0) { nState=4; /* fnSpeak("I am at my guard post."); */}
|
|
else { // move
|
|
if (GetCurrentAction(oMe)!=ACTION_MOVETOPOINT)
|
|
{
|
|
AssignCommand(oMe,ClearAllActions(TRUE));
|
|
AssignCommand(oMe,ActionMoveToLocation(lLoc,nRun));
|
|
}
|
|
break;
|
|
} // move
|
|
break;
|
|
} // go to guard location
|
|
case 4: { // guard location decision
|
|
SetAILevel(oMe,AI_LEVEL_DEFAULT);
|
|
nN=GetCurrentHitPoints(oMe);
|
|
nN2=GetMaxHitPoints(oMe);
|
|
if (nN<=(nN2/2)&&GetArea(oMe)==GetArea(oThrone))
|
|
{ // heal
|
|
nState=6; fnSpeak("I need to rest.");
|
|
} // heal
|
|
else
|
|
{ // maybe wander... maybe heal
|
|
oOb=fnFindHealTarget();
|
|
if (oOb!=OBJECT_INVALID&&fnHasHealSpells()==TRUE) { nState=8; fnSpeak("Some allies near me need healing."); }
|
|
else if (!GetLocalInt(oMe,"bFormationGuard")) { nState=5; }
|
|
else
|
|
{ // set facing
|
|
AssignCommand(oMe,SetFacing(fFacing));
|
|
} // set facing
|
|
} // maybe wander... maybe heal
|
|
break;
|
|
} // guard location decision
|
|
case 5: { // wander
|
|
SetAILevel(oMe,AI_LEVEL_DEFAULT);
|
|
oOb=GetNearestObject(OBJECT_TYPE_WAYPOINT,oMe,d20());
|
|
AssignCommand(oMe,ASActionMoveToObject(oOb,nRun,3.0));
|
|
DelayCommand(4.0,AssignCommand(oMe,ClearAllActions()));
|
|
nState=3;
|
|
break;
|
|
} // wander
|
|
case 6: { // go to heal location
|
|
SetAILevel(oMe,AI_LEVEL_NORMAL);
|
|
oOb=GetWaypointByTag(sID+"_HEAL");
|
|
fF=GetDistanceBetween(oMe,oOb);
|
|
if (fF<=5.0) nState=7;
|
|
else { AssignCommand(oMe,ClearAllActions()); AssignCommand(oMe,ASActionMoveToObject(oOb,nRun,3.0)); }
|
|
break;
|
|
} // go to heal location
|
|
case 7: { // heal
|
|
SetAILevel(oMe,AI_LEVEL_NORMAL);
|
|
nN=GetCurrentHitPoints(oMe);
|
|
nN2=GetMaxHitPoints(oMe);
|
|
if (nN==nN2) { nState=0; fnSpeak("I feel better and am going back to my guard post."); }
|
|
else
|
|
{
|
|
AssignCommand(oMe,PRCForceRest(oMe));
|
|
}
|
|
break;
|
|
} // heal
|
|
case 8: { // heal nearby friendly units
|
|
SetAILevel(oMe,AI_LEVEL_NORMAL);
|
|
oOb=fnFindHealTarget();
|
|
if (oOb!=OBJECT_INVALID)
|
|
{ // try to heal
|
|
if (GetHasSpell(SPELL_CURE_MINOR_WOUNDS,oMe)>0)
|
|
{ AssignCommand(oMe,ActionCastSpellAtObject(SPELL_CURE_MINOR_WOUNDS,oOb)); }
|
|
else if (GetHasSpell(SPELL_CURE_LIGHT_WOUNDS,oMe)>0)
|
|
{ AssignCommand(oMe,ActionCastSpellAtObject(SPELL_CURE_LIGHT_WOUNDS,oOb)); }
|
|
else if (GetHasSpell(SPELL_CURE_MODERATE_WOUNDS,oMe)>0)
|
|
{ AssignCommand(oMe,ActionCastSpellAtObject(SPELL_CURE_MODERATE_WOUNDS,oOb)); }
|
|
else if (GetHasSpell(SPELL_CURE_SERIOUS_WOUNDS,oMe)>0)
|
|
{ AssignCommand(oMe,ActionCastSpellAtObject(SPELL_CURE_SERIOUS_WOUNDS,oOb)); }
|
|
else if (GetHasSpell(SPELL_CURE_CRITICAL_WOUNDS,oMe)>0)
|
|
{ AssignCommand(oMe,ActionCastSpellAtObject(SPELL_CURE_CRITICAL_WOUNDS,oOb)); }
|
|
else if (GetHasSpell(SPELL_AID,oMe)>0)
|
|
{ AssignCommand(oMe,ActionCastSpellAtObject(SPELL_AID,oOb)); }
|
|
else if (GetHasSpell(SPELL_HEALING_CIRCLE,oMe)>0)
|
|
{ AssignCommand(oMe,ActionCastSpellAtObject(SPELL_HEALING_CIRCLE,oOb)); }
|
|
else if (GetHasSpell(SPELL_HEAL,oMe)>0)
|
|
{ AssignCommand(oMe,ActionCastSpellAtObject(SPELL_HEAL,oOb)); }
|
|
else if (GetHasSpell(SPELL_MASS_HEAL,oMe)>0)
|
|
{ AssignCommand(oMe,ActionCastSpellAtObject(SPELL_MASS_HEAL,oOb)); }
|
|
else if (GetHasSpell(SPELL_REGENERATE,oMe)>0)
|
|
{ AssignCommand(oMe,ActionCastSpellAtObject(SPELL_REGENERATE,oOb)); }
|
|
else { nState=4; }
|
|
} // try to heal
|
|
else { nState=4; }
|
|
break;
|
|
} // heal nearby friendly units
|
|
default: break;
|
|
} // main switch
|
|
SetLocalInt(oMe,"nSState",nState);
|
|
} // okay to guard
|
|
else
|
|
{ // combat or something interfering
|
|
DeleteLocalInt(oMe,"nSState");
|
|
} // combat or something interfering
|
|
}
|
|
////////////////////////////////////////////////////////////////////// MAIN
|
|
|
|
/////////////////////////
|
|
// FUNCTIONS
|
|
/////////////////////////
|
|
void fnSpeak(string sSay)
|
|
{ // speak message if Intelligence>8
|
|
int nINT=GetAbilityScore(OBJECT_SELF,ABILITY_INTELLIGENCE);
|
|
if (nINT>8) SpeakString(sSay);
|
|
} // fnSpeak()
|
|
|
|
object fnFindHealTarget()
|
|
{ // remember NO UNDEAD targets!!!
|
|
object oRet=OBJECT_INVALID;
|
|
object oOb;
|
|
object oMe=OBJECT_SELF;
|
|
int nCHP;
|
|
int nMHP;
|
|
float fDist;
|
|
int nC;
|
|
nC=1;
|
|
oOb=GetNearestCreature(CREATURE_TYPE_REPUTATION,REPUTATION_TYPE_FRIEND,oMe,nC,CREATURE_TYPE_PLAYER_CHAR,PLAYER_CHAR_IS_PC);
|
|
fDist=GetDistanceBetween(oMe,oOb);
|
|
while(oOb!=OBJECT_INVALID&&fDist<11.0)
|
|
{ // check PCs
|
|
if (GetLocalInt(oOb,"nIsVampire")!=TRUE&&GetCurrentAction(oOb)!=ACTION_REST)
|
|
{ // not a vampire
|
|
nCHP=GetCurrentHitPoints(oOb);
|
|
nMHP=GetMaxHitPoints(oOb);
|
|
if (nMHP>nCHP) return oOb;
|
|
} // not a vampire
|
|
nC++;
|
|
oOb=GetNearestCreature(CREATURE_TYPE_REPUTATION,REPUTATION_TYPE_FRIEND,oMe,nC,CREATURE_TYPE_PLAYER_CHAR,PLAYER_CHAR_IS_PC);
|
|
fDist=GetDistanceBetween(oMe,oOb);
|
|
} // check PCs
|
|
nC=1;
|
|
oOb=GetNearestCreature(CREATURE_TYPE_REPUTATION,REPUTATION_TYPE_FRIEND,oMe,nC,CREATURE_TYPE_PLAYER_CHAR,PLAYER_CHAR_NOT_PC);
|
|
fDist=GetDistanceBetween(oMe,oOb);
|
|
while(oOb!=OBJECT_INVALID&&fDist<11.0)
|
|
{ // check NPCs
|
|
if (MyPRCGetRacialType(oOb)!=RACIAL_TYPE_UNDEAD&&GetRacialType(oOb)!=RACIAL_TYPE_CONSTRUCT)
|
|
{ // okay to heal
|
|
nCHP=GetCurrentHitPoints(oOb);
|
|
nMHP=GetMaxHitPoints(oOb);
|
|
if (nCHP<=(nMHP/2)) return oOb;
|
|
} // okay to heal
|
|
nC++;
|
|
oOb=GetNearestCreature(CREATURE_TYPE_REPUTATION,REPUTATION_TYPE_FRIEND,oMe,nC,CREATURE_TYPE_PLAYER_CHAR,PLAYER_CHAR_NOT_PC);
|
|
fDist=GetDistanceBetween(oMe,oOb);
|
|
} // check NPCs
|
|
return oRet;
|
|
} // fnFindHealTarget()
|
|
|
|
int fnHasHealSpells()
|
|
{ // returns TRUE if has heal spells
|
|
object oMe=OBJECT_SELF;
|
|
if (GetHasSpell(SPELL_CURE_MINOR_WOUNDS,oMe)>0) return TRUE;
|
|
else if (GetHasSpell(SPELL_CURE_LIGHT_WOUNDS,oMe)>0) return TRUE;
|
|
else if (GetHasSpell(SPELL_CURE_MODERATE_WOUNDS,oMe)>0) return TRUE;
|
|
else if (GetHasSpell(SPELL_CURE_SERIOUS_WOUNDS,oMe)>0) return TRUE;
|
|
else if (GetHasSpell(SPELL_CURE_CRITICAL_WOUNDS,oMe)>0) return TRUE;
|
|
else if (GetHasSpell(SPELL_AID,oMe)>0) return TRUE;
|
|
else if (GetHasSpell(SPELL_HEALING_CIRCLE,oMe)>0) return TRUE;
|
|
else if (GetHasSpell(SPELL_HEAL,oMe)>0) return TRUE;
|
|
else if (GetHasSpell(SPELL_MASS_HEAL,oMe)>0) return TRUE;
|
|
else if (GetHasSpell(SPELL_REGENERATE,oMe)>0) return TRUE;
|
|
return FALSE;
|
|
} // fnHasHealSpells()
|