HoS_PRC8/_mod/_module/nss/rtsa_unit_ai.nss
Jaysyn904 e2f4ba74d5 Merged redundant hak files
Merged redundant hak files.  Moved hak scripts into module.  Updated gitignore.  Full Compile.  Added release folder & archive.
2024-12-12 15:02:17 -05:00

1210 lines
37 KiB
Plaintext

///////////////////////////////////////////////////////////////////////////////////
// REAL TIME STRATEGY ADVENTURE - Kit
// FILE: rtsa_unit_ai
// NAME: This is the main script that controls Unit Artificial Intelligence
// SCRIPTED BY: Deva Bryson Winblood
// DATE: 4/13/2003
///////////////////////////////////////////////////////////////////////////////////
#include "rtsa_headera" // ai
#include "rtsa_headere" // errors
#include "rtsa_headerp" // parser
#include "antistuck_h"
/////////////////////////////////////////
// PROTOTYPES
/////////////////////////////////////////
void fnMainAIRoutine(); // The main switch
void fnFollowPC(int nType=0); // FOLLOW command
void fnRoam(); // ROAM command
void fnSeek(); // SEEK AND DESTROY command
void fnGuardLair(); // GUARD LAIR command
void fnGuardLocation(); // GUARD SPECIFIC LOCATION command
void fnAttackLocation(); // ATTACK SPECIFIC LOCATION command
void fnHeal(); // return to heal location in lair and heal
void fnHide(); // Use HIDE and MOVE SILENTLY skills
void fnSearch(); // Search for and disarm traps
void fnRecon(); // reconnoiter command
void fnBurrow(); // Burrow command
void fnDestroyObject(); // Destroy Object
void fnOpenObject(); // Open Object
void fnDie(); // Die
void fnRetreat(); // flee to base
void fnSleep(); // sleep and recover spells
void fnPatrol(); // Walk up to a 4 point patrol path
void fnBreed(); // breed creatures
void fnFlee(string sWhere="NA"); // Flee to base, sunlight, insanity
////////////////////////////////////////////////////////// MAIN /////////////////
void main()
{
object oMod=GetModule();
object oMe=OBJECT_SELF;
int nDelay=GetLocalInt(oMod,"nRTSAIDelay");
object oAttacker=GetLastAttacker();
float fDist=-1.0;
int nSpeed=GetLocalInt(oMe,"nSpeed");
object oEnemy=GetNearestCreature(CREATURE_TYPE_PERCEPTION,PERCEPTION_SEEN,OBJECT_SELF,1,CREATURE_TYPE_REPUTATION,REPUTATION_TYPE_ENEMY,CREATURE_TYPE_IS_ALIVE,TRUE);
int nMState=GetLocalInt(OBJECT_SELF,"nMState");
if (!GetIsDead(oAttacker)) fDist=GetDistanceToObject(oAttacker);
SetLocalInt(OBJECT_SELF,"nLastDelaySec",GetTimeSecond()); // set monitor for HBKICK
if (!IsInConversation(oMe))
{ // is not talking
if (fDist==-1.0||fDist>20.0)
{ // Last attacker is not near
if ((oEnemy!=OBJECT_INVALID&&(nMState>27&&nMState<51))||oEnemy==OBJECT_INVALID||GetLocalInt(oMe,"nAggression")==1)
{ // No enemies perceived nearby
if (GetLocalInt(oMe,"nAIBusy")!=TRUE)
{ // Not in busy mode
fnMainAIRoutine();
} // Not in busy mode
} // No enemies perceived nearby
} // Last attacker is not near
} // is not talking
// DelayCommand(IntToFloat(nDelay+nSpeed),ExecuteScript("rtsa_unit_ai",oMe));
ExecuteScript("rtsa_ai_smonitor",oMe);
} // main()
/////////////////////////////////////////////////////////// MAIN /////////////////
///////////////////////////////////////
// FUNCTIONS
///////////////////////////////////////
//--------------------------------------------------[ fnMainAIRoutine ]------
void fnMainAIRoutine()
{ // main switch statement for AI
object oMe=OBJECT_SELF;
int nMState=GetLocalInt(oMe,"nMState"); // main state
int nSState=GetLocalInt(oMe,"nSState"); // sub state
object oDest=GetLocalObject(oMe,"oDest"); // Destination Waypoint
object oPer=GetNearestCreature(CREATURE_TYPE_PERCEPTION,PERCEPTION_SEEN,oMe,CREATURE_TYPE_REPUTATION,REPUTATION_TYPE_ENEMY,CREATURE_TYPE_IS_ALIVE,TRUE);
int nCHP=GetCurrentHitPoints(oMe);
int nMHP=GetMaxHitPoints(oMe);
float fDist;
string sID=GetLocalString(oMe,"sTeamID");
fnDebug("["+GetName(oMe)+"] MainState:"+IntToString(nMState)+" SubState:"+IntToString(nSState));
switch(nMState)
{ // Main Switch -----------------------------------<<<<<
case 1: { // Follow Leader
SetAILevel(oMe,AI_LEVEL_DEFAULT);
if(GetLocalString(oDest,"sTeamID")!="FREE")
fnFollowPC();
else
fnFollowPC(1);
break;
} // Follow Leader
case 2: { // Protect
SetAILevel(oMe,AI_LEVEL_NORMAL);
fnFollowPC(1);
break;
} // Protect
case 3: {// Guard Location
SetAILevel(oMe,AI_LEVEL_DEFAULT);
fnGuardLocation();
break;
} // Guard Location
case 4: {// Attack Location
SetAILevel(oMe,AI_LEVEL_NORMAL);
fnAttackLocation();
break;
} // Attack Location
case 5: {// Roam
SetAILevel(oMe,AI_LEVEL_DEFAULT);
fnRoam();
break;
} // Roam
case 6: {// Seek and Destroy
SetAILevel(oMe,AI_LEVEL_NORMAL);
fnSeek();
break;
} // Seek and Destroy
case 7: {// Scout
SetAILevel(oMe,AI_LEVEL_NORMAL);
ExecuteScript("rtsa_ai_scout",oMe);
break;
} // Scout
case 8: {// Heal
SetAILevel(oMe,AI_LEVEL_NORMAL);
fnHeal();
break;
} // Heal
case 9: {// Hide
SetAILevel(oMe,AI_LEVEL_DEFAULT);
fnHide();
break;
} // Hide
case 10: {// Search
SetAILevel(oMe,AI_LEVEL_DEFAULT);
fnSearch();
break;
} // Search
case 11: {// Recon
SetAILevel(oMe,AI_LEVEL_DEFAULT);
fnRecon();
break;
} // Recon
case 12: {// Burrow
SetAILevel(oMe,AI_LEVEL_NORMAL);
fnBurrow();
break;
} // Burrow
case 13: {// Destroy Object
SetAILevel(oMe,AI_LEVEL_DEFAULT);
fnDestroyObject();
break;
} // Destroy Object
case 14: {// Trade
SetAILevel(oMe,AI_LEVEL_NORMAL);
ExecuteScript("rtsa_ai_trade",oMe);
break;
} // Trade
case 15: {// Deliver Message
SetAILevel(oMe,AI_LEVEL_NORMAL);
ExecuteScript("rtsa_ai_message",oMe);
break;
} // Deliver Message
case 16: {// Build
SetAILevel(oMe,AI_LEVEL_DEFAULT);
SetLocalInt(oMe,"nParm",1);
if(nSState==0) ExecuteScript("rtsa_su_cb",oMe);
else ExecuteScript("rtsa_ai_cb",oMe);
break;
} // Build
case 17: {// Craft
SetAILevel(oMe,AI_LEVEL_DEFAULT);
SetLocalInt(oMe,"nParm",2);
if(nSState==0) ExecuteScript("rtsa_su_cb",oMe);
else ExecuteScript("rtsa_ai_cb",oMe);
break;
} // Craft
case 18: {// Upgrade
SetAILevel(oMe,AI_LEVEL_DEFAULT);
ExecuteScript("rtsa_upgrade",oMe);
break;
} // Upgrade
case 19: {// Breed
SetAILevel(oMe,AI_LEVEL_NORMAL);
ExecuteScript("rtsa_ai_breed",oMe);
break;
} // Breed
case 20: {// Open Object
SetAILevel(oMe,AI_LEVEL_DEFAULT);
fnOpenObject();
break;
} // Open Object
case 21: {// Guard the Lair
SetAILevel(oMe,AI_LEVEL_DEFAULT);
fnGuardLair();
break;
} // Guard the Lair
case 22: {// Stand
SetAILevel(oMe,AI_LEVEL_DEFAULT);
break;
} // Stand
case 23: {// Sleep
SetAILevel(oMe,AI_LEVEL_NORMAL);
fnSleep();
break;
} // Sleep
case 24: {// Patrol
SetAILevel(oMe,AI_LEVEL_NORMAL);
fnPatrol();
break;
} // Patrol
case 25: {// Die
SetAILevel(oMe,AI_LEVEL_DEFAULT);
fnDie();
break;
} // Die
case 26: {// Manage Inventory
SetAILevel(oMe,AI_LEVEL_DEFAULT);
break;
} // Manage Inventory
case 27: {// Heal Nearby
SetAILevel(oMe,AI_LEVEL_NORMAL);
ExecuteScript("rtsa_ai_healn",oMe);
break;
} // Heal Nearby
case 28: {// retreat
SetAILevel(oMe,AI_LEVEL_DEFAULT);
fnRetreat();
break;
} // retreat
case 30: {// harvest
SetAILevel(oMe,AI_LEVEL_NORMAL);
ExecuteScript("rtsa_ai_harv",oMe);
break;
} // harvest
case 40: {// Flee to base
SetAILevel(oMe,AI_LEVEL_NORMAL);
fnFlee(sID+"_START");
break;
} // Flee to base
case 41: {// Flee sunlight
SetAILevel(oMe,AI_LEVEL_NORMAL);
fnFlee("SUN");
break;
} // Flee sunlight
case 42: {// Insanity
SetAILevel(oMe,AI_LEVEL_DEFAULT);
fnFlee("NA");
break;
} // Insanity
case 51: { // Custom command 1
SetAILevel(oMe,AI_LEVEL_DEFAULT);
ExecuteScript("rtsa_ai_cust1",oMe);
break;
} // Custom command 1
case 52: { // Custom command 2
SetAILevel(oMe,AI_LEVEL_DEFAULT);
ExecuteScript("rtsa_ai_cust2",oMe);
break;
} // Custom command 2
case 53: { // Custom command 3
SetAILevel(oMe,AI_LEVEL_NORMAL);
ExecuteScript("rtsa_ai_cust3",oMe);
break;
} // Custom Command 3
default: { // default
SetAILevel(oMe,AI_LEVEL_DEFAULT);
SetLocalInt(oMe,"nSpeed",0);
break;
} // default
} // Main Switch -----------------------------------<<<<<
} // fnMainAIRoutine()
//----------------------------------------------------[ fnFollowPC ]----------
void fnFollowPC(int nType=0)
{ // follow a PC
object oMe=OBJECT_SELF;
object oMod=GetModule();
string sID=GetLocalString(oMe,"sTeamID");
object oLeader=GetLocalObject(oMod,"oTeamLead"+sID);
float fClose=3.0;
int nParm=GetLocalInt(oMe,"nParm");
float fDist;
if (nType==1) oLeader=GetLocalObject(oMe,"oDest");
fDist=GetDistanceToObject(oLeader);
if (nParm==2) fClose=7.0;
if (fDist==-1.0||fDist>40.0)
{ // too far away - teleport
AssignCommand(oMe,ClearAllActions());
AssignCommand(oMe,JumpToObject(oLeader));
AssignCommand(oMe,ActionForceFollowObject(oLeader,fClose));
} // too far away - teleport
else
{ // keep following
AssignCommand(oMe,ActionForceFollowObject(oLeader,fClose));
} // keep following
} // fnFollowPC()
//-----------------------------------------------------[ Roam ]---------------
void fnRoam()
{ // Roam about - only seeking to leave an area 1 on 8
object oMe=OBJECT_SELF;
object oArea=GetArea(oMe);
int nR=d8();
int nResults;
object oDest=GetLocalObject(oMe,"oDest");
int nSState=GetLocalInt(oMe,"nSState");
fnDebug(" fnRoam() was called by "+GetName(oMe)+" State:"+IntToString(nSState)+" Destination:"+GetTag(oDest));
switch(nSState)
{ // state
case 0: { // find destination
fnFlushS("Pathing");
if (nR==1)
{ // leave area
oDest=fnRandomTrans(oArea);
oDest=GetTransitionTarget(oDest);
fnDebug(" Random Trans:"+GetTag(oDest));
if (oDest!=OBJECT_INVALID)
{
SetLocalInt(oMe,"nSState",1);
nSState=1;
}
SetLocalObject(oMe,"oDest",oDest);
} // leave area
else
{ // random object here
oDest=fnRandomObject(oArea);
if (oDest!=OBJECT_INVALID)
SetLocalInt(oMe,"nSState",1);
fnDebug(" Random Object:"+GetTag(oDest));
SetLocalObject(oMe,"oDest",oDest);
} // random object here
} // find destination
case 1: { // move to destination
if (nSState==1)
{ // if proper state
fnDebug(" Calling fnMovePath");
nResults=fnMovePath(oDest,TRUE);
if (nResults==1||nResults==-1)
{ // arrived or error
SetLocalInt(oMe,"nSState",0);
} // arrived or error
} // if proper state
break;
} // move to destination
default: { SetLocalInt(oMe,"nSState",0); break; }
} // state
} // fnRoam()
//------------------------------------------------[ SEEK AND DESTROY ]--------
void fnSeek()
{ // seek out enemies and destroy
// oLArea1 & oLArea2 - remembers the previous 2 areas visited
object oMe=OBJECT_SELF;
int nSState=GetLocalInt(oMe,"nSState");
object oDest=GetLocalObject(oMe,"oDest");
int nErr; // error trapping
object oH; // object handle
float fDist; // used to measure distances
int nN; // number
object oArea=GetArea(oMe);
object oLArea1=GetLocalObject(oMe,"oLArea1");
object oLArea2=GetLocalObject(oMe,"oLArea2");
if (nSState==0)
{ // find enemy or next destination
fnFlushS("Pathing");
fnDebug(" Seek - State: 0");
oH=GetNearestCreature(CREATURE_TYPE_PERCEPTION,PERCEPTION_SEEN,oMe,CREATURE_TYPE_REPUTATION,REPUTATION_TYPE_ENEMY,CREATURE_TYPE_IS_ALIVE,TRUE);
if (oH!=OBJECT_INVALID)
{
oDest=oH;
SetLocalObject(oMe,"oDest",oH);
}
if (oH==OBJECT_INVALID)
{ // no enemies nearby
if (d8()>4)
{ // seek area transition
oH=fnRandomTrans(oArea);
oH=GetTransitionTarget(oH);
nN=0;
while((GetArea(oH)==oLArea1||GetArea(oH)==oLArea2)&&nN<3)
{ // find good transition
oH=fnRandomTrans(oArea);
oH=GetTransitionTarget(oH);
nN++;
} // find good transition
if (GetArea(oH)!=oLArea1&&GetArea(oH)!=oLArea2)
{ // found a good target
SetLocalObject(oMe,"oDest",oH);
oDest=oH;
SetLocalInt(oMe,"nSState",2);
nSState=2;
SetLocalObject(oMe,"oLArea2",oLArea1);
SetLocalObject(oMe,"oLArea1",oArea);
} // found a good target
} // seek area transition
else
{ // seek object
oH=fnRandomObject(oArea);
if (oH!=OBJECT_INVALID)
{ // good object
oDest=oH;
SetLocalInt(oMe,"nSState",2);
SetLocalObject(oMe,"oDest",oH);
nSState=2;
} // good object
} // seek object
} // no enemies nearby
else
{ // see enemy - engage
SetLocalObject(oMe,"oDest",oH);
SetLocalInt(oMe,"nSState",1);
nSState=1;
} // see enemy - engage
} // find enemy or next destination
if (nSState==1)
{ // engage enemy
AssignCommand(oMe,ASActionMoveToObject(oDest,TRUE,2.0));
fDist=GetDistanceToObject(oDest);
if (fDist==-1.0||fDist>60.0)
{ // no longer in sight
SetLocalInt(oMe,"nSState",0);
AssignCommand(oMe,ClearAllActions());
} // no longer in sight
} // engage enemy
if (nSState==2)
{ // move to destination
fnDebug(" Seek - State: 2");
nErr=fnMoveToDestination(oDest,TRUE);
if (nErr==1)
{ // should be there
fDist=GetDistanceToObject(oDest);
if (fDist!=-1.0&&fDist<3.0)
{ // we are indeed there
SetLocalInt(oMe,"nSState",0);
AssignCommand(oMe,ClearAllActions());
} // we are indeed there
} // should be there
else if (nErr==-1)
{ // can't reach there
if(GetArea(oDest)!=oArea)
{ // failed to reach another area
SetLocalObject(oMe,"oLArea1",oLArea2);
DeleteLocalObject(oMe,"oLArea2");
} // failed to reach another area
SetLocalInt(oMe,"nSState",0);
AssignCommand(oMe,ClearAllActions());
AssignCommand(oMe,ActionSpeakString("I cannot get there."));
AssignCommand(oMe,PlayVoiceChat(VOICE_CHAT_CANTDO));
SetLocalInt(oMe,"nASC",0);
SetLocalObject(oMe,"oDest",OBJECT_INVALID);
} // can't reach there
} // move to destination
} // fnSeek()
//--------------------------------------------[ GUARD LAIR ]------------------
void fnGuardLair()
{ // Guard the lair command
object oMe=OBJECT_SELF;
object oArea=GetArea(oMe);
object oH;
float fDist;
int nErr;
string sTeamID=GetLocalString(oMe,"sTeamID");
object oDest=GetLocalObject(oMe,"oDest");
int nSState=GetLocalInt(oMe,"nSState");
switch(nSState)
{ // Guard lair switch
case 0: { // find out if in lair
oH=GetWaypointByTag(sTeamID+"_START");
if (GetDistanceToObject(oH)==-1.0)
{ // different area
nSState=1;
oDest=oH;
SetLocalObject(oMe,"oDest",oDest);
} // different area
else
{ // same area
nSState=2;
} // same area
} // find out if in lair
case 1: { // Move to lair
if (nSState==1)
{ // do it
fDist=GetDistanceToObject(oDest);
if (fDist==-1.0||fDist>4.0)
{ // not close enough
nErr=fnMovePath(oDest,TRUE);
if (nErr==-1) fnError("RTSA ERROR: '"+GetName(oMe)+"' cannot reach "+sTeamID+"_START.");
} // not close enough
else
{ // arrived
nSState=2;
} // arrived
} // do it
break;
} // Move to lair
case 2: { // Pick new target
oH=fnRandomObject(oArea);
if (oH!=OBJECT_INVALID)
{ // good object
oDest=oH;
SetLocalInt(oMe,"nSState",3);
SetLocalObject(oMe,"oDest",oH);
nSState=3;
} // good object
} // Pick new target
case 3: { // Move to target
if (nSState==3)
{ // do it
fDist=GetDistanceToObject(oDest);
if (fDist==-1.0||fDist>4.0)
{ // not close enough
nErr=fnMovePath(oDest,TRUE);
if (nErr==-1)
{ // cannot reach
nSState=0;
} // cannot reach
} // not close enough
else
{ // arrived
nSState=2;
} // arrived
} // do it
break;
} // Move to target
default: { nSState=0; break; }
} // Guard lair switch
SetLocalInt(oMe,"nSState",nSState);
} // fnGuardLair()
//--------------------------------------------------[ fnGuardLocation ]-------
void fnGuardLocation()
{ // if not at location move to it - if chase enemy return to this location
// when done chasing.
object oMe=OBJECT_SELF;
object oDest=GetLocalObject(oMe,"oDest");
float fDist=GetDistanceToObject(oDest);
int nErr;
if (fDist==-1.0||fDist>6.9||oDest==OBJECT_INVALID)
{ // move to area to guard
if (oDest!=OBJECT_INVALID)
{ // !OI
nErr=fnMovePath(oDest,TRUE);
if (nErr==-1)
{ // error reaching location - switch to guard the lair
SetLocalInt(oMe,"nMState",21);
SetLocalInt(oMe,"nSState",0);
} // error reaching location - switch to guard the lair
} // !OI
else
{ // target missing switch to Guard The Lair
SetLocalInt(oMe,"nMState",21);
SetLocalInt(oMe,"nSState",0);
} // target missing switch to Guard The Lair
} // move to area to guard
else
{ // in area make sure pathing stack is empty
nErr=fnSizeS("Pathing");
if (nErr!=0)
fnFlushS("Pathing");
} // in area make sure pathing stack is empty
} // fnGuardLocation()
//------------------------------------------------[ fnAttackLocation ]--------
void fnAttackLocation()
{ // go to location - wander short distances from there looking for targets
object oMe=OBJECT_SELF;
object oDest=GetLocalObject(oMe,"oDest");
float fDist=GetDistanceToObject(oDest);
int nErr;
if (fDist==-1.0||fDist>6.9||oDest==OBJECT_INVALID)
{ // move to location
if (oDest!=OBJECT_INVALID)
{ // !OI
nErr=fnMovePath(oDest,TRUE);
if (nErr==-1)
{ // error reaching location - switch to guard the lair
SetLocalInt(oMe,"nMState",21);
SetLocalInt(oMe,"nSState",0);
} // error reaching location - switch to guard the lair
} // !OI
else
{ // target missing switch to Guard The Lair
SetLocalInt(oMe,"nMState",21);
SetLocalInt(oMe,"nSState",0);
} // target missing switch to Guard The Lair
} // move to location
else
{ // pick nearby location
oDest=fnRandomObject(GetArea(oMe),0);
AssignCommand(oMe,ASActionMoveToObject(oDest));
DelayCommand(10.0,AssignCommand(oMe,ClearAllActions()));
} // pick nearby location
} // fnAttackLocation()
void fnHeal()
{ // return to healing location in lair and heal
object oMe=OBJECT_SELF;
object oDest=GetLocalObject(oMe,"oDest");
float fDist=GetDistanceToObject(oDest);
int nSState=GetLocalInt(oMe,"nSState");
int nMHP=GetMaxHitPoints(oMe);
int nCHP=GetCurrentHitPoints(oMe);
int nPrev=GetLocalInt(oMe,"nPrev");
object oPrev=GetLocalObject(oMe,"oPrev");
string sID=GetLocalString(oMe,"sTeamID");
int nHealAmt=1+GetAbilityModifier(ABILITY_CONSTITUTION,oMe);
effect eHeal;
int nErr;
if (nHealAmt<1) nHealAmt=1;
eHeal=EffectHeal(nHealAmt);
if (nMHP==nCHP)
{ // healed
AssignCommand(oMe,ClearAllActions());
SetLocalInt(oMe,"nMState",nPrev);
SetLocalInt(oMe,"nSState",0);
SetLocalObject(oMe,"oDest",oPrev);
} // healed
else
{ // needs healing
switch(nSState)
{ // heal sub-state
case 0: { // find destination heal location
oDest=GetWaypointByTag(sID+"_HEAL");
if (oDest!=OBJECT_INVALID)
{ // valid location
SetLocalInt(oMe,"nSState",1);
SetLocalObject(oMe,"oDest",oDest);
nErr=fnMovePath(oDest,TRUE); // start moving
} // valid location
else
{ // not valid
AssignCommand(oMe,ClearAllActions());
if (GetAbilityScore(oMe,ABILITY_INTELLIGENCE)>7)
AssignCommand(oMe,SpeakString("I don't know where the healing location is."));
SetLocalInt(oMe,"nMState",nPrev);
SetLocalInt(oMe,"nSState",0);
SetLocalObject(oMe,"oDest",oPrev);
} // not valid
break;
} // find destination heal location
case 1: { // await arrival at heal location
nErr=fnMovePath(oDest,TRUE);
if (nErr==1)
{ // arrived
SetLocalInt(oMe,"nSState",2);
} // arrived
else if (nErr==-1)
{ // cannot reach
AssignCommand(oMe,ClearAllActions());
if (GetAbilityScore(oMe,ABILITY_INTELLIGENCE)>7)
AssignCommand(oMe,SpeakString("I cannot reach the healing location."));
SetLocalInt(oMe,"nMState",nPrev);
SetLocalInt(oMe,"nSState",0);
SetLocalObject(oMe,"oDest",oPrev);
} // cannot reach
break;
} // await arrival at heal location
case 2: { // start heal process
AssignCommand(oMe,ActionPlayAnimation(ANIMATION_LOOPING_DEAD_BACK,1.0,31.0));
DelayCommand(30.0,ApplyEffectToObject(DURATION_TYPE_INSTANT,eHeal,oMe,1.0));
break;
} // start heal process
} // heal sub-state
} // needs healing
} // fnHeal()
void fnHide()
{ // use the HIDE skill
object oMe=OBJECT_SELF;
AssignCommand(oMe,ActionUseSkill(SKILL_HIDE,oMe));
AssignCommand(oMe,ActionUseSkill(SKILL_MOVE_SILENTLY,oMe));
} // use the HIDE skill
void fnSearch()
{ // search for and disarm traps
object oMe=OBJECT_SELF;
int nPrev=GetLocalInt(oMe,"nPrev");
int nSState=GetLocalInt(oMe,"nSState");
object oPrev=GetLocalObject(oMe,"oPrev");
object oDest=GetLocalObject(oMe,"oDest");
int nC;
int nD;
float fDist;
switch(nSState)
{ // search and disarm state
case 0: { // look for nearby traps
nC=1;
oDest=GetNearestObject(OBJECT_TYPE_TRIGGER,oMe,nC);
fDist=GetDistanceToObject(oDest);
while(oDest!=OBJECT_INVALID&&nSState==0&&fDist<15.1)
{ // check for traps
if (GetTrapDetectable(oDest)==TRUE&&GetTrapDisarmable(oDest)==TRUE)
{ // check to see if detected
nD=d20()+GetSkillRank(SKILL_SEARCH,oMe)-GetTrapDetectDC(oDest);
if (nD>-1)
{ // detected
SetLocalObject(oMe,"oDest",oDest);
SetLocalInt(oMe,"nSState",1);
nSState=1;
} // detected
} // check to see if detected
if (nSState==0)
{ // next trap
nC++;
oDest=GetNearestObject(OBJECT_TYPE_TRIGGER,oMe,nC);
fDist=GetDistanceToObject(oDest);
} // next trap
} // check for traps
if (nSState==0)
{ // no traps detected
if(GetAbilityScore(oMe,ABILITY_INTELLIGENCE)>7)
AssignCommand(oMe,SpeakString("I don't think there are any traps here."));
SetLocalInt(oMe,"nSState",2);
} // no traps detected
break;
} // look for nearby traps
case 1: { // disarm trap
AssignCommand(oMe,ActionUseSkill(SKILL_DISABLE_TRAP,oDest));
if (GetAbilityScore(oMe,ABILITY_INTELLIGENCE)>7)
AssignCommand(oMe,SpeakString("I see a trap. I'll try to disarm it."));
SetLocalInt(oMe,"nSState",0);
SetLocalObject(oMe,"oDest",OBJECT_INVALID);
break;
} // disarm trap
case 2: { // no more traps
AssignCommand(oMe,ClearAllActions());
SetLocalInt(oMe,"nMState",nPrev);
SetLocalInt(oMe,"nSState",0);
SetLocalObject(oMe,"oDest",oPrev);
break;
} // no more traps
} // search and disarm state
} // search for and disarm traps
void fnRecon()
{ // reconnoiter
object oMe=OBJECT_SELF;
int nParm=GetLocalInt(oMe,"nParm");
float fAheadDist=3.0;
float fDX;
float fDY;
float fDZ;
float fMX=0.0;
float fMY=0.0;
string sID=GetLocalString(oMe,"sTeamID");
object oMod=GetModule();
object oLead=GetLocalObject(oMe,"oDest"); // who to follow
location lRecon;
float fFacing=GetFacing(oLead);
vector vVecPC=GetPosition(oLead);
float fLX=vVecPC.x;
float fLY=vVecPC.y;
float fLZ=vVecPC.z;
vector vNewVec;
int nRun=GetLocalInt(oMe,"nRun");
float fDist=GetDistanceToObject(oLead);
int nReconV=GetLocalInt(oMe,"nRecon");
if ((fDist!=-1.0)&&(nReconV!=TRUE))
SetLocalInt(oMe,"nRecon",TRUE);
if (GetLocalInt(oMe,"nRecon")==TRUE)
{ // was near object when recon initiated
if (oLead!=OBJECT_INVALID)
{ // valid leader
if (nParm==2) fAheadDist=7.0;
else if (nParm==3) fAheadDist=10.0;
else if (nParm==4) fAheadDist=15.0;
else if (nParm==5) fAheadDist=20.0;
else if (nParm==6) fAheadDist=30.0;
fnDebug("["+GetName(oMe)+"]Recon:("+FloatToString(fLX)+","+FloatToString(fLY)+","+FloatToString(fLZ)+") Ahead Dist:"+FloatToString(fAheadDist));
if (fFacing>335.0||fFacing<25.0)
{ // east
fMX=1.0;
} // east
else if (fFacing>291.0&&fFacing<335.1)
{ // south east
fMX=0.75;
fMY=-0.75;
} // south east
else if (fFacing>250.0&&fFacing<291.1)
{ // south
fMY=-1.0;
} // south
else if (fFacing>200.0&&fFacing<250.1)
{ // south west
fMX=-0.75;
fMY=-0.75;
} // south west
else if (fFacing>160.0&&fFacing<200.1)
{ // west
fMX=-1.0;
} // west
else if (fFacing>110.0&&fFacing<160.1)
{ // north west
fMX=-0.75;
fMY=0.75;
} // north west
else if (fFacing>70.0&&fFacing<110.1)
{ // north
fMY=1.0;
} // north
else
{ // north east
fMY=0.75;
fMX=0.75;
} // north east
fDX=fLX+(fMX*fAheadDist);
fDY=fLY+(fMY*fAheadDist);
fDZ=fLZ;
if (fDX<0.0) fDX=0.0;
if (fDY<0.0) fDY=0.0;
fnDebug(" MULTIPLIERS: X:"+FloatToString(fMX)+" Y:"+FloatToString(fMY));
fnDebug(" Facing:"+FloatToString(fFacing)+" Recon to:"+FloatToString(fDX)+","+FloatToString(fDY)+","+FloatToString(fDZ));
vNewVec=Vector(fDX,fDY,fDZ);
//vNewVec=VectorNormalize(vNewVec);
if (GetArea(oLead)!=GetArea(oMe))
{ // jump to leader
AssignCommand(oMe,ClearAllActions());
AssignCommand(oMe,JumpToObject(oLead));
} // jump to leader
else
{ // same area
lRecon=Location(GetArea(oMe),vNewVec,fFacing);
AssignCommand(oMe,ClearAllActions());
AssignCommand(oMe,ActionMoveToLocation(lRecon,nRun));
} // same area
} // valid leader
} // was near object when recon initiated
else
{ // cannot recon on that unit - prevent cheating
if(GetAbilityScore(oMe,ABILITY_INTELLIGENCE)>7)
AssignCommand(oMe,SpeakString("I do not see that recon leader here. I therefor can no longer recon."));
SetLocalInt(oMe,"nMState",0);
SetLocalInt(oMe,"nSState",0);
} // cannot recon on that unit - prevent cheating
} // fnRecon()
void fnBurrow()
{ // dig into the ground and wait
object oMe=OBJECT_SELF;
object oBurrow=GetLocalObject(oMe,"oDest");
int nSState=GetLocalInt(oMe,"nSState");
string sID=GetLocalString(oMe,"sTeamID");
object oWP=GetWaypointByTag(sID+"_LIMBO");
float fDist;
int nC;
int nEnemy=FALSE;
switch (nSState)
{ // burrow switch
case 0: { // play animation - digging
AssignCommand(oMe,ActionPlayAnimation(ANIMATION_LOOPING_GET_LOW,1.0,9.0));
SetLocalInt(oMe,"nSState",1);
break;
} // play animation - digging
case 1: { // place scorch mark + dig
AssignCommand(oMe,ActionPlayAnimation(ANIMATION_LOOPING_GET_LOW,1.0,9.0));
oBurrow=CreateObject(OBJECT_TYPE_PLACEABLE,"rtsa_burrow",GetLocation(oMe),FALSE);
SetLocalObject(oMe,"oDest",oBurrow);
SetLocalInt(oMe,"nSState",2);
break;
} // place scorch mark + dig
case 2: { // teleport to limbo
AssignCommand(oMe,ClearAllActions());
AssignCommand(oMe,JumpToObject(oWP));
SetLocalInt(oMe,"nSState",3);
break;
} // teleport to limbo
case 3: { // wait for enemies
nC=1;
oWP=GetNearestObject(OBJECT_TYPE_CREATURE,oBurrow,nC);
fDist=GetDistanceBetween(oWP,oBurrow);
while(fDist<10.1&&oWP!=OBJECT_INVALID&&nEnemy==FALSE)
{ // look for enemies
if (GetIsEnemy(oWP)==TRUE) nEnemy=TRUE;
else
{ // continue looking
nC++;
oWP=GetNearestObject(OBJECT_TYPE_CREATURE,oBurrow,nC);
fDist=GetDistanceBetween(oWP,oBurrow);
} // continue looking
} // look for enemies
if (nEnemy==TRUE)
{ // enemy time
AssignCommand(oMe,ClearAllActions());
AssignCommand(oMe,JumpToObject(oBurrow));
DestroyObject(oBurrow,2.0);
SetLocalInt(oMe,"nSState",0);
} // enemy time
break;
} // wait for enemies
} // burrow switch
} // fnBurrow()
void fnDestroyObject()
{ // Destroy object
object oMe=OBJECT_SELF;
object oDest=GetLocalObject(oMe,"oDest");
float fDist=GetDistanceToObject(oDest);
int nErr;
if (GetArea(oDest)!=GetArea(oMe))
{ // different area
nErr=fnMovePath(oDest,TRUE);
if (nErr==-1)
{ // cannot reach
AssignCommand(oMe,ClearAllActions());
AssignCommand(oMe,SpeakString("I cannot reach the object I am to destroy."));
SetLocalInt(oMe,"nMState",0);
} // cannot reach
} // different area
else
{ // same area
if (fDist>3.0)
{ // too far away
nErr=fnMoveToDestination(oDest,TRUE);
if (nErr==-1)
{ // cannot reach
AssignCommand(oMe,ClearAllActions());
AssignCommand(oMe,SpeakString("I cannot reach the object I am to destroy."));
SetLocalInt(oMe,"nMState",0);
} // cannot reach
} // too far away
else
{ // close enough
if (GetPlotFlag(oDest)==TRUE)
{ // plot item
AssignCommand(oMe,ClearAllActions());
AssignCommand(oMe,SpeakString("I cannot possibly destroy that object."));
SetLocalInt(oMe,"nMState",0);
} // plot item
else
{ // attack it
AssignCommand(oMe,ActionAttack(oDest));
} // attack it
} // close enough
} // same area
} // fnDestroyObject()
void fnOpenObject()
{ // Destroy object
object oMe=OBJECT_SELF;
object oDest=GetLocalObject(oMe,"oDest");
float fDist=GetDistanceToObject(oDest);
int nErr;
if (GetArea(oDest)!=GetArea(oMe))
{ // different area
nErr=fnMovePath(oDest,TRUE);
if (nErr==-1)
{ // cannot reach
AssignCommand(oMe,ClearAllActions());
AssignCommand(oMe,SpeakString("I cannot reach the object I am to destroy."));
SetLocalInt(oMe,"nMState",0);
} // cannot reach
} // different area
else
{ // same area
if (fDist>3.0)
{ // too far away
nErr=fnMoveToDestination(oDest,TRUE);
if (nErr==-1)
{ // cannot reach
AssignCommand(oMe,ClearAllActions());
AssignCommand(oMe,SpeakString("I cannot reach the object I am to destroy."));
SetLocalInt(oMe,"nMState",0);
} // cannot reach
} // too far away
else
{ // close enough
if (GetLocked(oDest)==TRUE)
{ // attempt to unlock
nErr=d20()+GetSkillRank(SKILL_OPEN_LOCK,oMe);
if (nErr>=GetLockUnlockDC(oDest))
{ // open the lock
AssignCommand(oMe,ActionPlayAnimation(ANIMATION_LOOPING_GET_MID,1.0,3.0));
AssignCommand(oMe,ActionDoCommand(SetLocked(oDest,FALSE)));
AssignCommand(oMe,ActionDoCommand(AssignCommand(oDest,SpeakString("*click*"))));
} // open the lock
} // attempt to unlock
else
{ // open the object
AssignCommand(oMe,ActionOpenDoor(oDest));
AssignCommand(oMe,ActionDoCommand(SetLocalInt(oMe,"nMState",0)));
} // open the object
} // close enough
} // same area
} // fnOpenObject()
void fnDie()
{ // self terminate
object oMe=OBJECT_SELF;
int nMHP=GetMaxHitPoints(oMe);
effect eDie;
nMHP=nMHP*2;
eDie=EffectDamage(nMHP);
ApplyEffectToObject(DURATION_TYPE_INSTANT,eDie,oMe,1.0);
} // fnDie()
void fnRetreat()
{ // flee to o<teamID>RETREAT location or sID_START
object oMe=OBJECT_SELF;
int nParm=GetLocalInt(oMe,"nParm"); // previous run state
int nParm2=GetLocalInt(oMe,"nParm2"); // previous aggression state
int nSState=GetLocalInt(oMe,"nSState");
object oDest=GetLocalObject(oMe,"oDest");
object oMod=GetModule();
string sID=GetLocalString(oMe,"sTeamID");
switch (nSState)
{ // retreat switch
case 0: { // determine retreat location
oDest=GetLocalObject(oMod,"o"+sID+"Retreat");
if (oDest==OBJECT_INVALID)
oDest=GetWaypointByTag(sID+"_START");
SetLocalObject(oMe,"oDest",oDest);
nParm=GetLocalInt(oMe,"nRun");
SetLocalInt(oMe,"nParm",nParm);
nParm2=GetLocalInt(oMe,"nAggression");
SetLocalInt(oMe,"nParm2",nParm2);
SetLocalInt(oMe,"nSState",1);
SetLocalInt(oMe,"nRun",TRUE);
SetLocalInt(oMe,"nAggression",1);
break;
} // determine retreat location
case 1: { // retreat
nParm=fnMovePath(oDest,TRUE);
if (nParm==1||nParm==-1)
{ // arrived
SetLocalInt(oMe,"nSState",2);
} // arrived
break;
} // retreat
case 2: { // set back to original behavior
SetLocalInt(oMe,"nRun",nParm);
SetLocalInt(oMe,"nAggression",nParm2);
SetLocalInt(oMe,"nMState",0);
break;
} // set back to original behavior
} // retreat switch
} // fnRetreat()
void fnSleep()
{ // sleep
object oMe=OBJECT_SELF;
int nPrev=GetLocalInt(oMe,"nPrev");
int nCHP=GetCurrentHitPoints(oMe);
int nMHP=GetMaxHitPoints(oMe);
int nDif=nMHP-nCHP;
effect eDmg;
nDif=nDif-1;
if (GetAbilityModifier(ABILITY_CONSTITUTION,oMe)>0)
nDif=nDif-GetAbilityModifier(ABILITY_CONSTITUTION,oMe);
if (nDif<1) nDif=0;
if (GetLocalInt(oMe,"nSState")==0)
{
SetLocalInt(oMe,"nRestTime",GetTimeHour());
SetLocalInt(oMe,"nSState",1);
}
eDmg=EffectDamage(nDif);
ActionRest();
if (nDif>0) ActionDoCommand(ApplyEffectToObject(DURATION_TYPE_INSTANT,eDmg,oMe,1.0));
ActionDoCommand(SetLocalInt(oMe,"nMState",nPrev));
} // fnSleep()
void fnPatrol()
{ // 4 point patrol system
object oMe=OBJECT_SELF;
int nParm=GetLocalInt(oMe,"nParm"); // current patrol point
object oDest=GetLocalObject(oMe,"oDest");
int nSState=GetLocalInt(oMe,"nSState");
int nErr;
string sVar;
switch (nSState)
{ // Patrol switch
case 0: { // initialize patrol
AssignCommand(oMe,ClearAllActions());
if (GetAbilityScore(oMe,ABILITY_INTELLIGENCE)>7)
AssignCommand(oMe,SpeakString("I am beginning my patrol."));
SetLocalInt(oMe,"nParm",0);
SetLocalInt(oMe,"nSState",1);
break;
} // initialize patrol
case 1: { // choose destination
if (GetAbilityScore(oMe,ABILITY_INTELLIGENCE)>7&&d4()<3)
AssignCommand(oMe,SpeakString("I'm off to my next patrol location."));
nParm++;
if (nParm>4) nParm=1;
sVar="oPatrol0"+IntToString(nParm);
oDest=GetLocalObject(oMe,sVar);
if (oDest!=OBJECT_INVALID)
{ // valid object
SetLocalObject(oMe,"oDest",oDest);
SetLocalInt(oMe,"nSState",2);
} // valid object
SetLocalInt(oMe,"nParm",nParm);
break;
} // choose destination
case 2: { // moving
nErr=fnMovePath(oDest,TRUE);
if (nErr==1||nErr==-1)
SetLocalInt(oMe,"nSState",1);
break;
} // moving
} // Patrol switch
} // fnPatrol()
object fnNoSunPlace()
{ // find an object to run to that is out of the sun
object oRet=OBJECT_INVALID;
object oMe=OBJECT_SELF;
object oArea=GetArea(oMe);
int nC=GetLocalInt(oArea,"nNumTrans");
int nL=1;
object oDest;
object oWarn;
while(nL<=nC&&oRet==OBJECT_INVALID)
{ // find destination
oDest=GetLocalObject(oArea,"oTrans"+IntToString(nL));
oDest=GetTransitionTarget(oDest);
if (oDest!=OBJECT_INVALID)
{ // valid transition
oWarn=GetNearestObjectByTag("RTSA_SUN",oMe);
if (oWarn==OBJECT_INVALID) return oDest;
} // valid transition
nL++;
} // find destination
return oRet;
} // fnNoSunPlace()
void fnFlee(string sWhere="NA")
{ // Flee to base, sunlight, and insanity
object oMe=OBJECT_SELF;
string sID=GetLocalString(oMe,"sTeamID");
int nS=GetLocalInt(oMe,"nSState");
object oDest=GetLocalObject(oMe,"oDest");
int nN;
SetLocalInt(oMe,"nRun",TRUE);
switch(nS)
{ // Flee switch
case 0: { // find destination
if (sWhere=="SUN")
{ // find place away from the sun
oDest=fnNoSunPlace();
if (oDest!=OBJECT_INVALID)
{ // get moving
SetLocalObject(oMe,"oDest",oDest);
SetLocalInt(oMe,"nSState",1);
} // get moving
else
{ // Move to random door
oDest=fnRandomTrans(GetArea(oMe));
oDest=GetTransitionTarget(oDest);
SetLocalObject(oMe,"oDest",oDest);
SetLocalInt(oMe,"nSState",1);
} // Move to random door
} // find place away from the sun
else
{ // insane
oDest=GetNearestObject(OBJECT_TYPE_TRIGGER,oMe,d20());
if (oDest!=OBJECT_INVALID)
{ // found one
oDest=GetTransitionTarget(oDest);
if (oDest!=OBJECT_INVALID)
{ // works
oDest=GetNearestObject(OBJECT_TYPE_PLACEABLE,oDest,d4());
if (oDest!=OBJECT_INVALID)
{ // found a target
SetLocalObject(oMe,"oDest",oDest);
SetLocalInt(oMe,"nSState",1);
} // found a target
} // works
} // found one
} // insane
break;
} // find destination
case 1: { // move to destination
nN=fnMovePath(oDest,TRUE);
if (nN==-1)
{ // error
SetLocalInt(oMe,"nSState",0);
} // error
else if (nN==1)
{ // arrived
if (sWhere=="SUN")
{ // out of the sunlight
if (GetNearestObjectByTag("RTSA_SUN",oMe)!=OBJECT_INVALID)
SetLocalInt(oMe,"nMState",0);
else
{
SetLocalInt(oMe,"nMState",0);
SetLocalInt(oMe,"nSState",0);
}
} // out of the sunlight
else
{
SetLocalInt(oMe,"nSState",1);
}
} // arrived
break;
} // move to destination
} // Flee switch
} // fnFlee()