2023-08-08 01:40:06 +00:00
|
|
|
#ifndef MOVEMENTAICOMPONENT_H
|
|
|
|
#include "MovementAIComponent.h"
|
|
|
|
#endif
|
2023-08-10 02:37:36 +00:00
|
|
|
#include "eWaypointCommandType.h"
|
2023-08-12 05:40:48 +00:00
|
|
|
#include "RenderComponent.h"
|
|
|
|
#include "SkillComponent.h"
|
2023-08-14 14:31:10 +00:00
|
|
|
#include "InventoryComponent.h"
|
|
|
|
#include "Zone.h"
|
|
|
|
#include "EntityInfo.h"
|
|
|
|
#include "ProximityMonitorComponent.h"
|
|
|
|
#include "DestroyableComponent.h"
|
2023-08-08 01:40:06 +00:00
|
|
|
|
2023-08-14 14:31:10 +00:00
|
|
|
void MovementAIComponent::HandleWaypointArrived(uint32_t commandIndex) {
|
2023-08-21 19:33:13 +00:00
|
|
|
if (!m_Path || commandIndex >= m_Path->pathWaypoints.at(m_CurrentPathWaypointIndex).commands.size()) {
|
|
|
|
if (!AdvancePathWaypointIndex()) {
|
|
|
|
if (m_Path) {
|
|
|
|
if (m_Path->pathBehavior == PathBehavior::Bounce) {
|
|
|
|
ReversePath();
|
|
|
|
} else if (m_Path->pathBehavior == PathBehavior::Loop) {
|
|
|
|
m_CurrentPathWaypointIndex = 0;
|
|
|
|
m_NextPathWaypointIndex = 0;
|
|
|
|
AdvancePathWaypointIndex();
|
|
|
|
SetDestination(GetCurrentPathWaypoint());
|
|
|
|
SetMaxSpeed(GetCurrentPathWaypointSpeed());
|
|
|
|
} else {
|
|
|
|
Stop();
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
Stop();
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
SetDestination(GetCurrentPathWaypoint());
|
|
|
|
SetMaxSpeed(GetCurrentPathWaypointSpeed());
|
2023-08-14 14:31:10 +00:00
|
|
|
return;
|
|
|
|
}
|
2023-08-21 19:33:13 +00:00
|
|
|
if (!IsPaused()) Pause();
|
2023-08-14 14:31:10 +00:00
|
|
|
const auto& data = m_Path->pathWaypoints.at(m_CurrentPathWaypointIndex).commands.at(commandIndex).data;
|
|
|
|
const auto& command = m_Path->pathWaypoints.at(m_CurrentPathWaypointIndex).commands.at(commandIndex).command;
|
|
|
|
float delay = 0.0f;
|
2023-08-21 19:33:13 +00:00
|
|
|
switch (command) {
|
|
|
|
case eWaypointCommandType::STOP:
|
|
|
|
Stop();
|
|
|
|
break;
|
|
|
|
case eWaypointCommandType::GROUP_EMOTE:
|
|
|
|
delay = HandleWaypointCommandGroupEmote(data);
|
|
|
|
break;
|
|
|
|
case eWaypointCommandType::SET_VARIABLE:
|
|
|
|
HandleWaypointCommandSetVariable(data);
|
|
|
|
break;
|
|
|
|
case eWaypointCommandType::CAST_SKILL:
|
|
|
|
HandleWaypointCommandCastSkill(data);
|
|
|
|
break;
|
|
|
|
case eWaypointCommandType::EQUIP_INVENTORY:
|
|
|
|
HandleWaypointCommandEquipInventory(data);
|
|
|
|
break;
|
|
|
|
case eWaypointCommandType::UNEQUIP_INVENTORY:
|
|
|
|
HandleWaypointCommandUnequipInventory(data);
|
|
|
|
break;
|
|
|
|
case eWaypointCommandType::DELAY:
|
|
|
|
delay = HandleWaypointCommandDelay(data);
|
|
|
|
break;
|
|
|
|
case eWaypointCommandType::EMOTE:
|
|
|
|
delay = RenderComponent::PlayAnimation(m_Parent, data);
|
|
|
|
break;
|
|
|
|
case eWaypointCommandType::TELEPORT:
|
|
|
|
HandleWaypointCommandTeleport(data);
|
|
|
|
break;
|
|
|
|
case eWaypointCommandType::PATH_SPEED:
|
|
|
|
HandleWaypointCommandPathSpeed(data);
|
|
|
|
break;
|
|
|
|
case eWaypointCommandType::REMOVE_NPC:
|
|
|
|
HandleWaypointCommandRemoveNPC(data);
|
|
|
|
break;
|
|
|
|
case eWaypointCommandType::CHANGE_WAYPOINT:
|
|
|
|
HandleWaypointCommandChangeWaypoint(data);
|
|
|
|
break;
|
|
|
|
case eWaypointCommandType::KILL_SELF:
|
|
|
|
m_Parent->Smash(LWOOBJID_EMPTY, eKillType::SILENT);
|
|
|
|
break;
|
|
|
|
case eWaypointCommandType::DELETE_SELF:
|
|
|
|
m_Parent->Kill();
|
|
|
|
break;
|
|
|
|
case eWaypointCommandType::SPAWN_OBJECT:
|
|
|
|
HandleWaypointCommandSpawnObject(data);
|
|
|
|
break;
|
|
|
|
case eWaypointCommandType::PLAY_SOUND:
|
|
|
|
GameMessages::SendPlayNDAudioEmitter(m_Parent, UNASSIGNED_SYSTEM_ADDRESS, data);
|
|
|
|
break;
|
|
|
|
case eWaypointCommandType::BOUNCE:
|
|
|
|
Game::logger->LogDebug("MovementAIComponent", "Unable to process bounce waypoint command server side!");
|
|
|
|
break;
|
|
|
|
case eWaypointCommandType::INVALID:
|
|
|
|
default:
|
|
|
|
Game::logger->LogDebug("MovementAIComponent", "Got invalid waypoint command %i", command);
|
|
|
|
break;
|
2023-08-10 02:37:36 +00:00
|
|
|
}
|
2023-08-14 14:31:10 +00:00
|
|
|
|
2023-08-21 19:33:13 +00:00
|
|
|
m_Parent->AddCallbackTimer(delay, [this, commandIndex]() {
|
2023-08-15 14:47:45 +00:00
|
|
|
this->HandleWaypointArrived(commandIndex + 1);
|
2023-08-14 14:31:10 +00:00
|
|
|
}
|
|
|
|
);
|
2023-08-08 01:40:06 +00:00
|
|
|
}
|
2023-08-12 05:40:48 +00:00
|
|
|
|
2023-08-14 14:31:10 +00:00
|
|
|
float MovementAIComponent::HandleWaypointCommandGroupEmote(const std::string& data) {
|
2023-08-12 05:40:48 +00:00
|
|
|
const auto& split = GeneralUtils::SplitString(data, ';');
|
2023-08-14 14:31:10 +00:00
|
|
|
if (split.size() != 2) return 0.0f;
|
|
|
|
const auto& entities = Game::entityManager->GetEntitiesInGroup(split.at(0));
|
|
|
|
float delay = 0.0f;
|
2023-08-21 19:33:13 +00:00
|
|
|
for (auto& entity : entities) {
|
2023-08-14 14:31:10 +00:00
|
|
|
delay = RenderComponent::PlayAnimation(entity, split.at(1));
|
2023-08-12 05:40:48 +00:00
|
|
|
}
|
2023-08-14 14:31:10 +00:00
|
|
|
return delay;
|
2023-08-12 05:40:48 +00:00
|
|
|
}
|
2023-08-14 14:31:10 +00:00
|
|
|
|
|
|
|
void MovementAIComponent::HandleWaypointCommandSetVariable(const std::string& data) {
|
|
|
|
const auto& split = GeneralUtils::SplitString(data, ',');
|
|
|
|
m_Parent->SetNetworkVar(GeneralUtils::ASCIIToUTF16(split.at(0)), split.at(1));
|
2023-08-12 05:40:48 +00:00
|
|
|
}
|
2023-08-14 14:31:10 +00:00
|
|
|
|
|
|
|
void MovementAIComponent::HandleWaypointCommandCastSkill(const std::string& data) {
|
2023-08-12 05:40:48 +00:00
|
|
|
if (data.empty()) return;
|
|
|
|
auto* skillComponent = m_Parent->GetComponent<SkillComponent>();
|
|
|
|
if (!skillComponent) {
|
2023-08-14 14:31:10 +00:00
|
|
|
Game::logger->LogDebug("MovementAIComponent::HandleWaypointCommandCastSkill", "Skill component not found!");
|
2023-08-12 05:40:48 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
uint32_t skillId = 0;
|
2023-08-20 05:13:01 +00:00
|
|
|
if (!GeneralUtils::TryParse<uint32_t>(data, skillId)) return;
|
2023-08-12 05:40:48 +00:00
|
|
|
if (skillId != 0) skillComponent->CastSkill(skillId);
|
2023-08-14 14:31:10 +00:00
|
|
|
return;
|
2023-08-12 05:40:48 +00:00
|
|
|
}
|
2023-08-14 14:31:10 +00:00
|
|
|
|
|
|
|
void MovementAIComponent::HandleWaypointCommandEquipInventory(const std::string& data) {
|
|
|
|
if (data.empty()) return;
|
|
|
|
auto* inventoryComponent = m_Parent->GetComponent<InventoryComponent>();
|
|
|
|
if (!inventoryComponent) {
|
|
|
|
Game::logger->LogDebug("MovementAIComponent::HandleWaypointCommandEquipInventory", "Inventory component not found!");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
// the client says use slot 0 of items
|
|
|
|
const auto inventory = inventoryComponent->GetInventory(eInventoryType::ITEMS);
|
|
|
|
if (!inventory) return;
|
|
|
|
const auto slots = inventory->GetSlots();
|
|
|
|
const auto item = slots.find(0);
|
|
|
|
if (item != slots.end()) inventoryComponent->EquipItem(item->second);
|
2023-08-12 05:40:48 +00:00
|
|
|
}
|
2023-08-14 14:31:10 +00:00
|
|
|
|
|
|
|
void MovementAIComponent::HandleWaypointCommandUnequipInventory(const std::string& data) {
|
|
|
|
if (data.empty()) return;
|
|
|
|
auto* inventoryComponent = m_Parent->GetComponent<InventoryComponent>();
|
|
|
|
if (!inventoryComponent) {
|
|
|
|
Game::logger->LogDebug("MovementAIComponent::HandleWaypointCommandEquipInventory", "Inventory component not found!");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
// the client says use slot 0 of items
|
|
|
|
const auto inventory = inventoryComponent->GetInventory(eInventoryType::ITEMS);
|
|
|
|
if (!inventory) return;
|
|
|
|
const auto slots = inventory->GetSlots();
|
|
|
|
const auto item = slots.find(0);
|
|
|
|
if (item != slots.end()) inventoryComponent->UnEquipItem(item->second);
|
2023-08-12 05:40:48 +00:00
|
|
|
}
|
2023-08-14 14:31:10 +00:00
|
|
|
|
|
|
|
float MovementAIComponent::HandleWaypointCommandDelay(const std::string& data) {
|
|
|
|
float delay = 0.0f;
|
|
|
|
std::string delayString = data;
|
2023-08-21 19:33:13 +00:00
|
|
|
if (!GeneralUtils::TryParse<float>(delayString, delay)) {
|
2023-08-20 05:36:28 +00:00
|
|
|
Game::logger->LogDebug("MovementAIComponentAronwk", "Failed to parse delay %s", data.c_str());
|
|
|
|
}
|
2023-08-14 14:31:10 +00:00
|
|
|
return delay;
|
2023-08-12 05:40:48 +00:00
|
|
|
}
|
2023-08-14 14:31:10 +00:00
|
|
|
|
|
|
|
void MovementAIComponent::HandleWaypointCommandTeleport(const std::string& data) {
|
2023-08-12 05:40:48 +00:00
|
|
|
auto posString = GeneralUtils::SplitString(data, ',');
|
|
|
|
if (posString.size() == 0) return;
|
|
|
|
auto newPos = NiPoint3();
|
2023-08-14 14:31:10 +00:00
|
|
|
if (posString.size() == 1 && !GeneralUtils::TryParse<float>(posString.at(0), newPos.x)) return;
|
|
|
|
if (posString.size() == 2 && !GeneralUtils::TryParse<float>(posString.at(1), newPos.y)) return;
|
|
|
|
if (posString.size() == 3 && !GeneralUtils::TryParse<float>(posString.at(2), newPos.z)) return;
|
2023-08-12 05:40:48 +00:00
|
|
|
GameMessages::SendTeleport(m_Parent->GetObjectID(), newPos, NiQuaternion::IDENTITY, UNASSIGNED_SYSTEM_ADDRESS);
|
|
|
|
}
|
2023-08-14 14:31:10 +00:00
|
|
|
|
|
|
|
void MovementAIComponent::HandleWaypointCommandPathSpeed(const std::string& data) {
|
2023-08-12 05:40:48 +00:00
|
|
|
float speed = 0.0;
|
2023-08-20 05:13:01 +00:00
|
|
|
if (!GeneralUtils::TryParse<float>(data, speed)) return;
|
2023-08-14 14:31:10 +00:00
|
|
|
SetCurrentSpeed(speed);
|
2023-08-12 05:40:48 +00:00
|
|
|
}
|
2023-08-14 14:31:10 +00:00
|
|
|
|
|
|
|
void MovementAIComponent::HandleWaypointCommandRemoveNPC(const std::string& data) {
|
|
|
|
if (data.empty()) return;
|
|
|
|
auto* proximityMonitorComponent = m_Parent->GetComponent<ProximityMonitorComponent>();
|
|
|
|
if (!proximityMonitorComponent) {
|
|
|
|
Game::logger->LogDebug("MovementAIComponent::HandleWaypointCommandRemoveNPC", "Proximity monitor component not found!");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
const auto foundObjs = proximityMonitorComponent->GetProximityObjects("KillOBJS");
|
2023-08-21 19:33:13 +00:00
|
|
|
for (auto& [objid, phyEntity] : foundObjs) {
|
2023-08-14 14:31:10 +00:00
|
|
|
auto entity = Game::entityManager->GetEntity(objid);
|
|
|
|
if (!entity) return;
|
|
|
|
auto* destroyableComponent = m_Parent->GetComponent<DestroyableComponent>();
|
|
|
|
if (!destroyableComponent) {
|
|
|
|
Game::logger->LogDebug("MovementAIComponent::HandleWaypointCommandRemoveNPC", "Destroyable component not found!");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
uint32_t factionID = -1;
|
2023-08-20 05:13:01 +00:00
|
|
|
if (!GeneralUtils::TryParse<uint32_t>(data, factionID)) return;
|
2023-08-14 14:31:10 +00:00
|
|
|
if (destroyableComponent->BelongsToFaction(factionID)) m_Parent->Kill();
|
|
|
|
}
|
2023-08-12 05:40:48 +00:00
|
|
|
}
|
2023-08-14 14:31:10 +00:00
|
|
|
|
|
|
|
void MovementAIComponent::HandleWaypointCommandChangeWaypoint(const std::string& data) {
|
2023-08-12 05:40:48 +00:00
|
|
|
std::string path_string = "";
|
|
|
|
int32_t index = 0;
|
|
|
|
// sometimes there's a path and what waypoint to start, which are comma separated
|
2023-08-21 19:33:13 +00:00
|
|
|
if (data.find(",") != std::string::npos) {
|
2023-08-12 05:40:48 +00:00
|
|
|
auto datas = GeneralUtils::SplitString(data, ',');
|
2023-08-14 14:31:10 +00:00
|
|
|
path_string = datas.at(0);
|
2023-08-20 05:13:01 +00:00
|
|
|
if (!GeneralUtils::TryParse(datas.at(1), index)) return;
|
2023-08-12 05:40:48 +00:00
|
|
|
} else path_string = data;
|
|
|
|
|
|
|
|
if (path_string != "") {
|
2023-08-15 14:47:45 +00:00
|
|
|
SetPathStartingWaypointIndex(index);
|
2023-08-12 05:40:48 +00:00
|
|
|
SetupPath(path_string);
|
|
|
|
}
|
|
|
|
}
|
2023-08-14 14:31:10 +00:00
|
|
|
|
|
|
|
void MovementAIComponent::HandleWaypointCommandSpawnObject(const std::string& data) {
|
|
|
|
LOT newObjectLOT = 0;
|
2023-08-20 05:13:01 +00:00
|
|
|
if (!GeneralUtils::TryParse(data, newObjectLOT)) return;
|
2023-08-14 14:31:10 +00:00
|
|
|
EntityInfo info{};
|
|
|
|
info.lot = newObjectLOT;
|
|
|
|
info.pos = m_Parent->GetPosition();
|
|
|
|
info.rot = m_Parent->GetRotation();
|
|
|
|
auto* spawnedEntity = Game::entityManager->CreateEntity(info, nullptr, m_Parent);
|
|
|
|
Game::entityManager->ConstructEntity(spawnedEntity);
|
|
|
|
m_Parent->Smash(LWOOBJID_EMPTY, eKillType::SILENT);
|
2023-08-12 05:40:48 +00:00
|
|
|
}
|