fix: Buff FX not playing and general BuffComponent improvements (#1296)

* fix: Buff FX not playing

Fixes an issue where buff effects would not play at all.

Tested that frakjaw and maelstrom dagger now play their respective effects when you are effected by them

fix: buffs general improvements

add new arguments

* Remove duplicated code

* fix times and remove buff
This commit is contained in:
David Markowitz 2023-12-01 08:12:48 -08:00 committed by GitHub
parent 0b9dbaedbf
commit eca87c7257
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 187 additions and 52 deletions

View File

@ -15,7 +15,7 @@ void ApplyBuffBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitS
if (buffComponent == nullptr) return; if (buffComponent == nullptr) return;
buffComponent->ApplyBuff(m_BuffId, m_Duration, context->originator, addImmunity, cancelOnDamaged, cancelOnDeath, buffComponent->ApplyBuff(m_BuffId, m_Duration, context->originator, addImmunity, cancelOnDamaged, cancelOnDeath,
cancelOnLogout, cancelonRemoveBuff, cancelOnUi, cancelOnUnequip, cancelOnZone); cancelOnLogout, cancelonRemoveBuff, cancelOnUi, cancelOnUnequip, cancelOnZone, m_ApplyOnTeammates);
} }
void ApplyBuffBehavior::UnCast(BehaviorContext* context, BehaviorBranchContext branch) { void ApplyBuffBehavior::UnCast(BehaviorContext* context, BehaviorBranchContext branch) {
@ -45,4 +45,5 @@ void ApplyBuffBehavior::Load() {
cancelOnUi = GetBoolean("cancel_on_ui"); cancelOnUi = GetBoolean("cancel_on_ui");
cancelOnUnequip = GetBoolean("cancel_on_unequip"); cancelOnUnequip = GetBoolean("cancel_on_unequip");
cancelOnZone = GetBoolean("cancel_on_zone"); cancelOnZone = GetBoolean("cancel_on_zone");
m_ApplyOnTeammates = GetBoolean("apply_on_teammates");
} }

View File

@ -31,4 +31,6 @@ public:
void Calculate(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) override; void Calculate(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) override;
void Load() override; void Load() override;
private:
bool m_ApplyOnTeammates;
}; };

View File

