mirror of
https://github.com/TorqueGameEngines/Torque3D.git
synced 2026-01-19 20:24:49 +00:00
completed list of roughly ported over scripthooks.
todo: need to figure out why followobject is only hitting the first path node. likely amixup with goal handling
This commit is contained in:
parent
e37ae27bc0
commit
4fb92f02a3
|
|
@ -28,7 +28,7 @@ struct AIAimTarget : AIInfo
|
|||
typedef AIInfo Parent;
|
||||
Point3F mAimOffset;
|
||||
bool mTargetInLOS; // Is target object visible?
|
||||
Point3F getPosition() { return ((mObj) ? mObj->getPosition() : mPosition) + mAimOffset; }
|
||||
Point3F getPosition() { return ((mObj.isValid()) ? mObj->getPosition() : mPosition) + mAimOffset; }
|
||||
bool checkInLos(SceneObject* target = NULL, bool _useMuzzle = false, bool _checkEnabled = false);
|
||||
bool checkInFoV(SceneObject* target = NULL, F32 camFov = 45.0f, bool _checkEnabled = false);
|
||||
F32 getTargetDistance(SceneObject* target, bool _checkEnabled);
|
||||
|
|
|
|||
|
|
@ -82,25 +82,25 @@ bool AIController::getAIMove(Move* movePtr)
|
|||
{
|
||||
if (mMovement.mMoveState != ModeStop)
|
||||
getNav()->updateNavMesh();
|
||||
if (!getGoal()->mObj.isNull())
|
||||
if (getGoal() && !getGoal()->mObj.isNull())
|
||||
{
|
||||
if (getNav()->mPathData.path.isNull())
|
||||
{
|
||||
if (getGoal()->getDist() > mControllerData->mMoveTolerance)
|
||||
getNav()->followObject(getGoal());
|
||||
if (getGoal()->getDist() > mControllerData->mFollowTolerance)
|
||||
getNav()->followObject(getGoal()->mObj, mControllerData->mFollowTolerance);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (getGoal()->getDist() > mControllerData->mMoveTolerance)
|
||||
if (getGoal()->getDist() > mControllerData->mFollowTolerance)
|
||||
getNav()->repath();
|
||||
|
||||
if (getAim()->getDist() < mControllerData->mMoveTolerance)
|
||||
if (getGoal()->getDist() < mControllerData->mFollowTolerance)
|
||||
{
|
||||
getNav()->clearPath();
|
||||
mMovement.mMoveState = ModeStop;
|
||||
throwCallback("onTargetInRange");
|
||||
}
|
||||
else if (getAim()->getDist() < mControllerData->mAttackRadius)
|
||||
else if (getGoal()->getDist() < mControllerData->mAttackRadius)
|
||||
{
|
||||
throwCallback("onTargetInFiringRange");
|
||||
}
|
||||
|
|
@ -178,11 +178,29 @@ bool AIController::getAIMove(Move* movePtr)
|
|||
void AIController::clearCover()
|
||||
{
|
||||
// Notify cover that we are no longer on our way.
|
||||
if (!getCover()->mCoverPoint.isNull())
|
||||
if (getCover() && !getCover()->mCoverPoint.isNull())
|
||||
getCover()->mCoverPoint->setOccupied(false);
|
||||
SAFE_DELETE(mCover);
|
||||
}
|
||||
|
||||
void AIController::Movement::stopMove()
|
||||
{
|
||||
mMoveState = ModeStop;
|
||||
#ifdef TORQUE_NAVIGATION_ENABLED
|
||||
mControllerRef->getNav()->clearPath();
|
||||
mControllerRef->clearCover();
|
||||
mControllerRef->getNav()->clearFollow();
|
||||
#endif
|
||||
}
|
||||
void AIController::Movement::onStuck()
|
||||
{
|
||||
mControllerRef->throwCallback("onMoveStuck");
|
||||
#ifdef TORQUE_NAVIGATION_ENABLED
|
||||
if (!mControllerRef->getNav()->getPath().isNull())
|
||||
mControllerRef->getNav()->repath();
|
||||
#endif
|
||||
}
|
||||
|
||||
DefineEngineMethod(AIController, setMoveSpeed, void, (F32 speed), ,
|
||||
"@brief Sets the move speed for an AI object.\n\n"
|
||||
|
||||
|
|
@ -205,6 +223,60 @@ DefineEngineMethod(AIController, getMoveSpeed, F32, (), ,
|
|||
return object->mMovement.getMoveSpeed();
|
||||
}
|
||||
|
||||
DefineEngineMethod(AIController, stop, void, (), ,
|
||||
"@brief Tells the AIPlayer to stop moving.\n\n")
|
||||
{
|
||||
object->mMovement.stopMove();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Set the state of a movement trigger.
|
||||
*
|
||||
* @param slot The trigger slot to set
|
||||
* @param isSet set/unset the trigger
|
||||
*/
|
||||
void AIController::TriggerState::setMoveTrigger(U32 slot, const bool isSet)
|
||||
{
|
||||
if (slot >= MaxTriggerKeys)
|
||||
{
|
||||
Con::errorf("Attempting to set an invalid trigger slot (%i)", slot);
|
||||
}
|
||||
else
|
||||
{
|
||||
mMoveTriggers[slot] = isSet; // set the trigger
|
||||
mControllerRef->getAIInfo()->mObj->setMaskBits(ShapeBase::NoWarpMask); // force the client to updateMove
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the state of a movement trigger.
|
||||
*
|
||||
* @param slot The trigger slot to query
|
||||
* @return True if the trigger is set, false if it is not set
|
||||
*/
|
||||
bool AIController::TriggerState::getMoveTrigger(U32 slot) const
|
||||
{
|
||||
if (slot >= MaxTriggerKeys)
|
||||
{
|
||||
Con::errorf("Attempting to get an invalid trigger slot (%i)", slot);
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
return mMoveTriggers[slot];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear the trigger state for all movement triggers.
|
||||
*/
|
||||
void AIController::TriggerState::clearMoveTriggers()
|
||||
{
|
||||
for (U32 i = 0; i < MaxTriggerKeys; i++)
|
||||
setMoveTrigger(i, false);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
IMPLEMENT_CO_DATABLOCK_V1(AIControllerData);
|
||||
|
|
@ -341,6 +413,7 @@ void AIControllerData::resolveStuck(AIController* obj)
|
|||
if (obj->mMovement.mMoveState != AIController::ModeSlowing || locationDelta == 0)
|
||||
{
|
||||
obj->mMovement.mMoveState = AIController::ModeStuck;
|
||||
obj->mMovement.onStuck();
|
||||
obj->throwCallback("onStuck");
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -29,7 +29,6 @@
|
|||
#include "AICover.h"
|
||||
#include "AINavigation.h"
|
||||
class AIControllerData;
|
||||
class AIController;
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
class AIController : public SimObject {
|
||||
|
|
@ -83,6 +82,7 @@ public:
|
|||
AINavigation* getNav() { return mNav; };
|
||||
struct Movement
|
||||
{
|
||||
AIController* mControllerRef;
|
||||
MoveState mMoveState;
|
||||
F32 mMoveSpeed = 1.0;
|
||||
void setMoveSpeed(F32 speed) { mMoveSpeed = speed; };
|
||||
|
|
@ -99,6 +99,8 @@ public:
|
|||
|
||||
struct TriggerState
|
||||
{
|
||||
AIController* mControllerRef;
|
||||
bool mMoveTriggers[MaxTriggerKeys];
|
||||
// Trigger sets/gets
|
||||
void setMoveTrigger(U32 slot, const bool isSet = true);
|
||||
bool getMoveTrigger(U32 slot) const;
|
||||
|
|
@ -109,12 +111,18 @@ public:
|
|||
static void initPersistFields();
|
||||
AIController()
|
||||
{
|
||||
for (S32 i = 0; i < MaxTriggerKeys; i++)
|
||||
mTriggerState.mMoveTriggers[i] = false;
|
||||
|
||||
mMovement.mControllerRef = this;
|
||||
mTriggerState.mControllerRef = this;
|
||||
mControllerData = NULL;
|
||||
mAIInfo = new AIInfo(this);
|
||||
mGoal = new AIGoal(this);
|
||||
mAimTarget = new AIAimTarget(this);
|
||||
mCover = new AICover(this);
|
||||
mNav = new AINavigation(this);
|
||||
mMovement.mMoveState = ModeStop;
|
||||
};
|
||||
|
||||
DECLARE_CONOBJECT(AIController);
|
||||
|
|
@ -127,7 +135,16 @@ class AIControllerData : public SimDataBlock {
|
|||
|
||||
public:
|
||||
|
||||
AIControllerData() { mMoveTolerance = 0.25; mFollowTolerance = 1.0; mAttackRadius = 2.0; mMoveStuckTolerance = 0.01f; mMoveStuckTestDelay = 30;};
|
||||
AIControllerData()
|
||||
{
|
||||
mMoveTolerance = 0.25;
|
||||
mFollowTolerance = 1.0;
|
||||
mAttackRadius = 2.0;
|
||||
mMoveStuckTolerance = 0.01f;
|
||||
mMoveStuckTestDelay = 30;
|
||||
mLinkTypes = LinkData(AllFlags);
|
||||
mNavSize = AINavigation::Regular;
|
||||
};
|
||||
~AIControllerData() {};
|
||||
|
||||
static void initPersistFields();
|
||||
|
|
@ -140,7 +157,7 @@ public:
|
|||
S32 mMoveStuckTestDelay; // The number of ticks to wait before checking if the AI is stuck
|
||||
/// Types of link we can use.
|
||||
LinkData mLinkTypes;
|
||||
|
||||
AINavigation::NavSize mNavSize;
|
||||
void resolveYaw(AIController* obj, Point3F location, Move* movePtr);
|
||||
void resolvePitch(AIController* obj, Point3F location, Move* movePtr) {};
|
||||
void resolveRoll(AIController* obj, Point3F location, Move* movePtr);
|
||||
|
|
|
|||
|
|
@ -19,3 +19,90 @@
|
|||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
// IN THE SOFTWARE.
|
||||
//-----------------------------------------------------------------------------
|
||||
#include "AICover.h"
|
||||
#include "AIController.h"
|
||||
|
||||
struct CoverSearch
|
||||
{
|
||||
Point3F loc;
|
||||
Point3F from;
|
||||
F32 dist;
|
||||
F32 best;
|
||||
CoverPoint* point;
|
||||
CoverSearch() : loc(0, 0, 0), from(0, 0, 0)
|
||||
{
|
||||
best = -FLT_MAX;
|
||||
point = NULL;
|
||||
dist = FLT_MAX;
|
||||
}
|
||||
};
|
||||
|
||||
static void findCoverCallback(SceneObject* obj, void* key)
|
||||
{
|
||||
CoverPoint* p = dynamic_cast<CoverPoint*>(obj);
|
||||
if (!p || p->isOccupied())
|
||||
return;
|
||||
CoverSearch* s = static_cast<CoverSearch*>(key);
|
||||
Point3F dir = s->from - p->getPosition();
|
||||
dir.normalizeSafe();
|
||||
// Score first based on angle of cover point to enemy.
|
||||
F32 score = mDot(p->getNormal(), dir);
|
||||
// Score also based on distance from seeker.
|
||||
score -= (p->getPosition() - s->loc).len() / s->dist;
|
||||
// Finally, consider cover size.
|
||||
score += (p->getSize() + 1) / CoverPoint::NumSizes;
|
||||
score *= p->getQuality();
|
||||
if (score > s->best)
|
||||
{
|
||||
s->best = score;
|
||||
s->point = p;
|
||||
}
|
||||
}
|
||||
|
||||
bool AIController::findCover(const Point3F& from, F32 radius)
|
||||
{
|
||||
if (radius <= 0)
|
||||
return false;
|
||||
|
||||
// Create a search state.
|
||||
CoverSearch s;
|
||||
s.loc = getAIInfo()->getPosition();
|
||||
s.dist = radius;
|
||||
// Direction we seek cover FROM.
|
||||
s.from = from;
|
||||
|
||||
// Find cover points.
|
||||
Box3F box(radius * 2.0f);
|
||||
box.setCenter(getAIInfo()->getPosition());
|
||||
getAIInfo()->mObj->getContainer()->findObjects(box, MarkerObjectType, findCoverCallback, &s);
|
||||
|
||||
// Go to cover!
|
||||
if (s.point)
|
||||
{
|
||||
// Calling setPathDestination clears cover...
|
||||
bool foundPath = getNav()->setPathDestination(s.point->getPosition());
|
||||
setCover(s.point);
|
||||
s.point->setOccupied(true);
|
||||
return foundPath;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
DefineEngineMethod(AIController, findCover, S32, (Point3F from, F32 radius), ,
|
||||
"@brief Tells the AI to find cover nearby.\n\n"
|
||||
|
||||
"@param from Location to find cover from (i.e., enemy position).\n"
|
||||
"@param radius Distance to search for cover.\n"
|
||||
"@return Cover point ID if cover was found, -1 otherwise.\n\n")
|
||||
{
|
||||
if (object->findCover(from, radius))
|
||||
{
|
||||
CoverPoint* cover = object->getCover()->mCoverPoint.getObject();
|
||||
return cover ? cover->getId() : -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -23,6 +23,9 @@
|
|||
#define _AICOVER_H_
|
||||
|
||||
#include "AIInfo.h"
|
||||
#include "navigation/coverPoint.h"
|
||||
|
||||
|
||||
|
||||
struct AICover : AIInfo
|
||||
{
|
||||
|
|
@ -30,7 +33,7 @@ struct AICover : AIInfo
|
|||
/// Pointer to a cover point.
|
||||
SimObjectPtr<CoverPoint> mCoverPoint;
|
||||
AICover(AIController* controller) : Parent(controller) {};
|
||||
AICover(AIController* controller, SimObjectPtr<SceneObject> objIn, F32 radIn) : Parent(controller, objIn, radIn) {};
|
||||
AICover(AIController* controller, SimObjectPtr<SceneObject> objIn, F32 radIn) : Parent(controller, objIn, radIn) { mCoverPoint = dynamic_cast<CoverPoint*>(objIn.getPointer());};
|
||||
AICover(AIController* controller, Point3F pointIn, F32 radIn) : Parent(controller, pointIn, radIn) {};
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -53,7 +53,7 @@ AIInfo::AIInfo(AIController* controller, Point3F pointIn, F32 radIn)
|
|||
F32 AIInfo::getDist()
|
||||
{
|
||||
AIInfo* controlObj = getCtrl()->getAIInfo();
|
||||
F32 ret = VectorF(controlObj->mObj->getPosition() - getPosition()).len();
|
||||
F32 ret = VectorF(controlObj->getPosition() - getPosition()).len();
|
||||
ret -= controlObj->mRadius + mRadius;
|
||||
return ret;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -36,7 +36,7 @@ struct AIInfo
|
|||
Point3F mPosition, mLastPos;
|
||||
bool mPosSet;
|
||||
F32 mRadius;
|
||||
Point3F getPosition() { return (mObj) ? mObj->getPosition() : mPosition; }
|
||||
Point3F getPosition() { return (mObj.isValid()) ? mObj->getPosition() : mPosition; }
|
||||
F32 getDist();
|
||||
AIInfo() = delete;
|
||||
AIInfo(AIController* controller);
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@ AINavigation::AINavigation(AIController* controller)
|
|||
{
|
||||
mControllerRef = controller;
|
||||
mJump = None;
|
||||
mNavSize = Regular;
|
||||
}
|
||||
|
||||
NavMesh* AINavigation::findNavMesh() const
|
||||
|
|
@ -40,6 +41,19 @@ NavMesh* AINavigation::findNavMesh() const
|
|||
NavMesh* m = static_cast<NavMesh*>(set->at(i));
|
||||
if (m->getWorldBox().isContained(gbo->getWorldBox()))
|
||||
{
|
||||
// Check that mesh size is appropriate.
|
||||
if (gbo->isMounted())
|
||||
{
|
||||
if (!m->mVehicles)
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
if ((getNavSize() == Small && !m->mSmallCharacters) ||
|
||||
(getNavSize() == Regular && !m->mRegularCharacters) ||
|
||||
(getNavSize() == Large && !m->mLargeCharacters))
|
||||
continue;
|
||||
}
|
||||
if (!mesh || m->getWorldBox().getVolume() < mesh->getWorldBox().getVolume())
|
||||
mesh = m;
|
||||
}
|
||||
|
|
@ -101,6 +115,8 @@ void AINavigation::repath()
|
|||
if (mPathData.path.isNull() || !mPathData.owned)
|
||||
return;
|
||||
|
||||
if (!mControllerRef->getGoal()) return;
|
||||
|
||||
// If we're following, get their position.
|
||||
mPathData.path->mTo = mControllerRef->getGoal()->getPosition();
|
||||
// Update from position and replan.
|
||||
|
|
@ -212,24 +228,21 @@ bool AINavigation::setPathDestination(const Point3F& pos)
|
|||
}
|
||||
}
|
||||
|
||||
void AINavigation::followObject(AIInfo* targ)
|
||||
void AINavigation::followObject()
|
||||
{
|
||||
if (!targ) return;
|
||||
|
||||
if (targ->getDist() < mControllerRef->mControllerData->mMoveTolerance)
|
||||
if ((mControllerRef->getGoal()->mLastPos - mControllerRef->getAIInfo()->getPosition()).len() < mControllerRef->mControllerData->mMoveTolerance)
|
||||
return;
|
||||
|
||||
if (setPathDestination(targ->getPosition()))
|
||||
if (setPathDestination(mControllerRef->getGoal()->getPosition()))
|
||||
{
|
||||
mControllerRef->clearCover();
|
||||
mControllerRef->setGoal(targ);
|
||||
}
|
||||
}
|
||||
|
||||
void AINavigation::followObject(SceneObject* obj, F32 radius)
|
||||
{
|
||||
mControllerRef->setGoal(obj, radius);
|
||||
followObject(mControllerRef->getGoal());
|
||||
followObject();
|
||||
}
|
||||
|
||||
void AINavigation::clearFollow()
|
||||
|
|
@ -289,3 +302,107 @@ DefineEngineMethod(AIController, getMoveDestination, Point3F, (), ,
|
|||
return object->getNav()->getMoveDestination();
|
||||
}
|
||||
|
||||
DefineEngineMethod(AIController, setPathDestination, bool, (Point3F goal), ,
|
||||
"@brief Tells the AI to find a path to the location provided\n\n"
|
||||
|
||||
"@param goal Coordinates in world space representing location to move to.\n"
|
||||
"@return True if a path was found.\n\n"
|
||||
|
||||
"@see getPathDestination()\n"
|
||||
"@see setMoveDestination()\n")
|
||||
{
|
||||
return object->getNav()->setPathDestination(goal);
|
||||
}
|
||||
|
||||
|
||||
DefineEngineMethod(AIController, getPathDestination, Point3F, (), ,
|
||||
"@brief Get the AIPlayer's current pathfinding destination.\n\n"
|
||||
|
||||
"@return Returns a point containing the \"x y z\" position "
|
||||
"of the AIPlayer's current path destination. If no path destination "
|
||||
"has yet been set, this returns \"0 0 0\"."
|
||||
|
||||
"@see setPathDestination()\n")
|
||||
{
|
||||
return object->getNav()->getPathDestination();
|
||||
}
|
||||
|
||||
DefineEngineMethod(AIController, followNavPath, void, (SimObjectId obj), ,
|
||||
"@brief Tell the AIPlayer to follow a path.\n\n"
|
||||
|
||||
"@param obj ID of a NavPath object for the character to follow.")
|
||||
{
|
||||
NavPath* path;
|
||||
if (Sim::findObject(obj, path))
|
||||
object->getNav()->followNavPath(path);
|
||||
}
|
||||
|
||||
DefineEngineMethod(AIController, followObject, void, (SimObjectId obj, F32 radius), ,
|
||||
"@brief Tell the AIPlayer to follow another object.\n\n"
|
||||
|
||||
"@param obj ID of the object to follow.\n"
|
||||
"@param radius Maximum distance we let the target escape to.")
|
||||
{
|
||||
SceneObject* follow;
|
||||
object->getNav()->clearPath();
|
||||
object->clearCover();
|
||||
object->getNav()->clearFollow();
|
||||
|
||||
if (Sim::findObject(obj, follow))
|
||||
object->getNav()->followObject(follow, radius);
|
||||
}
|
||||
|
||||
|
||||
DefineEngineMethod(AIController, repath, void, (), ,
|
||||
"@brief Tells the AI to re-plan its path. Does nothing if the character "
|
||||
"has no path, or if it is following a mission path.\n\n")
|
||||
{
|
||||
object->getNav()->repath();
|
||||
}
|
||||
|
||||
DefineEngineMethod(AIController, findNavMesh, S32, (), ,
|
||||
"@brief Get the NavMesh object this AIPlayer is currently using.\n\n"
|
||||
|
||||
"@return The ID of the NavPath object this character is using for "
|
||||
"pathfinding. This is determined by the character's location, "
|
||||
"navigation type and other factors. Returns -1 if no NavMesh is "
|
||||
"found.")
|
||||
{
|
||||
NavMesh* mesh = object->getNav()->getNavMesh();
|
||||
return mesh ? mesh->getId() : -1;
|
||||
}
|
||||
|
||||
DefineEngineMethod(AIController, getNavMesh, S32, (), ,
|
||||
"@brief Return the NavMesh this AIPlayer is using to navigate.\n\n")
|
||||
{
|
||||
NavMesh* m = object->getNav()->getNavMesh();
|
||||
return m ? m->getId() : 0;
|
||||
}
|
||||
|
||||
DefineEngineMethod(AIController, setNavSize, void, (const char* size), ,
|
||||
"@brief Set the size of NavMesh this character uses. One of \"Small\", \"Regular\" or \"Large\".")
|
||||
{
|
||||
if (!String::compare(size, "Small"))
|
||||
object->getNav()->setNavSize(AINavigation::Small);
|
||||
else if (!String::compare(size, "Regular"))
|
||||
object->getNav()->setNavSize(AINavigation::Regular);
|
||||
else if (!String::compare(size, "Large"))
|
||||
object->getNav()->setNavSize(AINavigation::Large);
|
||||
else
|
||||
Con::errorf("AIPlayer::setNavSize: no such size '%s'.", size);
|
||||
}
|
||||
|
||||
DefineEngineMethod(AIController, getNavSize, const char*, (), ,
|
||||
"@brief Return the size of NavMesh this character uses for pathfinding.")
|
||||
{
|
||||
switch (object->getNav()->getNavSize())
|
||||
{
|
||||
case AINavigation::Small:
|
||||
return "Small";
|
||||
case AINavigation::Regular:
|
||||
return "Regular";
|
||||
case AINavigation::Large:
|
||||
return "Large";
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
|
|
|||
|
|
@ -59,6 +59,14 @@ struct AINavigation
|
|||
Ledge, ///< Jump when we walk off a ledge.
|
||||
};
|
||||
|
||||
enum NavSize {
|
||||
Small,
|
||||
Regular,
|
||||
Large
|
||||
} mNavSize;
|
||||
void setNavSize(NavSize size) { mNavSize = size; updateNavMesh(); }
|
||||
NavSize getNavSize() const { return mNavSize; }
|
||||
|
||||
Point3F mMoveDestination;
|
||||
void setMoveDestination(const Point3F& location, bool slowdown);
|
||||
Point3F getMoveDestination() { return mMoveDestination; };
|
||||
|
|
@ -68,6 +76,7 @@ struct AINavigation
|
|||
SimObjectPtr<NavMesh> mNavMesh;
|
||||
NavMesh* findNavMesh() const;
|
||||
void updateNavMesh();
|
||||
NavMesh* getNavMesh() const { return mNavMesh; }
|
||||
PathData mPathData;
|
||||
JumpStates mJump;
|
||||
|
||||
|
|
@ -81,7 +90,7 @@ struct AINavigation
|
|||
SimObjectPtr<NavPath> getPath() { return mPathData.path; };
|
||||
void followNavPath(NavPath* path);
|
||||
|
||||
void followObject(AIInfo* targ);
|
||||
void followObject();
|
||||
void followObject(SceneObject* obj, F32 radius);
|
||||
void clearFollow();
|
||||
/// Move to the specified node in the current path.
|
||||
|
|
|
|||
|
|
@ -2259,14 +2259,14 @@ void Player::advanceTime(F32 dt)
|
|||
}
|
||||
}
|
||||
|
||||
bool Player::setAIController(S32 controller)
|
||||
bool Player::setAIController(SimObjectId controller)
|
||||
{
|
||||
if (Sim::findObject(controller, mAIController))
|
||||
{
|
||||
mAIController->setAIInfo(this);
|
||||
return true;
|
||||
}
|
||||
|
||||
Con::errorf("unable to find AIController : %i", controller);
|
||||
mAIController = NULL;
|
||||
return false;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -763,7 +763,7 @@ public:
|
|||
void setMomentum(const Point3F &momentum) override;
|
||||
bool displaceObject(const Point3F& displaceVector) override;
|
||||
virtual bool getAIMove(Move*);
|
||||
bool setAIController(S32 controller);
|
||||
bool setAIController(SimObjectId controller);
|
||||
AIController* getAIController() { return mAIController; };
|
||||
|
||||
bool checkDismountPosition(const MatrixF& oldPos, const MatrixF& newPos); ///< Is it safe to dismount here?
|
||||
|
|
|
|||
|
|
@ -225,8 +225,18 @@ void GuiNavEditorCtrl::spawnPlayer(const Point3F &pos)
|
|||
SimGroup* missionCleanup = dynamic_cast<SimGroup*>(cleanup);
|
||||
missionCleanup->addObject(obj);
|
||||
}
|
||||
mPlayer = static_cast<AIPlayer*>(obj);
|
||||
Con::executef(this, "onPlayerSelected", Con::getIntArg(mPlayer->mLinkTypes.getFlags()));
|
||||
mPlayer = obj;
|
||||
Player* po = dynamic_cast<Player*>(obj);
|
||||
if (!po) return; //todo, more types
|
||||
if (po->getAIController())
|
||||
{
|
||||
if (po->getAIController()->mControllerData)
|
||||
Con::executef(this, "onPlayerSelected", Con::getIntArg(po->getAIController()->mControllerData->mLinkTypes.getFlags()));
|
||||
}
|
||||
else
|
||||
{
|
||||
Con::executef(this, "onPlayerSelected");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -383,16 +393,34 @@ void GuiNavEditorCtrl::on3DMouseDown(const Gui3DMouseEvent & event)
|
|||
// Select/move character
|
||||
else
|
||||
{
|
||||
if(gServerContainer.castRay(startPnt, endPnt, PlayerObjectType, &ri))
|
||||
if(gServerContainer.castRay(startPnt, endPnt, PlayerObjectType | VehicleObjectType, &ri))
|
||||
{
|
||||
if(dynamic_cast<AIPlayer*>(ri.object))
|
||||
if(ri.object)
|
||||
{
|
||||
mPlayer = dynamic_cast<AIPlayer*>(ri.object);
|
||||
Con::executef(this, "onPlayerSelected", Con::getIntArg(mPlayer->mLinkTypes.getFlags()));
|
||||
mPlayer = ri.object;
|
||||
Player* po = dynamic_cast<Player*>(ri.object);
|
||||
if (!po) return; //todo, more types
|
||||
if (po->getAIController())
|
||||
{
|
||||
if (po->getAIController()->mControllerData)
|
||||
Con::executef(this, "onPlayerSelected", Con::getIntArg(po->getAIController()->mControllerData->mLinkTypes.getFlags()));
|
||||
}
|
||||
else
|
||||
{
|
||||
Con::executef(this, "onPlayerSelected");
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (!mPlayer.isNull() && gServerContainer.castRay(startPnt, endPnt, StaticObjectType, &ri))
|
||||
{
|
||||
Player* po = dynamic_cast<Player*>(mPlayer.getPointer());
|
||||
if (!po) return; //todo, more types
|
||||
if (po->getAIController())
|
||||
{
|
||||
if (po->getAIController()->mControllerData)
|
||||
po->getAIController()->getNav()->setPathDestination(ri.point);
|
||||
}
|
||||
}
|
||||
else if(!mPlayer.isNull() && gServerContainer.castRay(startPnt, endPnt, StaticObjectType, &ri))
|
||||
mPlayer->setPathDestination(ri.point);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -455,8 +483,8 @@ void GuiNavEditorCtrl::on3DMouseMove(const Gui3DMouseEvent & event)
|
|||
|
||||
if(mMode == mTestMode)
|
||||
{
|
||||
if(gServerContainer.castRay(startPnt, endPnt, PlayerObjectType, &ri))
|
||||
mCurPlayer = dynamic_cast<AIPlayer*>(ri.object);
|
||||
if(gServerContainer.castRay(startPnt, endPnt, PlayerObjectType | VehicleObjectType, &ri))
|
||||
mCurPlayer = ri.object;
|
||||
else
|
||||
mCurPlayer = NULL;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -155,8 +155,8 @@ protected:
|
|||
/// @name Test mode
|
||||
/// @{
|
||||
|
||||
SimObjectPtr<AIPlayer> mPlayer;
|
||||
SimObjectPtr<AIPlayer> mCurPlayer;
|
||||
SimObjectPtr<SceneObject> mPlayer;
|
||||
SimObjectPtr<SceneObject> mCurPlayer;
|
||||
|
||||
/// @}
|
||||
|
||||
|
|
|
|||
|
|
@ -169,3 +169,8 @@ datablock LightAnimData( SpinLightAnim )
|
|||
rotKeys[2] = "az";
|
||||
rotSmooth[2] = true;
|
||||
};
|
||||
|
||||
datablock AIPlayerControllerData( aiPlayerControl )
|
||||
{
|
||||
|
||||
};
|
||||
|
|
@ -104,6 +104,7 @@ function ENavEditorSettingsPage::init(%this)
|
|||
{
|
||||
// Initialises the settings controls in the settings dialog box.
|
||||
%this-->SpawnClassOptions.clear();
|
||||
%this-->SpawnClassOptions.add("Player");
|
||||
%this-->SpawnClassOptions.add("AIPlayer");
|
||||
%this-->SpawnClassOptions.setFirstSelected();
|
||||
}
|
||||
|
|
@ -240,7 +241,7 @@ function NavEditorPlugin::initSettings(%this)
|
|||
{
|
||||
EditorSettings.beginGroup("NavEditor", true);
|
||||
|
||||
EditorSettings.setDefaultValue("SpawnClass", "AIPlayer");
|
||||
EditorSettings.setDefaultValue("SpawnClass", "Player");
|
||||
EditorSettings.setDefaultValue("SpawnDatablock", "DefaultPlayerData");
|
||||
|
||||
EditorSettings.endGroup();
|
||||
|
|
|
|||
|
|
@ -459,6 +459,12 @@ function NavEditorGui::onLinkSelected(%this, %flags)
|
|||
|
||||
function NavEditorGui::onPlayerSelected(%this, %flags)
|
||||
{
|
||||
if (!isObject(%this.getPlayer().aiController))
|
||||
{
|
||||
%this.getPlayer().aiController = new AIController(){ ControllerData = aiPlayerControl; };
|
||||
%this.getPlayer().setAIController(%this.getPlayer().aiController);
|
||||
}
|
||||
NavMeshIgnore(%this.getPlayer(), true);
|
||||
updateLinkData(NavEditorOptionsWindow-->TestProperties, %flags);
|
||||
}
|
||||
|
||||
|
|
@ -526,7 +532,7 @@ function NavEditorGui::findCover(%this)
|
|||
%text = NavEditorOptionsWindow-->TestProperties->CoverPosition.getText();
|
||||
if(%text !$= "")
|
||||
%pos = eval("return " @ %text);
|
||||
%this.getPlayer().findCover(%pos, NavEditorOptionsWindow-->TestProperties->CoverRadius.getText());
|
||||
%this.getPlayer().getAIController().findCover(%pos, NavEditorOptionsWindow-->TestProperties->CoverRadius.getText());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -547,7 +553,7 @@ function NavEditorGui::followObject(%this)
|
|||
toolsMessageBoxOk("Error", "Cannot find object" SPC %text);
|
||||
}
|
||||
if(isObject(%obj))
|
||||
%this.getPlayer().followObject(%obj, NavEditorOptionsWindow-->TestProperties->FollowRadius.getText());
|
||||
%this.getPlayer().getAIController().followObject(%obj, NavEditorOptionsWindow-->TestProperties->FollowRadius.getText());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue