///////////////////////////////////////////////////// ///////////////////////////////////////////////////// // // 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; }