diff --git a/dGame/dComponents/SwitchComponent.cpp b/dGame/dComponents/SwitchComponent.cpp index 7c38fba11..205491cfc 100644 --- a/dGame/dComponents/SwitchComponent.cpp +++ b/dGame/dComponents/SwitchComponent.cpp @@ -77,6 +77,7 @@ void SwitchComponent::EntityEnter(Entity* entity) { m_Active = true; if (!m_Parent) return; m_Parent->TriggerEvent(eTriggerEventType::ACTIVATED, entity); + for (const auto& callback : std::vector(m_ActivationCallbacks)) callback(true); const auto grpName = m_Parent->GetVarAsString(u"grp_name"); @@ -114,6 +115,7 @@ void SwitchComponent::Run(float deltaTime) { m_Active = false; if (!m_Parent) return; m_Parent->TriggerEvent(eTriggerEventType::DEACTIVATED, m_Parent); + for (const auto& callback : std::vector(m_ActivationCallbacks)) callback(false); const auto grpName = m_Parent->GetVarAsString(u"grp_name"); diff --git a/dGame/dComponents/SwitchComponent.h b/dGame/dComponents/SwitchComponent.h index 88763647e..b7d9aa0cb 100644 --- a/dGame/dComponents/SwitchComponent.h +++ b/dGame/dComponents/SwitchComponent.h @@ -8,6 +8,7 @@ #include "QuickBuildComponent.h" #include "BouncerComponent.h" #include +#include #include "Component.h" #include "eReplicaComponentType.h" @@ -72,6 +73,12 @@ public: */ static SwitchComponent* GetClosestSwitch(NiPoint3 position); + /** + * Calls back when the switch is activated (true) and when it is deactivated (false): what an object's script asks + * a switch for with a notification request for ObjectActivated and ObjectDeactivated + */ + void AddActivationCallback(const std::function& callback) { m_ActivationCallbacks.push_back(callback); } + const std::vector& GetFactionsToRespondTo() const { return m_FactionsToRespondTo; } @@ -113,6 +120,8 @@ private: BouncerComponent* m_PetBouncer = nullptr; std::vector m_FactionsToRespondTo{}; + + std::vector> m_ActivationCallbacks; }; #endif // SWITCHCOMPONENT_H diff --git a/dScripts/02_server/Map/General/CMakeLists.txt b/dScripts/02_server/Map/General/CMakeLists.txt index 221faebea..cb07588fe 100644 --- a/dScripts/02_server/Map/General/CMakeLists.txt +++ b/dScripts/02_server/Map/General/CMakeLists.txt @@ -15,6 +15,7 @@ set(DSCRIPTS_SOURCES_02_SERVER_MAP_GENERAL "PropertyPlatform.cpp" "QbEnemyStunner.cpp" "QbSpawner.cpp" + "SimpleMoverSwitch.cpp" "SimpleOnceOnlyMoverSpinnerEvent.cpp" "StoryBoxInteractServer.cpp" "TokenConsoleServer.cpp" diff --git a/dScripts/02_server/Map/General/SimpleMoverSwitch.cpp b/dScripts/02_server/Map/General/SimpleMoverSwitch.cpp new file mode 100644 index 000000000..868993735 --- /dev/null +++ b/dScripts/02_server/Map/General/SimpleMoverSwitch.cpp @@ -0,0 +1,37 @@ +#include "SimpleMoverSwitch.h" + +#include "Entity.h" +#include "EntityManager.h" +#include "MovingPlatformComponent.h" +#include "SwitchComponent.h" + +void SimpleMoverSwitch::OnStartup(Entity* self) { + RequestSwitches(self); +} + +// switchStartup: every switch in the group is asked for its ObjectActivated (and from then on, in turn, its +// ObjectDeactivated and ObjectActivated). A switch loaded after the platform tells its group so in live +// (objectTypeLoaded) and is asked then; here the platform looks again until it has found one. +void SimpleMoverSwitch::RequestSwitches(Entity* self) { + const auto group = self->GetVarAsString(u"switchGroup"); + if (group.empty()) return; + + bool found = false; + for (auto* const object : Game::entityManager->GetEntitiesInGroup(group)) { + if (object == self) continue; + auto* const switchComponent = object->GetComponent(); + if (!switchComponent) continue; + found = true; + switchComponent->AddActivationCallback([platformID = self->GetObjectID()](const bool active) { + auto* const platformObject = Game::entityManager->GetEntity(platformID); + if (!platformObject) return; + // notifyObjectActivated: GoToWaypoint{ iPathIndex = 1 }; notifyObjectDeactivated: GoToWaypoint{ iPathIndex = 0 } + if (auto* const platform = platformObject->GetComponent()) platform->GotoWaypoint(active ? 1 : 0); + }); + } + if (!found) self->AddTimer("FindSwitch", 1.0f); +} + +void SimpleMoverSwitch::OnTimerDone(Entity* self, std::string timerName) { + if (timerName == "FindSwitch") RequestSwitches(self); +} diff --git a/dScripts/02_server/Map/General/SimpleMoverSwitch.h b/dScripts/02_server/Map/General/SimpleMoverSwitch.h new file mode 100644 index 000000000..7ac01bf44 --- /dev/null +++ b/dScripts/02_server/Map/General/SimpleMoverSwitch.h @@ -0,0 +1,13 @@ +#pragma once +#include "CppScripts.h" + +// L_SIMPLE_MOVER_SWITCH.lua with L_BASE_SWITCH_ACTIVATED_SERVER.lua: a moving platform that a switch sends to and fro +// (the NJ monastery's ice and lightning attic puzzles). It asks the switches in its switchGroup to tell it when they +// are activated and deactivated, and goes to waypoint 1 on the one and back to waypoint 0 on the other. +class SimpleMoverSwitch : public CppScripts::Script { +public: + void OnStartup(Entity* self) override; + void OnTimerDone(Entity* self, std::string timerName) override; +private: + void RequestSwitches(Entity* self); +}; diff --git a/dScripts/CppScripts.cpp b/dScripts/CppScripts.cpp index 645792ad5..b927ab6df 100644 --- a/dScripts/CppScripts.cpp +++ b/dScripts/CppScripts.cpp @@ -272,6 +272,7 @@ #include "NjNPCMissionSpinjitzuServer.h" #include "NjJayMissionItems.h" #include "FallingTile.h" +#include "SimpleMoverSwitch.h" #include "SimpleOnceOnlyMoverSpinnerEvent.h" #include "ImaginationShrineServer.h" #include "Lieutenant.h" @@ -680,6 +681,7 @@ namespace { {"scripts\\02_server\\Map\\General\\Ninjago\\L_RAIL_POST_SERVER.lua", []() {return new NjRailPostServer();}}, {"scripts\\02_server\\Map\\General\\Ninjago\\L_ICE_RAIL_ACTIVATOR_SERVER.lua", []() {return new NjIceRailActivator();}}, {"scripts\\02_server\\Map\\njhub\\L_FALLING_TILE.lua", []() {return new FallingTile();}}, + {"scripts\\02_server\\Map\\General\\L_SIMPLE_MOVER_SWITCH.lua", []() {return new SimpleMoverSwitch();}}, {"scripts\\02_server\\Map\\firetemple\\L_SIMPLE_ONCE_ONLY_MOVER_SPINNER_EVENT.lua", []() {return new SimpleOnceOnlyMoverSpinnerEvent();}}, {"scripts\\02_server\\Enemy\\General\\L_ENEMY_NJ_BUFF_STUN_IMMUNITY.lua", []() {return new EnemyNjBuff();}}, {"scripts\\02_server\\Map\\njhub\\L_IMAGINATION_SHRINE_SERVER.lua", []() {return new ImaginationShrineServer();}}, @@ -814,7 +816,6 @@ namespace { "scripts\\ai\\GENERAL\\L_NPC_GENERIC_WANDER_SMALL.lua", // Really old alpha script "scripts\\zone\\LUPs\\Moonbase Intro\\WBL_Enemy_Grabbler.lua", // Really old alpha script, only sets wander variables "scripts\\ai\\NP\\L_NPC_NP_OLD_MAN_SHERLAND.lua", // This NPC doesn't even exist in modern crux, the only place this is used... - "scripts\\02_server\\Map\\General\\L_SIMPLE_MOVER_SWITCH.lua", // This platform does not exist even when moved manually on a client }; };