Implement some more trigger event calls and command handlers (#989)

* Implement some trigger event calls
and command handlers

* add zone summary dimissed GM

* break and remove log

* some cleanup in Gather Targets
and blocking out

* fix default value of unlock for play cinematic

* Log on errors
add enum for physics effect type
simplify nipoint3 logic
check arg count
add enum for End behavior

* tryparse for nipoint3

* totally didn't forget to include it

* bleh c++ is blah

* ???

* address feedback

* Fix for #1028
This commit is contained in:
Aaron Kimbrell 2023-03-25 05:26:39 -05:00 committed by GitHub
parent 72ca0f13ff
commit c415d0520a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
32 changed files with 461 additions and 152 deletions

View File

@ -319,3 +319,7 @@ std::vector<std::string> GeneralUtils::GetSqlFileNamesFromFolder(const std::stri
return sortedFiles;
}
bool GeneralUtils::TryParse(const std::string& x, const std::string& y, const std::string& z, NiPoint3& dst) {
return TryParse<float>(x.c_str(), dst.x) && TryParse<float>(y.c_str(), dst.y) && TryParse<float>(z.c_str(), dst.z);
}

View File

@ -10,6 +10,7 @@
#include <type_traits>
#include <stdexcept>
#include <BitStream.h>
#include "NiPoint3.h"
#include "Game.h"
#include "dLogger.h"
@ -208,6 +209,8 @@ namespace GeneralUtils {
return TryParse<T>(value.c_str(), dst);
}
bool TryParse(const std::string& x, const std::string& y, const std::string& z, NiPoint3& dst);
template<typename T>
std::u16string to_u16string(T value) {
return GeneralUtils::ASCIIToUTF16(std::to_string(value));

View File

@ -128,6 +128,12 @@ NiPoint3 NiPoint3::operator+(const NiPoint3& point) const {
return NiPoint3(this->x + point.x, this->y + point.y, this->z + point.z);
}
//! Operator for addition of vectors
NiPoint3 NiPoint3::operator+=(const NiPoint3& point) const {
return NiPoint3(this->x + point.x, this->y + point.y, this->z + point.z);
}
//! Operator for subtraction of vectors
NiPoint3 NiPoint3::operator-(const NiPoint3& point) const {
return NiPoint3(this->x - point.x, this->y - point.y, this->z - point.z);

View File

@ -135,6 +135,9 @@ public:
//! Operator for addition of vectors
NiPoint3 operator+(const NiPoint3& point) const;
//! Operator for addition of vectors
NiPoint3 operator+=(const NiPoint3& point) const;
//! Operator for subtraction of vectors
NiPoint3 operator-(const NiPoint3& point) const;

View File

@ -445,6 +445,7 @@ enum GAME_MSG : unsigned short {
GAME_MSG_BBB_SAVE_RESPONSE = 1006,
GAME_MSG_NOTIFY_CLIENT_OBJECT = 1042,
GAME_MSG_DISPLAY_ZONE_SUMMARY = 1043,
GAME_MSG_ZONE_SUMMARY_DISMISSED = 1044,
GAME_MSG_ACTIVITY_STATE_CHANGE_REQUEST = 1053,
GAME_MSG_MODIFY_PLAYER_ZONE_STATISTIC = 1046,
GAME_MSG_START_BUILDING_WITH_ITEM = 1057,

View File

@ -0,0 +1,11 @@
#ifndef __EENDBEHAVIOR__H__
#define __EENDBEHAVIOR__H__
#include <cstdint>
enum class eEndBehavior : uint32_t {
RETURN,
WAIT
};
#endif //!__EENDBEHAVIOR__H__

View File

@ -0,0 +1,15 @@
#ifndef __EPHYSICSEFFECTTYPE__H__
#define __EPHYSICSEFFECTTYPE__H__
#include <cstdint>
enum class ePhysicsEffectType : uint32_t {
PUSH,
ATTRACT,
REPULSE,
GRAVITY_SCALE,
FRICTION
};
#endif //!__EPHYSICSEFFECTTYPE__H__

View File

@ -35,7 +35,7 @@ public:
{"OnTimerDone", eTriggerEventType::TIMER_DONE},
{"OnRebuildComplete", eTriggerEventType::REBUILD_COMPLETE},
{"OnActivated", eTriggerEventType::ACTIVATED},
{"OnDeactivated", eTriggerEventType::DEACTIVATED},
{"OnDectivated", eTriggerEventType::DEACTIVATED}, // Dectivated vs Deactivated
{"OnArrived", eTriggerEventType::ARRIVED},
{"OnArrivedAtEndOfPath", eTriggerEventType::ARRIVED_AT_END_OF_PATH},
{"OnZoneSummaryDismissed", eTriggerEventType::ZONE_SUMMARY_DISMISSED},

View File

@ -763,7 +763,7 @@ void Entity::Initialize() {
no_ghosting:
TriggerEvent(eTriggerEventType::CREATE);
TriggerEvent(eTriggerEventType::CREATE, this);
if (m_Character) {
auto* controllablePhysicsComponent = GetComponent<ControllablePhysicsComponent>();
@ -1390,7 +1390,7 @@ void Entity::OnEmoteReceived(const int32_t emote, Entity* target) {
}
void Entity::OnUse(Entity* originator) {
TriggerEvent(eTriggerEventType::INTERACT);
TriggerEvent(eTriggerEventType::INTERACT, originator);
for (CppScripts::Script* script : CppScripts::GetEntityScripts(this)) {
script->OnUse(this, originator);
@ -1412,6 +1412,7 @@ void Entity::OnHitOrHealResult(Entity* attacker, int32_t damage) {
}
void Entity::OnHit(Entity* attacker) {
TriggerEvent(eTriggerEventType::HIT, attacker);
for (CppScripts::Script* script : CppScripts::GetEntityScripts(this)) {
script->OnHit(this, attacker);
}

View File

@ -163,6 +163,8 @@ void EntityManager::DestroyEntity(Entity* entity) {
return;
}
entity->TriggerEvent(eTriggerEventType::DESTROY, entity);
const auto id = entity->GetObjectID();
if (std::count(m_EntitiesToDelete.begin(), m_EntitiesToDelete.end(), id)) {
@ -588,7 +590,7 @@ void EntityManager::ScheduleForKill(Entity* entity) {
SwitchComponent* switchComp = entity->GetComponent<SwitchComponent>();
if (switchComp) {
entity->TriggerEvent(eTriggerEventType::DEACTIVATED);
entity->TriggerEvent(eTriggerEventType::DEACTIVATED, entity);
}
const auto objectId = entity->GetObjectID();

View File

@ -7,6 +7,7 @@
#include "dLogger.h"
#include "GameMessages.h"
#include <BitStream.h>
#include "eTriggerEventType.h"
BouncerComponent::BouncerComponent(Entity* parent) : Component(parent) {
m_PetEnabled = false;
@ -46,8 +47,10 @@ void BouncerComponent::SetPetBouncerEnabled(bool value) {
EntityManager::Instance()->SerializeEntity(m_Parent);
if (value) {
m_Parent->TriggerEvent(eTriggerEventType::PET_ON_SWITCH, m_Parent);
GameMessages::SendPlayFXEffect(m_Parent->GetObjectID(), 1513, u"create", "PetOnSwitch", LWOOBJID_EMPTY, 1, 1, true);
} else {
m_Parent->TriggerEvent(eTriggerEventType::PET_OFF_SWITCH, m_Parent);
GameMessages::SendStopFXEffect(m_Parent, true, "PetOnSwitch");
}

View File

@ -14,6 +14,7 @@
#include "EntityManager.h"
#include "ControllablePhysicsComponent.h"
#include "GameMessages.h"
#include "ePhysicsEffectType.h"
#include "CDClientManager.h"
#include "CDComponentsRegistryTable.h"
@ -36,7 +37,7 @@ PhantomPhysicsComponent::PhantomPhysicsComponent(Entity* parent) : Component(par
m_PositionInfoDirty = false;
m_IsPhysicsEffectActive = false;
m_EffectType = 0;
m_EffectType = ePhysicsEffectType::PUSH;
m_DirectionalMultiplier = 0.0f;
m_MinMax = false;
@ -405,7 +406,7 @@ void PhantomPhysicsComponent::SetDirectionalMultiplier(float mul) {
m_EffectInfoDirty = true;
}
void PhantomPhysicsComponent::SetEffectType(uint32_t type) {
void PhantomPhysicsComponent::SetEffectType(ePhysicsEffectType type) {
m_EffectType = type;
m_EffectInfoDirty = true;
}

View File

@ -17,6 +17,7 @@
class LDFBaseData;
class Entity;
class dpEntity;
enum class ePhysicsEffectType : uint32_t ;
/**
* Allows the creation of phantom physics for an entity: a physics object that is generally invisible but can be
@ -103,13 +104,13 @@ public:
* Returns the effect that's currently active, defaults to 0
* @return the effect that's currently active
*/
uint32_t GetEffectType() const { return m_EffectType; }
ePhysicsEffectType GetEffectType() const { return m_EffectType; }
/**
* Sets the effect that's currently active
* @param type the effect to set
*/
void SetEffectType(uint32_t type);
void SetEffectType(ePhysicsEffectType type);
/**
* Returns the Physics entity for the component
@ -168,7 +169,7 @@ private:
/**
* The physics effect that's currently active, defaults to 0
*/
uint32_t m_EffectType;
ePhysicsEffectType m_EffectType;
/**
* A scaling multiplier to add to the directional vector

View File

@ -8,6 +8,7 @@
#include "CharacterComponent.h"
#include "MissionComponent.h"
#include "eMissionTaskType.h"
#include "eTriggerEventType.h"
#include "dServer.h"
#include "PacketUtils.h"
@ -495,6 +496,8 @@ void RebuildComponent::CompleteRebuild(Entity* user) {
for (const auto& callback : m_RebuildCompleteCallbacks)
callback(user);
m_Parent->TriggerEvent(eTriggerEventType::REBUILD_COMPLETE, user);
auto* movingPlatform = m_Parent->GetComponent<MovingPlatformComponent>();
if (movingPlatform != nullptr) {
movingPlatform->OnCompleteRebuild();

View File

@ -43,7 +43,7 @@ void SwitchComponent::EntityEnter(Entity* entity) {
}
m_Active = true;
if (!m_Parent) return;
m_Parent->TriggerEvent(eTriggerEventType::ACTIVATED);
m_Parent->TriggerEvent(eTriggerEventType::ACTIVATED, entity);
const auto grpName = m_Parent->GetVarAsString(u"grp_name");
@ -79,7 +79,7 @@ void SwitchComponent::Update(float deltaTime) {
if (m_Timer <= 0.0f) {
m_Active = false;
if (!m_Parent) return;
m_Parent->TriggerEvent(eTriggerEventType::DEACTIVATED);
m_Parent->TriggerEvent(eTriggerEventType::DEACTIVATED, m_Parent);
const auto grpName = m_Parent->GetVarAsString(u"grp_name");

View File

@ -1,10 +1,19 @@
#include "TriggerComponent.h"
#include "dZoneManager.h"
#include "LUTriggers.h"
#include "TeamManager.h"
#include "eTriggerCommandType.h"
#include "eMissionTaskType.h"
#include "ePhysicsEffectType.h"
#include "CharacterComponent.h"
#include "ControllablePhysicsComponent.h"
#include "MissionComponent.h"
#include "PhantomPhysicsComponent.h"
#include "CDMissionTasksTable.h"
#include "Player.h"
#include "RebuildComponent.h"
#include "SkillComponent.h"
#include "eEndBehavior.h"
TriggerComponent::TriggerComponent(Entity* parent, const std::string triggerInfo): Component(parent) {
m_Parent = parent;
@ -51,19 +60,37 @@ void TriggerComponent::HandleTriggerCommand(LUTriggers::Command* command, Entity
case eTriggerCommandType::FIRE_EVENT:
HandleFireEvent(targetEntity, command->args);
break;
case eTriggerCommandType::DESTROY_OBJ: break;
case eTriggerCommandType::TOGGLE_TRIGGER: break;
case eTriggerCommandType::RESET_REBUILD: break;
case eTriggerCommandType::DESTROY_OBJ:
HandleDestroyObject(targetEntity, command->args);
break;
case eTriggerCommandType::TOGGLE_TRIGGER:
HandleToggleTrigger(targetEntity, command->args);
break;
case eTriggerCommandType::RESET_REBUILD:
HandleResetRebuild(targetEntity, command->args);
break;
case eTriggerCommandType::SET_PATH: break;
case eTriggerCommandType::SET_PICK_TYPE: break;
case eTriggerCommandType::MOVE_OBJECT: break;
case eTriggerCommandType::ROTATE_OBJECT: break;
case eTriggerCommandType::PUSH_OBJECT: break;
case eTriggerCommandType::REPEL_OBJECT: break;
case eTriggerCommandType::MOVE_OBJECT:
HandleMoveObject(targetEntity, argArray);
break;
case eTriggerCommandType::ROTATE_OBJECT:
HandleRotateObject(targetEntity, argArray);
break;
case eTriggerCommandType::PUSH_OBJECT:
HandlePushObject(targetEntity, argArray);
break;
case eTriggerCommandType::REPEL_OBJECT:
HandleRepelObject(targetEntity, command->args);
break;
case eTriggerCommandType::SET_TIMER: break;
case eTriggerCommandType::CANCEL_TIMER: break;
case eTriggerCommandType::PLAY_CINEMATIC: break;
case eTriggerCommandType::TOGGLE_BBB: break;
case eTriggerCommandType::PLAY_CINEMATIC:
HandlePlayCinematic(targetEntity, argArray);
break;
case eTriggerCommandType::TOGGLE_BBB:
HandleToggleBBB(targetEntity, command->args);
break;
case eTriggerCommandType::UPDATE_MISSION:
HandleUpdateMission(targetEntity, argArray);
break;
@ -75,8 +102,43 @@ void TriggerComponent::HandleTriggerCommand(LUTriggers::Command* command, Entity
case eTriggerCommandType::STOP_PATHING: break;
case eTriggerCommandType::START_PATHING: break;
case eTriggerCommandType::LOCK_OR_UNLOCK_CONTROLS: break;
case eTriggerCommandType::PLAY_EFFECT: break;
case eTriggerCommandType::STOP_EFFECT: break;
case eTriggerCommandType::PLAY_EFFECT:
HandlePlayEffect(targetEntity, argArray);
break;
case eTriggerCommandType::STOP_EFFECT:
GameMessages::SendStopFXEffect(targetEntity, true, command->args);
break;
case eTriggerCommandType::CAST_SKILL:
HandleCastSkill(targetEntity, command->args);
break;
case eTriggerCommandType::DISPLAY_ZONE_SUMMARY:
GameMessages::SendDisplayZoneSummary(targetEntity->GetObjectID(), targetEntity->GetSystemAddress(), false, command->args == "1", m_Parent->GetObjectID());
break;
case eTriggerCommandType::SET_PHYSICS_VOLUME_EFFECT:
HandleSetPhysicsVolumeEffect(targetEntity, argArray);
break;
case eTriggerCommandType::SET_PHYSICS_VOLUME_STATUS:
HandleSetPhysicsVolumeStatus(targetEntity, command->args);
break;
case eTriggerCommandType::SET_MODEL_TO_BUILD: break;
case eTriggerCommandType::SPAWN_MODEL_BRICKS: break;
case eTriggerCommandType::ACTIVATE_SPAWNER_NETWORK:
HandleActivateSpawnerNetwork(command->args);
break;
case eTriggerCommandType::DEACTIVATE_SPAWNER_NETWORK:
HandleDeactivateSpawnerNetwork(command->args);
break;
case eTriggerCommandType::RESET_SPAWNER_NETWORK:
HandleResetSpawnerNetwork(command->args);
break;
case eTriggerCommandType::DESTROY_SPAWNER_NETWORK_OBJECTS:
HandleDestroySpawnerNetworkObjects(command->args);
break;
case eTriggerCommandType::GO_TO_WAYPOINT: break;
case eTriggerCommandType::ACTIVATE_PHYSICS:
HandleActivatePhysics(targetEntity, command->args);
break;
// DEPRECATED BLOCK START
case eTriggerCommandType::ACTIVATE_MUSIC_CUE: break;
case eTriggerCommandType::DEACTIVATE_MUSIC_CUE: break;
case eTriggerCommandType::FLASH_MUSIC_CUE: break;
@ -87,20 +149,7 @@ void TriggerComponent::HandleTriggerCommand(LUTriggers::Command* command, Entity
case eTriggerCommandType::STOP_3D_AMBIENT_SOUND: break;
case eTriggerCommandType::ACTIVATE_MIXER_PROGRAM: break;
case eTriggerCommandType::DEACTIVATE_MIXER_PROGRAM: break;
case eTriggerCommandType::CAST_SKILL: break;
case eTriggerCommandType::DISPLAY_ZONE_SUMMARY: break;
case eTriggerCommandType::SET_PHYSICS_VOLUME_EFFECT:
HandleSetPhysicsVolume(targetEntity, argArray, command->target);
break;
case eTriggerCommandType::SET_PHYSICS_VOLUME_STATUS: break;
case eTriggerCommandType::SET_MODEL_TO_BUILD: break;
case eTriggerCommandType::SPAWN_MODEL_BRICKS: break;
case eTriggerCommandType::ACTIVATE_SPAWNER_NETWORK: break;
case eTriggerCommandType::DEACTIVATE_SPAWNER_NETWORK: break;
case eTriggerCommandType::RESET_SPAWNER_NETWORK: break;
case eTriggerCommandType::DESTROY_SPAWNER_NETWORK_OBJECTS: break;
case eTriggerCommandType::GO_TO_WAYPOINT: break;
case eTriggerCommandType::ACTIVATE_PHYSICS: break;
// DEPRECATED BLOCK END
default:
Game::logger->LogDebug("TriggerComponent", "Event %i was not handled!", command->id);
break;
@ -113,70 +162,262 @@ std::vector<Entity*> TriggerComponent::GatherTargets(LUTriggers::Command* comman
if (command->target == "self") entities.push_back(m_Parent);
else if (command->target == "zone") { /*TODO*/ }
else if (command->target == "target") { /*TODO*/ }
else if (command->target == "targetTeam") { /*TODO*/ }
else if (command->target == "objGroup") entities = EntityManager::Instance()->GetEntitiesInGroup(command->targetName);
else if (command->target == "allPlayers") { /*TODO*/ }
else if (command->target == "allNPCs") { /*TODO*/ }
if (optionalTarget) entities.push_back(optionalTarget);
else if (command->target == "target" && optionalTarget) entities.push_back(optionalTarget);
else if (command->target == "targetTeam" && optionalTarget) {
auto* team = TeamManager::Instance()->GetTeam(optionalTarget->GetObjectID());
for (const auto memberId : team->members) {
auto* member = EntityManager::Instance()->GetEntity(memberId);
if (member) entities.push_back(member);
}
} else if (command->target == "objGroup") entities = EntityManager::Instance()->GetEntitiesInGroup(command->targetName);
else if (command->target == "allPlayers") {
for (auto* player : Player::GetAllPlayers()) {
entities.push_back(player);
}
} else if (command->target == "allNPCs") { /*UNUSED*/ }
return entities;
}
void TriggerComponent::HandleSetPhysicsVolume(Entity* targetEntity, std::vector<std::string> argArray, std::string target) {
PhantomPhysicsComponent* phanPhys = m_Parent->GetComponent<PhantomPhysicsComponent>();
if (!phanPhys) return;
phanPhys->SetPhysicsEffectActive(true);
uint32_t effectType = 0;
std::transform(argArray.at(0).begin(), argArray.at(0).end(), argArray.at(0).begin(), ::tolower); //Transform to lowercase
if (argArray.at(0) == "push") effectType = 0;
else if (argArray.at(0) == "attract") effectType = 1;
else if (argArray.at(0) == "repulse") effectType = 2;
else if (argArray.at(0) == "gravity") effectType = 3;
else if (argArray.at(0) == "friction") effectType = 4;
phanPhys->SetEffectType(effectType);
phanPhys->SetDirectionalMultiplier(std::stof(argArray.at(1)));
if (argArray.size() > 4) {
NiPoint3 direction = NiPoint3::ZERO;
GeneralUtils::TryParse<float>(argArray.at(2), direction.x);
GeneralUtils::TryParse<float>(argArray.at(3), direction.y);
GeneralUtils::TryParse<float>(argArray.at(4), direction.z);
phanPhys->SetDirection(direction);
}
if (argArray.size() > 5) {
uint32_t min;
GeneralUtils::TryParse<uint32_t>(argArray.at(6), min);
phanPhys->SetMin(min);
uint32_t max;
GeneralUtils::TryParse<uint32_t>(argArray.at(7), max);
phanPhys->SetMax(max);
}
// TODO: why is this contruct and not serialize?
if (target == "self") EntityManager::Instance()->ConstructEntity(m_Parent);
}
void TriggerComponent::HandleUpdateMission(Entity* targetEntity, std::vector<std::string> argArray) {
CDMissionTasksTable* missionTasksTable = CDClientManager::Instance().GetTable<CDMissionTasksTable>();
std::vector<CDMissionTasks> missionTasks = missionTasksTable->Query([=](CDMissionTasks entry) {
return (entry.targetGroup == argArray.at(4));
});
for (const CDMissionTasks& task : missionTasks) {
MissionComponent* missionComponent = targetEntity->GetComponent<MissionComponent>();
if (!missionComponent) continue;
missionComponent->ForceProgress(task.id, task.uid, std::stoi(argArray.at(2)));
}
}
void TriggerComponent::HandleFireEvent(Entity* targetEntity, std::string args) {
for (CppScripts::Script* script : CppScripts::GetEntityScripts(targetEntity)) {
script->OnFireEventServerSide(targetEntity, m_Parent, args, 0, 0, 0);
}
}
void TriggerComponent::HandleDestroyObject(Entity* targetEntity, std::string args){
uint32_t killType;
GeneralUtils::TryParse<uint32_t>(args, killType);
targetEntity->Smash(m_Parent->GetObjectID(), static_cast<eKillType>(killType));
}
void TriggerComponent::HandleToggleTrigger(Entity* targetEntity, std::string args){
auto* triggerComponent = targetEntity->GetComponent<TriggerComponent>();
if (!triggerComponent) {
Game::logger->Log("TriggerComponent::HandleToggleTrigger", "Trigger component not found!");
return;
}
triggerComponent->SetTriggerEnabled(args == "1");
}
void TriggerComponent::HandleResetRebuild(Entity* targetEntity, std::string args){
auto* rebuildComponent = targetEntity->GetComponent<RebuildComponent>();
if (!rebuildComponent) {
Game::logger->Log("TriggerComponent::HandleResetRebuild", "Rebuild component not found!");
return;
}
rebuildComponent->ResetRebuild(args == "1");
}
void TriggerComponent::HandleMoveObject(Entity* targetEntity, std::vector<std::string> argArray){
if (argArray.size() <= 2) return;
auto position = targetEntity->GetPosition();
NiPoint3 offset = NiPoint3::ZERO;
GeneralUtils::TryParse(argArray.at(0), argArray.at(1), argArray.at(2), offset);
position += offset;
targetEntity->SetPosition(position);
}
void TriggerComponent::HandleRotateObject(Entity* targetEntity, std::vector<std::string> argArray){
if (argArray.size() <= 2) return;
NiPoint3 vector = NiPoint3::ZERO;
GeneralUtils::TryParse(argArray.at(0), argArray.at(1), argArray.at(2), vector);
NiQuaternion rotation = NiQuaternion::FromEulerAngles(vector);
targetEntity->SetRotation(rotation);
}
void TriggerComponent::HandlePushObject(Entity* targetEntity, std::vector<std::string> argArray){
auto* phantomPhysicsComponent = m_Parent->GetComponent<PhantomPhysicsComponent>();
if (!phantomPhysicsComponent) {
Game::logger->Log("TriggerComponent::HandlePushObject", "Phantom Physics component not found!");
return;
}
phantomPhysicsComponent->SetPhysicsEffectActive(true);
phantomPhysicsComponent->SetEffectType(ePhysicsEffectType::PUSH);
phantomPhysicsComponent->SetDirectionalMultiplier(1);
NiPoint3 direction = NiPoint3::ZERO;
GeneralUtils::TryParse(argArray.at(0), argArray.at(1), argArray.at(2), direction);
phantomPhysicsComponent->SetDirection(direction);
EntityManager::Instance()->SerializeEntity(m_Parent);
}
void TriggerComponent::HandleRepelObject(Entity* targetEntity, std::string args){
auto* phantomPhysicsComponent = m_Parent->GetComponent<PhantomPhysicsComponent>();
if (!phantomPhysicsComponent) {
Game::logger->Log("TriggerComponent::HandleRepelObject", "Phantom Physics component not found!");
return;
}
float forceMultiplier;
GeneralUtils::TryParse<float>(args, forceMultiplier);
phantomPhysicsComponent->SetPhysicsEffectActive(true);
phantomPhysicsComponent->SetEffectType(ePhysicsEffectType::REPULSE);
phantomPhysicsComponent->SetDirectionalMultiplier(forceMultiplier);
auto triggerPos = m_Parent->GetPosition();
auto targetPos = targetEntity->GetPosition();
// normalize the vectors to get the direction
auto delta = targetPos - triggerPos;
auto length = delta.Length();
NiPoint3 direction = delta / length;
phantomPhysicsComponent->SetDirection(direction);
EntityManager::Instance()->SerializeEntity(m_Parent);
}
void TriggerComponent::HandlePlayCinematic(Entity* targetEntity, std::vector<std::string> argArray) {
float leadIn = -1.0;
auto wait = eEndBehavior::RETURN;
bool unlock = true;
bool leaveLocked = false;
bool hidePlayer = false;
if (argArray.size() >= 2) {
GeneralUtils::TryParse<float>(argArray.at(1), leadIn);
if (argArray.size() >= 3 && argArray.at(2) == "wait") {
wait = eEndBehavior::WAIT;
if (argArray.size() >= 4 && argArray.at(3) == "unlock") {
unlock = false;
if (argArray.size() >= 5 && argArray.at(4) == "leavelocked") {
leaveLocked = true;
if (argArray.size() >= 6 && argArray.at(5) == "hideplayer") {
hidePlayer = true;
}
}
}
}
}
GameMessages::SendPlayCinematic(targetEntity->GetObjectID(), GeneralUtils::UTF8ToUTF16(argArray.at(0)), targetEntity->GetSystemAddress(), true, true, false, false, wait, hidePlayer, leadIn, leaveLocked, unlock);
}
void TriggerComponent::HandleToggleBBB(Entity* targetEntity, std::string args) {
auto* character = targetEntity->GetCharacter();
if (!character) {
Game::logger->Log("TriggerComponent::HandleToggleBBB", "Character was not found!");
return;
}
bool buildMode = !(character->GetBuildMode());
if (args == "enter") buildMode = true;
else if (args == "exit") buildMode = false;
character->SetBuildMode(buildMode);
}
void TriggerComponent::HandleUpdateMission(Entity* targetEntity, std::vector<std::string> argArray) {
// there are only explore tasks used
// If others need to be implemented for modding
// then we need a good way to convert this from a string to that enum
if (argArray.at(0) != "exploretask") return;
MissionComponent* missionComponent = targetEntity->GetComponent<MissionComponent>();
if (!missionComponent){
Game::logger->Log("TriggerComponent::HandleUpdateMission", "Mission component not found!");
return;
}
missionComponent->Progress(eMissionTaskType::EXPLORE, 0, 0, argArray.at(4));
}
void TriggerComponent::HandlePlayEffect(Entity* targetEntity, std::vector<std::string> argArray) {
if (argArray.size() < 3) return;
int32_t effectID = 0;
if (!GeneralUtils::TryParse<int32_t>(argArray.at(1), effectID)) return;
std::u16string effectType = GeneralUtils::UTF8ToUTF16(argArray.at(2));
float priority = 1;
if (argArray.size() == 4) GeneralUtils::TryParse<float>(argArray.at(3), priority);
GameMessages::SendPlayFXEffect(targetEntity, effectID, effectType, argArray.at(0), LWOOBJID_EMPTY, priority);
}
void TriggerComponent::HandleCastSkill(Entity* targetEntity, std::string args){
auto* skillComponent = targetEntity->GetComponent<SkillComponent>();
if (!skillComponent) {
Game::logger->Log("TriggerComponent::HandleCastSkill", "Skill component not found!");
return;
}
uint32_t skillId;
GeneralUtils::TryParse<uint32_t>(args, skillId);
skillComponent->CastSkill(skillId, targetEntity->GetObjectID());
}
void TriggerComponent::HandleSetPhysicsVolumeEffect(Entity* targetEntity, std::vector<std::string> argArray) {
auto* phantomPhysicsComponent = targetEntity->GetComponent<PhantomPhysicsComponent>();
if (!phantomPhysicsComponent) {
Game::logger->Log("TriggerComponent::HandleSetPhysicsVolumeEffect", "Phantom Physics component not found!");
return;
}
phantomPhysicsComponent->SetPhysicsEffectActive(true);
ePhysicsEffectType effectType = ePhysicsEffectType::PUSH;
std::transform(argArray.at(0).begin(), argArray.at(0).end(), argArray.at(0).begin(), ::tolower); //Transform to lowercase
if (argArray.at(0) == "push") effectType = ePhysicsEffectType::PUSH;
else if (argArray.at(0) == "attract") effectType = ePhysicsEffectType::ATTRACT;
else if (argArray.at(0) == "repulse") effectType = ePhysicsEffectType::REPULSE;
else if (argArray.at(0) == "gravity") effectType = ePhysicsEffectType::GRAVITY_SCALE;
else if (argArray.at(0) == "friction") effectType = ePhysicsEffectType::FRICTION;
phantomPhysicsComponent->SetEffectType(effectType);
phantomPhysicsComponent->SetDirectionalMultiplier(std::stof(argArray.at(1)));
if (argArray.size() > 4) {
NiPoint3 direction = NiPoint3::ZERO;
GeneralUtils::TryParse(argArray.at(2), argArray.at(3), argArray.at(4), direction);
phantomPhysicsComponent->SetDirection(direction);
}
if (argArray.size() > 5) {
uint32_t min;
GeneralUtils::TryParse<uint32_t>(argArray.at(6), min);
phantomPhysicsComponent->SetMin(min);
uint32_t max;
GeneralUtils::TryParse<uint32_t>(argArray.at(7), max);
phantomPhysicsComponent->SetMax(max);
}
EntityManager::Instance()->SerializeEntity(targetEntity);
}
void TriggerComponent::HandleSetPhysicsVolumeStatus(Entity* targetEntity, std::string args) {
auto* phantomPhysicsComponent = targetEntity->GetComponent<PhantomPhysicsComponent>();
if (!phantomPhysicsComponent) {
Game::logger->Log("TriggerComponent::HandleSetPhysicsVolumeEffect", "Phantom Physics component not found!");
return;
}
phantomPhysicsComponent->SetPhysicsEffectActive(args == "On");
EntityManager::Instance()->SerializeEntity(targetEntity);
}
void TriggerComponent::HandleActivateSpawnerNetwork(std::string args){
for (auto* spawner : dZoneManager::Instance()->GetSpawnersByName(args)) {
if (spawner) spawner->Activate();
}
}
void TriggerComponent::HandleDeactivateSpawnerNetwork(std::string args){
for (auto* spawner : dZoneManager::Instance()->GetSpawnersByName(args)) {
if (spawner) spawner->Deactivate();
}
}
void TriggerComponent::HandleResetSpawnerNetwork(std::string args){
for (auto* spawner : dZoneManager::Instance()->GetSpawnersByName(args)) {
if (spawner) spawner->Reset();
}
}
void TriggerComponent::HandleDestroySpawnerNetworkObjects(std::string args){
for (auto* spawner : dZoneManager::Instance()->GetSpawnersByName(args)) {
if (spawner) spawner->DestroyAllEntities();
}
}
void TriggerComponent::HandleActivatePhysics(Entity* targetEntity, std::string args) {
if (args == "true") {
// TODO add physics entity if there isn't one
} else if (args == "false"){
// TODO remove Phsyics entity if there is one
} else {
Game::logger->LogDebug("TriggerComponent", "Invalid argument for ActivatePhysics Trigger: %s", args.c_str());
}
}

View File

@ -2,13 +2,9 @@
#define __TRIGGERCOMPONENT__H__
#include "Component.h"
#include "LUTriggers.h"
#include "eReplicaComponentType.h"
namespace LUTriggers {
struct Trigger;
struct Command;
};
class TriggerComponent : public Component {
public:
static const eReplicaComponentType ComponentType = eReplicaComponentType::TRIGGER;
@ -17,18 +13,35 @@ public:
void TriggerEvent(eTriggerEventType event, Entity* optionalTarget = nullptr);
LUTriggers::Trigger* GetTrigger() const { return m_Trigger; }
void SetTriggerEnabled(bool enabled){ m_Trigger->enabled = enabled; };
private:
void HandleTriggerCommand(LUTriggers::Command* command, Entity* optionalTarget);
std::vector<std::string> ParseArgs(std::string args);
std::vector<Entity*> GatherTargets(LUTriggers::Command* command, Entity* optionalTarget);
// Trigger Event Handlers
void HandleSetPhysicsVolume(Entity* targetEntity, std::vector<std::string> argArray, std::string target);
void HandleUpdateMission(Entity* targetEntity, std::vector<std::string> argArray);
void HandleFireEvent(Entity* targetEntity, std::string args);
void HandleCastSkill(Entity* targetEntity, uint32_t skillID);
void HandleDestroyObject(Entity* targetEntity, std::string args);
void HandleToggleTrigger(Entity* targetEntity, std::string args);
void HandleResetRebuild(Entity* targetEntity, std::string args);
void HandleMoveObject(Entity* targetEntity, std::vector<std::string> argArray);
void HandleRotateObject(Entity* targetEntity, std::vector<std::string> argArray);
void HandlePushObject(Entity* targetEntity, std::vector<std::string> argArray);
void HandleRepelObject(Entity* targetEntity, std::string args);
void HandlePlayCinematic(Entity* targetEntity, std::vector<std::string> argArray);
void HandleToggleBBB(Entity* targetEntity, std::string args);
void HandleUpdateMission(Entity* targetEntity, std::vector<std::string> argArray);
void HandlePlayEffect(Entity* targetEntity, std::vector<std::string> argArray);
void HandleCastSkill(Entity* targetEntity, std::string args);
void HandleSetPhysicsVolumeEffect(Entity* targetEntity, std::vector<std::string> argArray);
void HandleSetPhysicsVolumeStatus(Entity* targetEntity, std::string args);
void HandleActivateSpawnerNetwork(std::string args);
void HandleDeactivateSpawnerNetwork(std::string args);
void HandleResetSpawnerNetwork(std::string args);
void HandleDestroySpawnerNetworkObjects(std::string args);
void HandleActivatePhysics(Entity* targetEntity, std::string args);
LUTriggers::Trigger* m_Trigger;
};

View File

@ -673,6 +673,9 @@ void GameMessageHandler::HandleMessage(RakNet::BitStream* inStream, const System
case GAME_MSG_ACTIVATE_BUBBLE_BUFF:
GameMessages::HandleActivateBubbleBuff(inStream, entity);
break;
case GAME_MSG_ZONE_SUMMARY_DISMISSED:
GameMessages::HandleZoneSummaryDismissed(inStream, entity);
break;
default:
// Game::logger->Log("GameMessageHandler", "Unknown game message ID: %i", messageID);
break;

View File

@ -34,6 +34,7 @@
#include "eRacingTaskParam.h"
#include "eMissionTaskType.h"
#include "eMissionState.h"
#include "eTriggerEventType.h"
#include <sstream>
#include <future>
@ -2813,7 +2814,7 @@ void GameMessages::HandleSetConsumableItem(RakNet::BitStream* inStream, Entity*
void GameMessages::SendPlayCinematic(LWOOBJID objectId, std::u16string pathName, const SystemAddress& sysAddr,
bool allowGhostUpdates, bool bCloseMultiInteract, bool bSendServerNotify, bool bUseControlledObjectForAudioListener,
int endBehavior, bool hidePlayerDuringCine, float leadIn, bool leavePlayerLockedWhenFinished,
eEndBehavior endBehavior, bool hidePlayerDuringCine, float leadIn, bool leavePlayerLockedWhenFinished,
bool lockPlayer, bool result, bool skipIfSamePath, float startTimeAdvance) {
CBITSTREAM;
CMSGHEADER;
@ -2826,8 +2827,8 @@ void GameMessages::SendPlayCinematic(LWOOBJID objectId, std::u16string pathName,
bitStream.Write(bSendServerNotify);
bitStream.Write(bUseControlledObjectForAudioListener);
bitStream.Write(endBehavior != 0);
if (endBehavior != 0) bitStream.Write(endBehavior);
bitStream.Write(endBehavior != eEndBehavior::RETURN);
if (endBehavior != eEndBehavior::RETURN) bitStream.Write(endBehavior);
bitStream.Write(hidePlayerDuringCine);
@ -6155,6 +6156,13 @@ void GameMessages::SendDeactivateBubbleBuffFromServer(LWOOBJID objectId, const S
SEND_PACKET;
}
void GameMessages::HandleZoneSummaryDismissed(RakNet::BitStream* inStream, Entity* entity) {
LWOOBJID player_id;
inStream->Read<LWOOBJID>(player_id);
auto target = EntityManager::Instance()->GetEntity(player_id);
entity->TriggerEvent(eTriggerEventType::ZONE_SUMMARY_DISMISSED, target);
};
void GameMessages::SendSetNamebillboardState(const SystemAddress& sysAddr, LWOOBJID objectId) {
CBITSTREAM;
CMSGHEADER;

View File

@ -7,6 +7,7 @@
#include <vector>
#include "eMovementPlatformState.h"
#include "NiPoint3.h"
#include "eEndBehavior.h"
class AMFValue;
class Entity;
@ -266,7 +267,7 @@ namespace GameMessages {
void SendPlayCinematic(LWOOBJID objectId, std::u16string pathName, const SystemAddress& sysAddr,
bool allowGhostUpdates = true, bool bCloseMultiInteract = true, bool bSendServerNotify = false, bool bUseControlledObjectForAudioListener = false,
int endBehavior = 0, bool hidePlayerDuringCine = false, float leadIn = -1, bool leavePlayerLockedWhenFinished = false,
eEndBehavior endBehavior = eEndBehavior::RETURN, bool hidePlayerDuringCine = false, float leadIn = -1, bool leavePlayerLockedWhenFinished = false,
bool lockPlayer = true, bool result = false, bool skipIfSamePath = false, float startTimeAdvance = 0);
void SendEndCinematic(LWOOBJID objectID, std::u16string pathName, const SystemAddress& sysAddr = UNASSIGNED_SYSTEM_ADDRESS,
@ -633,6 +634,8 @@ namespace GameMessages {
void SendActivateBubbleBuffFromServer(LWOOBJID objectId, const SystemAddress& sysAddr);
void SendDeactivateBubbleBuffFromServer(LWOOBJID objectId, const SystemAddress& sysAddr);
void HandleZoneSummaryDismissed(RakNet::BitStream* inStream, Entity* entity);
};
#endif // GAMEMESSAGES_H

View File

@ -2018,7 +2018,7 @@ void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entit
auto* phantomPhysicsComponent = closest->GetComponent<PhantomPhysicsComponent>();
if (phantomPhysicsComponent != nullptr) {
ChatPackets::SendSystemMessage(sysAddr, u"Type: " + (GeneralUtils::to_u16string(phantomPhysicsComponent->GetEffectType())));
ChatPackets::SendSystemMessage(sysAddr, u"Type: " + (GeneralUtils::to_u16string(static_cast<uint32_t>(phantomPhysicsComponent->GetEffectType()))));
const auto dir = phantomPhysicsComponent->GetDirection();
ChatPackets::SendSystemMessage(sysAddr, u"Direction: <" + (GeneralUtils::to_u16string(dir.x)) + u", " + (GeneralUtils::to_u16string(dir.y)) + u", " + (GeneralUtils::to_u16string(dir.z)) + u">");
ChatPackets::SendSystemMessage(sysAddr, u"Multiplier: " + (GeneralUtils::to_u16string(phantomPhysicsComponent->GetDirectionalMultiplier())));

View File

@ -5,13 +5,14 @@
#include "EntityManager.h"
#include "AgMonumentLaserServer.h"
#include "EntityManager.h"
#include "ePhysicsEffectType.h"
#include "eReplicaComponentType.h"
void AgLaserSensorServer::OnStartup(Entity* self) {
PhantomPhysicsComponent* physComp = static_cast<PhantomPhysicsComponent*>(self->GetComponent(eReplicaComponentType::PHANTOM_PHYSICS));
physComp->SetPhysicsEffectActive(true);
physComp->SetEffectType(2); // repulse (prolly should make definitions of these are in Entity.cpp)
physComp->SetEffectType(ePhysicsEffectType::REPULSE);
physComp->SetDirectionalMultiplier(static_cast<float>(m_RepelForce));
physComp->SetDirection(NiPoint3::UNIT_Y);

View File

@ -2,6 +2,7 @@
#include "EntityManager.h"
#include "GameMessages.h"
#include "Preconditions.h"
#include "eEndBehavior.h"
#include "DestroyableComponent.h"
#ifdef _WIN32
@ -52,7 +53,7 @@ void MastTeleport::OnTimerDone(Entity* self, std::string timerName) {
if (!cinematic.empty()) {
GameMessages::SendPlayCinematic(playerId, GeneralUtils::ASCIIToUTF16(cinematic), player->GetSystemAddress(),
true, true, false, false, 0, false, leanIn
true, true, false, false, eEndBehavior::RETURN, false, leanIn
);
}

View File

@ -1,6 +1,7 @@
#include "ForceVolumeServer.h"
#include "PhantomPhysicsComponent.h"
#include "EntityManager.h"
#include "ePhysicsEffectType.h"
void ForceVolumeServer::OnStartup(Entity* self) {
auto* phantomPhysicsComponent = self->GetComponent<PhantomPhysicsComponent>();
@ -12,7 +13,7 @@ void ForceVolumeServer::OnStartup(Entity* self) {
const auto forceY = self->GetVar<float>(u"ForceY");
const auto forceZ = self->GetVar<float>(u"ForceZ");
phantomPhysicsComponent->SetEffectType(0); // PUSH
phantomPhysicsComponent->SetEffectType(ePhysicsEffectType::PUSH);
phantomPhysicsComponent->SetDirectionalMultiplier(forceAmount);
phantomPhysicsComponent->SetDirection({ forceX, forceY, forceZ });
phantomPhysicsComponent->SetPhysicsEffectActive(true);

View File

@ -4,6 +4,7 @@
#include "MissionComponent.h"
#include "eMissionTaskType.h"
#include "eMissionState.h"
#include "eEndBehavior.h"
void NtAssemblyTubeServer::OnStartup(Entity* self) {
self->SetProximityRadius(5, "teleport");
@ -45,7 +46,7 @@ void NtAssemblyTubeServer::RunAssemblyTube(Entity* self, Entity* player) {
if (!teleCinematic.empty()) {
const auto teleCinematicUname = teleCinematic;
GameMessages::SendPlayCinematic(player->GetObjectID(), teleCinematicUname, player->GetSystemAddress(),
true, true, true, false, 0, false, -1, false, true
true, true, true, false, eEndBehavior::RETURN, false, -1, false, true
);
}

View File

@ -3,6 +3,7 @@
#include "EntityManager.h"
#include "MissionComponent.h"
#include "eMissionTaskType.h"
#include "ePhysicsEffectType.h"
void NtSentinelWalkwayServer::OnStartup(Entity* self) {
auto* phantomPhysicsComponent = self->GetComponent<PhantomPhysicsComponent>();
@ -19,7 +20,7 @@ void NtSentinelWalkwayServer::OnStartup(Entity* self) {
const auto forward = self->GetRotation().GetRightVector() * -1;
phantomPhysicsComponent->SetEffectType(0); // PUSH
phantomPhysicsComponent->SetEffectType(ePhysicsEffectType::PUSH);
phantomPhysicsComponent->SetDirectionalMultiplier(force);
phantomPhysicsComponent->SetDirection(forward);
phantomPhysicsComponent->SetPhysicsEffectActive(true);

View File

@ -1,6 +1,7 @@
#include "NtVentureCannonServer.h"
#include "GameMessages.h"
#include "EntityManager.h"
#include "eEndBehavior.h"
void NtVentureCannonServer::OnUse(Entity* self, Entity* user) {
auto* player = user;
@ -73,7 +74,7 @@ void NtVentureCannonServer::EnterCannonEnded(Entity* self, Entity* player) {
const auto exitCinematicUname = exitCinematic;
GameMessages::SendPlayCinematic(player->GetObjectID(), exitCinematicUname, player->GetSystemAddress(),
true, true, true, false, 0, false, 0, false, false
true, true, true, false, eEndBehavior::RETURN, false, 0, false, false
);
self->AddCallbackTimer(1.5f, [this, self, playerID]() {

View File

@ -303,18 +303,8 @@ void BasePropertyServer::ResetSpawner(const std::string& spawnerName) {
void BasePropertyServer::DestroySpawner(const std::string& spawnerName) {
for (auto* spawner : dZoneManager::Instance()->GetSpawnersByName(spawnerName)) {
for (auto* node : spawner->m_Info.nodes) {
for (const auto& element : node->entities) {
auto* entity = EntityManager::Instance()->GetEntity(element);
if (entity == nullptr)
continue;
entity->Kill();
}
node->entities.clear();
}
if (!spawner) return;
spawner->DestroyAllEntities();
spawner->Deactivate();
}
}

View File

@ -3,6 +3,7 @@
#include "RebuildComponent.h"
#include "GameMessages.h"
#include "MissionComponent.h"
#include "eEndBehavior.h"
void ActParadoxPipeFix::OnRebuildComplete(Entity* self, Entity* target) {
const auto myGroup = "AllPipes";
@ -42,7 +43,7 @@ void ActParadoxPipeFix::OnRebuildComplete(Entity* self, Entity* target) {
missionComponent->ForceProgressTaskType(769, 1, 1, false);
}
GameMessages::SendPlayCinematic(player->GetObjectID(), u"ParadoxPipeFinish", player->GetSystemAddress(), true, true, false, false, 0, false, 2.0f);
GameMessages::SendPlayCinematic(player->GetObjectID(), u"ParadoxPipeFinish", player->GetSystemAddress(), true, true, false, false, eEndBehavior::RETURN, false, 2.0f);
}
object->SetVar(u"PlayerID", LWOOBJID_EMPTY);

View File

@ -134,24 +134,23 @@ void Spawner::AddEntitySpawnedCallback(std::function<void(Entity*)> callback) {
void Spawner::Reset() {
m_Start = true;
for (auto* node : m_Info.nodes) {
for (const auto& spawned : node->entities) {
auto* entity = EntityManager::Instance()->GetEntity(spawned);
if (entity == nullptr) continue;
entity->Kill();
}
node->entities.clear();
}
DestroyAllEntities();
m_Entities.clear();
m_AmountSpawned = 0;
m_NeedsUpdate = true;
}
void Spawner::DestroyAllEntities(){
for (auto* node : m_Info.nodes) {
for (const auto& element : node->entities) {
auto* entity = EntityManager::Instance()->GetEntity(element);
if (entity == nullptr) continue;
entity->Kill();
}
node->entities.clear();
}
}
void Spawner::SoftReset() {
m_Start = true;
m_AmountSpawned = 0;

View File

@ -61,6 +61,7 @@ public:
void AddEntitySpawnedCallback(std::function<void(Entity*)> callback);
void SetSpawnLot(LOT lot);
void Reset();
void DestroyAllEntities();
void SoftReset();
void SetRespawnTime(float time);
void SetNumToMaintain(int32_t value);

View File

@ -182,17 +182,7 @@ void dZoneManager::RemoveSpawner(const LWOOBJID id) {
Game::logger->Log("dZoneManager", "Failed to find spawner entity (%llu)", id);
}
for (auto* node : spawner->m_Info.nodes) {
for (const auto& element : node->entities) {
auto* nodeEntity = EntityManager::Instance()->GetEntity(element);
if (nodeEntity == nullptr) continue;
nodeEntity->Kill();
}
node->entities.clear();
}
spawner->DestroyAllEntities();
spawner->Deactivate();