HoS_PRC8/_mod/_module/nss/rts_ai_guard.nss
Jaysyn904 04165202c0 Initial upload
Initial upload
2024-11-25 19:36:07 -05:00

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()