From 0f8c5b436d4512aa5ca30d3f86d6f3fb122e8251 Mon Sep 17 00:00:00 2001 From: David Markowitz <39972741+EmosewaMC@users.noreply.github.com> Date: Sun, 15 Dec 2024 21:44:57 -0800 Subject: [PATCH] fix: implement enemy clear threat script (#1678) * brother * use some better logic --- dGame/Entity.cpp | 34 ++++-- dGame/Entity.h | 5 + dGame/dComponents/BaseCombatAIComponent.cpp | 105 ++++++++++++------ dGame/dComponents/BaseCombatAIComponent.h | 16 +++ .../ControllablePhysicsComponent.cpp | 2 +- .../ControllablePhysicsComponent.h | 2 +- .../HavokVehiclePhysicsComponent.cpp | 2 +- .../HavokVehiclePhysicsComponent.h | 2 +- dGame/dComponents/PhantomPhysicsComponent.cpp | 2 +- dGame/dComponents/PhantomPhysicsComponent.h | 2 +- dGame/dComponents/PhysicsComponent.cpp | 13 ++- dGame/dComponents/PhysicsComponent.h | 7 +- .../RigidbodyPhantomPhysicsComponent.cpp | 2 +- .../RigidbodyPhantomPhysicsComponent.h | 2 +- dGame/dComponents/SimplePhysicsComponent.cpp | 2 +- dGame/dComponents/SimplePhysicsComponent.h | 2 +- dScripts/02_server/Map/General/CMakeLists.txt | 1 + .../Map/General/EnemyClearThreat.cpp | 25 +++++ .../02_server/Map/General/EnemyClearThreat.h | 11 ++ dScripts/CppScripts.cpp | 24 ++-- 20 files changed, 197 insertions(+), 64 deletions(-) create mode 100644 dScripts/02_server/Map/General/EnemyClearThreat.cpp create mode 100644 dScripts/02_server/Map/General/EnemyClearThreat.h diff --git a/dGame/Entity.cpp b/dGame/Entity.cpp index 59f6e0e08..f5887996d 100644 --- a/dGame/Entity.cpp +++ b/dGame/Entity.cpp @@ -97,6 +97,8 @@ #include "CDSkillBehaviorTable.h" #include "CDZoneTableTable.h" +#include + Observable Entity::OnPlayerPositionUpdate; Entity::Entity(const LWOOBJID& objectID, EntityInfo info, User* parentUser, Entity* parentEntity) { @@ -286,8 +288,9 @@ void Entity::Initialize() { AddComponent(propertyEntranceComponentID); } - if (compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::CONTROLLABLE_PHYSICS) > 0) { - auto* controllablePhysics = AddComponent(); + const int32_t controllablePhysicsComponentID = compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::CONTROLLABLE_PHYSICS); + if (controllablePhysicsComponentID > 0) { + auto* controllablePhysics = AddComponent(controllablePhysicsComponentID); if (m_Character) { controllablePhysics->LoadFromXml(m_Character->GetXMLDoc()); @@ -330,16 +333,19 @@ void Entity::Initialize() { AddComponent(simplePhysicsComponentID); } - if (compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::RIGID_BODY_PHANTOM_PHYSICS) > 0) { - AddComponent(); + const int32_t rigidBodyPhantomPhysicsComponentID = compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::RIGID_BODY_PHANTOM_PHYSICS); + if (rigidBodyPhantomPhysicsComponentID > 0) { + AddComponent(rigidBodyPhantomPhysicsComponentID); } - if (markedAsPhantom || compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::PHANTOM_PHYSICS) > 0) { - AddComponent()->SetPhysicsEffectActive(false); + const int32_t phantomPhysicsComponentID = compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::PHANTOM_PHYSICS); + if (markedAsPhantom || phantomPhysicsComponentID > 0) { + AddComponent(phantomPhysicsComponentID)->SetPhysicsEffectActive(false); } - if (compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::HAVOK_VEHICLE_PHYSICS) > 0) { - auto* havokVehiclePhysicsComponent = AddComponent(); + const int32_t havokVehiclePhysicsComponentID = compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::HAVOK_VEHICLE_PHYSICS); + if (havokVehiclePhysicsComponentID > 0) { + auto* havokVehiclePhysicsComponent = AddComponent(havokVehiclePhysicsComponentID); havokVehiclePhysicsComponent->SetPosition(m_DefaultPosition); havokVehiclePhysicsComponent->SetRotation(m_DefaultRotation); } @@ -2161,7 +2167,19 @@ void Entity::SetRespawnPos(const NiPoint3& position) { auto* characterComponent = GetComponent(); if (characterComponent) characterComponent->SetRespawnPos(position); } + void Entity::SetRespawnRot(const NiQuaternion& rotation) { auto* characterComponent = GetComponent(); if (characterComponent) characterComponent->SetRespawnRot(rotation); } + +int32_t Entity::GetCollisionGroup() const { + for (const auto* component : m_Components | std::views::values) { + auto* compToCheck = dynamic_cast(component); + if (compToCheck) { + return compToCheck->GetCollisionGroup(); + } + } + + return 0; +} diff --git a/dGame/Entity.h b/dGame/Entity.h index 5d2b95272..2ed7aa536 100644 --- a/dGame/Entity.h +++ b/dGame/Entity.h @@ -107,6 +107,11 @@ class Entity { const SystemAddress& GetSystemAddress() const; + // Returns the collision group for this entity. + // Because the collision group is stored on a base component, this will look for a physics component + // then return the collision group from that. + int32_t GetCollisionGroup() const; + /** * Setters */ diff --git a/dGame/dComponents/BaseCombatAIComponent.cpp b/dGame/dComponents/BaseCombatAIComponent.cpp index bfb0bbfa8..fbe5a3825 100644 --- a/dGame/dComponents/BaseCombatAIComponent.cpp +++ b/dGame/dComponents/BaseCombatAIComponent.cpp @@ -16,6 +16,7 @@ #include "DestroyableComponent.h" #include +#include #include #include @@ -27,7 +28,7 @@ #include "CDPhysicsComponentTable.h" #include "dNavMesh.h" -BaseCombatAIComponent::BaseCombatAIComponent(Entity* parent, const uint32_t id): Component(parent) { +BaseCombatAIComponent::BaseCombatAIComponent(Entity* parent, const uint32_t id) : Component(parent) { m_Target = LWOOBJID_EMPTY; m_DirtyStateOrTarget = true; m_State = AiState::spawn; @@ -37,6 +38,7 @@ BaseCombatAIComponent::BaseCombatAIComponent(Entity* parent, const uint32_t id): m_Disabled = false; m_SkillEntries = {}; m_SoftTimer = 5.0f; + m_ForcedTetherTime = 0.0f; //Grab the aggro information from BaseCombatAI: auto componentQuery = CDClientDatabase::CreatePreppedStmt( @@ -170,6 +172,17 @@ void BaseCombatAIComponent::Update(const float deltaTime) { GameMessages::SendStopFXEffect(m_Parent, true, "tether"); m_TetherEffectActive = false; } + m_ForcedTetherTime -= deltaTime; + if (m_ForcedTetherTime >= 0) return; + } + + for (auto entry = m_RemovedThreatList.begin(); entry != m_RemovedThreatList.end();) { + entry->second -= deltaTime; + if (entry->second <= 0.0f) { + entry = m_RemovedThreatList.erase(entry); + } else { + ++entry; + } } if (m_SoftTimer <= 0.0f) { @@ -287,40 +300,7 @@ void BaseCombatAIComponent::CalculateCombat(const float deltaTime) { } if (!m_TetherEffectActive && m_OutOfCombat && (m_OutOfCombatTime -= deltaTime) <= 0) { - auto* destroyableComponent = m_Parent->GetComponent(); - - if (destroyableComponent != nullptr && destroyableComponent->HasFaction(4)) { - auto serilizationRequired = false; - - if (destroyableComponent->GetHealth() != destroyableComponent->GetMaxHealth()) { - destroyableComponent->SetHealth(destroyableComponent->GetMaxHealth()); - - serilizationRequired = true; - } - - if (destroyableComponent->GetArmor() != destroyableComponent->GetMaxArmor()) { - destroyableComponent->SetArmor(destroyableComponent->GetMaxArmor()); - - serilizationRequired = true; - } - - if (serilizationRequired) { - Game::entityManager->SerializeEntity(m_Parent); - } - - GameMessages::SendPlayFXEffect(m_Parent->GetObjectID(), 6270, u"tether", "tether"); - - m_TetherEffectActive = true; - - m_TetherTime = 3.0f; - } - - // Speed towards start position - if (m_MovementAI != nullptr) { - m_MovementAI->SetHaltDistance(0); - m_MovementAI->SetMaxSpeed(m_PursuitSpeed); - m_MovementAI->SetDestination(m_StartPosition); - } + TetherLogic(); m_OutOfCombat = false; m_OutOfCombatTime = 0.0f; @@ -499,7 +479,7 @@ std::vector BaseCombatAIComponent::GetTargetWithinAggroRange() const { const auto distance = Vector3::DistanceSquared(m_Parent->GetPosition(), other->GetPosition()); - if (distance > m_AggroRadius * m_AggroRadius) continue; + if (distance > m_AggroRadius * m_AggroRadius || m_RemovedThreatList.contains(id)) continue; targets.push_back(id); } @@ -626,6 +606,7 @@ const NiPoint3& BaseCombatAIComponent::GetStartPosition() const { void BaseCombatAIComponent::ClearThreat() { m_ThreatEntries.clear(); + m_Target = LWOOBJID_EMPTY; m_DirtyThreat = true; } @@ -806,3 +787,55 @@ void BaseCombatAIComponent::Wake() { m_dpEntity->SetSleeping(false); m_dpEntityEnemy->SetSleeping(false); } + +void BaseCombatAIComponent::TetherLogic() { + auto* destroyableComponent = m_Parent->GetComponent(); + + if (destroyableComponent != nullptr && destroyableComponent->HasFaction(4)) { + auto serilizationRequired = false; + + if (destroyableComponent->GetHealth() != destroyableComponent->GetMaxHealth()) { + destroyableComponent->SetHealth(destroyableComponent->GetMaxHealth()); + + serilizationRequired = true; + } + + if (destroyableComponent->GetArmor() != destroyableComponent->GetMaxArmor()) { + destroyableComponent->SetArmor(destroyableComponent->GetMaxArmor()); + + serilizationRequired = true; + } + + if (serilizationRequired) { + Game::entityManager->SerializeEntity(m_Parent); + } + + GameMessages::SendPlayFXEffect(m_Parent->GetObjectID(), 6270, u"tether", "tether"); + + m_TetherEffectActive = true; + + m_TetherTime = 3.0f; + } + + // Speed towards start position + if (m_MovementAI != nullptr) { + m_MovementAI->SetHaltDistance(0); + m_MovementAI->SetMaxSpeed(m_PursuitSpeed); + m_MovementAI->SetDestination(m_StartPosition); + } +} + +void BaseCombatAIComponent::ForceTether() { + SetTarget(LWOOBJID_EMPTY); + m_ThreatEntries.clear(); + TetherLogic(); + m_ForcedTetherTime = m_TetherTime; + + SetAiState(AiState::aggro); +} + +void BaseCombatAIComponent::IgnoreThreat(const LWOOBJID threat, const float value) { + m_RemovedThreatList[threat] = value; + SetThreat(threat, 0.0f); + m_Target = LWOOBJID_EMPTY; +} diff --git a/dGame/dComponents/BaseCombatAIComponent.h b/dGame/dComponents/BaseCombatAIComponent.h index 89985d647..52adb429e 100644 --- a/dGame/dComponents/BaseCombatAIComponent.h +++ b/dGame/dComponents/BaseCombatAIComponent.h @@ -224,6 +224,16 @@ class BaseCombatAIComponent final : public Component { */ void Wake(); + // Force this entity to tether and ignore all other actions + void ForceTether(); + + // heals the entity to full health and armor + // and tethers them to their spawn point + void TetherLogic(); + + // Ignore a threat for a certain amount of time + void IgnoreThreat(const LWOOBJID target, const float time); + private: /** * Returns the current target or the target that currently is the largest threat to this entity @@ -382,6 +392,12 @@ class BaseCombatAIComponent final : public Component { */ bool m_DirtyStateOrTarget = false; + // The amount of time the entity will be forced to tether for + float m_ForcedTetherTime = 0.0f; + + // The amount of time a removed threat will be ignored for. + std::map m_RemovedThreatList; + /** * Whether the current entity is a mech enemy, needed as mechs tether radius works differently * @return whether this entity is a mech diff --git a/dGame/dComponents/ControllablePhysicsComponent.cpp b/dGame/dComponents/ControllablePhysicsComponent.cpp index 18e4b19d4..1a05020b5 100644 --- a/dGame/dComponents/ControllablePhysicsComponent.cpp +++ b/dGame/dComponents/ControllablePhysicsComponent.cpp @@ -15,7 +15,7 @@ #include "LevelProgressionComponent.h" #include "eStateChangeType.h" -ControllablePhysicsComponent::ControllablePhysicsComponent(Entity* entity) : PhysicsComponent(entity) { +ControllablePhysicsComponent::ControllablePhysicsComponent(Entity* entity, int32_t componentId) : PhysicsComponent(entity, componentId) { m_Velocity = {}; m_AngularVelocity = {}; m_InJetpackMode = false; diff --git a/dGame/dComponents/ControllablePhysicsComponent.h b/dGame/dComponents/ControllablePhysicsComponent.h index 6309b8fc3..31a6bb301 100644 --- a/dGame/dComponents/ControllablePhysicsComponent.h +++ b/dGame/dComponents/ControllablePhysicsComponent.h @@ -23,7 +23,7 @@ class ControllablePhysicsComponent : public PhysicsComponent { public: static constexpr eReplicaComponentType ComponentType = eReplicaComponentType::CONTROLLABLE_PHYSICS; - ControllablePhysicsComponent(Entity* entity); + ControllablePhysicsComponent(Entity* entity, int32_t componentId); ~ControllablePhysicsComponent() override; void Update(float deltaTime) override; diff --git a/dGame/dComponents/HavokVehiclePhysicsComponent.cpp b/dGame/dComponents/HavokVehiclePhysicsComponent.cpp index 635830cc5..e977f952d 100644 --- a/dGame/dComponents/HavokVehiclePhysicsComponent.cpp +++ b/dGame/dComponents/HavokVehiclePhysicsComponent.cpp @@ -1,7 +1,7 @@ #include "HavokVehiclePhysicsComponent.h" #include "EntityManager.h" -HavokVehiclePhysicsComponent::HavokVehiclePhysicsComponent(Entity* parent) : PhysicsComponent(parent) { +HavokVehiclePhysicsComponent::HavokVehiclePhysicsComponent(Entity* parent, int32_t componentId) : PhysicsComponent(parent, componentId) { m_Velocity = NiPoint3Constant::ZERO; m_AngularVelocity = NiPoint3Constant::ZERO; m_IsOnGround = true; diff --git a/dGame/dComponents/HavokVehiclePhysicsComponent.h b/dGame/dComponents/HavokVehiclePhysicsComponent.h index 83eb82fe6..ad6087a7d 100644 --- a/dGame/dComponents/HavokVehiclePhysicsComponent.h +++ b/dGame/dComponents/HavokVehiclePhysicsComponent.h @@ -13,7 +13,7 @@ class HavokVehiclePhysicsComponent : public PhysicsComponent { public: static constexpr eReplicaComponentType ComponentType = eReplicaComponentType::HAVOK_VEHICLE_PHYSICS; - HavokVehiclePhysicsComponent(Entity* parentEntity); + HavokVehiclePhysicsComponent(Entity* parentEntity, int32_t componentId); void Serialize(RakNet::BitStream& outBitStream, bool bIsInitialUpdate) override; diff --git a/dGame/dComponents/PhantomPhysicsComponent.cpp b/dGame/dComponents/PhantomPhysicsComponent.cpp index 95fed36e6..be7fe7746 100644 --- a/dGame/dComponents/PhantomPhysicsComponent.cpp +++ b/dGame/dComponents/PhantomPhysicsComponent.cpp @@ -27,7 +27,7 @@ #include "dpShapeBox.h" #include "dpShapeSphere.h" -PhantomPhysicsComponent::PhantomPhysicsComponent(Entity* parent) : PhysicsComponent(parent) { +PhantomPhysicsComponent::PhantomPhysicsComponent(Entity* parent, int32_t componentId) : PhysicsComponent(parent, componentId) { m_Position = m_Parent->GetDefaultPosition(); m_Rotation = m_Parent->GetDefaultRotation(); m_Scale = m_Parent->GetDefaultScale(); diff --git a/dGame/dComponents/PhantomPhysicsComponent.h b/dGame/dComponents/PhantomPhysicsComponent.h index 89cfb857c..cd54587be 100644 --- a/dGame/dComponents/PhantomPhysicsComponent.h +++ b/dGame/dComponents/PhantomPhysicsComponent.h @@ -30,7 +30,7 @@ class PhantomPhysicsComponent final : public PhysicsComponent { public: static constexpr eReplicaComponentType ComponentType = eReplicaComponentType::PHANTOM_PHYSICS; - PhantomPhysicsComponent(Entity* parent); + PhantomPhysicsComponent(Entity* parent, int32_t componentId); ~PhantomPhysicsComponent() override; void Update(float deltaTime) override; void Serialize(RakNet::BitStream& outBitStream, bool bIsInitialUpdate) override; diff --git a/dGame/dComponents/PhysicsComponent.cpp b/dGame/dComponents/PhysicsComponent.cpp index 4a250a6a9..67fca8d9a 100644 --- a/dGame/dComponents/PhysicsComponent.cpp +++ b/dGame/dComponents/PhysicsComponent.cpp @@ -14,10 +14,21 @@ #include "EntityInfo.h" -PhysicsComponent::PhysicsComponent(Entity* parent) : Component(parent) { +PhysicsComponent::PhysicsComponent(Entity* parent, int32_t componentId) : Component(parent) { m_Position = NiPoint3Constant::ZERO; m_Rotation = NiQuaternionConstant::IDENTITY; m_DirtyPosition = false; + + CDPhysicsComponentTable* physicsComponentTable = CDClientManager::GetTable(); + + if (physicsComponentTable) { + auto* info = physicsComponentTable->GetByID(componentId); + if (info) { + m_CollisionGroup = info->collisionGroup; + } + } + + if (m_Parent->HasVar(u"CollisionGroupID")) m_CollisionGroup = m_Parent->GetVar(u"CollisionGroupID"); } void PhysicsComponent::Serialize(RakNet::BitStream& outBitStream, bool bIsInitialUpdate) { diff --git a/dGame/dComponents/PhysicsComponent.h b/dGame/dComponents/PhysicsComponent.h index 4bf0828a0..41a4b9d15 100644 --- a/dGame/dComponents/PhysicsComponent.h +++ b/dGame/dComponents/PhysicsComponent.h @@ -15,7 +15,7 @@ class dpEntity; class PhysicsComponent : public Component { public: - PhysicsComponent(Entity* parent); + PhysicsComponent(Entity* parent, int32_t componentId); virtual ~PhysicsComponent() = default; void Serialize(RakNet::BitStream& outBitStream, bool bIsInitialUpdate) override; @@ -25,6 +25,9 @@ class PhysicsComponent : public Component { const NiQuaternion& GetRotation() const { return m_Rotation; } virtual void SetRotation(const NiQuaternion& rot) { if (m_Rotation == rot) return; m_Rotation = rot; m_DirtyPosition = true; } + + int32_t GetCollisionGroup() const noexcept { return m_CollisionGroup; } + void SetCollisionGroup(int32_t group) noexcept { m_CollisionGroup = group; } protected: dpEntity* CreatePhysicsEntity(eReplicaComponentType type); @@ -37,6 +40,8 @@ class PhysicsComponent : public Component { NiQuaternion m_Rotation; bool m_DirtyPosition; + + int32_t m_CollisionGroup{}; }; #endif //!__PHYSICSCOMPONENT__H__ diff --git a/dGame/dComponents/RigidbodyPhantomPhysicsComponent.cpp b/dGame/dComponents/RigidbodyPhantomPhysicsComponent.cpp index df81aab36..d0f8caeb2 100644 --- a/dGame/dComponents/RigidbodyPhantomPhysicsComponent.cpp +++ b/dGame/dComponents/RigidbodyPhantomPhysicsComponent.cpp @@ -12,7 +12,7 @@ #include "dpShapeSphere.h" #include"EntityInfo.h" -RigidbodyPhantomPhysicsComponent::RigidbodyPhantomPhysicsComponent(Entity* parent) : PhysicsComponent(parent) { +RigidbodyPhantomPhysicsComponent::RigidbodyPhantomPhysicsComponent(Entity* parent, int32_t componentId) : PhysicsComponent(parent, componentId) { m_Position = m_Parent->GetDefaultPosition(); m_Rotation = m_Parent->GetDefaultRotation(); m_Scale = m_Parent->GetDefaultScale(); diff --git a/dGame/dComponents/RigidbodyPhantomPhysicsComponent.h b/dGame/dComponents/RigidbodyPhantomPhysicsComponent.h index 11595ec03..e7ce93d64 100644 --- a/dGame/dComponents/RigidbodyPhantomPhysicsComponent.h +++ b/dGame/dComponents/RigidbodyPhantomPhysicsComponent.h @@ -21,7 +21,7 @@ class RigidbodyPhantomPhysicsComponent : public PhysicsComponent { public: static constexpr eReplicaComponentType ComponentType = eReplicaComponentType::RIGID_BODY_PHANTOM_PHYSICS; - RigidbodyPhantomPhysicsComponent(Entity* parent); + RigidbodyPhantomPhysicsComponent(Entity* parent, int32_t componentId); void Update(const float deltaTime) override; diff --git a/dGame/dComponents/SimplePhysicsComponent.cpp b/dGame/dComponents/SimplePhysicsComponent.cpp index 6bc2e2bc9..825570f2d 100644 --- a/dGame/dComponents/SimplePhysicsComponent.cpp +++ b/dGame/dComponents/SimplePhysicsComponent.cpp @@ -13,7 +13,7 @@ #include "Entity.h" -SimplePhysicsComponent::SimplePhysicsComponent(Entity* parent, uint32_t componentID) : PhysicsComponent(parent) { +SimplePhysicsComponent::SimplePhysicsComponent(Entity* parent, int32_t componentID) : PhysicsComponent(parent, componentID) { m_Position = m_Parent->GetDefaultPosition(); m_Rotation = m_Parent->GetDefaultRotation(); diff --git a/dGame/dComponents/SimplePhysicsComponent.h b/dGame/dComponents/SimplePhysicsComponent.h index b4491e127..61362712d 100644 --- a/dGame/dComponents/SimplePhysicsComponent.h +++ b/dGame/dComponents/SimplePhysicsComponent.h @@ -30,7 +30,7 @@ class SimplePhysicsComponent : public PhysicsComponent { public: static constexpr eReplicaComponentType ComponentType = eReplicaComponentType::SIMPLE_PHYSICS; - SimplePhysicsComponent(Entity* parent, uint32_t componentID); + SimplePhysicsComponent(Entity* parent, int32_t componentID); ~SimplePhysicsComponent() override; void Serialize(RakNet::BitStream& outBitStream, bool bIsInitialUpdate) override; diff --git a/dScripts/02_server/Map/General/CMakeLists.txt b/dScripts/02_server/Map/General/CMakeLists.txt index 3379e5b00..dc32d53c5 100644 --- a/dScripts/02_server/Map/General/CMakeLists.txt +++ b/dScripts/02_server/Map/General/CMakeLists.txt @@ -2,6 +2,7 @@ set(DSCRIPTS_SOURCES_02_SERVER_MAP_GENERAL "BankInteractServer.cpp" "BaseInteractDropLootServer.cpp" "Binoculars.cpp" + "EnemyClearThreat.cpp" "ExplodingAsset.cpp" "FrictionVolumeServer.cpp" "ForceVolumeServer.cpp" diff --git a/dScripts/02_server/Map/General/EnemyClearThreat.cpp b/dScripts/02_server/Map/General/EnemyClearThreat.cpp new file mode 100644 index 000000000..b026899c3 --- /dev/null +++ b/dScripts/02_server/Map/General/EnemyClearThreat.cpp @@ -0,0 +1,25 @@ +#include "EnemyClearThreat.h" + +#include "BaseCombatAIComponent.h" +#include "PhysicsComponent.h" + +void EnemyClearThreat::OnCollisionPhantom(Entity* self, Entity* target) { + if (!target) return; + + const auto colGroup = target->GetCollisionGroup(); + if (colGroup == 12) { // enemy + auto* const baseCombatAiComponent = target->GetComponent(); + if (!baseCombatAiComponent) return; + + baseCombatAiComponent->ClearThreat(); + baseCombatAiComponent->ForceTether(); + } else if (colGroup == 10) { // player + const auto enemies = Game::entityManager->GetEntitiesByComponent(eReplicaComponentType::BASE_COMBAT_AI); + for (const auto& enemy : enemies) { + auto* const baseCombatAiComponent = enemy->GetComponent(); + if (!baseCombatAiComponent) continue; + + baseCombatAiComponent->IgnoreThreat(target->GetObjectID(), 3.0f); + } + } +} diff --git a/dScripts/02_server/Map/General/EnemyClearThreat.h b/dScripts/02_server/Map/General/EnemyClearThreat.h new file mode 100644 index 000000000..97cce4268 --- /dev/null +++ b/dScripts/02_server/Map/General/EnemyClearThreat.h @@ -0,0 +1,11 @@ +#ifndef ENEMYCLEARTHREAT_H +#define ENEMYCLEARTHREAT_H + +#include "CppScripts.h" + +class EnemyClearThreat : public CppScripts::Script { +public: + void OnCollisionPhantom(Entity* self, Entity* target) override; +}; + +#endif //!ENEMYCLEARTHREAT_H diff --git a/dScripts/CppScripts.cpp b/dScripts/CppScripts.cpp index ed0de2ba3..e3b3acdbd 100644 --- a/dScripts/CppScripts.cpp +++ b/dScripts/CppScripts.cpp @@ -327,6 +327,7 @@ #include "VisToggleNotifierServer.h" #include "LupGenericInteract.h" #include "WblRobotCitizen.h" +#include "EnemyClearThreat.h" #include #include @@ -686,8 +687,21 @@ namespace { {"scripts\\zone\\LUPs\\RobotCity Intro\\WBL_RCIntro_RobotCitizenOrange.lua", []() {return new WblRobotCitizen();}}, {"scripts\\zone\\LUPs\\RobotCity Intro\\WBL_RCIntro_RobotCitizenRed.lua", []() {return new WblRobotCitizen();}}, {"scripts\\zone\\LUPs\\RobotCity Intro\\WBL_RCIntro_RobotCitizenYellow.lua", []() {return new WblRobotCitizen();}}, + {"scripts\\02_server\\Map\\General\\L_ENEMY_CLEAR_THREAT.lua", []() {return new EnemyClearThreat();}}, }; + + std::set g_ExcludedScripts = { + "scripts\\02_server\\Enemy\\General\\L_SUSPEND_LUA_AI.lua", + "scripts\\02_server\\Enemy\\General\\L_BASE_ENEMY_SPIDERLING.lua", + "scripts\\ai\\AG\\L_AG_SENTINEL_GUARD.lua", + "scripts\\ai\\FV\\L_ACT_NINJA_STUDENT.lua", + "scripts\\ai\\WILD\\L_WILD_GF_FROG.lua", + "scripts\\empty.lua", + "scripts\\zone\\AG\\L_ZONE_AG.lua", + "scripts\\zone\\NS\\L_ZONE_NS.lua", + "scripts\\zone\\GF\\L_ZONE_GF.lua", + }; }; CppScripts::Script* const CppScripts::GetScript(Entity* parent, const std::string& scriptName) { @@ -699,14 +713,8 @@ CppScripts::Script* const CppScripts::GetScript(Entity* parent, const std::strin const auto itrTernary = scriptLoader.find(scriptName); Script* script = itrTernary != scriptLoader.cend() ? itrTernary->second() : &InvalidToReturn; - if (script == &InvalidToReturn) { - if ((scriptName.length() > 0) && !((scriptName == "scripts\\02_server\\Enemy\\General\\L_SUSPEND_LUA_AI.lua") || - (scriptName == "scripts\\02_server\\Enemy\\General\\L_BASE_ENEMY_SPIDERLING.lua") || - (scriptName == "scripts\\ai\\FV\\L_ACT_NINJA_STUDENT.lua") || - (scriptName == "scripts\\ai\\WILD\\L_WILD_GF_FROG.lua") || - (scriptName == "scripts\\empty.lua") || - (scriptName == "scripts\\ai\\AG\\L_AG_SENTINEL_GUARD.lua") - )) LOG_DEBUG("LOT %i attempted to load CppScript for '%s', but returned InvalidScript.", parent->GetLOT(), scriptName.c_str()); + if (script == &InvalidToReturn && !scriptName.empty() && !g_ExcludedScripts.contains(scriptName)) { + LOG_DEBUG("LOT %i attempted to load CppScript for '%s', but returned InvalidScript.", parent->GetLOT(), scriptName.c_str()); } g_Scripts[scriptName] = script;