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:
AzaezelX 2025-04-17 01:27:08 -05:00
parent e37ae27bc0
commit 4fb92f02a3
16 changed files with 386 additions and 40 deletions

View file

@ -28,7 +28,7 @@ struct AIAimTarget : AIInfo
typedef AIInfo Parent; typedef AIInfo Parent;
Point3F mAimOffset; Point3F mAimOffset;
bool mTargetInLOS; // Is target object visible? 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 checkInLos(SceneObject* target = NULL, bool _useMuzzle = false, bool _checkEnabled = false);
bool checkInFoV(SceneObject* target = NULL, F32 camFov = 45.0f, bool _checkEnabled = false); bool checkInFoV(SceneObject* target = NULL, F32 camFov = 45.0f, bool _checkEnabled = false);
F32 getTargetDistance(SceneObject* target, bool _checkEnabled); F32 getTargetDistance(SceneObject* target, bool _checkEnabled);

View file

@ -82,25 +82,25 @@ bool AIController::getAIMove(Move* movePtr)
{ {
if (mMovement.mMoveState != ModeStop) if (mMovement.mMoveState != ModeStop)
getNav()->updateNavMesh(); getNav()->updateNavMesh();
if (!getGoal()->mObj.isNull()) if (getGoal() && !getGoal()->mObj.isNull())
{ {
if (getNav()->mPathData.path.isNull()) if (getNav()->mPathData.path.isNull())
{ {
if (getGoal()->getDist() > mControllerData->mMoveTolerance) if (getGoal()->getDist() > mControllerData->mFollowTolerance)
getNav()->followObject(getGoal()); getNav()->followObject(getGoal()->mObj, mControllerData->mFollowTolerance);
} }
else else
{ {
if (getGoal()->getDist() > mControllerData->mMoveTolerance) if (getGoal()->getDist() > mControllerData->mFollowTolerance)
getNav()->repath(); getNav()->repath();
if (getAim()->getDist() < mControllerData->mMoveTolerance) if (getGoal()->getDist() < mControllerData->mFollowTolerance)
{ {
getNav()->clearPath(); getNav()->clearPath();
mMovement.mMoveState = ModeStop; mMovement.mMoveState = ModeStop;
throwCallback("onTargetInRange"); throwCallback("onTargetInRange");
} }
else if (getAim()->getDist() < mControllerData->mAttackRadius) else if (getGoal()->getDist() < mControllerData->mAttackRadius)
{ {
throwCallback("onTargetInFiringRange"); throwCallback("onTargetInFiringRange");
} }
@ -178,11 +178,29 @@ bool AIController::getAIMove(Move* movePtr)
void AIController::clearCover() void AIController::clearCover()
{ {
// Notify cover that we are no longer on our way. // Notify cover that we are no longer on our way.
if (!getCover()->mCoverPoint.isNull()) if (getCover() && !getCover()->mCoverPoint.isNull())
getCover()->mCoverPoint->setOccupied(false); getCover()->mCoverPoint->setOccupied(false);
SAFE_DELETE(mCover); 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), , DefineEngineMethod(AIController, setMoveSpeed, void, (F32 speed), ,
"@brief Sets the move speed for an AI object.\n\n" "@brief Sets the move speed for an AI object.\n\n"
@ -205,6 +223,60 @@ DefineEngineMethod(AIController, getMoveSpeed, F32, (), ,
return object->mMovement.getMoveSpeed(); 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); IMPLEMENT_CO_DATABLOCK_V1(AIControllerData);
@ -341,6 +413,7 @@ void AIControllerData::resolveStuck(AIController* obj)
if (obj->mMovement.mMoveState != AIController::ModeSlowing || locationDelta == 0) if (obj->mMovement.mMoveState != AIController::ModeSlowing || locationDelta == 0)
{ {
obj->mMovement.mMoveState = AIController::ModeStuck; obj->mMovement.mMoveState = AIController::ModeStuck;
obj->mMovement.onStuck();
obj->throwCallback("onStuck"); obj->throwCallback("onStuck");
} }
} }

View file

@ -29,7 +29,6 @@
#include "AICover.h" #include "AICover.h"
#include "AINavigation.h" #include "AINavigation.h"
class AIControllerData; class AIControllerData;
class AIController;
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
class AIController : public SimObject { class AIController : public SimObject {
@ -83,6 +82,7 @@ public:
AINavigation* getNav() { return mNav; }; AINavigation* getNav() { return mNav; };
struct Movement struct Movement
{ {
AIController* mControllerRef;
MoveState mMoveState; MoveState mMoveState;
F32 mMoveSpeed = 1.0; F32 mMoveSpeed = 1.0;
void setMoveSpeed(F32 speed) { mMoveSpeed = speed; }; void setMoveSpeed(F32 speed) { mMoveSpeed = speed; };
@ -99,6 +99,8 @@ public:
struct TriggerState struct TriggerState
{ {
AIController* mControllerRef;
bool mMoveTriggers[MaxTriggerKeys];
// Trigger sets/gets // Trigger sets/gets
void setMoveTrigger(U32 slot, const bool isSet = true); void setMoveTrigger(U32 slot, const bool isSet = true);
bool getMoveTrigger(U32 slot) const; bool getMoveTrigger(U32 slot) const;
@ -109,12 +111,18 @@ public:
static void initPersistFields(); static void initPersistFields();
AIController() AIController()
{ {
for (S32 i = 0; i < MaxTriggerKeys; i++)
mTriggerState.mMoveTriggers[i] = false;
mMovement.mControllerRef = this;
mTriggerState.mControllerRef = this;
mControllerData = NULL; mControllerData = NULL;
mAIInfo = new AIInfo(this); mAIInfo = new AIInfo(this);
mGoal = new AIGoal(this); mGoal = new AIGoal(this);
mAimTarget = new AIAimTarget(this); mAimTarget = new AIAimTarget(this);
mCover = new AICover(this); mCover = new AICover(this);
mNav = new AINavigation(this); mNav = new AINavigation(this);
mMovement.mMoveState = ModeStop;
}; };
DECLARE_CONOBJECT(AIController); DECLARE_CONOBJECT(AIController);
@ -127,7 +135,16 @@ class AIControllerData : public SimDataBlock {
public: 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() {}; ~AIControllerData() {};
static void initPersistFields(); static void initPersistFields();
@ -140,7 +157,7 @@ public:
S32 mMoveStuckTestDelay; // The number of ticks to wait before checking if the AI is stuck S32 mMoveStuckTestDelay; // The number of ticks to wait before checking if the AI is stuck
/// Types of link we can use. /// Types of link we can use.
LinkData mLinkTypes; LinkData mLinkTypes;
AINavigation::NavSize mNavSize;
void resolveYaw(AIController* obj, Point3F location, Move* movePtr); void resolveYaw(AIController* obj, Point3F location, Move* movePtr);
void resolvePitch(AIController* obj, Point3F location, Move* movePtr) {}; void resolvePitch(AIController* obj, Point3F location, Move* movePtr) {};
void resolveRoll(AIController* obj, Point3F location, Move* movePtr); void resolveRoll(AIController* obj, Point3F location, Move* movePtr);

View file

@ -19,3 +19,90 @@
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE. // 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;
}
}

View file

@ -23,6 +23,9 @@
#define _AICOVER_H_ #define _AICOVER_H_
#include "AIInfo.h" #include "AIInfo.h"
#include "navigation/coverPoint.h"
struct AICover : AIInfo struct AICover : AIInfo
{ {
@ -30,7 +33,7 @@ struct AICover : AIInfo
/// Pointer to a cover point. /// Pointer to a cover point.
SimObjectPtr<CoverPoint> mCoverPoint; SimObjectPtr<CoverPoint> mCoverPoint;
AICover(AIController* controller) : Parent(controller) {}; 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) {}; AICover(AIController* controller, Point3F pointIn, F32 radIn) : Parent(controller, pointIn, radIn) {};
}; };

View file

@ -53,7 +53,7 @@ AIInfo::AIInfo(AIController* controller, Point3F pointIn, F32 radIn)
F32 AIInfo::getDist() F32 AIInfo::getDist()
{ {
AIInfo* controlObj = getCtrl()->getAIInfo(); AIInfo* controlObj = getCtrl()->getAIInfo();
F32 ret = VectorF(controlObj->mObj->getPosition() - getPosition()).len(); F32 ret = VectorF(controlObj->getPosition() - getPosition()).len();
ret -= controlObj->mRadius + mRadius; ret -= controlObj->mRadius + mRadius;
return ret; return ret;
} }

View file

@ -36,7 +36,7 @@ struct AIInfo
Point3F mPosition, mLastPos; Point3F mPosition, mLastPos;
bool mPosSet; bool mPosSet;
F32 mRadius; F32 mRadius;
Point3F getPosition() { return (mObj) ? mObj->getPosition() : mPosition; } Point3F getPosition() { return (mObj.isValid()) ? mObj->getPosition() : mPosition; }
F32 getDist(); F32 getDist();
AIInfo() = delete; AIInfo() = delete;
AIInfo(AIController* controller); AIInfo(AIController* controller);

View file

@ -26,6 +26,7 @@ AINavigation::AINavigation(AIController* controller)
{ {
mControllerRef = controller; mControllerRef = controller;
mJump = None; mJump = None;
mNavSize = Regular;
} }
NavMesh* AINavigation::findNavMesh() const NavMesh* AINavigation::findNavMesh() const
@ -40,6 +41,19 @@ NavMesh* AINavigation::findNavMesh() const
NavMesh* m = static_cast<NavMesh*>(set->at(i)); NavMesh* m = static_cast<NavMesh*>(set->at(i));
if (m->getWorldBox().isContained(gbo->getWorldBox())) 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()) if (!mesh || m->getWorldBox().getVolume() < mesh->getWorldBox().getVolume())
mesh = m; mesh = m;
} }
@ -101,6 +115,8 @@ void AINavigation::repath()
if (mPathData.path.isNull() || !mPathData.owned) if (mPathData.path.isNull() || !mPathData.owned)
return; return;
if (!mControllerRef->getGoal()) return;
// If we're following, get their position. // If we're following, get their position.
mPathData.path->mTo = mControllerRef->getGoal()->getPosition(); mPathData.path->mTo = mControllerRef->getGoal()->getPosition();
// Update from position and replan. // 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 ((mControllerRef->getGoal()->mLastPos - mControllerRef->getAIInfo()->getPosition()).len() < mControllerRef->mControllerData->mMoveTolerance)
if (targ->getDist() < mControllerRef->mControllerData->mMoveTolerance)
return; return;
if (setPathDestination(targ->getPosition())) if (setPathDestination(mControllerRef->getGoal()->getPosition()))
{ {
mControllerRef->clearCover(); mControllerRef->clearCover();
mControllerRef->setGoal(targ);
} }
} }
void AINavigation::followObject(SceneObject* obj, F32 radius) void AINavigation::followObject(SceneObject* obj, F32 radius)
{ {
mControllerRef->setGoal(obj, radius); mControllerRef->setGoal(obj, radius);
followObject(mControllerRef->getGoal()); followObject();
} }
void AINavigation::clearFollow() void AINavigation::clearFollow()
@ -289,3 +302,107 @@ DefineEngineMethod(AIController, getMoveDestination, Point3F, (), ,
return object->getNav()->getMoveDestination(); 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 "";
}

View file

@ -59,6 +59,14 @@ struct AINavigation
Ledge, ///< Jump when we walk off a ledge. 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; Point3F mMoveDestination;
void setMoveDestination(const Point3F& location, bool slowdown); void setMoveDestination(const Point3F& location, bool slowdown);
Point3F getMoveDestination() { return mMoveDestination; }; Point3F getMoveDestination() { return mMoveDestination; };
@ -68,6 +76,7 @@ struct AINavigation
SimObjectPtr<NavMesh> mNavMesh; SimObjectPtr<NavMesh> mNavMesh;
NavMesh* findNavMesh() const; NavMesh* findNavMesh() const;
void updateNavMesh(); void updateNavMesh();
NavMesh* getNavMesh() const { return mNavMesh; }
PathData mPathData; PathData mPathData;
JumpStates mJump; JumpStates mJump;
@ -81,7 +90,7 @@ struct AINavigation
SimObjectPtr<NavPath> getPath() { return mPathData.path; }; SimObjectPtr<NavPath> getPath() { return mPathData.path; };
void followNavPath(NavPath* path); void followNavPath(NavPath* path);
void followObject(AIInfo* targ); void followObject();
void followObject(SceneObject* obj, F32 radius); void followObject(SceneObject* obj, F32 radius);
void clearFollow(); void clearFollow();
/// Move to the specified node in the current path. /// Move to the specified node in the current path.

View file

@ -2259,14 +2259,14 @@ void Player::advanceTime(F32 dt)
} }
} }
bool Player::setAIController(S32 controller) bool Player::setAIController(SimObjectId controller)
{ {
if (Sim::findObject(controller, mAIController)) if (Sim::findObject(controller, mAIController))
{ {
mAIController->setAIInfo(this); mAIController->setAIInfo(this);
return true; return true;
} }
Con::errorf("unable to find AIController : %i", controller);
mAIController = NULL; mAIController = NULL;
return false; return false;
} }

View file

@ -763,7 +763,7 @@ public:
void setMomentum(const Point3F &momentum) override; void setMomentum(const Point3F &momentum) override;
bool displaceObject(const Point3F& displaceVector) override; bool displaceObject(const Point3F& displaceVector) override;
virtual bool getAIMove(Move*); virtual bool getAIMove(Move*);
bool setAIController(S32 controller); bool setAIController(SimObjectId controller);
AIController* getAIController() { return mAIController; }; AIController* getAIController() { return mAIController; };
bool checkDismountPosition(const MatrixF& oldPos, const MatrixF& newPos); ///< Is it safe to dismount here? bool checkDismountPosition(const MatrixF& oldPos, const MatrixF& newPos); ///< Is it safe to dismount here?

View file

@ -225,8 +225,18 @@ void GuiNavEditorCtrl::spawnPlayer(const Point3F &pos)
SimGroup* missionCleanup = dynamic_cast<SimGroup*>(cleanup); SimGroup* missionCleanup = dynamic_cast<SimGroup*>(cleanup);
missionCleanup->addObject(obj); missionCleanup->addObject(obj);
} }
mPlayer = static_cast<AIPlayer*>(obj); mPlayer = obj;
Con::executef(this, "onPlayerSelected", Con::getIntArg(mPlayer->mLinkTypes.getFlags())); 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 // Select/move character
else 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); mPlayer = ri.object;
Con::executef(this, "onPlayerSelected", Con::getIntArg(mPlayer->mLinkTypes.getFlags())); 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(mMode == mTestMode)
{ {
if(gServerContainer.castRay(startPnt, endPnt, PlayerObjectType, &ri)) if(gServerContainer.castRay(startPnt, endPnt, PlayerObjectType | VehicleObjectType, &ri))
mCurPlayer = dynamic_cast<AIPlayer*>(ri.object); mCurPlayer = ri.object;
else else
mCurPlayer = NULL; mCurPlayer = NULL;
} }

