fix(scripts): the Spider Queen screams from the mountain when a spiderling dies (issue 307)

The zone script never handed the boss her landing target and scream emitter: ZoneAgProperty::ProcessGroupObjects
was empty and nothing answered the boss client script's "QueryZoneScript" event. As the live scripts: the boss asks
the zone ("RetrieveZoneData"), the zone stores the first object of Land_Target and Spider_Scream on her as
LandingTarget and ScreamEmitter (looking again every 0.3 s until they are spawned), and each spiderling death sends
NotifyClientObject "EmitScream" with the emitter, which the boss's client script plays as the scream. The landing
skill and camera shake now come from the landing target, not the boss.

Check in game: AG Spider Queen (property or instance): kill a spiderling: the scream plays from the mountain; when
she comes back down, the landing blast hits around the landing spot and the camera shakes.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Aaron Kimbrell
2026-09-29 10:16:02 -05:00
parent fb525b6fa4
commit 4900f11cf1
7 changed files with 161 additions and 24 deletions

View File

@@ -53,6 +53,15 @@ void EnemySpiderSpawner::OnTimerDone(Entity* self, std::string timerName) {
if (newEntity) {
Game::entityManager->ConstructEntity(newEntity);
newEntity->GetGroups().push_back("BabySpider");
// The Spider Queen screams from the mountain when one of her spiderlings dies
const auto spawnOwner = self->GetI64(u"SpawnOwner");
const auto spiderlingID = newEntity->GetObjectID();
newEntity->AddDieCallback([spawnOwner, spiderlingID]() {
auto* const spiderBoss = Game::entityManager->GetEntity(spawnOwner);
auto* const spiderling = Game::entityManager->GetEntity(spiderlingID);
if (spiderBoss && spiderling) spiderBoss->GetScript()->OnNotifyObject(spiderBoss, spiderling, "SpiderlingDied");
});
}
self->ScheduleKillAfterUpdate();

View File

@@ -1,4 +1,5 @@
#include "ZoneAgProperty.h"
#include "GeneralUtils.h"
#include "EntityManager.h"
#include "Character.h"
#include "Entity.h"
@@ -113,7 +114,25 @@ void ZoneAgProperty::LoadProperty(Entity* self) {
ActivateSpawner(self->GetVar<std::string>(MailboxSpawner));
}
void ZoneAgProperty::ProcessGroupObjects(Entity* self, std::string group) {
void ZoneAgProperty::ProcessGroupObjects(Entity* self, const std::string& group) {
// Hands the Spider Queen the first object of the group: the landing target casts her landing skill,
// the mountain emitter plays her scream
std::u16string varName;
if (group == self->GetVar<std::string>(LandTargetGroup)) varName = u"LandingTarget";
else if (group == self->GetVar<std::string>(SpiderScreamGroup)) varName = u"ScreamEmitter";
else return;
auto* const spiderBoss = Game::entityManager->GetEntity(self->GetVar<LWOOBJID>(u"SpiderBossID"));
if (!spiderBoss) return;
const auto objects = Game::entityManager->GetEntitiesInGroup(group);
if (objects.empty()) {
// Not spawned yet: look again shortly
self->AddTimer("ProcessGroupObj_" + GeneralUtils::UTF16ToWTF8(varName), 0.3f);
return;
}
spiderBoss->SetVar<LWOOBJID>(varName, objects.front()->GetObjectID());
}
void ZoneAgProperty::SpawnSpots(Entity* self) {
@@ -290,8 +309,10 @@ void ZoneAgProperty::BaseTimerDone(Entity* self, const std::string& timerName) {
DestroySpawner(self->GetVar<std::string>(FXManagerSpawner));
self->SetVar<bool>(u"FXObjectGone", true);
} else if (timerName == "ProcessGroupObj") {
// TODO
} else if (timerName == "ProcessGroupObj_LandingTarget") {
ProcessGroupObjects(self, self->GetVar<std::string>(LandTargetGroup));
} else if (timerName == "ProcessGroupObj_ScreamEmitter") {
ProcessGroupObjects(self, self->GetVar<std::string>(SpiderScreamGroup));
}
}

View File

@@ -30,7 +30,7 @@ public:
void LoadInstance(Entity* self);
void LoadProperty(Entity* self);
void ProcessGroupObjects(Entity* self, std::string group);
void ProcessGroupObjects(Entity* self, const std::string& group);
void SpawnSpots(Entity* self) override;
void KillSpots(Entity* self) override;