2022-08-06 03:01:59 +00:00
|
|
|
#include "MovementAIComponent.h"
|
2021-12-05 17:54:36 +00:00
|
|
|
|
|
|
|
#include <utility>
|
|
|
|
#include <cmath>
|
|
|
|
|
|
|
|
#include "ControllablePhysicsComponent.h"
|
|
|
|
#include "BaseCombatAIComponent.h"
|
|
|
|
#include "dpCommon.h"
|
|
|
|
#include "dpWorld.h"
|
|
|
|
#include "EntityManager.h"
|
|
|
|
#include "SimplePhysicsComponent.h"
|
|
|
|
|
|
|
|
std::map<LOT, float> MovementAIComponent::m_PhysicsSpeedCache = {};
|
|
|
|
|
|
|
|
MovementAIComponent::MovementAIComponent(Entity* parent, MovementAIInfo info) : Component(parent) {
|
|
|
|
m_Info = std::move(info);
|
|
|
|
m_Done = true;
|
|
|
|
|
|
|
|
m_BaseCombatAI = nullptr;
|
2022-07-28 13:39:57 +00:00
|
|
|
|
2021-12-05 17:54:36 +00:00
|
|
|
m_BaseCombatAI = reinterpret_cast<BaseCombatAIComponent*>(m_Parent->GetComponent(COMPONENT_TYPE_BASE_COMBAT_AI));
|
|
|
|
|
|
|
|
//Try and fix the insane values:
|
|
|
|
if (m_Info.wanderRadius > 5.0f) m_Info.wanderRadius = m_Info.wanderRadius * 0.5f;
|
|
|
|
if (m_Info.wanderRadius > 8.0f) m_Info.wanderRadius = 8.0f;
|
|
|
|
if (m_Info.wanderSpeed > 0.5f) m_Info.wanderSpeed = m_Info.wanderSpeed * 0.5f;
|
|
|
|
|
|
|
|
m_BaseSpeed = GetBaseSpeed(m_Parent->GetLOT());
|
|
|
|
|
|
|
|
m_NextWaypoint = GetCurrentPosition();
|
|
|
|
m_Acceleration = 0.4f;
|
|
|
|
m_Interrupted = false;
|
|
|
|
m_PullPoint = {};
|
|
|
|
m_HaltDistance = 0;
|
|
|
|
m_Timer = 0;
|
|
|
|
m_CurrentSpeed = 0;
|
|
|
|
m_Speed = 0;
|
|
|
|
m_TotalTime = 0;
|
|
|
|
m_LockRotation = false;
|
2022-11-12 14:47:47 +00:00
|
|
|
|
|
|
|
m_MovementPath = nullptr;
|
|
|
|
m_isReverse = false;
|
2021-12-05 17:54:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
MovementAIComponent::~MovementAIComponent() = default;
|
|
|
|
|
|
|
|
void MovementAIComponent::Update(const float deltaTime) {
|
2022-07-28 13:39:57 +00:00
|
|
|
if (m_Interrupted) {
|
2021-12-05 17:54:36 +00:00
|
|
|
const auto source = GetCurrentWaypoint();
|
|
|
|
|
|
|
|
const auto speed = deltaTime * 2.5f;
|
2022-07-28 13:39:57 +00:00
|
|
|
|
2021-12-05 17:54:36 +00:00
|
|
|
NiPoint3 velocity;
|
|
|
|
|
|
|
|
velocity.x = (m_PullPoint.x - source.x) * speed;
|
|
|
|
velocity.y = (m_PullPoint.y - source.y) * speed;
|
|
|
|
velocity.z = (m_PullPoint.z - source.z) * speed;
|
|
|
|
|
|
|
|
SetPosition(source + velocity);
|
|
|
|
|
2022-07-28 13:39:57 +00:00
|
|
|
if (Vector3::DistanceSquared(GetCurrentPosition(), m_PullPoint) < 2 * 2) {
|
2021-12-05 17:54:36 +00:00
|
|
|
m_Interrupted = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
2022-07-28 13:39:57 +00:00
|
|
|
|
2022-11-12 14:47:47 +00:00
|
|
|
if (AtFinalWaypoint()) return; // Are we donw?
|
2021-12-05 17:54:36 +00:00
|
|
|
|
2022-07-28 13:39:57 +00:00
|
|
|
if (m_HaltDistance > 0) {
|
2022-11-12 14:47:47 +00:00
|
|
|
if (Vector3::DistanceSquared(ApproximateLocation(), GetDestination()) < m_HaltDistance * m_HaltDistance) { // Prevent us from hugging the target
|
2021-12-05 17:54:36 +00:00
|
|
|
Stop();
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
2022-11-12 14:47:47 +00:00
|
|
|
Game::logger->Log("MovementAIComponent", "timer %f", m_Timer);
|
2022-07-28 13:39:57 +00:00
|
|
|
if (m_Timer > 0) {
|
2021-12-05 17:54:36 +00:00
|
|
|
m_Timer -= deltaTime;
|
|
|
|
|
2022-07-28 13:39:57 +00:00
|
|
|
if (m_Timer > 0) {
|
2021-12-05 17:54:36 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
m_Timer = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
const auto source = GetCurrentWaypoint();
|
2022-07-28 13:39:57 +00:00
|
|
|
|
2021-12-05 17:54:36 +00:00
|
|
|
SetPosition(source);
|
|
|
|
|
|
|
|
NiPoint3 velocity = NiPoint3::ZERO;
|
|
|
|
|
2022-11-12 14:47:47 +00:00
|
|
|
if (AdvanceWaypointIndex()) { // Do we have another waypoint to seek?
|
2021-12-05 17:54:36 +00:00
|
|
|
m_NextWaypoint = GetCurrentWaypoint();
|
|
|
|
|
2022-07-28 13:39:57 +00:00
|
|
|
if (m_NextWaypoint == source) {
|
2021-12-05 17:54:36 +00:00
|
|
|
m_Timer = 0;
|
2022-11-12 14:47:47 +00:00
|
|
|
} else {
|
2021-12-05 17:54:36 +00:00
|
|
|
|
2022-11-12 14:47:47 +00:00
|
|
|
if (m_CurrentSpeed < m_Speed) {
|
|
|
|
m_CurrentSpeed += m_Acceleration;
|
|
|
|
}
|
2021-12-05 17:54:36 +00:00
|
|
|
|
2022-11-12 14:47:47 +00:00
|
|
|
if (m_CurrentSpeed > m_Speed) {
|
|
|
|
m_CurrentSpeed = m_Speed;
|
|
|
|
}
|
2021-12-05 17:54:36 +00:00
|
|
|
|
2022-11-12 14:47:47 +00:00
|
|
|
const auto speed = m_CurrentSpeed * m_BaseSpeed;
|
2021-12-05 17:54:36 +00:00
|
|
|
|
2022-11-12 14:47:47 +00:00
|
|
|
const auto delta = m_NextWaypoint - source;
|
2021-12-05 17:54:36 +00:00
|
|
|
|
2022-11-12 14:47:47 +00:00
|
|
|
// Normalize the vector
|
|
|
|
const auto length = sqrtf(delta.x * delta.x + delta.y * delta.y + delta.z * delta.z);
|
2021-12-05 17:54:36 +00:00
|
|
|
|
2022-11-12 14:47:47 +00:00
|
|
|
if (length > 0) {
|
|
|
|
velocity.x = (delta.x / length) * speed;
|
|
|
|
velocity.y = (delta.y / length) * speed;
|
|
|
|
velocity.z = (delta.z / length) * speed;
|
|
|
|
}
|
2021-12-05 17:54:36 +00:00
|
|
|
|
2022-11-12 14:47:47 +00:00
|
|
|
// Calclute the time it will take to reach the next waypoint with the current speed
|
|
|
|
Game::logger->Log("MovementAIComponent", "length %f speed %f", length, speed);
|
|
|
|
m_TotalTime = m_Timer = length / speed;
|
2022-07-28 13:39:57 +00:00
|
|
|
|
2022-11-12 14:47:47 +00:00
|
|
|
SetRotation(NiQuaternion::LookAt(source, m_NextWaypoint));
|
|
|
|
}
|
2022-07-28 13:39:57 +00:00
|
|
|
} else {
|
2021-12-05 17:54:36 +00:00
|
|
|
// Check if there are more waypoints in the queue, if so set our next destination to the next waypoint
|
2022-07-28 13:39:57 +00:00
|
|
|
if (!m_Queue.empty()) {
|
2021-12-05 17:54:36 +00:00
|
|
|
SetDestination(m_Queue.top());
|
|
|
|
|
|
|
|
m_Queue.pop();
|
2022-07-28 13:39:57 +00:00
|
|
|
} else {
|
2021-12-05 17:54:36 +00:00
|
|
|
// We have reached our final waypoint
|
|
|
|
Stop();
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
2022-07-28 13:39:57 +00:00
|
|
|
|
2021-12-05 17:54:36 +00:00
|
|
|
SetVelocity(velocity);
|
|
|
|
|
|
|
|
EntityManager::Instance()->SerializeEntity(m_Parent);
|
|
|
|
}
|
|
|
|
|
2022-07-28 13:39:57 +00:00
|
|
|
const MovementAIInfo& MovementAIComponent::GetInfo() const {
|
2021-12-05 17:54:36 +00:00
|
|
|
return m_Info;
|
|
|
|
}
|
|
|
|
|
2022-07-28 13:39:57 +00:00
|
|
|
bool MovementAIComponent::AdvanceWaypointIndex() {
|
2022-11-12 14:47:47 +00:00
|
|
|
Game::logger->Log("MovementAIComponent", "reached waypoint check");
|
|
|
|
|
2022-07-28 13:39:57 +00:00
|
|
|
if (m_PathIndex >= m_CurrentPath.size()) {
|
2022-11-12 14:47:47 +00:00
|
|
|
if (m_MovementPath){
|
|
|
|
if (m_MovementPath->pathBehavior == PathBehavior::Loop){
|
|
|
|
m_PathIndex = 0;
|
|
|
|
return true;
|
|
|
|
} else {
|
|
|
|
if (m_MovementPath->pathBehavior == PathBehavior::Bounce){
|
|
|
|
m_isReverse = true;
|
|
|
|
m_PathIndex--;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2021-12-05 17:54:36 +00:00
|
|
|
return false;
|
2022-11-12 14:47:47 +00:00
|
|
|
} else if (m_PathIndex <= 0) {
|
|
|
|
m_PathIndex = 0;
|
|
|
|
m_isReverse = false;
|
2021-12-05 17:54:36 +00:00
|
|
|
}
|
2022-07-28 13:39:57 +00:00
|
|
|
|
2022-11-12 14:47:47 +00:00
|
|
|
if (m_isReverse) m_PathIndex--;
|
|
|
|
else m_PathIndex++;
|
2021-12-05 17:54:36 +00:00
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2022-07-28 13:39:57 +00:00
|
|
|
NiPoint3 MovementAIComponent::GetCurrentWaypoint() const {
|
2022-11-12 14:47:47 +00:00
|
|
|
Game::logger->Log("MovementAIComponent", "get current waypoint");
|
2022-07-28 13:39:57 +00:00
|
|
|
if (m_PathIndex >= m_CurrentPath.size()) {
|
2021-12-05 17:54:36 +00:00
|
|
|
return GetCurrentPosition();
|
|
|
|
}
|
|
|
|
|
2022-11-12 14:47:47 +00:00
|
|
|
auto source = GetCurrentPosition();
|
|
|
|
auto destination = m_CurrentPa.at(m_PathIndex);
|
|
|
|
if (dpWorld::Instance().IsLoaded()) {
|
|
|
|
destination.y = dpWorld::Instance().GetNavMesh()->GetHeightAtPoint(destination);
|
|
|
|
}
|
|
|
|
if (abs(destination.y - source.y) > 3) destination.y = source.y;
|
|
|
|
|
|
|
|
return destination;
|
|
|
|
}
|
|
|
|
|
|
|
|
void MovementAIComponent::ArrivedAtPathWaypoint(){
|
|
|
|
// TODO: Call scripts here
|
|
|
|
|
|
|
|
PathWaypoint waypoint = m_CurrentPath->pathWaypoints.at(m_WaypointPathIndex);
|
|
|
|
|
|
|
|
if (waypoint.config.size() > 0) {
|
|
|
|
|
|
|
|
for (LDFBaseData* action : waypoint.config) {
|
|
|
|
if (action) {
|
|
|
|
|
|
|
|
// delay: has time as float
|
|
|
|
if (action->GetKey() == u"delay"){
|
|
|
|
m_WaitingTime += std::stof(action->GetValueAsString());
|
|
|
|
SetVelocity(NiPoint3::ZERO);
|
|
|
|
EntityManager::Instance()->SerializeEntity(m_Parent);
|
|
|
|
|
|
|
|
// emote: has name of animation to play
|
|
|
|
} else if (action->GetKey() == u"emote"){
|
|
|
|
GameMessages::SendPlayAnimation(m_Parent, GeneralUtils::UTF8ToUTF16(action->GetValueAsString()));
|
|
|
|
// TODO Get proper animation time and add to wait
|
|
|
|
m_WaitingTime += 1;
|
|
|
|
SetVelocity(NiPoint3::ZERO);
|
|
|
|
EntityManager::Instance()->SerializeEntity(m_Parent);
|
|
|
|
|
|
|
|
// pathspeed: has pathing speed as a float
|
|
|
|
} else if (action->GetKey() == u"pathspeed") {
|
|
|
|
m_PathSpeed = std::stof(action->GetValueAsString());
|
|
|
|
|
|
|
|
// changeWP: <path to change to>,<waypoint to use> the command and waypoint are optional
|
|
|
|
} else if (action->GetKey() == u"changeWP") {
|
|
|
|
// use an intermediate value since it can be one or two things
|
|
|
|
auto intermed = action->GetValueAsString();
|
|
|
|
std::string path_string = "";
|
|
|
|
|
|
|
|
// sometimes there's a path and what waypoint to start, which are comma separated
|
|
|
|
if (intermed.find(",") != std::string::npos){
|
|
|
|
auto datas = GeneralUtils::SplitString(intermed, ',');
|
|
|
|
path_string = datas[0];
|
|
|
|
m_WaypointPathIndex = stoi(datas[1]) - 1; // becuase 0 vs 1 indexed
|
|
|
|
} else {
|
|
|
|
path_string = intermed;
|
|
|
|
m_WaypointPathIndex = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (path_string != "") {
|
|
|
|
m_CurrentPath = const_cast<Path*>(dZoneManager::Instance()->GetZone()->GetPath(path_string));
|
|
|
|
} else m_CurrentPath = nullptr;
|
|
|
|
|
|
|
|
} else {
|
|
|
|
// We don't recognize the action, let a dev know
|
|
|
|
Game::logger->LogDebug("ControllablePhysicsComponent", "Unhandled action %s", GeneralUtils::UTF16ToWTF8(action->GetKey()).c_str());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (m_WaitingTime == 0) { // if we don't have any time to wait
|
|
|
|
m_Waiting = false;
|
|
|
|
}
|
2021-12-05 17:54:36 +00:00
|
|
|
}
|
|
|
|
|
2022-07-28 13:39:57 +00:00
|
|
|
NiPoint3 MovementAIComponent::GetNextWaypoint() const {
|
2021-12-05 17:54:36 +00:00
|
|
|
return m_NextWaypoint;
|
|
|
|
}
|
|
|
|
|
2022-07-28 13:39:57 +00:00
|
|
|
NiPoint3 MovementAIComponent::GetCurrentPosition() const {
|
2021-12-05 17:54:36 +00:00
|
|
|
return m_Parent->GetPosition();
|
|
|
|
}
|
|
|
|
|
2022-07-28 13:39:57 +00:00
|
|
|
NiPoint3 MovementAIComponent::ApproximateLocation() const {
|
2021-12-05 17:54:36 +00:00
|
|
|
auto source = GetCurrentPosition();
|
2022-07-28 13:39:57 +00:00
|
|
|
|
|
|
|
if (m_Done) {
|
2021-12-05 17:54:36 +00:00
|
|
|
return source;
|
|
|
|
}
|
2022-07-28 13:39:57 +00:00
|
|
|
|
2021-12-05 17:54:36 +00:00
|
|
|
auto destination = m_NextWaypoint;
|
|
|
|
|
|
|
|
auto factor = m_TotalTime > 0 ? (m_TotalTime - m_Timer) / m_TotalTime : 0;
|
|
|
|
|
|
|
|
auto x = source.x + factor * (destination.x - source.x);
|
|
|
|
auto y = source.y + factor * (destination.y - source.y);
|
|
|
|
auto z = source.z + factor * (destination.z - source.z);
|
|
|
|
|
|
|
|
NiPoint3 approximation = NiPoint3(x, y, z);
|
2022-07-28 13:39:57 +00:00
|
|
|
|
|
|
|
if (dpWorld::Instance().IsLoaded()) {
|
2022-08-02 05:30:19 +00:00
|
|
|
approximation.y = dpWorld::Instance().GetNavMesh()->GetHeightAtPoint(approximation);
|
2021-12-05 17:54:36 +00:00
|
|
|
}
|
2022-11-12 14:47:47 +00:00
|
|
|
if (abs(destination.y - source.y) > 3) destination.y = source.y;
|
2021-12-05 17:54:36 +00:00
|
|
|
|
|
|
|
return approximation;
|
|
|
|
}
|
|
|
|
|
2022-07-28 13:39:57 +00:00
|
|
|
bool MovementAIComponent::Warp(const NiPoint3& point) {
|
2021-12-05 17:54:36 +00:00
|
|
|
Stop();
|
2022-07-28 13:39:57 +00:00
|
|
|
|
2021-12-05 17:54:36 +00:00
|
|
|
NiPoint3 destination = point;
|
|
|
|
|
2022-07-28 13:39:57 +00:00
|
|
|
if (dpWorld::Instance().IsLoaded()) {
|
2022-08-02 05:30:19 +00:00
|
|
|
destination.y = dpWorld::Instance().GetNavMesh()->GetHeightAtPoint(point);
|
2021-12-05 17:54:36 +00:00
|
|
|
|
2022-07-28 13:39:57 +00:00
|
|
|
if (std::abs(destination.y - point.y) > 3) {
|
2021-12-05 17:54:36 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
SetPosition(destination);
|
|
|
|
|
|
|
|
EntityManager::Instance()->SerializeEntity(m_Parent);
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2022-07-28 13:39:57 +00:00
|
|
|
float MovementAIComponent::GetTimer() const {
|
2021-12-05 17:54:36 +00:00
|
|
|
return m_Timer;
|
|
|
|
}
|
|
|
|
|
2022-07-28 13:39:57 +00:00
|
|
|
bool MovementAIComponent::AtFinalWaypoint() const {
|
2022-11-12 14:47:47 +00:00
|
|
|
|
2021-12-05 17:54:36 +00:00
|
|
|
return m_Done;
|
|
|
|
}
|
|
|
|
|
2022-07-28 13:39:57 +00:00
|
|
|
void MovementAIComponent::Stop() {
|
2022-11-12 14:47:47 +00:00
|
|
|
Game::logger->Log("MovementAIComponent", "stopped");
|
2022-07-28 13:39:57 +00:00
|
|
|
if (m_Done) {
|
2021-12-05 17:54:36 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
SetPosition(ApproximateLocation());
|
|
|
|
|
|
|
|
SetVelocity(NiPoint3::ZERO);
|
2022-07-28 13:39:57 +00:00
|
|
|
|
2021-12-05 17:54:36 +00:00
|
|
|
m_TotalTime = m_Timer = 0;
|
2022-07-28 13:39:57 +00:00
|
|
|
|
2021-12-05 17:54:36 +00:00
|
|
|
m_Done = true;
|
|
|
|
|
|
|
|
m_CurrentPath = {};
|
|
|
|
|
|
|
|
m_PathIndex = 0;
|
|
|
|
|
|
|
|
m_CurrentSpeed = 0;
|
2022-07-28 13:39:57 +00:00
|
|
|
|
2021-12-05 17:54:36 +00:00
|
|
|
EntityManager::Instance()->SerializeEntity(m_Parent);
|
|
|
|
}
|
|
|
|
|
2022-07-28 13:39:57 +00:00
|
|
|
void MovementAIComponent::PullToPoint(const NiPoint3& point) {
|
2021-12-05 17:54:36 +00:00
|
|
|
Stop();
|
2022-07-28 13:39:57 +00:00
|
|
|
|
2021-12-05 17:54:36 +00:00
|
|
|
m_Interrupted = true;
|
|
|
|
m_PullPoint = point;
|
|
|
|
}
|
|
|
|
|
2022-07-28 13:39:57 +00:00
|
|
|
void MovementAIComponent::SetPath(std::vector<NiPoint3> path) {
|
2021-12-05 17:54:36 +00:00
|
|
|
std::reverse(path.begin(), path.end());
|
|
|
|
|
2022-07-28 13:39:57 +00:00
|
|
|
for (const auto& point : path) {
|
2021-12-05 17:54:36 +00:00
|
|
|
m_Queue.push(point);
|
|
|
|
}
|
|
|
|
|
|
|
|
SetDestination(m_Queue.top());
|
|
|
|
|
|
|
|
m_Queue.pop();
|
|
|
|
}
|
|
|
|
|
2022-11-12 14:47:47 +00:00
|
|
|
void MovementAIComponent::SetMovementPath(Path* movementPath){
|
|
|
|
Game::logger->Log("MovementAIComponent", "setmovementpath %s", movementPath->pathName.c_str());
|
|
|
|
m_MovementPath = movementPath;
|
|
|
|
|
|
|
|
// get waypoints
|
|
|
|
std::vector<NiPoint3> pathWaypoints;
|
|
|
|
for (const auto& waypoint : movementPath->pathWaypoints) m_CurrentPath.push_back(waypoint.position);
|
|
|
|
SetSpeed(m_BaseSpeed);
|
|
|
|
m_PathIndex = 0;
|
|
|
|
|
|
|
|
m_TotalTime = m_Timer = 0;
|
|
|
|
|
|
|
|
m_Done = false;
|
|
|
|
|
|
|
|
};
|
|
|
|
|
2022-07-28 13:39:57 +00:00
|
|
|
float MovementAIComponent::GetBaseSpeed(LOT lot) {
|
2021-12-05 17:54:36 +00:00
|
|
|
// Check if the lot is in the cache
|
|
|
|
const auto& it = m_PhysicsSpeedCache.find(lot);
|
2022-07-28 13:39:57 +00:00
|
|
|
|
|
|
|
if (it != m_PhysicsSpeedCache.end()) {
|
2021-12-05 17:54:36 +00:00
|
|
|
return it->second;
|
|
|
|
}
|
2022-07-28 13:39:57 +00:00
|
|
|
|
2021-12-05 17:54:36 +00:00
|
|
|
CDComponentsRegistryTable* componentRegistryTable = CDClientManager::Instance()->GetTable<CDComponentsRegistryTable>("ComponentsRegistry");
|
|
|
|
CDPhysicsComponentTable* physicsComponentTable = CDClientManager::Instance()->GetTable<CDPhysicsComponentTable>("PhysicsComponent");
|
|
|
|
|
|
|
|
int32_t componentID;
|
|
|
|
CDPhysicsComponent* physicsComponent = nullptr;
|
|
|
|
|
2022-07-28 13:39:57 +00:00
|
|
|
componentID = componentRegistryTable->GetByIDAndType(lot, COMPONENT_TYPE_CONTROLLABLE_PHYSICS, -1);
|
2021-12-05 17:54:36 +00:00
|
|
|
|
2022-07-28 13:39:57 +00:00
|
|
|
if (componentID != -1) {
|
2021-12-05 17:54:36 +00:00
|
|
|
physicsComponent = physicsComponentTable->GetByID(componentID);
|
|
|
|
|
|
|
|
goto foundComponent;
|
|
|
|
}
|
|
|
|
|
|
|
|
componentID = componentRegistryTable->GetByIDAndType(lot, COMPONENT_TYPE_SIMPLE_PHYSICS, -1);
|
|
|
|
|
2022-07-28 13:39:57 +00:00
|
|
|
if (componentID != -1) {
|
2021-12-05 17:54:36 +00:00
|
|
|
physicsComponent = physicsComponentTable->GetByID(componentID);
|
|
|
|
|
|
|
|
goto foundComponent;
|
|
|
|
}
|
|
|
|
|
2022-07-28 13:39:57 +00:00
|
|
|
foundComponent:
|
2021-12-05 17:54:36 +00:00
|
|
|
|
|
|
|
float speed;
|
|
|
|
|
2022-07-28 13:39:57 +00:00
|
|
|
if (physicsComponent == nullptr) {
|
2021-12-05 17:54:36 +00:00
|
|
|
speed = 8;
|
2022-07-28 13:39:57 +00:00
|
|
|
} else {
|
2021-12-05 17:54:36 +00:00
|
|
|
speed = physicsComponent->speed;
|
|
|
|
}
|
|
|
|
|
|
|
|
m_PhysicsSpeedCache[lot] = speed;
|
2022-11-12 14:47:47 +00:00
|
|
|
Game::logger->Log("MovementAIComponent", "speed = %f", speed);
|
2021-12-05 17:54:36 +00:00
|
|
|
|
|
|
|
return speed;
|
|
|
|
}
|
|
|
|
|
2022-07-28 13:39:57 +00:00
|
|
|
void MovementAIComponent::SetPosition(const NiPoint3& value) {
|
2022-11-12 14:47:47 +00:00
|
|
|
Game::logger->Log("MovementAIComponent", "set position %f %f %f", value.x, value.y, value.z);
|
2021-12-05 17:54:36 +00:00
|
|
|
auto* controllablePhysicsComponent = m_Parent->GetComponent<ControllablePhysicsComponent>();
|
|
|
|
|
2022-07-28 13:39:57 +00:00
|
|
|
if (controllablePhysicsComponent != nullptr) {
|
2021-12-05 17:54:36 +00:00
|
|
|
controllablePhysicsComponent->SetPosition(value);
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
auto* simplePhysicsComponent = m_Parent->GetComponent<SimplePhysicsComponent>();
|
|
|
|
|
2022-07-28 13:39:57 +00:00
|
|
|
if (simplePhysicsComponent != nullptr) {
|
2021-12-05 17:54:36 +00:00
|
|
|
simplePhysicsComponent->SetPosition(value);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-07-28 13:39:57 +00:00
|
|
|
void MovementAIComponent::SetRotation(const NiQuaternion& value) {
|
|
|
|
if (m_LockRotation) {
|
2021-12-05 17:54:36 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
auto* controllablePhysicsComponent = m_Parent->GetComponent<ControllablePhysicsComponent>();
|
|
|
|
|
2022-07-28 13:39:57 +00:00
|
|
|
if (controllablePhysicsComponent != nullptr) {
|
2021-12-05 17:54:36 +00:00
|
|
|
controllablePhysicsComponent->SetRotation(value);
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
auto* simplePhysicsComponent = m_Parent->GetComponent<SimplePhysicsComponent>();
|
|
|
|
|
2022-07-28 13:39:57 +00:00
|
|
|
if (simplePhysicsComponent != nullptr) {
|
2021-12-05 17:54:36 +00:00
|
|
|
simplePhysicsComponent->SetRotation(value);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-07-28 13:39:57 +00:00
|
|
|
void MovementAIComponent::SetVelocity(const NiPoint3& value) {
|
2022-11-12 14:47:47 +00:00
|
|
|
Game::logger->Log("MovementAIComponent", "set velocity %f %f %f", value.x, value.y, value.z);
|
|
|
|
|
2021-12-05 17:54:36 +00:00
|
|
|
auto* controllablePhysicsComponent = m_Parent->GetComponent<ControllablePhysicsComponent>();
|
|
|
|
|
2022-07-28 13:39:57 +00:00
|
|
|
if (controllablePhysicsComponent != nullptr) {
|
2021-12-05 17:54:36 +00:00
|
|
|
controllablePhysicsComponent->SetVelocity(value);
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
auto* simplePhysicsComponent = m_Parent->GetComponent<SimplePhysicsComponent>();
|
|
|
|
|
2022-07-28 13:39:57 +00:00
|
|
|
if (simplePhysicsComponent != nullptr) {
|
2021-12-05 17:54:36 +00:00
|
|
|
simplePhysicsComponent->SetVelocity(value);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-07-28 13:39:57 +00:00
|
|
|
void MovementAIComponent::SetDestination(const NiPoint3& value) {
|
|
|
|
if (m_Interrupted) {
|
2021-12-05 17:54:36 +00:00
|
|
|
return;
|
|
|
|
}
|
2022-07-28 13:39:57 +00:00
|
|
|
|
2021-12-05 17:54:36 +00:00
|
|
|
/*if (Vector3::DistanceSquared(value, GetDestination()) < 2 * 2)
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}*/
|
|
|
|
|
|
|
|
const auto location = ApproximateLocation();
|
|
|
|
|
2022-07-28 13:39:57 +00:00
|
|
|
if (!AtFinalWaypoint()) {
|
2021-12-05 17:54:36 +00:00
|
|
|
SetPosition(location);
|
|
|
|
}
|
|
|
|
|
|
|
|
std::vector<NiPoint3> computedPath;
|
2022-07-28 13:39:57 +00:00
|
|
|
|
|
|
|
if (dpWorld::Instance().IsLoaded()) {
|
2022-08-02 05:30:19 +00:00
|
|
|
computedPath = dpWorld::Instance().GetNavMesh()->GetPath(GetCurrentPosition(), value, m_Info.wanderSpeed);
|
2022-07-28 13:39:57 +00:00
|
|
|
} else {
|
2021-12-05 17:54:36 +00:00
|
|
|
// Than take 10 points between the current position and the destination and make that the path
|
|
|
|
|
|
|
|
auto point = location;
|
|
|
|
|
|
|
|
auto delta = value - point;
|
|
|
|
|
|
|
|
auto step = delta / 10;
|
|
|
|
|
2022-07-28 13:39:57 +00:00
|
|
|
for (int i = 0; i < 10; i++) {
|
2021-12-05 17:54:36 +00:00
|
|
|
point = point + step;
|
|
|
|
|
|
|
|
computedPath.push_back(point);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (computedPath.empty()) // Somehow failed
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
m_CurrentPath.clear();
|
|
|
|
|
|
|
|
m_CurrentPath.push_back(location);
|
|
|
|
|
|
|
|
// Simply path
|
2022-07-28 13:39:57 +00:00
|
|
|
for (auto point : computedPath) {
|
|
|
|
if (dpWorld::Instance().IsLoaded()) {
|
2022-08-02 05:30:19 +00:00
|
|
|
point.y = dpWorld::Instance().GetNavMesh()->GetHeightAtPoint(point);
|
2021-12-05 17:54:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
m_CurrentPath.push_back(point);
|
|
|
|
}
|
|
|
|
|
2022-11-12 14:47:47 +00:00
|
|
|
m_CurrentPath.push_back(computedPath.at(computedPath.size() - 1]));
|
2022-07-28 13:39:57 +00:00
|
|
|
|
2021-12-05 17:54:36 +00:00
|
|
|
m_PathIndex = 0;
|
2022-07-28 13:39:57 +00:00
|
|
|
|
2021-12-05 17:54:36 +00:00
|
|
|
m_TotalTime = m_Timer = 0;
|
2022-07-28 13:39:57 +00:00
|
|
|
|
2021-12-05 17:54:36 +00:00
|
|
|
m_Done = false;
|
|
|
|
}
|
|
|
|
|
2022-07-28 13:39:57 +00:00
|
|
|
NiPoint3 MovementAIComponent::GetDestination() const {
|
|
|
|
if (m_CurrentPath.empty()) {
|
2021-12-05 17:54:36 +00:00
|
|
|
return GetCurrentPosition();
|
|
|
|
}
|
|
|
|
|
2022-11-12 14:47:47 +00:00
|
|
|
auto destination = m_CurrentPath.at(m_CurrentPath.size() - 1);
|
|
|
|
if (dpWorld::Instance().IsLoaded()) {
|
|
|
|
destination.y = dpWorld::Instance().GetNavMesh()->GetHeightAtPoint(destination);
|
|
|
|
}
|
|
|
|
auto source = ApproximateLocation();
|
|
|
|
if (abs(destination.y - source.y) > 3) destination.y = source.y;
|
|
|
|
|
|
|
|
return destination;
|
2021-12-05 17:54:36 +00:00
|
|
|
}
|
|
|
|
|
2022-07-28 13:39:57 +00:00
|
|
|
void MovementAIComponent::SetSpeed(const float value) {
|
2021-12-05 17:54:36 +00:00
|
|
|
m_Speed = value;
|
|
|
|
m_Acceleration = value / 5;
|
|
|
|
}
|
|
|
|
|
2022-07-28 13:39:57 +00:00
|
|
|
float MovementAIComponent::GetSpeed() const {
|
2021-12-05 17:54:36 +00:00
|
|
|
return m_Speed;
|
|
|
|
}
|
|
|
|
|
2022-07-28 13:39:57 +00:00
|
|
|
void MovementAIComponent::SetAcceleration(const float value) {
|
2021-12-05 17:54:36 +00:00
|
|
|
m_Acceleration = value;
|
|
|
|
}
|
|
|
|
|
2022-07-28 13:39:57 +00:00
|
|
|
float MovementAIComponent::GetAcceleration() const {
|
2021-12-05 17:54:36 +00:00
|
|
|
return m_Acceleration;
|
|
|
|
}
|
|
|
|
|
2022-07-28 13:39:57 +00:00
|
|
|
void MovementAIComponent::SetHaltDistance(const float value) {
|
2021-12-05 17:54:36 +00:00
|
|
|
m_HaltDistance = value;
|
|
|
|
}
|
|
|
|
|
2022-07-28 13:39:57 +00:00
|
|
|
float MovementAIComponent::GetHaltDistance() const {
|
2021-12-05 17:54:36 +00:00
|
|
|
return m_HaltDistance;
|
|
|
|
}
|
|
|
|
|
2022-07-28 13:39:57 +00:00
|
|
|
void MovementAIComponent::SetCurrentSpeed(float value) {
|
2021-12-05 17:54:36 +00:00
|
|
|
m_CurrentSpeed = value;
|
|
|
|
}
|
|
|
|
|
2022-07-28 13:39:57 +00:00
|
|
|
float MovementAIComponent::GetCurrentSpeed() const {
|
2021-12-05 17:54:36 +00:00
|
|
|
return m_CurrentSpeed;
|
|
|
|
}
|
|
|
|
|
2022-07-28 13:39:57 +00:00
|
|
|
void MovementAIComponent::SetLockRotation(bool value) {
|
2021-12-05 17:54:36 +00:00
|
|
|
m_LockRotation = value;
|
|
|
|
}
|
|
|
|
|
2022-07-28 13:39:57 +00:00
|
|
|
bool MovementAIComponent::GetLockRotation() const {
|
2021-12-05 17:54:36 +00:00
|
|
|
return m_LockRotation;
|
|
|
|
}
|