HoS_PRC8/_mod/_module/nss/rtsa_headera_o.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

457 lines
15 KiB
Plaintext

///////////////////////////////////////////////////////////////////////////////////
// REAL TIME STRATEGY ADVENTURE - Kit
// FILE: rtsa_headera
// NAME: header functions for unit AI
// SCRIPTED BY: Deva Bryson Winblood
// DATE: 4/13/2003
///////////////////////////////////////////////////////////////////////////////////
// This header contains pathing and other AI critical parts for the AI
///////////////////////////////////////////////////////////////////////////////////
#include "rtsa_headers"
/////////////////////////////////////////
// FUNCTIONS
/////////////////////////////////////////
object fnRandomObject(object oArea,int nObType=0)
{ // This will return a random object from the area of the specified type
// if none is specified it will return a random object placeable, door, waypoint,
// or trigger
// This WILL NOT return area transition objects use fnRandomTrans for that
object oRet=OBJECT_INVALID;
int nObT=nObType;
int nR;
int nC;
float fDist=0.0;
int nLim=0;
object oObB=GetFirstObjectInArea(oArea);
SendMessageToPC(GetFirstPC(),"fnRandomObject("+GetName(oArea)+","+IntToString(nObType)+")");
SendMessageToPC(GetFirstPC()," First Object in Area:"+GetTag(oObB)+" Type:"+IntToString(GetObjectType(oObB)));
while(fDist<4.0&&nLim<3)
{ // find something not close
if (nObType==0)
{
nR=d4();
if (nR==1) nObT=OBJECT_TYPE_PLACEABLE;
else if (nR==2) nObT=OBJECT_TYPE_WAYPOINT;
else if (nR==3) nObT=OBJECT_TYPE_DOOR;
else if (nR==4) nObT=OBJECT_TYPE_TRIGGER;
}
SendMessageToPC(GetFirstPC()," Object type chosen:"+IntToString(nObT));
nC=0;
while(nC<4&&(nObT==GetObjectType(oObB)||oObB==OBJECT_INVALID))
{ // make sure checker object is of a different type
if(nObT!=OBJECT_TYPE_WAYPOINT)
oObB=GetNearestObject(OBJECT_TYPE_WAYPOINT,oObB,1);
else
oObB=GetNearestObject(OBJECT_TYPE_PLACEABLE,oObB,1);
nC++;
} // make sure checker object is of a different type
SendMessageToPC(GetFirstPC()," Object to compare against:"+GetTag(oObB));
if (nObT==OBJECT_TYPE_PLACEABLE)
nC=GetLocalInt(oArea,"nNumPlaceables");
else if (nObT==OBJECT_TYPE_WAYPOINT)
nC=GetLocalInt(oArea,"nNumWP");
else if (nObT==OBJECT_TYPE_DOOR)
nC=GetLocalInt(oArea,"nNumDoors");
else if (nObT==OBJECT_TYPE_TRIGGER)
nC=GetLocalInt(oArea,"nNumTriggers");
if (nC==0&&nObType==0)
{ // no objects of that type exist
if (nObT!=OBJECT_TYPE_PLACEABLE&&GetObjectType(oObB)!=OBJECT_TYPE_PLACEABLE&&GetLocalInt(oArea,"nNumPlaceables")>0)
{ // try for placeables
nObT=OBJECT_TYPE_PLACEABLE;
nC=GetLocalInt(oArea,"nNumPlaceables");
} // try for placeables
else if (nObT!=OBJECT_TYPE_WAYPOINT&&GetObjectType(oObB)!=OBJECT_TYPE_WAYPOINT&&GetLocalInt(oArea,"nNumWP")>0)
{ // try for waypoints
nObT=OBJECT_TYPE_WAYPOINT;
nC=GetLocalInt(oArea,"nNumWP");
} // try for waypoints
else if (nObT!=OBJECT_TYPE_DOOR&&GetObjectType(oObB)!=OBJECT_TYPE_DOOR&&GetLocalInt(oArea,"nNumDoors")>0)
{ // try a door
nObT=OBJECT_TYPE_DOOR;
nC=GetLocalInt(oArea,"nNumDoors");
} // try a door
else if (nObT!=OBJECT_TYPE_TRIGGER&&GetObjectType(oObB)!=OBJECT_TYPE_TRIGGER&&GetLocalInt(oArea,"nNumTriggers")>0)
{ // try a trigger
nObT=OBJECT_TYPE_TRIGGER;
nC=GetLocalInt(oArea,"nNumTriggers");
} // try a trigger
} // no objects of that type exist
if (nC>0&&oObB!=OBJECT_INVALID)
{ // get the random object
nR=Random(nC)+1;
if (nObT==OBJECT_TYPE_PLACEABLE)
oRet=GetNearestObject(OBJECT_TYPE_PLACEABLE,oObB,nR);
else if (nObT==OBJECT_TYPE_WAYPOINT)
oRet=GetNearestObject(OBJECT_TYPE_WAYPOINT,oObB,nR);
else if (nObT==OBJECT_TYPE_DOOR)
oRet=GetLocalObject(oArea,"oDoor"+IntToString(nR));
else if (nObT==OBJECT_TYPE_TRIGGER)
oRet=GetLocalObject(oArea,"oTrigger"+IntToString(nR));
} // get the random object
else if (oObB==OBJECT_INVALID)
oRet=GetFirstObjectInArea(oArea);
nLim++;
fDist=GetDistanceToObject(oRet);
} // find something not close
return oRet;
} // fnRandomObject()
object fnRandomTrans(object oArea)
{ // Returns a random area transition target (trigger or door)
object oRet=OBJECT_INVALID;
int nC=GetLocalInt(oArea,"nNumTrans");
int nR=Random(nC)+1;
if (nC>0)
oRet=GetLocalObject(oArea,"oTrans"+IntToString(nR));
return oRet;
} // fnRandomTrans()
void fnMakeSureNotImpossible(object oDest,float fRange)
{
float fDist=GetDistanceToObject(oDest);
object oMe=OBJECT_SELF;
if (fDist>fRange)
{ // not possible
SetLocalInt(oMe,"nWanderCount",0);
SetLocalFloat(oMe,"fDistR",fDist);
SetLocalInt(oMe,"nASC",1000);
} // not possible
} // fnMakeSureNotImpossible()
int fnMoveToDestination(object oDest,int nAS=TRUE,float fRange=2.5)
{ // Move to destination and anti-stuck procedures
// RETURN VALUES 0 = moving, 1 = appear to have arrived, -1 = unreachable
int nRet=0;
object oMe=OBJECT_SELF;
object oNear=GetLocalObject(oMe,"oNear");
int nASC=GetLocalInt(oMe,"nASC"); // Anti-Stuck counter
float fDistR=GetLocalFloat(oMe,"fDistR"); // distance recorded last time
float fDist=GetDistanceToObject(oDest);
int nRun=GetLocalInt(oMe,"nRun");
object oBackup;
int nSpeedB=0;
int nWander=GetLocalInt(oMe,"nWander");
int nR=GetMovementRate(oMe);
int nWC=GetLocalInt(oMe,"nWanderCount");
nSpeedB=7-nR;
if (oNear!=OBJECT_INVALID&&fDist!=-1.0)
DeleteLocalObject(oMe,"oNear");
if (nSpeedB<1) nSpeedB=0;
if (nWander!=TRUE)
{ // not currently wandering
SendMessageToPC(GetFirstPC(),"fnMoveToDestination:"+GetTag(oDest)+" nASC:"+IntToString(nASC)+" fDist:"+FloatToString(fDist)+" fDistR:"+FloatToString(fDistR)+" nSpeedB:"+IntToString(nSpeedB));
if (GetTransitionTarget(oDest)!=OBJECT_INVALID)
{ // this is a transition object
oBackup=GetNearestObject(OBJECT_TYPE_ALL,oDest,1);
if (GetTransitionTarget(oBackup)!=OBJECT_INVALID)
oBackup=GetNearestObject(OBJECT_TYPE_ALL,oDest,2);
if (GetTransitionTarget(oBackup)!=OBJECT_INVALID)
oBackup=GetNearestObject(OBJECT_TYPE_ALL,oDest,3);
if (oBackup!=OBJECT_INVALID)
{ // destination
oDest=oBackup;
} // destination
else
return -1;
fDist=GetDistanceToObject(oDest);
} // this is a transition object
if (fDist!=-1.0&&fDist==fDistR&&nAS==TRUE)
{ // appears to be stuck
nASC++;
if (nASC>5+nSpeedB)
{ // extreme anti-stuck cannot reach destination
SetLocalObject(oMe,"oDest",OBJECT_INVALID);
SetLocalInt(oMe,"nASC",0);
SetLocalInt(oMe,"nWanderCount",0);
return -1; // signal failure to reach area
} // extreme anti-stuck cannot reach destination
else if (nASC>3+nSpeedB)
{ // badly stuck - teleport
AssignCommand(oMe,ClearAllActions());
AssignCommand(oMe,JumpToObject(oDest));
SetLocalInt(oMe,"nWanderCount",0);
SetLocalFloat(oMe,"fDistR",GetDistanceToObject(oDest));
DelayCommand(2.5,fnMakeSureNotImpossible(oDest,fRange));
} // badly stuck - teleport
else if (nASC>1+nSpeedB)
{ // pick a nearby target to move to
if (nWC<2)
{ // only 2 wander tries
if (nWander!=TRUE)
{ // pick target
oBackup=fnRandomObject(GetArea(oMe));
if (oBackup==OBJECT_INVALID)
{ // pick our own
oBackup=GetNearestObject(OBJECT_TYPE_ALL,oMe,d6());
if (GetTransitionTarget(oBackup)!=OBJECT_INVALID)
oBackup=OBJECT_INVALID;
} // pick our own
if (oBackup!=OBJECT_INVALID)
{ // valid object
SetLocalInt(oMe,"nWander",TRUE);
nWC++;
SetLocalInt(oMe,"nWanderCount",nWC);
AssignCommand(oMe,ClearAllActions());
AssignCommand(oMe,ActionMoveToObject(oBackup,nRun,3.0));
nR=4+d4();
DelayCommand(IntToFloat(nR),AssignCommand(oMe,ClearAllActions()));
DelayCommand(IntToFloat(nR)+0.1,AssignCommand(oMe,ActionMoveToObject(oDest,nRun,fRange)));
DelayCommand(IntToFloat(nR)+4.0,SetLocalInt(oMe,"nWander",FALSE));
} // valid object
SetLocalFloat(oMe,"fDistR",fDist);
} // pick target
} // only 2 wander tries
else
{ // abort - set to teleport time
SetLocalFloat(oMe,"fDistR",GetDistanceToObject(oDest));
SetLocalInt(oMe,"nASC",3+nSpeedB);
} // abort - set to teleport time
} // pick a nearby target to move to
else if (nASC==2)
{ // kick start - move to object
AssignCommand(oMe,ClearAllActions());
AssignCommand(oMe,ActionMoveToObject(oDest,nRun,fRange));
SetLocalFloat(oMe,"fDistR",fDist);
} // kick start - move to object
else
{ // move to object
AssignCommand(oMe,ActionMoveToObject(oDest,nRun,fRange));
SetLocalFloat(oMe,"fDistR",fDist);
} // move to object
SetLocalInt(oMe,"nASC",nASC);
} // appears to be stuck
else if (nAS!=TRUE&&fDist!=-1.0&&fDist==fDistR)
{ // Might be stuck but, don't use anti-stuck
AssignCommand(oMe,ActionMoveToObject(oDest,nRun,fRange));
} // Might be stuck but, don't use anti-stuck
else if (fDist==-1.0)
{ // different area
if (oNear==OBJECT_INVALID)
{ // near
oNear=GetNearestObject(OBJECT_TYPE_ALL,oMe,1);
fDist=GetDistanceToObject(oNear);
if (fDist!=fDistR)
{ // seems to be moving
AssignCommand(oMe,ActionMoveToObject(oDest,nRun,fRange));
SetLocalInt(oMe,"nASC",0);
SetLocalFloat(oMe,"fDistR",fDist);
} // seems to be moving
else
{ // might be stuck
nASC++;
SetLocalInt(oMe,"nASC",nASC);
if (nASC>3)
{ // abort this
return -1;
} // abort this
else if (nASC==2)
{ // kickstart
AssignCommand(oMe,ClearAllActions());
AssignCommand(oMe,ActionMoveToObject(oDest,nRun,fRange));
} // kickstart
else
{ // kickstart
AssignCommand(oMe,ActionMoveToObject(oDest,nRun,fRange));
} // kickstart
} // might be stuck
} // near
} // different area
else
{ // not stuck
SetLocalInt(oMe,"nASC",0);
SetLocalFloat(oMe,"fDistR",fDist);
if (fDist!=-1.0&&fDist<(fRange+0.1))
{ // arrived
SetLocalInt(oMe,"nWanderCount",0);
return 1;
} // arrived
} // not stuck
} // not currently wandering
return nRet;
} // fnMoveToDestination()
object fnDirectConnection(object oStart,object oEnd)
{ // find out if there is a direct area transition between the two places
object oRet=OBJECT_INVALID;
int nX=GetLocalInt(oStart,"nNumTrans");
int nC=1;
object oT=GetLocalObject(oStart,"oTrans"+IntToString(nC));
object oX;
oX=GetTransitionTarget(oT);
while (nC<=nX&&GetArea(oX)!=oEnd)
{ // look
oT=GetLocalObject(oStart,"oTrans"+IntToString(nC));
oX=GetTransitionTarget(oT);
nC++;
} // look
if (GetArea(oX)==oEnd) oRet=oT;
return oRet;
} // fnDirectConnection()
int fnBuildPath(object oEnd,int nMax=10)
{ // build a reverse path between this location and me
int nRet=FALSE;
object oMe=OBJECT_SELF;
int nX;
int nR;
int nDepth=0;
object oAt=oEnd;
object oPrev;
object oH1;
object oH2;
fnPush("Pathing","",0,oEnd); // put end point on stack
oH1=fnDirectConnection(GetArea(oEnd),GetArea(oMe));
if (oH1!=OBJECT_INVALID)
{ // direct connection
oH2=GetTransitionTarget(oH1);
fnPush("Pathing","",0,oH2);
fnPush("Pathing","",0,GetNearestObject(OBJECT_TYPE_ALL,oH1,1));
return TRUE;
} // direct connection
while(oAt!=oMe&&nDepth<=nMax)
{ // traverse nodes
oH1=fnDirectConnection(GetArea(oAt),GetArea(oMe));
if (oH1!=OBJECT_INVALID)
{ // direct connection
oH1=GetTransitionTarget(oH1);
fnPush("Pathing","",0,oH1);
return TRUE;
} // direct connection
oH1=fnRandomTrans(GetArea(oAt));
oH1=GetTransitionTarget(oH1);
nX=0;
while (GetArea(oH1)==oPrev&&nX<3)
{ // keep looking
oH1=fnRandomTrans(GetArea(oAt));
oH1=GetTransitionTarget(oH1);
nX++;
} // keep looking
if (GetArea(oH1)!=oPrev)
{ // found a direction to try
oPrev=GetArea(oAt);
fnPush("Pathing","",0,oH1);
oAt=oH1;
nDepth++;
} // found a direction to try
} // traverse nodes
return nRet;
} // fnBuildPath()
void fnFindPathTo(object oDest,int nMaxNodes=10)
{ // find a path
object oMe=OBJECT_SELF;
object oMyArea=GetArea(oMe);
object oDestArea=GetArea(oDest);
int nFoundPath=FALSE;
int nPathing=GetLocalInt(oMe,"nPathing");
if (nPathing!=TRUE)
{ // starting pathing
fnFlushS("Pathing");
fnInitializeStack("Pathing",3); // object stack
if (oMyArea==oDestArea)
{ // same area - no pathing needed
SendMessageToPC(GetFirstPC(),"Pathing: Same Area");
fnPush("Pathing","",0,oDest);
nFoundPath=TRUE;
} // same area - no pathing needed
else if (fnDirectConnection(oMyArea,oDestArea)!=OBJECT_INVALID)
{ // there is a direct link - no pathing needed
fnPush("Pathing","",0,GetNearestObject(OBJECT_TYPE_ALL,oDest,1));
fnPush("Pathing","",0,oDest);
SendMessageToPC(GetFirstPC(),"Pathing: Direct link");
nFoundPath=TRUE;
} // there is a direct link - no pathing needed
else
{ // build a path
SendMessageToPC(GetFirstPC(),"Call fnBuildPath");
nFoundPath=fnBuildPath(oDest,nMaxNodes);
} // build a path
if (nFoundPath==TRUE)
SetLocalInt(oMe,"nPathing",FALSE);
} // starting pathing
else
{ // still looking
SendMessageToPC(GetFirstPC(),"Pathing: Still calling fnBuildPath");
nFoundPath=fnBuildPath(oDest,nMaxNodes);
if (nFoundPath==TRUE)
SetLocalInt(oMe,"nPathing",FALSE);
} // still looking
} // fnFindPathTo()
int fnMovePath(object oDest,int nAS,float fRange=2.5)
{ // move following a path - this is the main movement function
int nRet=0;
object oMe=OBJECT_SELF;
object oDirect;
int nErr;
int nTop=fnSizeS("Pathing");
float fDist=GetDistanceToObject(oDest);
SendMessageToPC(GetFirstPC(),"fnMovePath("+GetTag(oDest)+",AS:"+IntToString(nAS)+",RANGE:"+FloatToString(fRange)+")");
if (nTop==0)
{ // no path
if (fDist==-1.0||fDist>fRange)
{ // build a path
SendMessageToPC(GetFirstPC(),"Building path");
fnFindPathTo(oDest);
nErr=fnMovePath(oDest,nAS,fRange);
if (nErr==-1) return -1;
} // build a path
else
{ // we have arrived
return 1;
} // we have arrived
} // no path
else if (nTop==1)
{ // direct link
oDirect=fnPopObject("Pathing",FALSE);
fDist=GetDistanceToObject(oDirect);
if (fDist!=-1.0&&fDist<=fRange)
{ // arrived
SendMessageToPC(GetFirstPC(),"We arrived");
oDirect=fnPopObject("Pathing");
nRet=fnMovePath(oDest,nAS,fRange);
} // arrived
else
{ // move
SendMessageToPC(GetFirstPC(),"Call Move");
nErr=fnMoveToDestination(oDirect,nAS,fRange);
if (nErr==-1)
{ // error
return nErr;
} // error
} // move
} // direct link
else
{ // complex path
SendMessageToPC(GetFirstPC(),"Complex path");
oDirect=fnPopObject("Pathing",FALSE);
fDist=GetDistanceToObject(oDirect);
if (fDist!=-1.0&&fDist<=fRange)
{ // arrived at that node
oDirect=fnPopObject("Pathing");
nRet=fnMovePath(oDest,nAS,fRange);
} // arrived at that node
else
{ // move
nErr=fnMoveToDestination(oDirect,nAS,fRange);
if (nErr==-1)
{ // cannot reach node
fnFlushS("Pathing");
nRet=nErr;
} // cannot reach node
} // move
} // complex path
return nRet;
} // fnMovePath()