mirror of
https://github.com/DarkflameUniverse/DarkflameServer.git
synced 2025-01-08 22:07:10 +00:00
Merge branch 'main' of https://github.com/DarkflameUniverse/DarkflameServer into ecs-experiment
This commit is contained in:
commit
179f0cf32d
@ -97,6 +97,8 @@
|
|||||||
#include "CDSkillBehaviorTable.h"
|
#include "CDSkillBehaviorTable.h"
|
||||||
#include "CDZoneTableTable.h"
|
#include "CDZoneTableTable.h"
|
||||||
|
|
||||||
|
#include <ranges>
|
||||||
|
|
||||||
Observable<Entity*, const PositionUpdate&> Entity::OnPlayerPositionUpdate;
|
Observable<Entity*, const PositionUpdate&> Entity::OnPlayerPositionUpdate;
|
||||||
|
|
||||||
Entity::Entity(const LWOOBJID& objectID, EntityInfo info, User* parentUser, Entity* parentEntity) {
|
Entity::Entity(const LWOOBJID& objectID, EntityInfo info, User* parentUser, Entity* parentEntity) {
|
||||||
@ -286,8 +288,9 @@ void Entity::Initialize() {
|
|||||||
AddComponent<PropertyEntranceComponent>(propertyEntranceComponentID);
|
AddComponent<PropertyEntranceComponent>(propertyEntranceComponentID);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::CONTROLLABLE_PHYSICS) > 0) {
|
const int32_t controllablePhysicsComponentID = compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::CONTROLLABLE_PHYSICS);
|
||||||
auto* controllablePhysics = AddComponent<ControllablePhysicsComponent>();
|
if (controllablePhysicsComponentID > 0) {
|
||||||
|
auto* controllablePhysics = AddComponent<ControllablePhysicsComponent>(controllablePhysicsComponentID);
|
||||||
|
|
||||||
if (m_Character) {
|
if (m_Character) {
|
||||||
controllablePhysics->LoadFromXml(m_Character->GetXMLDoc());
|
controllablePhysics->LoadFromXml(m_Character->GetXMLDoc());
|
||||||
@ -330,16 +333,19 @@ void Entity::Initialize() {
|
|||||||
AddComponent<SimplePhysicsComponent>(simplePhysicsComponentID);
|
AddComponent<SimplePhysicsComponent>(simplePhysicsComponentID);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::RIGID_BODY_PHANTOM_PHYSICS) > 0) {
|
const int32_t rigidBodyPhantomPhysicsComponentID = compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::RIGID_BODY_PHANTOM_PHYSICS);
|
||||||
AddComponent<RigidbodyPhantomPhysicsComponent>();
|
if (rigidBodyPhantomPhysicsComponentID > 0) {
|
||||||
|
AddComponent<RigidbodyPhantomPhysicsComponent>(rigidBodyPhantomPhysicsComponentID);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (markedAsPhantom || compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::PHANTOM_PHYSICS) > 0) {
|
const int32_t phantomPhysicsComponentID = compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::PHANTOM_PHYSICS);
|
||||||
AddComponent<PhantomPhysicsComponent>()->SetPhysicsEffectActive(false);
|
if (markedAsPhantom || phantomPhysicsComponentID > 0) {
|
||||||
|
AddComponent<PhantomPhysicsComponent>(phantomPhysicsComponentID)->SetPhysicsEffectActive(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::HAVOK_VEHICLE_PHYSICS) > 0) {
|
const int32_t havokVehiclePhysicsComponentID = compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::HAVOK_VEHICLE_PHYSICS);
|
||||||
auto* havokVehiclePhysicsComponent = AddComponent<HavokVehiclePhysicsComponent>();
|
if (havokVehiclePhysicsComponentID > 0) {
|
||||||
|
auto* havokVehiclePhysicsComponent = AddComponent<HavokVehiclePhysicsComponent>(havokVehiclePhysicsComponentID);
|
||||||
havokVehiclePhysicsComponent->SetPosition(m_DefaultPosition);
|
havokVehiclePhysicsComponent->SetPosition(m_DefaultPosition);
|
||||||
havokVehiclePhysicsComponent->SetRotation(m_DefaultRotation);
|
havokVehiclePhysicsComponent->SetRotation(m_DefaultRotation);
|
||||||
}
|
}
|
||||||
@ -2161,7 +2167,19 @@ void Entity::SetRespawnPos(const NiPoint3& position) {
|
|||||||
auto* characterComponent = GetComponent<CharacterComponent>();
|
auto* characterComponent = GetComponent<CharacterComponent>();
|
||||||
if (characterComponent) characterComponent->SetRespawnPos(position);
|
if (characterComponent) characterComponent->SetRespawnPos(position);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Entity::SetRespawnRot(const NiQuaternion& rotation) {
|
void Entity::SetRespawnRot(const NiQuaternion& rotation) {
|
||||||
auto* characterComponent = GetComponent<CharacterComponent>();
|
auto* characterComponent = GetComponent<CharacterComponent>();
|
||||||
if (characterComponent) characterComponent->SetRespawnRot(rotation);
|
if (characterComponent) characterComponent->SetRespawnRot(rotation);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int32_t Entity::GetCollisionGroup() const {
|
||||||
|
for (const auto* component : m_Components | std::views::values) {
|
||||||
|
auto* compToCheck = dynamic_cast<const PhysicsComponent*>(component);
|
||||||
|
if (compToCheck) {
|
||||||
|
return compToCheck->GetCollisionGroup();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
@ -107,6 +107,11 @@ public:
|
|||||||
|
|
||||||
const SystemAddress& GetSystemAddress() const;
|
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
|
* Setters
|
||||||
*/
|
*/
|
||||||
|
@ -16,6 +16,7 @@
|
|||||||
#include "DestroyableComponent.h"
|
#include "DestroyableComponent.h"
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
#include <ranges>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
@ -27,7 +28,7 @@
|
|||||||
#include "CDPhysicsComponentTable.h"
|
#include "CDPhysicsComponentTable.h"
|
||||||
#include "dNavMesh.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_Target = LWOOBJID_EMPTY;
|
||||||
m_DirtyStateOrTarget = true;
|
m_DirtyStateOrTarget = true;
|
||||||
m_State = AiState::spawn;
|
m_State = AiState::spawn;
|
||||||
@ -37,6 +38,7 @@ BaseCombatAIComponent::BaseCombatAIComponent(Entity* parent, const uint32_t id):
|
|||||||
m_Disabled = false;
|
m_Disabled = false;
|
||||||
m_SkillEntries = {};
|
m_SkillEntries = {};
|
||||||
m_SoftTimer = 5.0f;
|
m_SoftTimer = 5.0f;
|
||||||
|
m_ForcedTetherTime = 0.0f;
|
||||||
|
|
||||||
//Grab the aggro information from BaseCombatAI:
|
//Grab the aggro information from BaseCombatAI:
|
||||||
auto componentQuery = CDClientDatabase::CreatePreppedStmt(
|
auto componentQuery = CDClientDatabase::CreatePreppedStmt(
|
||||||
@ -170,6 +172,17 @@ void BaseCombatAIComponent::Update(const float deltaTime) {
|
|||||||
GameMessages::SendStopFXEffect(m_Parent, true, "tether");
|
GameMessages::SendStopFXEffect(m_Parent, true, "tether");
|
||||||
m_TetherEffectActive = false;
|
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) {
|
if (m_SoftTimer <= 0.0f) {
|
||||||
@ -287,40 +300,7 @@ void BaseCombatAIComponent::CalculateCombat(const float deltaTime) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!m_TetherEffectActive && m_OutOfCombat && (m_OutOfCombatTime -= deltaTime) <= 0) {
|
if (!m_TetherEffectActive && m_OutOfCombat && (m_OutOfCombatTime -= deltaTime) <= 0) {
|
||||||
auto* destroyableComponent = m_Parent->GetComponent<DestroyableComponent>();
|
TetherLogic();
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
m_OutOfCombat = false;
|
m_OutOfCombat = false;
|
||||||
m_OutOfCombatTime = 0.0f;
|
m_OutOfCombatTime = 0.0f;
|
||||||
@ -499,7 +479,7 @@ std::vector<LWOOBJID> BaseCombatAIComponent::GetTargetWithinAggroRange() const {
|
|||||||
|
|
||||||
const auto distance = Vector3::DistanceSquared(m_Parent->GetPosition(), other->GetPosition());
|
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);
|
targets.push_back(id);
|
||||||
}
|
}
|
||||||
@ -626,6 +606,7 @@ const NiPoint3& BaseCombatAIComponent::GetStartPosition() const {
|
|||||||
|
|
||||||
void BaseCombatAIComponent::ClearThreat() {
|
void BaseCombatAIComponent::ClearThreat() {
|
||||||
m_ThreatEntries.clear();
|
m_ThreatEntries.clear();
|
||||||
|
m_Target = LWOOBJID_EMPTY;
|
||||||
|
|
||||||
m_DirtyThreat = true;
|
m_DirtyThreat = true;
|
||||||
}
|
}
|
||||||
@ -806,3 +787,55 @@ void BaseCombatAIComponent::Wake() {
|
|||||||
m_dpEntity->SetSleeping(false);
|
m_dpEntity->SetSleeping(false);
|
||||||
m_dpEntityEnemy->SetSleeping(false);
|
m_dpEntityEnemy->SetSleeping(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void BaseCombatAIComponent::TetherLogic() {
|
||||||
|
auto* destroyableComponent = m_Parent->GetComponent<DestroyableComponent>();
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
@ -224,6 +224,16 @@ public:
|
|||||||
*/
|
*/
|
||||||
void Wake();
|
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:
|
private:
|
||||||
/**
|
/**
|
||||||
* Returns the current target or the target that currently is the largest threat to this entity
|
* Returns the current target or the target that currently is the largest threat to this entity
|
||||||
@ -382,6 +392,12 @@ private:
|
|||||||
*/
|
*/
|
||||||
bool m_DirtyStateOrTarget = false;
|
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<LWOOBJID, float> m_RemovedThreatList;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Whether the current entity is a mech enemy, needed as mechs tether radius works differently
|
* Whether the current entity is a mech enemy, needed as mechs tether radius works differently
|
||||||
* @return whether this entity is a mech
|
* @return whether this entity is a mech
|
||||||
|
@ -15,7 +15,7 @@
|
|||||||
#include "LevelProgressionComponent.h"
|
#include "LevelProgressionComponent.h"
|
||||||
#include "eStateChangeType.h"
|
#include "eStateChangeType.h"
|
||||||
|
|
||||||
ControllablePhysicsComponent::ControllablePhysicsComponent(Entity* entity) : PhysicsComponent(entity) {
|
ControllablePhysicsComponent::ControllablePhysicsComponent(Entity* entity, int32_t componentId) : PhysicsComponent(entity, componentId) {
|
||||||
m_Velocity = {};
|
m_Velocity = {};
|
||||||
m_AngularVelocity = {};
|
m_AngularVelocity = {};
|
||||||
m_InJetpackMode = false;
|
m_InJetpackMode = false;
|
||||||
|
@ -23,7 +23,7 @@ class ControllablePhysicsComponent : public PhysicsComponent {
|
|||||||
public:
|
public:
|
||||||
static constexpr eReplicaComponentType ComponentType = eReplicaComponentType::CONTROLLABLE_PHYSICS;
|
static constexpr eReplicaComponentType ComponentType = eReplicaComponentType::CONTROLLABLE_PHYSICS;
|
||||||
|
|
||||||
ControllablePhysicsComponent(Entity* entity);
|
ControllablePhysicsComponent(Entity* entity, int32_t componentId);
|
||||||
~ControllablePhysicsComponent() override;
|
~ControllablePhysicsComponent() override;
|
||||||
|
|
||||||
void Update(float deltaTime) override;
|
void Update(float deltaTime) override;
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
#include "HavokVehiclePhysicsComponent.h"
|
#include "HavokVehiclePhysicsComponent.h"
|
||||||
#include "EntityManager.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_Velocity = NiPoint3Constant::ZERO;
|
||||||
m_AngularVelocity = NiPoint3Constant::ZERO;
|
m_AngularVelocity = NiPoint3Constant::ZERO;
|
||||||
m_IsOnGround = true;
|
m_IsOnGround = true;
|
||||||
|
@ -13,7 +13,7 @@ class HavokVehiclePhysicsComponent : public PhysicsComponent {
|
|||||||
public:
|
public:
|
||||||
static constexpr eReplicaComponentType ComponentType = eReplicaComponentType::HAVOK_VEHICLE_PHYSICS;
|
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;
|
void Serialize(RakNet::BitStream& outBitStream, bool bIsInitialUpdate) override;
|
||||||
|
|
||||||
|
@ -27,7 +27,7 @@
|
|||||||
#include "dpShapeBox.h"
|
#include "dpShapeBox.h"
|
||||||
#include "dpShapeSphere.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_Position = m_Parent->GetDefaultPosition();
|
||||||
m_Rotation = m_Parent->GetDefaultRotation();
|
m_Rotation = m_Parent->GetDefaultRotation();
|
||||||
m_Scale = m_Parent->GetDefaultScale();
|
m_Scale = m_Parent->GetDefaultScale();
|
||||||
|
@ -30,7 +30,7 @@ class PhantomPhysicsComponent final : public PhysicsComponent {
|
|||||||
public:
|
public:
|
||||||
static constexpr eReplicaComponentType ComponentType = eReplicaComponentType::PHANTOM_PHYSICS;
|
static constexpr eReplicaComponentType ComponentType = eReplicaComponentType::PHANTOM_PHYSICS;
|
||||||
|
|
||||||
PhantomPhysicsComponent(Entity* parent);
|
PhantomPhysicsComponent(Entity* parent, int32_t componentId);
|
||||||
~PhantomPhysicsComponent() override;
|
~PhantomPhysicsComponent() override;
|
||||||
void Update(float deltaTime) override;
|
void Update(float deltaTime) override;
|
||||||
void Serialize(RakNet::BitStream& outBitStream, bool bIsInitialUpdate) override;
|
void Serialize(RakNet::BitStream& outBitStream, bool bIsInitialUpdate) override;
|
||||||
|
@ -14,10 +14,21 @@
|
|||||||
|
|
||||||
#include "EntityInfo.h"
|
#include "EntityInfo.h"
|
||||||
|
|
||||||
PhysicsComponent::PhysicsComponent(Entity* parent) : Component(parent) {
|
PhysicsComponent::PhysicsComponent(Entity* parent, int32_t componentId) : Component(parent) {
|
||||||
m_Position = NiPoint3Constant::ZERO;
|
m_Position = NiPoint3Constant::ZERO;
|
||||||
m_Rotation = NiQuaternionConstant::IDENTITY;
|
m_Rotation = NiQuaternionConstant::IDENTITY;
|
||||||
m_DirtyPosition = false;
|
m_DirtyPosition = false;
|
||||||
|
|
||||||
|
CDPhysicsComponentTable* physicsComponentTable = CDClientManager::GetTable<CDPhysicsComponentTable>();
|
||||||
|
|
||||||
|
if (physicsComponentTable) {
|
||||||
|
auto* info = physicsComponentTable->GetByID(componentId);
|
||||||
|
if (info) {
|
||||||
|
m_CollisionGroup = info->collisionGroup;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_Parent->HasVar(u"CollisionGroupID")) m_CollisionGroup = m_Parent->GetVar<int32_t>(u"CollisionGroupID");
|
||||||
}
|
}
|
||||||
|
|
||||||
void PhysicsComponent::Serialize(RakNet::BitStream& outBitStream, bool bIsInitialUpdate) {
|
void PhysicsComponent::Serialize(RakNet::BitStream& outBitStream, bool bIsInitialUpdate) {
|
||||||
|
@ -15,7 +15,7 @@ class dpEntity;
|
|||||||
|
|
||||||
class PhysicsComponent : public Component {
|
class PhysicsComponent : public Component {
|
||||||
public:
|
public:
|
||||||
PhysicsComponent(Entity* parent);
|
PhysicsComponent(Entity* parent, int32_t componentId);
|
||||||
virtual ~PhysicsComponent() = default;
|
virtual ~PhysicsComponent() = default;
|
||||||
|
|
||||||
void Serialize(RakNet::BitStream& outBitStream, bool bIsInitialUpdate) override;
|
void Serialize(RakNet::BitStream& outBitStream, bool bIsInitialUpdate) override;
|
||||||
@ -25,6 +25,9 @@ public:
|
|||||||
|
|
||||||
const NiQuaternion& GetRotation() const { return m_Rotation; }
|
const NiQuaternion& GetRotation() const { return m_Rotation; }
|
||||||
virtual void SetRotation(const NiQuaternion& rot) { if (m_Rotation == rot) return; m_Rotation = rot; m_DirtyPosition = true; }
|
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:
|
protected:
|
||||||
dpEntity* CreatePhysicsEntity(eReplicaComponentType type);
|
dpEntity* CreatePhysicsEntity(eReplicaComponentType type);
|
||||||
|
|
||||||
@ -37,6 +40,8 @@ protected:
|
|||||||
NiQuaternion m_Rotation;
|
NiQuaternion m_Rotation;
|
||||||
|
|
||||||
bool m_DirtyPosition;
|
bool m_DirtyPosition;
|
||||||
|
|
||||||
|
int32_t m_CollisionGroup{};
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif //!__PHYSICSCOMPONENT__H__
|
#endif //!__PHYSICSCOMPONENT__H__
|
||||||
|
@ -12,7 +12,7 @@
|
|||||||
#include "dpShapeSphere.h"
|
#include "dpShapeSphere.h"
|
||||||
#include"EntityInfo.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_Position = m_Parent->GetDefaultPosition();
|
||||||
m_Rotation = m_Parent->GetDefaultRotation();
|
m_Rotation = m_Parent->GetDefaultRotation();
|
||||||
m_Scale = m_Parent->GetDefaultScale();
|
m_Scale = m_Parent->GetDefaultScale();
|
||||||
|
@ -21,7 +21,7 @@ class RigidbodyPhantomPhysicsComponent : public PhysicsComponent {
|
|||||||
public:
|
public:
|
||||||
static constexpr eReplicaComponentType ComponentType = eReplicaComponentType::RIGID_BODY_PHANTOM_PHYSICS;
|
static constexpr eReplicaComponentType ComponentType = eReplicaComponentType::RIGID_BODY_PHANTOM_PHYSICS;
|
||||||
|
|
||||||
RigidbodyPhantomPhysicsComponent(Entity* parent);
|
RigidbodyPhantomPhysicsComponent(Entity* parent, int32_t componentId);
|
||||||
|
|
||||||
void Update(const float deltaTime) override;
|
void Update(const float deltaTime) override;
|
||||||
|
|
||||||
|
@ -13,7 +13,7 @@
|
|||||||
|
|
||||||
#include "Entity.h"
|
#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_Position = m_Parent->GetDefaultPosition();
|
||||||
m_Rotation = m_Parent->GetDefaultRotation();
|
m_Rotation = m_Parent->GetDefaultRotation();
|
||||||
|
|
||||||
|
@ -30,7 +30,7 @@ class SimplePhysicsComponent : public PhysicsComponent {
|
|||||||
public:
|
public:
|
||||||
static constexpr eReplicaComponentType ComponentType = eReplicaComponentType::SIMPLE_PHYSICS;
|
static constexpr eReplicaComponentType ComponentType = eReplicaComponentType::SIMPLE_PHYSICS;
|
||||||
|
|
||||||
SimplePhysicsComponent(Entity* parent, uint32_t componentID);
|
SimplePhysicsComponent(Entity* parent, int32_t componentID);
|
||||||
~SimplePhysicsComponent() override;
|
~SimplePhysicsComponent() override;
|
||||||
|
|
||||||
void Serialize(RakNet::BitStream& outBitStream, bool bIsInitialUpdate) override;
|
void Serialize(RakNet::BitStream& outBitStream, bool bIsInitialUpdate) override;
|
||||||
|
@ -6338,6 +6338,40 @@ void GameMessages::SendUpdateInventoryUi(LWOOBJID objectId, const SystemAddress&
|
|||||||
|
|
||||||
bitStream.Write(objectId);
|
bitStream.Write(objectId);
|
||||||
bitStream.Write(MessageType::Game::UPDATE_INVENTORY_UI);
|
bitStream.Write(MessageType::Game::UPDATE_INVENTORY_UI);
|
||||||
|
|
||||||
|
SEND_PACKET;
|
||||||
|
}
|
||||||
|
|
||||||
|
void GameMessages::DisplayTooltip::Send() const {
|
||||||
|
CBITSTREAM;
|
||||||
|
CMSGHEADER;
|
||||||
|
|
||||||
|
bitStream.Write(target);
|
||||||
|
bitStream.Write(msgId);
|
||||||
|
|
||||||
|
bitStream.Write(doOrDie);
|
||||||
|
bitStream.Write(noRepeat);
|
||||||
|
bitStream.Write(noRevive);
|
||||||
|
bitStream.Write(isPropertyTooltip);
|
||||||
|
bitStream.Write(show);
|
||||||
|
bitStream.Write(translate);
|
||||||
|
bitStream.Write(time);
|
||||||
|
bitStream.Write<int32_t>(id.size());
|
||||||
|
bitStream.Write(id);
|
||||||
|
|
||||||
|
std::string toWrite;
|
||||||
|
for (const auto* item : localizeParams) {
|
||||||
|
toWrite += item->GetString() + "\n";
|
||||||
|
}
|
||||||
|
if (!toWrite.empty()) toWrite.pop_back();
|
||||||
|
bitStream.Write<int32_t>(toWrite.size());
|
||||||
|
bitStream.Write(GeneralUtils::ASCIIToUTF16(toWrite));
|
||||||
|
if (!toWrite.empty()) bitStream.Write<uint16_t>(0x00); // Null Terminator
|
||||||
|
|
||||||
|
bitStream.Write<int32_t>(imageName.size());
|
||||||
|
bitStream.Write(imageName);
|
||||||
|
bitStream.Write<int32_t>(text.size());
|
||||||
|
bitStream.Write(text);
|
||||||
|
|
||||||
SEND_PACKET;
|
SEND_PACKET;
|
||||||
}
|
}
|
||||||
|
@ -11,6 +11,7 @@
|
|||||||
#include "eCyclingMode.h"
|
#include "eCyclingMode.h"
|
||||||
#include "eLootSourceType.h"
|
#include "eLootSourceType.h"
|
||||||
#include "Brick.h"
|
#include "Brick.h"
|
||||||
|
#include "MessageType/Game.h"
|
||||||
|
|
||||||
class AMFBaseValue;
|
class AMFBaseValue;
|
||||||
class Entity;
|
class Entity;
|
||||||
@ -20,6 +21,7 @@ class User;
|
|||||||
class Leaderboard;
|
class Leaderboard;
|
||||||
class PropertySelectQueryProperty;
|
class PropertySelectQueryProperty;
|
||||||
class TradeItem;
|
class TradeItem;
|
||||||
|
class LDFBaseData;
|
||||||
|
|
||||||
enum class eAnimationFlags : uint32_t;
|
enum class eAnimationFlags : uint32_t;
|
||||||
|
|
||||||
@ -47,6 +49,15 @@ enum class eCameraTargetCyclingMode : int32_t {
|
|||||||
};
|
};
|
||||||
|
|
||||||
namespace GameMessages {
|
namespace GameMessages {
|
||||||
|
struct GameMsg {
|
||||||
|
GameMsg(MessageType::Game gmId) : msgId{ gmId } {}
|
||||||
|
virtual ~GameMsg() = default;
|
||||||
|
virtual void Send() const {}
|
||||||
|
MessageType::Game msgId;
|
||||||
|
LWOOBJID target{ LWOOBJID_EMPTY };
|
||||||
|
SystemAddress sysAddr{ UNASSIGNED_SYSTEM_ADDRESS };
|
||||||
|
};
|
||||||
|
|
||||||
class PropertyDataMessage;
|
class PropertyDataMessage;
|
||||||
void SendFireEventClientSide(const LWOOBJID& objectID, const SystemAddress& sysAddr, std::u16string args, const LWOOBJID& object, int64_t param1, int param2, const LWOOBJID& sender);
|
void SendFireEventClientSide(const LWOOBJID& objectID, const SystemAddress& sysAddr, std::u16string args, const LWOOBJID& object, int64_t param1, int param2, const LWOOBJID& sender);
|
||||||
void SendTeleport(const LWOOBJID& objectID, const NiPoint3& pos, const NiQuaternion& rot, const SystemAddress& sysAddr, bool bSetRotation = false);
|
void SendTeleport(const LWOOBJID& objectID, const NiPoint3& pos, const NiQuaternion& rot, const SystemAddress& sysAddr, bool bSetRotation = false);
|
||||||
@ -680,6 +691,22 @@ namespace GameMessages {
|
|||||||
|
|
||||||
// This is a client gm however its default values are exactly what we need to get around the invisible inventory item issues.
|
// This is a client gm however its default values are exactly what we need to get around the invisible inventory item issues.
|
||||||
void SendUpdateInventoryUi(LWOOBJID objectId, const SystemAddress& sysAddr);
|
void SendUpdateInventoryUi(LWOOBJID objectId, const SystemAddress& sysAddr);
|
||||||
|
|
||||||
|
struct DisplayTooltip : public GameMsg {
|
||||||
|
DisplayTooltip() : GameMsg(MessageType::Game::DISPLAY_TOOLTIP) {}
|
||||||
|
bool doOrDie{};
|
||||||
|
bool noRepeat{};
|
||||||
|
bool noRevive{};
|
||||||
|
bool isPropertyTooltip{};
|
||||||
|
bool show{};
|
||||||
|
bool translate{};
|
||||||
|
int32_t time{};
|
||||||
|
std::u16string id{};
|
||||||
|
std::vector<LDFBaseData*> localizeParams{};
|
||||||
|
std::u16string imageName{};
|
||||||
|
std::u16string text{};
|
||||||
|
void Send() const override;
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // GAMEMESSAGES_H
|
#endif // GAMEMESSAGES_H
|
||||||
|
@ -8,7 +8,6 @@ class AMFArrayValue;
|
|||||||
/**
|
/**
|
||||||
* @brief Sent when a player moves a Behavior A at position B to their inventory.
|
* @brief Sent when a player moves a Behavior A at position B to their inventory.
|
||||||
*/
|
*/
|
||||||
#pragma warning("This Control Behavior Message does not have a test yet. Non-developers can ignore this warning.")
|
|
||||||
class MoveToInventoryMessage : public BehaviorMessageBase {
|
class MoveToInventoryMessage : public BehaviorMessageBase {
|
||||||
public:
|
public:
|
||||||
MoveToInventoryMessage(const AMFArrayValue& arguments);
|
MoveToInventoryMessage(const AMFArrayValue& arguments);
|
||||||
|
@ -137,7 +137,7 @@ bool Precondition::CheckValue(Entity* player, const uint32_t value, bool evaluat
|
|||||||
|
|
||||||
return inventoryComponent->GetLotCount(value) >= count;
|
return inventoryComponent->GetLotCount(value) >= count;
|
||||||
case PreconditionType::DoesNotHaveItem:
|
case PreconditionType::DoesNotHaveItem:
|
||||||
return inventoryComponent->IsEquipped(value) < count;
|
return inventoryComponent->IsEquipped(value) && count > 0;
|
||||||
case PreconditionType::HasAchievement:
|
case PreconditionType::HasAchievement:
|
||||||
if (missionComponent == nullptr) return false;
|
if (missionComponent == nullptr) return false;
|
||||||
return missionComponent->GetMissionState(value) >= eMissionState::COMPLETE;
|
return missionComponent->GetMissionState(value) >= eMissionState::COMPLETE;
|
||||||
|
@ -2,6 +2,7 @@ set(DSCRIPTS_SOURCES_02_SERVER_MAP_GENERAL
|
|||||||
"BankInteractServer.cpp"
|
"BankInteractServer.cpp"
|
||||||
"BaseInteractDropLootServer.cpp"
|
"BaseInteractDropLootServer.cpp"
|
||||||
"Binoculars.cpp"
|
"Binoculars.cpp"
|
||||||
|
"EnemyClearThreat.cpp"
|
||||||
"ExplodingAsset.cpp"
|
"ExplodingAsset.cpp"
|
||||||
"FrictionVolumeServer.cpp"
|
"FrictionVolumeServer.cpp"
|
||||||
"ForceVolumeServer.cpp"
|
"ForceVolumeServer.cpp"
|
||||||
|
25
dScripts/02_server/Map/General/EnemyClearThreat.cpp
Normal file
25
dScripts/02_server/Map/General/EnemyClearThreat.cpp
Normal file
@ -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<BaseCombatAIComponent>();
|
||||||
|
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<BaseCombatAIComponent>();
|
||||||
|
if (!baseCombatAiComponent) continue;
|
||||||
|
|
||||||
|
baseCombatAiComponent->IgnoreThreat(target->GetObjectID(), 3.0f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
11
dScripts/02_server/Map/General/EnemyClearThreat.h
Normal file
11
dScripts/02_server/Map/General/EnemyClearThreat.h
Normal file
@ -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
|
@ -327,6 +327,8 @@
|
|||||||
#include "VisToggleNotifierServer.h"
|
#include "VisToggleNotifierServer.h"
|
||||||
#include "LupGenericInteract.h"
|
#include "LupGenericInteract.h"
|
||||||
#include "WblRobotCitizen.h"
|
#include "WblRobotCitizen.h"
|
||||||
|
#include "EnemyClearThreat.h"
|
||||||
|
#include "AgSpiderBossMessage.h"
|
||||||
|
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <string>
|
#include <string>
|
||||||
@ -686,8 +688,22 @@ namespace {
|
|||||||
{"scripts\\zone\\LUPs\\RobotCity Intro\\WBL_RCIntro_RobotCitizenOrange.lua", []() {return new WblRobotCitizen();}},
|
{"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_RobotCitizenRed.lua", []() {return new WblRobotCitizen();}},
|
||||||
{"scripts\\zone\\LUPs\\RobotCity Intro\\WBL_RCIntro_RobotCitizenYellow.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();}},
|
||||||
|
{"scripts\\ai\\AG\\L_AG_SPIDER_BOSS_MESSAGE.lua", []() {return new AgSpiderBossMessage();}},
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
std::set<std::string> 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) {
|
CppScripts::Script* const CppScripts::GetScript(Entity* parent, const std::string& scriptName) {
|
||||||
@ -699,14 +715,8 @@ CppScripts::Script* const CppScripts::GetScript(Entity* parent, const std::strin
|
|||||||
const auto itrTernary = scriptLoader.find(scriptName);
|
const auto itrTernary = scriptLoader.find(scriptName);
|
||||||
Script* script = itrTernary != scriptLoader.cend() ? itrTernary->second() : &InvalidToReturn;
|
Script* script = itrTernary != scriptLoader.cend() ? itrTernary->second() : &InvalidToReturn;
|
||||||
|
|
||||||
if (script == &InvalidToReturn) {
|
if (script == &InvalidToReturn && !scriptName.empty() && !g_ExcludedScripts.contains(scriptName)) {
|
||||||
if ((scriptName.length() > 0) && !((scriptName == "scripts\\02_server\\Enemy\\General\\L_SUSPEND_LUA_AI.lua") ||
|
LOG_DEBUG("LOT %i attempted to load CppScript for '%s', but returned InvalidScript.", parent->GetLOT(), scriptName.c_str());
|
||||||
(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());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
g_Scripts[scriptName] = script;
|
g_Scripts[scriptName] = script;
|
||||||
|
81
dScripts/ai/AG/AgSpiderBossMessage.cpp
Normal file
81
dScripts/ai/AG/AgSpiderBossMessage.cpp
Normal file
@ -0,0 +1,81 @@
|
|||||||
|
#include "AgSpiderBossMessage.h"
|
||||||
|
|
||||||
|
#include "Entity.h"
|
||||||
|
#include "GameMessages.h"
|
||||||
|
|
||||||
|
#include "RenderComponent.h"
|
||||||
|
|
||||||
|
Box AgSpiderBossMessage::GetBox(Entity* self) const {
|
||||||
|
return self->GetVar<Box>(u"box");
|
||||||
|
}
|
||||||
|
|
||||||
|
void AgSpiderBossMessage::SetBox(Entity* self, const Box& box) const {
|
||||||
|
self->SetVar(u"box", box);
|
||||||
|
}
|
||||||
|
|
||||||
|
void AgSpiderBossMessage::MakeBox(Entity* self) const {
|
||||||
|
auto box = GetBox(self);
|
||||||
|
if (box.boxTarget == LWOOBJID_EMPTY || box.isDisplayed || box.boxSelf == LWOOBJID_EMPTY) return;
|
||||||
|
|
||||||
|
box.isDisplayed = true;
|
||||||
|
SetBox(self, box);
|
||||||
|
self->AddTimer("BoxTimer", box.boxTime);
|
||||||
|
|
||||||
|
const auto* const tgt = Game::entityManager->GetEntity(box.boxTarget);
|
||||||
|
if (!tgt) return;
|
||||||
|
GameMessages::DisplayTooltip tooltip;
|
||||||
|
tooltip.target = tgt->GetObjectID();
|
||||||
|
tooltip.sysAddr = tgt->GetSystemAddress();
|
||||||
|
tooltip.show = true;
|
||||||
|
tooltip.text = box.boxText;
|
||||||
|
tooltip.time = box.boxTime * 1000; // to ms
|
||||||
|
tooltip.Send();
|
||||||
|
}
|
||||||
|
|
||||||
|
void AgSpiderBossMessage::OnCollisionPhantom(Entity* self, Entity* target) {
|
||||||
|
if (!target || !target->IsPlayer()) return;
|
||||||
|
|
||||||
|
auto box = GetBox(self);
|
||||||
|
// knockback the target
|
||||||
|
auto forward = target->GetRotation().GetForwardVector();
|
||||||
|
box.boxTarget = target->GetObjectID();
|
||||||
|
GameMessages::SendPlayFXEffect(target->GetObjectID(), 1378, u"create", "pushBack");
|
||||||
|
RenderComponent::PlayAnimation(target, "knockback-recovery");
|
||||||
|
forward.y += 15;
|
||||||
|
forward.x *= 100;
|
||||||
|
forward.z *= 100;
|
||||||
|
GameMessages::SendKnockback(target->GetObjectID(), self->GetObjectID(), self->GetObjectID(), 0, forward);
|
||||||
|
|
||||||
|
if (box.isTouch || box.isDisplayed) return;
|
||||||
|
box.boxSelf = self->GetObjectID();
|
||||||
|
box.isTouch = true;
|
||||||
|
box.boxText = u"%[SPIDER_CAVE_MESSAGE]";
|
||||||
|
SetBox(self, box);
|
||||||
|
self->AddTimer("EventTimer", 0.1f);
|
||||||
|
}
|
||||||
|
|
||||||
|
void AgSpiderBossMessage::OnOffCollisionPhantom(Entity* self, Entity* target) {
|
||||||
|
if (!target) return;
|
||||||
|
auto box = GetBox(self);
|
||||||
|
box.isTouch = false;
|
||||||
|
box.Reset();
|
||||||
|
SetBox(self, box);
|
||||||
|
}
|
||||||
|
|
||||||
|
void AgSpiderBossMessage::OnTimerDone(Entity* self, std::string timerName) {
|
||||||
|
if (timerName == "BoxTimer") {
|
||||||
|
auto box = GetBox(self);
|
||||||
|
box.isDisplayed = false;
|
||||||
|
SetBox(self, box);
|
||||||
|
ResetBox(self);
|
||||||
|
} else if (timerName == "EventTimer") {
|
||||||
|
auto box = GetBox(self);
|
||||||
|
MakeBox(self);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void AgSpiderBossMessage::ResetBox(Entity* self) const {
|
||||||
|
auto box = GetBox(self);
|
||||||
|
box.Reset();
|
||||||
|
SetBox(self, box);
|
||||||
|
}
|
37
dScripts/ai/AG/AgSpiderBossMessage.h
Normal file
37
dScripts/ai/AG/AgSpiderBossMessage.h
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
#ifndef AGSPIDERBOSSMESSAGE_H
|
||||||
|
#define AGSPIDERBOSSMESSAGE_H
|
||||||
|
|
||||||
|
#include "CppScripts.h"
|
||||||
|
|
||||||
|
struct Box {
|
||||||
|
LWOOBJID boxTarget{};
|
||||||
|
bool isDisplayed{};
|
||||||
|
bool isTouch{};
|
||||||
|
bool isFirst{};
|
||||||
|
LWOOBJID boxSelf{};
|
||||||
|
std::u16string boxText{};
|
||||||
|
int32_t boxTime{ 1 };
|
||||||
|
|
||||||
|
void Reset() {
|
||||||
|
boxTarget = LWOOBJID_EMPTY;
|
||||||
|
isDisplayed = false;
|
||||||
|
isTouch = false;
|
||||||
|
isFirst = false;
|
||||||
|
boxSelf = LWOOBJID_EMPTY;
|
||||||
|
boxText.clear();
|
||||||
|
boxTime = 1;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class AgSpiderBossMessage : public CppScripts::Script {
|
||||||
|
public:
|
||||||
|
Box GetBox(Entity* self) const;
|
||||||
|
void SetBox(Entity* self, const Box& box) const;
|
||||||
|
void MakeBox(Entity* self) const;
|
||||||
|
void OnCollisionPhantom(Entity* self, Entity* target) override;
|
||||||
|
void OnOffCollisionPhantom(Entity* self, Entity* target) override;
|
||||||
|
void OnTimerDone(Entity* self, std::string timerName) override;
|
||||||
|
void ResetBox(Entity* self) const;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif //!AGSPIDERBOSSMESSAGE_H
|
@ -1,6 +1,7 @@
|
|||||||
set(DSCRIPTS_SOURCES_AI_AG
|
set(DSCRIPTS_SOURCES_AI_AG
|
||||||
"AgShipPlayerDeathTrigger.cpp"
|
"AgShipPlayerDeathTrigger.cpp"
|
||||||
"AgSpaceStuff.cpp"
|
"AgSpaceStuff.cpp"
|
||||||
|
"AgSpiderBossMessage.cpp"
|
||||||
"AgShipShake.cpp"
|
"AgShipShake.cpp"
|
||||||
"AgShipPlayerShockServer.cpp"
|
"AgShipPlayerShockServer.cpp"
|
||||||
"AgImagSmashable.cpp"
|
"AgImagSmashable.cpp"
|
||||||
|
Loading…
Reference in New Issue
Block a user