mirror of
https://github.com/DarkflameUniverse/DarkflameServer.git
synced 2026-10-02 02:43:44 +00:00
fix(scripts): Spider Queen rain of fire hits two spots in each outer ring (issue 2016)
The live boss script's rain of fire takes every target of the first ROF target group and ROFImpactCnt (2) different random targets of each other group. The server took one per group, so the rain was sparser than live. The impacts are now picked like the live script (without repeats inside a group). Check in game: AG Spider Queen stage 3; the rain of fire lands on the centre ring and on two spots in each outer ring. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -352,31 +352,20 @@ void BossSpiderQueenEnemyServer::RunRainOfFire(Entity* self) {
|
||||
ToggleForSpecial(self, true);
|
||||
SetRainOfFireStun(self, true);
|
||||
|
||||
impactList.clear();
|
||||
|
||||
auto index = 0u;
|
||||
std::vector<std::vector<LWOOBJID>> targetGroups;
|
||||
for (const auto& rofGroup : ROFTargetGroupIDTable) {
|
||||
const auto spawners = Game::zoneManager->GetSpawnersInGroup(rofGroup);
|
||||
|
||||
std::vector<LWOOBJID> spawned;
|
||||
|
||||
for (auto* spawner : spawners) {
|
||||
auto& spawned = targetGroups.emplace_back();
|
||||
for (auto* spawner : Game::zoneManager->GetSpawnersInGroup(rofGroup)) {
|
||||
for (const auto* node : spawner->m_Info.nodes) {
|
||||
spawned.insert(spawned.end(), node->entities.begin(), node->entities.end());
|
||||
}
|
||||
}
|
||||
|
||||
if (index == 0) {
|
||||
impactList.insert(impactList.end(), spawned.begin(), spawned.end());
|
||||
} else if (!spawned.empty()) {
|
||||
const auto randomIndex = GeneralUtils::GenerateRandomNumber<int32_t>(0, spawned.size() - 1);
|
||||
|
||||
impactList.push_back(spawned[randomIndex]);
|
||||
}
|
||||
|
||||
index++;
|
||||
}
|
||||
|
||||
impactList = PickRainOfFireImpacts(targetGroups, [](const size_t count) {
|
||||
return GeneralUtils::GenerateRandomNumber<size_t>(0, count - 1);
|
||||
});
|
||||
|
||||
const auto animTime = PlayAnimAndReturnTime(self, spiderROFAnim);
|
||||
|
||||
self->AddTimer("StartROF", animTime);
|
||||
@@ -504,6 +493,25 @@ std::vector<LWOOBJID> BossSpiderQueenEnemyServer::BuildRapidFireTargets(const st
|
||||
return attackTargets;
|
||||
}
|
||||
|
||||
std::vector<LWOOBJID> BossSpiderQueenEnemyServer::PickRainOfFireImpacts(const std::vector<std::vector<LWOOBJID>>& groups,
|
||||
const std::function<size_t(size_t count)>& randomIndex) {
|
||||
std::vector<LWOOBJID> impacts;
|
||||
for (size_t i = 0; i < groups.size(); i++) {
|
||||
if (i == 0) {
|
||||
impacts.insert(impacts.end(), groups[i].begin(), groups[i].end());
|
||||
continue;
|
||||
}
|
||||
|
||||
auto remaining = groups[i];
|
||||
for (size_t picked = 0; picked < ROFImpactCnt && !remaining.empty(); picked++) {
|
||||
const auto index = randomIndex(remaining.size());
|
||||
impacts.push_back(remaining[index]);
|
||||
remaining.erase(remaining.begin() + static_cast<std::ptrdiff_t>(index));
|
||||
}
|
||||
}
|
||||
return impacts;
|
||||
}
|
||||
|
||||
void BossSpiderQueenEnemyServer::OnZoneVolumeEntered(Entity* self, Entity* player, const std::string& volumeGroup) {
|
||||
if (!player || !player->IsPlayer()) return;
|
||||
|
||||
|
||||
@@ -65,6 +65,11 @@ public:
|
||||
static std::vector<LWOOBJID> BuildRapidFireTargets(const std::string& primaryZone, bool clockwise,
|
||||
const std::function<std::vector<RapidFireTarget>(const std::string& group)>& groupTargets);
|
||||
|
||||
// The rain of fire's impacts: every target of the first group and ROFImpactCnt different random targets of each
|
||||
// other group. randomIndex(n) returns a number in [0, n).
|
||||
static std::vector<LWOOBJID> PickRainOfFireImpacts(const std::vector<std::vector<LWOOBJID>>& groups,
|
||||
const std::function<size_t(size_t count)>& randomIndex);
|
||||
|
||||
// A player touched one of the arena's zone volumes (group Zone1Vol..Zone8Vol, AggroVol or TeleVol)
|
||||
void OnZoneVolumeEntered(Entity* self, Entity* player, const std::string& volumeGroup);
|
||||
|
||||
@@ -99,7 +104,7 @@ private:
|
||||
|
||||
const std::vector<int> spiderWaveCntTable = { 2, 3 }; //The number of Dark Spiderling enemies to spawn per indexed wave number
|
||||
|
||||
const int ROFImpactCnt = 2; //The number of ROF impacts in each quadrant of the arena selected at random
|
||||
static constexpr size_t ROFImpactCnt = 2; //The number of ROF impacts in each quadrant of the arena selected at random
|
||||
|
||||
const LOT SpiderlingID = 16197; //Reference obj ID for hatched Spiderlings
|
||||
|
||||
|
||||
@@ -149,6 +149,13 @@ TEST_F(SpiderQueenTest, RapidFireSweepsOverTheEdgeBetweenZonesEightAndOne) {
|
||||
EXPECT_EQ(BossSpiderQueenEnemyServer::BuildRapidFireTargets("Zone2Vol", true, ArenaGroup), Ids({ 1, 2, 3, 4, 5, 6, 7 }));
|
||||
}
|
||||
|
||||
TEST_F(SpiderQueenTest, RainOfFireTakesTheFirstGroupAndTwoOfEachOther) {
|
||||
const std::vector<std::vector<LWOOBJID>> groups = { { 1, 2, 3 }, { 10, 11, 12, 13 }, { 20 }, {}, { 40, 41 } };
|
||||
// Always the last remaining target
|
||||
const auto impacts = BossSpiderQueenEnemyServer::PickRainOfFireImpacts(groups, [](const size_t count) { return count - 1; });
|
||||
EXPECT_EQ(impacts, (std::vector<LWOOBJID>{ 1, 2, 3, 13, 12, 20, 41, 40 }));
|
||||
}
|
||||
|
||||
TEST_F(SpiderQueenTest, ZoneVolumesTellTheBossWhereThePlayerIs) {
|
||||
for (const auto& group : { "Zone1Vol", "Zone2Vol", "Zone3Vol", "Zone4Vol", "Zone5Vol", "Zone6Vol", "Zone7Vol", "Zone8Vol", "AggroVol", "TeleVol" }) {
|
||||
Add(0x2000 + static_cast<LWOOBJID>(entities.size()), 14400, { group });
|
||||
|
||||
Reference in New Issue
Block a user