@ -11,9 +11,21 @@
#include "EntityManager.h" #include "EntityManager.h"
#include "CDClientManager.h" #include "CDClientManager.h"
#include "CDSkillBehaviorTable.h" #include "CDSkillBehaviorTable.h"
#include "TeamManager.h"
std::unordered_map<int32_t, std::vector<BuffParameter>> BuffComponent::m_Cache{}; std::unordered_map<int32_t, std::vector<BuffParameter>> BuffComponent::m_Cache{};
namespace {
std::map<std::string, std::string> BuffFx = {
{ "overtime", "OTB_" },
{ "max_health", "HEALTH_" },
{ "max_imagination", "IMAGINATION_" },
{ "max_armor", "ARMOR_" },
{ "speed", "SPEED_" },
{ "loot", "LOOT_" }
};
}
BuffComponent::BuffComponent(Entity* parent) : Component(parent) { BuffComponent::BuffComponent(Entity* parent) : Component(parent) {
} }
@ -22,32 +34,38 @@ BuffComponent::~BuffComponent() {
void BuffComponent::Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate) { void BuffComponent::Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate) {
if (!bIsInitialUpdate) return; if (!bIsInitialUpdate) return;
if (m_Buffs.empty()) { outBitStream->Write(!m_Buffs.empty());
outBitStream->Write0(); if (!m_Buffs.empty()) {
} else {
outBitStream->Write1();
outBitStream->Write<uint32_t>(m_Buffs.size()); outBitStream->Write<uint32_t>(m_Buffs.size());
for (const auto& buff : m_Buffs) { for (const auto& [id, buff] : m_Buffs) {
outBitStream->Write<uint32_t>(buff.first); outBitStream->Write<uint32_t>(id);
outBitStream->Write0(); outBitStream->Write(buff.time != 0.0f);
outBitStream->Write0(); if (buff.time != 0.0f) outBitStream->Write(static_cast<uint32_t>(buff.time * 1000.0f));
outBitStream->Write0(); outBitStream->Write(buff.cancelOnDeath);
outBitStream->Write0(); outBitStream->Write(buff.cancelOnZone);
outBitStream->Write0(); outBitStream->Write(buff.cancelOnDamaged);
outBitStream->Write0(); outBitStream->Write(buff.cancelOnRemoveBuff);
outBitStream->Write0(); outBitStream->Write(buff.cancelOnUi);
outBitStream->Write0(); outBitStream->Write(buff.cancelOnLogout);
outBitStream->Write0(); outBitStream->Write(buff.cancelOnUnequip);
outBitStream->Write0(); // Cancel on Damage Absorb Ran Out. Generally false from what I can tell
outBitStream->Write0(); auto* team = TeamManager::Instance()->GetTeam(buff.source);
outBitStream->Write0(); bool addedByTeammate = false;
if (team) {
addedByTeammate = std::count(team->members.begin(), team->members.end(), m_Parent->GetObjectID()) > 0;
}
outBitStream->Write<uint32_t>(0); outBitStream->Write(addedByTeammate); // Added by teammate. If source is in the same team as the target, this is true. Otherwise, false.
outBitStream->Write(buff.applyOnTeammates);
if (addedByTeammate) outBitStream->Write(buff.source);
outBitStream->Write<uint32_t>(buff.refCount);
} }
} }
outBitStream->Write0(); outBitStream->Write0(); // something to do with immunity buffs?
} }
void BuffComponent::Update(float deltaTime) { void BuffComponent::Update(float deltaTime) {
@ -83,17 +101,55 @@ void BuffComponent::Update(float deltaTime) {
} }
} }
const std::string& GetFxName(const std::string& buffname) {
const auto& toReturn = BuffFx[buffname];
if (toReturn.empty()) {
LOG_DEBUG("No fx name for %s", buffname.c_str());
}
return toReturn;
}
void BuffComponent::ApplyBuffFx(uint32_t buffId, const BuffParameter& buff) {
std::string fxToPlay;
const auto& buffName = GetFxName(buff.name);
if (buffName.empty()) return;
fxToPlay += std::to_string(buffId);
LOG_DEBUG("Playing %s %i", fxToPlay.c_str(), buff.effectId);
GameMessages::SendPlayFXEffect(m_Parent->GetObjectID(), buff.effectId, u"cast", fxToPlay, LWOOBJID_EMPTY, 1.07f, 1.0f, false);
}
void BuffComponent::RemoveBuffFx(uint32_t buffId, const BuffParameter& buff) {
std::string fxToPlay;
const auto& buffName = GetFxName(buff.name);
if (buffName.empty()) return;
fxToPlay += std::to_string(buffId);
LOG_DEBUG("Stopping %s", fxToPlay.c_str());
GameMessages::SendStopFXEffect(m_Parent, false, fxToPlay);
}
void BuffComponent::ApplyBuff(const int32_t id, const float duration, const LWOOBJID source, bool addImmunity, void BuffComponent::ApplyBuff(const int32_t id, const float duration, const LWOOBJID source, bool addImmunity,
bool cancelOnDamaged, bool cancelOnDeath, bool cancelOnLogout, bool cancelOnRemoveBuff, bool cancelOnDamaged, bool cancelOnDeath, bool cancelOnLogout, bool cancelOnRemoveBuff,
bool cancelOnUi, bool cancelOnUnequip, bool cancelOnZone) { bool cancelOnUi, bool cancelOnUnequip, bool cancelOnZone, bool applyOnTeammates) {
// Prevent buffs from stacking. // Prevent buffs from stacking.
if (HasBuff(id)) { if (HasBuff(id)) {
m_Buffs[id].refCount++;
m_Buffs[id].time = duration;
return; return;
} }
auto* team = TeamManager::Instance()->GetTeam(source);
bool addedByTeammate = false;
if (team) {
addedByTeammate = std::count(team->members.begin(), team->members.end(), m_Parent->GetObjectID()) > 0;
}
GameMessages::SendAddBuff(const_cast<LWOOBJID&>(m_Parent->GetObjectID()), source, (uint32_t)id, GameMessages::SendAddBuff(const_cast<LWOOBJID&>(m_Parent->GetObjectID()), source, (uint32_t)id,
(uint32_t)duration * 1000, addImmunity, cancelOnDamaged, cancelOnDeath, (uint32_t)duration * 1000, addImmunity, cancelOnDamaged, cancelOnDeath,
cancelOnLogout, cancelOnRemoveBuff, cancelOnUi, cancelOnUnequip, cancelOnZone); cancelOnLogout, cancelOnRemoveBuff, cancelOnUi, cancelOnUnequip, cancelOnZone, addedByTeammate, applyOnTeammates);
float tick = 0; float tick = 0;
float stacks = 0; float stacks = 0;
@ -121,17 +177,43 @@ void BuffComponent::ApplyBuff(const int32_t id, const float duration, const LWOO
buff.stacks = stacks; buff.stacks = stacks;
buff.source = source; buff.source = source;
buff.behaviorID = behaviorID; buff.behaviorID = behaviorID;
buff.cancelOnDamaged = cancelOnDamaged;
buff.cancelOnDeath = cancelOnDeath;
buff.cancelOnLogout = cancelOnLogout;
buff.cancelOnRemoveBuff = cancelOnRemoveBuff;
buff.cancelOnUi = cancelOnUi;
buff.cancelOnUnequip = cancelOnUnequip;
buff.cancelOnZone = cancelOnZone;
buff.refCount = 1;
m_Buffs.emplace(id, buff); m_Buffs.emplace(id, buff);
auto* parent = GetParent();
if (!cancelOnDeath) return;
m_Parent->AddDieCallback([parent, id]() {
LOG_DEBUG("Removing buff %i because parent died", id);
if (!parent) return;
auto* buffComponent = parent->GetComponent<BuffComponent>();
if (buffComponent) buffComponent->RemoveBuff(id, false, false, true);
});
} }
void BuffComponent::RemoveBuff(int32_t id, bool fromUnEquip, bool removeImmunity) { void BuffComponent::RemoveBuff(int32_t id, bool fromUnEquip, bool removeImmunity, bool ignoreRefCount) {
const auto& iter = m_Buffs.find(id); const auto& iter = m_Buffs.find(id);
if (iter == m_Buffs.end()) { if (iter == m_Buffs.end()) {
return; return;
} }
if (!ignoreRefCount && !iter->second.cancelOnRemoveBuff) {
iter->second.refCount--;
LOG_DEBUG("refCount for buff %i is now %i", id, iter->second.refCount);
if (iter->second.refCount > 0) {
return;
}
}
GameMessages::SendRemoveBuff(m_Parent, fromUnEquip, removeImmunity, id); GameMessages::SendRemoveBuff(m_Parent, fromUnEquip, removeImmunity, id);
m_Buffs.erase(iter); m_Buffs.erase(iter);
@ -146,6 +228,7 @@ bool BuffComponent::HasBuff(int32_t id) {
void BuffComponent::ApplyBuffEffect(int32_t id) { void BuffComponent::ApplyBuffEffect(int32_t id) {
const auto& parameters = GetBuffParameters(id); const auto& parameters = GetBuffParameters(id);
for (const auto& parameter : parameters) { for (const auto& parameter : parameters) {
ApplyBuffFx(id, parameter);
if (parameter.name == "max_health") { if (parameter.name == "max_health") {
const auto maxHealth = parameter.value; const auto maxHealth = parameter.value;
@ -182,6 +265,7 @@ void BuffComponent::ApplyBuffEffect(int32_t id) {
void BuffComponent::RemoveBuffEffect(int32_t id) { void BuffComponent::RemoveBuffEffect(int32_t id) {
const auto& parameters = GetBuffParameters(id); const auto& parameters = GetBuffParameters(id);
for (const auto& parameter : parameters) { for (const auto& parameter : parameters) {
RemoveBuffFx(id, parameter);
if (parameter.name == "max_health") { if (parameter.name == "max_health") {
const auto maxHealth = parameter.value; const auto maxHealth = parameter.value;
@ -251,13 +335,25 @@ void BuffComponent::LoadFromXml(tinyxml2::XMLDocument* doc) {
auto* buffEntry = buffElement->FirstChildElement("b"); auto* buffEntry = buffElement->FirstChildElement("b");
while (buffEntry != nullptr) { while (buffEntry) {
int32_t id = buffEntry->IntAttribute("id"); int32_t id = buffEntry->IntAttribute("id");
float t = buffEntry->FloatAttribute("t"); float t = buffEntry->FloatAttribute("t");
float tk = buffEntry->FloatAttribute("tk"); float tk = buffEntry->FloatAttribute("tk");
float tt = buffEntry->FloatAttribute("tt");
int32_t s = buffEntry->FloatAttribute("s"); int32_t s = buffEntry->FloatAttribute("s");
LWOOBJID sr = buffEntry->Int64Attribute("sr"); LWOOBJID sr = buffEntry->Int64Attribute("sr");
int32_t b = buffEntry->IntAttribute("b"); int32_t b = buffEntry->IntAttribute("b");
int32_t refCount = buffEntry->IntAttribute("refCount");
bool cancelOnDamaged = buffEntry->BoolAttribute("cancelOnDamaged");
bool cancelOnDeath = buffEntry->BoolAttribute("cancelOnDeath");
bool cancelOnLogout = buffEntry->BoolAttribute("cancelOnLogout");
bool cancelOnRemoveBuff = buffEntry->BoolAttribute("cancelOnRemoveBuff");
bool cancelOnUi = buffEntry->BoolAttribute("cancelOnUi");
bool cancelOnUnequip = buffEntry->BoolAttribute("cancelOnUnequip");
bool cancelOnZone = buffEntry->BoolAttribute("cancelOnZone");
bool applyOnTeammates = buffEntry->BoolAttribute("applyOnTeammates");
Buff buff; Buff buff;
buff.id = id; buff.id = id;
@ -266,6 +362,18 @@ void BuffComponent::LoadFromXml(tinyxml2::XMLDocument* doc) {
buff.stacks = s; buff.stacks = s;
buff.source = sr; buff.source = sr;
buff.behaviorID = b; buff.behaviorID = b;
buff.refCount = refCount;
buff.tickTime = tt;
buff.cancelOnDamaged = cancelOnDamaged;
buff.cancelOnDeath = cancelOnDeath;
buff.cancelOnLogout = cancelOnLogout;
buff.cancelOnRemoveBuff = cancelOnRemoveBuff;
buff.cancelOnUi = cancelOnUi;
buff.cancelOnUnequip = cancelOnUnequip;
buff.cancelOnZone = cancelOnZone;
buff.applyOnTeammates = applyOnTeammates;
m_Buffs.emplace(id, buff); m_Buffs.emplace(id, buff);
@ -288,15 +396,27 @@ void BuffComponent::UpdateXml(tinyxml2::XMLDocument* doc) {
buffElement->DeleteChildren(); buffElement->DeleteChildren();
} }
for (const auto& buff : m_Buffs) { for (const auto& [id, buff] : m_Buffs) {
auto* buffEntry = doc->NewElement("b"); auto* buffEntry = doc->NewElement("b");
if (buff.cancelOnZone || buff.cancelOnLogout) continue;
buffEntry->SetAttribute("id", buff.first); buffEntry->SetAttribute("id", id);
buffEntry->SetAttribute("t", buff.second.time); buffEntry->SetAttribute("t", buff.time);
buffEntry->SetAttribute("tk", buff.second.tick); buffEntry->SetAttribute("tk", buff.tick);
buffEntry->SetAttribute("s", buff.second.stacks); buffEntry->SetAttribute("tt", buff.tickTime);
buffEntry->SetAttribute("sr", buff.second.source); buffEntry->SetAttribute("s", buff.stacks);
buffEntry->SetAttribute("b", buff.second.behaviorID); buffEntry->SetAttribute("sr", buff.source);
buffEntry->SetAttribute("b", buff.behaviorID);
buffEntry->SetAttribute("refCount", buff.refCount);
buffEntry->SetAttribute("cancelOnDamaged", buff.cancelOnDamaged);
buffEntry->SetAttribute("cancelOnDeath", buff.cancelOnDeath);
buffEntry->SetAttribute("cancelOnLogout", buff.cancelOnLogout);
buffEntry->SetAttribute("cancelOnRemoveBuff", buff.cancelOnRemoveBuff);
buffEntry->SetAttribute("cancelOnUi", buff.cancelOnUi);
buffEntry->SetAttribute("cancelOnUnequip", buff.cancelOnUnequip);
buffEntry->SetAttribute("cancelOnZone", buff.cancelOnZone);
buffEntry->SetAttribute("applyOnTeammates", buff.applyOnTeammates);
buffElement->LinkEndChild(buffEntry); buffElement->LinkEndChild(buffEntry);
} }
@ -309,8 +429,7 @@ const std::vector<BuffParameter>& BuffComponent::GetBuffParameters(int32_t buffI
return pair->second; return pair->second;
} }
auto query = CDClientDatabase::CreatePreppedStmt( auto query = CDClientDatabase::CreatePreppedStmt("SELECT * FROM BuffParameters WHERE BuffID = ?;");
"SELECT * FROM BuffParameters WHERE BuffID = ?;");
query.bind(1, (int)buffId); query.bind(1, (int)buffId);
auto result = query.execQuery(); auto result = query.execQuery();
@ -321,11 +440,12 @@ const std::vector<BuffParameter>& BuffComponent::GetBuffParameters(int32_t buffI
BuffParameter param; BuffParameter param;
param.buffId = buffId; param.buffId = buffId;
param.name = result.getStringField(1); param.name = result.getStringField("ParameterName");
param.value = result.getFloatField(2); param.value = result.getFloatField("NumberValue");
param.effectId = result.getIntField("EffectID");
if (!result.fieldIsNull(3)) { if (!result.fieldIsNull(3)) {
std::istringstream stream(result.getStringField(3)); std::istringstream stream(result.getStringField("StringValue"));
std::string token; std::string token;
while (std::getline(stream, token, ',')) { while (std::getline(stream, token, ',')) {

View File

@ -14,8 +14,7 @@ class Entity;
/** /**
* Extra information on effects to apply after applying a buff, for example whether to buff armor, imag or health and by how much * Extra information on effects to apply after applying a buff, for example whether to buff armor, imag or health and by how much
*/ */
struct BuffParameter struct BuffParameter {
{
int32_t buffId; int32_t buffId;
std::string name; std::string name;
float value; float value;
@ -26,8 +25,7 @@ struct BuffParameter
/** /**
* Meta information about a buff that can be applied, e.g. how long it's applied, who applied it, etc. * Meta information about a buff that can be applied, e.g. how long it's applied, who applied it, etc.
*/ */
struct Buff struct Buff {
{
int32_t id = 0; int32_t id = 0;
float time = 0; float time = 0;
float tick = 0; float tick = 0;
@ -35,6 +33,15 @@ struct Buff
int32_t stacks = 0; int32_t stacks = 0;
LWOOBJID source = 0; LWOOBJID source = 0;
int32_t behaviorID = 0; int32_t behaviorID = 0;
bool cancelOnDamaged = false;
bool cancelOnDeath = false;
bool cancelOnLogout = false;
bool cancelOnRemoveBuff = false;
bool cancelOnUi = false;
bool cancelOnUnequip = false;
bool cancelOnZone = false;
bool applyOnTeammates = false;
uint32_t refCount = 0;
}; };
/** /**
@ -74,14 +81,17 @@ public:
*/ */
void ApplyBuff(int32_t id, float duration, LWOOBJID source, bool addImmunity = false, bool cancelOnDamaged = false, void ApplyBuff(int32_t id, float duration, LWOOBJID source, bool addImmunity = false, bool cancelOnDamaged = false,
bool cancelOnDeath = true, bool cancelOnLogout = false, bool cancelOnRemoveBuff = true, bool cancelOnDeath = true, bool cancelOnLogout = false, bool cancelOnRemoveBuff = true,
bool cancelOnUi = false, bool cancelOnUnequip = false, bool cancelOnZone = false); bool cancelOnUi = false, bool cancelOnUnequip = false, bool cancelOnZone = false, bool applyOnTeammates = false);
void ApplyBuffFx(uint32_t buffId, const BuffParameter& buffName);
void RemoveBuffFx(uint32_t buffId, const BuffParameter& buffName);
/** /**
* Removes a buff from the parent entity, reversing its effects * Removes a buff from the parent entity, reversing its effects
* @param id the id of the buff to remove * @param id the id of the buff to remove
* @param removeImmunity whether or not to remove immunity on removing the buff * @param removeImmunity whether or not to remove immunity on removing the buff
*/ */
void RemoveBuff(int32_t id, bool fromUnEquip = false, bool removeImmunity = false); void RemoveBuff(int32_t id, bool fromUnEquip = false, bool removeImmunity = false, bool ignoreRefCount = false);
/** /**
* Returns whether or not the entity has a buff identified by `id` * Returns whether or not the entity has a buff identified by `id`

View File

@ -4477,7 +4477,7 @@ void GameMessages::SendVehicleNotifyFinishedRace(LWOOBJID objectId, const System
void GameMessages::SendAddBuff(LWOOBJID& objectID, const LWOOBJID& casterID, uint32_t buffID, uint32_t msDuration, void GameMessages::SendAddBuff(LWOOBJID& objectID, const LWOOBJID& casterID, uint32_t buffID, uint32_t msDuration,
bool addImmunity, bool cancelOnDamaged, bool cancelOnDeath, bool cancelOnLogout, bool addImmunity, bool cancelOnDamaged, bool cancelOnDeath, bool cancelOnLogout,
bool cancelOnRemoveBuff, bool cancelOnUi, bool cancelOnUnequip, bool cancelOnZone, bool cancelOnRemoveBuff, bool cancelOnUi, bool cancelOnUnequip, bool cancelOnZone, bool addedByTeammate, bool applyOnTeammates,
const SystemAddress& sysAddr) { const SystemAddress& sysAddr) {
CBITSTREAM; CBITSTREAM;
CMSGHEADER; CMSGHEADER;
@ -4485,27 +4485,29 @@ void GameMessages::SendAddBuff(LWOOBJID& objectID, const LWOOBJID& casterID, uin
bitStream.Write(objectID); bitStream.Write(objectID);
bitStream.Write(eGameMessageType::ADD_BUFF); bitStream.Write(eGameMessageType::ADD_BUFF);
bitStream.Write(false); // Added by teammate bitStream.Write(addedByTeammate); // Added by teammate
bitStream.Write(false); // Apply on teammates bitStream.Write(applyOnTeammates); // Apply on teammates
bitStream.Write(false); // Cancel on damage absorb ran out
bitStream.Write(cancelOnDamaged); bitStream.Write(cancelOnDamaged);
bitStream.Write(cancelOnDeath); bitStream.Write(cancelOnDeath);
bitStream.Write(cancelOnLogout); bitStream.Write(cancelOnLogout);
bitStream.Write(false); // Cancel on move bitStream.Write(false); // Cancel on move
bitStream.Write(cancelOnRemoveBuff); bitStream.Write(cancelOnRemoveBuff);
bitStream.Write(cancelOnUi); bitStream.Write(cancelOnUi);
bitStream.Write(cancelOnUnequip); bitStream.Write(cancelOnUnequip);
bitStream.Write(cancelOnZone); bitStream.Write(cancelOnZone);
bitStream.Write(false); // Ignore immunities bitStream.Write(false); // Ignore immunities
bitStream.Write(addImmunity); bitStream.Write(addImmunity);
bitStream.Write(false); // Use ref count bitStream.Write(false); // Use ref count
bitStream.Write(buffID); bitStream.Write(casterID != LWOOBJID_EMPTY);
bitStream.Write(msDuration); if (casterID != LWOOBJID_EMPTY) bitStream.Write(casterID);
bitStream.Write(casterID); bitStream.Write(buffID);
bitStream.Write(casterID);
bitStream.Write(msDuration != 0);
if (msDuration != 0) bitStream.Write(msDuration);
if (sysAddr == UNASSIGNED_SYSTEM_ADDRESS) SEND_PACKET_BROADCAST; if (sysAddr == UNASSIGNED_SYSTEM_ADDRESS) SEND_PACKET_BROADCAST;
SEND_PACKET; SEND_PACKET;

View File

@ -206,7 +206,7 @@ namespace GameMessages {
void SendAddBuff(LWOOBJID& objectID, const LWOOBJID& casterID, uint32_t buffID, uint32_t msDuration, void SendAddBuff(LWOOBJID& objectID, const LWOOBJID& casterID, uint32_t buffID, uint32_t msDuration,
bool addImmunity = false, bool cancelOnDamaged = false, bool cancelOnDeath = true, bool addImmunity = false, bool cancelOnDamaged = false, bool cancelOnDeath = true,
bool cancelOnLogout = false, bool cancelOnRemoveBuff = true, bool cancelOnUi = false, bool cancelOnLogout = false, bool cancelOnRemoveBuff = true, bool cancelOnUi = false,
bool cancelOnUnequip = false, bool cancelOnZone = false, const SystemAddress& sysAddr = UNASSIGNED_SYSTEM_ADDRESS); bool cancelOnUnequip = false, bool cancelOnZone = false, bool addedByTeammate = false, bool applyOnTeammates = false, const SystemAddress& sysAddr = UNASSIGNED_SYSTEM_ADDRESS);
void SendToggleGMInvis(LWOOBJID objectId, bool enabled, const SystemAddress& sysAddr); void SendToggleGMInvis(LWOOBJID objectId, bool enabled, const SystemAddress& sysAddr);