HoS_PRC8/_mod/_module/nss/lib_hos2_shpath.nss
Jaysyn904 04165202c0 Initial upload
Initial upload
2024-11-25 19:36:07 -05:00

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(){}