#include #include "GameDependencies.h" #include "Entity.h" #include "ObjectMessages.h" #include "dGameMessagesTests/GameMessageTestUtils.h" #include "02_server/Enemy/AG/BossSpiderQueenEnemyServer.h" #include "02_server/Map/Property/AG_Small/ZoneAgProperty.h" // The AG property's Spider Queen fight (L_ZONE_AG_PROPERTY.lua, L_BOSS_SPIDER_QUEEN_ENEMY_SERVER.lua). using namespace GameMessageTestUtils; class SpiderQueenTest : public GameDependenciesTest { protected: static constexpr LWOOBJID ZONE = 70368744177662; static constexpr LWOOBJID BOSS = 0x1000; static constexpr LWOOBJID LAND_TARGET = 0x1001; static constexpr LWOOBJID SCREAM_EMITTER = 0x1002; static constexpr LWOOBJID SPIDERLING = 0x1003; std::vector> entities; Entity* zone = nullptr; Entity* boss = nullptr; ZoneAgProperty zoneScript; BossSpiderQueenEnemyServer bossScript; void SetUp() override { SetUpDependencies(); zone = Add(ZONE, 0, {}); boss = Add(BOSS, 14381, { "SpiderBoss" }); zoneScript.SetGameVariables(zone); } void TearDown() override { for (const auto& entity : entities) Game::entityManager->_removeEntity(entity->GetObjectID()); entities.clear(); TearDownDependencies(); } Entity* Add(const LWOOBJID id, const LOT lot, const std::vector& groups) { info.lot = lot; auto* const entity = entities.emplace_back(std::make_unique(id, info)).get(); entity->GetGroups() = groups; Game::entityManager->_addEntity(entity); return entity; } }; TEST_F(SpiderQueenTest, ZoneHandsTheBossItsLandingTargetAndScreamEmitter) { Add(LAND_TARGET, 14382, { "Land_Target" }); Add(SCREAM_EMITTER, 14383, { "Spider_Scream" }); zoneScript.BaseOnFireEventServerSide(zone, boss, "RetrieveZoneData"); EXPECT_EQ(zone->GetVar(u"SpiderBossID"), BOSS); EXPECT_EQ(boss->GetVar(u"LandingTarget"), LAND_TARGET); EXPECT_EQ(boss->GetVar(u"ScreamEmitter"), SCREAM_EMITTER); zone->Update(0.0f); EXPECT_FALSE(zone->HasTimer("ProcessGroupObj_LandingTarget")); EXPECT_FALSE(zone->HasTimer("ProcessGroupObj_ScreamEmitter")); } TEST_F(SpiderQueenTest, ZoneLooksAgainWhileTheObjectsAreNotSpawned) { zoneScript.BaseOnFireEventServerSide(zone, boss, "RetrieveZoneData"); EXPECT_EQ(boss->GetVar(u"LandingTarget"), LWOOBJID_EMPTY); zone->Update(0.0f); // starts the pending timers EXPECT_TRUE(zone->HasTimer("ProcessGroupObj_LandingTarget")); EXPECT_TRUE(zone->HasTimer("ProcessGroupObj_ScreamEmitter")); Add(SCREAM_EMITTER, 14383, { "Spider_Scream" }); zoneScript.OnTimerDone(zone, "ProcessGroupObj_ScreamEmitter"); EXPECT_EQ(boss->GetVar(u"ScreamEmitter"), SCREAM_EMITTER); } TEST_F(SpiderQueenTest, ASpiderlingDeathMakesTheBossScreamFromTheMountain) { boss->SetVar(u"ScreamEmitter", SCREAM_EMITTER); auto* const spiderling = Add(SPIDERLING, 16197, { "BabySpider" }); const auto packets = Capture([&] { bossScript.OnNotifyObject(boss, spiderling, "SpiderlingDied", 0, 0); }); const auto sent = SentGameMessages(packets); ASSERT_EQ(sent.size(), 1u); EXPECT_EQ(sent[0].target, BOSS); EXPECT_EQ(sent[0].name, u"EmitScream"); EXPECT_EQ(sent[0].paramObj, SCREAM_EMITTER); EXPECT_TRUE(packets[0].broadcast); } TEST_F(SpiderQueenTest, OnlySpiderlingsMakeTheBossScream) { auto* const other = Add(SPIDERLING, 16196, {}); const auto packets = Capture([&] { bossScript.OnNotifyObject(boss, other, "SpiderlingDied", 0, 0); }); EXPECT_TRUE(packets.empty()); } TEST_F(SpiderQueenTest, TheMeleeSmashLocksTheSpecialsForItsLength) { bossScript.OnSkillCast(boss, 303); EXPECT_FALSE(boss->GetBoolean(u"bSpecialLock")); bossScript.OnSkillCast(boss, 322); EXPECT_TRUE(boss->GetBoolean(u"bSpecialLock")); boss->Update(0.0f); EXPECT_TRUE(boss->HasTimer("UnlockSpecials")); // A special due during the smash waits for it bossScript.SpiderSkillManager(boss, true); EXPECT_TRUE(boss->GetBoolean(u"bSpecialQueued")); bossScript.OnTimerDone(boss, "UnlockSpecials"); EXPECT_FALSE(boss->GetBoolean(u"bSpecialLock")); EXPECT_FALSE(boss->GetBoolean(u"bSpecialQueued")); } TEST_F(SpiderQueenTest, NoSpecialsBeforeTheFirstWave) { // Stage 1 has no special attack; the skill manager does nothing const auto packets = Capture([&] { bossScript.SpiderSkillManager(boss, true); }); EXPECT_TRUE(packets.empty()); EXPECT_FALSE(boss->GetBoolean(u"isSpecialAttacking")); }