/////////////////////////////////////////////////////
/////////////////////////////////////////////////////
//
// 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:
On: Activate or reactive the following.
Off: Stop the following.
Reset: Abord the following.
Out: Is activate when the path is finished to be followed.
Can't Follow Path: Is activate when follow is reseted or when target can't follow the path
Path ID: Path ID
Character Direction: defines the character's frontal direction.
Change Direction Factor:
Limit Angle:
Fuzzyness: Allow to add noise to the path.
Ping Pong: Character follow the path in both ways, indefinitely.
Max Blocked Time: Max time a target stay blocked before abording following the path (and activating "Can't Follow Path").
Blocked Distance": Minimun distance than character must cover to not being considered as blocked.
Enter Teleporter Time: Time character stay before being teleported.
Travel Teleporter Time: Teleporter travel time.
Exit Teleporter Time: Time character stay before exit from a teleporter.
Manage Teleporter: Add teleporter parameters inputs and outputs.
*/
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;
}