710 lines
30 KiB
Plaintext
710 lines
30 KiB
Plaintext
////////////////////////////////////////////////////////////////////////////////
|
|
// npcact_h_moving - The movement library for NPC ACTIVITIES 6.0
|
|
// By Deva Bryson Winblood.
|
|
// Last Modified By: Deva Bryson Winblood ON: 1/25/2005
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
const int MOVE_DEBUG_ON = FALSE; // set to TRUE if you want movement debug messages
|
|
const string MOVE_DEBUG_NPC = ""; // set to tag of specific NPC if you wish to debug movement
|
|
|
|
/////////////////////////////////////////
|
|
// PROTOTYPES
|
|
/////////////////////////////////////////
|
|
|
|
// FILE: npcactivitiesh FUNCTION: fnMoveToDestination()
|
|
//-------------------------------------------------------
|
|
// This function is called to move an npc to a specified destination oDest
|
|
// to the range fRange. This function uses anti-stuck scripting technology,
|
|
// supports multiple movement methods, and can make calls to more complex pathing
|
|
// commands if need be. It also checks nearby doors, triggers, and placeables to
|
|
// insure that the closest entrance to another area is chosen. This is done to
|
|
// prevent the choosing a further door problem that Bioware pathing sometimes uses
|
|
// when there are more than one door linking to another area. It will with Bioware
|
|
// sometimes wander to another door rather than using the one it is standing directly
|
|
// next to. This has been addressed by this function. The function returns the
|
|
// following values: 0 = still pathing, 1=arrived, -1 = error unreachable
|
|
// -1 and 1 you must react to. -1 is returned when even with all the anti-stuck
|
|
// technology the NPC was still unable to reach the destination.
|
|
int fnMoveToDestinationB(object oNPC,object oDest,float fRange=1.0);
|
|
|
|
|
|
/////////////////////////////////////////
|
|
// FUNCTIONS
|
|
/////////////////////////////////////////
|
|
|
|
void DebugMove(string sSay)
|
|
{ // PURPOSE: To display debug messages for movement
|
|
// LAST MODIFIED BY: Deva Bryson Winblood 6/25/2004
|
|
string sMsg="["+GetTag(OBJECT_SELF)+"] [npcact_h_moving debug] "+sSay;
|
|
if (MOVE_DEBUG_ON)
|
|
{ // movement debug
|
|
if (GetStringLength(MOVE_DEBUG_NPC)<3||GetTag(OBJECT_SELF)==MOVE_DEBUG_NPC)
|
|
{ // okay to display
|
|
SendMessageToPC(GetFirstPC(),sMsg);
|
|
PrintString("[npcact_h_moving debug] "+sMsg);
|
|
} // okay to display
|
|
} // movement debug
|
|
} // DebugMove()
|
|
|
|
int fnHandleStuck(object oNPC,object oDest,int nASC,int nASR,int nRun)
|
|
{ // PURPOSE: To handle anti-stuck situations
|
|
// LAST MODIFIED BY: Deva Bryson Winblood 6/25/2004
|
|
int nRet=0;
|
|
object oOb;
|
|
object oMe=oNPC;
|
|
float fR;
|
|
int nR;
|
|
nASC++;
|
|
SetLocalInt(oNPC,"nGNBASC",nASC);
|
|
if (nASC==1)
|
|
{ // first encounter
|
|
AssignCommand(oNPC,ClearAllActions(TRUE));
|
|
AssignCommand(oNPC,ActionMoveToObject(oDest,nRun));
|
|
} // first encounter
|
|
else if (nASC==3&&nASR<3)
|
|
{ // pick a nearby object to move near
|
|
oOb=GetNearestObject(OBJECT_TYPE_PLACEABLE,oNPC,d10());
|
|
if (!GetIsObjectValid(oOb)) oOb=GetNearestObject(OBJECT_TYPE_PLACEABLE,oNPC,d8());
|
|
if (!GetIsObjectValid(oOb)) oOb=GetNearestObject(OBJECT_TYPE_PLACEABLE,oNPC,d4());
|
|
if (!GetIsObjectValid(oOb)) oOb=GetNearestObject(OBJECT_TYPE_WAYPOINT,oNPC,d20());
|
|
if (!GetIsObjectValid(oOb)) oOb=GetNearestObject(OBJECT_TYPE_WAYPOINT,oNPC,d12());
|
|
if (!GetIsObjectValid(oOb)) oOb=GetNearestObject(OBJECT_TYPE_WAYPOINT,oNPC,d10());
|
|
if (!GetIsObjectValid(oOb)) oOb=GetNearestObject(OBJECT_TYPE_WAYPOINT,oNPC,d8());
|
|
if (!GetIsObjectValid(oOb)) oOb=GetNearestObject(OBJECT_TYPE_WAYPOINT,oNPC,d6());
|
|
if (!GetIsObjectValid(oOb)) oOb=GetNearestObject(OBJECT_TYPE_WAYPOINT,oNPC,d4());
|
|
if (!GetIsObjectValid(oOb)) oOb=GetNearestObject(OBJECT_TYPE_ALL,oNPC,1);
|
|
if (GetIsObjectValid(oOb))
|
|
{ // found temporary target
|
|
AssignCommand(oNPC,ClearAllActions(TRUE));
|
|
AssignCommand(oNPC,ActionMoveToObject(oOb,nRun));
|
|
nR=d4();
|
|
fR=4.0+IntToFloat(nR);
|
|
DelayCommand(fR,AssignCommand(oNPC,ClearAllActions(TRUE)));
|
|
DelayCommand(fR+0.1,AssignCommand(oNPC,ActionMoveToObject(oDest,nRun)));
|
|
} // found temporary target
|
|
SetLocalInt(oNPC,"nGNBASC",0);
|
|
nASR++;
|
|
SetLocalInt(oNPC,"nGNBASR",nASR);
|
|
} // pick a nearby object to move near
|
|
else if (nASC==3&&nASR==3)
|
|
{ // teleport
|
|
AssignCommand(oMe,ClearAllActions(TRUE));
|
|
AssignCommand(oMe,JumpToLocation(GetLocation(oDest)));
|
|
} // teleport
|
|
else if (nASC>3)
|
|
{ // can't get there
|
|
DeleteLocalFloat(oNPC,"fLastDist");
|
|
DeleteLocalInt(oNPC,"nGNBASC");
|
|
DeleteLocalInt(oNPC,"nGNBASR");
|
|
DeleteLocalObject(oNPC,"oGNBNearbyObject");
|
|
return -1;
|
|
} // can't get there
|
|
return nRet;
|
|
} // fnHandleStuck()
|
|
|
|
/*int fnMoveToDestination(object oNPC,object oDest,float fRange=1.0)
|
|
{ // PURPOSE: This function handles all the movement for the NPC
|
|
// LAST MODIFIED BY: Deva Bryson Winblood 6/25/2004
|
|
int nRet=0;
|
|
object oRelative; // oGNBNearbyObject
|
|
int nASC; // nGNBASC
|
|
int nASR; // nGNBASR
|
|
int nGRun; // nGNBRun
|
|
int nRun; // nRun
|
|
int nN;
|
|
float fLD; // fLastDist
|
|
float fDist;
|
|
effect eEff;
|
|
DebugMove("fnMoveToDestination("+GetTag(oNPC)+","+GetTag(oDest)+")");
|
|
if (!GetIsObjectValid(oDest))
|
|
{ // not a valid destination
|
|
DebugMove("INVALID DESTINATION!!!");
|
|
} // not a valid destination
|
|
if (GetArea(oDest)==GetArea(oNPC)&&GetDistanceBetween(oNPC,oDest)<=fRange)
|
|
{ // arrived
|
|
DeleteLocalFloat(oNPC,"fLastDist");
|
|
DeleteLocalInt(oNPC,"nGNBASC");
|
|
DeleteLocalInt(oNPC,"nGNBASR");
|
|
DeleteLocalObject(oNPC,"oGNBNearbyObject");
|
|
return 1;
|
|
} // arrived
|
|
else
|
|
{ // have not arrived --------------------------------------------------
|
|
oRelative=GetLocalObject(oNPC,"oGNBNearbyObject");
|
|
nASC=GetLocalInt(oNPC,"nGNBASC");
|
|
nASR=GetLocalInt(oNPC,"nGNBASR");
|
|
nGRun=GetLocalInt(oNPC,"nGNBRun");
|
|
fLD=GetLocalFloat(oNPC,"fLastDist");
|
|
nRun=FALSE;
|
|
if (nGRun==1) nRun=TRUE;
|
|
if (nGRun==0||nGRun==1) { // no stealth or search
|
|
SetActionMode(oNPC,ACTION_MODE_DETECT,FALSE);
|
|
SetActionMode(oNPC,ACTION_MODE_STEALTH,FALSE);
|
|
} // no stealth or search
|
|
else if (nGRun==2||nGRun==4)
|
|
{ // hide
|
|
SetActionMode(oNPC,ACTION_MODE_STEALTH,TRUE);
|
|
} // hide
|
|
if (nGRun==3||nGRun==4)
|
|
{ // search
|
|
SetActionMode(oNPC,ACTION_MODE_DETECT,TRUE);
|
|
} // search
|
|
if ((nGRun==5||nGRun==6||nGRun==7||nGRun==8)&&nASR==0)
|
|
{ // teleport type instant movement
|
|
if (nGRun==5) { AssignCommand(oNPC,ClearAllActions(TRUE)); AssignCommand(oNPC,JumpToObject(oDest)); }
|
|
else if (nGRun==6)
|
|
{ // teleport w/ VFX
|
|
AssignCommand(oNPC,ClearAllActions(TRUE));
|
|
eEff=EffectVisualEffect(VFX_FNF_IMPLOSION);
|
|
ApplyEffectAtLocation(DURATION_TYPE_INSTANT,eEff,GetLocation(oNPC),3.0);
|
|
ApplyEffectAtLocation(DURATION_TYPE_INSTANT,eEff,GetLocation(oDest),3.0);
|
|
DelayCommand(0.8,AssignCommand(oNPC,JumpToObject(oDest)));
|
|
} // teleport w/ VFX
|
|
else if (nGRun==7)
|
|
{ // fly out and then in
|
|
AssignCommand(oNPC,ClearAllActions(TRUE));
|
|
eEff=EffectDisappearAppear(GetLocation(oDest),1);
|
|
ApplyEffectToObject(DURATION_TYPE_TEMPORARY,eEff,oNPC,4.0);
|
|
} // fly out and then in
|
|
else if (nRun==8)
|
|
{ // custom VFX teleport
|
|
AssignCommand(oNPC,ClearAllActions(TRUE));
|
|
nN=GetLocalInt(oNPC,"nGNBVFX1");
|
|
eEff=EffectVisualEffect(nN);
|
|
ApplyEffectAtLocation(DURATION_TYPE_TEMPORARY,eEff,GetLocation(oNPC),4.0);
|
|
nN=GetLocalInt(oNPC,"nGNBVFX2");
|
|
eEff=EffectVisualEffect(nN);
|
|
ApplyEffectAtLocation(DURATION_TYPE_TEMPORARY,eEff,GetLocation(oDest),4.0);
|
|
DelayCommand(2.5,AssignCommand(oNPC,JumpToObject(oDest)));
|
|
} // custom VFX teleport
|
|
SetLocalInt(oNPC,"nGNBASR",1);
|
|
} // teleport type instant movement
|
|
else if ((nGRun==5||nGRun==6||nGRun==7||nGRun==8)&&nASR==1)
|
|
{ // effect called
|
|
nASC++;
|
|
if (GetArea(oDest)==GetArea(oNPC)&&GetDistanceBetween(oDest,oNPC)<=fRange)
|
|
{ // arrived
|
|
DeleteLocalFloat(oNPC,"fLastDist");
|
|
DeleteLocalInt(oNPC,"nGNBASC");
|
|
DeleteLocalInt(oNPC,"nGNBASR");
|
|
DeleteLocalObject(oNPC,"oGNBNearbyObject");
|
|
return 1;
|
|
} // arrived
|
|
else if (nASC>4)
|
|
{ // did not arrive
|
|
DeleteLocalFloat(oNPC,"fLastDist");
|
|
DeleteLocalInt(oNPC,"nGNBASC");
|
|
DeleteLocalInt(oNPC,"nGNBASR");
|
|
DeleteLocalObject(oNPC,"oGNBNearbyObject");
|
|
return -1;
|
|
} // did not arrive
|
|
SetLocalInt(oNPC,"nGNBASC",nASC);
|
|
} // effect called
|
|
else if (GetArea(oDest)==GetArea(oNPC))
|
|
{ // same area movement
|
|
fDist=GetDistanceBetween(oNPC,oDest);
|
|
if (fDist>fRange&&fDist==fLD)
|
|
{ // not there and not moving
|
|
nRet=fnHandleStuck(oNPC,oDest,nASC,nASR,nRun);
|
|
} // not there and not moving
|
|
if (fLD==0.0)
|
|
{ // start the initial movement
|
|
AssignCommand(oNPC,ClearAllActions(TRUE));
|
|
AssignCommand(oNPC,ActionMoveToObject(oDest,nRun,fRange));
|
|
} // start the initial movement
|
|
} // same area movement
|
|
else
|
|
{ // different area movement
|
|
if (!GetIsObjectValid(oRelative)||GetArea(oRelative)!=GetArea(oNPC))
|
|
{ // setup relative object for tracking distance changes accurately
|
|
oRelative=GetNearestObject(OBJECT_TYPE_PLACEABLE,oNPC,d10());
|
|
if (!GetIsObjectValid(oRelative)) oRelative=GetNearestObject(OBJECT_TYPE_PLACEABLE,oNPC,d4());
|
|
if (!GetIsObjectValid(oRelative)) oRelative=GetNearestObject(OBJECT_TYPE_DOOR,oNPC,d6());
|
|
if (!GetIsObjectValid(oRelative)) oRelative=GetNearestObject(OBJECT_TYPE_DOOR,oNPC,d4());
|
|
if (!GetIsObjectValid(oRelative)) oRelative=GetNearestObject(OBJECT_TYPE_WAYPOINT,oNPC,d6());
|
|
if (!GetIsObjectValid(oRelative)) oRelative=GetNearestObject(OBJECT_TYPE_ALL,oNPC,d6());
|
|
if (!GetIsObjectValid(oRelative)) oRelative=GetNearestObject(OBJECT_TYPE_ALL,oNPC,1);
|
|
if (!GetIsObjectValid(oRelative))
|
|
{ // error cannot find relative object
|
|
DebugMove("Cannot find a relative object in area '"+GetName(GetArea(oNPC))+"'!");
|
|
DeleteLocalFloat(oNPC,"fLastDist");
|
|
DeleteLocalInt(oNPC,"nGNBASC");
|
|
DeleteLocalInt(oNPC,"nGNBASR");
|
|
DeleteLocalObject(oNPC,"oGNBNearbyObject");
|
|
return -1;
|
|
} // error cannot find relative object
|
|
else
|
|
{ // relative found
|
|
SetLocalObject(oNPC,"oGNBNearbyObject",oRelative);
|
|
} // relative found
|
|
} // setup relative object for tracking distance changes accurately
|
|
fDist=GetDistanceBetween(oRelative,oNPC);
|
|
if (fDist==fLD)
|
|
{ // possibly stuck
|
|
nRet=fnHandleStuck(oNPC,oDest,nASC,nASR,nRun);
|
|
} // possibly stuck
|
|
if (fLD==0.0)
|
|
{ // start the initial movement
|
|
AssignCommand(oNPC,ClearAllActions(TRUE));
|
|
AssignCommand(oNPC,ActionMoveToObject(oDest,nRun,fRange));
|
|
} // start the initial movement
|
|
} // different area movement
|
|
SetLocalFloat(oNPC,"fLastDist",fDist);
|
|
} // have not arrived --------------------------------------------------
|
|
return nRet;
|
|
} // fnMoveToDestination() */
|
|
|
|
void fnJumpNPC(object oNPC,object oDest,float fRange)
|
|
{ // PURPOSE: Move the NPC quick
|
|
if (GetArea(oNPC)!=GetArea(oDest)||GetDistanceBetween(oNPC,oDest)>fRange)
|
|
{ // teleport
|
|
if (GetIsInCombat(oNPC)==FALSE)
|
|
{ // okay to teleport
|
|
AssignCommand(oNPC,ClearAllActions());
|
|
AssignCommand(oNPC,JumpToObject(oDest));
|
|
DelayCommand(6.0,fnJumpNPC(oNPC,oDest,fRange));
|
|
} // okay to teleport
|
|
} // teleport
|
|
} // fnJumpNPC()
|
|
|
|
void fnLowAINoPCMove(object oNPC,object oDest,float fRange)
|
|
{ // PURPOSE: To Assign to the module object to handle movement of this
|
|
// NPC if AI level is less than normal.
|
|
float fTime=5.0;
|
|
object oOb;
|
|
if (GetLocalInt(oNPC,"bModulePossessed")!=TRUE)
|
|
{ // possess
|
|
SetLocalInt(oNPC,"bModulePossessed",TRUE);
|
|
if (GetArea(oDest)==GetArea(oNPC))
|
|
{ // same area
|
|
fTime=fTime+(GetDistanceBetween(oNPC,oDest)/3.0);
|
|
DelayCommand(fTime,fnJumpNPC(oNPC,oDest,fRange));
|
|
} // same area
|
|
else
|
|
{ // different area
|
|
DelayCommand(60.0,fnJumpNPC(oNPC,oDest,fRange));
|
|
} // different area
|
|
} // possess
|
|
} // fnLowAINoPCMove()
|
|
|
|
int fnMoveToDestinationB(object oNPC,object oDest,float fRange=1.0)
|
|
{ // PURPOSE: Version 2.0 of the fnMoveToDestination function
|
|
// VARIABLES:
|
|
// OnModule
|
|
// ========
|
|
// bGNBAccuratePathing if set to 1 will always try to get nearby transition
|
|
// OnNPC
|
|
// ========
|
|
// bGNBAccuratePathing if set to 1 will always try to get nearby transition
|
|
// bGNBQuickMove if set to 1 will use jump and such to move NPCs when no PCs
|
|
// are around to witness it.
|
|
int nRet=0;
|
|
int nN;
|
|
object oT;
|
|
object oD;
|
|
object oC;
|
|
float fD;
|
|
object oRelative; // oGNBNearbyObject
|
|
int nASC; // nGNBASC
|
|
int nASR; // nGNBASR
|
|
int nGRun; // nGNBRun
|
|
int nRun; // nRun
|
|
float fLD; // fLastDist
|
|
float fDist;
|
|
effect eEff;
|
|
float fF;
|
|
float fFF;
|
|
//vector vVec;
|
|
//vector vNew;
|
|
//location lLoc;
|
|
int bNoAIHandle=FALSE;
|
|
int bAP=GetLocalInt(GetModule(),"bGNBAccuratePathing");
|
|
int nAIL=GetAILevel(oNPC);
|
|
object oPCN=GetNearestCreature(CREATURE_TYPE_PLAYER_CHAR,PLAYER_CHAR_IS_PC,oNPC,1,CREATURE_TYPE_IS_ALIVE,TRUE);
|
|
object oPCD=GetNearestCreature(CREATURE_TYPE_PLAYER_CHAR,PLAYER_CHAR_IS_PC,oDest,1,CREATURE_TYPE_IS_ALIVE,TRUE);
|
|
object oEnemy=GetNearestCreature(CREATURE_TYPE_REPUTATION,REPUTATION_TYPE_ENEMY,oNPC,1,CREATURE_TYPE_PERCEPTION,PERCEPTION_SEEN,CREATURE_TYPE_IS_ALIVE,TRUE);
|
|
if (!bAP) bAP=GetLocalInt(oNPC,"bGNBAccuratePathing");
|
|
DebugMove("fnMoveToDestination("+GetTag(oNPC)+","+GetTag(oDest)+","+FloatToString(fRange)+")");
|
|
if (oPCN==OBJECT_INVALID&&oPCD==OBJECT_INVALID&&oEnemy==OBJECT_INVALID&&GetLocalInt(oNPC,"bGNBQuickMove")==TRUE)
|
|
{ // might be able to take short cut
|
|
if (nAIL!=AI_LEVEL_HIGH&&nAIL!=AI_LEVEL_VERY_HIGH&&nAIL!=AI_LEVEL_NORMAL) bNoAIHandle=TRUE;
|
|
} // might be able to take short cut
|
|
if (!bNoAIHandle)
|
|
{ // AI level is sufficient or PCs are present
|
|
DebugMove(" Normal movement");
|
|
nGRun=GetLocalInt(oNPC,"nGNBRun");
|
|
if (nGRun<5)
|
|
{ // no instant movement
|
|
nRun=FALSE;
|
|
if (nGRun==1) nRun=TRUE;
|
|
if (nGRun==0||nGRun==1) { // no stealth or search
|
|
SetActionMode(oNPC,ACTION_MODE_DETECT,FALSE);
|
|
SetActionMode(oNPC,ACTION_MODE_STEALTH,FALSE);
|
|
} // no stealth or search
|
|
else if (nGRun==2||nGRun==4)
|
|
{ // hide
|
|
SetActionMode(oNPC,ACTION_MODE_STEALTH,TRUE);
|
|
} // hide
|
|
if (nGRun==3||nGRun==4)
|
|
{ // search
|
|
SetActionMode(oNPC,ACTION_MODE_DETECT,TRUE);
|
|
} // search
|
|
if (GetArea(oNPC)==GetArea(oDest))
|
|
{ // NPC is in the same area as the destination
|
|
DebugMove(" Same Area");
|
|
if (GetDistanceBetween(oNPC,oDest)<=fRange)
|
|
{ // arrived
|
|
// cleanup variables return 1;
|
|
DeleteLocalInt(oNPC,"nGNBASC");
|
|
DeleteLocalInt(oNPC,"nGNBASR");
|
|
DeleteLocalFloat(oNPC,"fLastDist");
|
|
DeleteLocalObject(oNPC,"oGNBNearbyObject");
|
|
return 1;
|
|
} // arrived
|
|
else
|
|
{ // not close enough
|
|
fLD=GetLocalFloat(oNPC,"fLastDist");
|
|
fDist=GetDistanceBetween(oNPC,oDest);
|
|
if (fDist==fLD)
|
|
{ // have not moved - could be stuck
|
|
nASC=GetLocalInt(oNPC,"nGNBASC");
|
|
nASR=GetLocalInt(oNPC,"nGNBASR");
|
|
nASC++;
|
|
DebugMove(" anti-stuck nASC="+IntToString(nASC)+" nASR="+IntToString(nASR));
|
|
if (nASC<3)
|
|
{ // just try to move again
|
|
AssignCommand(oNPC,ClearAllActions());
|
|
AssignCommand(oNPC,ActionMoveToObject(oDest,nRun,fRange));
|
|
} // just try to move again
|
|
else if (nASC>2&&nASR<3)
|
|
{ // try nearby object
|
|
oRelative=GetNearestObject(OBJECT_TYPE_WAYPOINT,oNPC,d10());
|
|
if (oRelative==OBJECT_INVALID) oRelative=GetNearestObject(OBJECT_TYPE_WAYPOINT,oNPC,d8());
|
|
if (oRelative==OBJECT_INVALID) oRelative=GetNearestObject(OBJECT_TYPE_WAYPOINT,oNPC,d6());
|
|
if (oRelative==OBJECT_INVALID) oRelative=GetNearestObject(OBJECT_TYPE_PLACEABLE,oNPC,d10());
|
|
if (oRelative==OBJECT_INVALID) oRelative=GetNearestObject(OBJECT_TYPE_PLACEABLE,oNPC,d8());
|
|
if (oRelative==OBJECT_INVALID) oRelative=GetNearestObject(OBJECT_TYPE_PLACEABLE,oNPC,d6());
|
|
if (oRelative==OBJECT_INVALID) oRelative=GetNearestObject(OBJECT_TYPE_WAYPOINT,oNPC,1);
|
|
if (oRelative==OBJECT_INVALID) oRelative=GetNearestObject(OBJECT_TYPE_PLACEABLE,oNPC,1);
|
|
if (oRelative!=OBJECT_INVALID)
|
|
{ // object found
|
|
AssignCommand(oNPC,ClearAllActions());
|
|
AssignCommand(oNPC,ActionMoveToObject(oRelative,TRUE,1.0));
|
|
DelayCommand(5.0,AssignCommand(oNPC,ClearAllActions()));
|
|
DelayCommand(5.1,AssignCommand(oNPC,ActionMoveToObject(oDest,nRun,fRange)));
|
|
nASR++;
|
|
SetLocalInt(oNPC,"nGNBASR",nASR);
|
|
} // object found
|
|
} // try nearby object
|
|
else if (nASC>2&&nASR<5)
|
|
{ // jump to location
|
|
nASR++;
|
|
DebugMove(" Teleport called to handle stuck.");
|
|
SetLocalInt(oNPC,"nGNBASR",nASR);
|
|
AssignCommand(oNPC,ClearAllActions());
|
|
AssignCommand(oNPC,JumpToObject(oDest));
|
|
} // jump to loaction
|
|
else if (nASR>4)
|
|
{ // ERROR
|
|
return -1;
|
|
} // ERROR
|
|
SetLocalInt(oNPC,"nGNBASC",nASC);
|
|
} // have not moved - could be stuck
|
|
else if (fLD!=0.0)
|
|
{ // not stuck
|
|
DeleteLocalInt(oNPC,"nGNBASC");
|
|
return 0;
|
|
} // not stuck
|
|
else
|
|
{ // have not tried to move yet
|
|
AssignCommand(oNPC,ActionMoveToObject(oDest,nRun,fRange));
|
|
return 0;
|
|
} // have not tried to move yet
|
|
SetLocalFloat(oNPC,"fLastDist",fDist);
|
|
} // not close enough
|
|
} // NPC is in the same area as the destination
|
|
else
|
|
{ // different area
|
|
DebugMove(" Different Area");
|
|
nN=1;
|
|
if (bAP)
|
|
{ // accurate pathing
|
|
oC=GetLocalObject(oNPC,"oNearestTransition");
|
|
oT=GetNearestObject(OBJECT_TYPE_TRIGGER,oNPC,nN);
|
|
oD=GetNearestObject(OBJECT_TYPE_DOOR,oNPC,nN);
|
|
} // accurate pathing
|
|
else
|
|
{ // standard pathing
|
|
oC=OBJECT_INVALID;
|
|
oT=OBJECT_INVALID;
|
|
oD=OBJECT_INVALID;
|
|
} // standard pathing
|
|
while(oC==OBJECT_INVALID&&(oT!=OBJECT_INVALID||oD!=OBJECT_INVALID)&&bAP)
|
|
{ // look for nearest transition
|
|
nN++;
|
|
if (oT!=OBJECT_INVALID)
|
|
{ // trigger found
|
|
if (GetTransitionTarget(oT)!=OBJECT_INVALID)
|
|
{ // transition found
|
|
if (GetArea(GetTransitionTarget(oT))==GetArea(oDest))
|
|
{ // same area
|
|
oC=oT;
|
|
SetLocalObject(oNPC,"oNearestTransition",oC);
|
|
} // same area
|
|
} // transition found
|
|
} // trigger found
|
|
if (oD!=OBJECT_INVALID&&(GetDistanceBetween(oT,oNPC)<GetDistanceBetween(oD,oNPC)||oC==OBJECT_INVALID))
|
|
{ // door found
|
|
if (GetTransitionTarget(oD)!=OBJECT_INVALID)
|
|
{ // transition found
|
|
if (GetArea(GetTransitionTarget(oD))==GetArea(oDest))
|
|
{ // same area
|
|
oC=oD;
|
|
SetLocalObject(oNPC,"oNearestTransition",oC);
|
|
} // same area
|
|
} // transition found
|
|
} // door found
|
|
oT=GetNearestObject(OBJECT_TYPE_TRIGGER,oNPC,nN);
|
|
oD=GetNearestObject(OBJECT_TYPE_DOOR,oNPC,nN);
|
|
} // look for nearest transition
|
|
if (oC==OBJECT_INVALID||!bAP)
|
|
{ // long distance pathing
|
|
DebugMove(" Long Distance Pathing");
|
|
oRelative=GetLocalObject(oNPC,"oGNBNearbyObject");
|
|
if (oRelative==OBJECT_INVALID||GetArea(oRelative)!=GetArea(oNPC))
|
|
{ // find nearby object
|
|
oRelative=GetNearestObject(OBJECT_TYPE_WAYPOINT,oNPC,1);
|
|
if (oRelative==OBJECT_INVALID) oRelative=GetNearestObject(OBJECT_TYPE_PLACEABLE,oNPC,1);
|
|
if (oRelative==OBJECT_INVALID) oRelative=GetNearestObject(OBJECT_TYPE_DOOR,oNPC,1);
|
|
if (oRelative==OBJECT_INVALID) oRelative=GetNearestObject(OBJECT_TYPE_TRIGGER,oNPC,1);
|
|
if (oRelative!=OBJECT_INVALID)
|
|
{ // relative object found
|
|
SetLocalObject(oNPC,"oGNBNearbyObject",oRelative);
|
|
fLD=GetDistanceBetween(oNPC,oRelative);
|
|
SetLocalFloat(oNPC,"fLastDist",fLD);
|
|
DeleteLocalInt(oNPC,"nGNBASC");
|
|
DeleteLocalInt(oNPC,"nGNBASR");
|
|
AssignCommand(oNPC,ClearAllActions());
|
|
AssignCommand(oNPC,ActionMoveToObject(oDest,nRun,fRange));
|
|
return 0;
|
|
} // relative object found
|
|
} // find nearby object
|
|
else
|
|
{ // object exists
|
|
fDist=GetDistanceBetween(oNPC,oRelative);
|
|
fLD=GetLocalFloat(oNPC,"fLastDist");
|
|
if (fDist==fLD)
|
|
{ // might be stuck
|
|
nASC=GetLocalInt(oNPC,"nGNBASC");
|
|
nASR=GetLocalInt(oNPC,"nGNBASR");
|
|
nASC++;
|
|
DebugMove(" anti-stuck nASC="+IntToString(nASC)+" nASR="+IntToString(nASR));
|
|
if (nASC<3)
|
|
{ // regular movement restart
|
|
AssignCommand(oNPC,ClearAllActions());
|
|
AssignCommand(oNPC,ActionMoveToObject(oDest,nRun,fRange));
|
|
} // regular movement restart
|
|
else if (nASC>2&&nASR<3)
|
|
{ // try nearby object
|
|
oRelative=GetNearestObject(OBJECT_TYPE_WAYPOINT,oNPC,d10());
|
|
if (oRelative==OBJECT_INVALID) oRelative=GetNearestObject(OBJECT_TYPE_WAYPOINT,oNPC,d8());
|
|
if (oRelative==OBJECT_INVALID) oRelative=GetNearestObject(OBJECT_TYPE_WAYPOINT,oNPC,d6());
|
|
if (oRelative==OBJECT_INVALID) oRelative=GetNearestObject(OBJECT_TYPE_PLACEABLE,oNPC,d10());
|
|
if (oRelative==OBJECT_INVALID) oRelative=GetNearestObject(OBJECT_TYPE_PLACEABLE,oNPC,d8());
|
|
if (oRelative==OBJECT_INVALID) oRelative=GetNearestObject(OBJECT_TYPE_PLACEABLE,oNPC,d6());
|
|
if (oRelative==OBJECT_INVALID) oRelative=GetNearestObject(OBJECT_TYPE_WAYPOINT,oNPC,1);
|
|
if (oRelative==OBJECT_INVALID) oRelative=GetNearestObject(OBJECT_TYPE_PLACEABLE,oNPC,1);
|
|
if (oRelative!=OBJECT_INVALID)
|
|
{ // object found
|
|
AssignCommand(oNPC,ClearAllActions());
|
|
AssignCommand(oNPC,ActionMoveToObject(oRelative,TRUE,1.0));
|
|
DelayCommand(5.0,AssignCommand(oNPC,ClearAllActions()));
|
|
DelayCommand(5.1,AssignCommand(oNPC,ActionMoveToObject(oDest,nRun,fRange)));
|
|
nASR++;
|
|
} // object found
|
|
} // try nearby object
|
|
else if (nASC>2&&nASR>2)
|
|
{ // try teleport
|
|
DebugMove(" Teleport called to handle stuck.");
|
|
AssignCommand(oNPC,ClearAllActions());
|
|
AssignCommand(oNPC,JumpToObject(oDest));
|
|
nASR++;
|
|
} // try teleport
|
|
else if (nASR>4)
|
|
{ // error
|
|
return -1;
|
|
} // error
|
|
SetLocalInt(oNPC,"nGNBASC",nASC);
|
|
SetLocalInt(oNPC,"nGNBASR",nASR);
|
|
return 0;
|
|
} // might be stuck
|
|
else
|
|
{ // not stuck
|
|
DeleteLocalInt(oNPC,"nGNBASC");
|
|
} // not stuck
|
|
SetLocalFloat(oNPC,"fLastDist",fDist);
|
|
return 0;
|
|
} // object exists
|
|
} // long distance pathing
|
|
else
|
|
{ // use nearest transition
|
|
DebugMove(" Use nearby transition");
|
|
if (GetDistanceBetween(oNPC,oC)<=1.5)
|
|
{ // arrived at transition
|
|
AssignCommand(oNPC,ClearAllActions());
|
|
if (GetObjectType(oC)==OBJECT_TYPE_DOOR&&GetIsOpen(oC)==FALSE)
|
|
{ // face and open door
|
|
AssignCommand(oNPC,ActionOpenDoor(oC));
|
|
if (GetObjectType(GetTransitionTarget(oC))==OBJECT_TYPE_DOOR)
|
|
AssignCommand(GetTransitionTarget(oC),ActionOpenDoor(oC));
|
|
} // face and open door
|
|
oEnemy=GetTransitionTarget(oC);
|
|
oPCN=GetNearestObject(OBJECT_TYPE_WAYPOINT,oEnemy,1);
|
|
if (oPCN==OBJECT_INVALID) oPCN=GetNearestObject(OBJECT_TYPE_PLACEABLE,oEnemy,1);
|
|
if (oPCN==OBJECT_INVALID) oPCN=oEnemy;
|
|
AssignCommand(oNPC,JumpToObject(oPCN));
|
|
DeleteLocalInt(oNPC,"nGNBASC");
|
|
DeleteLocalInt(oNPC,"nGNBASR");
|
|
DeleteLocalFloat(oNPC,"fLastDist");
|
|
return 0;
|
|
} // arrived at transition
|
|
else
|
|
{ // move to nearby transition
|
|
fLD=GetLocalFloat(oNPC,"fLastDist");
|
|
fDist=GetDistanceBetween(oNPC,oC);
|
|
nASC=GetLocalInt(oNPC,"nGNBASC");
|
|
nASR=GetLocalInt(oNPC,"nGNBASR");
|
|
if (fLD==fDist)
|
|
{ // might be stuck
|
|
nASC++;
|
|
DebugMove(" anti-stuck nASC="+IntToString(nASC)+" nASR="+IntToString(nASR));
|
|
if (nASC<3)
|
|
{ // regular movement restart
|
|
AssignCommand(oNPC,ClearAllActions());
|
|
AssignCommand(oNPC,ActionMoveToLocation(GetLocation(oC),nRun));
|
|
} // regular movement restart
|
|
else if (nASC>2&&nASR<3)
|
|
{ // try nearby object
|
|
oRelative=GetNearestObject(OBJECT_TYPE_WAYPOINT,oNPC,d10());
|
|
if (oRelative==OBJECT_INVALID) oRelative=GetNearestObject(OBJECT_TYPE_WAYPOINT,oNPC,d8());
|
|
if (oRelative==OBJECT_INVALID) oRelative=GetNearestObject(OBJECT_TYPE_WAYPOINT,oNPC,d6());
|
|
if (oRelative==OBJECT_INVALID) oRelative=GetNearestObject(OBJECT_TYPE_PLACEABLE,oNPC,d10());
|
|
if (oRelative==OBJECT_INVALID) oRelative=GetNearestObject(OBJECT_TYPE_PLACEABLE,oNPC,d8());
|
|
if (oRelative==OBJECT_INVALID) oRelative=GetNearestObject(OBJECT_TYPE_PLACEABLE,oNPC,d6());
|
|
if (oRelative==OBJECT_INVALID) oRelative=GetNearestObject(OBJECT_TYPE_WAYPOINT,oNPC,1);
|
|
if (oRelative==OBJECT_INVALID) oRelative=GetNearestObject(OBJECT_TYPE_PLACEABLE,oNPC,1);
|
|
if (oRelative!=OBJECT_INVALID)
|
|
{ // object found
|
|
AssignCommand(oNPC,ClearAllActions());
|
|
AssignCommand(oNPC,ActionMoveToObject(oRelative,TRUE,1.0));
|
|
DelayCommand(5.0,AssignCommand(oNPC,ClearAllActions()));
|
|
DelayCommand(5.1,AssignCommand(oNPC,ActionMoveToLocation(GetLocation(oC),nRun)));
|
|
nASR++;
|
|
} // object found
|
|
} // try nearby object
|
|
else if (nASC>2&&nASR>2)
|
|
{ // try teleport
|
|
DebugMove(" Teleport called to handle stuck.");
|
|
AssignCommand(oNPC,ClearAllActions());
|
|
AssignCommand(oNPC,JumpToLocation(GetLocation(oC)));
|
|
nASR++;
|
|
} // try teleport
|
|
else if (nASR>4)
|
|
{ // error
|
|
AssignCommand(oNPC,ClearAllActions());
|
|
AssignCommand(oNPC,ActionForceMoveToObject(oDest,TRUE,fRange,60.0));
|
|
} // error
|
|
SetLocalInt(oNPC,"nGNBASC",nASC);
|
|
SetLocalInt(oNPC,"nGNBASR",nASR);
|
|
return 0;
|
|
} // might be stuck
|
|
else
|
|
{ // not stuck
|
|
nASC=0;
|
|
} // not stuck
|
|
SetLocalInt(oNPC,"nGNBASC",nASC);
|
|
SetLocalInt(oNPC,"nGNBASR",nASR);
|
|
SetLocalFloat(oNPC,"fLastDist",fDist);
|
|
return 0;
|
|
} // move to nearby transition
|
|
} // use nearest transition
|
|
} // different area
|
|
} // no instant movement
|
|
else
|
|
{ // teleport like movement
|
|
nASC=GetLocalInt(oNPC,"nGNBASC");
|
|
nASR=GetLocalInt(oNPC,"nGNBASR");
|
|
DebugMove(" Teleport Style Movement");
|
|
if (nASR==0)
|
|
{ // do teleport
|
|
if (nGRun==5) { AssignCommand(oNPC,ClearAllActions(TRUE)); AssignCommand(oNPC,JumpToObject(oDest)); }
|
|
else if (nGRun==6)
|
|
{ // teleport w/ VFX
|
|
AssignCommand(oNPC,ClearAllActions(TRUE));
|
|
eEff=EffectVisualEffect(VFX_FNF_IMPLOSION);
|
|
ApplyEffectAtLocation(DURATION_TYPE_INSTANT,eEff,GetLocation(oNPC),3.0);
|
|
ApplyEffectAtLocation(DURATION_TYPE_INSTANT,eEff,GetLocation(oDest),3.0);
|
|
DelayCommand(0.8,AssignCommand(oNPC,JumpToObject(oDest)));
|
|
} // teleport w/ VFX
|
|
else if (nGRun==7)
|
|
{ // fly out and then in
|
|
AssignCommand(oNPC,ClearAllActions(TRUE));
|
|
eEff=EffectDisappearAppear(GetLocation(oDest),1);
|
|
ApplyEffectToObject(DURATION_TYPE_TEMPORARY,eEff,oNPC,4.0);
|
|
} // fly out and then in
|
|
else if (nRun==8)
|
|
{ // custom VFX teleport
|
|
AssignCommand(oNPC,ClearAllActions(TRUE));
|
|
nN=GetLocalInt(oNPC,"nGNBVFX1");
|
|
eEff=EffectVisualEffect(nN);
|
|
ApplyEffectAtLocation(DURATION_TYPE_TEMPORARY,eEff,GetLocation(oNPC),4.0);
|
|
nN=GetLocalInt(oNPC,"nGNBVFX2");
|
|
eEff=EffectVisualEffect(nN);
|
|
ApplyEffectAtLocation(DURATION_TYPE_TEMPORARY,eEff,GetLocation(oDest),4.0);
|
|
DelayCommand(2.5,AssignCommand(oNPC,JumpToObject(oDest)));
|
|
} // custom VFX teleport
|
|
SetLocalInt(oNPC,"nGNBASR",1);
|
|
} // do teleport
|
|
else if (nASR==1)
|
|
{ // effect called
|
|
nASC++;
|
|
if (GetArea(oDest)==GetArea(oNPC)&&GetDistanceBetween(oDest,oNPC)<=fRange)
|
|
{ // arrived
|
|
DeleteLocalFloat(oNPC,"fLastDist");
|
|
DeleteLocalInt(oNPC,"nGNBASC");
|
|
DeleteLocalInt(oNPC,"nGNBASR");
|
|
DeleteLocalObject(oNPC,"oGNBNearbyObject");
|
|
return 1;
|
|
} // arrived
|
|
else if (nASC>4)
|
|
{ // did not arrive
|
|
DeleteLocalFloat(oNPC,"fLastDist");
|
|
DeleteLocalInt(oNPC,"nGNBASC");
|
|
DeleteLocalInt(oNPC,"nGNBASR");
|
|
DeleteLocalObject(oNPC,"oGNBNearbyObject");
|
|
return -1;
|
|
} // did not arrive
|
|
SetLocalInt(oNPC,"nGNBASC",nASC);
|
|
} // effect called
|
|
} // teleport like movement
|
|
} // AI level is sufficient or PCs are present
|
|
else
|
|
{ // handle no PC present and low AI level
|
|
if (GetArea(oDest)!=GetArea(oNPC)||GetDistanceBetween(oNPC,oDest)>fRange)
|
|
{ // move
|
|
DebugMove(" Execute Low-AI and No PC present movement routines");
|
|
AssignCommand(GetModule(),fnLowAINoPCMove(oNPC,oDest,fRange));
|
|
return 0;
|
|
} // move
|
|
else
|
|
{ // arrived
|
|
DeleteLocalInt(oNPC,"bModulePossessed");
|
|
return 1;
|
|
} // arrived
|
|
} // handle no PC present and loq AI level
|
|
return nRet;
|
|
} // fnMoveToDestinationB()
|
|
|
|
|
|
//void main(){}
|