#include "AmSkullkinTower.h" #include "EntityManager.h" #include "DestroyableComponent.h" #include "MovingPlatformComponent.h" #include "EntityInfo.h" #include "GameMessages.h" #include "MissionComponent.h" #include "RenderComponent.h" void AmSkullkinTower::OnStartup(Entity* self) { self->SetProximityRadius(20, "Tower"); // onPhysicsComponentReady auto* movingPlatformComponent = self->GetComponent(); if (movingPlatformComponent != nullptr) { movingPlatformComponent->StopPathing(); } SpawnLegs(self, "Left"); SpawnLegs(self, "Right"); SpawnLegs(self, "Rear"); } void AmSkullkinTower::SpawnLegs(Entity* self, const std::string& loc) { auto pos = self->GetPosition(); auto rot = self->GetRotation(); pos.y += self->GetVarAs(u"vert_offset"); auto newRot = rot; auto offset = self->GetVarAs(u"hort_offset"); auto legLOT = self->GetVar(u"legLOT"); if (legLOT == 0) { return; } std::vector config = { new LDFData(u"Leg", loc) }; EntityInfo info{}; info.lot = legLOT; info.spawnerID = self->GetObjectID(); info.settings = config; info.rot = newRot; if (loc == "Right") { const auto dir = rot.GetForwardVector(); pos.x += dir.x * offset; pos.z += dir.z * offset; info.pos = pos; } else if (loc == "Rear") { const auto dir = rot.GetRightVector(); pos.x += dir.x * offset; pos.z += dir.z * offset; info.pos = pos; } else if (loc == "Left") { const auto dir = rot.GetForwardVector() * -1; pos.x += dir.x * offset; pos.z += dir.z * offset; info.pos = pos; } info.rot = NiQuaternion::LookAt(info.pos, self->GetPosition()); auto* entity = Game::entityManager->CreateEntity(info); Game::entityManager->ConstructEntity(entity); OnChildLoaded(self, entity); } void AmSkullkinTower::OnChildLoaded(Entity* self, Entity* child) { auto legTable = self->GetVar>(u"legTable"); legTable.push_back(child->GetObjectID()); self->SetVar(u"legTable", legTable); const auto selfID = self->GetObjectID(); child->AddDieCallback([this, selfID, child]() { auto* self = Game::entityManager->GetEntity(selfID); auto* destroyableComponent = child->GetComponent(); if (destroyableComponent == nullptr || self == nullptr) { return; } NotifyDie(self, child, destroyableComponent->GetKiller()); }); } void AmSkullkinTower::NotifyDie(Entity* self, Entity* other, Entity* killer) { auto players = self->GetVar>(u"Players"); const auto& iter = std::find(players.begin(), players.end(), killer->GetObjectID()); if (iter == players.end()) { players.push_back(killer->GetObjectID()); } self->SetVar(u"Players", players); OnChildRemoved(self, other); } void AmSkullkinTower::OnChildRemoved(Entity* self, Entity* child) { auto legTable = self->GetVar>(u"legTable"); const auto& iter = std::find(legTable.begin(), legTable.end(), child->GetObjectID()); if (iter != legTable.end()) { legTable.erase(iter); } self->SetVar(u"legTable", legTable); if (legTable.size() == 2) { RenderComponent::PlayAnimation(self, u"wobble-1"); } else if (legTable.size() == 1) { RenderComponent::PlayAnimation(self, u"wobble-2"); } else if (legTable.empty()) { const auto animTime = 2.5f; RenderComponent::PlayAnimation(self, u"fall"); self->AddTimer("spawnGuys", animTime - 0.2f); self->CancelTimer("RespawnLeg"); self->CancelTimer("RespawnLeg"); self->CancelTimer("RespawnLeg"); std::vector missionIDs; auto missionsString = self->GetVar(u"missions"); if (!missionsString.empty()) { // Split the missions string by '_' const auto missions = GeneralUtils::SplitString( GeneralUtils::UTF16ToWTF8(missionsString), '_' ); for (const auto& mission : missions) { const auto missionID = GeneralUtils::TryParse(mission); if (!missionID) continue; missionIDs.push_back(missionID.value()); } } const auto& players = self->GetVar>(u"Players"); for (const auto& playerID : players) { auto* player = Game::entityManager->GetEntity(playerID); if (player == nullptr) { continue; } auto* missionComponent = player->GetComponent(); if (missionComponent == nullptr) { continue; } for (const auto missionID : missionIDs) { missionComponent->ForceProgressValue(missionID, 1, self->GetLOT()); } //missionComponent->ForceProgressValue(1305, 1, self->GetLOT()); } } auto deadLegs = self->GetVar>(u"DeadLegs"); const auto& leg = child->GetVar(u"Leg"); const auto& legIter = std::find(deadLegs.begin(), deadLegs.end(), leg); if (legIter == deadLegs.end()) { deadLegs.push_back(leg); } self->SetVar(u"DeadLegs", deadLegs); self->AddTimer("RespawnLeg", 20); } void AmSkullkinTower::OnProximityUpdate(Entity* self, Entity* entering, std::string name, std::string status) { if (status != "LEAVE") { return; } auto players = self->GetVar>(u"Players"); const auto& iter = std::find(players.begin(), players.end(), entering->GetObjectID()); if (iter != players.end()) { players.erase(iter); } self->SetVar(u"Players", players); } void AmSkullkinTower::OnTimerDone(Entity* self, std::string timerName) { if (timerName == "RespawnLeg") { auto deadLegs = self->GetVar>(u"DeadLegs"); if (deadLegs.empty()) { return; } SpawnLegs(self, deadLegs[0]); deadLegs.erase(deadLegs.begin()); self->SetVar>(u"DeadLegs", deadLegs); } else if (timerName == "spawnGuys") { EntityInfo info{}; info.lot = self->GetVar(u"enemyToSpawn"); auto pos = self->GetPosition(); pos.y += 7; info.pos = pos; info.rot = self->GetRotation(); info.spawnerID = self->GetObjectID(); for (size_t i = 0; i < 2; i++) { info.pos.x += i * 2; // Just to set the apart a bit auto* entity = Game::entityManager->CreateEntity(info); Game::entityManager->ConstructEntity(entity); } self->AddTimer("killTower", 0.7f); } else if (timerName == "killTower") { self->Smash(self->GetObjectID()); } }