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