677 lines
28 KiB
Plaintext
677 lines
28 KiB
Plaintext
////////////////////////////////////////////////////////////////////////////////
|
|
// lib_hos2_shpath - Short Pathing AI
|
|
// By Deva B. Winblood. April 7th, 2008
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
const int MOVE_RESULT_MOVING = 0;
|
|
const int MOVE_RESULT_ARRIVED = 1;
|
|
const int MOVE_RESULT_UNREACHABLE = -1;
|
|
|
|
|
|
//////////////////////////////////////
|
|
// PROTOTYPES
|
|
//////////////////////////////////////
|
|
|
|
|
|
// FILE: lib_hos2_shpath FUNCTION: MoveToLocation()
|
|
// This will move oNPC to the location lLoc and uses a proxy object for distance
|
|
int MoveToLocation(object oNPC,location lLoc,int bRun=FALSE,float fRange=5.0);
|
|
|
|
|
|
// FILE: lib_hos2_shpath FUNCTION: MoveToObject()
|
|
// This will move oNPC to oTarget and will return -1 if object is unreachable
|
|
// or 1 if it has made it within range or 0 if it is still working on getting
|
|
// within range.
|
|
int MoveToObject(object oNPC,object oTarget,int bRun=FALSE,float fRange=5.0);
|
|
|
|
|
|
// FILE: lib_hos2_shpath FUNCTION: MoveTransition()
|
|
// This will move oNPC to an area near oDestination
|
|
void MoveTransition(object oNPC,object oDestination);
|
|
|
|
|
|
int fnGetTransitionCount(int bAboveGround);
|
|
|
|
|
|
object fnGetRandomTransition(int bAboveGround,object oFor=OBJECT_INVALID,int bLightFatal=FALSE);
|
|
|
|
// FILE: lib_hos2_shpath FUNCTION: MoveGetRandomLocation()
|
|
// Get a Random Destination within nRange of lCenter. nRange is the max
|
|
// deviation in x and y coordinates allowed.
|
|
location MoveGetRandomLocation(location lCenter,int nRange=10);
|
|
|
|
|
|
// FILE: lib_hos2_shpath FUNCTION: MoveToAndUseTransition()
|
|
// This will move oNPC to within fRange of oTransition and then will transition.
|
|
// This function does not return any feedback so, it should only be used by
|
|
// routines that know when they have reached where they are trying to go.
|
|
void MoveToAndUseTransition(object oNPC,object oTransition,float fRange=4.0);
|
|
|
|
|
|
//////////////////////////////////////
|
|
// FUNCTIONS
|
|
//////////////////////////////////////
|
|
|
|
|
|
location MoveGetRandomLocation(location lCenter,int nRange=10)
|
|
{ // PURPOSE: Return a Random Location
|
|
location lRet=lCenter;
|
|
vector vCenter=GetPositionFromLocation(lCenter);
|
|
int nCX=FloatToInt(vCenter.x);
|
|
int nCY=FloatToInt(vCenter.y);
|
|
int nMinX=nCX-nRange;
|
|
int nMinY=nCY-nRange;
|
|
int nMaxX=nCX+nRange;
|
|
int nMaxY=nCY+nRange;
|
|
object oArea=GetAreaFromLocation(lCenter);
|
|
int nAreaX=GetAreaSize(AREA_WIDTH,oArea)*10;
|
|
int nAreaY=GetAreaSize(AREA_HEIGHT,oArea)*10;
|
|
int nRollX;
|
|
int nRollY;
|
|
//SendMessageToPC(GetFirstPC(),"[lib_hos2_shpath]MoveGetRandomLocation("+IntToString(nRange)+") Center X:"+IntToString(nCX)+" Center Y:"+IntToString(nCY)+" nArea(x:"+IntToString(nAreaX)+", y:"+IntToString(nAreaY)+")");
|
|
if (nMinX<1) nMinX=1;
|
|
if (nMinY<1) nMinY=1;
|
|
if (nMaxX>=nAreaX) nMaxX=nAreaX-1;
|
|
if (nMaxY>=nAreaY) nMaxY=nAreaY-1;
|
|
nCX=nMaxX-nMinX;
|
|
nCY=nMaxY-nMinY;
|
|
//SendMessageToPC(GetFirstPC()," nMinX:"+IntToString(nMinX)+" nMaxX:"+IntToString(nMaxX)+" nDiffX:"+IntToString(nCX)+" nMinY:"+IntToString(nMinY)+" nMaxY:"+IntToString(nMaxY)+" nDiffY:"+IntToString(nCY));
|
|
nRollX=nMinX+Random(nCX);
|
|
nRollY=nMinY+Random(nCY);
|
|
//SendMessageToPC(GetFirstPC()," nRollX:"+IntToString(nRollX)+", nRollY:"+IntToString(nRollY));
|
|
vCenter.x=IntToFloat(nRollX);
|
|
vCenter.y=IntToFloat(nRollY);
|
|
lRet=Location(oArea,vCenter,IntToFloat(Random(360)));
|
|
return lRet;
|
|
} // MoveGetRandomLocation()
|
|
|
|
|
|
|
|
|
|
int MoveToLocation(object oNPC,location lLoc,int bRun=FALSE,float fRange=5.0)
|
|
{ // PURPOSE: Move to lLocation and use an object as a proxy since pathing to
|
|
// objects handles pathing better using the Engine
|
|
object oShortPathDest=GetLocalObject(oNPC,"oShortPathDest");
|
|
float fLast;
|
|
float fDist=GetDistanceBetween(oNPC,oShortPathDest);
|
|
location lDest=GetLocalLocation(oNPC,"lShortPathDest");
|
|
if (lDest!=lLoc)
|
|
{ // new
|
|
if (GetIsObjectValid(oShortPathDest)) DestroyObject(oShortPathDest);
|
|
AssignCommand(oNPC,ClearAllActions()); // stop trying to reach old path
|
|
} // new
|
|
if (!GetIsObjectValid(oShortPathDest)||fDist<1.0)
|
|
{ // create pathing object
|
|
if (GetIsObjectValid(oShortPathDest)) DestroyObject(oShortPathDest);
|
|
oShortPathDest=CreateObject(OBJECT_TYPE_PLACEABLE,"pathing_object",lLoc);
|
|
if (!GetIsObjectValid(oShortPathDest)) return -1;
|
|
SetLocalObject(oShortPathDest,"oOwner",oNPC);
|
|
SetLocalObject(oNPC,"oShortPathDest",oShortPathDest);
|
|
fDist=GetDistanceBetween(oNPC,oShortPathDest);
|
|
SetLocalLocation(oNPC,"lShortPathDest",lLoc);
|
|
} // create pathing object
|
|
if (fDist<=fRange)
|
|
{ // arrived
|
|
DestroyObject(oShortPathDest);
|
|
DeleteLocalFloat(oNPC,"fLastShortPath");
|
|
DeleteLocalInt(oNPC,"nASCShortPath");
|
|
return 1;
|
|
} // arrived
|
|
fLast=GetLocalFloat(oNPC,"fLastShortPath");
|
|
if (fLast!=0.0&&fLast<=fDist)
|
|
{ // stuck
|
|
int nASC=GetLocalInt(oNPC,"nASCShortPath");
|
|
nASC++;
|
|
//SendMessageToPC(GetFirstPC()," Stuck:"+IntToString(nASC));
|
|
if (nASC<2)
|
|
{ // try again
|
|
SetLocalInt(oNPC,"nASCShortPath",nASC);
|
|
AssignCommand(oNPC,ClearAllActions(TRUE));
|
|
AssignCommand(oNPC,ActionMoveToObject(oShortPathDest,TRUE,fRange-0.5));
|
|
} // try again
|
|
else if (nASC==2)
|
|
{ // try moving away
|
|
SetLocalInt(oNPC,"nASCShortPath",nASC);
|
|
AssignCommand(oNPC,ClearAllActions(TRUE));
|
|
AssignCommand(oNPC,ActionMoveAwayFromObject(oShortPathDest,TRUE,fDist+2.0));
|
|
AssignCommand(oNPC,ActionMoveToObject(oShortPathDest,TRUE,fRange-0.5));
|
|
} // try moving away
|
|
else if (nASC==3)
|
|
{ // move towards one more time
|
|
SetLocalInt(oNPC,"nASCShortPath",nASC);
|
|
AssignCommand(oNPC,ClearAllActions(TRUE));
|
|
AssignCommand(oNPC,ActionMoveToObject(oShortPathDest,TRUE,fRange-0.5));
|
|
} // move towards one more time
|
|
else
|
|
{ // cannot reach
|
|
DestroyObject(oShortPathDest);
|
|
DeleteLocalFloat(oNPC,"fLastShortPath");
|
|
DeleteLocalInt(oNPC,"nASCShortPath");
|
|
return -1;
|
|
} // cannot reach
|
|
} // stuck
|
|
else
|
|
{ // move
|
|
AssignCommand(oNPC,ClearAllActions(TRUE));
|
|
AssignCommand(oNPC,ActionMoveToObject(oShortPathDest,bRun,fRange-0.5));
|
|
SetLocalFloat(oNPC,"fLastShortPath",fDist);
|
|
DeleteLocalInt(oNPC,"nASCShortPath");
|
|
} // move
|
|
return 0;
|
|
} // MoveToLocation()
|
|
|
|
|
|
void VectorMove(object oNPC,object oMoveAfter,float fRange)
|
|
{ // PURPOSE: Move to a random Vector
|
|
vector vPos=GetPosition(oNPC);
|
|
int nRX=Random(601)-300;
|
|
int nRY=Random(601)-300;
|
|
float fRX=IntToFloat(nRX)/10.0;
|
|
float fRY=IntToFloat(nRY)/10.0;
|
|
vPos.x=vPos.x+fRX;
|
|
vPos.y=vPos.y+fRY;
|
|
location lLoc=Location(GetArea(oNPC),vPos,IntToFloat(Random(360)));
|
|
AssignCommand(oNPC,ActionMoveToLocation(lLoc,TRUE));
|
|
AssignCommand(oNPC,ActionMoveToObject(oMoveAfter,TRUE,fRange));
|
|
} // VectorMove()
|
|
|
|
|
|
int privateMoveToObject(object oNPC,object oTarget,int bRun,float fRange,object oShortPathDest)
|
|
{ // PURPOSE: PATHING
|
|
float fLast;
|
|
float fDist;
|
|
int nN;
|
|
int nASC;
|
|
object oMe=oNPC;
|
|
if (oShortPathDest!=oTarget)
|
|
{ // new destination
|
|
SetLocalObject(oNPC,"oShortPathDest",oTarget);
|
|
DeleteLocalFloat(oNPC,"fLastShortPath");
|
|
DeleteLocalInt(oNPC,"nASCShortPath");
|
|
AssignCommand(oNPC,ClearAllActions());
|
|
AssignCommand(oNPC,ActionMoveToObject(oTarget,bRun,fRange));
|
|
} // new destination
|
|
else
|
|
{ // same destination
|
|
fLast=GetLocalFloat(oNPC,"fLastShortPath");
|
|
if (fLast==0.0) fLast=999.0;
|
|
fDist=GetDistanceBetween(oNPC,oTarget);
|
|
if (fDist<=fRange)
|
|
{ // arrived
|
|
DeleteLocalInt(oNPC,"nASCShortPath");
|
|
AssignCommand(oNPC,ClearAllActions());
|
|
return 1;
|
|
} // arrived
|
|
else if (fDist!=fLast)
|
|
{ // not stuck
|
|
if (GetCurrentAction(oNPC)!=ACTION_MOVETOPOINT)
|
|
{ // move
|
|
AssignCommand(oNPC,ClearAllActions());
|
|
AssignCommand(oNPC,ActionMoveToObject(oTarget,bRun,fRange));
|
|
} // move
|
|
if (fDist<fLast) DeleteLocalInt(oNPC,"nASCShortPath");
|
|
SetLocalFloat(oNPC,"fLastShortPath",fDist);
|
|
} // not stuck
|
|
else
|
|
{ // stuck
|
|
nASC=GetLocalInt(oNPC,"nASCShortPath");
|
|
nASC++;
|
|
SetLocalInt(oNPC,"nASCShortPath",nASC);
|
|
if (nASC<1)
|
|
{ // normal move attempt
|
|
AssignCommand(oNPC,ClearAllActions());
|
|
AssignCommand(oNPC,ActionMoveToObject(oTarget,bRun,fRange));
|
|
} // normal move attempt
|
|
else if (nASC==1||nASC==2)
|
|
{ // choose nearby random location
|
|
AssignCommand(oNPC,ClearAllActions());
|
|
AssignCommand(oNPC,ActionMoveAwayFromObject(oTarget,TRUE,fDist+(fRange*1.0)));
|
|
AssignCommand(oNPC,ActionDoCommand(VectorMove(oNPC,oTarget,fRange)));
|
|
} // choose nearby random location
|
|
else if (nASC==3)
|
|
{ // normal move attempt
|
|
AssignCommand(oNPC,ClearAllActions());
|
|
AssignCommand(oNPC,ActionMoveToObject(oTarget,TRUE,fRange));
|
|
} // normal move attempt
|
|
else if (nASC==4)
|
|
{ // jump
|
|
AssignCommand(oNPC,ClearAllActions());
|
|
AssignCommand(oNPC,JumpToObject(oTarget));
|
|
} // jump
|
|
else
|
|
{ // unreachable
|
|
return -1;
|
|
} // unreachable
|
|
} // stuck
|
|
} // same destination
|
|
return 0;
|
|
} // privateMoveToObject()
|
|
|
|
|
|
int MoveToObject(object oNPC,object oTarget,int bRun=FALSE,float fRange=5.0)
|
|
{ // PURPOSE: MoveToObject
|
|
object oShortPathDest=GetLocalObject(oNPC,"oShortPathDest");
|
|
float fLast;
|
|
float fDist;
|
|
object oOb=GetNearestObjectByTag("ALT_PATH",oTarget,1);
|
|
int nN;
|
|
int nASC;
|
|
object oMe=oNPC;
|
|
//AssignCommand(oNPC,ClearAllActions());
|
|
if (!GetIsObjectValid(oOb))
|
|
{ // normal pathing
|
|
if (GetLocalInt(GetArea(oNPC),"bOP")!=TRUE)
|
|
{ // standard
|
|
nN=privateMoveToObject(oNPC,oTarget,bRun,fRange,oShortPathDest);
|
|
return nN;
|
|
} // standard
|
|
else
|
|
{ // outer planes
|
|
if (GetArea(oTarget)==GetArea(oNPC))
|
|
{ // in same area
|
|
nN=privateMoveToObject(oNPC,oTarget,bRun,fRange,oShortPathDest);
|
|
return nN;
|
|
} // in same area
|
|
else
|
|
{ // other area
|
|
if (GetIsObjectValid(oShortPathDest)&&GetArea(oShortPathDest)==GetArea(oNPC))
|
|
{ // same area
|
|
nN=privateMoveToObject(oNPC,oTarget,bRun,fRange,oShortPathDest);
|
|
if (nN==1)
|
|
{ // jump
|
|
AssignCommand(oNPC,ClearAllActions());
|
|
AssignCommand(oNPC,JumpToObject(GetTransitionTarget(oShortPathDest)));
|
|
DeleteLocalObject(oNPC,"oShortPathDest");
|
|
return 0;
|
|
} // jump
|
|
} // same area
|
|
else
|
|
{ // find a door
|
|
nN=1;
|
|
oShortPathDest=OBJECT_INVALID;
|
|
oOb=GetNearestObject(OBJECT_TYPE_DOOR,oNPC,nN);
|
|
while(!GetIsObjectValid(oShortPathDest)&&GetIsObjectValid(oOb))
|
|
{ // check doors
|
|
if (GetIsObjectValid(GetTransitionTarget(oOb))&&GetArea(GetTransitionTarget(oOb))==GetArea(oTarget))
|
|
{ // transition found
|
|
oShortPathDest=oOb;
|
|
} // transition found
|
|
nN++;
|
|
oOb=GetNearestObject(OBJECT_TYPE_DOOR,oNPC,nN);
|
|
} // check doors
|
|
nN=1;
|
|
oOb=GetNearestObject(OBJECT_TYPE_TRIGGER,oNPC,nN);
|
|
while(!GetIsObjectValid(oShortPathDest)&&GetIsObjectValid(oOb))
|
|
{ // check triggers
|
|
if (GetIsObjectValid(GetTransitionTarget(oOb))&&GetArea(GetTransitionTarget(oOb))==GetArea(oTarget))
|
|
{ // transition found
|
|
oShortPathDest=oOb;
|
|
} // transition found
|
|
nN++;
|
|
oOb=GetNearestObject(OBJECT_TYPE_TRIGGER,oNPC,nN);
|
|
} // check triggers
|
|
if (GetIsObjectValid(oShortPathDest))
|
|
{ // transition found
|
|
SetLocalObject(oNPC,"oShortPathDest",oShortPathDest);
|
|
AssignCommand(oNPC,ClearAllActions());
|
|
AssignCommand(oNPC,ActionMoveToObject(oShortPathDest,bRun,4.0));
|
|
return 0;
|
|
} // transition found
|
|
else
|
|
{ // error
|
|
return -1; // no direct door to the area
|
|
} // error
|
|
} // find a door
|
|
} // other area
|
|
} // outer planes
|
|
} // normal pathing
|
|
else
|
|
{ // alternate pathing
|
|
if (oShortPathDest!=oTarget)
|
|
{ // new path
|
|
SetLocalObject(oMe,"oShortPathDest",oTarget);
|
|
DeleteLocalInt(oMe,"nASCShortPath");
|
|
DeleteLocalInt(oMe,"nASCState");
|
|
SetLocalFloat(oMe,"fLastShortPath",900.0);
|
|
nASC=0;
|
|
oShortPathDest=oTarget;
|
|
} // new path
|
|
nN=GetLocalInt(oMe,"nASCState");
|
|
fLast=GetLocalFloat(oMe,"fLastShortPath");
|
|
if (nN==0)
|
|
{ // path to nearest alt path
|
|
fDist=GetDistanceBetween(oMe,oOb);
|
|
if (fDist<=3.0)
|
|
{ // arrived - next state
|
|
SetLocalInt(oMe,"nASCState",1);
|
|
AssignCommand(oMe,ClearAllActions());
|
|
oOb=GetNearestObjectByTag("ALT_PATH",oTarget,1);
|
|
AssignCommand(oMe,ActionMoveToObject(oOb,bRun,fRange));
|
|
DeleteLocalInt(oMe,"nASCShortPath");
|
|
SetLocalFloat(oMe,"fLastShortPath",900.0);
|
|
} // arrived - next state
|
|
else
|
|
{ // move
|
|
if (fDist==fLast)
|
|
{ // stuck
|
|
nASC=GetLocalInt(oMe,"nASCShortPath");
|
|
if (nASC<1)
|
|
{ // try moving again
|
|
AssignCommand(oNPC,ClearAllActions());
|
|
AssignCommand(oNPC,ActionMoveToObject(oOb,TRUE,fRange));
|
|
nASC++;
|
|
SetLocalInt(oMe,"nASCShortPath",nASC);
|
|
} // try moving again
|
|
else if (nASC<3)
|
|
{ // try random vector
|
|
AssignCommand(oNPC,ClearAllActions());
|
|
AssignCommand(oNPC,ActionMoveAwayFromObject(oOb,TRUE,fDist+(fRange*1.5)));
|
|
AssignCommand(oNPC,ActionDoCommand(VectorMove(oOb,oTarget,fRange)));
|
|
nASC++;
|
|
SetLocalInt(oMe,"nASCShortPath",nASC);
|
|
} // try random vector
|
|
else
|
|
{ // go onto next path
|
|
SetLocalInt(oMe,"nASCState",1);
|
|
AssignCommand(oMe,ClearAllActions());
|
|
oOb=GetNearestObjectByTag("ALT_PATH",oTarget,1);
|
|
AssignCommand(oMe,ActionMoveToObject(oOb,bRun,fRange));
|
|
DeleteLocalInt(oMe,"nASCShortPath");
|
|
SetLocalFloat(oMe,"fLastShortPath",900.0);
|
|
} // go onto next path
|
|
} // stuck
|
|
else
|
|
{ // move
|
|
AssignCommand(oMe,ClearAllActions());
|
|
AssignCommand(oMe,ActionMoveToObject(oOb,bRun,2.9));
|
|
SetLocalFloat(oMe,"fLastShortPath",fDist);
|
|
} // move
|
|
} // move
|
|
} // path to nearest alt path
|
|
else if (nN==1)
|
|
{ // nearest alt path to destination
|
|
oOb=GetNearestObjectByTag("ALT_PATH",oTarget,1);
|
|
fDist=GetDistanceBetween(oMe,oOb);
|
|
if (fDist<=3.0)
|
|
{ // arrived
|
|
SetLocalInt(oMe,"nASCState",2);
|
|
AssignCommand(oMe,ClearAllActions());
|
|
oOb=oTarget;
|
|
AssignCommand(oMe,ActionMoveToObject(oOb,bRun,fRange));
|
|
DeleteLocalInt(oMe,"nASCShortPath");
|
|
SetLocalFloat(oMe,"fLastShortPath",900.0);
|
|
} // arrived
|
|
else
|
|
{ // move
|
|
if (fDist==fLast)
|
|
{ // stuck
|
|
nASC=GetLocalInt(oMe,"nASCShortPath");
|
|
if (nASC<1)
|
|
{ // try moving again
|
|
AssignCommand(oNPC,ClearAllActions());
|
|
AssignCommand(oNPC,ActionMoveToObject(oOb,TRUE,fRange));
|
|
nASC++;
|
|
SetLocalInt(oMe,"nASCShortPath",nASC);
|
|
} // try moving again
|
|
else if (nASC<3)
|
|
{ // try random vector
|
|
AssignCommand(oNPC,ClearAllActions());
|
|
AssignCommand(oNPC,ActionMoveAwayFromObject(oOb,TRUE,fDist+(fRange*1.5)));
|
|
AssignCommand(oNPC,ActionDoCommand(VectorMove(oOb,oTarget,fRange)));
|
|
nASC++;
|
|
SetLocalInt(oMe,"nASCShortPath",nASC);
|
|
} // try random vector
|
|
else
|
|
{ // go onto next path
|
|
SetLocalInt(oMe,"nASCState",2);
|
|
AssignCommand(oMe,ClearAllActions());
|
|
oOb=GetNearestObjectByTag("ALT_PATH",oTarget,1);
|
|
AssignCommand(oMe,ActionMoveToObject(oOb,bRun,fRange));
|
|
DeleteLocalInt(oMe,"nASCShortPath");
|
|
SetLocalFloat(oMe,"fLastShortPath",900.0);
|
|
} // go onto next path
|
|
} // stuck
|
|
else
|
|
{ // move
|
|
AssignCommand(oMe,ClearAllActions());
|
|
AssignCommand(oMe,ActionMoveToObject(oOb,bRun,2.9));
|
|
SetLocalFloat(oMe,"fLastShortPath",fDist);
|
|
} // move
|
|
} // move
|
|
} // nearest alt path to destination
|
|
else if (nN==2)
|
|
{ // path to desired destination
|
|
oOb=oTarget;
|
|
fDist=GetDistanceBetween(oMe,oOb);
|
|
if (fDist<=fRange) return 1;
|
|
if (fDist==fLast)
|
|
{ // stuck
|
|
nASC=GetLocalInt(oMe,"nASCShortPath");
|
|
if (nASC<1)
|
|
{ // try moving again
|
|
AssignCommand(oNPC,ClearAllActions());
|
|
AssignCommand(oNPC,ActionMoveToObject(oOb,TRUE,fRange));
|
|
nASC++;
|
|
SetLocalInt(oMe,"nASCShortPath",nASC);
|
|
} // try moving again
|
|
else if (nASC<3)
|
|
{ // try random vector
|
|
AssignCommand(oNPC,ClearAllActions());
|
|
AssignCommand(oNPC,ActionMoveAwayFromObject(oOb,TRUE,fDist+(fRange*1.5)));
|
|
AssignCommand(oNPC,ActionDoCommand(VectorMove(oOb,oTarget,fRange)));
|
|
nASC++;
|
|
SetLocalInt(oMe,"nASCShortPath",nASC);
|
|
} // try random vector
|
|
else if (nASC==4)
|
|
{ // jump
|
|
AssignCommand(oNPC,ClearAllActions());
|
|
AssignCommand(oNPC,JumpToObject(oTarget));
|
|
nASC++;
|
|
SetLocalInt(oMe,"nASCShortPath",nASC);
|
|
} // jump
|
|
else
|
|
{ // fail
|
|
DeleteLocalInt(oMe,"nASCShortPath");
|
|
return -1;
|
|
} // fail
|
|
} // stuck
|
|
else
|
|
{ // move
|
|
AssignCommand(oMe,ClearAllActions());
|
|
AssignCommand(oMe,ActionMoveToObject(oOb,bRun,2.9));
|
|
SetLocalFloat(oMe,"fLastShortPath",fDist);
|
|
} // move
|
|
} // path to desired destination
|
|
} // alternate pathing
|
|
return 0;
|
|
} // MoveToObject()
|
|
|
|
|
|
void MoveTransition(object oNPC,object oDestination)
|
|
{ // PURPOSE: Move to a location near the oDestination
|
|
object oWP=GetNearestObject(OBJECT_TYPE_WAYPOINT,oDestination,1);
|
|
//SendMessageToPC(GetFirstPC(),"["+GetTag(oNPC)+"] oDestination='"+GetTag(oDestination)+"' oWP='"+GetTag(oWP)+"'");
|
|
if (GetDistanceBetween(oWP,oDestination)<6.0)
|
|
{ // jump
|
|
DeleteLocalObject(oNPC,"oTransition");
|
|
SetLocalObject(oNPC,"oWasHere",GetArea(oNPC));
|
|
AssignCommand(oNPC,ActionJumpToObject(oWP));
|
|
AssignCommand(oNPC,ActionMoveAwayFromObject(oDestination,TRUE,6.0));
|
|
AssignCommand(oNPC,ActionDoCommand(ClearAllActions()));
|
|
} // jump
|
|
else
|
|
{ // normal
|
|
DeleteLocalObject(oNPC,"oTransition");
|
|
SetLocalObject(oNPC,"oWasHere",GetArea(oNPC));
|
|
AssignCommand(oNPC,ActionJumpToObject(oDestination));
|
|
AssignCommand(oNPC,ActionMoveAwayFromObject(oDestination,TRUE,6.0));
|
|
AssignCommand(oNPC,ActionDoCommand(ClearAllActions()));
|
|
} // normal
|
|
} // MoveTransition()
|
|
|
|
|
|
int fnGetTransitionCount(int bAboveGround)
|
|
{ // PURPOSE: Returns the transition count for this area
|
|
object oMe=OBJECT_SELF;
|
|
int nCountA=GetLocalInt(GetArea(oMe),"nTransitionCountA");
|
|
int nCountB=GetLocalInt(GetArea(oMe),"nTransitionCountB");
|
|
if (nCountA>0&&bAboveGround) return nCountA;
|
|
if (nCountB>0&&!bAboveGround) return nCountB;
|
|
int nN;
|
|
object oOb;
|
|
object oTrans;
|
|
//SendMessageToPC(GetFirstPC(),"fnGetTransitionCount("+IntToString(bAboveGround)+")");
|
|
nN=1;
|
|
oOb=GetNearestObject(OBJECT_TYPE_TRIGGER,oMe,nN);
|
|
while(GetIsObjectValid(oOb))
|
|
{ // count triggers
|
|
oTrans=GetTransitionTarget(oOb);
|
|
if (GetIsObjectValid(oTrans))
|
|
{ // transition
|
|
if(GetIsAreaAboveGround(GetArea(oTrans))&&!GetIsAreaInterior(GetArea(oTrans)))
|
|
{ // above ground
|
|
nCountA++;
|
|
//SendMessageToPC(GetFirstPC()," [A"+IntToString(nCountA)+"] "+GetTag(oOb));
|
|
SetLocalObject(GetArea(oMe),"oTransitionA"+IntToString(nCountA),oOb);
|
|
} // above ground
|
|
else
|
|
{ // below ground
|
|
nCountB++;
|
|
//SendMessageToPC(GetFirstPC()," [B"+IntToString(nCountB)+"] "+GetTag(oOb));
|
|
SetLocalObject(GetArea(oMe),"oTransitionB"+IntToString(nCountB),oOb);
|
|
} // below ground
|
|
} // transition
|
|
nN++;
|
|
oOb=GetNearestObject(OBJECT_TYPE_TRIGGER,oMe,nN);
|
|
} // count triggers
|
|
nN=1;
|
|
oOb=GetNearestObject(OBJECT_TYPE_DOOR,oMe,nN);
|
|
while(GetIsObjectValid(oOb))
|
|
{ // count doors
|
|
oTrans=GetTransitionTarget(oOb);
|
|
if (GetIsObjectValid(oTrans))
|
|
{ // transition
|
|
if(GetIsAreaAboveGround(GetArea(oTrans))&&!GetIsAreaInterior(GetArea(oTrans)))
|
|
{ // above ground
|
|
nCountA++;
|
|
//SendMessageToPC(GetFirstPC()," [A"+IntToString(nCountA)+"] "+GetTag(oOb));
|
|
SetLocalObject(GetArea(oMe),"oTransitionA"+IntToString(nCountA),oOb);
|
|
} // above ground
|
|
else
|
|
{ // below ground
|
|
nCountB++;
|
|
//SendMessageToPC(GetFirstPC()," [B"+IntToString(nCountB)+"] "+GetTag(oOb));
|
|
SetLocalObject(GetArea(oMe),"oTransitionB"+IntToString(nCountB),oOb);
|
|
} // below ground
|
|
} // transition
|
|
nN++;
|
|
oOb=GetNearestObject(OBJECT_TYPE_DOOR,oMe,nN);
|
|
} // count doors
|
|
nN=1;
|
|
oOb=GetNearestObject(OBJECT_TYPE_PLACEABLE,oMe,nN);
|
|
while(GetIsObjectValid(oOb))
|
|
{ // count doors
|
|
oTrans=GetObjectByTag(GetLocalString(oOb,"sDestTag"));
|
|
if (GetIsObjectValid(oTrans))
|
|
{ // transition
|
|
if(GetIsAreaAboveGround(GetArea(oTrans))&&!GetIsAreaInterior(GetArea(oTrans)))
|
|
{ // above ground
|
|
nCountA++;
|
|
//SendMessageToPC(GetFirstPC()," [A"+IntToString(nCountA)+"] "+GetTag(oOb));
|
|
SetLocalObject(GetArea(oMe),"oTransitionA"+IntToString(nCountA),oOb);
|
|
} // above ground
|
|
else
|
|
{ // below ground
|
|
nCountB++;
|
|
//SendMessageToPC(GetFirstPC()," [B"+IntToString(nCountB)+"] "+GetTag(oOb));
|
|
SetLocalObject(GetArea(oMe),"oTransitionB"+IntToString(nCountB),oOb);
|
|
} // below ground
|
|
} // transition
|
|
nN++;
|
|
oOb=GetNearestObject(OBJECT_TYPE_PLACEABLE,oMe,nN);
|
|
} // count doors
|
|
//SendMessageToPC(GetFirstPC()," Above Count:"+IntToString(nCountA)+" Below Count:"+IntToString(nCountB));
|
|
SetLocalInt(GetArea(oMe),"nTransitionCountA",nCountA);
|
|
SetLocalInt(GetArea(oMe),"nTransitionCountB",nCountB);
|
|
if (bAboveGround) return nCountA;
|
|
return nCountB;
|
|
} // fnGetTransitionCount()
|
|
|
|
|
|
object fnGetRandomTransition(int bAboveGround,object oFor=OBJECT_INVALID,int bLightFatal=FALSE)
|
|
{ // PURPOSE: Get a random transition
|
|
object oRet;
|
|
int nCount=fnGetTransitionCount(bAboveGround);
|
|
//SendMessageToPC(GetFirstPC(),"[Random Transition]: AboveGround:"+IntToString(nCount));
|
|
if (nCount>0)
|
|
{ // random
|
|
int nR=Random(nCount)+1;
|
|
if (bAboveGround&&(GetIsNight()||!bLightFatal)) oRet=GetLocalObject(GetArea(OBJECT_SELF),"oTransitionA"+IntToString(nR));
|
|
else { oRet=GetLocalObject(GetArea(OBJECT_SELF),"oTransitionB"+IntToString(nR)); }
|
|
//SendMessageToPC(GetFirstPC()," First:("+IntToString(nR)+") Choose:"+GetTag(oRet));
|
|
if ((GetArea(GetTransitionTarget(oRet))==oFor||GetLocked(oRet))&&nCount>1)
|
|
{ // try again
|
|
nR=nR+1;
|
|
if (nR>nCount) nR=1;
|
|
if (bAboveGround&&(GetIsNight()||!bLightFatal)) oRet=GetLocalObject(GetArea(OBJECT_SELF),"oTransitionA"+IntToString(nR));
|
|
else { oRet=GetLocalObject(GetArea(OBJECT_SELF),"oTransitionB"+IntToString(nR)); }
|
|
//SendMessageToPC(GetFirstPC()," Second:("+IntToString(nR)+") Choose:"+GetTag(oRet));
|
|
} // try again
|
|
return oRet;
|
|
} // random
|
|
return OBJECT_INVALID;
|
|
} // fnGetRandomTransition()
|
|
|
|
|
|
void MoveToAndUseTransition(object oNPC,object oTransition,float fRange=4.0)
|
|
{ // PURPOSE: Move to oTransition and then transition
|
|
int nN;
|
|
object oDest;
|
|
nN=MoveToObject(oNPC,oTransition,TRUE,fRange);
|
|
if (nN==1)
|
|
{ // arrived
|
|
if (GetObjectType(oTransition)==OBJECT_TYPE_DOOR)
|
|
{ // door
|
|
AssignCommand(oNPC,ClearAllActions());
|
|
AssignCommand(oNPC,ActionDoCommand(SetFacingPoint(GetPosition(oTransition))));
|
|
if (!GetIsOpen(oTransition))
|
|
{ // open door
|
|
AssignCommand(oNPC,ActionPlayAnimation(ANIMATION_LOOPING_GET_MID,1.0,2.0));
|
|
AssignCommand(oTransition,ActionOpenDoor(oTransition));
|
|
} // open door
|
|
oDest=GetTransitionTarget(oTransition);
|
|
if (GetObjectType(oDest)==OBJECT_TYPE_DOOR&&!GetIsOpen(oDest)) AssignCommand(oNPC,ActionDoCommand(AssignCommand(oDest,ActionOpenDoor(oDest))));
|
|
AssignCommand(oNPC,ActionDoCommand(MoveTransition(oNPC,oDest)));
|
|
DeleteLocalObject(oNPC,"oWasHere");
|
|
DeleteLocalObject(oNPC,"oTransition");
|
|
} // door
|
|
else if (GetObjectType(oTransition)==OBJECT_TYPE_PLACEABLE)
|
|
{ // placeable
|
|
AssignCommand(oNPC,ClearAllActions());
|
|
AssignCommand(oNPC,ActionDoCommand(SetFacingPoint(GetPosition(oTransition))));
|
|
AssignCommand(oNPC,ActionPlayAnimation(ANIMATION_LOOPING_GET_MID,1.0,2.0));
|
|
oDest=GetObjectByTag(GetLocalString(oTransition,"sDestTag"));
|
|
if (GetObjectType(oDest)==OBJECT_TYPE_DOOR&&!GetIsOpen(oDest)) AssignCommand(oNPC,ActionDoCommand(AssignCommand(oDest,ActionOpenDoor(oDest))));
|
|
AssignCommand(oNPC,ActionDoCommand(MoveTransition(oNPC,oDest)));
|
|
DeleteLocalObject(oNPC,"oWasHere");
|
|
DeleteLocalObject(oNPC,"oTransition");
|
|
} // placeable
|
|
else
|
|
{ // trigger
|
|
AssignCommand(oNPC,ClearAllActions());
|
|
oDest=GetTransitionTarget(oTransition);
|
|
if (GetObjectType(oDest)==OBJECT_TYPE_DOOR&&!GetIsOpen(oDest)) AssignCommand(oNPC,ActionDoCommand(AssignCommand(oDest,ActionOpenDoor(oDest))));
|
|
AssignCommand(oNPC,ActionDoCommand(MoveTransition(oNPC,oDest)));
|
|
DeleteLocalObject(oNPC,"oWasHere");
|
|
DeleteLocalObject(oNPC,"oTransition");
|
|
} // trigger
|
|
} // arrived
|
|
else if (nN==-1)
|
|
{ // error
|
|
PrintString("[Error: lib_hos2_shpath(MoveToAndUseTransition)] Cannot reach transition '"+GetTag(oTransition)+"' in area '"+GetName(GetArea(oNPC))+"'");
|
|
DeleteLocalObject(oNPC,"oTransition");
|
|
} // error
|
|
} // MoveToAndUseTransition()
|
|
|
|
//void main(){}
|