#include "NsConcertQuickBuild.h" #include "EntityManager.h" #include "NsConcertChoiceBuildManager.h" #include "DestroyableComponent.h" #include "GameMessages.h" #include "MovingPlatformComponent.h" #include "MissionComponent.h" const float NsConcertQuickBuild::resetTime = 40.0f; const float NsConcertQuickBuild::resetBlinkTime = 6.0f; const float NsConcertQuickBuild::resetStageTime = 66.5f; const float NsConcertQuickBuild::resetActivatorTime = 30.0f; const std::map NsConcertQuickBuild::quickBuildSets{ {5846, QuickBuildSet {"laser", {"discoball", "discofloor", "stagelights", "spotlight"}}}, {5847, QuickBuildSet {"spotlight", {"spotlight", "stagelights"}}}, {5848, QuickBuildSet {"rocket", {"flamethrower"}}}, {5845, QuickBuildSet {"speaker", {"speaker", "speakerHill", "stagelights", "spotlight"}}} }; const std::map NsConcertQuickBuild::quickBuildFX{ {"discoball", "effectsDiscoball"}, {"speaker", "effectsShell"}, {"speakerHill", "effectsHill"}, {"spotlight", "effectsHill"}, {"discofloor", "effectsShell"}, {"flamethrower", "effectsShell"}, {"stagelights", "effectsShell"} }; std::vector NsConcertQuickBuild::finishedQuickBuilds = {}; void NsConcertQuickBuild::OnStartup(Entity* self) { const auto groups = self->GetGroups(); if (groups.empty()) return; // Groups are of the form Concert_Laser_QB_1, Concert_Laser_QB_2, etc. auto group = groups.at(0); const auto splitGroup = GeneralUtils::SplitString(group, '_'); if (splitGroup.size() < 4) return; // Get the manager of the crate of this quick build const auto groupNumber = std::stoi(splitGroup.at(3)); const auto managerObjects = EntityManager::Instance()->GetEntitiesInGroup("CB_" + std::to_string(groupNumber)); if (managerObjects.empty()) return; auto* managerObject = managerObjects.at(0); self->SetVar(u"managerObject", managerObject->GetObjectID()); self->SetVar(u"groupNumber", groupNumber); // Makes the quick build blink after a certain amount of time self->AddCallbackTimer(GetBlinkTime(resetActivatorTime), [self]() { self->SetNetworkVar(u"startEffect", NsConcertQuickBuild::GetBlinkTime(resetActivatorTime)); }); // Destroys the quick build after a while if it wasn't built self->AddCallbackTimer(resetActivatorTime, [self]() { self->SetNetworkVar(u"startEffect", -1.0f); self->Smash(self->GetObjectID(), eKillType::SILENT); }); } float NsConcertQuickBuild::GetBlinkTime(float time) { return time <= NsConcertQuickBuild::resetBlinkTime ? 1.0f : time - NsConcertQuickBuild::resetBlinkTime; } void NsConcertQuickBuild::OnDie(Entity* self, Entity* killer) { auto* managerObject = EntityManager::Instance()->GetEntity(self->GetVar(u"managerObject")); if (managerObject) { managerObject->CancelAllTimers(); managerObject->AddCallbackTimer(1.0f, [managerObject]() { NsConcertChoiceBuildManager::SpawnCrate(managerObject); }); } auto position = std::find(finishedQuickBuilds.begin(), finishedQuickBuilds.end(), self->GetObjectID()); if (position != finishedQuickBuilds.end()) finishedQuickBuilds.erase(position); } void NsConcertQuickBuild::OnRebuildComplete(Entity* self, Entity* target) { const auto groupNumber = self->GetVar(u"groupNumber"); finishedQuickBuilds.push_back(self->GetObjectID()); self->SetNetworkVar(u"startEffect", -1.0f); ProgressStageCraft(self, target); // Find all the quick build objects of the same lot auto finishedQuickBuildObjects = std::vector(); for (auto quickBuildID : finishedQuickBuilds) { const auto quickBuildObject = EntityManager::Instance()->GetEntity(quickBuildID); if (quickBuildObject && quickBuildObject->GetLOT() == self->GetLOT()) { quickBuildObject->SetVar(u"Player_" + (GeneralUtils::to_u16string(groupNumber)), target->GetObjectID()); finishedQuickBuildObjects.push_back(quickBuildObject); } } // If all 4 sets were built, do cool stuff if (finishedQuickBuildObjects.size() >= 4) { // Move all the platforms so the user can collect the imagination brick const auto movingPlatforms = EntityManager::Instance()->GetEntitiesInGroup("ConcertPlatforms"); for (auto* movingPlatform : movingPlatforms) { auto component = movingPlatform->GetComponent(); if (component) { component->WarpToWaypoint(component->GetLastWaypointIndex()); movingPlatform->AddCallbackTimer(resetStageTime, [movingPlatform, component]() { component->WarpToWaypoint(0); }); } } ProgressLicensedTechnician(self); // Reset all timers for the quickbuilds and make them indestructible for (auto quickBuild : finishedQuickBuildObjects) { quickBuild->SetNetworkVar(u"startEffect", -1.0f); quickBuild->CancelAllTimers(); // Indicate that the stage will reset quickBuild->AddCallbackTimer(GetBlinkTime(resetStageTime), [quickBuild]() { quickBuild->SetNetworkVar(u"startEffect", GetBlinkTime(resetTime)); }); // Reset the stage quickBuild->AddCallbackTimer(resetStageTime, [quickBuild]() { CancelEffects(quickBuild); quickBuild->SetNetworkVar(u"startEffect", -1); quickBuild->Smash(); }); auto destroyableComponent = quickBuild->GetComponent(); if (destroyableComponent) destroyableComponent->SetFaction(-1); } UpdateEffects(self); return; } // If not all 4 sets were built, reset the timers that were set on spawn self->CancelAllTimers(); // Makes the quick build blink after a certain amount of time self->AddCallbackTimer(GetBlinkTime(resetTime), [self]() { self->SetNetworkVar(u"startEffect", NsConcertQuickBuild::GetBlinkTime(resetActivatorTime)); }); // Destroys the quick build after a while if it wasn't built self->AddCallbackTimer(resetTime, [self]() { self->SetNetworkVar(u"startEffect", -1.0f); self->Smash(self->GetObjectID()); }); } void NsConcertQuickBuild::ProgressStageCraft(Entity* self, Entity* player) { auto missionComponent = player->GetComponent(); if (missionComponent) { // Has to be forced as to not accidentally trigger the licensed technician achievement switch (self->GetLOT()) { case 5845: missionComponent->ForceProgress(283, 432, 5845); break; case 5846: missionComponent->ForceProgress(283, 433, 5846); break; case 5847: missionComponent->ForceProgress(283, 434, 5847); break; case 5848: missionComponent->ForceProgress(283, 435, 5848); break; default: break; } } } void NsConcertQuickBuild::ProgressLicensedTechnician(Entity* self) { for (auto i = 1; i < 5; i++) { const auto playerID = self->GetVar(u"Player_" + (GeneralUtils::to_u16string(i))); if (playerID != LWOOBJID_EMPTY) { const auto player = EntityManager::Instance()->GetEntity(playerID); if (player) { auto playerMissionComponent = player->GetComponent(); if (playerMissionComponent) playerMissionComponent->ForceProgress(598, 903, self->GetLOT()); } } } } void NsConcertQuickBuild::UpdateEffects(Entity* self) { CancelEffects(self); auto setIterator = quickBuildSets.find(self->GetLOT()); if (setIterator == quickBuildSets.end()) return; for (const auto& effectName : setIterator->second.effects) { const auto effectObjects = EntityManager::Instance()->GetEntitiesInGroup(quickBuildFX.at(effectName)); for (auto* effectObject : effectObjects) { GameMessages::SendPlayFXEffect(effectObject, 0, GeneralUtils::ASCIIToUTF16(effectName), effectName + "Effect", LWOOBJID_EMPTY, 1, 1, true); } } } void NsConcertQuickBuild::CancelEffects(Entity* self) { auto setIterator = quickBuildSets.find(self->GetLOT()); if (setIterator == quickBuildSets.end()) return; for (const auto& effectName : setIterator->second.effects) { const auto effectObjects = EntityManager::Instance()->GetEntitiesInGroup(quickBuildFX.at(effectName)); for (auto* effectObject : effectObjects) { GameMessages::SendStopFXEffect(effectObject, true, effectName + "Effect"); } } }