Jaysyn904 04165202c0 Initial upload
Initial upload
2024-11-25 19:36:07 -05:00

528 lines
19 KiB
Plaintext

///////////////////////////////////////////////////////////////////////////////////
// Real Time Strategy - NWN - Complex Path Finding Made Easy
//================================================================================
// By Deva Bryson Winblood. 03/09/2003
///////////////////////////////////////////////////////////////////////////////////
// required: each area have a waypoint with tag FIND_NODE
// NAME must be setup as follows x.y.z.UP.DOWN.NORTH.EAST.SOUTH.WEST
// where x,y,z is a number 0 and up. The directions are replaced by the tag
// of the area that leads to. This waypoint will be used by units for
// pathing.
int MAX_SEARCH = 15;
int DIR_UP = 1;
int DIR_DOWN = 2;
int DIR_NORTH = 3;
int DIR_EAST = 4;
int DIR_SOUTH = 5;
int DIR_WEST = 6;
void fnError(string sE)
{ // quick error message
SendMessageToPC(GetFirstPC(),sE);
PrintString(sE);
} // fnError()
string fnParsePeriod(string sIn)
{ // Parse period
string sH=sIn;
string sR="";
while (GetStringLength(sH)>0&&GetStringLeft(sH,1)!=".")
{ // build string
sR=sR+GetStringLeft(sH,1);
sH=GetStringRight(sH,GetStringLength(sH)-1);
} // build string
return sR;
} // fnParsePeriod()
string fnRemParsed(string sO, string sP)
{ // Remove parsed portion from sO
string sR="";
if (GetStringLength(sO)>=GetStringLength(sP))
sR=GetStringRight(sO,GetStringLength(sO)-GetStringLength(sP));
if (GetStringLeft(sR,1)==".") sR=GetStringRight(sR,GetStringLength(sR)-1);
return sR;
} // fnRemParsed()
string fnCanGoDirection(object oArea,int nDir)
{ // is their a direction for this returns NA if false
string sMNDown; // down destination
string sMNUp; // up destination
string sMNNorth; // North destination
string sMNSouth; // South destination
string sMNEast; // East destination
string sMNWest; // West destination
string x,y,z; // coordinates
object oNode=GetNearestObjectByTag("FIND_NODE",oArea);
string sName=GetName(oNode);
x=fnParsePeriod(sName);
sName=fnRemParsed(sName,x);
y=fnParsePeriod(sName);
sName=fnRemParsed(sName,y);
z=fnParsePeriod(sName);
sName=fnRemParsed(sName,z);
sMNUp=fnParsePeriod(sName);
sName=fnRemParsed(sName,sMNUp);
sMNDown=fnParsePeriod(sName);
sName=fnRemParsed(sName,sMNDown);
sMNNorth=fnParsePeriod(sName);
sName=fnRemParsed(sName,sMNNorth);
sMNEast=fnParsePeriod(sName);
sName=fnRemParsed(sName,sMNEast);
sMNSouth=fnParsePeriod(sName);
sName=fnRemParsed(sName,sMNSouth);
sMNWest=fnParsePeriod(sName);
sName=fnRemParsed(sName,sMNWest);
if (nDir==DIR_UP&&sMNUp!="NA"&&GetStringLength(sMNUp)>1)
return sMNUp;
else if (nDir==DIR_DOWN&&sMNDown!="NA"&&GetStringLength(sMNDown)>1)
return sMNDown;
else if (nDir==DIR_NORTH&&sMNNorth!="NA"&&GetStringLength(sMNNorth)>1)
return sMNNorth;
else if (nDir==DIR_EAST&&sMNEast!="NA"&&GetStringLength(sMNEast)>1)
return sMNEast;
else if (nDir==DIR_SOUTH&&sMNSouth!="NA"&&GetStringLength(sMNSouth)>1)
return sMNSouth;
else if (nDir==DIR_WEST&&sMNWest!="NA"&&GetStringLength(sMNWest)>1)
return sMNWest;
return "NA";
} // fnCanGoDirection()
int fnAreaWhichDirection(object oArea,object oDest)
{ // returns the direction to be taken to the area specified
// return of 0 = already there
int nRet=0;
string x,y,z;
string dx,dy,dz;
string sName=GetName(oArea);
int nx,ny,nz;
int ndx,ndy,ndz;
object oHandle;
x=fnParsePeriod(sName);
sName=fnRemParsed(sName,x);
y=fnParsePeriod(sName);
sName=fnRemParsed(sName,y);
z=fnParsePeriod(sName);
sName=GetName(oDest);
dx=fnParsePeriod(sName);
sName=fnRemParsed(sName,dx);
dy=fnParsePeriod(sName);
sName=fnRemParsed(sName,dy);
dz=fnParsePeriod(sName);
nx=StringToInt(x);
ny=StringToInt(y);
nz=StringToInt(z);
ndx=StringToInt(dx);
ndy=StringToInt(dy);
ndz=StringToInt(dz);
if (oArea!=oDest)
{ // separate areas
if (nz!=ndz)
{ // deal with Z axis first
if (ndz>nz)
{ // need to go up
if (fnCanGoDirection(oArea,DIR_UP)!="NA")
return DIR_UP;
else { // find nearby up location
sName=fnCanGoDirection(oArea,DIR_NORTH);
oHandle=GetObjectByTag(sName);
if (oHandle!=OBJECT_INVALID)
{ // test this direction
if(fnCanGoDirection(oHandle,DIR_UP)!="NA")
return DIR_NORTH;
} // test this direction
sName=fnCanGoDirection(oArea,DIR_SOUTH);
oHandle=GetObjectByTag(sName);
if (oHandle!=OBJECT_INVALID)
{ // test this direction
if(fnCanGoDirection(oHandle,DIR_UP)!="NA")
return DIR_SOUTH;
} // test this direction
sName=fnCanGoDirection(oArea,DIR_EAST);
oHandle=GetObjectByTag(sName);
if (oHandle!=OBJECT_INVALID)
{ // test this direction
if(fnCanGoDirection(oHandle,DIR_UP)!="NA")
return DIR_EAST;
} // test this direction
sName=fnCanGoDirection(oArea,DIR_WEST);
oHandle=GetObjectByTag(sName);
if (oHandle!=OBJECT_INVALID)
{ // test this direction
if(fnCanGoDirection(oHandle,DIR_UP)!="NA")
return DIR_WEST;
} // test this direction
return d6(); // random direction
} // find nearby up location
} // need to go up
else
{ // need to go down
if (fnCanGoDirection(oArea,DIR_DOWN)!="NA")
return DIR_DOWN;
else { // find nearby down location
sName=fnCanGoDirection(oArea,DIR_NORTH);
oHandle=GetObjectByTag(sName);
if (oHandle!=OBJECT_INVALID)
{ // test this direction
if(fnCanGoDirection(oHandle,DIR_DOWN)!="NA")
return DIR_NORTH;
} // test this direction
sName=fnCanGoDirection(oArea,DIR_SOUTH);
oHandle=GetObjectByTag(sName);
if (oHandle!=OBJECT_INVALID)
{ // test this direction
if(fnCanGoDirection(oHandle,DIR_DOWN)!="NA")
return DIR_SOUTH;
} // test this direction
sName=fnCanGoDirection(oArea,DIR_EAST);
oHandle=GetObjectByTag(sName);
if (oHandle!=OBJECT_INVALID)
{ // test this direction
if(fnCanGoDirection(oHandle,DIR_DOWN)!="NA")
return DIR_EAST;
} // test this direction
sName=fnCanGoDirection(oArea,DIR_WEST);
oHandle=GetObjectByTag(sName);
if (oHandle!=OBJECT_INVALID)
{ // test this direction
if(fnCanGoDirection(oHandle,DIR_DOWN)!="NA")
return DIR_WEST;
} // test this direction
return d6(); // random direction
} // find nearby down location
} // need to go down
} // deal with Z axis first
else if (nx!=ndx)
{ // deal with X axis
if (ndx>nx)
{ // need to go east
if (fnCanGoDirection(oArea,DIR_EAST)!="NA")
return DIR_EAST;
else { // find nearby east location
sName=fnCanGoDirection(oArea,DIR_NORTH);
oHandle=GetObjectByTag(sName);
if (oHandle!=OBJECT_INVALID)
{ // test this direction
if(fnCanGoDirection(oHandle,DIR_EAST)!="NA")
return DIR_NORTH;
} // test this direction
sName=fnCanGoDirection(oArea,DIR_SOUTH);
oHandle=GetObjectByTag(sName);
if (oHandle!=OBJECT_INVALID)
{ // test this direction
if(fnCanGoDirection(oHandle,DIR_EAST)!="NA")
return DIR_SOUTH;
} // test this direction
sName=fnCanGoDirection(oArea,DIR_UP);
oHandle=GetObjectByTag(sName);
if (oHandle!=OBJECT_INVALID)
{ // test this direction
if(fnCanGoDirection(oHandle,DIR_EAST)!="NA")
return DIR_UP;
} // test this direction
sName=fnCanGoDirection(oArea,DIR_DOWN);
oHandle=GetObjectByTag(sName);
if (oHandle!=OBJECT_INVALID)
{ // test this direction
if(fnCanGoDirection(oHandle,DIR_EAST)!="NA")
return DIR_DOWN;
} // test this direction
return d6(); // random direction
} // find nearby east location
} // need to go east
else
{ // need to go west
if (fnCanGoDirection(oArea,DIR_WEST)!="NA")
return DIR_WEST;
else { // find nearby west location
sName=fnCanGoDirection(oArea,DIR_NORTH);
oHandle=GetObjectByTag(sName);
if (oHandle!=OBJECT_INVALID)
{ // test this direction
if(fnCanGoDirection(oHandle,DIR_WEST)!="NA")
return DIR_NORTH;
} // test this direction
sName=fnCanGoDirection(oArea,DIR_SOUTH);
oHandle=GetObjectByTag(sName);
if (oHandle!=OBJECT_INVALID)
{ // test this direction
if(fnCanGoDirection(oHandle,DIR_WEST)!="NA")
return DIR_SOUTH;
} // test this direction
sName=fnCanGoDirection(oArea,DIR_UP);
oHandle=GetObjectByTag(sName);
if (oHandle!=OBJECT_INVALID)
{ // test this direction
if(fnCanGoDirection(oHandle,DIR_WEST)!="NA")
return DIR_UP;
} // test this direction
sName=fnCanGoDirection(oArea,DIR_DOWN);
oHandle=GetObjectByTag(sName);
if (oHandle!=OBJECT_INVALID)
{ // test this direction
if(fnCanGoDirection(oHandle,DIR_WEST)!="NA")
return DIR_DOWN;
} // test this direction
return d6(); // random direction
} // find nearby west location
} // need to go west
} // deal with X axis
else if (ny!=ndy)
{ // deal with Y axis
if (ndy>ny)
{ // need to go south
if (fnCanGoDirection(oArea,DIR_SOUTH)!="NA")
return DIR_SOUTH;
else { // find nearby south location
sName=fnCanGoDirection(oArea,DIR_EAST);
oHandle=GetObjectByTag(sName);
if (oHandle!=OBJECT_INVALID)
{ // test this direction
if(fnCanGoDirection(oHandle,DIR_SOUTH)!="NA")
return DIR_EAST;
} // test this direction
sName=fnCanGoDirection(oArea,DIR_WEST);
oHandle=GetObjectByTag(sName);
if (oHandle!=OBJECT_INVALID)
{ // test this direction
if(fnCanGoDirection(oHandle,DIR_SOUTH)!="NA")
return DIR_WEST;
} // test this direction
sName=fnCanGoDirection(oArea,DIR_UP);
oHandle=GetObjectByTag(sName);
if (oHandle!=OBJECT_INVALID)
{ // test this direction
if(fnCanGoDirection(oHandle,DIR_SOUTH)!="NA")
return DIR_UP;
} // test this direction
sName=fnCanGoDirection(oArea,DIR_DOWN);
oHandle=GetObjectByTag(sName);
if (oHandle!=OBJECT_INVALID)
{ // test this direction
if(fnCanGoDirection(oHandle,DIR_SOUTH)!="NA")
return DIR_DOWN;
} // test this direction
return d6(); // random direction
} // find nearby south location
} // need to go south
else
{ // need to go north
if (fnCanGoDirection(oArea,DIR_NORTH)!="NA")
return DIR_NORTH;
else { // find nearby north location
sName=fnCanGoDirection(oArea,DIR_EAST);
oHandle=GetObjectByTag(sName);
if (oHandle!=OBJECT_INVALID)
{ // test this direction
if(fnCanGoDirection(oHandle,DIR_NORTH)!="NA")
return DIR_EAST;
} // test this direction
sName=fnCanGoDirection(oArea,DIR_WEST);
oHandle=GetObjectByTag(sName);
if (oHandle!=OBJECT_INVALID)
{ // test this direction
if(fnCanGoDirection(oHandle,DIR_NORTH)!="NA")
return DIR_WEST;
} // test this direction
sName=fnCanGoDirection(oArea,DIR_UP);
oHandle=GetObjectByTag(sName);
if (oHandle!=OBJECT_INVALID)
{ // test this direction
if(fnCanGoDirection(oHandle,DIR_NORTH)!="NA")
return DIR_UP;
} // test this direction
sName=fnCanGoDirection(oArea,DIR_DOWN);
oHandle=GetObjectByTag(sName);
if (oHandle!=OBJECT_INVALID)
{ // test this direction
if(fnCanGoDirection(oHandle,DIR_NORTH)!="NA")
return DIR_DOWN;
} // test this direction
return d6(); // random direction
} // find nearby north location
} // need to go north
} // deal with Y axis
else
return -1; // error
} // separate areas
return nRet;
} // fnAreaWhichDirection()
int fnDirectPathBetween(object oStart,object oEnd)
{ // find out if there is a direct route between oStart and oEnd
int nRet=FALSE;
object oDoor;
object oTrans;
int nC=1;
oDoor=GetNearestObject(OBJECT_TYPE_DOOR,oStart,nC);
while(oDoor!=OBJECT_INVALID&&nRet==FALSE)
{ // check doors
nC++;
oTrans=GetTransitionTarget(oDoor);
if (oTrans!=OBJECT_INVALID)
{
if (GetArea(oTrans)==oEnd) nRet=TRUE;
}
oDoor=GetNearestObject(OBJECT_TYPE_DOOR,oStart,nC);
} // check doors
nC=1;
oDoor=GetNearestObject(OBJECT_TYPE_TRIGGER,oStart,nC);
while(oDoor!=OBJECT_INVALID&&nRet==FALSE)
{ // check doors
nC++;
oTrans=GetTransitionTarget(oDoor);
if (oTrans!=OBJECT_INVALID)
{
if (GetArea(oTrans)==oEnd) nRet=TRUE;
}
oDoor=GetNearestObject(OBJECT_TYPE_TRIGGER,oStart,nC);
} // check doors
return nRet;
} // fnDirectPathBetween()
void fnSneak()
{ // sneaky method
} // fnSneak()
//====================================================== MAIN ==================
void main()
{
object oMe=OBJECT_SELF;
object oMDest=GetLocalObject(oMe,"oMainDest"); // main destination
object oDest=GetLocalObject(oMe,"oDestWP"); // current destination
int nMM=GetLocalInt(oMe,"nMoveMethod"); // 0 = whatever RUN is set at 1= sneak
int nRun=GetLocalInt(oMe,"nRun"); // FALSE = WALK, TRUE = RUN
int nWalk=GetLocalInt(oMe,"nWalkDir"); // move in specific direction
object oCMNode=GetNearestObjectByTag("FIND_NODE",GetArea(oMe)); // local map node
object oDMNode=GetNearestObjectByTag("FIND_NODE",GetArea(oMDest));
int nDir;
string cx,cy,cz; // current X,Y,Z coordinates
string dx,dy,dz; // destination X,Y,Z coordinates
string sMNDown; // down destination
string sMNUp; // up destination
string sMNNorth; // North destination
string sMNSouth; // South destination
string sMNEast; // East destination
string sMNWest; // West destination
string sName; // name stored for FIND_NODES
string sParse; // used for parsing
float fDist=GetDistanceBetween(oDest,oMe);
float fAS=GetLocalFloat(oMe,"fAS");
int nASC=GetLocalInt(oMe,"nASC");
sName=GetName(oCMNode); ////// Get X,Y,Z coordinates
cx=fnParsePeriod(sName);
sName=fnRemParsed(sName,cx);
cy=fnParsePeriod(sName);
sName=fnRemParsed(sName,cy);
cz=fnParsePeriod(sName); ////// End X,Y,Z get
if (nMM==1) fnSneak();
if (GetArea(oDest)==GetArea(oMe)||fnDirectPathBetween(GetArea(oDest),GetArea(oMe)))
{ // same area
if (fDist<3.0&&fDist!=0.0)
{ // we are there
if (oDest==oMDest)
{ // final destination reached
SetLocalObject(oMe,"oMainDest",OBJECT_INVALID);
} // final destination reached
else
{ // set new destination
SetLocalObject(oMe,"oDestWP",oMDest);
} // set new destination
} // we are there
else
{ // check for anti-stuck
if (fAS==fDist&&fDist!=0.0)
{ // possibly stuck
nASC++;
if (nASC<5)
{ // gentle prod
AssignCommand(oMe,ActionMoveToObject(oDest,nRun,2.0));
} // gentle prod
else if (nASC==5)
{ // simple anti-stuck
oDest=GetNearestObject(OBJECT_TYPE_WAYPOINT,oMe,d4());
AssignCommand(oMe,ClearAllActions());
AssignCommand(oMe,ActionMoveToObject(oDest,nRun,3.0));
DelayCommand(10.0,AssignCommand(oMe,ClearAllActions()));
} // simple anti-stuck
else if (nASC==10)
{ // really stuck TELEPORT
AssignCommand(oMe,ClearAllActions());
AssignCommand(oMe,JumpToObject(oDest));
} // really stuck TELEPORT
else if (nASC>12)
{ // get unstuck - just do it
oDest=GetNearestObject(OBJECT_TYPE_WAYPOINT,oMe,d8());
AssignCommand(oMe,ClearAllActions());
AssignCommand(oMe,JumpToObject(oDest));
} // get unstuck - just do it
SetLocalInt(oMe,"nASC",nASC);
} // possibly stuck
else
{ // set distance for future AS and set AS counter to 0
SetLocalInt(oMe,"nASC",0);
SetLocalFloat(oMe,"fAS",fDist);
AssignCommand(oMe,ActionMoveToObject(oDest,nRun,2.0));
} // set distance for future AS and set AS counter to 0
} // check for anti-stuck
} // same area
else
{ // different area
fDist=GetDistanceBetween(oMe,oCMNode);
if (fDist==fAS)
{ // possibly stuck
nASC++;
if (nASC==5)
{ // simple anti-stuck
oDest=GetNearestObject(OBJECT_TYPE_WAYPOINT,oMe,d4());
AssignCommand(oMe,ClearAllActions());
AssignCommand(oMe,ActionMoveToObject(oDest,nRun,3.0));
DelayCommand(10.0,AssignCommand(oMe,ClearAllActions()));
} // simple anti-stuck
else if (nASC==10)
{ // really stuck TELEPORT
AssignCommand(oMe,ClearAllActions());
AssignCommand(oMe,JumpToObject(oDest));
} // really stuck TELEPORT
else if (nASC>12)
{ // get unstuck - just do it
oDest=GetNearestObject(OBJECT_TYPE_WAYPOINT,oMe,d8());
AssignCommand(oMe,ClearAllActions());
AssignCommand(oMe,JumpToObject(oDest));
} // get unstuck - just do it
SetLocalInt(oMe,"nASC",nASC);
} // possibly stuck
else
{ // not stuck
SetLocalInt(oMe,"nASC",0);
SetLocalFloat(oMe,"fAS",fDist);
nDir=fnAreaWhichDirection(oCMNode,oDMNode);
if (nDir==0)
{ // should be there
SetLocalObject(oMe,"oDestWP",oMDest);
} // should be there
else if (nDir==-1)
{ // error
} // error
else
{ // go that way
sName=fnCanGoDirection(GetArea(oMe),nDir);
oDest=GetObjectByTag(sName);
if (oDest!=OBJECT_INVALID)
{ // go to that area
oMDest=GetNearestObject(OBJECT_TYPE_WAYPOINT,oDest,d8());
while(oMDest==OBJECT_INVALID)
oMDest=GetNearestObject(OBJECT_TYPE_WAYPOINT,oDest,d8());
SetLocalObject(oMe,"oDestWP",oMDest);
} // go to that area
else
{
fnError(GetName(GetArea(oMe))+" pathing error direction: "+IntToString(nDir));
}
} // go that way
} // not stuck
} // different area
}