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

484 lines
16 KiB
Plaintext

//////////////////////////////////////////////////////////////////////////////
// Real Time Strategy - NWN - Header file for some useful functions
//===========================================================================
// By Deva Bryson Winblood. 02/24/2003
//////////////////////////////////////////////////////////////////////////////
// FILE: rts_header
int fnMoveToDestination(object oWP,int nAS=FALSE,int nInitStack=FALSE);
////
int MAX_AI_SCAN = 4; // used to prevent TMI errors
int fnCheckForLight()
{ // fnCheckForLight
object oMe=OBJECT_SELF;
object oMod=GetModule();
int nSun=GetLocalInt(oMod,GetTag(oMe)+"_light");
return nSun;
} // fnCheckForLight
int fnArePCsPresent(object oArea)
{
int nRet=0;
object oOb=GetFirstObjectInArea(oArea);
if (GetObjectType(oOb)!=OBJECT_TYPE_WAYPOINT) oOb=GetNearestObject(OBJECT_TYPE_WAYPOINT,oOb,1);
if (GetNearestCreature(CREATURE_TYPE_PLAYER_CHAR,PLAYER_CHAR_IS_PC,oOb,1)!=OBJECT_INVALID) return 1;
return nRet;
} // fnCountPCsInArea()
object fnRandomObject(object oArea,int nType=OBJECT_TYPE_ALL)
{
object oRet=OBJECT_INVALID;
object oTest=GetFirstObjectInArea(oArea);
int nC=GetLocalInt(oArea,"nAllObjects");
if (nType==OBJECT_TYPE_PLACEABLE) nC=GetLocalInt(oArea,"nPlaceables");
else if (nType==OBJECT_TYPE_TRIGGER) nC=GetLocalInt(oArea,"nTriggers");
else if (nType==OBJECT_TYPE_DOOR) nC=GetLocalInt(oArea,"nDoors");
else if (nType==OBJECT_TYPE_WAYPOINT) nC=GetLocalInt(oArea,"nWaypoints");
oRet=GetNearestObject(nType,oTest,Random(nC)+1);
return oRet;
} // fnRandomObject()
object fnExposed(object oD)
{ // return OBJECT_INVALID if has an RTS_SURFACE
object oRet=OBJECT_INVALID;
object oW;
if (GetTransitionTarget(oD)!=OBJECT_INVALID)
{
oW=GetNearestObjectByTag("RTS_SURFACE",GetTransitionTarget(oD));
if (oW==OBJECT_INVALID)
{ // flee here
oRet=fnRandomObject(GetArea(GetTransitionTarget(oD)),OBJECT_TYPE_PLACEABLE);
} // flee here
}
return oRet;
} // fnExposed
void fnInitializeStack(object oNPC)
{ // init the stack
int nTop=GetLocalInt(oNPC,"nPSTop");
int nL=1;
//SendMessageToPC(GetFirstPC(),"fnInitializeStack was called");
while (nL<=nTop)
{
DeleteLocalObject(oNPC,"nPSPath"+IntToString(nL));
nL++;
}
SetLocalInt(oNPC,"nPSTop",0);
} // fnInitalizeStack()
void fnPush(object oNPC,object oPath)
{ // push a path on
int nTop=GetLocalInt(oNPC,"nPSTop");
nTop++;
//SendMessageToPC(GetFirstPC(),"fnPush("+GetName(oNPC)+","+GetName(GetArea(oPath))+") TOP:"+IntToString(nTop));
SetLocalInt(oNPC,"nPSTop",nTop);
SetLocalObject(oNPC,"nPSPath"+IntToString(nTop),oPath);
} // fnPush
object fnPop(object oNPC)
{ // pop an item off of the stack
int nTop=GetLocalInt(oNPC,"nPSTop");
object oRet=OBJECT_INVALID;
if (nTop>0)
{
oRet=GetLocalObject(oNPC,"nPSPath"+IntToString(nTop));
DeleteLocalObject(oNPC,"nPSPath"+IntToString(nTop));
nTop--;
SetLocalInt(oNPC,"nPSTop",nTop);
}
return oRet;
} // fnPop()
object fnTransitionBetweenAreas(object oArea1,object oArea2)
{ // find a transition
object oRet=OBJECT_INVALID;
object oTest=GetFirstObjectInArea(oArea1);
oTest=GetNearestObject(OBJECT_TYPE_PLACEABLE,oTest,1);
if (oTest==OBJECT_INVALID) SendMessageToPC(GetFirstPC(),"RTS ERROR in area "+GetName(oArea1)+" no placeables available for algorithm to use.");
int nDoors=GetLocalInt(oArea1,"nDoors");
int nTriggers=GetLocalInt(oArea1,"nTriggers");
int nC=1;
object oWork=GetNearestObject(OBJECT_TYPE_DOOR,oTest,nC);
object oTarg=GetTransitionTarget(oWork);
//SendMessageToPC(GetFirstPC(),"fnTBA("+GetName(oArea1)+","+GetName(oArea2)+"):Test("+GetName(oTest)+") nDoors:"+IntToString(nDoors)+" nTriggers:"+IntToString(nTriggers));
while(oRet==OBJECT_INVALID&&nC<=nDoors)
{ // test doors
if (GetArea(oTarg)==oArea2) oRet=oTarg;
nC++;
oWork=GetNearestObject(OBJECT_TYPE_DOOR,oTest,nC);
oTarg=GetTransitionTarget(oWork);
} // test doors
if (oRet==OBJECT_INVALID)
{ // keep looking
nC=1;
oWork=GetNearestObject(OBJECT_TYPE_TRIGGER,oTest,nC);
oTarg=GetTransitionTarget(oWork);
while(oRet==OBJECT_INVALID&&nC<=nTriggers)
{ // test Triggers
if (GetArea(oTarg)==oArea2) oRet=oTarg;
nC++;
oWork=GetNearestObject(OBJECT_TYPE_TRIGGER,oTest,nC);
oTarg=GetTransitionTarget(oWork);
} // test Triggers
} // keep looking
return oRet;
} //fnTransitionBetweenAreas()
object fnGetNearTransitionTarget(object oTransition)
{ // Get a closeby object for the transition
object oRet=OBJECT_INVALID;
float fDist;
object oTest=GetNearestObject(OBJECT_TYPE_PLACEABLE,oTransition,1);
fDist=GetDistanceBetween(oTest,oTransition);
if (oTest==OBJECT_INVALID||fDist>10.0)
{ // keep looking
oTest=GetNearestObject(OBJECT_TYPE_ITEM,oTransition,1);
fDist=GetDistanceBetween(oTest,oTransition);
if (oTest==OBJECT_INVALID||fDist>10.0)
{ // keep looking
oTest=GetNearestObject(OBJECT_TYPE_STORE,oTransition,1);
fDist=GetDistanceBetween(oTest,oTransition);
if (oTest==OBJECT_INVALID||fDist>10.0)
{ // keep looking
oTest=GetNearestObject(OBJECT_TYPE_WAYPOINT,oTransition,1);
fDist=GetDistanceBetween(oTest,oTransition);
if (oTest==OBJECT_INVALID||fDist>10.0)
{ // keep looking
oRet=fnRandomObject(GetArea(oTransition),OBJECT_TYPE_WAYPOINT);
} // keep looking
else
oRet=oTest;
} // keep looking
else
oRet=oTest;
} // keep looking
else
oRet=oTest;
} // keep looking
else
oRet=oTest;
//SendMessageToPC(GetFirstPC(),"fnGetNearTransitionTarget("+GetTag(oTransition)+":area["+GetName(GetArea(oTransition))+"])="+GetTag(oRet));
return oRet;
} // fnGetNearTransitionTarget()
int fnNotInStack(object oArea)
{
int nRet=TRUE;
int nC=0;
int nTop=GetLocalInt(OBJECT_SELF,"nStackTop");
if (nTop>0)
{
while(nC<nTop&&nRet)
{ // check stack entries
nC++;
if (GetLocalObject(OBJECT_SELF,"oStack"+IntToString(nC))==oArea) nRet=FALSE;
} // check stack entries
}
return nRet;
} // fnNotInStack
void fnPushPSR(object oArea)
{ // push Path Stack Recursive
int nTop=GetLocalInt(OBJECT_SELF,"nPSRTop");
nTop++;
//SendMessageToPC(GetFirstPC(),"fnPushPSR("+GetName(oArea)+") TOP:"+IntToString(nTop));
SetLocalObject(OBJECT_SELF,"oPSR"+IntToString(nTop),oArea);
SetLocalInt(OBJECT_SELF,"nPSRTop",nTop);
} // fnPushPSR()
void fnPushStack(object oArea)
{ // push Path Stack Recursive
int nTop=GetLocalInt(OBJECT_SELF,"nStackTop");
nTop++;
//SendMessageToPC(GetFirstPC(),"fnPushStack("+GetName(oArea)+") TOP:"+IntToString(nTop));
SetLocalObject(OBJECT_SELF,"oStack"+IntToString(nTop),oArea);
SetLocalInt(OBJECT_SELF,"nStackTop",nTop);
} // fnPushPSR()
object fnPopStack()
{
object oRet=OBJECT_INVALID;
int nTop=GetLocalInt(OBJECT_SELF,"nStackTop");
if (nTop!=0)
{ // pop
oRet=GetLocalObject(OBJECT_SELF,"oStack"+IntToString(nTop));
DeleteLocalObject(OBJECT_SELF,"oStack"+IntToString(nTop));
nTop--;
//SendMessageToPC(GetFirstPC(),"fnPopStack("+GetName(oRet)+") TOP:"+IntToString(nTop));
SetLocalInt(OBJECT_SELF,"nStackTop",nTop);
} // pop
//if (nTop==0) SendMessageToPC(GetFirstPC(),"Empty Stack - oStack");
return oRet;
} // fnPopPSR()
int fnFindAreasBetween(object oSource,object oD,int nMax,int nNode=0)
{ // build a one time stack of areas for use in fnBuildPath
int nRet=nNode;
int nHigh=nMax;
int nRes;
int nDoors=GetLocalInt(oSource,"nDoors");
int nTriggers=GetLocalInt(oSource,"nTriggers");
object oFOB=fnRandomObject(oSource,OBJECT_TYPE_WAYPOINT);
int nC=0;
object oNull;
object oPath=fnRandomObject(oSource,OBJECT_TYPE_DOOR);
object oTarg=GetTransitionTarget(oPath);
//SendMessageToPC(GetFirstPC(),"==Pathing:"+GetName(oSource)+","+GetName(oD)+","+IntToString(nMax)+","+IntToString(nNode));
if (nNode==nMax) return 0;
while(nC<2)
{ // check 2 door paths
if (oTarg!=OBJECT_INVALID)
{ // is a transition
if(oD==GetArea(oTarg))
{ // target destination
fnPushPSR(GetArea(oTarg));
return nRet+1; // destination reached
} // target destination
else if (fnNotInStack(GetArea(oTarg))==TRUE)
{ // haven't been here before
fnPushStack(GetArea(oTarg));
nRes=fnFindAreasBetween(GetArea(oTarg),oD,nMax,nNode+1);
oNull=fnPopStack();
if (nRes!=0)
{
fnPushPSR(oNull);
return nRes;
}
} // haven't been here before
} // is a transition
nC++;
oPath=fnRandomObject(oSource,OBJECT_TYPE_DOOR);
} // check 2 door paths
oPath=fnRandomObject(oSource,OBJECT_TYPE_TRIGGER);
oTarg=GetTransitionTarget(oPath);
nC=0;
while(nC<2)
{ // check 2 TRIGGER paths
if (oTarg!=OBJECT_INVALID)
{ // is a transition
if(oD==GetArea(oTarg))
{ // target destination
fnPushPSR(GetArea(oTarg));
return nRet+1; // destination reached
} // target destination
else if (fnNotInStack(GetArea(oTarg))==TRUE)
{ // haven't been here before
fnPushStack(GetArea(oTarg));
nRes=fnFindAreasBetween(GetArea(oTarg),oD,nMax,nNode+1);
oNull=fnPopStack();
if (nRes!=0)
{
fnPushPSR(oNull);
return nRes;
}
} // haven't been here before
} // is a transition
nC++;
oPath=fnRandomObject(oSource,OBJECT_TYPE_TRIGGER);
} // check 2 TRIGGER path
return 0;
} // fnFindAreasBetween()
object fnPopPSR()
{
object oRet=OBJECT_INVALID;
int nTop=GetLocalInt(OBJECT_SELF,"nPSRTop");
if (nTop!=0)
{ // pop
oRet=GetLocalObject(OBJECT_SELF,"oPSR"+IntToString(nTop));
DeleteLocalObject(OBJECT_SELF,"oPSR"+IntToString(nTop));
nTop--;
SetLocalInt(OBJECT_SELF,"nPSRTop",nTop);
} // pop
return oRet;
} // fnPopPSR()
void fnBuildPath(object oA,object oD,int nMaxNodes=8)
{ // build the reverse stack path
int nRes;
object oNode;
object oNull;
//SendMessageToPC(GetFirstPC(),"Look for path");
nRes=fnFindAreasBetween(GetArea(oD),oA,nMaxNodes);
if (nRes==0)
{ // delay then look again
DelayCommand(4.0,fnBuildPath(oA,oD,nMaxNodes)); // try again
} // delay then look again
else
{ // path found
//SendMessageToPC(GetFirstPC(),"Path found");
fnPush(OBJECT_SELF,oD);
//fnPush(OBJECT_SELF,fnRandomObject(GetArea(oD),OBJECT_TYPE_WAYPOINT));
oNode=fnPopPSR();
while(oNode!=OBJECT_INVALID)
{ // build path
fnPush(OBJECT_SELF,fnRandomObject(oNode,OBJECT_TYPE_WAYPOINT));
oNode=fnPopPSR();
//if (GetLocalInt(OBJECT_SELF,"nPSRTop")==1) oNull=fnPopPSR();
} // build path
SetLocalInt(OBJECT_SELF,"nPathingActive",FALSE);
} // path found
} // fnBuildPath()
int fnMoveTo(object oDest,int nAS=FALSE)
{ // move
int nRet=0;
object oMe=OBJECT_SELF;
int nASC=GetLocalInt(oMe,"nASC"); // Anti-stuck counter
float fDist=GetDistanceBetween(oDest,oMe);
int nPCs=fnArePCsPresent(GetArea(oMe))+fnArePCsPresent(GetArea(oDest));
int nRun=GetLocalInt(oMe,"nRun");
int nConfused=GetLocalInt(oMe,"nConfused");
object oConfused=GetLocalObject(oMe,"oConfused");
float fLDist=GetLocalFloat(oMe,"fLastDist");
int nMR=GetMovementRate(oMe);
object oArbitrary=GetFirstObjectInArea(GetArea(oMe));
if (GetObjectType(oArbitrary)!=OBJECT_TYPE_WAYPOINT) oArbitrary=GetNearestObject(OBJECT_TYPE_WAYPOINT,oArbitrary,1);
if (GetArea(oMe)!=GetArea(oDest)) fDist=GetDistanceBetween(oMe,oArbitrary);
if (nMR==7) nMR=4;
if (oDest==OBJECT_INVALID) return -1;
if (nAS==TRUE)
{ // anti-stuck is engaged
if (fLDist==fDist)
{ // same distance as last time
nASC++;
SetLocalInt(oMe,"nASC",nASC);
if (nPCs>0)
{ // there are PCs - aggressive anti-stuck
//SendMessageToPC(GetFirstPC(),"Anti-Stuck PCs");
if (nASC>11)
{ // that did not work - pick a better destination
nRet=-1;
} // that did not work - pick a better destination
else if (nASC>9)
{ // very stuck - teleport
AssignCommand(oMe,ClearAllActions());
AssignCommand(oMe,ActionJumpToObject(oDest));
} // very stuck - teleport
else if (nASC>4)
{ // moderately stuck - look for nearby
if (oConfused==OBJECT_INVALID)
SetLocalObject(oMe,"oConfused",oDest);
else if (oConfused!=oDest) nConfused=0;
AssignCommand(oMe,ClearAllActions());
oDest=GetNearestObject(OBJECT_TYPE_WAYPOINT,oMe,d12());
AssignCommand(oMe,ActionMoveToObject(oDest,nRun,1.0));
DelayCommand(8.0,AssignCommand(oMe,ClearAllActions()));
nConfused++;
if (nConfused>3) nRet=-1;
SetLocalInt(oMe,"nConfused",nConfused);
} // moderately stuck - look for nearby
else
{ // normal reminder
AssignCommand(oMe,ActionMoveToObject(oDest,nRun,1.0));
} // normal reminder
} // there are PCs - aggressive anti-stuck
else
{ // no PCs-- teleport after 10
//SendMessageToPC(GetFirstPC(),"Anti-Stuck NO PCs");
if (nASC>(15-nMR))
{ // that did not work - pick a better destination
nRet=-1;
} // that did not work - pick a better destination
else if (nASC>(13-nMR))
{ // teleport
AssignCommand(oMe,ClearAllActions());
AssignCommand(oMe,ActionJumpToObject(oDest));
SetLocalInt(oMe,"nASC",0);
} // teleport
} // no PCs-- teleport after 10
} // same distance as last time
else
{ // moved
SetLocalInt(oMe,"nASC",0);
SetLocalFloat(oMe,"fLastDist",fDist);
} // moved
} // anti-stuck is engaged
else
{ // no anti-stuck
AssignCommand(oMe,ActionMoveToObject(oDest,nRun,1.0));
} // no anti-stuck
return nRet;
} // fnMoveTo()
int fnMoveToDestination(object oWP,int nAS=FALSE,int nInitStack=FALSE)
{ // Move to Waypoint with Anti-Stuck on/off
// nInitStack = do I need to setup the pathing stack
int nRet=0;
object oMe=OBJECT_SELF;
int nPSTop=GetLocalInt(oMe,"nPSTop");
object oArea=GetArea(oMe);
object oDArea=GetArea(oWP);
object oDest=GetLocalObject(oMe,"oDestWP");
float fDist;
object oBinder=GetObjectByTag("RTS_BINDER");
int nPA=GetLocalInt(oMe,"nPathingActive");
if (oWP==OBJECT_INVALID) return -1;
if (nInitStack==FALSE&&nPSTop!=0)
{ // there is stack info to process still
if(oDest==oBinder)
{ // first call
//SendMessageToPC(GetFirstPC(),"First Stack Pathing Call");
oDest=fnPop(oMe);
SetLocalObject(oMe,"oDestWP",oDest);
} // first call
if (fnTransitionBetweenAreas(GetArea(oMe),GetArea(oDest))==OBJECT_INVALID)
{ // not a valid path
oDest=fnPop(oMe);
SetLocalObject(oMe,"oDestWP",oDest);
} // not a valid path
fDist=GetDistanceBetween(oDest,oMe);
if ((fDist==0.0&&GetArea(oDest)!=oArea)||fDist>7.0)
{ // still too far away
//SendMessageToPC(GetFirstPC(),"Stack Path Dest:"+GetTag(oDest)+" Area:"+GetName(GetArea(oDest)));
nRet=fnMoveTo(oDest,nAS);
} // still too far away
else
{ // pop an item off the stack
oDest=fnPop(oMe);
//SendMessageToPC(GetFirstPC(),"Stack Path: Pop off next destination:"+GetTag(oDest)+" Area:"+GetName(GetArea(oDest)));
SetLocalObject(oMe,"oDestWP",oDest);
nRet=fnMoveTo(oDest,nAS);
} // pop an item off the stack
} // there is stack info to process still
else if (nInitStack==TRUE)
{ // initialize the stack
fnInitializeStack(oMe);
SetLocalInt(oMe,"nPathingActive",TRUE);
SetLocalObject(oMe,"oDestWP",oBinder);
fnBuildPath(oArea,oWP);
// build pathing stack backwards from destination
} // initialize the stack
else if (nPA==FALSE)
{ // No stack items & not waiting on complex pathing
if (oArea==oDArea)
{ // same area
nRet=fnMoveTo(oWP,nAS);
if (nRet==-1)
{ // abort
SetLocalObject(oMe,"oDestWP",OBJECT_INVALID);
} // abort
} // same area
else
{ // different areas
oDest=fnTransitionBetweenAreas(oArea,oDArea);
if (oDest!=OBJECT_INVALID)
{ // adjacent areas
nRet=fnMoveTo(oDest,nAS);
} // adjacent areas
else
{ // no direct connection
nRet=fnMoveToDestination(oWP,nAS,TRUE); // initialize stack
} // no direct connection
} // different areas
} // No stack items & not waiting on complex pathing
return nRet;
} // fnMoveToDestination()