diff --git a/dGame/Entity.cpp b/dGame/Entity.cpp index 95a550a6..bb78af29 100644 --- a/dGame/Entity.cpp +++ b/dGame/Entity.cpp @@ -1342,6 +1342,10 @@ void Entity::OnCollisionLeavePhantom(const LWOOBJID otherEntity) { auto* other = EntityManager::Instance()->GetEntity(otherEntity); if (!other) return; + for (CppScripts::Script* script : CppScripts::GetEntityScripts(this)) { + script->OnOffCollisionPhantom(this, other); + } + TriggerEvent(eTriggerEventType::EXIT, other); SwitchComponent* switchComp = GetComponent(); diff --git a/dGame/dComponents/PhantomPhysicsComponent.cpp b/dGame/dComponents/PhantomPhysicsComponent.cpp index ce205826..e6272aa4 100644 --- a/dGame/dComponents/PhantomPhysicsComponent.cpp +++ b/dGame/dComponents/PhantomPhysicsComponent.cpp @@ -216,6 +216,13 @@ PhantomPhysicsComponent::PhantomPhysicsComponent(Entity* parent) : Component(par m_dpEntity->SetRotation(m_Rotation); m_dpEntity->SetPosition(m_Position); dpWorld::Instance().AddEntity(m_dpEntity); + } else if (info->physicsAsset == "env\\env_won_fv_gas-blocking-volume.hkx"){ + m_dpEntity = new dpEntity(m_Parent->GetObjectID(), 390.496826f, 111.467964f, 600.821534f, true); + m_dpEntity->SetScale(m_Scale); + m_dpEntity->SetRotation(m_Rotation); + m_Position.y -= (111.467964f * m_Scale) / 2; + m_dpEntity->SetPosition(m_Position); + dpWorld::Instance().AddEntity(m_dpEntity); } else { //Game::logger->Log("PhantomPhysicsComponent", "This one is supposed to have %s", info->physicsAsset.c_str()); diff --git a/dScripts/CppScripts.cpp b/dScripts/CppScripts.cpp index b9b481f3..5459fd37 100644 --- a/dScripts/CppScripts.cpp +++ b/dScripts/CppScripts.cpp @@ -294,6 +294,10 @@ // WBL scripts #include "WblGenericZone.h" +// Alpha Scripts +#include "TriggerGas.h" +#include "ActNinjaSensei.h" + // pickups #include "SpecialCoinSpawner.h" #include "SpecialPowerupSpawner.h" @@ -304,6 +308,9 @@ #include "WildGfGlowbug.h" #include "WildAmbientCrab.h" #include "WildPants.h" +#include "WildNinjaStudent.h" +#include "WildNinjaSensei.h" +#include "WildNinjaBricks.h" //Big bad global bc this is a namespace and not a class: InvalidScript* invalidToReturn = new InvalidScript(); @@ -868,6 +875,12 @@ CppScripts::Script* CppScripts::GetScript(Entity* parent, const std::string& scr else if (scriptName == "scripts\\zone\\LUPs\\WBL_generic_zone.lua") script = new WblGenericZone(); + // Alpha + if (scriptName == "scripts\\ai\\FV\\L_TRIGGER_GAS.lua") + script = new TriggerGas(); + else if (scriptName == "scripts\\ai\\FV\\L_ACT_NINJA_SENSEI.lua") + script = new ActNinjaSensei(); + // pickups if (scriptName == "scripts\\ai\\SPEC\\L_SPECIAL_1_BRONZE-COIN-SPAWNER.lua") script = new SpecialCoinSpawner(1); @@ -907,12 +920,19 @@ CppScripts::Script* CppScripts::GetScript(Entity* parent, const std::string& scr script = new WildAmbientCrab(); else if (scriptName == "scripts\\ai\\WILD\\L_WILD_PANTS.lua") script = new WildPants(); + else if (scriptName == "scripts\\ai\\WILD\\L_WILD_NINJA_BRICKS.lua") + script = new WildNinjaBricks(); + else if (scriptName == "scripts\\ai\\WILD\\L_WILD_NINJA_STUDENT.lua") + script = new WildNinjaStudent(); + else if (scriptName == "scripts\\ai\\WILD\\L_WILD_NINJA_SENSEI.lua") + script = new WildNinjaSensei(); // handle invalid script reporting if the path is greater than zero and it's not an ignored script // information not really needed for sys admins but is for developers else if (script == invalidToReturn) { if ((scriptName.length() > 0) && !((scriptName == "scripts\\02_server\\Enemy\\General\\L_SUSPEND_LUA_AI.lua") || (scriptName == "scripts\\02_server\\Enemy\\General\\L_BASE_ENEMY_SPIDERLING.lua") || + (scriptName =="scripts\\ai\\FV\\L_ACT_NINJA_STUDENT.lua") || (scriptName == "scripts\\ai\\WILD\\L_WILD_GF_FROG.lua") || (scriptName == "scripts\\empty.lua") )) Game::logger->LogDebug("CppScripts", "LOT %i attempted to load CppScript for '%s', but returned InvalidScript.", parent->GetLOT(), scriptName.c_str()); diff --git a/dScripts/CppScripts.h b/dScripts/CppScripts.h index 21ff8427..5c702a70 100644 --- a/dScripts/CppScripts.h +++ b/dScripts/CppScripts.h @@ -44,6 +44,13 @@ namespace CppScripts { */ virtual void OnCollisionPhantom(Entity* self, Entity* target) {}; + /** + * Invoked upon an entity leaving the phantom collider on self. + * + * Equivalent to 'function onOffCollisionPhantom(self, msg)' + */ + virtual void OnOffCollisionPhantom(Entity* self, Entity* target) {}; + /** * Invoked when a player accepted a mission. * diff --git a/dScripts/ai/FV/ActNinjaSensei.cpp b/dScripts/ai/FV/ActNinjaSensei.cpp new file mode 100644 index 00000000..27e42219 --- /dev/null +++ b/dScripts/ai/FV/ActNinjaSensei.cpp @@ -0,0 +1,78 @@ +#include "ActNinjaSensei.h" +#include "Entity.h" +#include "EntityManager.h" +#include "GameMessages.h" + +void ActNinjaSensei::OnStartup(Entity* self) { + auto students = EntityManager::Instance()->GetEntitiesInGroup(this->m_StudentGroup); + std::vector validStudents = {}; + for (auto* student : students) { + if (student && student->GetLOT() == this->m_StudentLOT) validStudents.push_back(student); + } + self->SetVar(u"students", validStudents); + self->AddTimer("crane", 5); +} + +void ActNinjaSensei::OnTimerDone(Entity* self, std::string timerName) { + auto students = self->GetVar>(u"students"); + if (students.empty()) return; + + if (timerName == "crane") { + for (auto student : students) { + if (student) GameMessages::SendPlayAnimation(student, u"crane"); + } + GameMessages::SendPlayAnimation(self, u"crane"); + self->AddTimer("bow", 15.33); + } + + if (timerName == "bow") { + GameMessages::SendPlayAnimation(self, u"bow"); + for (auto student : students) { + if (student) GameMessages::SendPlayAnimation(student, u"bow"); + } + GameMessages::SendPlayAnimation(self, u"bow"); + self->AddTimer("tiger", 5); + } + + if (timerName == "tiger") { + GameMessages::SendPlayAnimation(self, u"tiger"); + for (auto student : students) { + if (student) GameMessages::SendPlayAnimation(student, u"tiger"); + } + GameMessages::SendPlayAnimation(self, u"tiger"); + self->AddTimer("bow2", 15.33); + } + + if (timerName == "bow2") { + GameMessages::SendPlayAnimation(self, u"bow"); + for (auto student : students) { + if (student) GameMessages::SendPlayAnimation(student, u"bow"); + } + GameMessages::SendPlayAnimation(self, u"bow"); + self->AddTimer("mantis", 5); + } + + if (timerName == "mantis") { + GameMessages::SendPlayAnimation(self, u"mantis"); + for (auto student : students) { + if (student) GameMessages::SendPlayAnimation(student, u"mantis"); + } + GameMessages::SendPlayAnimation(self, u"mantis"); + self->AddTimer("bow3", 15.3); + } + + if (timerName == "bow3") { + GameMessages::SendPlayAnimation(self, u"bow"); + for (auto student : students) { + if (student) GameMessages::SendPlayAnimation(student, u"bow"); + } + GameMessages::SendPlayAnimation(self, u"bow"); + self->AddTimer("repeat", 5); + } + + if (timerName == "repeat") { + self->CancelAllTimers(); + self->AddTimer("crane", 5); + } +} + diff --git a/dScripts/ai/FV/ActNinjaSensei.h b/dScripts/ai/FV/ActNinjaSensei.h new file mode 100644 index 00000000..c35ede12 --- /dev/null +++ b/dScripts/ai/FV/ActNinjaSensei.h @@ -0,0 +1,10 @@ +#pragma once +#include "CppScripts.h" + +class ActNinjaSensei : public CppScripts::Script { + void OnStartup(Entity* self) override; + void OnTimerDone(Entity* self, std::string timerName) override; +private: + std::string m_StudentGroup = "Sensei_kids"; + LOT m_StudentLOT = 2497; +}; diff --git a/dScripts/ai/FV/CMakeLists.txt b/dScripts/ai/FV/CMakeLists.txt index 2a8a3367..56418706 100644 --- a/dScripts/ai/FV/CMakeLists.txt +++ b/dScripts/ai/FV/CMakeLists.txt @@ -1,4 +1,5 @@ -set(DSCRIPTS_SOURCES_AI_FV +set(DSCRIPTS_SOURCES_AI_FV + "ActNinjaSensei.cpp" "ActNinjaTurret.cpp" "FvFlyingCreviceDragon.cpp" "FvDragonSmashingGolemQb.cpp" @@ -15,4 +16,5 @@ set(DSCRIPTS_SOURCES_AI_FV "FvPassThroughWall.cpp" "FvBounceOverWall.cpp" "FvMaelstromGeyser.cpp" + "TriggerGas.cpp" PARENT_SCOPE) diff --git a/dScripts/ai/FV/TriggerGas.cpp b/dScripts/ai/FV/TriggerGas.cpp new file mode 100644 index 00000000..7e9762e3 --- /dev/null +++ b/dScripts/ai/FV/TriggerGas.cpp @@ -0,0 +1,49 @@ +#include "TriggerGas.h" +#include "InventoryComponent.h" +#include "SkillComponent.h" +#include "Entity.h" +#include "dLogger.h" + + +void TriggerGas::OnStartup(Entity* self) { + self->AddTimer(this->m_TimerName, this->m_Time); +} + +void TriggerGas::OnCollisionPhantom(Entity* self, Entity* target) { + if (!target->IsPlayer()) return; + auto players = self->GetVar>(u"players"); + players.push_back(target); + self->SetVar(u"players", players); +} + +void TriggerGas::OnOffCollisionPhantom(Entity* self, Entity* target) { + auto players = self->GetVar>(u"players"); + if (!target->IsPlayer() || players.empty()) return; + auto position = std::find(players.begin(), players.end(), target); + if (position != players.end()) players.erase(position); + self->SetVar(u"players", players); +} + +void TriggerGas::OnTimerDone(Entity* self, std::string timerName) { + if (timerName != this->m_TimerName) return; + auto players = self->GetVar>(u"players"); + for (auto player : players) { + if (player->GetIsDead() || !player){ + auto position = std::find(players.begin(), players.end(), player); + if (position != players.end()) players.erase(position); + continue; + } + auto inventoryComponent = player->GetComponent(); + if (inventoryComponent) { + if (!inventoryComponent->IsEquipped(this->m_MaelstromHelmet)) { + auto* skillComponent = self->GetComponent(); + if (skillComponent) { + skillComponent->CastSkill(this->m_FogDamageSkill, player->GetObjectID()); + } + } + } + } + self->SetVar(u"players", players); + self->AddTimer(this->m_TimerName, this->m_Time); +} + diff --git a/dScripts/ai/FV/TriggerGas.h b/dScripts/ai/FV/TriggerGas.h new file mode 100644 index 00000000..284f2485 --- /dev/null +++ b/dScripts/ai/FV/TriggerGas.h @@ -0,0 +1,14 @@ +#pragma once +#include "CppScripts.h" + +class TriggerGas : public CppScripts::Script { + void OnStartup(Entity* self) override; + void OnCollisionPhantom(Entity* self, Entity* target) override; + void OnOffCollisionPhantom(Entity* self, Entity* target) override; + void OnTimerDone(Entity* self, std::string timerName) override; +private: + std::string m_TimerName = "gasTriggerDamage"; + float m_Time = 3.0f; + uint32_t m_MaelstromHelmet = 3068; + uint32_t m_FogDamageSkill = 103; +}; diff --git a/dScripts/ai/WILD/CMakeLists.txt b/dScripts/ai/WILD/CMakeLists.txt index d3e499db..446ce0d4 100644 --- a/dScripts/ai/WILD/CMakeLists.txt +++ b/dScripts/ai/WILD/CMakeLists.txt @@ -4,5 +4,8 @@ set(DSCRIPTS_SOURCES_AI_WILD "WildAmbientCrab.cpp" "WildAndScared.cpp" "WildGfGlowbug.cpp" + "WildNinjaBricks.cpp" + "WildNinjaStudent.cpp" + "WildNinjaSensei.cpp" "WildPants.cpp" PARENT_SCOPE) diff --git a/dScripts/ai/WILD/WildNinjaBricks.cpp b/dScripts/ai/WILD/WildNinjaBricks.cpp new file mode 100644 index 00000000..4fa65b01 --- /dev/null +++ b/dScripts/ai/WILD/WildNinjaBricks.cpp @@ -0,0 +1,13 @@ +#include "WildNinjaBricks.h" +#include "Entity.h" + +void WildNinjaBricks::OnStartup(Entity* self) { + self->AddToGroup("Ninjastuff"); +} + +void WildNinjaBricks::OnNotifyObject(Entity* self, Entity* sender, const std::string& name, int32_t param1, int32_t param2) { + if (name == "Crane") GameMessages::SendPlayAnimation(self, u"crane"); + else if (name == "Tiger") GameMessages::SendPlayAnimation(self, u"tiger"); + else if (name == "Mantis") GameMessages::SendPlayAnimation(self, u"mantis"); +} + diff --git a/dScripts/ai/WILD/WildNinjaBricks.h b/dScripts/ai/WILD/WildNinjaBricks.h new file mode 100644 index 00000000..a1f470a3 --- /dev/null +++ b/dScripts/ai/WILD/WildNinjaBricks.h @@ -0,0 +1,9 @@ +#pragma once +#include "CppScripts.h" + +class WildNinjaBricks : public CppScripts::Script { +public: + void OnStartup(Entity* self); + void OnNotifyObject(Entity* self, Entity* sender, const std::string& name, int32_t param1 = 0, int32_t param2 = 0) override; +}; + diff --git a/dScripts/ai/WILD/WildNinjaSensei.cpp b/dScripts/ai/WILD/WildNinjaSensei.cpp new file mode 100644 index 00000000..42ddfa21 --- /dev/null +++ b/dScripts/ai/WILD/WildNinjaSensei.cpp @@ -0,0 +1,36 @@ +#include "WildNinjaSensei.h" +#include "Entity.h" + +void WildNinjaSensei::OnStartup(Entity* self) { + GameMessages::SendPlayAnimation(self, u"bow"); + self->AddTimer("CraneStart", 5); +} + +void WildNinjaSensei::OnTimerDone(Entity* self, std::string timerName) { + if (timerName == "CraneStart") { + auto ninjas = EntityManager::Instance()->GetEntitiesInGroup("Ninjastuff"); + for (auto ninja : ninjas) ninja->NotifyObject(self, "Crane"); + self->AddTimer("Bow", 15.5f); + self->AddTimer("TigerStart", 25); + GameMessages::SendPlayAnimation(self, u"crane"); + } else if (timerName == "TigerStart") { + auto ninjas = EntityManager::Instance()->GetEntitiesInGroup("Ninjastuff"); + GameMessages::SendPlayAnimation(self, u"bow"); + for (auto ninja : ninjas) ninja->NotifyObject(self, "Tiger"); + self->AddTimer("Bow", 15.5f); + self->AddTimer("MantisStart", 25); + GameMessages::SendPlayAnimation(self, u"tiger"); + } else if (timerName == "MantisStart") { + auto ninjas = EntityManager::Instance()->GetEntitiesInGroup("Ninjastuff"); + GameMessages::SendPlayAnimation(self, u"tiger"); + for (auto ninja : ninjas) ninja->NotifyObject(self, "Mantis"); + self->AddTimer("Bow", 15.5f); + self->AddTimer("CraneStart", 25); + GameMessages::SendPlayAnimation(self, u"mantis"); + } else if (timerName == "Bow") { + auto ninjas = EntityManager::Instance()->GetEntitiesInGroup("Ninjastuff"); + for (auto ninja : ninjas) ninja->NotifyObject(self, "Bow"); + GameMessages::SendPlayAnimation(self, u"bow"); + } +} + diff --git a/dScripts/ai/WILD/WildNinjaSensei.h b/dScripts/ai/WILD/WildNinjaSensei.h new file mode 100644 index 00000000..c14b6f08 --- /dev/null +++ b/dScripts/ai/WILD/WildNinjaSensei.h @@ -0,0 +1,9 @@ +#pragma once +#include "CppScripts.h" + +class WildNinjaSensei : public CppScripts::Script { +public: + void OnStartup(Entity* self); + void OnTimerDone(Entity* self, std::string timerName); +}; + diff --git a/dScripts/ai/WILD/WildNinjaStudent.cpp b/dScripts/ai/WILD/WildNinjaStudent.cpp new file mode 100644 index 00000000..b7e2f585 --- /dev/null +++ b/dScripts/ai/WILD/WildNinjaStudent.cpp @@ -0,0 +1,14 @@ +#include "WildNinjaStudent.h" +#include "GameMessages.h" + +void WildNinjaStudent::OnStartup(Entity* self) { + self->AddToGroup("Ninjastuff"); + GameMessages::SendPlayAnimation(self, u"bow"); +} + +void WildNinjaStudent::OnNotifyObject(Entity* self, Entity* sender, const std::string& name, int32_t param1, int32_t param2) { + if (name == "Crane") GameMessages::SendPlayAnimation(self, u"crane"); + else if (name == "Tiger") GameMessages::SendPlayAnimation(self, u"tiger"); + else if (name == "Mantis") GameMessages::SendPlayAnimation(self, u"mantis"); + else if (name == "Bow") GameMessages::SendPlayAnimation(self, u"bow"); +} diff --git a/dScripts/ai/WILD/WildNinjaStudent.h b/dScripts/ai/WILD/WildNinjaStudent.h new file mode 100644 index 00000000..2948ee3c --- /dev/null +++ b/dScripts/ai/WILD/WildNinjaStudent.h @@ -0,0 +1,9 @@ +#pragma once +#include "CppScripts.h" + +class WildNinjaStudent : public CppScripts::Script { +public: + void OnStartup(Entity* self); + void OnNotifyObject(Entity* self, Entity* sender, const std::string& name, int32_t param1 = 0, int32_t param2 = 0) override; +}; + diff --git a/migrations/cdserver/6_ninja_sensei.sql b/migrations/cdserver/6_ninja_sensei.sql new file mode 100644 index 00000000..f3828b07 --- /dev/null +++ b/migrations/cdserver/6_ninja_sensei.sql @@ -0,0 +1,2 @@ +INSERT INTO ScriptComponent (id, script_name, client_script_name) VALUES (228, 'scripts\ai\FV\L_ACT_NINJA_SENSEI.lua', null); +UPDATE ComponentsRegistry SET component_id = 228 WHERE id = 2489 AND component_type = 5;