mirror of
https://github.com/DarkflameUniverse/DarkflameServer
synced 2024-08-30 18:43:58 +00:00
eccd6f691f
- Move code to CharacterComponent - Remove extraneous interfaces - Simplify some code greatly - Change some types to return and take in const ref (only structs larger than 8 bytes benefit from this change.) - Update code to use CharacterComponent for sending to zone instead of Player*. - Remove static storage container (static containers can be destroyed before exit/terminate handler executes)
579 lines
20 KiB
C++
579 lines
20 KiB
C++
#include "BaseSurvivalServer.h"
|
|
#include "GameMessages.h"
|
|
#include "DestroyableComponent.h"
|
|
#include "EntityManager.h"
|
|
#include "dZoneManager.h"
|
|
#include "CharacterComponent.h"
|
|
#include "eMissionTaskType.h"
|
|
#include "eMissionState.h"
|
|
#include "MissionComponent.h"
|
|
#include "Character.h"
|
|
#include "Game.h"
|
|
#include "dConfig.h"
|
|
|
|
void BaseSurvivalServer::SetGameVariables(Entity* self) {
|
|
this->constants = std::move(GetConstants());
|
|
this->mobSets = std::move(GetMobSets());
|
|
this->spawnerNetworks = std::move(GetSpawnerNetworks());
|
|
this->missionsToUpdate = std::move(GetMissionsToUpdate());
|
|
}
|
|
|
|
void BaseSurvivalServer::BasePlayerLoaded(Entity* self, Entity* player) {
|
|
const auto& waitingIter = std::find(state.waitingPlayers.begin(), state.waitingPlayers.end(), player->GetObjectID());
|
|
const auto& playersIter = std::find(state.players.begin(), state.players.end(), player->GetObjectID());
|
|
|
|
if (waitingIter != state.waitingPlayers.end() || playersIter != state.players.end()) {
|
|
auto* characterComponent = player->GetComponent<CharacterComponent>();
|
|
if (characterComponent) characterComponent->SendToZone(player->GetCharacter()->GetLastNonInstanceZoneID());
|
|
|
|
return;
|
|
}
|
|
|
|
state.waitingPlayers.push_back(player->GetObjectID());
|
|
state.players.push_back(player->GetObjectID());
|
|
|
|
self->SetNetworkVar<uint32_t>(NumberOfPlayersVariable, self->GetNetworkVar<uint32_t>(NumberOfPlayersVariable) + 1);
|
|
self->SetNetworkVar<std::string>(DefinePlayerToUIVariable, std::to_string(player->GetObjectID()), player->GetSystemAddress());
|
|
|
|
// Notify the players of all other players
|
|
if (!self->GetNetworkVar<bool>(WavesStartedVariable)) {
|
|
auto counter = 1;
|
|
for (const auto& playerID : state.players) {
|
|
self->SetNetworkVar<std::string>(UpdateScoreboardPlayersVariable + GeneralUtils::to_u16string(counter), std::to_string(playerID));
|
|
counter++;
|
|
}
|
|
|
|
self->SetNetworkVar<bool>(ShowScoreboardVariable, true);
|
|
}
|
|
|
|
SetPlayerSpawnPoints();
|
|
|
|
if (!self->GetNetworkVar<bool>(WavesStartedVariable)) {
|
|
PlayerConfirmed(self);
|
|
} else {
|
|
UpdatePlayer(self, player->GetObjectID());
|
|
GetLeaderboardData(self, player->GetObjectID(), GetActivityID(self), 50);
|
|
ResetStats(player->GetObjectID());
|
|
}
|
|
|
|
player->AddCallbackTimer(5.0f, [this, self, player]() {
|
|
self->SetNetworkVar<uint32_t>(NumberOfPlayersVariable, self->GetNetworkVar<uint32_t>(NumberOfPlayersVariable));
|
|
self->SetNetworkVar<std::string>(DefinePlayerToUIVariable, std::to_string(player->GetObjectID()), player->GetSystemAddress());
|
|
if (!self->GetNetworkVar<bool>(WavesStartedVariable)) {
|
|
auto counter = 1;
|
|
for (const auto& playerID : state.players) {
|
|
self->SetNetworkVar<std::string>(UpdateScoreboardPlayersVariable + GeneralUtils::to_u16string(counter), std::to_string(playerID));
|
|
counter++;
|
|
}
|
|
|
|
self->SetNetworkVar<bool>(ShowScoreboardVariable, true);
|
|
}
|
|
});
|
|
}
|
|
|
|
void BaseSurvivalServer::BaseStartup(Entity* self) {
|
|
self->SetVar<uint32_t>(PlayersAcceptedVariable, 0);
|
|
self->SetVar<bool>(PlayersReadyVariable, false);
|
|
}
|
|
|
|
void BaseSurvivalServer::BasePlayerExit(Entity* self, Entity* player) {
|
|
const auto& waitingIter = std::find(state.waitingPlayers.begin(), state.waitingPlayers.end(), player->GetObjectID());
|
|
const auto& playersIter = std::find(state.players.begin(), state.players.end(), player->GetObjectID());
|
|
|
|
if (waitingIter != state.waitingPlayers.end()) {
|
|
state.waitingPlayers.erase(waitingIter);
|
|
}
|
|
|
|
if (playersIter != state.players.end()) {
|
|
state.players.erase(playersIter);
|
|
}
|
|
|
|
if (waitingIter == state.waitingPlayers.end() && playersIter == state.players.end()) {
|
|
return;
|
|
}
|
|
|
|
if (!self->GetNetworkVar<bool>(WavesStartedVariable)) {
|
|
PlayerConfirmed(self);
|
|
|
|
if (state.players.empty())
|
|
return;
|
|
|
|
if (state.waitingPlayers.empty()) {
|
|
ActivityTimerStopAllTimers(self);
|
|
ActivityTimerStart(self, AllAcceptedDelayTimer, 1.0f, constants.startDelay);
|
|
} else if (state.players.size() > state.waitingPlayers.size()) {
|
|
if (!self->GetVar<bool>(AcceptedDelayStartedVariable)) {
|
|
self->SetVar<bool>(AcceptedDelayStartedVariable, true);
|
|
ActivityTimerStart(self, AcceptedDelayTimer, 1.0f, constants.acceptedDelay);
|
|
}
|
|
}
|
|
} else {
|
|
UpdatePlayer(self, player->GetObjectID(), true);
|
|
if (CheckAllPlayersDead()) {
|
|
GameOver(self);
|
|
}
|
|
}
|
|
|
|
SetActivityValue(self, player->GetObjectID(), 1, 0);
|
|
self->SetNetworkVar<uint32_t>(NumberOfPlayersVariable,
|
|
std::min(static_cast<uint32_t>(0), self->GetNetworkVar<uint32_t>(NumberOfPlayersVariable) - 1));
|
|
}
|
|
|
|
void BaseSurvivalServer::BaseFireEvent(Entity* self, Entity* sender, const std::string& args, int32_t param1, int32_t param2,
|
|
int32_t param3) {
|
|
if (args == "start") {
|
|
StartWaves(self);
|
|
} else if (args == "DeactivateRewards") {
|
|
SpawnerReset(spawnerNetworks.rewardNetworks);
|
|
} else if (sender != nullptr && IsPlayerInActivity(self, sender->GetObjectID())) {
|
|
auto currentScore = GetActivityValue(self, sender->GetObjectID(), 0);
|
|
SetActivityValue(self, sender->GetObjectID(), 0, currentScore + param1);
|
|
}
|
|
}
|
|
|
|
void BaseSurvivalServer::BasePlayerDied(Entity* self, Entity* player) {
|
|
if (self->GetNetworkVar<bool>(WavesStartedVariable)) {
|
|
const auto finalTime = ActivityTimerGetCurrentTime(self, ClockTickTimer);
|
|
SetActivityValue(self, player->GetObjectID(), 1, finalTime);
|
|
|
|
auto paramString = CheckAllPlayersDead() ? "true" : "false";
|
|
GameMessages::SendNotifyClientZoneObject(self->GetObjectID(), u"Player_Died", finalTime, 0,
|
|
player->GetObjectID(), paramString, player->GetSystemAddress());
|
|
GameOver(self);
|
|
} else {
|
|
player->Resurrect();
|
|
SetPlayerSpawnPoints();
|
|
}
|
|
}
|
|
|
|
void BaseSurvivalServer::BasePlayerResurrected(Entity* self, Entity* player) {
|
|
self->SetNetworkVar<bool>(ShowScoreboardVariable, true);
|
|
}
|
|
|
|
void BaseSurvivalServer::BaseMessageBoxResponse(Entity* self, Entity* sender, int32_t button,
|
|
const std::u16string& identifier, const std::u16string& userData) {
|
|
if (identifier == u"RePlay") {
|
|
PlayerAccepted(self, sender->GetObjectID());
|
|
PlayerConfirmed(self);
|
|
} else if (identifier == u"Exit_Question" && button == 1) {
|
|
ResetStats(sender->GetObjectID());
|
|
self->SetNetworkVar<std::string>(ExitWavesVariable, std::to_string(sender->GetObjectID()));
|
|
|
|
if (sender->IsPlayer()) {
|
|
auto* character = sender->GetCharacter();
|
|
if (character != nullptr) {
|
|
auto* characterComponent = sender->GetComponent<CharacterComponent>();
|
|
if (characterComponent) characterComponent->SendToZone(character->GetLastNonInstanceZoneID());
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void BaseSurvivalServer::OnActivityTimerUpdate(Entity* self, const std::string& name, float_t remainingTime, float_t elapsedTime) {
|
|
if (name == AcceptedDelayTimer) {
|
|
self->SetNetworkVar<uint64_t>(UpdateDefaultStartTimerVariable, remainingTime);
|
|
} else if (name == ClockTickTimer) {
|
|
self->SetNetworkVar<float_t>(UpdateTimerVariable, elapsedTime);
|
|
} else if (name == SpawnTickTimer && !self->GetVar<bool>(IsCooldownVariable)) {
|
|
SpawnMobs(self);
|
|
}
|
|
}
|
|
|
|
void BaseSurvivalServer::OnActivityTimerDone(Entity* self, const std::string& name) {
|
|
auto cooldownTime = constants.rewardInterval * constants.waveTime;
|
|
|
|
if (name == AcceptedDelayTimer) {
|
|
self->SetNetworkVar<uint64_t>(UpdateDefaultStartTimerVariable, 0);
|
|
ActivityTimerStart(self, AllAcceptedDelayTimer, 1, 1);
|
|
} else if (name == AllAcceptedDelayTimer) {
|
|
self->SetNetworkVar<bool>(ClearScoreboardVariable, true);
|
|
ActivityTimerStart(self, StartDelayTimer, 3, 3);
|
|
|
|
StartWaves(self);
|
|
} else if (name == StartDelayTimer) {
|
|
ActivityTimerStart(self, ClockTickTimer, 1);
|
|
ActivityTimerStart(self, SpawnTickTimer, constants.waveTime);
|
|
SpawnMobs(self);
|
|
ActivityTimerStart(self, PlaySpawnSoundTimer, 3, 3);
|
|
ActivityTimerStart(self, CoolDownStartTimer, cooldownTime, cooldownTime);
|
|
} else if (name == CoolDownStartTimer) {
|
|
self->SetVar<bool>(IsCooldownVariable, true);
|
|
|
|
ActivityTimerStop(self, SpawnTickTimer);
|
|
ActivityTimerStart(self, CoolDownStopTimer, 1, constants.coolDownTime);
|
|
|
|
ActivateSpawnerNetwork(spawnerNetworks.rewardNetworks);
|
|
SpawnerReset(spawnerNetworks.baseNetworks, false);
|
|
SpawnerReset(spawnerNetworks.randomNetworks, false);
|
|
} else if (name == CoolDownStopTimer) {
|
|
self->SetVar<bool>(IsCooldownVariable, false);
|
|
|
|
ActivityTimerStart(self, SpawnTickTimer, constants.waveTime);
|
|
ActivityTimerStart(self, CoolDownStartTimer, cooldownTime, cooldownTime);
|
|
|
|
SpawnMobs(self);
|
|
ActivityTimerStart(self, PlaySpawnSoundTimer, 3, 3);
|
|
} else if (name == PlaySpawnSoundTimer) {
|
|
for (const auto& playerID : state.players) {
|
|
auto* player = Game::entityManager->GetEntity(playerID);
|
|
if (player != nullptr) {
|
|
GameMessages::SendPlayNDAudioEmitter(player, player->GetSystemAddress(), spawnSoundGUID);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void BaseSurvivalServer::ResetStats(LWOOBJID playerID) {
|
|
auto* player = Game::entityManager->GetEntity(playerID);
|
|
if (player != nullptr) {
|
|
|
|
// Boost all the player stats when loading in
|
|
auto* destroyableComponent = player->GetComponent<DestroyableComponent>();
|
|
if (destroyableComponent != nullptr) {
|
|
destroyableComponent->SetHealth(destroyableComponent->GetMaxHealth());
|
|
destroyableComponent->SetArmor(destroyableComponent->GetMaxArmor());
|
|
destroyableComponent->SetImagination(destroyableComponent->GetMaxImagination());
|
|
}
|
|
}
|
|
}
|
|
|
|
void BaseSurvivalServer::PlayerConfirmed(Entity* self) {
|
|
std::vector<LWOOBJID> confirmedPlayers{};
|
|
|
|
for (const auto& playerID : state.players) {
|
|
auto pass = false;
|
|
for (const auto& waitingPlayerID : state.waitingPlayers) {
|
|
if (waitingPlayerID == playerID)
|
|
pass = true;
|
|
}
|
|
|
|
if (!pass)
|
|
confirmedPlayers.push_back(playerID);
|
|
}
|
|
|
|
auto playerIndex = 1;
|
|
for (const auto& playerID : confirmedPlayers) {
|
|
self->SetNetworkVar<std::string>(PlayerConfirmVariable + GeneralUtils::to_u16string(playerIndex), std::to_string(playerID));
|
|
playerIndex++;
|
|
}
|
|
}
|
|
|
|
void BaseSurvivalServer::PlayerAccepted(Entity* self, LWOOBJID playerID) {
|
|
const auto& iter = std::find(state.waitingPlayers.begin(), state.waitingPlayers.end(), playerID);
|
|
|
|
if (iter == state.waitingPlayers.end()) {
|
|
return;
|
|
}
|
|
|
|
state.waitingPlayers.erase(iter);
|
|
|
|
if (state.waitingPlayers.empty() && state.players.size() >= self->GetNetworkVar<uint32_t>(NumberOfPlayersVariable)) {
|
|
ActivityTimerStopAllTimers(self);
|
|
ActivityTimerStart(self, AllAcceptedDelayTimer, 1, constants.startDelay);
|
|
} else if (!self->GetVar<bool>(AcceptedDelayStartedVariable)) {
|
|
self->SetVar<bool>(AcceptedDelayStartedVariable, true);
|
|
ActivityTimerStart(self, AcceptedDelayTimer, 1, constants.acceptedDelay);
|
|
}
|
|
}
|
|
|
|
void BaseSurvivalServer::StartWaves(Entity* self) {
|
|
GameMessages::SendActivityStart(self->GetObjectID(), UNASSIGNED_SYSTEM_ADDRESS);
|
|
|
|
self->SetVar<bool>(PlayersReadyVariable, true);
|
|
self->SetVar<uint32_t>(BaseMobSetIndexVariable, 0);
|
|
self->SetVar<uint32_t>(RandMobSetIndexVariable, 0);
|
|
self->SetVar<bool>(AcceptedDelayStartedVariable, false);
|
|
|
|
state.waitingPlayers.clear();
|
|
|
|
for (const auto& playerID : state.players) {
|
|
const auto player = Game::entityManager->GetEntity(playerID);
|
|
if (player != nullptr) {
|
|
state.waitingPlayers.push_back(playerID);
|
|
UpdatePlayer(self, playerID);
|
|
GetLeaderboardData(self, playerID, GetActivityID(self), 50);
|
|
ResetStats(playerID);
|
|
|
|
if (!self->GetVar<bool>(FirstTimeDoneVariable)) {
|
|
TakeActivityCost(self, playerID);
|
|
}
|
|
|
|
GameMessages::SendPlayerSetCameraCyclingMode(playerID, player->GetSystemAddress());
|
|
}
|
|
}
|
|
|
|
self->SetVar<bool>(FirstTimeDoneVariable, true);
|
|
self->SetVar<std::string>(MissionTypeVariable, state.players.size() == 1 ? "survival_time_solo" : "survival_time_team");
|
|
|
|
ActivateSpawnerNetwork(spawnerNetworks.smashNetworks);
|
|
self->SetNetworkVar<bool>(WavesStartedVariable, true);
|
|
self->SetNetworkVar<std::string>(StartWaveMessageVariable, "Start!");
|
|
}
|
|
|
|
bool BaseSurvivalServer::CheckAllPlayersDead() {
|
|
auto deadPlayers = 0;
|
|
|
|
for (const auto& playerID : state.players) {
|
|
auto* player = Game::entityManager->GetEntity(playerID);
|
|
if (player == nullptr || player->GetIsDead()) {
|
|
deadPlayers++;
|
|
}
|
|
}
|
|
|
|
return deadPlayers >= state.players.size();
|
|
}
|
|
|
|
void BaseSurvivalServer::SetPlayerSpawnPoints() {
|
|
auto spawnerIndex = 1;
|
|
for (const auto& playerID : state.players) {
|
|
auto* player = Game::entityManager->GetEntity(playerID);
|
|
if (player != nullptr) {
|
|
auto possibleSpawners = Game::entityManager->GetEntitiesInGroup("P" + std::to_string(spawnerIndex) + "_Spawn");
|
|
if (!possibleSpawners.empty()) {
|
|
auto* spawner = possibleSpawners.at(0);
|
|
GameMessages::SendTeleport(playerID, spawner->GetPosition(), spawner->GetRotation(), player->GetSystemAddress(), true);
|
|
}
|
|
}
|
|
|
|
spawnerIndex++;
|
|
}
|
|
}
|
|
|
|
void BaseSurvivalServer::GameOver(Entity* self) {
|
|
if (!CheckAllPlayersDead())
|
|
return;
|
|
|
|
ActivityTimerStopAllTimers(self);
|
|
|
|
// Reset all the spawners
|
|
SpawnerReset(spawnerNetworks.baseNetworks);
|
|
SpawnerReset(spawnerNetworks.randomNetworks);
|
|
SpawnerReset(spawnerNetworks.rewardNetworks);
|
|
|
|
for (const auto& playerID : state.players) {
|
|
auto* player = Game::entityManager->GetEntity(playerID);
|
|
if (player == nullptr)
|
|
continue;
|
|
|
|
const auto score = GetActivityValue(self, playerID, 0);
|
|
const auto time = GetActivityValue(self, playerID, 1);
|
|
SaveScore(self, playerID, score, time);
|
|
|
|
GameMessages::SendNotifyClientZoneObject(self->GetObjectID(), u"Update_ScoreBoard", time, 0,
|
|
playerID, std::to_string(score), UNASSIGNED_SYSTEM_ADDRESS);
|
|
player->Resurrect();
|
|
|
|
// Update all mission progression
|
|
auto* missionComponent = player->GetComponent<MissionComponent>();
|
|
if (missionComponent != nullptr) {
|
|
missionComponent->Progress(eMissionTaskType::PERFORM_ACTIVITY, time, self->GetObjectID(),
|
|
self->GetVar<std::string>(MissionTypeVariable));
|
|
|
|
for (const auto& survivalMission : missionsToUpdate) {
|
|
auto* mission = missionComponent->GetMission(survivalMission.first);
|
|
if (mission != nullptr && static_cast<uint32_t>(time) >= survivalMission.second
|
|
&& (mission->GetMissionState() == eMissionState::ACTIVE
|
|
|| mission->GetMissionState() == eMissionState::COMPLETE_ACTIVE)) {
|
|
|
|
mission->Progress(eMissionTaskType::SCRIPT, self->GetLOT());
|
|
}
|
|
}
|
|
}
|
|
|
|
StopActivity(self, playerID, score, time);
|
|
}
|
|
|
|
state.waveNumber = 1;
|
|
state.rewardTick = 1;
|
|
state.totalSpawned = 0;
|
|
|
|
self->SetNetworkVar<bool>(WavesStartedVariable, false);
|
|
|
|
if (constants.useMobLots) {
|
|
constants.lotPhase = 0;
|
|
UpdateMobLots(spawnerNetworks.baseNetworks);
|
|
UpdateMobLots(spawnerNetworks.randomNetworks);
|
|
}
|
|
|
|
SetPlayerSpawnPoints();
|
|
}
|
|
|
|
void BaseSurvivalServer::SpawnerReset(SpawnerNetworkCollection& spawnerNetworkCollection, bool hardReset) {
|
|
auto totalSpawned = 0;
|
|
|
|
for (auto& spawner : spawnerNetworkCollection.networks) {
|
|
for (auto& spawnerName : spawner.names) {
|
|
auto spawners = Game::zoneManager->GetSpawnersByName(spawnerName + spawner.number);
|
|
if (!spawners.empty()) {
|
|
auto* spawnerObject = spawners.at(0);
|
|
|
|
auto amountSpawned = spawnerObject->GetAmountSpawned();
|
|
totalSpawned += amountSpawned;
|
|
|
|
spawner.isActive = false;
|
|
if (hardReset) {
|
|
spawnerObject->Reset();
|
|
} else {
|
|
spawnerObject->SoftReset();
|
|
}
|
|
|
|
spawnerObject->Deactivate();
|
|
}
|
|
}
|
|
}
|
|
|
|
state.totalSpawned = std::max(static_cast<uint32_t>(totalSpawned), state.totalSpawned);
|
|
}
|
|
|
|
void BaseSurvivalServer::SpawnerUpdate(Entity* self, SpawnerNetworkCollection& spawnerNetworkCollection, uint32_t amount) {
|
|
if (spawnerNetworkCollection.networks.empty())
|
|
return;
|
|
|
|
// If we want to spawn something specific now
|
|
if (amount != 0) {
|
|
auto spawnerNetwork = spawnerNetworkCollection.networks.at(0);
|
|
auto possibleSpawners = Game::zoneManager->GetSpawnersByName(spawnerNetwork.names.at(0) + spawnerNetwork.number);
|
|
if (!possibleSpawners.empty()) {
|
|
SpawnNow(possibleSpawners.at(0), amount);
|
|
return;
|
|
}
|
|
}
|
|
|
|
auto setNumber = self->GetVar<uint32_t>(GeneralUtils::ASCIIToUTF16(spawnerNetworkCollection.mobSetName + "Num"));
|
|
auto newSet = GetRandomMobSet(spawnerNetworkCollection, setNumber);
|
|
|
|
if (!newSet.empty()) {
|
|
auto spawnerNetwork = GetRandomSpawner(spawnerNetworkCollection);
|
|
for (auto i = 0; i < spawnerNetwork.names.size(); i++) {
|
|
const auto& name = spawnerNetwork.names.at(i);
|
|
const auto& toSpawn = newSet.at(i);
|
|
|
|
auto possibleSpawners = Game::zoneManager->GetSpawnersByName(name + spawnerNetwork.number);
|
|
if (!possibleSpawners.empty()) {
|
|
SpawnNow(possibleSpawners.front(), toSpawn);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void BaseSurvivalServer::SpawnNow(Spawner* spawner, uint32_t amount) {
|
|
if (spawner != nullptr) {
|
|
if (!spawner->m_Active) {
|
|
spawner->m_Info.amountMaintained = amount;
|
|
spawner->Activate();
|
|
} else {
|
|
spawner->m_Info.amountMaintained = amount;
|
|
}
|
|
}
|
|
}
|
|
|
|
std::vector<uint32_t> BaseSurvivalServer::GetRandomMobSet(SpawnerNetworkCollection& spawnerNetworkCollection,
|
|
uint32_t setNumber) {
|
|
|
|
if (mobSets.sets.find(spawnerNetworkCollection.mobSetName) != mobSets.sets.end()) {
|
|
auto mobSet = mobSets.sets.at(spawnerNetworkCollection.mobSetName);
|
|
if (setNumber < mobSet.size()) {
|
|
return mobSet.at(setNumber).at(GeneralUtils::GenerateRandomNumber<int32_t>(0, mobSet.at(setNumber).size() - 1));
|
|
}
|
|
}
|
|
|
|
return {};
|
|
}
|
|
|
|
SpawnerNetwork BaseSurvivalServer::GetRandomSpawner(SpawnerNetworkCollection& spawnerNetworkCollection) {
|
|
std::vector<SpawnerNetwork> validSpawners{};
|
|
for (const auto& spawner : spawnerNetworkCollection.networks) {
|
|
if (!spawner.isLocked)
|
|
validSpawners.push_back(spawner);
|
|
}
|
|
|
|
if (!validSpawners.empty()) {
|
|
auto spawner = validSpawners.at(GeneralUtils::GenerateRandomNumber<int32_t>(0, validSpawners.size() - 1));
|
|
spawner.isActive = true;
|
|
return spawner;
|
|
}
|
|
|
|
return {};
|
|
}
|
|
|
|
void BaseSurvivalServer::ActivateSpawnerNetwork(SpawnerNetworkCollection& spawnerNetworkCollection) {
|
|
for (auto& spawner : spawnerNetworkCollection.networks) {
|
|
for (const auto& spawnerName : spawner.names) {
|
|
auto possibleSpawners = Game::zoneManager->GetSpawnersByName(spawnerName + spawner.number);
|
|
if (!possibleSpawners.empty()) {
|
|
auto* spawnerObject = possibleSpawners.at(0);
|
|
spawnerObject->Activate();
|
|
spawnerObject->Reset();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void BaseSurvivalServer::UpdateMobLots(SpawnerNetworkCollection& spawnerNetworkCollection) {
|
|
for (auto& spawner : spawnerNetworkCollection.networks) {
|
|
for (auto& spawnerName : spawner.names) {
|
|
if (!spawnerName.empty()) {
|
|
auto spawnerObjects = Game::zoneManager->GetSpawnersByName(spawnerName + spawner.number);
|
|
if (!spawnerObjects.empty()) {
|
|
auto splitName = GeneralUtils::SplitString(spawnerName, '_');
|
|
auto cleanName = splitName.size() > 1 ? splitName.at(1) : splitName.at(0);
|
|
|
|
if (!cleanName.empty()) {
|
|
auto spawnerObject = spawnerObjects.at(0);
|
|
spawnerObject->SetSpawnLot(mobSets.mobLots.at(cleanName).at(constants.lotPhase));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void BaseSurvivalServer::SpawnMobs(Entity* self) {
|
|
if (!self->GetNetworkVar<bool>(WavesStartedVariable))
|
|
return;
|
|
|
|
state.waveNumber++;
|
|
auto spawnNumber = state.waveNumber > constants.rewardInterval ? state.waveNumber - state.rewardTick - 1 : state.waveNumber;
|
|
|
|
for (const auto& tier : constants.baseMobsStartTier) {
|
|
if (tier == spawnNumber)
|
|
self->SetVar<uint32_t>(BaseMobSetIndexVariable, (self->GetVar<uint32_t>(BaseMobSetIndexVariable) + 1)
|
|
% (constants.baseMobsStartTier.size() - 1));
|
|
}
|
|
|
|
for (const auto& tier : constants.randMobsStartTier) {
|
|
if (tier == spawnNumber)
|
|
self->SetVar<uint32_t>(RandMobSetIndexVariable, (self->GetVar<uint32_t>(RandMobSetIndexVariable) + 1)
|
|
% (constants.randMobsStartTier.size() - 1));
|
|
}
|
|
|
|
if (state.waveNumber == constants.unlockNetwork3)
|
|
spawnerNetworks.randomNetworks.networks.at(2).isLocked = false;
|
|
|
|
SpawnerReset(spawnerNetworks.baseNetworks, false);
|
|
SpawnerReset(spawnerNetworks.randomNetworks, false);
|
|
SpawnerUpdate(self, spawnerNetworks.baseNetworks);
|
|
|
|
if (spawnNumber >= constants.mobSet2Wave) {
|
|
if (spawnNumber == constants.mobSet2Wave)
|
|
self->SetNetworkVar<std::string>(SpawnMobVariable, "2");
|
|
SpawnerUpdate(self, spawnerNetworks.randomNetworks);
|
|
}
|
|
|
|
if (spawnNumber >= constants.mobSet3Wave) {
|
|
if (spawnNumber == constants.mobSet3Wave)
|
|
self->SetNetworkVar<std::string>(SpawnMobVariable, "3");
|
|
SpawnerUpdate(self, spawnerNetworks.randomNetworks);
|
|
}
|
|
|
|
// If we reached the end of the spawn phase we increase the lost to make it more difficult
|
|
if (constants.useMobLots && constants.lotPhase < (mobSets.mobLots.begin()->second.size() - 1)
|
|
&& spawnNumber >= constants.baseMobsStartTier.back()) {
|
|
state.waveNumber = 1;
|
|
constants.lotPhase++;
|
|
|
|
UpdateMobLots(spawnerNetworks.baseNetworks);
|
|
UpdateMobLots(spawnerNetworks.randomNetworks);
|
|
}
|
|
}
|