View file

@ -155,8 +155,8 @@ protected:
/// @name Test mode /// @name Test mode
/// @{ /// @{
SimObjectPtr<AIPlayer> mPlayer; SimObjectPtr<SceneObject> mPlayer;
SimObjectPtr<AIPlayer> mCurPlayer; SimObjectPtr<SceneObject> mCurPlayer;
/// @} /// @}

View file

@ -169,3 +169,8 @@ datablock LightAnimData( SpinLightAnim )
rotKeys[2] = "az"; rotKeys[2] = "az";
rotSmooth[2] = true; rotSmooth[2] = true;
}; };
datablock AIPlayerControllerData( aiPlayerControl )
{
};

View file

@ -104,6 +104,7 @@ function ENavEditorSettingsPage::init(%this)
{ {
// Initialises the settings controls in the settings dialog box. // Initialises the settings controls in the settings dialog box.
%this-->SpawnClassOptions.clear(); %this-->SpawnClassOptions.clear();
%this-->SpawnClassOptions.add("Player");
%this-->SpawnClassOptions.add("AIPlayer"); %this-->SpawnClassOptions.add("AIPlayer");
%this-->SpawnClassOptions.setFirstSelected(); %this-->SpawnClassOptions.setFirstSelected();
} }
@ -240,7 +241,7 @@ function NavEditorPlugin::initSettings(%this)
{ {
EditorSettings.beginGroup("NavEditor", true); EditorSettings.beginGroup("NavEditor", true);
EditorSettings.setDefaultValue("SpawnClass", "AIPlayer"); EditorSettings.setDefaultValue("SpawnClass", "Player");
EditorSettings.setDefaultValue("SpawnDatablock", "DefaultPlayerData"); EditorSettings.setDefaultValue("SpawnDatablock", "DefaultPlayerData");
EditorSettings.endGroup(); EditorSettings.endGroup();

View file

@ -459,6 +459,12 @@ function NavEditorGui::onLinkSelected(%this, %flags)
function NavEditorGui::onPlayerSelected(%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); updateLinkData(NavEditorOptionsWindow-->TestProperties, %flags);
} }
@ -526,7 +532,7 @@ function NavEditorGui::findCover(%this)
%text = NavEditorOptionsWindow-->TestProperties->CoverPosition.getText(); %text = NavEditorOptionsWindow-->TestProperties->CoverPosition.getText();
if(%text !$= "") if(%text !$= "")
%pos = eval("return " @ %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); toolsMessageBoxOk("Error", "Cannot find object" SPC %text);
} }
if(isObject(%obj)) if(isObject(%obj))
%this.getPlayer().followObject(%obj, NavEditorOptionsWindow-->TestProperties->FollowRadius.getText()); %this.getPlayer().getAIController().followObject(%obj, NavEditorOptionsWindow-->TestProperties->FollowRadius.getText());
} }
} }