mirror of
https://github.com/DarkflameUniverse/DarkflameServer.git
synced 2026-10-02 02:43:44 +00:00
EventGating (eventName, date_start, date_end; 8 rows) is only in the
CDClient for the server: the 1.10.64 client has no string for it. The
dates are Unix times (UTC), inclusive: pirateDay 2011-09-19 00:00 to
2011-09-20 23:59:59 (Talk Like a Pirate Day), buildNexusTower 2010-03-09
to 2011-03-14, buildNexusTowerEnd, frostburgh2010_notused and test rows.
The live Lua asked for an event with GetHolidayEvent{eventToCheck =
name}.isValid; the only callers are the Crux Prime random spawners
(L_BASE_RANDOM_SPAWNER.lua, L_AM_ZONE_SERVER.lua), whose only event is
pirateDay. DLU's BaseRandomServer::CheckEvents was a TODO.
- CDEventGatingTable loads the table; HolidayEvents::IsActive(name) is
true while the dates include now, or when event_1..event_8 names the
event (every live date is in 2010/2011, so this is how a server turns
one on; the same settings already switch gatingOnFeature objects).
- BaseRandomServer::CheckEvents: during pirateDay the str and zip areas
use the event loads from the Lua (80%: 5 pirates on each of type1-3,
20%: 5 admirals each; multipliers secA 1, secB 1, secC 1.2 for str).
Inferred: every spawner's Lua put the whole {str, zip} table in its
zones, which its getRandomLoad walks with ipairs and so finds no load;
DLU uses each table for the area it names, as L_AM_ZONE_SERVER.lua's
layout intends.
- sharedconfig.ini says event_N also takes EventGating names.
Check in game: with event_2=pirateDay in sharedconfig.ini, the Crux Prime
areas filled by the str and zip random spawners (spawner networks
em_str_* and em_zip_*) spawn only Maelstrom pirates and admirals; the
other two areas and a server without the setting spawn the usual mix.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
189 lines
4.9 KiB
C++
189 lines
4.9 KiB
C++
#include "BaseRandomServer.h"
|
|
#include "dZoneManager.h"
|
|
#include "Spawner.h"
|
|
#include "Logger.h"
|
|
#include "Entity.h"
|
|
#include "HolidayEvents.h"
|
|
|
|
void BaseRandomServer::BaseStartup(Entity* self) {
|
|
self->SetVar<std::string>(u"SpawnState", "min");
|
|
self->SetVar<bool>(u"JustChanged", false);
|
|
|
|
CheckEvents(self);
|
|
SpawnMapZones(self);
|
|
}
|
|
|
|
void BaseRandomServer::CheckEvents(Entity* self) {
|
|
// L_BASE_RANDOM_SPAWNER.lua: while a holiday event runs, its loads replace the spawner's. The only event the Crux
|
|
// Prime spawners check is pirateDay, with loads for the str and zip areas (each spawner's Lua carries both tables;
|
|
// each is used here for the area it names)
|
|
if (zoneName != "str" && zoneName != "zip") return;
|
|
if (!HolidayEvents::IsActive("pirateDay")) return;
|
|
|
|
constexpr LOT pirate = 11215;
|
|
constexpr LOT admiral = 11216;
|
|
zones = {
|
|
{ { { pirate, 5, "type1" }, { pirate, 5, "type2" }, { pirate, 5, "type3" } }, 80 },
|
|
{ { { admiral, 5, "type1" }, { admiral, 5, "type2" }, { admiral, 5, "type3" } }, 20 },
|
|
};
|
|
if (zoneName == "str") sectionMultipliers = { { "secA", 1.0f }, { "secB", 1.0f }, { "secC", 1.2f } };
|
|
else sectionMultipliers = { { "secA", 1.0f }, { "secB", 1.0f } };
|
|
}
|
|
|
|
void BaseRandomServer::SpawnMapZones(Entity* self) {
|
|
for (const auto& pair : sectionMultipliers) {
|
|
const auto sectionName = zonePrefix + "_" + zoneName + "_" + pair.first;
|
|
|
|
SpawnSection(self, sectionName, pair.second);
|
|
}
|
|
|
|
if (zoneName == "str") {
|
|
SpawnNamedEnemy(self);
|
|
}
|
|
|
|
self->SetVar(u"bInit", true);
|
|
}
|
|
|
|
void BaseRandomServer::SpawnSection(Entity* self, const std::string& sectionName, float iMultiplier) {
|
|
Zone* spawnLoad = GetRandomLoad(self, sectionName);
|
|
|
|
if (spawnLoad == nullptr) {
|
|
LOG("Failed to find section: %s", sectionName.c_str());
|
|
|
|
return;
|
|
}
|
|
|
|
for (const auto& spawnerData : spawnLoad->entries) {
|
|
if (spawnerData.name.empty()) {
|
|
continue;
|
|
}
|
|
|
|
const auto spawnNum = std::floor(spawnerData.num * iMultiplier);
|
|
const auto spawnerName = sectionName + "_" + spawnerData.name;
|
|
|
|
SetSpawnerNetwork(self, spawnerName, spawnNum, spawnerData.lot);
|
|
}
|
|
}
|
|
|
|
void BaseRandomServer::SetSpawnerNetwork(Entity* self, const std::string& spawnerName, int32_t spawnNum, LOT spawnLOT) {
|
|
const auto& spawners = Game::zoneManager->GetSpawnersByName(spawnerName);
|
|
|
|
if (spawnLOT == 11217 && spawnNum > 1) {
|
|
spawnNum = 1;
|
|
}
|
|
|
|
if (spawners.empty()) {
|
|
LOG("Failed to find spawner: %s", spawnerName.c_str());
|
|
|
|
return;
|
|
}
|
|
|
|
auto* spawner = spawners[0];
|
|
|
|
if (spawnLOT != 0) {
|
|
spawner->SetSpawnLot(spawnLOT);
|
|
spawner->SetRespawnTime(respawnTime);
|
|
}
|
|
|
|
if (spawnNum != 0) {
|
|
spawner->SetNumToMaintain(spawnNum);
|
|
}
|
|
|
|
if (spawnerName == "Named_Enemies") {
|
|
spawner->SoftReset();
|
|
}
|
|
|
|
spawner->Activate();
|
|
|
|
if (std::find(spawnersWatched.begin(), spawnersWatched.end(), spawner) != spawnersWatched.end()) {
|
|
return;
|
|
}
|
|
|
|
spawner->AddSpawnedEntityDieCallback([this, self, spawner]() {
|
|
NotifySpawnerOfDeath(self, spawner);
|
|
});
|
|
|
|
spawnersWatched.push_back(spawner);
|
|
}
|
|
|
|
BaseRandomServer::Zone* BaseRandomServer::GetRandomLoad(Entity* self, const std::string& sectionName) {
|
|
const auto zoneInfo = GeneralUtils::SplitString(sectionName, '_');
|
|
|
|
int32_t totalWeight = 0;
|
|
|
|
for (const auto& load : zones) {
|
|
totalWeight += load.iChance;
|
|
}
|
|
|
|
const auto randWeight = GeneralUtils::GenerateRandomNumber<int32_t>(0, totalWeight);
|
|
|
|
int32_t weight = 0;
|
|
for (auto& zone : zones) {
|
|
weight += zone.iChance;
|
|
|
|
if (randWeight <= weight) {
|
|
return &zone;
|
|
}
|
|
}
|
|
|
|
return nullptr;
|
|
}
|
|
|
|
void BaseRandomServer::NotifySpawnerOfDeath(Entity* self, Spawner* spawner) {
|
|
const auto& spawnerName = spawner->GetName();
|
|
|
|
if (spawnerName == "Named_Enemies") {
|
|
NamedEnemyDeath(self, spawner);
|
|
|
|
return;
|
|
}
|
|
|
|
if (spawnerName.size() >= 7) {
|
|
const auto& sectionName = spawnerName.substr(0, spawnerName.size() - 7);
|
|
|
|
const auto variableName = u"mobsDead" + GeneralUtils::ASCIIToUTF16(sectionName);
|
|
|
|
auto mobDeathCount = self->GetVar<int32_t>(variableName);
|
|
|
|
mobDeathCount++;
|
|
|
|
if (mobDeathCount >= mobDeathResetNumber) {
|
|
const auto& zoneInfo = GeneralUtils::SplitString(sectionName, '_');
|
|
|
|
SpawnSection(self, sectionName, sectionMultipliers[zoneInfo[sectionIDConst - 1]]);
|
|
}
|
|
|
|
self->SetVar(variableName, mobDeathCount);
|
|
}
|
|
}
|
|
|
|
void BaseRandomServer::NamedEnemyDeath(Entity* self, Spawner* spawner) {
|
|
const auto spawnDelay = GeneralUtils::GenerateRandomNumber<float>(1, 2) * 450;
|
|
|
|
self->AddTimer("SpawnNewEnemy", spawnDelay);
|
|
}
|
|
|
|
void BaseRandomServer::SpawnersUp(Entity* self) {
|
|
|
|
}
|
|
|
|
void BaseRandomServer::SpawnersDown(Entity* self) {
|
|
|
|
}
|
|
|
|
void BaseRandomServer::BaseOnTimerDone(Entity* self, const std::string& timerName) {
|
|
NamedTimerDone(self, timerName);
|
|
}
|
|
|
|
void BaseRandomServer::SpawnNamedEnemy(Entity* self) {
|
|
const auto enemy = namedMobs[GeneralUtils::GenerateRandomNumber<int32_t>(0, namedMobs.size() - 1)];
|
|
|
|
SetSpawnerNetwork(self, "Named_Enemies", 1, enemy);
|
|
}
|
|
|
|
void BaseRandomServer::NamedTimerDone(Entity* self, const std::string& timerName) {
|
|
if (timerName == "SpawnNewEnemy") {
|
|
SpawnNamedEnemy(self);
|
|
}
|
|
}
|