DarkflameServer/dScripts/ai/NS/NsConcertQuickBuild.cpp
David Markowitz 455f9470a5
Move EntityManager to Game namespace (#1140)
* Move EntityManager to Game namespace

* move initialization to later

Need to wait for dZoneManager to be initialized.

* Fix bugs

- Cannot delete from a RandomAccessIterator while in a range based for loop.

Touchup zone manager initialize

replace magic numbers with better named constants
replace magic zonecontrol id with a more readable hex alternative
condense stack variables
move initializers closer to their use
initialize entity manager with zone control

change initialize timings

If zone is not zero we expect to initialize the entity manager during zone manager initialization

Add constexpr for zone control LOT

* Add proper error handling

* revert vanity changes

* Update WorldServer.cpp

* Update dZoneManager.cpp
2023-07-15 13:56:33 -07:00

225 lines
7.9 KiB
C++

#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<LOT, QuickBuildSet> 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<std::string, std::string> NsConcertQuickBuild::quickBuildFX{
{"discoball", "effectsDiscoball"},
{"speaker", "effectsShell"},
{"speakerHill", "effectsHill"},
{"spotlight", "effectsHill"},
{"discofloor", "effectsShell"},
{"flamethrower", "effectsShell"},
{"stagelights", "effectsShell"}
};
std::vector<LWOOBJID> 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 = Game::entityManager->GetEntitiesInGroup("CB_" + std::to_string(groupNumber));
if (managerObjects.empty())
return;
auto* managerObject = managerObjects.at(0);
self->SetVar<LWOOBJID>(u"managerObject", managerObject->GetObjectID());
self->SetVar<int32_t>(u"groupNumber", groupNumber);
// Makes the quick build blink after a certain amount of time
self->AddCallbackTimer(GetBlinkTime(resetActivatorTime), [self]() {
self->SetNetworkVar<float>(u"startEffect", NsConcertQuickBuild::GetBlinkTime(resetActivatorTime));
});
// Destroys the quick build after a while if it wasn't built
self->AddCallbackTimer(resetActivatorTime, [self]() {
self->SetNetworkVar<float>(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 = Game::entityManager->GetEntity(self->GetVar<LWOOBJID>(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<int32_t>(u"groupNumber");
finishedQuickBuilds.push_back(self->GetObjectID());
self->SetNetworkVar<float>(u"startEffect", -1.0f);
ProgressStageCraft(self, target);
// Find all the quick build objects of the same lot
auto finishedQuickBuildObjects = std::vector<Entity*>();
for (auto quickBuildID : finishedQuickBuilds) {
const auto quickBuildObject = Game::entityManager->GetEntity(quickBuildID);
if (quickBuildObject && quickBuildObject->GetLOT() == self->GetLOT()) {
quickBuildObject->SetVar<LWOOBJID>(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 = Game::entityManager->GetEntitiesInGroup("ConcertPlatforms");
for (auto* movingPlatform : movingPlatforms) {
auto* component = movingPlatform->GetComponent<MovingPlatformComponent>();
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<float>(u"startEffect", -1.0f);
quickBuild->CancelAllTimers();
// Indicate that the stage will reset
quickBuild->AddCallbackTimer(GetBlinkTime(resetStageTime), [quickBuild]() {
quickBuild->SetNetworkVar<float>(u"startEffect", GetBlinkTime(resetTime));
});
// Reset the stage
quickBuild->AddCallbackTimer(resetStageTime, [quickBuild]() {
CancelEffects(quickBuild);
quickBuild->SetNetworkVar<float>(u"startEffect", -1);
quickBuild->Smash();
});
auto* destroyableComponent = quickBuild->GetComponent<DestroyableComponent>();
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<float>(u"startEffect", NsConcertQuickBuild::GetBlinkTime(resetActivatorTime));
});
// Destroys the quick build after a while if it wasn't built
self->AddCallbackTimer(resetTime, [self]() {
self->SetNetworkVar<float>(u"startEffect", -1.0f);
self->Smash(self->GetObjectID());
});
}
void NsConcertQuickBuild::ProgressStageCraft(Entity* self, Entity* player) {
auto* missionComponent = player->GetComponent<MissionComponent>();
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<LWOOBJID>(u"Player_" + (GeneralUtils::to_u16string(i)));
if (playerID != LWOOBJID_EMPTY) {
const auto player = Game::entityManager->GetEntity(playerID);
if (player) {
auto playerMissionComponent = player->GetComponent<MissionComponent>();
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 = Game::entityManager->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 = Game::entityManager->GetEntitiesInGroup(quickBuildFX.at(effectName));
for (auto* effectObject : effectObjects) {
GameMessages::SendStopFXEffect(effectObject, true, effectName + "Effect");
}
}
}