#include "QbSpawner.h" #include "BaseCombatAIComponent.h" #include "EntityInfo.h" #include "MovementAIComponent.h" void QbSpawner::OnStartup(Entity* self) { auto mobNum = self->GetVar(u"mobNum"); auto spawnDist = self->GetVar(u"spawnDist"); auto mobTemplate = self->GetVar(u"mobTemplate"); auto spawnTime = self->GetVar(u"spawnTime"); if (!mobNum) self->SetVar(u"mobNum", m_DefaultMobNum); if (!spawnDist) self->SetVar(u"spawnDist", m_DefaultSpawnDist); if (!mobTemplate) self->SetVar(u"mobTemplate", m_DefaultMobTemplate); if (!spawnTime) self->SetVar(u"spawnTime", m_DefaultSpawnTime); // go ahead and setup the mob table here std::vector mobTable; mobTable.assign(self->GetVar(u"mobNum"), LWOOBJID_EMPTY); self->SetVar>(u"mobTable", mobTable); } void QbSpawner::OnFireEventServerSide(Entity* self, Entity* sender, std::string args, int32_t param1, int32_t param2, int32_t param3) { auto gateObjID = sender->GetObjectID(); if (!gateObjID) return; if (args == "spawnMobs") { self->SetVar(u"gateObj", gateObjID); auto spawnTime = self->GetVar(u"spawnTime"); self->AddTimer("SpawnMobEnemies", spawnTime); } } void QbSpawner::OnTimerDone(Entity* self, std::string timerName) { if (timerName == "SpawnMobEnemies") { auto mobTable = self->GetVar>(u"mobTable"); auto spawnDist = self->GetVar(u"spawnDist"); auto mobTemplate = self->GetVar(u"mobTemplate"); auto gateObjID = self->GetVar(u"gateObj"); if (!gateObjID) return; auto* gate = Game::entityManager->GetEntity(gateObjID); if (!gate) return; auto oPos = gate->GetPosition(); auto oDir = gate->GetRotation().GetForwardVector(); NiPoint3 newPos( oPos.x + (oDir.x * spawnDist), oPos.y, oPos.z + (oDir.z * spawnDist) ); auto newRot = NiQuaternion::LookAt(newPos, oPos); for (int i = 0; i < mobTable.size(); i++) { int posOffset = -10; if (mobTable[i] == LWOOBJID_EMPTY) { posOffset = posOffset + 5 * i; auto newOffset = newPos; newOffset.z = newOffset.z + posOffset; EntityInfo info{}; info.lot = mobTemplate; info.pos = newOffset; info.rot = newRot; info.spawnerID = self->GetObjectID(); info.spawnerNodeID = 0; info.settings = { new LDFData(u"no_timed_spawn", true), new LDFData(u"aggroRadius", 70), new LDFData(u"softtetherRadius", 80), new LDFData(u"tetherRadius", 90), new LDFData(u"wanderRadius", 5), new LDFData(u"mobTableLoc", i) }; auto* child = Game::entityManager->CreateEntity(info, nullptr, self); Game::entityManager->ConstructEntity(child); OnChildLoaded(self, child); } else { auto* mob = Game::entityManager->GetEntity(mobTable[i]); AggroTargetObject(self, mob); } } } } void QbSpawner::OnChildLoaded(Entity* self, Entity* child) { auto mobTable = self->GetVar>(u"mobTable"); auto tableLoc = child->GetVar(u"mobTableLoc"); mobTable[tableLoc] = child->GetObjectID(); self->SetVar>(u"mobTable", mobTable); AggroTargetObject(self, child); const auto selfID = self->GetObjectID(); child->AddDieCallback([this, selfID, child]() { auto* self = Game::entityManager->GetEntity(selfID); OnChildRemoved(self, child); } ); } void QbSpawner::OnChildRemoved(Entity* self, Entity* child) { auto mobTable = self->GetVar>(u"mobTable"); auto tableLoc = child->GetVar(u"mobTableLoc"); mobTable[tableLoc] = LWOOBJID_EMPTY; self->SetVar>(u"mobTable", mobTable); } void QbSpawner::AggroTargetObject(Entity* self, Entity* enemy) { auto* baseCombatAIComponent = enemy->GetComponent(); if (!baseCombatAIComponent) return; auto gateObjID = self->GetVar(u"gateObj"); if (gateObjID) { auto* gate = Game::entityManager->GetEntity(gateObjID); if (gate) { auto* movementAIComponent = enemy->GetComponent(); if (movementAIComponent) movementAIComponent->SetDestination(gate->GetPosition()); baseCombatAIComponent->Taunt(gateObjID, 1000); } } auto playerObjID = self->GetVar(u"player"); if (playerObjID) { baseCombatAIComponent->Taunt(playerObjID, 100); } }