diff --git a/CMakeVariables.txt b/CMakeVariables.txt index d9430d9d..31482ce4 100644 --- a/CMakeVariables.txt +++ b/CMakeVariables.txt @@ -1,6 +1,6 @@ PROJECT_VERSION_MAJOR=1 -PROJECT_VERSION_MINOR=1 -PROJECT_VERSION_PATCH=1 +PROJECT_VERSION_MINOR=2 +PROJECT_VERSION_PATCH=0 # Debugging # Set DYNAMIC to 1 to enable the -rdynamic flag for the linker, yielding some symbols in crashlogs. diff --git a/dGame/Entity.cpp b/dGame/Entity.cpp index 00ad8471..59b583d3 100644 --- a/dGame/Entity.cpp +++ b/dGame/Entity.cpp @@ -1840,6 +1840,12 @@ const NiPoint3& Entity::GetPosition() const { return vehicel->GetPosition(); } + auto* rigidBodyPhantomPhysicsComponent = GetComponent(); + + if (rigidBodyPhantomPhysicsComponent != nullptr) { + return rigidBodyPhantomPhysicsComponent->GetPosition(); + } + return NiPoint3Constant::ZERO; } @@ -1868,6 +1874,12 @@ const NiQuaternion& Entity::GetRotation() const { return vehicel->GetRotation(); } + auto* rigidBodyPhantomPhysicsComponent = GetComponent(); + + if (rigidBodyPhantomPhysicsComponent != nullptr) { + return rigidBodyPhantomPhysicsComponent->GetRotation(); + } + return NiQuaternionConstant::IDENTITY; } @@ -1896,6 +1908,12 @@ void Entity::SetPosition(const NiPoint3& position) { vehicel->SetPosition(position); } + auto* rigidBodyPhantomPhysicsComponent = GetComponent(); + + if (rigidBodyPhantomPhysicsComponent != nullptr) { + rigidBodyPhantomPhysicsComponent->SetPosition(position); + } + Game::entityManager->SerializeEntity(this); } @@ -1924,6 +1942,12 @@ void Entity::SetRotation(const NiQuaternion& rotation) { vehicel->SetRotation(rotation); } + auto* rigidBodyPhantomPhysicsComponent = GetComponent(); + + if (rigidBodyPhantomPhysicsComponent != nullptr) { + rigidBodyPhantomPhysicsComponent->SetRotation(rotation); + } + Game::entityManager->SerializeEntity(this); } diff --git a/dGame/dComponents/PhantomPhysicsComponent.cpp b/dGame/dComponents/PhantomPhysicsComponent.cpp index ba0c2495..95fed36e 100644 --- a/dGame/dComponents/PhantomPhysicsComponent.cpp +++ b/dGame/dComponents/PhantomPhysicsComponent.cpp @@ -47,7 +47,7 @@ PhantomPhysicsComponent::PhantomPhysicsComponent(Entity* parent) : PhysicsCompon m_Direction = NiPoint3(); // * m_DirectionalMultiplier if (m_Parent->GetVar(u"create_physics")) { - CreatePhysics(); + m_dpEntity = CreatePhysicsLnv(m_Scale, ComponentType); } if (m_Parent->GetVar(u"respawnVol")) { @@ -89,105 +89,9 @@ PhantomPhysicsComponent::PhantomPhysicsComponent(Entity* parent) : PhysicsCompon m_RespawnRot = m_Rotation; } - /* - for (LDFBaseData* data : settings) { - if (data) { - if (data->GetKey() == u"create_physics") { - if (bool(std::stoi(data->GetValueAsString()))) { - CreatePhysics(settings); - } - } - - if (data->GetKey() == u"respawnVol") { - if (bool(std::stoi(data->GetValueAsString()))) { - m_IsRespawnVolume = true; - } - } - - if (m_IsRespawnVolume) { - if (data->GetKey() == u"rspPos") { - //Joy, we get to split strings! - std::stringstream test(data->GetValueAsString()); - std::string segment; - std::vector seglist; - - while (std::getline(test, segment, '\x1f')) { - seglist.push_back(segment); - } - - m_RespawnPos = NiPoint3(std::stof(seglist[0]), std::stof(seglist[1]), std::stof(seglist[2])); - } - - if (data->GetKey() == u"rspRot") { - //Joy, we get to split strings! - std::stringstream test(data->GetValueAsString()); - std::string segment; - std::vector seglist; - - while (std::getline(test, segment, '\x1f')) { - seglist.push_back(segment); - } - - m_RespawnRot = NiQuaternion(std::stof(seglist[0]), std::stof(seglist[1]), std::stof(seglist[2]), std::stof(seglist[3])); - } - } - - if (m_Parent->GetLOT() == 4945) // HF - RespawnPoints - { - m_IsRespawnVolume = true; - m_RespawnPos = m_Position; - m_RespawnRot = m_Rotation; - } - } - } - */ - - if (!m_HasCreatedPhysics) { - CDComponentsRegistryTable* compRegistryTable = CDClientManager::GetTable(); - auto componentID = compRegistryTable->GetByIDAndType(m_Parent->GetLOT(), eReplicaComponentType::PHANTOM_PHYSICS); - - CDPhysicsComponentTable* physComp = CDClientManager::GetTable(); - - if (physComp == nullptr) return; - - auto* info = physComp->GetByID(componentID); - if (info == nullptr || info->physicsAsset == "" || info->physicsAsset == "NO_PHYSICS") return; - - //temp test - if (info->physicsAsset == "miscellaneous\\misc_phys_10x1x5.hkx") { - m_dpEntity = new dpEntity(m_Parent->GetObjectID(), 10.0f, 5.0f, 1.0f); - } else if (info->physicsAsset == "miscellaneous\\misc_phys_640x640.hkx") { - // TODO Fix physics simulation to do simulation at high velocities due to bullet through paper problem... - m_dpEntity = new dpEntity(m_Parent->GetObjectID(), 1638.4f, 13.521004f * 2.0f, 1638.4f); - - // Move this down by 13.521004 units so it is still effectively at the same height as before - m_Position = m_Position - NiPoint3Constant::UNIT_Y * 13.521004f; - } else if (info->physicsAsset == "env\\trigger_wall_tall.hkx") { - m_dpEntity = new dpEntity(m_Parent->GetObjectID(), 10.0f, 25.0f, 1.0f); - } else if (info->physicsAsset == "env\\env_gen_placeholderphysics.hkx") { - m_dpEntity = new dpEntity(m_Parent->GetObjectID(), 20.0f, 20.0f, 20.0f); - } else if (info->physicsAsset == "env\\POI_trigger_wall.hkx") { - m_dpEntity = new dpEntity(m_Parent->GetObjectID(), 1.0f, 12.5f, 20.0f); // Not sure what the real size is - } else if (info->physicsAsset == "env\\NG_NinjaGo\\env_ng_gen_gate_chamber_puzzle_ceiling_tile_falling_phantom.hkx") { - m_dpEntity = new dpEntity(m_Parent->GetObjectID(), 18.0f, 5.0f, 15.0f); - m_Position += m_Rotation.GetForwardVector() * 7.5f; - } else if (info->physicsAsset == "env\\NG_NinjaGo\\ng_flamejet_brick_phantom.HKX") { - m_dpEntity = new dpEntity(m_Parent->GetObjectID(), 1.0f, 1.0f, 12.0f); - m_Position += m_Rotation.GetForwardVector() * 6.0f; - } else if (info->physicsAsset == "env\\Ring_Trigger.hkx") { - m_dpEntity = new dpEntity(m_Parent->GetObjectID(), 6.0f, 6.0f, 6.0f); - } else if (info->physicsAsset == "env\\vfx_propertyImaginationBall.hkx") { - m_dpEntity = new dpEntity(m_Parent->GetObjectID(), 4.5f); - } else if (info->physicsAsset == "env\\env_won_fv_gas-blocking-volume.hkx") { - m_dpEntity = new dpEntity(m_Parent->GetObjectID(), 390.496826f, 111.467964f, 600.821534f, true); - m_Position.y -= (111.467964f * m_Scale) / 2; - } else { - // LOG_DEBUG("This one is supposed to have %s", info->physicsAsset.c_str()); - - //add fallback cube: - m_dpEntity = new dpEntity(m_Parent->GetObjectID(), 2.0f, 2.0f, 2.0f); - } - + if (!m_dpEntity) { + m_dpEntity = CreatePhysicsEntity(ComponentType); + if (!m_dpEntity) return; m_dpEntity->SetScale(m_Scale); m_dpEntity->SetRotation(m_Rotation); m_dpEntity->SetPosition(m_Position); @@ -201,69 +105,6 @@ PhantomPhysicsComponent::~PhantomPhysicsComponent() { } } -void PhantomPhysicsComponent::CreatePhysics() { - unsigned char alpha; - unsigned char red; - unsigned char green; - unsigned char blue; - int type = -1; - float x = 0.0f; - float y = 0.0f; - float z = 0.0f; - float width = 0.0f; //aka "radius" - float height = 0.0f; - - if (m_Parent->HasVar(u"primitiveModelType")) { - type = m_Parent->GetVar(u"primitiveModelType"); - x = m_Parent->GetVar(u"primitiveModelValueX"); - y = m_Parent->GetVar(u"primitiveModelValueY"); - z = m_Parent->GetVar(u"primitiveModelValueZ"); - } else { - CDComponentsRegistryTable* compRegistryTable = CDClientManager::GetTable(); - auto componentID = compRegistryTable->GetByIDAndType(m_Parent->GetLOT(), eReplicaComponentType::PHANTOM_PHYSICS); - - CDPhysicsComponentTable* physComp = CDClientManager::GetTable(); - - if (physComp == nullptr) return; - - auto info = physComp->GetByID(componentID); - - if (info == nullptr) return; - - type = info->pcShapeType; - width = info->playerRadius; - height = info->playerHeight; - } - - switch (type) { - case 1: { //Make a new box shape - NiPoint3 boxSize(x, y, z); - if (x == 0.0f) { - //LU has some weird values, so I think it's best to scale them down a bit - if (height < 0.5f) height = 2.0f; - if (width < 0.5f) width = 2.0f; - - //Scale them: - width = width * m_Scale; - height = height * m_Scale; - - boxSize = NiPoint3(width, height, width); - } - - m_dpEntity = new dpEntity(m_Parent->GetObjectID(), boxSize); - break; - } - } - - if (!m_dpEntity) return; - - m_dpEntity->SetPosition({ m_Position.x, m_Position.y - (height / 2), m_Position.z }); - - dpWorld::AddEntity(m_dpEntity); - - m_HasCreatedPhysics = true; -} - void PhantomPhysicsComponent::Serialize(RakNet::BitStream& outBitStream, bool bIsInitialUpdate) { PhysicsComponent::Serialize(outBitStream, bIsInitialUpdate); @@ -308,8 +149,9 @@ void ApplyCollisionEffect(const LWOOBJID& target, const ePhysicsEffectType effec controllablePhysicsComponent->SetGravityScale(effectScale); GameMessages::SendSetGravityScale(target, effectScale, targetEntity->GetSystemAddress()); } + break; } - // The other types are not handled by the server + case ePhysicsEffectType::ATTRACT: case ePhysicsEffectType::FRICTION: case ePhysicsEffectType::PUSH: @@ -317,6 +159,7 @@ void ApplyCollisionEffect(const LWOOBJID& target, const ePhysicsEffectType effec default: break; } + // The other types are not handled by the server and are here to handle all cases of the enum. } void PhantomPhysicsComponent::Update(float deltaTime) { @@ -356,24 +199,12 @@ void PhantomPhysicsComponent::SetDirection(const NiPoint3& pos) { m_IsDirectional = true; } -void PhantomPhysicsComponent::SpawnVertices() { - if (!m_dpEntity) return; - - LOG("%llu", m_Parent->GetObjectID()); - auto box = static_cast(m_dpEntity->GetShape()); - for (auto vert : box->GetVertices()) { - LOG("%f, %f, %f", vert.x, vert.y, vert.z); - - EntityInfo info; - info.lot = 33; - info.pos = vert; - info.spawner = nullptr; - info.spawnerID = m_Parent->GetObjectID(); - info.spawnerNodeID = 0; - - Entity* newEntity = Game::entityManager->CreateEntity(info, nullptr); - Game::entityManager->ConstructEntity(newEntity); +void PhantomPhysicsComponent::SpawnVertices() const { + if (!m_dpEntity) { + LOG("No dpEntity to spawn vertices for %llu:%i", m_Parent->GetObjectID(), m_Parent->GetLOT()); + return; } + PhysicsComponent::SpawnVertices(m_dpEntity); } void PhantomPhysicsComponent::SetDirectionalMultiplier(float mul) { diff --git a/dGame/dComponents/PhantomPhysicsComponent.h b/dGame/dComponents/PhantomPhysicsComponent.h index 1aae9527..89cfb857 100644 --- a/dGame/dComponents/PhantomPhysicsComponent.h +++ b/dGame/dComponents/PhantomPhysicsComponent.h @@ -18,6 +18,7 @@ class LDFBaseData; class Entity; class dpEntity; enum class ePhysicsEffectType : uint32_t ; +enum class eReplicaComponentType : uint32_t; /** * Allows the creation of phantom physics for an entity: a physics object that is generally invisible but can be @@ -34,11 +35,6 @@ public: void Update(float deltaTime) override; void Serialize(RakNet::BitStream& outBitStream, bool bIsInitialUpdate) override; - /** - * Creates the physics shape for this entity based on LDF data - */ - void CreatePhysics(); - /** * Sets the direction this physics object is pointed at * @param pos the direction to set @@ -109,7 +105,7 @@ public: /** * Spawns an object at each of the vertices for debugging purposes */ - void SpawnVertices(); + void SpawnVertices() const; /** * Legacy stuff no clue what this does @@ -166,11 +162,6 @@ private: */ dpEntity* m_dpEntity; - /** - * Whether or not the physics object has been created yet - */ - bool m_HasCreatedPhysics = false; - /** * Whether or not this physics object represents an object that updates the respawn pos of an entity that crosses it */ diff --git a/dGame/dComponents/PhysicsComponent.cpp b/dGame/dComponents/PhysicsComponent.cpp index 3a84c4ce..4a250a6a 100644 --- a/dGame/dComponents/PhysicsComponent.cpp +++ b/dGame/dComponents/PhysicsComponent.cpp @@ -1,5 +1,19 @@ #include "PhysicsComponent.h" +#include "eReplicaComponentType.h" +#include "NiPoint3.h" +#include "NiQuaternion.h" + +#include "CDComponentsRegistryTable.h" +#include "CDPhysicsComponentTable.h" + +#include "dpEntity.h" +#include "dpWorld.h" +#include "dpShapeBox.h" +#include "dpShapeSphere.h" + +#include "EntityInfo.h" + PhysicsComponent::PhysicsComponent(Entity* parent) : Component(parent) { m_Position = NiPoint3Constant::ZERO; m_Rotation = NiQuaternionConstant::IDENTITY; @@ -19,3 +33,190 @@ void PhysicsComponent::Serialize(RakNet::BitStream& outBitStream, bool bIsInitia if (!bIsInitialUpdate) m_DirtyPosition = false; } } + +dpEntity* PhysicsComponent::CreatePhysicsEntity(eReplicaComponentType type) { + CDComponentsRegistryTable* compRegistryTable = CDClientManager::GetTable(); + auto componentID = compRegistryTable->GetByIDAndType(m_Parent->GetLOT(), type); + + CDPhysicsComponentTable* physComp = CDClientManager::GetTable(); + + if (physComp == nullptr) return nullptr; + + auto* info = physComp->GetByID(componentID); + if (info == nullptr || info->physicsAsset == "" || info->physicsAsset == "NO_PHYSICS") return nullptr; + + dpEntity* toReturn; + if (info->physicsAsset == "miscellaneous\\misc_phys_10x1x5.hkx") { + toReturn = new dpEntity(m_Parent->GetObjectID(), 10.0f, 5.0f, 1.0f); + } else if (info->physicsAsset == "miscellaneous\\misc_phys_640x640.hkx") { + // TODO Fix physics simulation to do simulation at high velocities due to bullet through paper problem... + toReturn = new dpEntity(m_Parent->GetObjectID(), 1638.4f, 13.521004f * 2.0f, 1638.4f); + + // Move this down by 13.521004 units so it is still effectively at the same height as before + m_Position = m_Position - NiPoint3Constant::UNIT_Y * 13.521004f; + } else if (info->physicsAsset == "env\\trigger_wall_tall.hkx") { + toReturn = new dpEntity(m_Parent->GetObjectID(), 10.0f, 25.0f, 1.0f); + } else if (info->physicsAsset == "env\\env_gen_placeholderphysics.hkx") { + toReturn = new dpEntity(m_Parent->GetObjectID(), 20.0f, 20.0f, 20.0f); + } else if (info->physicsAsset == "env\\POI_trigger_wall.hkx") { + toReturn = new dpEntity(m_Parent->GetObjectID(), 1.0f, 12.5f, 20.0f); // Not sure what the real size is + } else if (info->physicsAsset == "env\\NG_NinjaGo\\env_ng_gen_gate_chamber_puzzle_ceiling_tile_falling_phantom.hkx") { + toReturn = new dpEntity(m_Parent->GetObjectID(), 18.0f, 5.0f, 15.0f); + m_Position += m_Rotation.GetForwardVector() * 7.5f; + } else if (info->physicsAsset == "env\\NG_NinjaGo\\ng_flamejet_brick_phantom.HKX") { + toReturn = new dpEntity(m_Parent->GetObjectID(), 1.0f, 1.0f, 12.0f); + m_Position += m_Rotation.GetForwardVector() * 6.0f; + } else if (info->physicsAsset == "env\\Ring_Trigger.hkx") { + toReturn = new dpEntity(m_Parent->GetObjectID(), 6.0f, 6.0f, 6.0f); + } else if (info->physicsAsset == "env\\vfx_propertyImaginationBall.hkx") { + toReturn = new dpEntity(m_Parent->GetObjectID(), 4.5f); + } else if (info->physicsAsset == "env\\env_won_fv_gas-blocking-volume.hkx") { + toReturn = new dpEntity(m_Parent->GetObjectID(), 390.496826f, 111.467964f, 600.821534f, true); + m_Position.y -= (111.467964f * m_Parent->GetDefaultScale()) / 2; + } else { + // LOG_DEBUG("This one is supposed to have %s", info->physicsAsset.c_str()); + + //add fallback cube: + toReturn = new dpEntity(m_Parent->GetObjectID(), 2.0f, 2.0f, 2.0f); + } + return toReturn; +} + +dpEntity* PhysicsComponent::CreatePhysicsLnv(const float scale, const eReplicaComponentType type) const { + int pcShapeType = -1; + float x = 0.0f; + float y = 0.0f; + float z = 0.0f; + float width = 0.0f; //aka "radius" + float height = 0.0f; + dpEntity* toReturn = nullptr; + + if (m_Parent->HasVar(u"primitiveModelType")) { + pcShapeType = m_Parent->GetVar(u"primitiveModelType"); + x = m_Parent->GetVar(u"primitiveModelValueX"); + y = m_Parent->GetVar(u"primitiveModelValueY"); + z = m_Parent->GetVar(u"primitiveModelValueZ"); + } else { + CDComponentsRegistryTable* compRegistryTable = CDClientManager::GetTable(); + auto componentID = compRegistryTable->GetByIDAndType(m_Parent->GetLOT(), type); + + CDPhysicsComponentTable* physComp = CDClientManager::GetTable(); + + if (physComp == nullptr) return nullptr; + + auto info = physComp->GetByID(componentID); + + if (info == nullptr) return nullptr; + + pcShapeType = info->pcShapeType; + width = info->playerRadius; + height = info->playerHeight; + } + + switch (pcShapeType) { + case 0: { // HKX type + break; + } + case 1: { //Make a new box shape + NiPoint3 boxSize(x, y, z); + if (x == 0.0f) { + //LU has some weird values, so I think it's best to scale them down a bit + if (height < 0.5f) height = 2.0f; + if (width < 0.5f) width = 2.0f; + + //Scale them: + width = width * scale; + height = height * scale; + + boxSize = NiPoint3(width, height, width); + } + + toReturn = new dpEntity(m_Parent->GetObjectID(), boxSize); + + toReturn->SetPosition({ m_Position.x, m_Position.y - (height / 2), m_Position.z }); + break; + } + case 2: { //Make a new cylinder shape + break; + } + case 3: { //Make a new sphere shape + auto [x, y, z] = m_Position; + toReturn = new dpEntity(m_Parent->GetObjectID(), width); + toReturn->SetPosition({ x, y, z }); + break; + } + case 4: { //Make a new capsule shape + break; + } + } + + if (toReturn) dpWorld::AddEntity(toReturn); + + return toReturn; +} + +void PhysicsComponent::SpawnVertices(dpEntity* entity) const { + if (!entity) return; + + LOG("Spawning vertices for %llu", m_Parent->GetObjectID()); + EntityInfo info; + info.lot = 33; + info.spawner = nullptr; + info.spawnerID = m_Parent->GetObjectID(); + info.spawnerNodeID = 0; + + // These don't use overloaded methods as dPhysics does not link with dGame at the moment. + auto box = dynamic_cast(entity->GetShape()); + if (box) { + for (auto vert : box->GetVertices()) { + LOG("Vertex at %f, %f, %f", vert.x, vert.y, vert.z); + + info.pos = vert; + Entity* newEntity = Game::entityManager->CreateEntity(info); + Game::entityManager->ConstructEntity(newEntity); + } + } + auto sphere = dynamic_cast(entity->GetShape()); + if (sphere) { + auto [x, y, z] = entity->GetPosition(); // Use shapes position instead of the parent's position in case it's different + float plusX = x + sphere->GetRadius(); + float minusX = x - sphere->GetRadius(); + float plusY = y + sphere->GetRadius(); + float minusY = y - sphere->GetRadius(); + float plusZ = z + sphere->GetRadius(); + float minusZ = z - sphere->GetRadius(); + + auto radius = sphere->GetRadius(); + LOG("Radius: %f", radius); + LOG("Plus Vertices %f %f %f", plusX, plusY, plusZ); + LOG("Minus Vertices %f %f %f", minusX, minusY, minusZ); + + info.pos = NiPoint3{ x, plusY, z }; + Entity* newEntity = Game::entityManager->CreateEntity(info); + Game::entityManager->ConstructEntity(newEntity); + + info.pos = NiPoint3{ x, minusY, z }; + newEntity = Game::entityManager->CreateEntity(info); + Game::entityManager->ConstructEntity(newEntity); + + info.pos = NiPoint3{ plusX, y, z }; + newEntity = Game::entityManager->CreateEntity(info); + Game::entityManager->ConstructEntity(newEntity); + + info.pos = NiPoint3{ minusX, y, z }; + newEntity = Game::entityManager->CreateEntity(info); + Game::entityManager->ConstructEntity(newEntity); + + info.pos = NiPoint3{ x, y, plusZ }; + newEntity = Game::entityManager->CreateEntity(info); + Game::entityManager->ConstructEntity(newEntity); + + info.pos = NiPoint3{ x, y, minusZ }; + newEntity = Game::entityManager->CreateEntity(info); + Game::entityManager->ConstructEntity(newEntity); + + info.pos = NiPoint3{ x, y, z }; + newEntity = Game::entityManager->CreateEntity(info); + Game::entityManager->ConstructEntity(newEntity); + } +} diff --git a/dGame/dComponents/PhysicsComponent.h b/dGame/dComponents/PhysicsComponent.h index 71f52e54..4bf0828a 100644 --- a/dGame/dComponents/PhysicsComponent.h +++ b/dGame/dComponents/PhysicsComponent.h @@ -9,6 +9,10 @@ namespace Raknet { class BitStream; }; +enum class eReplicaComponentType : uint32_t; + +class dpEntity; + class PhysicsComponent : public Component { public: PhysicsComponent(Entity* parent); @@ -22,6 +26,12 @@ public: const NiQuaternion& GetRotation() const { return m_Rotation; } virtual void SetRotation(const NiQuaternion& rot) { if (m_Rotation == rot) return; m_Rotation = rot; m_DirtyPosition = true; } protected: + dpEntity* CreatePhysicsEntity(eReplicaComponentType type); + + dpEntity* CreatePhysicsLnv(const float scale, const eReplicaComponentType type) const; + + void SpawnVertices(dpEntity* entity) const; + NiPoint3 m_Position; NiQuaternion m_Rotation; diff --git a/dGame/dComponents/RacingControlComponent.cpp b/dGame/dComponents/RacingControlComponent.cpp index d7e01f94..21d39249 100644 --- a/dGame/dComponents/RacingControlComponent.cpp +++ b/dGame/dComponents/RacingControlComponent.cpp @@ -817,8 +817,10 @@ void RacingControlComponent::Update(float deltaTime) { // Some offset up to make they don't fall through the terrain on a // respawn, seems to fix itself to the track anyhow - player.respawnPosition = position + NiPoint3Constant::UNIT_Y * 5; - player.respawnRotation = vehicle->GetRotation(); + if (waypoint.racing.isResetNode) { + player.respawnPosition = position + NiPoint3Constant::UNIT_Y * 5; + player.respawnRotation = vehicle->GetRotation(); + } player.respawnIndex = respawnIndex; // Reached the start point, lapped diff --git a/dGame/dComponents/RigidbodyPhantomPhysicsComponent.cpp b/dGame/dComponents/RigidbodyPhantomPhysicsComponent.cpp index 30faa688..df81aab3 100644 --- a/dGame/dComponents/RigidbodyPhantomPhysicsComponent.cpp +++ b/dGame/dComponents/RigidbodyPhantomPhysicsComponent.cpp @@ -1,16 +1,57 @@ -/* - * Darkflame Universe - * Copyright 2023 - */ +// Darkflame Universe +// Copyright 2024 #include "RigidbodyPhantomPhysicsComponent.h" #include "Entity.h" +#include "dpEntity.h" +#include "CDComponentsRegistryTable.h" +#include "CDPhysicsComponentTable.h" +#include "dpWorld.h" +#include "dpShapeBox.h" +#include "dpShapeSphere.h" +#include"EntityInfo.h" + RigidbodyPhantomPhysicsComponent::RigidbodyPhantomPhysicsComponent(Entity* parent) : PhysicsComponent(parent) { m_Position = m_Parent->GetDefaultPosition(); m_Rotation = m_Parent->GetDefaultRotation(); + m_Scale = m_Parent->GetDefaultScale(); + + if (m_Parent->GetVar(u"create_physics")) { + m_dpEntity = CreatePhysicsLnv(m_Scale, ComponentType); + if (!m_dpEntity) { + m_dpEntity = CreatePhysicsEntity(ComponentType); + if (!m_dpEntity) return; + m_dpEntity->SetScale(m_Scale); + m_dpEntity->SetRotation(m_Rotation); + m_dpEntity->SetPosition(m_Position); + dpWorld::AddEntity(m_dpEntity); + } + } } void RigidbodyPhantomPhysicsComponent::Serialize(RakNet::BitStream& outBitStream, bool bIsInitialUpdate) { PhysicsComponent::Serialize(outBitStream, bIsInitialUpdate); } + +void RigidbodyPhantomPhysicsComponent::Update(const float deltaTime) { + if (!m_dpEntity) return; + + //Process enter events + for (const auto id : m_dpEntity->GetNewObjects()) { + m_Parent->OnCollisionPhantom(id); + } + + //Process exit events + for (const auto id : m_dpEntity->GetRemovedObjects()) { + m_Parent->OnCollisionLeavePhantom(id); + } +} + +void RigidbodyPhantomPhysicsComponent::SpawnVertices() const { + if (!m_dpEntity) { + LOG("No dpEntity to spawn vertices for %llu:%i", m_Parent->GetObjectID(), m_Parent->GetLOT()); + return; + } + PhysicsComponent::SpawnVertices(m_dpEntity); +} diff --git a/dGame/dComponents/RigidbodyPhantomPhysicsComponent.h b/dGame/dComponents/RigidbodyPhantomPhysicsComponent.h index 09820f8e..11595ec0 100644 --- a/dGame/dComponents/RigidbodyPhantomPhysicsComponent.h +++ b/dGame/dComponents/RigidbodyPhantomPhysicsComponent.h @@ -1,10 +1,8 @@ -/* - * Darkflame Universe - * Copyright 2023 - */ +// Darkflame Universe +// Copyright 2024 -#ifndef __RIGIDBODYPHANTOMPHYSICS_H__ -#define __RIGIDBODYPHANTOMPHYSICS_H__ +#ifndef RIGIDBODYPHANTOMPHYSICS_H +#define RIGIDBODYPHANTOMPHYSICS_H #include "BitStream.h" #include "dCommonVars.h" @@ -13,6 +11,8 @@ #include "PhysicsComponent.h" #include "eReplicaComponentType.h" +class dpEntity; + /** * Component that handles rigid bodies that can be interacted with, mostly client-side rendered. An example is the * bananas that fall from trees in GF. @@ -23,7 +23,15 @@ public: RigidbodyPhantomPhysicsComponent(Entity* parent); + void Update(const float deltaTime) override; + void Serialize(RakNet::BitStream& outBitStream, bool bIsInitialUpdate) override; + + void SpawnVertices() const; +private: + float m_Scale{}; + + dpEntity* m_dpEntity{}; }; -#endif // __RIGIDBODYPHANTOMPHYSICS_H__ +#endif // RIGIDBODYPHANTOMPHYSICS_H diff --git a/dGame/dGameMessages/GameMessages.cpp b/dGame/dGameMessages/GameMessages.cpp index 74946179..614d544c 100644 --- a/dGame/dGameMessages/GameMessages.cpp +++ b/dGame/dGameMessages/GameMessages.cpp @@ -369,8 +369,8 @@ void GameMessages::SendPlatformResync(Entity* entity, const SystemAddress& sysAd const auto lot = entity->GetLOT(); - if (lot == 12341 || lot == 5027 || lot == 5028 || lot == 14335 || lot == 14447 || lot == 14449) { - iDesiredWaypointIndex = 0; + if (lot == 12341 || lot == 5027 || lot == 5028 || lot == 14335 || lot == 14447 || lot == 14449 || lot == 11306 || lot == 11308) { + iDesiredWaypointIndex = (lot == 11306 || lot == 11308) ? 1 : 0; iIndex = 0; nextIndex = 0; bStopAtDesiredWaypoint = true; diff --git a/dGame/dUtilities/SlashCommands/DEVGMCommands.cpp b/dGame/dUtilities/SlashCommands/DEVGMCommands.cpp index bc008ab2..00add608 100644 --- a/dGame/dUtilities/SlashCommands/DEVGMCommands.cpp +++ b/dGame/dUtilities/SlashCommands/DEVGMCommands.cpp @@ -41,6 +41,7 @@ #include "ScriptedActivityComponent.h" #include "SkillComponent.h" #include "TriggerComponent.h" +#include "RigidbodyPhantomPhysicsComponent.h" // Enums #include "eGameMasterLevel.h" @@ -1129,8 +1130,13 @@ namespace DEVGMCommands { void SpawnPhysicsVerts(Entity* entity, const SystemAddress& sysAddr, const std::string args) { //Go tell physics to spawn all the vertices: auto entities = Game::entityManager->GetEntitiesByComponent(eReplicaComponentType::PHANTOM_PHYSICS); - for (auto en : entities) { - auto phys = static_cast(en->GetComponent(eReplicaComponentType::PHANTOM_PHYSICS)); + for (const auto* en : entities) { + const auto* phys = static_cast(en->GetComponent(eReplicaComponentType::PHANTOM_PHYSICS)); + if (phys) + phys->SpawnVertices(); + } + for (const auto* en : Game::entityManager->GetEntitiesByComponent(eReplicaComponentType::RIGID_BODY_PHANTOM_PHYSICS)) { + const auto* phys = en->GetComponent(); if (phys) phys->SpawnVertices(); } diff --git a/dScripts/02_server/Map/FV/Racing/CMakeLists.txt b/dScripts/02_server/Map/FV/Racing/CMakeLists.txt index 89536b67..9b2108c8 100644 --- a/dScripts/02_server/Map/FV/Racing/CMakeLists.txt +++ b/dScripts/02_server/Map/FV/Racing/CMakeLists.txt @@ -1,3 +1,6 @@ set(DSCRIPTS_SOURCES_02_SERVER_MAP_FV_RACING + "RaceFireballs.cpp" "RaceMaelstromGeiser.cpp" + "RaceShipLapColumnsServer.cpp" + "FvRacingColumns.cpp" PARENT_SCOPE) diff --git a/dScripts/02_server/Map/FV/Racing/FvRacingColumns.cpp b/dScripts/02_server/Map/FV/Racing/FvRacingColumns.cpp new file mode 100644 index 00000000..a3e3dd4a --- /dev/null +++ b/dScripts/02_server/Map/FV/Racing/FvRacingColumns.cpp @@ -0,0 +1,15 @@ +#include "FvRacingColumns.h" +#include "MovingPlatformComponent.h" + +void FvRacingColumns::OnStartup(Entity* self) { + auto* movingPlatformComponent = self->GetComponent(); + if (!movingPlatformComponent) return; + + movingPlatformComponent->StopPathing(); + movingPlatformComponent->SetSerialized(true); + int32_t pathStart = 0; + if (self->HasVar(u"attached_path_start")) { + pathStart = self->GetVar(u"attached_path_start"); + } + movingPlatformComponent->WarpToWaypoint(pathStart); +} diff --git a/dScripts/02_server/Map/FV/Racing/FvRacingColumns.h b/dScripts/02_server/Map/FV/Racing/FvRacingColumns.h new file mode 100644 index 00000000..f4555693 --- /dev/null +++ b/dScripts/02_server/Map/FV/Racing/FvRacingColumns.h @@ -0,0 +1,6 @@ +#include "CppScripts.h" + +class FvRacingColumns : public CppScripts::Script { +public: + void OnStartup(Entity* self) override; +}; diff --git a/dScripts/02_server/Map/FV/Racing/RaceFireballs.cpp b/dScripts/02_server/Map/FV/Racing/RaceFireballs.cpp new file mode 100644 index 00000000..fb0f1272 --- /dev/null +++ b/dScripts/02_server/Map/FV/Racing/RaceFireballs.cpp @@ -0,0 +1,15 @@ +#include "RaceFireballs.h" +#include "SkillComponent.h" + +void RaceFireballs::OnStartup(Entity* self) { + self->AddTimer("fire", GeneralUtils::GenerateRandomNumber(3.0f, 10.0f)); +} + +void RaceFireballs::OnTimerDone(Entity* self, std::string timerName) { + if (timerName == "fire") { + auto* skillComponent = self->GetComponent(); + if (skillComponent) skillComponent->CastSkill(894); + self->AddTimer("fire", GeneralUtils::GenerateRandomNumber(3.0f, 10.0f)); + + } +} diff --git a/dScripts/02_server/Map/FV/Racing/RaceFireballs.h b/dScripts/02_server/Map/FV/Racing/RaceFireballs.h new file mode 100644 index 00000000..e96286ae --- /dev/null +++ b/dScripts/02_server/Map/FV/Racing/RaceFireballs.h @@ -0,0 +1,9 @@ +#pragma once +#include "CppScripts.h" + +class RaceFireballs : public CppScripts::Script +{ +public: + void OnStartup(Entity* self) override; + void OnTimerDone(Entity* self, std::string timerName) override; +}; diff --git a/dScripts/02_server/Map/FV/Racing/RaceShipLapColumnsServer.cpp b/dScripts/02_server/Map/FV/Racing/RaceShipLapColumnsServer.cpp new file mode 100644 index 00000000..c0112b6a --- /dev/null +++ b/dScripts/02_server/Map/FV/Racing/RaceShipLapColumnsServer.cpp @@ -0,0 +1,47 @@ +#include "RaceShipLapColumnsServer.h" + +#include "RacingControlComponent.h" +#include "MovingPlatformComponent.h" + +void RaceShipLapColumnsServer::OnStartup(Entity* self) { + self->SetVar(u"Lap2Complete", false); + self->SetVar(u"Lap3Complete", false); +} + +void SetMovingToWaypoint(const int32_t waypointIndex, const std::string group) { + const auto entities = Game::entityManager->GetEntitiesInGroup(group); + if (entities.empty()) return; + + auto* entity = entities[0]; + entity->SetIsGhostingCandidate(false); + + auto* movingPlatfromComponent = entity->GetComponent(); + if (!movingPlatfromComponent) return; + + movingPlatfromComponent->SetSerialized(true); + movingPlatfromComponent->GotoWaypoint(waypointIndex); + Game::entityManager->SerializeEntity(entity); +} + +void RaceShipLapColumnsServer::OnCollisionPhantom(Entity* self, Entity* target) { + if (!target) return; + + const auto racingControllers = Game::entityManager->GetEntitiesByComponent(eReplicaComponentType::RACING_CONTROL); + if (racingControllers.empty()) return; + + auto* racingControlComponent = racingControllers[0]->GetComponent(); + if (!racingControlComponent) return; + + const auto* player = racingControlComponent->GetPlayerData(target->GetObjectID()); + if (!player) return; + + if (player->lap == 1 && !self->GetVar(u"Lap2Complete")) { + self->SetVar(u"Lap2Complete", true); + SetMovingToWaypoint(1, "Lap2Column"); + SetMovingToWaypoint(0, "Lap2Ramp"); + } else if (player->lap == 2 && !self->GetVar(u"Lap3Complete")) { + self->SetVar(u"Lap3Complete", true); + SetMovingToWaypoint(1, "Lap3Column"); + SetMovingToWaypoint(0, "Lap3Ramp"); + } +} diff --git a/dScripts/02_server/Map/FV/Racing/RaceShipLapColumnsServer.h b/dScripts/02_server/Map/FV/Racing/RaceShipLapColumnsServer.h new file mode 100644 index 00000000..b8a26825 --- /dev/null +++ b/dScripts/02_server/Map/FV/Racing/RaceShipLapColumnsServer.h @@ -0,0 +1,8 @@ +#pragma once +#include "CppScripts.h" + +class RaceShipLapColumnsServer : public CppScripts::Script { +public: + void OnStartup(Entity* self) override; + void OnCollisionPhantom(Entity* self, Entity* target) override; +}; diff --git a/dScripts/CppScripts.cpp b/dScripts/CppScripts.cpp index 9018c3f4..12c730fa 100644 --- a/dScripts/CppScripts.cpp +++ b/dScripts/CppScripts.cpp @@ -154,6 +154,11 @@ #include "FvBounceOverWall.h" #include "FvFong.h" #include "FvMaelstromGeyser.h" +#include "FvRaceDragon.h" +#include "FvRacePillarABCServer.h" +#include "FvRacePillarDServer.h" +#include "RaceFireballs.h" +#include "RaceShipLapColumnsServer.h" // FB Scripts #include "AgJetEffectServer.h" @@ -179,6 +184,7 @@ #include "RaceMaelstromGeiser.h" #include "FvRaceSmashEggImagineServer.h" #include "RaceSmashServer.h" +#include "FvRacingColumns.h" // NT Scripts #include "NtSentinelWalkwayServer.h" @@ -622,9 +628,25 @@ CppScripts::Script* const CppScripts::GetScript(Entity* parent, const std::strin script = new FvBounceOverWall(); else if (scriptName == "scripts\\02_server\\Map\\FV\\L_NPC_FONG.lua") script = new FvFong(); - else if (scriptName == "scripts\\ai\\FV\\L_FV_MAELSTROM_GEYSER.lua") { + else if (scriptName == "scripts\\ai\\FV\\L_FV_MAELSTROM_GEYSER.lua") script = new FvMaelstromGeyser(); - } + else if (scriptName == "scripts\\02_server\\Map\\FV\\Racing\\RACE_SHIP_LAP_COLUMNS_SERVER.lua") + script = new RaceShipLapColumnsServer(); + + // yes we know the lap numbers dont match the file name or anim. thats what they desgined it as. + else if (scriptName == "scripts\\ai\\RACING\\OBJECTS\\FV_RACE_DRAGON_LAP1_SERVER.lua") + script = new FvRaceDragon("lap_01", 2); + else if (scriptName == "scripts\\ai\\RACING\\OBJECTS\\FV_RACE_DRAGON_LAP2_SERVER.lua") + script = new FvRaceDragon("lap_02", 0); + else if (scriptName == "scripts\\ai\\RACING\\OBJECTS\\FV_RACE_DRAGON_LAP3_SERVER.lua") + script = new FvRaceDragon("lap_03", 1); + else if (scriptName == "scripts\\ai\\RACING\\OBJECTS\\FV_RACE_PILLAR_ABC_SERVER.lua") + script = new FvRacePillarABCServer(); + else if (scriptName == "scripts\\ai\\RACING\\OBJECTS\\FV_RACE_PILLAR_D_SERVER.lua") + script = new FvRacePillarDServer(); + else if (scriptName == "scripts\\02_server\\Map\\FV\\Racing\\RACE_FIREBALLS.lua") + script = new RaceFireballs(); + //Misc: if (scriptName == "scripts\\02_server\\Map\\General\\L_EXPLODING_ASSET.lua") @@ -661,6 +683,8 @@ CppScripts::Script* const CppScripts::GetScript(Entity* parent, const std::strin script = new RaceMaelstromGeiser(); else if (scriptName == "scripts\\ai\\RACING\\OBJECTS\\FV_RACE_SMASH_EGG_IMAGINE_SERVER.lua") script = new FvRaceSmashEggImagineServer(); + else if (scriptName == "scripts\\02_server\\Map\\FV\\Racing\\FV_RACING_COLUMNS.lua") + script = new FvRacingColumns(); else if (scriptName == "scripts\\ai\\RACING\\OBJECTS\\RACE_SMASH_SERVER.lua") script = new RaceSmashServer(); diff --git a/dScripts/ai/RACING/OBJECTS/CMakeLists.txt b/dScripts/ai/RACING/OBJECTS/CMakeLists.txt index 4ef427d5..83f4b8b3 100644 --- a/dScripts/ai/RACING/OBJECTS/CMakeLists.txt +++ b/dScripts/ai/RACING/OBJECTS/CMakeLists.txt @@ -1,6 +1,10 @@ set(DSCRIPTS_SOURCES_AI_RACING_OBJECTS "RaceImagineCrateServer.cpp" "RaceImaginePowerup.cpp" + "FvRaceDragon.cpp" + "FvRacePillarServer.cpp" + "FvRacePillarABCServer.cpp" + "FvRacePillarDServer.cpp" "FvRaceSmashEggImagineServer.cpp" "RaceSmashServer.cpp" PARENT_SCOPE) diff --git a/dScripts/ai/RACING/OBJECTS/FvRaceDragon.cpp b/dScripts/ai/RACING/OBJECTS/FvRaceDragon.cpp new file mode 100644 index 00000000..cde7b809 --- /dev/null +++ b/dScripts/ai/RACING/OBJECTS/FvRaceDragon.cpp @@ -0,0 +1,30 @@ +#include "FvRaceDragon.h" +#include "RenderComponent.h" +#include "RacingControlComponent.h" + +void FvRaceDragon::OnCollisionPhantom(Entity* self, Entity* target) { + if (!target) return; + + const auto racingControllers = Game::entityManager->GetEntitiesByComponent(eReplicaComponentType::RACING_CONTROL); + if (racingControllers.empty()) return; + + auto* racingControlComponent = racingControllers[0]->GetComponent(); + if (!racingControlComponent) return; + + const auto* player = racingControlComponent->GetPlayerData(target->GetObjectID()); + if (!player) return; + + if (player->lap != m_Lap) return; + + const auto dragons = Game::entityManager->GetEntitiesInGroup("dragon"); + for (const auto& dragon : dragons) { + if (!dragon || dragon->GetLOT() != this->m_Dragon) continue; + + auto* renderComponent = dragon->GetComponent(); + if (!renderComponent) continue; + + renderComponent->PlayAnimation(dragon, m_LapAnimName); + + } + Game::entityManager->DestroyEntity(self); +} diff --git a/dScripts/ai/RACING/OBJECTS/FvRaceDragon.h b/dScripts/ai/RACING/OBJECTS/FvRaceDragon.h new file mode 100644 index 00000000..0a0320c3 --- /dev/null +++ b/dScripts/ai/RACING/OBJECTS/FvRaceDragon.h @@ -0,0 +1,15 @@ +#pragma once +#include "CppScripts.h" + +#include +#include + +class FvRaceDragon : public CppScripts::Script { +public: + FvRaceDragon(const std::string_view lapAnimName, const int32_t lap) : m_LapAnimName(lapAnimName), m_Lap(lap) {} +private: + void OnCollisionPhantom(Entity* self, Entity* target) override; + const std::string m_LapAnimName; + const int32_t m_Lap; + const LOT m_Dragon = 11898; +}; diff --git a/dScripts/ai/RACING/OBJECTS/FvRacePillarABCServer.cpp b/dScripts/ai/RACING/OBJECTS/FvRacePillarABCServer.cpp new file mode 100644 index 00000000..7023fecc --- /dev/null +++ b/dScripts/ai/RACING/OBJECTS/FvRacePillarABCServer.cpp @@ -0,0 +1,34 @@ +#include "FvRacePillarABCServer.h" +#include "RenderComponent.h" +#include "RacingControlComponent.h" + +void FvRacePillarABCServer::OnCollisionPhantom(Entity* self, Entity* target) { + if (!target) return; + + const auto racingControllers = Game::entityManager->GetEntitiesByComponent(eReplicaComponentType::RACING_CONTROL); + if (racingControllers.empty()) return; + + auto* racingControlComponent = racingControllers[0]->GetComponent(); + if (!racingControlComponent) return; + + const auto* player = racingControlComponent->GetPlayerData(target->GetObjectID()); + if (!player || player->lap != 1) return; + + PlayAnimation("crumble", "pillars", m_PillarA); + PlayAnimation("roar", "dragon", m_Dragon); + + self->AddTimer("PillarBFall", 2.5f); + self->AddTimer("PillarCFall", 3.7f); + self->AddTimer("DeleteObject", 3.8f); +} + +void FvRacePillarABCServer::OnTimerDone(Entity* self, std::string timerName) { + if (timerName == "PillarBFall") { + PlayAnimation("crumble", "pillars", m_PillarB); + } else if (timerName == "PillarCFall") { + PlayAnimation("crumble", "pillars", m_PillarC); + } else if (timerName == "DeleteObject") { + Game::entityManager->DestroyEntity(self); + } +} + diff --git a/dScripts/ai/RACING/OBJECTS/FvRacePillarABCServer.h b/dScripts/ai/RACING/OBJECTS/FvRacePillarABCServer.h new file mode 100644 index 00000000..9059fbeb --- /dev/null +++ b/dScripts/ai/RACING/OBJECTS/FvRacePillarABCServer.h @@ -0,0 +1,13 @@ +#pragma once +#include "CppScripts.h" +#include "FvRacePillarServer.h" + +class FvRacePillarABCServer : public FvRacePillarServer { + void OnCollisionPhantom(Entity* self, Entity* target) override; + void OnTimerDone(Entity* self, std::string timerName) override; +private: + const LOT m_PillarA = 11946; + const LOT m_PillarB = 11947; + const LOT m_PillarC = 11948; + const LOT m_Dragon = 11898; +}; diff --git a/dScripts/ai/RACING/OBJECTS/FvRacePillarDServer.cpp b/dScripts/ai/RACING/OBJECTS/FvRacePillarDServer.cpp new file mode 100644 index 00000000..b119352e --- /dev/null +++ b/dScripts/ai/RACING/OBJECTS/FvRacePillarDServer.cpp @@ -0,0 +1,21 @@ +#include "FvRacePillarDServer.h" +#include "RenderComponent.h" +#include "RacingControlComponent.h" + +void FvRacePillarDServer::OnCollisionPhantom(Entity* self, Entity* target) { + if (!target) return; + + const auto racingControllers = Game::entityManager->GetEntitiesByComponent(eReplicaComponentType::RACING_CONTROL); + if (racingControllers.empty()) return; + + auto* racingControlComponent = racingControllers[0]->GetComponent(); + if (!racingControlComponent) return; + + const auto* player = racingControlComponent->GetPlayerData(target->GetObjectID()); + if (!player) return; + + if (player->lap == 2) { + PlayAnimation("crumble", "pillars", m_PillarD); + PlayAnimation("roar", "dragon", m_Dragon); + } +} diff --git a/dScripts/ai/RACING/OBJECTS/FvRacePillarDServer.h b/dScripts/ai/RACING/OBJECTS/FvRacePillarDServer.h new file mode 100644 index 00000000..e8d21567 --- /dev/null +++ b/dScripts/ai/RACING/OBJECTS/FvRacePillarDServer.h @@ -0,0 +1,10 @@ +#pragma once +#include "CppScripts.h" +#include "FvRacePillarServer.h" + +class FvRacePillarDServer : public FvRacePillarServer { + void OnCollisionPhantom(Entity* self, Entity* target) override; +private: + const LOT m_PillarD = 11949; + const LOT m_Dragon = 11898; +}; diff --git a/dScripts/ai/RACING/OBJECTS/FvRacePillarServer.cpp b/dScripts/ai/RACING/OBJECTS/FvRacePillarServer.cpp new file mode 100644 index 00000000..c89cf2a2 --- /dev/null +++ b/dScripts/ai/RACING/OBJECTS/FvRacePillarServer.cpp @@ -0,0 +1,15 @@ +#include "FvRacePillarServer.h" + +#include "Game.h" +#include "EntityManager.h" +#include "RenderComponent.h" + +void FvRacePillarServer::PlayAnimation(const std::string animName, const std::string group, const LOT lot) { + const auto entities = Game::entityManager->GetEntitiesInGroup(group); + for (const auto& entity : entities) { + if (!entity || entity->GetLOT() != lot) continue; + auto* renderComponent = entity->GetComponent(); + if (!renderComponent) continue; + renderComponent->PlayAnimation(entity, animName); + } +} diff --git a/dScripts/ai/RACING/OBJECTS/FvRacePillarServer.h b/dScripts/ai/RACING/OBJECTS/FvRacePillarServer.h new file mode 100644 index 00000000..9249177a --- /dev/null +++ b/dScripts/ai/RACING/OBJECTS/FvRacePillarServer.h @@ -0,0 +1,12 @@ +#ifndef FVRACEPILLARSERVER__H +#define FVRACEPILLARSERVER__H + +#include "CppScripts.h" + +class FvRacePillarServer : public virtual CppScripts::Script { +protected: + // Plays an animation on all entities in a group with a specific LOT + void PlayAnimation(const std::string animName, const std::string group, const LOT lot); +}; + +#endif // FVRACEPILLARSERVER__H diff --git a/versions.txt b/versions.txt index 1dc48d9c..0b77997f 100644 --- a/versions.txt +++ b/versions.txt @@ -1,3 +1,5 @@ +1.2 - Dragonmaw functional +1.1 - Whole lot of fixed bugs and implemented features 1.0 - Final cleanup and bug fixing for public release 0.9 - Includes BBB without the need for a UGC server, cannon cove minigame, and bug fixes. 0.8 - Added Ninjago! and it's various features + frakjaw minigame. AG survival now works. @@ -7,4 +9,4 @@ 0.4 - Added Havok to replace Bullet, Instancing, Quickbuilds, rockets, and a ton more fixes and additions. 0.3 - FrostBurgh, Snowdrift and Snowman's Land testing version. Includes bodged systems. 0.2 - Transfer to VS2019 & Bullet -0.1 - Initial transfer from NixLU, up until BehaviorManager inclusion \ No newline at end of file +0.1 - Initial transfer from NixLU, up until BehaviorManager inclusion