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

874 lines
29 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_headere" // errors & debug
#include "rtsa_headers" // stacks
/////////////////////////////////////////
// FUNCTIONS
/////////////////////////////////////////
object fnRandomObject(object oArea,int nObType=0,object oOBT=OBJECT_INVALID)
{ // 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);
if (oOBT!=OBJECT_INVALID) oObB=oOBT;
fnDebug(" fnRandomObject("+GetName(oArea)+","+IntToString(nObType)+")");
fnDebug(" 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;
}
fnDebug(" Object type chosen:"+IntToString(nObT));
nC=0;
if (oOBT==OBJECT_INVALID)
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
fnDebug(" 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()
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
fnPush("Pathing","",0,oH1);
fnPush("Pathing","",0,fnRandomObject(GetArea(oH1),0,oH1));
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);
if(GetTransitionTarget(oH1)!=OBJECT_INVALID)
{ // !OI-TT
oH1=fnRandomObject(GetArea(oH1),0,oH1);
} // !OI-TT
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);
if(GetTransitionTarget(oH1)!=OBJECT_INVALID)
{ // !OI-TT
oH1=fnRandomObject(GetArea(oH1),0,oH1);
} // !OI-TT
fnPush("Pathing","",0,oH1);
oAt=oH1;
nDepth++;
} // found a direction to try
} // traverse nodes
return nRet;
} // fnBuildPath()
int fnFindPathTo(object oDest,int nMaxNodes=10)
{ // find a path
object oMe=OBJECT_SELF;
object oMyArea=GetArea(oMe);
object oDestArea=GetArea(oDest);
int nRet=0;
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,oDest);
fnPush("Pathing","",0,fnRandomObject(GetArea(oDest),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
return nRet;
} // fnFindPathTo()
float fnPlanarDistance(location lLoc1,location lLoc2)
{ // get planar distance
float fRet=0.0;
vector vVec=GetPositionFromLocation(lLoc1);
float fY1=vVec.y;
float fX1=vVec.x;
vVec=GetPositionFromLocation(lLoc2);
float fX2=vVec.x;
float fY2=vVec.y;
fY1=(fY1-fY2);
fX1=(fX1-fX2);
fRet=(fY1+fX1);
if (fRet<0.0) fRet=fRet*-1.0;
fRet=fRet/2.0;
return fRet;
} // fnPlanarDistance()
int fnMoveToDestination(object oDest,int nAS,float fRange=2.5)
{ // the actual movement command - handles anti-stuck as well
if (oDest!=OBJECT_INVALID&&GetIsPC(oDest)!=TRUE&&GetObjectType(oDest)!=OBJECT_TYPE_CREATURE)
{ // !OI
int nRet=0;
object oMe=OBJECT_SELF;
float fDist=GetDistanceToObject(oDest);
float fDistR=GetLocalFloat(oMe,"fDistR");
int nASC=GetLocalInt(oMe,"nASC");
int nWander=GetLocalInt(oMe,"nWander");
object oInArea=GetLocalObject(oMe,"oInArea");
location lMe=GetLocation(oMe);
location lDest=GetLocation(oDest);
int nRun=GetLocalInt(oMe,"nRun");
object oTrans;
int nC;
int nErr;
int nWC=GetLocalInt(oMe,"nWC"); // wander count
object oPC=GetNearestCreature(CREATURE_TYPE_PLAYER_CHAR,PLAYER_CHAR_IS_PC,oMe); // PC
fnDebug(" ["+GetName(oMe)+"]fnMoveToDestination("+GetTag(oDest)+","+IntToString(nAS)+","+FloatToString(fRange)+")");
if (oDest==OBJECT_INVALID) return -1;
if (fDist==-1.0)
{
if(oInArea==OBJECT_INVALID)
{
oInArea=fnRandomObject(GetArea(oMe));
SetLocalObject(oMe,"oInArea",oInArea);
}
}
else if (fDist!=-1.0&&fDist<=fRange)
{
return 1;
}
else if (oInArea!=OBJECT_INVALID)
DeleteLocalObject(oMe,"oInArea");
if (nWander!=TRUE)
{ // okay to process movement - not wandering
SetLocalFloat(oMe,"fDistR",fDist);
if (fDist==-1.0)
SetLocalFloat(oMe,"fDistR",GetDistanceToObject(oInArea));
fnDebug(" fnMoveToDestination:"+GetTag(oDest)+" nASC:"+IntToString(nASC)+" fDist:"+FloatToString(fDist)+" fDistR:"+FloatToString(fDistR)+" MvR:"+IntToString(GetMovementRate(oMe))+" Currently At:"+GetName(GetArea(oMe)));
if (nAS==TRUE&&((fDist==fDistR&&fDist!=-1.0)||(GetDistanceToObject(oInArea)==fDistR&&fDist==-1.0)))
{ // Possibly stuck and ANTI-STUCK is enabled
nASC++;
SetLocalInt(oMe,"nASC",nASC);
if (oPC==OBJECT_INVALID)
{ // no PCs in area - use speed method
nC=13-GetMovementRate(oMe);
if (nASC>(nC+2))
{ // teleport failed - return error
return -1;
} // teleport failed - return error
else if (nASC>nC)
{ // teleport
AssignCommand(oMe,ClearAllActions());
AssignCommand(oMe,JumpToObject(oDest));
} // teleport
else
{ // move
AssignCommand(oMe,ClearAllActions());
AssignCommand(oMe,ActionMoveToObject(oDest,nRun,fRange));
} // move
} // no PCs in area - use speed method
else
{ // PCs in area - use visible method
nC=8-GetMovementRate(oMe);
if (nASC>(nC+7))
{ // teleport failed - return error
return -1;
} // teleport failed - return error
else if (nASC>(nC+6))
{ // compare locations (disregard Z)
if (fnPlanarDistance(lMe,lDest)<fRange)
return 1;
} // compare locations (disregard Z)
else if (nASC>(nC+5))
{ // Teleport
AssignCommand(oMe,ClearAllActions());
AssignCommand(oMe,JumpToObject(oDest));
} // Teleport
else if (nASC>(nC+3))
{ // Wander mode
if (nWC<2)
{ // have not wandered too much
oTrans=fnRandomObject(GetArea(oMe));
SetLocalInt(oMe,"nWander",TRUE);
DelayCommand(8.0,SetLocalInt(oMe,"nWander",FALSE));
AssignCommand(oMe,ClearAllActions());
AssignCommand(oMe,ActionMoveToObject(oTrans,nRun,3.0));
DelayCommand(7.5,AssignCommand(oMe,ClearAllActions()));
DelayCommand(7.7,AssignCommand(oMe,ActionMoveToObject(oDest,nRun,fRange)));
nWC++;
SetLocalInt(oMe,"nWC",nWC);
} // have not wandered too much
} // Wander mode
else if (nASC>(nC+1))
{ // active kickstart
AssignCommand(oMe,ClearAllActions());
AssignCommand(oMe,ActionMoveToObject(oDest,nRun,fRange));
} // active kickstart
else
{ // issue move command
AssignCommand(oMe,ActionMoveToObject(oDest,nRun,fRange));
} // issue move command
} // PCs in area - use visible method
} // Possibly stuck and ANTI-STUCK is enabled
else
{ // Not STUCK or ANTI-STUCK disabled
if (fDist<=fRange&&fDist!=-1.0)
{ // arrived
SetLocalInt(oMe,"nWC",0);
SetLocalInt(oMe,"nASC",0);
SetLocalInt(oMe,"nWander",FALSE);
return 1;
} // arrived
else
{ // have not arrived
if (GetTransitionTarget(oDest)!=OBJECT_INVALID)
{ // transition target
oTrans=GetTransitionTarget(oDest);
oTrans=fnRandomObject(GetArea(oTrans),0,oTrans);
nC=2;
while((GetTransitionTarget(oTrans)!=OBJECT_INVALID||GetIsPC(oTrans)==TRUE||GetObjectType(oTrans)==OBJECT_TYPE_CREATURE)&&nC<10)
{
oTrans=GetNearestObject(OBJECT_TYPE_ALL,oTrans,nC);
nC++;
}
if (GetTransitionTarget(oTrans)==OBJECT_INVALID&&GetIsPC(oTrans)!=TRUE&&GetObjectType(oTrans)!=OBJECT_TYPE_CREATURE)
{ // go to this object
nErr=fnMoveToDestination(oTrans,nAS,fRange);
return nErr;
} // go to this object
else
return -1;
} // transition target
else
{ // in our area
AssignCommand(oMe,ActionMoveToObject(oDest,nRun,fRange));
SetLocalInt(oMe,"nASC",0);
} // in our area
} // have not arrived
} // Not STUCK or ANTI-STUCK disabled
} // okay to process movement - not wandering
return nRet;
} // OI
else
return -1; // OBJECT_INVALID
} // fnMoveToDestination()
int fnMovePath(object oDest,int nAS,float fRange=2.5)
{ // Main movement function
int nRet=0;
object oMe=OBJECT_SELF;
object oDirect;
object oD2;
int nErr;
int nTop=fnSizeS("Pathing");
float fDist=GetDistanceToObject(oDest);
if (oDest==OBJECT_INVALID) return -1;
else fnDebug(" fnMovePath("+GetTag(oDest)+"/"+GetName(oDest)+"/"+GetResRef(oDest)+")");
if (nTop==0)
{ // no path build one
fnDebug(" Initialize Stack & Find Path");
fnInitializeStack("Pathing",3); // Object stack
nErr=fnFindPathTo(oDest); // build pathing
if (nErr==-1)
return -1;
} // no path build one
else if (nTop==1)
{ // single destination
oDirect=fnPopObject("Pathing",FALSE);
fnDebug(" Single Destination Remains:"+GetTag(oDirect));
if (GetTransitionTarget(oDirect)!=OBJECT_INVALID)
{ // transition target
fDist=GetDistanceToObject(oDirect);
if (fDist!=-1.0&&fDist<20.1)
{ // close enough
nErr=fnMoveToDestination(oDirect,nAS,fRange);
if (nErr==1)
{ // arrived
oDirect=fnPopObject("Pathing");
return 1;
} // arrived
else
{ // seek target close to transition first
oD2=fnRandomObject(GetArea(oDirect),0,oDirect);
if (GetTransitionTarget(oD2)!=OBJECT_INVALID)
oD2=fnRandomObject(GetArea(oDirect),0,oDirect);
nErr=fnMoveToDestination(oD2,nAS,fRange);
if (nErr==1)
{ // arrived at mid-point
fDist=GetDistanceToObject(oDirect);
if (fDist!=-1.0&&fDist>20.0)
{ // still not close enough
nErr=fnMoveToDestination(oDirect,nAS,fRange);
if (fDist<30.0)
DelayCommand(3.0,ClearAllActions());
else if (fDist<50.0)
DelayCommand(5.0,ClearAllActions());
else
DelayCommand(8.0,ClearAllActions());
} // still not close enough
} // arrived at mid-point
else if (nErr==-1)
{ // mid-point error
oD2=fnRandomObject(GetArea(oDirect),0,oDirect);
nErr=fnMoveToDestination(oD2,nAS,fRange);
if (nErr==-1)
{ // mid-point 2 fail
nErr=fnMoveToDestination(oDirect,nAS,fRange);
} // mid-point 2 fail
} // mid-point error
} // seek target close to transition first
} // close enough
} // transition target
else
{ // not a transition target
nErr=fnMoveToDestination(oDirect,nAS,fRange);
if (nErr==1)
{ // arrived
oDirect=fnPopObject("Pathing");
return 1;
} // arrived
else if (nErr==-1)
{ // error
fnFlushS("Pathing");
return -1;
} // error
} // not a transition target
} // single destination
else
{ // stack of destinations
oDirect=fnPopObject("Pathing",FALSE);
fnDebug(" Stack of destinations Current="+GetTag(oDirect));
if (GetTransitionTarget(oDirect)!=OBJECT_INVALID)
{ // transition target -- TRANSITION
fDist=GetDistanceToObject(oDirect);
if (fDist!=-1.0&&fDist<20.1)
{ // close enough
nErr=fnMoveToDestination(oDirect,nAS,fRange);
if (nErr==1)
{ // arrived
oDirect=fnPopObject("Pathing");
return 0;
} // arrived
} // close enough
else
{ // seek target close to transition first
oD2=fnRandomObject(GetArea(oDirect),0,oDirect);
if (GetTransitionTarget(oD2)!=OBJECT_INVALID)
oD2=fnRandomObject(GetArea(oDirect),0,oDirect);
nErr=fnMoveToDestination(oD2,nAS,fRange);
if (nErr==1)
{ // arrived at mid-point
fDist=GetDistanceToObject(oDirect);
if (fDist!=-1.0&&fDist>20.0)
{ // still not close enough
nErr=fnMoveToDestination(oDirect,nAS,fRange);
if (fDist<30.0)
DelayCommand(3.0,ClearAllActions());
else if (fDist<50.0)
DelayCommand(5.0,ClearAllActions());
else
DelayCommand(8.0,ClearAllActions());
} // still not close enough
} // arrived at mid-point
else if (nErr==-1)
{ // mid-point error
oD2=fnRandomObject(GetArea(oDirect),0,oDirect);
nErr=fnMoveToDestination(oD2,nAS,fRange);
if (nErr==-1)
{ // mid-point 2 fail
nErr=fnMoveToDestination(oDirect,nAS,fRange);
} // mid-point 2 fail
} // mid-point error
} // seek target close to transition first
} // transition target -- TRANSITION
else
{ // not transition target -- NON-TRANSITION
nErr=fnMoveToDestination(oDirect,nAS,fRange);
if (nErr==1)
{ // arrived
oDirect=fnPopObject("Pathing");
return 0;
} // arrived
else if (nErr==-1)
{ // error - cannot reach
fnFlushS("Pathing");
return -1;
} // error - cannot reach
} // not transition target -- NON-TRANSITION
} // stack of destinations
return nRet;
} // fnMovePath()
/*
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() */
/*
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() */