2021-12-05 17:54:36 +00:00
|
|
|
#include "BaseEnemyApe.h"
|
|
|
|
#include "BaseCombatAIComponent.h"
|
|
|
|
#include "DestroyableComponent.h"
|
|
|
|
#include "GameMessages.h"
|
|
|
|
#include "EntityManager.h"
|
2023-01-07 05:17:05 +00:00
|
|
|
#include "EntityInfo.h"
|
2021-12-05 17:54:36 +00:00
|
|
|
#include "SkillComponent.h"
|
2024-11-18 00:39:44 +00:00
|
|
|
#include "eAnimationFlags.h"
|
2023-03-20 13:10:52 +00:00
|
|
|
#include "RenderComponent.h"
|
2023-05-02 22:39:21 +00:00
|
|
|
#include "eStateChangeType.h"
|
2021-12-05 17:54:36 +00:00
|
|
|
|
|
|
|
void BaseEnemyApe::OnStartup(Entity* self) {
|
|
|
|
self->SetVar<uint32_t>(u"timesStunned", 2);
|
|
|
|
self->SetVar<bool>(u"knockedOut", false);
|
|
|
|
}
|
|
|
|
|
|
|
|
void BaseEnemyApe::OnDie(Entity* self, Entity* killer) {
|
2023-07-15 20:56:33 +00:00
|
|
|
auto* anchor = Game::entityManager->GetEntity(self->GetVar<LWOOBJID>(u"QB"));
|
2021-12-05 17:54:36 +00:00
|
|
|
if (anchor != nullptr && !anchor->GetIsDead()) {
|
2023-05-02 22:39:21 +00:00
|
|
|
anchor->Smash(self->GetObjectID(), eKillType::SILENT);
|
2021-12-05 17:54:36 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void BaseEnemyApe::OnSkillCast(Entity* self, uint32_t skillID) {
|
2022-03-24 01:08:09 +00:00
|
|
|
const auto groundPoundSkill = self->GetVar<uint32_t>(u"GroundPoundSkill") != 0 ? self->GetVar<uint32_t>(u"GroundPoundSkill") : 725;
|
|
|
|
const auto spawnQuickBuildTime = self->GetVar<float_t>(u"spawnQBTime") != 0.0f ? self->GetVar<float_t>(u"spawnQBTime") : 5.0f;
|
2021-12-05 17:54:36 +00:00
|
|
|
|
|
|
|
if (skillID == groundPoundSkill && self->GetVar<LWOOBJID>(u"QB") == LWOOBJID_EMPTY) {
|
|
|
|
self->AddTimer("spawnQBTime", spawnQuickBuildTime);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void BaseEnemyApe::OnHit(Entity* self, Entity* attacker) {
|
|
|
|
auto* destroyableComponent = self->GetComponent<DestroyableComponent>();
|
|
|
|
if (destroyableComponent != nullptr && destroyableComponent->GetArmor() < 1 && !self->GetBoolean(u"knockedOut")) {
|
|
|
|
StunApe(self, true);
|
|
|
|
self->CancelTimer("spawnQBTime");
|
2022-12-23 06:14:51 +00:00
|
|
|
auto* skillComponent = self->GetComponent<SkillComponent>();
|
|
|
|
if (skillComponent) {
|
|
|
|
skillComponent->Reset();
|
|
|
|
}
|
2023-03-20 13:10:52 +00:00
|
|
|
RenderComponent::PlayAnimation(self, u"disable", 1.7f);
|
2022-12-23 06:14:51 +00:00
|
|
|
GameMessages::SendChangeIdleFlags(self->GetObjectID(), eAnimationFlags::IDLE_NONE, eAnimationFlags::IDLE_COMBAT, UNASSIGNED_SYSTEM_ADDRESS);
|
2021-12-05 17:54:36 +00:00
|
|
|
const auto reviveTime = self->GetVar<float_t>(u"reviveTime") != 0.0f
|
|
|
|
? self->GetVar<float_t>(u"reviveTime") : 12.0f;
|
|
|
|
self->AddTimer("reviveTime", reviveTime);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void BaseEnemyApe::OnTimerDone(Entity* self, std::string timerName) {
|
|
|
|
if (timerName == "reviveTime") {
|
2022-07-28 13:39:57 +00:00
|
|
|
|
2021-12-05 17:54:36 +00:00
|
|
|
// Revives the ape, giving it back some armor
|
|
|
|
const auto timesStunned = self->GetVar<uint32_t>(u"timesStunned");
|
|
|
|
auto* destroyableComponent = self->GetComponent<DestroyableComponent>();
|
|
|
|
if (destroyableComponent != nullptr) {
|
|
|
|
destroyableComponent->SetArmor(destroyableComponent->GetMaxArmor() / timesStunned);
|
|
|
|
}
|
2023-07-15 20:56:33 +00:00
|
|
|
Game::entityManager->SerializeEntity(self);
|
2022-12-23 06:14:51 +00:00
|
|
|
GameMessages::SendChangeIdleFlags(self->GetObjectID(), eAnimationFlags::IDLE_COMBAT, eAnimationFlags::IDLE_NONE, UNASSIGNED_SYSTEM_ADDRESS);
|
2021-12-05 17:54:36 +00:00
|
|
|
self->SetVar<uint32_t>(u"timesStunned", timesStunned + 1);
|
|
|
|
StunApe(self, false);
|
2022-07-28 13:39:57 +00:00
|
|
|
|
2021-12-05 17:54:36 +00:00
|
|
|
} else if (timerName == "spawnQBTime" && self->GetVar<LWOOBJID>(u"QB") == LWOOBJID_EMPTY) {
|
2022-03-24 01:08:09 +00:00
|
|
|
// Spawn QB in front of ape.
|
2021-12-05 17:54:36 +00:00
|
|
|
const auto position = self->GetPosition();
|
|
|
|
const auto rotation = self->GetRotation();
|
2022-07-28 13:39:57 +00:00
|
|
|
|
2021-12-05 17:54:36 +00:00
|
|
|
const auto backwardVector = rotation.GetForwardVector() * -1;
|
|
|
|
const auto objectPosition = NiPoint3(
|
|
|
|
position.GetX() - (backwardVector.GetX() * 8),
|
|
|
|
position.GetY(),
|
|
|
|
position.GetZ() - (backwardVector.GetZ() * 8)
|
|
|
|
);
|
2022-07-28 13:39:57 +00:00
|
|
|
|
2021-12-05 17:54:36 +00:00
|
|
|
EntityInfo entityInfo{};
|
2022-07-28 13:39:57 +00:00
|
|
|
|
2021-12-05 17:54:36 +00:00
|
|
|
entityInfo.pos = position;
|
|
|
|
entityInfo.rot = rotation;
|
|
|
|
entityInfo.pos.SetY(entityInfo.pos.GetY() + 13.0f);
|
2022-07-28 13:39:57 +00:00
|
|
|
|
2021-12-05 17:54:36 +00:00
|
|
|
entityInfo.spawnerID = self->GetObjectID();
|
|
|
|
entityInfo.lot = self->GetVar<LOT>(u"QuickbuildAnchorLOT") != 0
|
|
|
|
? self->GetVar<LOT>(u"QuickbuildAnchorLOT") : 7549;
|
|
|
|
entityInfo.settings = {
|
|
|
|
new LDFData<std::string>(u"rebuild_activators",
|
|
|
|
std::to_string(objectPosition.GetX()) + "\x1f" +
|
|
|
|
std::to_string(objectPosition.GetY()) + "\x1f" +
|
|
|
|
std::to_string(objectPosition.GetZ())
|
|
|
|
),
|
|
|
|
new LDFData<bool>(u"no_timed_spawn", true),
|
|
|
|
new LDFData<LWOOBJID>(u"ape", self->GetObjectID())
|
|
|
|
};
|
2022-07-28 13:39:57 +00:00
|
|
|
|
2023-07-15 20:56:33 +00:00
|
|
|
auto* anchor = Game::entityManager->CreateEntity(entityInfo);
|
|
|
|
Game::entityManager->ConstructEntity(anchor);
|
2021-12-05 17:54:36 +00:00
|
|
|
self->SetVar<LWOOBJID>(u"QB", anchor->GetObjectID());
|
2022-07-28 13:39:57 +00:00
|
|
|
|
2021-12-05 17:54:36 +00:00
|
|
|
} else if (timerName == "anchorDamageTimer") {
|
2022-07-28 13:39:57 +00:00
|
|
|
|
2021-12-05 17:54:36 +00:00
|
|
|
// Attacks the ape with some god skill
|
2023-07-15 20:56:33 +00:00
|
|
|
const auto* player = Game::entityManager->GetEntity(self->GetVar<LWOOBJID>(u"smasher"));
|
2021-12-05 17:54:36 +00:00
|
|
|
if (player == nullptr) {
|
|
|
|
return;
|
|
|
|
}
|
2022-07-28 13:39:57 +00:00
|
|
|
|
2021-12-05 17:54:36 +00:00
|
|
|
auto* skillComponent = self->GetComponent<SkillComponent>();
|
|
|
|
if (skillComponent != nullptr) {
|
|
|
|
skillComponent->CalculateBehavior(1273, 29446, self->GetObjectID(), true, false, player->GetObjectID());
|
|
|
|
}
|
2022-07-28 13:39:57 +00:00
|
|
|
|
2021-12-05 17:54:36 +00:00
|
|
|
self->SetVar<LWOOBJID>(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<LWOOBJID>(u"smasher", sender->GetObjectID());
|
2022-03-24 01:08:09 +00:00
|
|
|
const auto anchorDamageDelayTime = self->GetVar<float_t>(u"AnchorDamageDelayTime") != 0.0f ? self->GetVar<float_t>(u"AnchorDamageDelayTime") : 0.5f;
|
2021-12-05 17:54:36 +00:00
|
|
|
self->AddTimer("anchorDamageTimer", anchorDamageDelayTime);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void BaseEnemyApe::StunApe(Entity* self, bool stunState) {
|
|
|
|
auto* combatAIComponent = self->GetComponent<BaseCombatAIComponent>();
|
|
|
|
if (combatAIComponent != nullptr) {
|
|
|
|
combatAIComponent->SetDisabled(stunState);
|
|
|
|
combatAIComponent->SetStunned(stunState);
|
|
|
|
|
|
|
|
auto* skillComponent = self->GetComponent<SkillComponent>();
|
|
|
|
if (skillComponent != nullptr) {
|
|
|
|
skillComponent->Interrupt();
|
|
|
|
}
|
|
|
|
|
2023-01-07 05:59:19 +00:00
|
|
|
GameMessages::SendSetStunned(self->GetObjectID(), stunState ? eStateChangeType::PUSH : eStateChangeType::POP, UNASSIGNED_SYSTEM_ADDRESS, self->GetObjectID(),
|
2021-12-05 17:54:36 +00:00
|
|
|
true, true, true, true, true,
|
|
|
|
true, true, true, true);
|
|
|
|
|
|
|
|
self->SetBoolean(u"knockedOut", stunState);
|
|
|
|
}
|
|
|
|
}
|