344 lines
11 KiB
C++
344 lines
11 KiB
C++
/////////////////////////////////////////////////////
|
|
/////////////////////////////////////////////////////
|
|
//
|
|
// Character Grid Path Follow
|
|
//
|
|
/////////////////////////////////////////////////////
|
|
/////////////////////////////////////////////////////
|
|
|
|
#include "CKAll.h"
|
|
#include "./includes/GridManager.h"
|
|
#include "GridPathManager.h"
|
|
|
|
#define OUTPOUT_TELE1_NAME "Enter Teleporter"
|
|
#define OUTPOUT_TELE2_NAME "Travel Teleporter"
|
|
#define OUTPOUT_TELE3_NAME "Exit Teleporter"
|
|
|
|
//input
|
|
enum {INPUT_ON, INPUT_OFF, INPUT_RESET};
|
|
|
|
//outpout
|
|
enum
|
|
{
|
|
OUTPUT_OUT,
|
|
OUTPUT_STOP,
|
|
OUTPUT_COLLISION,
|
|
OUTPUT_AVOID,
|
|
OUTPUT_TELE1,
|
|
OUTPUT_TELE2,
|
|
OUTPUT_TELE3
|
|
};
|
|
|
|
//pinput
|
|
enum
|
|
{
|
|
INPUT_PARAM_PATHID,
|
|
INPUT_PARAM_DIR,
|
|
INPUT_PARAM_CHANGEDIRECTION,
|
|
INPUT_PARAM_LIMITANGLE,
|
|
INPUT_PARAM_FUZZY,
|
|
INPUT_PARAM_PINGPONG,
|
|
INPUT_PARAM_BLOCKEDTIME,
|
|
INPUT_PARAM_BLOCKEDDISTANCE,
|
|
INPUT_PARAM_TELE1,
|
|
INPUT_PARAM_TELE2,
|
|
INPUT_PARAM_TELE3
|
|
};
|
|
|
|
//pinput
|
|
enum
|
|
{
|
|
OUTPUT_PARAM_TARGETCOLLISION,
|
|
OUTPUT_PARAM_TARGETAVOID
|
|
};
|
|
|
|
//local parameter/setting
|
|
enum {LOCAL_SETTING_MANAGELINKER};
|
|
|
|
CKObjectDeclaration *FillBehaviorCharacterGridPathFollowDecl();
|
|
CKERROR CreateCharacterGridPathFollowProto(CKBehaviorPrototype **);
|
|
CKERROR CharacterGridPathFollowCallback (const CKBehaviorContext& behcontext);
|
|
int CharacterGridPathFollow(const CKBehaviorContext& behcontext);
|
|
|
|
//-------------------------------------------------
|
|
// Declaration
|
|
//-------------------------------------------------
|
|
|
|
CKObjectDeclaration *FillBehaviorCharacterGridPathFollowDecl()
|
|
{
|
|
CKObjectDeclaration *od = CreateCKObjectDeclaration("Character Grid Path Follow");
|
|
|
|
od->SetDescription("Allow to a character to follow a path generated by the GridPathSolver");
|
|
/* rem:
|
|
<SPAN CLASS=in>On: </SPAN>Activate or reactive the following.<BR>
|
|
<SPAN CLASS=in>Off: </SPAN>Stop the following.<BR>
|
|
<SPAN CLASS=in>Reset: </SPAN>Abord the following.<BR>
|
|
<BR>
|
|
<SPAN CLASS=out>Out: </SPAN>Is activate when the path is finished to be followed.<BR>
|
|
<SPAN CLASS=out>Can't Follow Path: </SPAN>Is activate when follow is reseted or when target can't follow the path<BR>
|
|
<BR>
|
|
<SPAN CLASS=pin>Path ID: </SPAN>Path ID<BR>
|
|
<SPAN CLASS=pin>Character Direction: </SPAN>defines the character's frontal direction.<BR>
|
|
<SPAN CLASS=pin>Change Direction Factor: </SPAN><BR>
|
|
<SPAN CLASS=pin>Limit Angle: </SPAN><BR>
|
|
<SPAN CLASS=pin>Fuzzyness: </SPAN>Allow to add noise to the path.<BR>
|
|
<SPAN CLASS=pin>Ping Pong: </SPAN>Character follow the path in both ways, indefinitely.<BR>
|
|
<SPAN CLASS=pin>Max Blocked Time: </SPAN>Max time a target stay blocked before abording following the path (and activating "Can't Follow Path").<BR>
|
|
<SPAN CLASS=pin>Blocked Distance": </SPAN>Minimun distance than character must cover to not being considered as blocked.<BR>
|
|
<SPAN CLASS=pin>Enter Teleporter Time: </SPAN>Time character stay before being teleported.<BR>
|
|
<SPAN CLASS=pin>Travel Teleporter Time: </SPAN>Teleporter travel time.<BR>
|
|
<SPAN CLASS=pin>Exit Teleporter Time: </SPAN>Time character stay before exit from a teleporter.<BR>
|
|
<BR>
|
|
<SPAN CLASS=setting>Manage Teleporter: </SPAN>Add teleporter parameters inputs and outputs.<BR>
|
|
|
|
*/
|
|
od->SetCategory("Grids/Path Finding");
|
|
od->SetType( CKDLL_BEHAVIORPROTOTYPE);
|
|
od->SetGuid(CKGUID(0x6d0a6dd3,0x43765df4));
|
|
od->SetAuthorGuid(VIRTOOLS_GUID);
|
|
od->SetAuthorName("Virtools");
|
|
od->SetVersion(0x00010000);
|
|
od->SetCreationFunction(CreateCharacterGridPathFollowProto);
|
|
od->SetCompatibleClassId(CKCID_CHARACTER);
|
|
return od;
|
|
}
|
|
|
|
//-------------------------------------------------
|
|
// Prototype
|
|
//-------------------------------------------------
|
|
|
|
CKERROR CreateCharacterGridPathFollowProto(CKBehaviorPrototype **pproto)
|
|
{
|
|
CKBehaviorPrototype *proto = CreateCKBehaviorPrototype("Character Grid Path Follow");
|
|
if(!proto) return CKERR_OUTOFMEMORY;
|
|
|
|
proto->DeclareInput("On");
|
|
proto->DeclareInput("Off");
|
|
proto->DeclareInput("Reset");
|
|
|
|
proto->DeclareOutput("Out");
|
|
proto->DeclareOutput("Can't Follow Path");
|
|
proto->DeclareOutput("Collion Happen");
|
|
proto->DeclareOutput("Avoid Happen");
|
|
|
|
proto->DeclareInParameter("Path ID", CKPGUID_INT);
|
|
proto->DeclareInParameter("Character Direction", CKPGUID_DIRECTION, "1");
|
|
proto->DeclareInParameter("Change Direction Factor", CKPGUID_FLOAT, "0.2");
|
|
proto->DeclareInParameter("Limit Angle", CKPGUID_ANGLE, "0:70");
|
|
proto->DeclareInParameter("Fuzzyness", CKPGUID_FLOAT, "0");
|
|
proto->DeclareInParameter("To and Fro", CKPGUID_BOOL, "FALSE");
|
|
proto->DeclareInParameter("Max Blocked Time", CKPGUID_TIME, "0m 10s 0ms");
|
|
proto->DeclareInParameter("Blocked Distance", CKPGUID_FLOAT, "0");
|
|
proto->DeclareInParameter("Enter Teleporter Time", CKPGUID_TIME);
|
|
proto->DeclareInParameter("Travel Teleporter Time", CKPGUID_TIME);
|
|
proto->DeclareInParameter("Exit Teleporter Time", CKPGUID_TIME);
|
|
|
|
proto->DeclareOutParameter("Collision Object", CKPGUID_3DENTITY);
|
|
proto->DeclareOutParameter("Avoid Object", CKPGUID_3DENTITY);
|
|
|
|
proto->DeclareSetting("Manage Teleporters", CKPGUID_BOOL, "FALSE");
|
|
|
|
proto->SetFlags(CK_BEHAVIORPROTOTYPE_NORMAL);
|
|
proto->SetFunction(CharacterGridPathFollow);
|
|
proto->SetBehaviorFlags((CK_BEHAVIOR_FLAGS)(CKBEHAVIOR_TARGETABLE | CKBEHAVIOR_MESSAGESENDER));
|
|
proto->SetBehaviorCallbackFct(CharacterGridPathFollowCallback);
|
|
|
|
*pproto = proto;
|
|
return CK_OK;
|
|
|
|
}
|
|
|
|
//-------------------------------------------------
|
|
// Fonction
|
|
//-------------------------------------------------
|
|
|
|
int CharacterGridPathFollow(const CKBehaviorContext& behcontext)
|
|
{
|
|
CKBehavior *beh = behcontext.Behavior;
|
|
CK3dEntity *target;
|
|
int followPathID;
|
|
|
|
// Get the 3d entity target.
|
|
target = (CK3dEntity *)beh->GetTarget();
|
|
beh->GetInputParameterValue(INPUT_PARAM_PATHID, &followPathID);
|
|
if (!target || followPathID < 0)
|
|
{
|
|
beh->ActivateOutput(OUTPUT_STOP, TRUE);
|
|
return CKBR_OWNERERROR;
|
|
}
|
|
|
|
CKGridManager *gm = (CKGridManager *)behcontext.Context->GetManagerByGuid(GRID_MANAGER_GUID);
|
|
GridPathManager *gridPathManager = ((GridManager *)gm)->GetGridPathManager();
|
|
|
|
// ON
|
|
if(beh->IsInputActive(INPUT_ON))
|
|
{
|
|
CKBOOL manageLinker;
|
|
|
|
// Desactivate Input.
|
|
beh->ActivateInput(INPUT_ON, FALSE);
|
|
|
|
// If problem exist and is stopped we set it to "on".
|
|
if (gridPathManager->GetStateFollowProblem(followPathID) == off)
|
|
{
|
|
gridPathManager->SetStateFollowProblem(followPathID, on);
|
|
return CKBR_ACTIVATENEXTFRAME;
|
|
}
|
|
|
|
FollowStruct followStruct;
|
|
followStruct.target = target;
|
|
followStruct.beh = beh;
|
|
followStruct.followPathID = followPathID;
|
|
|
|
// Get teleporter information.
|
|
beh->GetLocalParameterValue(LOCAL_SETTING_MANAGELINKER, &manageLinker);
|
|
if (manageLinker)
|
|
{
|
|
beh->GetInputParameterValue(INPUT_PARAM_TELE1, &followStruct.enterTele);
|
|
beh->GetInputParameterValue(INPUT_PARAM_TELE2, &followStruct.travelTele);
|
|
beh->GetInputParameterValue(INPUT_PARAM_TELE3, &followStruct.exitTele);
|
|
}
|
|
else
|
|
{
|
|
followStruct.enterTele = 0;
|
|
followStruct.travelTele = 0;
|
|
followStruct.exitTele = 0;
|
|
}
|
|
|
|
// Get param input.
|
|
beh->GetInputParameterValue(INPUT_PARAM_DIR, &followStruct.direction);
|
|
beh->GetInputParameterValue(INPUT_PARAM_CHANGEDIRECTION, &followStruct.minDistanceFactor);
|
|
beh->GetInputParameterValue(INPUT_PARAM_LIMITANGLE, &followStruct.limitAngle);
|
|
beh->GetInputParameterValue(INPUT_PARAM_FUZZY, &followStruct.fuzzyness);
|
|
beh->GetInputParameterValue(INPUT_PARAM_PINGPONG, &followStruct.pingpong);
|
|
beh->GetInputParameterValue(INPUT_PARAM_BLOCKEDTIME, &followStruct.maxBlockedTime);
|
|
beh->GetInputParameterValue(INPUT_PARAM_BLOCKEDDISTANCE, &followStruct.distanceBlocked);
|
|
|
|
// Register a new follow problem.
|
|
if (!gridPathManager->RegisterFollowProblem(&followStruct))
|
|
{
|
|
beh->ActivateOutput(OUTPUT_STOP, TRUE);
|
|
return CKBR_OK;
|
|
}
|
|
return CKBR_ACTIVATENEXTFRAME;
|
|
}
|
|
|
|
if (!gridPathManager->GetNbFollowProblem()) {
|
|
|
|
// Desactivate Input.
|
|
beh->ActivateInput(INPUT_OFF, FALSE);
|
|
beh->ActivateInput(INPUT_RESET, FALSE);
|
|
|
|
// Activate Output.
|
|
beh->ActivateOutput(OUTPUT_STOP);
|
|
return CKBR_OK;
|
|
}
|
|
|
|
// OFF
|
|
if(beh->IsInputActive(INPUT_OFF))
|
|
{
|
|
// Desactivate Input.
|
|
beh->ActivateInput(INPUT_OFF, FALSE);
|
|
|
|
// Set the follow problem to "stop"
|
|
gridPathManager->SetStateFollowProblem(followPathID, off);
|
|
}
|
|
|
|
// RESET
|
|
if(beh->IsInputActive(INPUT_RESET))
|
|
{
|
|
// Desactivate Input.
|
|
beh->ActivateInput(INPUT_RESET, FALSE);
|
|
|
|
// Unregister follow problem.
|
|
gridPathManager->UnregisterFollowProblem(followPathID);
|
|
|
|
// Activate Output.
|
|
beh->ActivateOutput(OUTPUT_STOP);
|
|
return CKBR_OK;
|
|
}
|
|
|
|
// Check if the target is on the path's end.
|
|
FollowState state = gridPathManager->GetStateFollowProblem(followPathID);
|
|
if (state == finish)
|
|
{
|
|
// Unregister follow problem.
|
|
gridPathManager->UnregisterFollowProblem(followPathID);
|
|
|
|
// Activate Output;
|
|
beh->ActivateOutput(OUTPUT_OUT);
|
|
return CKBR_OK;
|
|
}
|
|
else if (state == timeout)
|
|
{
|
|
// Unregister follow problem.
|
|
gridPathManager->UnregisterFollowProblem(followPathID);
|
|
|
|
// Activate Output;
|
|
beh->ActivateOutput(OUTPUT_STOP);
|
|
return CKBR_OK;
|
|
}
|
|
|
|
// The teleporter outputs are managed in gridPathManager.
|
|
//
|
|
return CKBR_ACTIVATENEXTFRAME;
|
|
}
|
|
|
|
//-------------------------------------------------
|
|
// Callback
|
|
//-------------------------------------------------
|
|
|
|
CKERROR CharacterGridPathFollowCallback (const CKBehaviorContext& behcontext)
|
|
{
|
|
CKBehavior* beh = behcontext.Behavior;
|
|
|
|
switch (behcontext.CallbackMessage)
|
|
{
|
|
case CKM_BEHAVIORLOAD:
|
|
case CKM_BEHAVIORCREATE:
|
|
case CKM_BEHAVIORSETTINGSEDITED:
|
|
{
|
|
CKParameterIn *pin1 = beh->GetInputParameter(INPUT_PARAM_TELE1);
|
|
CKParameterIn *pin2 = beh->GetInputParameter(INPUT_PARAM_TELE2);
|
|
CKParameterIn *pin3 = beh->GetInputParameter(INPUT_PARAM_TELE3);
|
|
CKBehaviorIO *outTele1 = beh->GetOutput(INPUT_PARAM_TELE1);
|
|
CKBehaviorIO *outTele2 = beh->GetOutput(INPUT_PARAM_TELE2);
|
|
CKBehaviorIO *outTele3 = beh->GetOutput(INPUT_PARAM_TELE3);
|
|
|
|
CKBOOL manageLinker;
|
|
beh->GetLocalParameterValue(LOCAL_SETTING_MANAGELINKER, &manageLinker);
|
|
int outpout_count = beh->GetOutputCount();
|
|
if (manageLinker)
|
|
{
|
|
// Add Teleporter input partameters.
|
|
pin1->Enable(TRUE);
|
|
pin2->Enable(TRUE);
|
|
pin3->Enable(TRUE);
|
|
if (outpout_count-1 < OUTPUT_TELE1)
|
|
{
|
|
// Add Teleporters Outputs.
|
|
beh->AddOutput(OUTPOUT_TELE1_NAME);
|
|
beh->AddOutput(OUTPOUT_TELE2_NAME);
|
|
beh->AddOutput(OUTPOUT_TELE3_NAME);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Remove Teleporter input partameters.
|
|
pin1->Enable(FALSE);
|
|
pin2->Enable(FALSE);
|
|
pin3->Enable(FALSE);
|
|
if (outpout_count-1 >= OUTPUT_TELE1)
|
|
{
|
|
// Remove Teleporters Outputs.
|
|
CKDestroyObject(beh->RemoveOutput(OUTPUT_TELE3));
|
|
CKDestroyObject(beh->RemoveOutput(OUTPUT_TELE2));
|
|
CKDestroyObject(beh->RemoveOutput(OUTPUT_TELE1));
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
return CKBR_OK;
|
|
}
|