From 67d5061416a6b253a11506428115e1e7ffac5a2a Mon Sep 17 00:00:00 2001 From: EmosewaMC <39972741+EmosewaMC@users.noreply.github.com> Date: Wed, 19 Jan 2022 02:10:04 -0800 Subject: [PATCH 1/3] Implemented Dragon Smash Quick Build for Crux Prime Dragons Implemented a script for the crux prime dragons to spawn the Golem Quick Build that insta kills the Entity if the player hits the dragon after the golem is built. Tested on Local Ubuntu instance against 1 Crux Prime Maelstrom Dragon and 1 Butterscorch and had no issues building the quick build or with the enemy not smashing. Enemies also correctly reset to their default behavior after the stun period has expired. --- dScripts/AmDarklingDragon.cpp | 167 +++++++++++++++++++++++++++++ dScripts/AmDarklingDragon.h | 12 +++ dScripts/AmNamedDarklingDragon.cpp | 12 --- dScripts/AmNamedDarklingDragon.h | 8 -- dScripts/CppScripts.cpp | 7 +- 5 files changed, 182 insertions(+), 24 deletions(-) create mode 100644 dScripts/AmDarklingDragon.cpp create mode 100644 dScripts/AmDarklingDragon.h delete mode 100644 dScripts/AmNamedDarklingDragon.cpp delete mode 100644 dScripts/AmNamedDarklingDragon.h diff --git a/dScripts/AmDarklingDragon.cpp b/dScripts/AmDarklingDragon.cpp new file mode 100644 index 00000000..435fa68d --- /dev/null +++ b/dScripts/AmDarklingDragon.cpp @@ -0,0 +1,167 @@ +#include "AmDarklingDragon.h" +#include "BaseCombatAIComponent.h" +#include "DestroyableComponent.h" +#include "EntityManager.h" +#include "GameMessages.h" +#include "SkillComponent.h" +#include "BaseCombatAIComponent.h" + + +void AmDarklingDragon::OnStartup(Entity* self) { + self->SetVar(u"weakspot", 0); + + auto* baseCombatAIComponent = self->GetComponent(); + + if (baseCombatAIComponent != nullptr) { + baseCombatAIComponent->SetStunImmune(true); + } +} + +void AmDarklingDragon::OnDie(Entity* self, Entity* killer) { + if (self->GetVar(u"bDied")) { + return; + } + + self->SetVar(u"bDied", true); + + auto position = self->GetPosition(); + auto rotation = self->GetRotation(); + + auto golemId = self->GetVar(u"Golem"); + + auto* golem = EntityManager::Instance()->GetEntity(golemId); + + if (golem != nullptr) { + golem->Smash(self->GetObjectID()); + } +} + +void AmDarklingDragon::OnHitOrHealResult(Entity* self, Entity* attacker, int32_t damage) { + GameMessages::SendPlayFXEffect(self, -1, u"gothit", "", LWOOBJID_EMPTY, 1, 1, true); + + if (true) { + auto weakpoint = self->GetVar(u"weakspot"); + + if (weakpoint == 1) + { + self->Smash(attacker->GetObjectID()); + } + } + + auto* destroyableComponent = self->GetComponent(); + + if (destroyableComponent != nullptr) { + Game::logger->Log("AmDarklingDragon", "Armor is %i\n", destroyableComponent->GetArmor()); + + if (destroyableComponent->GetArmor() > 0) return; + + auto weakpoint = self->GetVar(u"weakpoint"); + + if (weakpoint == 0) { + Game::logger->Log("AmDarklingDragon", "Activating weakpoint\n"); + + self->AddTimer("ReviveTimer", 12); + + auto* baseCombatAIComponent = self->GetComponent(); + auto* skillComponent = self->GetComponent(); + + if (baseCombatAIComponent != nullptr) { + baseCombatAIComponent->SetDisabled(true); + baseCombatAIComponent->SetStunned(true); + } + + if (skillComponent != nullptr) { + skillComponent->Interrupt(); + } + + self->SetVar(u"weakpoint", 2); + + GameMessages::SendPlayAnimation(self, u"stunstart", 1.7f); + + self->AddTimer("timeToStunLoop", 1); + + auto position = self->GetPosition(); + auto forward = self->GetRotation().GetForwardVector(); + auto backwards = forward * -1; + + forward.x *= 10; + forward.z *= 10; + + auto rotation = self->GetRotation(); + + auto objectPosition = NiPoint3(); + + objectPosition.y = position.y; + objectPosition.x = position.x - (backwards.x * 8); + objectPosition.z = position.z - (backwards.z * 8); + + auto golem = self->GetVar(u"DragonSmashingGolem"); + + EntityInfo info {}; + info.lot = golem != 0 ? golem : 8340; + info.pos = objectPosition; + info.rot = rotation; + info.spawnerID = self->GetObjectID(); + info.settings = { + new LDFData(u"rebuild_activators", + std::to_string(objectPosition.x + forward.x) + "\x1f" + + std::to_string(objectPosition.y) + "\x1f" + + std::to_string(objectPosition.z + forward.z) + ), + new LDFData(u"respawn", 100000), + new LDFData(u"rebuild_reset_time", 15), + new LDFData(u"no_timed_spawn", true), + new LDFData(u"Dragon", self->GetObjectID()) + }; + + auto* golemObject = EntityManager::Instance()->CreateEntity(info); + + EntityManager::Instance()->ConstructEntity(golemObject); + } + } +} + +void AmDarklingDragon::OnTimerDone(Entity* self, std::string timerName) { + if (timerName == "ReviveHeldTimer") { + self->AddTimer("backToAttack", 2.5); + } + else if (timerName == "ExposeWeakSpotTimer") { + self->SetVar(u"weakspot", 1); + } + else if (timerName == "timeToStunLoop") { + GameMessages::SendPlayAnimation(self, u"stunloop", 1.8f); + } + else if (timerName == "ReviveTimer") { + GameMessages::SendPlayAnimation(self, u"stunend", 2.0f); + self->AddTimer("backToAttack", 1); + } + else if (timerName == "backToAttack") { + auto* baseCombatAIComponent = self->GetComponent(); + auto* skillComponent = self->GetComponent(); + if (baseCombatAIComponent != nullptr) + { + baseCombatAIComponent->SetDisabled(false); + baseCombatAIComponent->SetStunned(false); + } + if (skillComponent != nullptr) + { + skillComponent->Interrupt(); + } + self->SetVar(u"weakspot", -1); + GameMessages::SendNotifyObject(self->GetObjectID(), self->GetObjectID(), u"DragonRevive", UNASSIGNED_SYSTEM_ADDRESS); + } +} + +void AmDarklingDragon::OnFireEventServerSide(Entity *self, Entity *sender, std::string args, int32_t param1, int32_t param2, int32_t param3) { + if (args != "rebuildDone") return; + + self->AddTimer("ExposeWeakSpotTimer", 3.8f); + + self->CancelTimer("ReviveTimer"); + + self->AddTimer("ReviveHeldTimer", 10.5f); + + self->SetVar(u"Golem", sender->GetObjectID()); + + GameMessages::SendPlayAnimation(self, u"quickbuildhold", 1.9f); +} \ No newline at end of file diff --git a/dScripts/AmDarklingDragon.h b/dScripts/AmDarklingDragon.h new file mode 100644 index 00000000..8c3617d2 --- /dev/null +++ b/dScripts/AmDarklingDragon.h @@ -0,0 +1,12 @@ +#pragma once +#include "CppScripts.h" + +class AmDarklingDragon : public CppScripts::Script +{ +public: + void OnStartup(Entity* self) override; + void OnDie(Entity* self, Entity* killer) override; + void OnHitOrHealResult(Entity* self, Entity* attacker, int32_t damage) override; + void OnTimerDone(Entity* self, std::string timerName) override; + void OnFireEventServerSide(Entity *self, Entity *sender, std::string args, int32_t param1, int32_t param2, int32_t param3) override; +}; diff --git a/dScripts/AmNamedDarklingDragon.cpp b/dScripts/AmNamedDarklingDragon.cpp deleted file mode 100644 index c7f51cbd..00000000 --- a/dScripts/AmNamedDarklingDragon.cpp +++ /dev/null @@ -1,12 +0,0 @@ -#include "AmNamedDarklingDragon.h" -#include "BaseCombatAIComponent.h" - -void AmNamedDarklingDragon::OnStartup(Entity* self) -{ - auto* baseCombatAIComponent = self->GetComponent(); - - if (baseCombatAIComponent != nullptr) - { - baseCombatAIComponent->SetStunImmune(true); - } -} diff --git a/dScripts/AmNamedDarklingDragon.h b/dScripts/AmNamedDarklingDragon.h deleted file mode 100644 index cad5c2ca..00000000 --- a/dScripts/AmNamedDarklingDragon.h +++ /dev/null @@ -1,8 +0,0 @@ -#pragma once -#include "CppScripts.h" - -class AmNamedDarklingDragon : public CppScripts::Script -{ -public: - void OnStartup(Entity* self) override; -}; diff --git a/dScripts/CppScripts.cpp b/dScripts/CppScripts.cpp index f6029076..7cbac5f3 100644 --- a/dScripts/CppScripts.cpp +++ b/dScripts/CppScripts.cpp @@ -219,7 +219,7 @@ #include "AmSkullkinDrill.h" #include "AmSkullkinDrillStand.h" #include "AmSkullkinTower.h" -#include "AmNamedDarklingDragon.h" +#include "AmDarklingDragon.h" #include "AmBlueX.h" // NJ Scripts @@ -675,11 +675,10 @@ CppScripts::Script* CppScripts::GetScript(Entity* parent, const std::string& scr script = new AmSkullkinDrillStand(); else if (scriptName == "scripts\\02_server\\Map\\AM\\L_SKULLKIN_TOWER.lua") script = new AmSkullkinTower(); - // This just makes them immune to stuns. TODO: Make seperate scripts else if (scriptName == "scripts\\02_server\\Enemy\\AM\\L_AM_NAMED_DARKLING_DRAGON.lua") - script = new AmNamedDarklingDragon(); + script = new AmDarklingDragon(); else if (scriptName == "scripts\\02_server\\Enemy\\AM\\L_AM_DARKLING_DRAGON.lua") - script = new AmNamedDarklingDragon(); + script = new AmDarklingDragon(); else if (scriptName == "scripts\\02_server\\Enemy\\AM\\L_AM_DARKLING_APE.lua") script = new BaseEnemyApe(); else if (scriptName == "scripts\\02_server\\Map\\AM\\L_BLUE_X.lua") From 097af41392cac4608a39cbf162b5ca8b90cbbd6c Mon Sep 17 00:00:00 2001 From: EmosewaMC <39972741+EmosewaMC@users.noreply.github.com> Date: Wed, 19 Jan 2022 02:28:50 -0800 Subject: [PATCH 2/3] Deleted unused variables --- dScripts/AmDarklingDragon.cpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/dScripts/AmDarklingDragon.cpp b/dScripts/AmDarklingDragon.cpp index 435fa68d..be87f466 100644 --- a/dScripts/AmDarklingDragon.cpp +++ b/dScripts/AmDarklingDragon.cpp @@ -23,9 +23,6 @@ void AmDarklingDragon::OnDie(Entity* self, Entity* killer) { } self->SetVar(u"bDied", true); - - auto position = self->GetPosition(); - auto rotation = self->GetRotation(); auto golemId = self->GetVar(u"Golem"); From 46f375a58e37d60227ae13f07e126e1618b261e2 Mon Sep 17 00:00:00 2001 From: EmosewaMC <39972741+EmosewaMC@users.noreply.github.com> Date: Wed, 19 Jan 2022 02:31:22 -0800 Subject: [PATCH 3/3] Added comments to header file --- dScripts/AmDarklingDragon.h | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/dScripts/AmDarklingDragon.h b/dScripts/AmDarklingDragon.h index 8c3617d2..ea4c2a19 100644 --- a/dScripts/AmDarklingDragon.h +++ b/dScripts/AmDarklingDragon.h @@ -4,9 +4,45 @@ class AmDarklingDragon : public CppScripts::Script { public: + /** + * @brief When called, this function will make self immune to stuns and initialize a weakspot boolean to false. + * + * @param self The Entity that called this function. + */ void OnStartup(Entity* self) override; + /** + * @brief When called, this function will destroy the golem if it was alive, otherwise returns immediately. + * + * @param self The Entity that called this function. + * @param killer The Entity that killed self. + */ void OnDie(Entity* self, Entity* killer) override; + /** + * @brief When self is hit or healed, this function will check if self is at zero armor. If self is at zero armor, a golem Entity Quick Build + * is spawned that, when built, will reveal a weakpoint on the dragon that if hit will smash the dragon instantly. If at more than zero armor, + * this function returns early. + * + * @param self The Entity that was hit. + * @param attacker The Entity that attacked self. + * @param damage The amount of damage attacker did to self. + */ void OnHitOrHealResult(Entity* self, Entity* attacker, int32_t damage) override; + /** + * @brief Called when self has a timer that ended. + * + * @param self The Entity who owns a timer that finished. + * @param timerName The name of a timer attacked to self that has ended. + */ void OnTimerDone(Entity* self, std::string timerName) override; + /** + * @brief When the Client has finished rebuilding the Golem for the dragon, this function exposes the weak spot for a set amount of time. + * + * @param self The Entity that called this script. + * @param sender The Entity that sent a fired event. + * @param args The argument that tells us what event has been fired off. + * @param param1 Unused in this script. + * @param param2 Unused in this script. + * @param param3 Unused in this script. + */ void OnFireEventServerSide(Entity *self, Entity *sender, std::string args, int32_t param1, int32_t param2, int32_t param3) override; };