#include "BasePropertyServer.h" #include "GameMessages.h" #include "EntityManager.h" #include "dZoneManager.h" #include "Character.h" #include "DestroyableComponent.h" #include "Entity.h" #include "RenderComponent.h" #include "PropertyManagementComponent.h" #include "MissionComponent.h" #include "eMissionTaskType.h" #include "eMissionState.h" void BasePropertyServer::SetGameVariables(Entity* self) { self->SetVar(ClaimMarkerGroup, ""); self->SetVar(GeneratorGroup, ""); self->SetVar(GuardGroup, ""); self->SetVar(PropertyPlaqueGroup, ""); self->SetVar(PropertyVendorGroup, ""); self->SetVar(SpotsGroup, ""); self->SetVar(MSCloudsGroup, ""); self->SetVar(EnemiesGroup, ""); self->SetVar(FXManagerGroup, ""); self->SetVar(ImagOrbGroup, ""); self->SetVar(GeneratorFXGroup, ""); self->SetVar>(EnemiesSpawner, {}); self->SetVar(ClaimMarkerSpawner, ""); self->SetVar(GeneratorSpawner, ""); self->SetVar(DamageFXSpawner, ""); self->SetVar(FXSpotsSpawner, ""); self->SetVar(PropertyMGSpawner, ""); self->SetVar(ImageOrbSpawner, ""); self->SetVar(GeneratorFXSpawner, ""); self->SetVar(SmashablesSpawner, ""); self->SetVar(FXManagerSpawner, ""); self->SetVar(PropObjsSpawner, ""); self->SetVar>(AmbientFXSpawner, {}); self->SetVar>(BehaviorObjsSpawner, {}); self->SetVar(defeatedProperyFlag, 0); self->SetVar(placedModelFlag, 0); self->SetVar(guardMissionFlag, 0); self->SetVar(brickLinkMissionIDFlag, 0); self->SetVar(passwordFlag, "s3kratK1ttN"); self->SetVar(generatorIdFlag, 0); self->SetVar(orbIDFlag, 0); self->SetVar(behaviorQBID, 0); } void BasePropertyServer::CheckForOwner(Entity* self) { if (EntityManager::Instance()->GetEntitiesInGroup(self->GetVar(PropertyPlaqueGroup)).empty()) { self->AddTimer(RunPlayerLoadedAgainTimer, 0.5f); return; } self->SetI64(PropertyOwnerVariable, GetOwner()); } void BasePropertyServer::OnStartup(Entity* self) { SetGameVariables(self); } void BasePropertyServer::OnFireEventServerSide(Entity* self, Entity* sender, std::string args, int32_t param1, int32_t param2, int32_t param3) { if (args == CheckForPropertyOwnerEvent) { sender->SetNetworkVar(PropertyOwnerIDVariable, std::to_string(self->GetVar(PropertyOwnerVariable))); } } void BasePropertyServer::BasePlayerLoaded(Entity* self, Entity* player) { CheckForOwner(self); auto rented = false; auto propertyOwner = PropertyManagementComponent::Instance()->GetOwnerId(); self->OnFireEventServerSide(self, CheckForPropertyOwnerEvent); if (propertyOwner > 0) { rented = true; } if (propertyOwner < 0) { propertyOwner = LWOOBJID_EMPTY; } self->SetNetworkVar(PropertyOwnerIDVariable, propertyOwner); if (rented) { auto plaques = EntityManager::Instance()->GetEntitiesInGroup("PropertyVendor"); for (auto* plaque : plaques) { EntityManager::Instance()->DestructEntity(plaque); } const auto& mapID = dZoneManager::Instance()->GetZone()->GetZoneID(); if (propertyOwner > 0) { auto missionComponent = player->GetComponent(); if (missionComponent != nullptr) { missionComponent->Progress( eMissionTaskType::VISIT_PROPERTY, mapID.GetMapID(), mapID.GetCloneID() ); } } GameMessages::SendStop2DAmbientSound(player, true, GUIDMaelstrom); GameMessages::SendPlay2DAmbientSound(player, GUIDPeaceful); self->AddTimer(TurnSkyOffTimer, 1.5f); // kill tornado FX and play peaceful noises if (!self->GetBoolean(FXObjectsGoneVariable)) { self->AddTimer(KillFXObjectTimer, 1.0f); } GameMessages::SendPlay2DAmbientSound(player, GUIDPeaceful); // activate property safe spawner network ActivateSpawner(self->GetVar(PropObjsSpawner)); // tell client script who owns the property self->SetNetworkVar(RenterVariable, std::to_string(propertyOwner)); if (player->GetObjectID() != propertyOwner) return; } else { const auto defeatedFlag = player->GetCharacter()->GetPlayerFlag(self->GetVar(defeatedProperyFlag)); self->SetNetworkVar(UnclaimedVariable, true); self->SetVar(PlayerIDVariable, player->GetObjectID()); if (!defeatedFlag) { StartMaelstrom(self, player); SpawnSpots(self); GameMessages::SendPlay2DAmbientSound(player, GUIDMaelstrom); } else { GameMessages::SendStop2DAmbientSound(player, true, GUIDMaelstrom); GameMessages::SendPlay2DAmbientSound(player, GUIDPeaceful); self->AddTimer(TurnSkyOffTimer, 1.5f); self->AddTimer(KillFXObjectTimer, 1.0f); } } PropGuardCheck(self, player); } void BasePropertyServer::PropGuardCheck(Entity* self, Entity* player) { auto missionComponent = player->GetComponent(); if (missionComponent != nullptr && missionComponent->GetMissionState(self->GetVar(guardMissionFlag)) != eMissionState::COMPLETE) { ActivateSpawner(self->GetVar(PropertyMGSpawner)); } } void BasePropertyServer::BaseZonePropertyRented(Entity* self, Entity* player) const { GameMessages::SendNotifyClientObject(self->GetObjectID(), u"PlayCinematic", 0, 0, LWOOBJID_EMPTY, "ShowProperty", UNASSIGNED_SYSTEM_ADDRESS); self->AddTimer(BoundsVisOnTimer, 2); self->SetVar(PropertyOwnerVariable, player->GetObjectID()); auto plaques = EntityManager::Instance()->GetEntitiesInGroup("PropertyVendor"); for (auto* plaque : plaques) { EntityManager::Instance()->DestructEntity(plaque); } auto brickLinkMissionID = self->GetVar(brickLinkMissionIDFlag); if (brickLinkMissionID != 0) { auto missionComponent = player->GetComponent(); if (missionComponent) missionComponent->CompleteMission(brickLinkMissionID, true); } ActivateSpawner(self->GetVar(PropObjsSpawner)); } void BasePropertyServer::BaseZonePropertyModelPlaced(Entity* self, Entity* player) const { auto* character = player->GetCharacter(); if (character == nullptr) return; auto flag = self->GetVar(placedModelFlag); if (flag) character->SetPlayerFlag(flag, true); } void BasePropertyServer::KillClouds(Entity* self) { DeactivateSpawner(self->GetVar(DamageFXSpawner)); DestroySpawner(self->GetVar(DamageFXSpawner)); } void BasePropertyServer::SpawnSpots(Entity* self) { ActivateSpawner(self->GetVar(FXSpotsSpawner)); } void BasePropertyServer::KillSpots(Entity* self) { DeactivateSpawner(self->GetVar(FXSpotsSpawner)); DestroySpawner(self->GetVar(FXSpotsSpawner)); } void BasePropertyServer::StartMaelstrom(Entity* self, Entity* player) { for (const auto& enemySpawner : self->GetVar>(EnemiesSpawner)) { ActivateSpawner(enemySpawner); } for (const auto& behaviorObjectSpawner : self->GetVar>(BehaviorObjsSpawner)) { ActivateSpawner(behaviorObjectSpawner); } ActivateSpawner(self->GetVar(DamageFXSpawner)); ActivateSpawner(self->GetVar(GeneratorSpawner)); ActivateSpawner(self->GetVar(GeneratorFXSpawner)); ActivateSpawner(self->GetVar(FXManagerSpawner)); ActivateSpawner(self->GetVar(ImageOrbSpawner)); ActivateSpawner(self->GetVar(SmashablesSpawner)); DestroySpawner(self->GetVar(ClaimMarkerSpawner)); for (const auto& ambientFXSpawner : self->GetVar>(AmbientFXSpawner)) { DestroySpawner(ambientFXSpawner); } StartTornadoFx(self); GameMessages::SendNotifyClientObject(self->GetObjectID(), u"maelstromSkyOn", 0, 0, LWOOBJID_EMPTY, "", player->GetSystemAddress()); self->AddTimer(StartGeneratorTimer, 0.0f); self->AddTimer(StartOrbTimer, 0.0f); } void BasePropertyServer::StartTornadoFx(Entity* self) const { const auto entities = EntityManager::Instance()->GetEntitiesInGroup(self->GetVar(FXManagerGroup)); if (entities.empty()) { self->AddTimer("pollTornadoFX", 0.1f); return; } for (auto* entity : entities) { auto renderComponent = entity->GetComponent(); if (renderComponent != nullptr) { renderComponent->PlayEffect(-1, u"debrisOn", "TornadoDebris"); renderComponent->PlayEffect(-1, u"VortexOn", "TornadoVortex"); renderComponent->PlayEffect(-1, u"onSilhouette", "silhouette"); } } } void BasePropertyServer::BasePlayerExit(Entity* self, Entity* player) { if (self->GetBoolean(UnclaimedVariable)) { if (player->GetObjectID() == self->GetVar(PlayerIDVariable)) { // Destroy all spawners } } } void BasePropertyServer::KillGuard(Entity* self) { const auto entities = EntityManager::Instance()->GetEntitiesInGroup(self->GetVar(GuardGroup)); if (entities.empty()) return; DeactivateSpawner(self->GetVar(PropertyMGSpawner)); auto* guard = entities[0]; guard->Smash(self->GetObjectID()); } void BasePropertyServer::RequestDie(Entity* self, Entity* other) { auto destroyable = other->GetComponent(); if (destroyable == nullptr) return; destroyable->Smash(other->GetObjectID(), eKillType::SILENT); } void BasePropertyServer::ActivateSpawner(const std::string& spawnerName) { for (auto* spawner : dZoneManager::Instance()->GetSpawnersByName(spawnerName)) { spawner->Activate(); } } void BasePropertyServer::DeactivateSpawner(const std::string& spawnerName) { for (auto* spawner : dZoneManager::Instance()->GetSpawnersByName(spawnerName)) { spawner->Deactivate(); } } void BasePropertyServer::TriggerSpawner(const std::string& spawnerName) { for (auto* spawner : dZoneManager::Instance()->GetSpawnersInGroup(spawnerName)) { spawner->Spawn(); } } void BasePropertyServer::ResetSpawner(const std::string& spawnerName) { for (auto* spawner : dZoneManager::Instance()->GetSpawnersByName(spawnerName)) { spawner->Reset(); } } void BasePropertyServer::DestroySpawner(const std::string& spawnerName) { for (auto* spawner : dZoneManager::Instance()->GetSpawnersByName(spawnerName)) { if (!spawner) return; spawner->DestroyAllEntities(); spawner->Deactivate(); } } LWOOBJID BasePropertyServer::GetOwner() { auto* manager = PropertyManagementComponent::Instance(); return manager == nullptr ? LWOOBJID_EMPTY : manager->GetOwnerId(); } void BasePropertyServer::BaseTimerDone(Entity* self, const std::string& timerName) { if (timerName == StartGeneratorTimer) { HandleGeneratorTimer(self); } else if (timerName == StartOrbTimer) { HandleOrbsTimer(self); } else if (timerName == StartQuickbuildTimer) { HandleQuickBuildTimer(self); } else if (timerName == "GuardFlyAway") { const auto zoneId = dZoneManager::Instance()->GetZone()->GetWorldID(); // No guard for the spider instance fight if (dZoneManager::Instance()->GetZoneID().GetMapID() == 1150) return; const auto entities = EntityManager::Instance()->GetEntitiesInGroup(self->GetVar(GuardGroup)); if (entities.empty()) return; auto* guard = entities[0]; GameMessages::SendNotifyClientObject(EntityManager::Instance()->GetZoneControlEntity()->GetObjectID(), u"GuardChat", 0, 0, guard->GetObjectID(), "", UNASSIGNED_SYSTEM_ADDRESS); self->AddTimer(KillGuardTimer, 5.0f); } else if (timerName == KillGuardTimer) { KillGuard(self); } else if (timerName == TornadoOffTimer) { auto fxManagers = EntityManager::Instance()->GetEntitiesInGroup(self->GetVar(FXManagerGroup)); for (auto* fxManager : fxManagers) { auto renderComponent = fxManager->GetComponent(); if (renderComponent != nullptr) { renderComponent->StopEffect("TornadoDebris", false); renderComponent->StopEffect("TornadoVortex", false); renderComponent->StopEffect("silhouette", false); } } self->AddTimer(ShowClearEffectsTimer, 2); } else if (timerName == ShowClearEffectsTimer) { auto fxManagers = EntityManager::Instance()->GetEntitiesInGroup(self->GetVar(FXManagerGroup)); for (auto* fxManager : fxManagers) { auto renderComponent = fxManager->GetComponent(); if (renderComponent != nullptr) renderComponent->PlayEffect(-1, u"beamOn", "beam"); } self->AddTimer(KillStrombiesTimer, 2.0f); self->AddTimer(TurnSkyOffTimer, 1.5f); self->AddTimer(KillFXObjectTimer, 8.0f); } else if (timerName == TurnSkyOffTimer) { auto* controller = dZoneManager::Instance()->GetZoneControlObject(); GameMessages::SendNotifyClientObject(controller->GetObjectID(), u"SkyOff", 0, 0, LWOOBJID_EMPTY, "", UNASSIGNED_SYSTEM_ADDRESS); } else if (timerName == KillStrombiesTimer) { const auto enemies = EntityManager::Instance()->GetEntitiesInGroup(self->GetVar(EnemiesGroup)); for (auto* enemy : enemies) { RequestDie(self, enemy); } DestroySpawner(self->GetVar(SmashablesSpawner)); KillSpots(self); auto* player = EntityManager::Instance()->GetEntity(self->GetVar(PlayerIDVariable)); if (player == nullptr) return; GameMessages::SendStop2DAmbientSound(player, true, GUIDMaelstrom); GameMessages::SendPlay2DAmbientSound(player, GUIDPeaceful); self->AddTimer(ShowVendorTimer, 5.0f); } else if (timerName == KillMarkerTimer) { DestroySpawner(self->GetVar(ClaimMarkerSpawner)); for (const auto& behaviorObjectSpawner : self->GetVar>(BehaviorObjsSpawner)) { DestroySpawner(behaviorObjectSpawner); } for (auto* entity : EntityManager::Instance()->GetEntitiesInGroup(self->GetVar(ImagOrbGroup))) { entity->Smash(); } DestroySpawner(self->GetVar(ImageOrbSpawner)); self->AddTimer(ShowVendorTimer, 1.0f); } else if (timerName == ShowVendorTimer) { GameMessages::SendNotifyClientObject(EntityManager::Instance()->GetZoneControlEntity()->GetObjectID(), u"vendorOn", 0, 0, LWOOBJID_EMPTY, "", UNASSIGNED_SYSTEM_ADDRESS); for (const auto& ambientFXSpawner : self->GetVar>(AmbientFXSpawner)) { ActivateSpawner(ambientFXSpawner); } } else if (timerName == BoundsVisOnTimer) { GameMessages::SendNotifyClientObject(self->GetObjectID(), u"boundsAnim", 0, 0, LWOOBJID_EMPTY, "", UNASSIGNED_SYSTEM_ADDRESS); } else if (timerName == RunPlayerLoadedAgainTimer) { CheckForOwner(self); } else if (timerName == PollTornadoFXTimer) { StartTornadoFx(self); } else if (timerName == KillFXObjectTimer) { const auto fxManagers = EntityManager::Instance()->GetEntitiesInGroup(self->GetVar(FXManagerGroup)); if (fxManagers.empty()) { self->AddTimer(KillFXObjectTimer, 1.0f); return; } for (auto* fxManager : fxManagers) { auto renderComponent = fxManager->GetComponent(); if (renderComponent != nullptr) { renderComponent->StopEffect("beam"); } } DestroySpawner(self->GetVar(FXManagerSpawner)); self->SetVar(u"FXObjectGone", true); } } void BasePropertyServer::HandleOrbsTimer(Entity* self) { self->SetVar(CollidedVariable, false); auto orbs = EntityManager::Instance()->GetEntitiesInGroup(self->GetVar(ImagOrbGroup)); if (orbs.empty()) { self->AddTimer(StartOrbTimer, 0.5f); return; } for (auto* orb : orbs) { orb->AddCollisionPhantomCallback([self, this](Entity* other) { if (other != nullptr && other->IsPlayer() && !self->GetVar(CollidedVariable)) { self->SetVar(CollidedVariable, true); KillClouds(self); DeactivateSpawner(self->GetVar(GeneratorSpawner)); for (const auto& enemySpawner : self->GetVar>(EnemiesSpawner)) { DeactivateSpawner(enemySpawner); } DestroySpawner(self->GetVar(GeneratorFXSpawner)); GameMessages::SendNotifyClientObject(EntityManager::Instance()->GetZoneControlEntity()->GetObjectID(), u"PlayCinematic", 0, 0, LWOOBJID_EMPTY, "DestroyMaelstrom", UNASSIGNED_SYSTEM_ADDRESS); // Notifies the client that the property has been claimed with a flag, completes missions too auto* player = EntityManager::Instance()->GetEntity(self->GetVar(PlayerIDVariable)); if (player != nullptr) { auto* character = player->GetCharacter(); if (character != nullptr) { character->SetPlayerFlag(self->GetVar(defeatedProperyFlag), true); } } self->AddTimer(TornadoOffTimer, 0.5f); self->AddTimer(KillMarkerTimer, 0.7f); } }); } } void BasePropertyServer::HandleGeneratorTimer(Entity* self) { auto generators = EntityManager::Instance()->GetEntitiesInGroup(self->GetVar(GeneratorGroup)); if (generators.empty()) { self->AddTimer(StartGeneratorTimer, 0.5f); return; } for (auto* generator : generators) { generator->AddDieCallback([self, this]() { ActivateSpawner(self->GetVar(ClaimMarkerSpawner)); self->AddTimer(StartQuickbuildTimer, 0.0f); for (const auto& enemySpawner : self->GetVar>(EnemiesSpawner)) { DeactivateSpawner(enemySpawner); } DeactivateSpawner(self->GetVar(GeneratorSpawner)); }); } } void BasePropertyServer::HandleQuickBuildTimer(Entity* self) { auto claimMarkers = EntityManager::Instance()->GetEntitiesInGroup(self->GetVar(ClaimMarkerGroup)); if (claimMarkers.empty()) { self->AddTimer(StartQuickbuildTimer, 0.5f); return; } for (auto* claimMarker : claimMarkers) { // TODO: Send password? } }