#include "BaseEnemyApe.h" #include "BaseCombatAIComponent.h" #include "DestroyableComponent.h" #include "GameMessages.h" #include "EntityManager.h" #include "EntityInfo.h" #include "SkillComponent.h" #include "eAninmationFlags.h" #include "RenderComponent.h" #include "eStateChangeType.h" void BaseEnemyApe::OnStartup(Entity* self) { self->SetVar(u"timesStunned", 2); self->SetVar(u"knockedOut", false); } void BaseEnemyApe::OnDie(Entity* self, Entity* killer) { auto* anchor = EntityManager::Instance()->GetEntity(self->GetVar(u"QB")); if (anchor != nullptr && !anchor->IsDead()) { anchor->Smash(self->GetObjectID(), eKillType::SILENT); } } void BaseEnemyApe::OnSkillCast(Entity* self, uint32_t skillID) { const auto groundPoundSkill = self->GetVar(u"GroundPoundSkill") != 0 ? self->GetVar(u"GroundPoundSkill") : 725; const auto spawnQuickBuildTime = self->GetVar(u"spawnQBTime") != 0.0f ? self->GetVar(u"spawnQBTime") : 5.0f; if (skillID == groundPoundSkill && self->GetVar(u"QB") == LWOOBJID_EMPTY) { self->AddTimer("spawnQBTime", spawnQuickBuildTime); } } void BaseEnemyApe::OnHit(Entity* self, Entity* attacker) { auto* destroyableComponent = self->GetComponent(); if (destroyableComponent != nullptr && destroyableComponent->GetArmor() < 1 && !self->GetBoolean(u"knockedOut")) { StunApe(self, true); self->CancelTimer("spawnQBTime"); auto* skillComponent = self->GetComponent(); if (skillComponent) { skillComponent->Reset(); } RenderComponent::PlayAnimation(self, u"disable", 1.7f); GameMessages::SendChangeIdleFlags(self->GetObjectID(), eAnimationFlags::IDLE_NONE, eAnimationFlags::IDLE_COMBAT, UNASSIGNED_SYSTEM_ADDRESS); const auto reviveTime = self->GetVar(u"reviveTime") != 0.0f ? self->GetVar(u"reviveTime") : 12.0f; self->AddTimer("reviveTime", reviveTime); } } void BaseEnemyApe::OnTimerDone(Entity* self, std::string timerName) { if (timerName == "reviveTime") { // Revives the ape, giving it back some armor const auto timesStunned = self->GetVar(u"timesStunned"); auto* destroyableComponent = self->GetComponent(); if (destroyableComponent != nullptr) { destroyableComponent->SetArmor(destroyableComponent->GetMaxArmor() / timesStunned); } EntityManager::Instance()->SerializeEntity(self); GameMessages::SendChangeIdleFlags(self->GetObjectID(), eAnimationFlags::IDLE_COMBAT, eAnimationFlags::IDLE_NONE, UNASSIGNED_SYSTEM_ADDRESS); self->SetVar(u"timesStunned", timesStunned + 1); StunApe(self, false); } else if (timerName == "spawnQBTime" && self->GetVar(u"QB") == LWOOBJID_EMPTY) { // Spawn QB in front of ape. const auto position = self->GetPosition(); const auto rotation = self->GetRotation(); const auto backwardVector = rotation.GetForwardVector() * -1; const auto objectPosition = NiPoint3( position.GetX() - (backwardVector.GetX() * 8), position.GetY(), position.GetZ() - (backwardVector.GetZ() * 8) ); EntityInfo entityInfo{}; entityInfo.pos = position; entityInfo.rot = rotation; entityInfo.pos.SetY(entityInfo.pos.GetY() + 13.0f); entityInfo.spawnerID = self->GetObjectID(); entityInfo.lot = self->GetVar(u"QuickbuildAnchorLOT") != 0 ? self->GetVar(u"QuickbuildAnchorLOT") : 7549; entityInfo.settings = { new LDFData(u"rebuild_activators", std::to_string(objectPosition.GetX()) + "\x1f" + std::to_string(objectPosition.GetY()) + "\x1f" + std::to_string(objectPosition.GetZ()) ), new LDFData(u"no_timed_spawn", true), new LDFData(u"ape", self->GetObjectID()) }; auto* anchor = EntityManager::Instance()->CreateEntity(entityInfo); EntityManager::Instance()->ConstructEntity(anchor); self->SetVar(u"QB", anchor->GetObjectID()); } else if (timerName == "anchorDamageTimer") { // Attacks the ape with some god skill const auto* player = EntityManager::Instance()->GetEntity(self->GetVar(u"smasher")); if (player == nullptr) { return; } auto* skillComponent = self->GetComponent(); if (skillComponent != nullptr) { skillComponent->CalculateBehavior(1273, 29446, self->GetObjectID(), true, false, player->GetObjectID()); } self->SetVar(u"QB", LWOOBJID_EMPTY); } } void BaseEnemyApe::OnFireEventServerSide(Entity* self, Entity* sender, std::string args, int32_t param1, int32_t param2, int32_t param3) { if (args == "rebuildDone" && sender != nullptr) { self->SetVar(u"smasher", sender->GetObjectID()); const auto anchorDamageDelayTime = self->GetVar(u"AnchorDamageDelayTime") != 0.0f ? self->GetVar(u"AnchorDamageDelayTime") : 0.5f; self->AddTimer("anchorDamageTimer", anchorDamageDelayTime); } } void BaseEnemyApe::StunApe(Entity* self, bool stunState) { auto* combatAIComponent = self->GetComponent(); if (combatAIComponent != nullptr) { combatAIComponent->SetDisabled(stunState); combatAIComponent->SetStunned(stunState); auto* skillComponent = self->GetComponent(); if (skillComponent != nullptr) { skillComponent->Interrupt(); } GameMessages::SendSetStunned(self->GetObjectID(), stunState ? eStateChangeType::PUSH : eStateChangeType::POP, UNASSIGNED_SYSTEM_ADDRESS, self->GetObjectID(), true, true, true, true, true, true, true, true, true); self->SetBoolean(u"knockedOut", stunState); } }