feat: implement ronin script

This commit is contained in:
David Markowitz
2026-06-21 20:57:09 -07:00
parent 5fa158298b
commit 30479a0ef0
11 changed files with 112 additions and 2 deletions

View File

@@ -521,6 +521,10 @@ void BaseCombatAIComponent::Serialize(RakNet::BitStream& outBitStream, bool bIsI
void BaseCombatAIComponent::SetAiState(AiState newState) { void BaseCombatAIComponent::SetAiState(AiState newState) {
if (newState == this->m_State) return; if (newState == this->m_State) return;
GameMessages::NotifyCombatAIStateChange stateMsg;
stateMsg.prevState = this->m_State;
stateMsg.newState = newState;
m_Parent->HandleMsg(stateMsg);
this->m_State = newState; this->m_State = newState;
m_DirtyStateOrTarget = true; m_DirtyStateOrTarget = true;
Game::entityManager->SerializeEntity(m_Parent); Game::entityManager->SerializeEntity(m_Parent);

View File

@@ -16,7 +16,7 @@ ScriptComponent::ScriptComponent(Entity* parent, const int32_t componentID, cons
m_ScriptName = scriptName; m_ScriptName = scriptName;
SetScript(scriptName); SetScript(scriptName);
RegisterMsg(&ScriptComponent::OnGetObjectReportInfo); Component::RegisterMsg(&ScriptComponent::OnGetObjectReportInfo);
} }
void ScriptComponent::Serialize(RakNet::BitStream& outBitStream, bool bIsInitialUpdate) { void ScriptComponent::Serialize(RakNet::BitStream& outBitStream, bool bIsInitialUpdate) {

View File

@@ -8,6 +8,9 @@
#include "CppScripts.h" #include "CppScripts.h"
#include "Component.h" #include "Component.h"
#include "GameMessages.h"
#include <functional>
#include <map>
#include <string> #include <string>
#include "eReplicaComponentType.h" #include "eReplicaComponentType.h"
@@ -45,6 +48,17 @@ public:
bool OnGetObjectReportInfo(GameMessages::GetObjectReportInfo& reportInfo); bool OnGetObjectReportInfo(GameMessages::GetObjectReportInfo& reportInfo);
// Registers a message from a script to be listened for on the parent object
template<typename ScriptClass, typename DerivedMsgType>
void RegisterMsg(ScriptClass* scriptThis, bool (ScriptClass::*scriptHandler)(Entity&, DerivedMsgType&)) {
const auto boundMsg = std::bind(scriptHandler, scriptThis, std::placeholders::_1, std::placeholders::_2);
const auto castWrapper = [this, boundMsg](GameMessages::GameMsg& msg) {
return boundMsg(*m_Parent, static_cast<DerivedMsgType&>(msg));
};
DerivedMsgType msg;
m_Parent->RegisterMsg(msg.msgId, castWrapper);
}
private: private:
/** /**
@@ -63,6 +77,8 @@ private:
bool m_Client; bool m_Client;
std::string m_ScriptName; std::string m_ScriptName;
std::map<MessageType::Game, std::function<bool(Entity&, GameMessages::GameMsg&)>> m_MsgHandlers;
}; };
#endif // SCRIPTCOMPONENT_H #endif // SCRIPTCOMPONENT_H

View File

@@ -45,6 +45,7 @@ enum class BehaviorSlot : int32_t;
enum class eVendorTransactionResult : uint32_t; enum class eVendorTransactionResult : uint32_t;
enum class eReponseMoveItemBetweenInventoryTypeCode : int32_t; enum class eReponseMoveItemBetweenInventoryTypeCode : int32_t;
enum class eMissionState : int; enum class eMissionState : int;
enum class AiState : uint32_t;
enum class eCameraTargetCyclingMode : int32_t { enum class eCameraTargetCyclingMode : int32_t {
ALLOW_CYCLE_TEAMMATES, ALLOW_CYCLE_TEAMMATES,
@@ -971,5 +972,12 @@ namespace GameMessages {
LWOOBJID objectID{}; LWOOBJID objectID{};
LOT lot{}; LOT lot{};
}; };
struct NotifyCombatAIStateChange : public GameMsg {
NotifyCombatAIStateChange() : GameMsg(MessageType::Game::NOTIFY_COMBAT_AI_STATE_CHANGE) {}
AiState newState;
AiState prevState;
};
}; };
#endif // GAMEMESSAGES_H #endif // GAMEMESSAGES_H

View File

@@ -1,4 +1,5 @@
set(DSCRIPTS_SOURCES_02_SERVER_ENEMY_FV set(DSCRIPTS_SOURCES_02_SERVER_ENEMY_FV
"DragonRonin.cpp"
"FvMaelstromCavalry.cpp" "FvMaelstromCavalry.cpp"
"FvMaelstromDragon.cpp" "FvMaelstromDragon.cpp"
PARENT_SCOPE) PARENT_SCOPE)

View File

@@ -0,0 +1,6 @@
#include "DragonRonin.h"
void DragonRonin::OnStartup(Entity* self) {
self->SetVar<float>(u"suicideTimer", 40);
CountdownDestroyAI::OnStartup(self);
}

View File

@@ -0,0 +1,7 @@
#pragma once
#include "CountdownDestroyAI.h"
class DragonRonin : public CountdownDestroyAI {
public:
void OnStartup(Entity* self) override;
};

View File

@@ -1,6 +1,7 @@
set(DSCRIPTS_SOURCES_02_SERVER_ENEMY_GENERAL set(DSCRIPTS_SOURCES_02_SERVER_ENEMY_GENERAL
"BaseEnemyMech.cpp" "BaseEnemyMech.cpp"
"BaseEnemyApe.cpp" "BaseEnemyApe.cpp"
"CountdownDestroyAI.cpp"
"GfApeSmashingQB.cpp" "GfApeSmashingQB.cpp"
"TreasureChestDragonServer.cpp" "TreasureChestDragonServer.cpp"
"EnemyNjBuff.cpp" "EnemyNjBuff.cpp"

View File

@@ -0,0 +1,50 @@
#include "CountdownDestroyAI.h"
#include "BaseCombatAIComponent.h"
#include "ScriptComponent.h"
void CountdownDestroyAI::OnStartup(Entity* self) {
CountdownStartup(*self);
auto* scriptComp = self->GetComponent<ScriptComponent>();
if (scriptComp) scriptComp->RegisterMsg(this, &CountdownDestroyAI::OnNotifyCombatAIStateChange);
}
void CountdownDestroyAI::CountdownStartup(Entity& self) {
auto suicideTimer = self.GetVar<float>(u"suicideTimer");
if (suicideTimer == 0.0f) suicideTimer = 60;
self.AddTimer("Dead", suicideTimer);
}
void CountdownDestroyAI::OnHit(Entity* self, Entity* attacker) {
if (!self->GetVar<bool>(u"ShouldBeDead")) return;
self->CancelTimer("IsBeingAttacked");
self->AddTimer("Dead", 5.0f);
}
void CountdownDestroyAI::OnTimerDone(Entity* self, std::string timerName) {
if (timerName == "Dead") {
self->SetVar<bool>(u"ShouldBeDead", true);
if (self->GetVar<bool>(u"Busy")) {
self->AddTimer("IsBeingAttacked", 5.0f);
} else {
self->Smash();
}
} else if (timerName == "IsBeingAttacked") {
self->Smash();
}
}
bool CountdownDestroyAI::OnNotifyCombatAIStateChange(Entity& self, GameMessages::NotifyCombatAIStateChange& notifyMsg) {
const auto curState = notifyMsg.newState;
if (curState == AiState::dead) return true;
if (curState == AiState::aggro) {
self.SetVar(u"Busy", true);
} else {
self.SetVar(u"Busy", false);
if (self.GetVar<bool>(u"ShouldBeDead")) {
self.Smash();
}
}
return true;
}

View File

@@ -0,0 +1,13 @@
#pragma once
#include "CppScripts.h"
#include "GameMessages.h"
class CountdownDestroyAI : public CppScripts::Script {
public:
void OnStartup(Entity* self) override;
void CountdownStartup(Entity& self);
void OnHit(Entity* self, Entity* attacker) override;
void OnTimerDone(Entity* self, std::string timerName) override;
bool OnNotifyCombatAIStateChange(Entity& self, GameMessages::NotifyCombatAIStateChange& msg);
};

View File

@@ -137,7 +137,9 @@
#include "FvFlyingCreviceDragon.h" #include "FvFlyingCreviceDragon.h"
#include "FvDragonInstanceServer.h" #include "FvDragonInstanceServer.h"
#include "FvMaelstromDragon.h" #include "FvMaelstromDragon.h"
#include "DragonRonin.h"
#include "FvDragonSmashingGolemQb.h" #include "FvDragonSmashingGolemQb.h"
#include "CountdownDestroyAI.h"
#include "TreasureChestDragonServer.h" #include "TreasureChestDragonServer.h"
#include "InstanceExitTransferPlayerToLastNonInstance.h" #include "InstanceExitTransferPlayerToLastNonInstance.h"
#include "FvFreeGfNinjas.h" #include "FvFreeGfNinjas.h"
@@ -492,7 +494,9 @@ namespace {
{"scripts\\02_server\\Map\\FV\\L_FV_HORSEMEN_TRIGGER.lua", []() {return new FvHorsemenTrigger();}}, {"scripts\\02_server\\Map\\FV\\L_FV_HORSEMEN_TRIGGER.lua", []() {return new FvHorsemenTrigger();}},
{"scripts\\ai\\FV\\L_FV_FLYING_CREVICE_DRAGON.lua", []() {return new FvFlyingCreviceDragon();}}, {"scripts\\ai\\FV\\L_FV_FLYING_CREVICE_DRAGON.lua", []() {return new FvFlyingCreviceDragon();}},
{"scripts\\ai\\FV\\Dragon_Instance\\L_FV_DRAGON_INSTANCE_SERVER.lua", []() {return new FvDragonInstanceServer();}}, {"scripts\\ai\\FV\\Dragon_Instance\\L_FV_DRAGON_INSTANCE_SERVER.lua", []() {return new FvDragonInstanceServer();}},
{"scripts\\02_server\\Enemy\\FV\\L_FV_DRAGON_RONIN.lua", []() {return new DragonRonin();}},
{"scripts\\02_server\\Enemy\\FV\\L_FV_MAELSTROM_DRAGON.lua", []() {return new FvMaelstromDragon();}}, {"scripts\\02_server\\Enemy\\FV\\L_FV_MAELSTROM_DRAGON.lua", []() {return new FvMaelstromDragon();}},
{"scripts\\02_server\\Enemy\\General\\L_COUNTDOWN_DESTROY_AI.lua", []() {return new CountdownDestroyAI();}},
{"scripts\\ai\\FV\\L_FV_DRAGON_SMASHING_GOLEM_QB.lua", []() {return new FvDragonSmashingGolemQb();}}, {"scripts\\ai\\FV\\L_FV_DRAGON_SMASHING_GOLEM_QB.lua", []() {return new FvDragonSmashingGolemQb();}},
{"scripts\\02_server\\Enemy\\General\\L_TREASURE_CHEST_DRAGON_SERVER.lua", []() {return new TreasureChestDragonServer();}}, {"scripts\\02_server\\Enemy\\General\\L_TREASURE_CHEST_DRAGON_SERVER.lua", []() {return new TreasureChestDragonServer();}},
{"scripts\\ai\\GENERAL\\L_INSTANCE_EXIT_TRANSFER_PLAYER_TO_LAST_NON_INSTANCE.lua", []() {return new InstanceExitTransferPlayerToLastNonInstance();}}, {"scripts\\ai\\GENERAL\\L_INSTANCE_EXIT_TRANSFER_PLAYER_TO_LAST_NON_INSTANCE.lua", []() {return new InstanceExitTransferPlayerToLastNonInstance();}},