Imminuty updates (#925)

* WIP Immunities

* Immunity getters

* remove redundent variable
replace it use with it's equivalent

* remove unused lookups, fix typos

* fix tests

* added imunity test

* address feedback

* more immunity tests

* explicit this
This commit is contained in:
Aaron Kimbrell 2023-01-06 23:59:19 -06:00 committed by GitHub
parent 1ac898ba00
commit 80f8dd8003
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
25 changed files with 681 additions and 99 deletions

View File

@ -366,7 +366,7 @@ enum eControlSceme {
SCHEME_WEAR_A_ROBOT //== freecam?
};
enum eStunState {
enum class eStateChangeType : uint32_t {
PUSH,
POP
};

View File

@ -293,6 +293,7 @@ enum GAME_MSG : unsigned short {
GAME_MSG_POP_EQUIPPED_ITEMS_STATE = 192,
GAME_MSG_SET_GM_LEVEL = 193,
GAME_MSG_SET_STUNNED = 198,
GAME_MSG_SET_STUN_IMMUNITY = 200,
GAME_MSG_KNOCKBACK = 202,
GAME_MSG_REBUILD_CANCEL = 209,
GAME_MSG_ENABLE_REBUILD = 213,
@ -512,6 +513,7 @@ enum GAME_MSG : unsigned short {
GAME_MSG_UPDATE_CHAT_MODE = 1395,
GAME_MSG_VEHICLE_NOTIFY_FINISHED_RACE = 1396,
GAME_MSG_SET_CONSUMABLE_ITEM = 1409,
GAME_MSG_SET_STATUS_IMMUNITY = 1435,
GAME_MSG_SET_PET_NAME_MODERATED = 1448,
GAME_MSG_MODIFY_LEGO_SCORE = 1459,
GAME_MSG_RESTORE_TO_POST_LOAD_STATS = 1468,

View File

@ -6,28 +6,47 @@
#include "Game.h"
#include "dLogger.h"
#include "DestroyableComponent.h"
#include "ControllablePhysicsComponent.h"
void ImmunityBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitStream, const BehaviorBranchContext branch) {
auto* target = EntityManager::Instance()->GetEntity(branch.target);
if (target == nullptr) {
if (!target) {
Game::logger->Log("DamageAbsorptionBehavior", "Failed to find target (%llu)!", branch.target);
return;
}
auto* destroyable = static_cast<DestroyableComponent*>(target->GetComponent(COMPONENT_TYPE_DESTROYABLE));
if (destroyable == nullptr) {
return;
auto* destroyableComponent = target->GetComponent<DestroyableComponent>();
if (destroyableComponent) {
destroyableComponent->SetStatusImmunity(
eStateChangeType::PUSH,
this->m_ImmuneToBasicAttack,
this->m_ImmuneToDamageOverTime,
this->m_ImmuneToKnockback,
this->m_ImmuneToInterrupt,
this->m_ImmuneToSpeed,
this->m_ImmuneToImaginationGain,
this->m_ImmuneToImaginationLoss,
this->m_ImmuneToQuickbuildInterrupt,
this->m_ImmuneToPullToPoint
);
}
if (!this->m_immuneBasicAttack) {
return;
auto* controllablePhysicsComponent = target->GetComponent<ControllablePhysicsComponent>();
if (controllablePhysicsComponent) {
controllablePhysicsComponent->SetStunImmunity(
eStateChangeType::PUSH,
context->caster,
this->m_ImmuneToStunAttack,
this->m_ImmuneToStunEquip,
this->m_ImmuneToStunInteract,
this->m_ImmuneToStunJump,
this->m_ImmuneToStunMove,
this->m_ImmuneToStunTurn,
this->m_ImmuneToStunUseItem
);
}
destroyable->PushImmunity();
context->RegisterTimerBehavior(this, branch, target->GetObjectID());
}
@ -38,21 +57,60 @@ void ImmunityBehavior::Calculate(BehaviorContext* context, RakNet::BitStream* bi
void ImmunityBehavior::Timer(BehaviorContext* context, BehaviorBranchContext branch, const LWOOBJID second) {
auto* target = EntityManager::Instance()->GetEntity(second);
if (target == nullptr) {
if (!target) {
Game::logger->Log("DamageAbsorptionBehavior", "Failed to find target (%llu)!", second);
return;
}
auto* destroyable = static_cast<DestroyableComponent*>(target->GetComponent(COMPONENT_TYPE_DESTROYABLE));
if (destroyable == nullptr) {
return;
auto* destroyableComponent = target->GetComponent<DestroyableComponent>();
if (destroyableComponent) {
destroyableComponent->SetStatusImmunity(
eStateChangeType::POP,
this->m_ImmuneToBasicAttack,
this->m_ImmuneToDamageOverTime,
this->m_ImmuneToKnockback,
this->m_ImmuneToInterrupt,
this->m_ImmuneToSpeed,
this->m_ImmuneToImaginationGain,
this->m_ImmuneToImaginationLoss,
this->m_ImmuneToQuickbuildInterrupt,
this->m_ImmuneToPullToPoint
);
}
auto* controllablePhysicsComponent = target->GetComponent<ControllablePhysicsComponent>();
if (controllablePhysicsComponent) {
controllablePhysicsComponent->SetStunImmunity(
eStateChangeType::POP,
context->caster,
this->m_ImmuneToStunAttack,
this->m_ImmuneToStunEquip,
this->m_ImmuneToStunInteract,
this->m_ImmuneToStunJump,
this->m_ImmuneToStunMove,
this->m_ImmuneToStunTurn,
this->m_ImmuneToStunUseItem
);
}
destroyable->PopImmunity();
}
void ImmunityBehavior::Load() {
this->m_immuneBasicAttack = GetBoolean("immune_basic_attack");
//Stun
this->m_ImmuneToStunAttack = GetBoolean("immune_stun_attack", false);
this->m_ImmuneToStunEquip = GetBoolean("immune_stun_equip", false);
this->m_ImmuneToStunInteract = GetBoolean("immune_stun_interact", false);
this->m_ImmuneToStunMove = GetBoolean("immune_stun_move", false);
this->m_ImmuneToStunTurn = GetBoolean("immune_stun_rotate", false);
// Status
this->m_ImmuneToBasicAttack = GetBoolean("immune_basic_attack", false);
this->m_ImmuneToDamageOverTime = GetBoolean("immune_damage_over_time", false);
this->m_ImmuneToKnockback = GetBoolean("immune_knockback", false);
this->m_ImmuneToInterrupt = GetBoolean("immune_interrupt", false);
this->m_ImmuneToSpeed = GetBoolean("immune_speed", false);
this->m_ImmuneToImaginationGain = GetBoolean("immune_imagination_gain", false);
this->m_ImmuneToImaginationLoss = GetBoolean("immune_imagination_loss", false);
this->m_ImmuneToQuickbuildInterrupt = GetBoolean("immune_quickbuild_interrupts", false);
this->m_ImmuneToPullToPoint = GetBoolean("immune_pulltopoint", false);
}

View File

@ -4,8 +4,6 @@
class ImmunityBehavior final : public Behavior
{
public:
uint32_t m_immuneBasicAttack;
/*
* Inherited
*/
@ -20,4 +18,25 @@ public:
void Timer(BehaviorContext* context, BehaviorBranchContext branch, LWOOBJID second) override;
void Load() override;
private:
// stuns
bool m_ImmuneToStunAttack = false;
bool m_ImmuneToStunEquip = false;
bool m_ImmuneToStunInteract = false;
bool m_ImmuneToStunJump = false; // Unused
bool m_ImmuneToStunMove = false;
bool m_ImmuneToStunTurn = false;
bool m_ImmuneToStunUseItem = false; // Unused
//status
bool m_ImmuneToBasicAttack = false;
bool m_ImmuneToDamageOverTime = false;
bool m_ImmuneToKnockback = false;
bool m_ImmuneToInterrupt = false;
bool m_ImmuneToSpeed = false;
bool m_ImmuneToImaginationGain = false;
bool m_ImmuneToImaginationLoss = false;
bool m_ImmuneToQuickbuildInterrupt = false;
bool m_ImmuneToPullToPoint = false; // Unused in cdclient, but used in client
};

View File

@ -35,6 +35,14 @@ ControllablePhysicsComponent::ControllablePhysicsComponent(Entity* entity) : Com
m_DirtyPickupRadiusScale = true;
m_IsTeleporting = false;
m_ImmuneToStunAttackCount = 0;
m_ImmuneToStunEquipCount = 0;
m_ImmuneToStunInteractCount = 0;
m_ImmuneToStunJumpCount = 0;
m_ImmuneToStunMoveCount = 0;
m_ImmuneToStunTurnCount = 0;
m_ImmuneToStunUseItemCount = 0;
if (entity->GetLOT() != 1) // Other physics entities we care about will be added by BaseCombatAI
return;
@ -71,7 +79,14 @@ void ControllablePhysicsComponent::Serialize(RakNet::BitStream* outBitStream, bo
outBitStream->Write(m_JetpackBypassChecks);
}
outBitStream->Write0(); //This contains info about immunities, but for now I'm leaving it out.
outBitStream->Write1(); // always write these on construction
outBitStream->Write(m_ImmuneToStunMoveCount);
outBitStream->Write(m_ImmuneToStunJumpCount);
outBitStream->Write(m_ImmuneToStunTurnCount);
outBitStream->Write(m_ImmuneToStunAttackCount);
outBitStream->Write(m_ImmuneToStunUseItemCount);
outBitStream->Write(m_ImmuneToStunEquipCount);
outBitStream->Write(m_ImmuneToStunInteractCount);
}
if (m_IgnoreMultipliers) m_DirtyCheats = false;
@ -298,3 +313,44 @@ void ControllablePhysicsComponent::RemoveSpeedboost(float value) {
SetSpeedMultiplier(m_SpeedBoost / 500.0f); // 500 being the base speed
EntityManager::Instance()->SerializeEntity(m_Parent);
}
void ControllablePhysicsComponent::SetStunImmunity(
const eStateChangeType state,
const LWOOBJID originator,
const bool bImmuneToStunAttack,
const bool bImmuneToStunEquip,
const bool bImmuneToStunInteract,
const bool bImmuneToStunJump,
const bool bImmuneToStunMove,
const bool bImmuneToStunTurn,
const bool bImmuneToStunUseItem){
if (state == eStateChangeType::POP){
if (bImmuneToStunAttack && m_ImmuneToStunAttackCount > 0) m_ImmuneToStunAttackCount -= 1;
if (bImmuneToStunEquip && m_ImmuneToStunEquipCount > 0) m_ImmuneToStunEquipCount -= 1;
if (bImmuneToStunInteract && m_ImmuneToStunInteractCount > 0) m_ImmuneToStunInteractCount -= 1;
if (bImmuneToStunJump && m_ImmuneToStunJumpCount > 0) m_ImmuneToStunJumpCount -= 1;
if (bImmuneToStunMove && m_ImmuneToStunMoveCount > 0) m_ImmuneToStunMoveCount -= 1;
if (bImmuneToStunTurn && m_ImmuneToStunTurnCount > 0) m_ImmuneToStunTurnCount -= 1;
if (bImmuneToStunUseItem && m_ImmuneToStunUseItemCount > 0) m_ImmuneToStunUseItemCount -= 1;
} else if (state == eStateChangeType::PUSH) {
if (bImmuneToStunAttack) m_ImmuneToStunAttackCount += 1;
if (bImmuneToStunEquip) m_ImmuneToStunEquipCount += 1;
if (bImmuneToStunInteract) m_ImmuneToStunInteractCount += 1;
if (bImmuneToStunJump) m_ImmuneToStunJumpCount += 1;
if (bImmuneToStunMove) m_ImmuneToStunMoveCount += 1;
if (bImmuneToStunTurn) m_ImmuneToStunTurnCount += 1;
if (bImmuneToStunUseItem) m_ImmuneToStunUseItemCount += 1;
}
GameMessages::SendSetStunImmunity(
m_Parent->GetObjectID(), state, m_Parent->GetSystemAddress(), originator,
bImmuneToStunAttack,
bImmuneToStunEquip,
bImmuneToStunInteract,
bImmuneToStunJump,
bImmuneToStunMove,
bImmuneToStunTurn,
bImmuneToStunUseItem
);
}

View File

@ -264,6 +264,30 @@ public:
std::vector<float> GetActiveSpeedboosts() { return m_ActivePickupRadiusScales; };
/**
* Push or Pop a layer of stun immunity to this entity
*/
void SetStunImmunity(
const eStateChangeType state,
const LWOOBJID originator = LWOOBJID_EMPTY,
const bool bImmuneToStunAttack = false,
const bool bImmuneToStunEquip = false,
const bool bImmuneToStunInteract = false,
const bool bImmuneToStunJump = false,
const bool bImmuneToStunMove = false,
const bool bImmuneToStunTurn = false,
const bool bImmuneToStunUseItem = false
);
// getters for stun immunities
const bool GetImmuneToStunAttack() { return m_ImmuneToStunAttackCount > 0;};
const bool GetImmuneToStunEquip() { return m_ImmuneToStunEquipCount > 0;};
const bool GetImmuneToStunInteract() { return m_ImmuneToStunInteractCount > 0;};
const bool GetImmuneToStunJump() { return m_ImmuneToStunJumpCount > 0;};
const bool GetImmuneToStunMove() { return m_ImmuneToStunMoveCount > 0;};
const bool GetImmuneToStunTurn() { return m_ImmuneToStunTurnCount > 0;};
const bool GetImmuneToStunUseItem() { return m_ImmuneToStunUseItemCount > 0;};
private:
/**
* The entity that owns this component
@ -389,6 +413,17 @@ private:
* The active speed boost for this entity
*/
float m_SpeedBoost;
/**
* stun immunity counters
*/
int32_t m_ImmuneToStunAttackCount;
int32_t m_ImmuneToStunEquipCount;
int32_t m_ImmuneToStunInteractCount;
int32_t m_ImmuneToStunJumpCount;
int32_t m_ImmuneToStunMoveCount;
int32_t m_ImmuneToStunTurnCount;
int32_t m_ImmuneToStunUseItemCount;
};
#endif // CONTROLLABLEPHYSICSCOMPONENT_H

View File

@ -55,8 +55,17 @@ DestroyableComponent::DestroyableComponent(Entity* parent) : Component(parent) {
m_LootMatrixID = 0;
m_MinCoins = 0;
m_MaxCoins = 0;
m_ImmuneStacks = 0;
m_DamageReduction = 0;
m_ImmuneToBasicAttackCount = 0;
m_ImmuneToDamageOverTimeCount = 0;
m_ImmuneToKnockbackCount = 0;
m_ImmuneToInterruptCount = 0;
m_ImmuneToSpeedCount = 0;
m_ImmuneToImaginationGainCount = 0;
m_ImmuneToImaginationLossCount = 0;
m_ImmuneToQuickbuildInterruptCount = 0;
m_ImmuneToPullToPointCount = 0;
}
DestroyableComponent::~DestroyableComponent() {
@ -106,7 +115,16 @@ void DestroyableComponent::Reinitialize(LOT templateID) {
void DestroyableComponent::Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate, uint32_t& flags) {
if (bIsInitialUpdate) {
outBitStream->Write0(); //Contains info about immunities this object has, but it's left out for now.
outBitStream->Write1(); // always write these on construction
outBitStream->Write(m_ImmuneToBasicAttackCount);
outBitStream->Write(m_ImmuneToDamageOverTimeCount);
outBitStream->Write(m_ImmuneToKnockbackCount);
outBitStream->Write(m_ImmuneToInterruptCount);
outBitStream->Write(m_ImmuneToSpeedCount);
outBitStream->Write(m_ImmuneToImaginationGainCount);
outBitStream->Write(m_ImmuneToImaginationLossCount);
outBitStream->Write(m_ImmuneToQuickbuildInterruptCount);
outBitStream->Write(m_ImmuneToPullToPointCount);
}
outBitStream->Write(m_DirtyHealth || bIsInitialUpdate);
@ -336,7 +354,7 @@ void DestroyableComponent::SetDamageReduction(int32_t value) {
void DestroyableComponent::SetIsImmune(bool value) {
m_DirtyHealth = true;
m_ImmuneStacks = value ? 1 : 0;
m_ImmuneToBasicAttackCount = value ? 1 : 0;
}
void DestroyableComponent::SetIsGMImmune(bool value) {
@ -439,7 +457,7 @@ void DestroyableComponent::SetAttacksToBlock(const uint32_t value) {
}
bool DestroyableComponent::IsImmune() const {
return m_ImmuneStacks > 0 || m_IsGMImmune;
return m_IsGMImmune || m_ImmuneToBasicAttackCount > 0;
}
bool DestroyableComponent::IsKnockbackImmune() const {
@ -804,12 +822,53 @@ void DestroyableComponent::SetFaction(int32_t factionID, bool ignoreChecks) {
AddFaction(factionID, ignoreChecks);
}
void DestroyableComponent::PushImmunity(int32_t stacks) {
m_ImmuneStacks += stacks;
}
void DestroyableComponent::SetStatusImmunity(
const eStateChangeType state,
const bool bImmuneToBasicAttack,
const bool bImmuneToDamageOverTime,
const bool bImmuneToKnockback,
const bool bImmuneToInterrupt,
const bool bImmuneToSpeed,
const bool bImmuneToImaginationGain,
const bool bImmuneToImaginationLoss,
const bool bImmuneToQuickbuildInterrupt,
const bool bImmuneToPullToPoint) {
void DestroyableComponent::PopImmunity(int32_t stacks) {
m_ImmuneStacks -= stacks;
if (state == eStateChangeType::POP) {
if (bImmuneToBasicAttack && m_ImmuneToBasicAttackCount > 0) m_ImmuneToBasicAttackCount -= 1;
if (bImmuneToDamageOverTime && m_ImmuneToDamageOverTimeCount > 0) m_ImmuneToDamageOverTimeCount -= 1;
if (bImmuneToKnockback && m_ImmuneToKnockbackCount > 0) m_ImmuneToKnockbackCount -= 1;
if (bImmuneToInterrupt && m_ImmuneToInterruptCount > 0) m_ImmuneToInterruptCount -= 1;
if (bImmuneToSpeed && m_ImmuneToSpeedCount > 0) m_ImmuneToSpeedCount -= 1;
if (bImmuneToImaginationGain && m_ImmuneToImaginationGainCount > 0) m_ImmuneToImaginationGainCount -= 1;
if (bImmuneToImaginationLoss && m_ImmuneToImaginationLossCount > 0) m_ImmuneToImaginationLossCount -= 1;
if (bImmuneToQuickbuildInterrupt && m_ImmuneToQuickbuildInterruptCount > 0) m_ImmuneToQuickbuildInterruptCount -= 1;
if (bImmuneToPullToPoint && m_ImmuneToPullToPointCount > 0) m_ImmuneToPullToPointCount -= 1;
} else if (state == eStateChangeType::PUSH){
if (bImmuneToBasicAttack) m_ImmuneToBasicAttackCount += 1;
if (bImmuneToDamageOverTime) m_ImmuneToDamageOverTimeCount += 1;
if (bImmuneToKnockback) m_ImmuneToKnockbackCount += 1;
if (bImmuneToInterrupt) m_ImmuneToInterruptCount += 1;
if (bImmuneToSpeed) m_ImmuneToSpeedCount += 1;
if (bImmuneToImaginationGain) m_ImmuneToImaginationGainCount += 1;
if (bImmuneToImaginationLoss) m_ImmuneToImaginationLossCount += 1;
if (bImmuneToQuickbuildInterrupt) m_ImmuneToQuickbuildInterruptCount += 1;
if (bImmuneToPullToPoint) m_ImmuneToPullToPointCount += 1;
}
GameMessages::SendSetStatusImmunity(
m_Parent->GetObjectID(), state, m_Parent->GetSystemAddress(),
bImmuneToBasicAttack,
bImmuneToDamageOverTime,
bImmuneToKnockback,
bImmuneToInterrupt,
bImmuneToSpeed,
bImmuneToImaginationGain,
bImmuneToImaginationLoss,
bImmuneToQuickbuildInterrupt,
bImmuneToPullToPoint
);
}
void DestroyableComponent::FixStats() {

View File

@ -396,16 +396,31 @@ public:
void Smash(LWOOBJID source, eKillType killType = eKillType::VIOLENT, const std::u16string& deathType = u"", uint32_t skillID = 0);
/**
* Pushes a layer of immunity to this entity, making it immune for longer
* @param stacks the amount of immunity to add
* Push or Pop a layer of status immunity to this entity
*/
void PushImmunity(int32_t stacks = 1);
void SetStatusImmunity(
const eStateChangeType state,
const bool bImmuneToBasicAttack = false,
const bool bImmuneToDamageOverTime = false,
const bool bImmuneToKnockback = false,
const bool bImmuneToInterrupt = false,
const bool bImmuneToSpeed = false,
const bool bImmuneToImaginationGain = false,
const bool bImmuneToImaginationLoss = false,
const bool bImmuneToQuickbuildInterrupt = false,
const bool bImmuneToPullToPoint = false
);
/**
* Pops layers of immunity, making it immune for less longer
* @param stacks the number of layers of immunity to remove
*/
void PopImmunity(int32_t stacks = 1);
// Getters for status immunities
const bool GetImmuneToBasicAttack() {return m_ImmuneToBasicAttackCount > 0;};
const bool GetImmuneToDamageOverTime() {return m_ImmuneToDamageOverTimeCount > 0;};
const bool GetImmuneToKnockback() {return m_ImmuneToKnockbackCount > 0;};
const bool GetImmuneToInterrupt() {return m_ImmuneToInterruptCount > 0;};
const bool GetImmuneToSpeed() {return m_ImmuneToSpeedCount > 0;};
const bool GetImmuneToImaginationGain() {return m_ImmuneToImaginationGainCount > 0;};
const bool GetImmuneToImaginationLoss() {return m_ImmuneToImaginationLossCount > 0;};
const bool GetImmuneToQuickbuildInterrupt() {return m_ImmuneToQuickbuildInterruptCount > 0;};
const bool GetImmuneToPullToPoint() {return m_ImmuneToPullToPointCount > 0;};
/**
* Utility to reset all stats to the default stats based on items and completed missions
@ -428,7 +443,7 @@ public:
/**
* Notify subscribed scripts of Damage actions.
*
*
* @param attacker The attacking Entity
* @param damage The amount of damage that was done
*/
@ -493,11 +508,6 @@ private:
*/
uint32_t m_AttacksToBlock;
/**
* The layers of immunity this entity has left
*/
int32_t m_ImmuneStacks;
/**
* The amount of damage that should be reduced from every attack
*/
@ -577,6 +587,19 @@ private:
* The list of scripts subscribed to this components actions
*/
std::map<LWOOBJID, CppScripts::Script*> m_SubscribedScripts;
/**
* status immunity counters
*/
uint32_t m_ImmuneToBasicAttackCount;
uint32_t m_ImmuneToDamageOverTimeCount;
uint32_t m_ImmuneToKnockbackCount;
uint32_t m_ImmuneToInterruptCount;
uint32_t m_ImmuneToSpeedCount;
uint32_t m_ImmuneToImaginationGainCount;
uint32_t m_ImmuneToImaginationLossCount;
uint32_t m_ImmuneToQuickbuildInterruptCount;
uint32_t m_ImmuneToPullToPointCount;
};
#endif // DESTROYABLECOMPONENT_H

View File

@ -959,7 +959,7 @@ void InventoryComponent::HandlePossession(Item* item) {
return;
}
GameMessages::SendSetStunned(m_Parent->GetObjectID(), eStunState::PUSH, m_Parent->GetSystemAddress(), LWOOBJID_EMPTY, true, false, true, false, false, false, false, true, true, true, true, true, true, true, true, true);
GameMessages::SendSetStunned(m_Parent->GetObjectID(), eStateChangeType::PUSH, m_Parent->GetSystemAddress(), LWOOBJID_EMPTY, true, false, true, false, false, false, false, true, true, true, true, true, true, true, true, true);
// Set the mount Item ID so that we know what were handling
possessorComponent->SetMountItemID(item->GetId());

View File

@ -54,7 +54,7 @@ void PossessorComponent::Mount(Entity* mount) {
// GM's to send
GameMessages::SendSetJetPackMode(m_Parent, false);
GameMessages::SendVehicleUnlockInput(mount->GetObjectID(), false, m_Parent->GetSystemAddress());
GameMessages::SendSetStunned(m_Parent->GetObjectID(), eStunState::PUSH, m_Parent->GetSystemAddress(), LWOOBJID_EMPTY, true, false, true, false, false, false, false, true, true, true, true, true, true, true, true, true);
GameMessages::SendSetStunned(m_Parent->GetObjectID(), eStateChangeType::PUSH, m_Parent->GetSystemAddress(), LWOOBJID_EMPTY, true, false, true, false, false, false, false, true, true, true, true, true, true, true, true, true);
EntityManager::Instance()->SerializeEntity(m_Parent);
EntityManager::Instance()->SerializeEntity(mount);

View File

@ -95,7 +95,7 @@ void RailActivatorComponent::OnUse(Entity* originator) {
void RailActivatorComponent::OnRailMovementReady(Entity* originator) const {
// Stun the originator
GameMessages::SendSetStunned(originator->GetObjectID(), PUSH, originator->GetSystemAddress(), LWOOBJID_EMPTY,
GameMessages::SendSetStunned(originator->GetObjectID(), eStateChangeType::PUSH, originator->GetSystemAddress(), LWOOBJID_EMPTY,
true, true, true, true, true, true, true
);
@ -123,7 +123,7 @@ void RailActivatorComponent::OnRailMovementReady(Entity* originator) const {
void RailActivatorComponent::OnCancelRailMovement(Entity* originator) {
// Remove the stun from the originator
GameMessages::SendSetStunned(originator->GetObjectID(), POP, originator->GetSystemAddress(), LWOOBJID_EMPTY,
GameMessages::SendSetStunned(originator->GetObjectID(), eStateChangeType::POP, originator->GetSystemAddress(), LWOOBJID_EMPTY,
true, true, true, true, true, true, true
);

View File

@ -2904,7 +2904,7 @@ void GameMessages::HandleCinematicUpdate(RakNet::BitStream* inStream, Entity* en
}
}
void GameMessages::SendSetStunned(LWOOBJID objectId, eStunState stateChangeType, const SystemAddress& sysAddr,
void GameMessages::SendSetStunned(LWOOBJID objectId, eStateChangeType stateChangeType, const SystemAddress& sysAddr,
LWOOBJID originator, bool bCantAttack, bool bCantEquip,
bool bCantInteract, bool bCantJump, bool bCantMove, bool bCantTurn,
bool bCantUseItem, bool bDontTerminateInteract, bool bIgnoreImmunity,
@ -2952,6 +2952,69 @@ void GameMessages::SendSetStunned(LWOOBJID objectId, eStunState stateChangeType,
SEND_PACKET;
}
void GameMessages::SendSetStunImmunity(LWOOBJID target, eStateChangeType state, const SystemAddress& sysAddr,
LWOOBJID originator,
bool bImmuneToStunAttack,
bool bImmuneToStunEquip,
bool bImmuneToStunInteract,
bool bImmuneToStunJump,
bool bImmuneToStunMove,
bool bImmuneToStunTurn,
bool bImmuneToStunUseItem) {
CBITSTREAM;
CMSGHEADER;
bitStream.Write(target);
bitStream.Write(GAME_MSG::GAME_MSG_SET_STUN_IMMUNITY);
bitStream.Write(originator != LWOOBJID_EMPTY);
if (originator != LWOOBJID_EMPTY) bitStream.Write(originator);
bitStream.Write(state);
bitStream.Write(bImmuneToStunAttack);
bitStream.Write(bImmuneToStunEquip);
bitStream.Write(bImmuneToStunInteract);
bitStream.Write(bImmuneToStunJump);
bitStream.Write(bImmuneToStunMove);
bitStream.Write(bImmuneToStunTurn);
bitStream.Write(bImmuneToStunUseItem);
if (sysAddr == UNASSIGNED_SYSTEM_ADDRESS) SEND_PACKET_BROADCAST;
SEND_PACKET;
}
void GameMessages::SendSetStatusImmunity(LWOOBJID objectId, eStateChangeType state, const SystemAddress& sysAddr,
bool bImmuneToBasicAttack,
bool bImmuneToDamageOverTime,
bool bImmuneToKnockback,
bool bImmuneToInterrupt,
bool bImmuneToSpeed,
bool bImmuneToImaginationGain,
bool bImmuneToImaginationLoss,
bool bImmuneToQuickbuildInterrupt,
bool bImmuneToPullToPoint) {
CBITSTREAM;
CMSGHEADER;
bitStream.Write(objectId);
bitStream.Write(GAME_MSG::GAME_MSG_SET_STATUS_IMMUNITY);
bitStream.Write(state);
bitStream.Write(bImmuneToBasicAttack);
bitStream.Write(bImmuneToDamageOverTime);
bitStream.Write(bImmuneToKnockback);
bitStream.Write(bImmuneToInterrupt);
bitStream.Write(bImmuneToSpeed);
bitStream.Write(bImmuneToImaginationGain);
bitStream.Write(bImmuneToImaginationLoss);
bitStream.Write(bImmuneToQuickbuildInterrupt);
bitStream.Write(bImmuneToPullToPoint);
if (sysAddr == UNASSIGNED_SYSTEM_ADDRESS) SEND_PACKET_BROADCAST;
SEND_PACKET;
}
void GameMessages::SendOrientToAngle(LWOOBJID objectId, bool bRelativeToCurrent, float fAngle, const SystemAddress& sysAddr) {
CBITSTREAM;
@ -3991,7 +4054,7 @@ void GameMessages::HandleDismountComplete(RakNet::BitStream* inStream, Entity* e
EntityManager::Instance()->SerializeEntity(entity);
// We aren't mounted so remove the stun
GameMessages::SendSetStunned(entity->GetObjectID(), eStunState::POP, UNASSIGNED_SYSTEM_ADDRESS, LWOOBJID_EMPTY, true, false, true, false, false, false, false, true, true, true, true, true, true, true, true, true);
GameMessages::SendSetStunned(entity->GetObjectID(), eStateChangeType::POP, UNASSIGNED_SYSTEM_ADDRESS, LWOOBJID_EMPTY, true, false, true, false, false, false, false, true, true, true, true, true, true, true, true, true);
}
}
}

View File

@ -268,7 +268,7 @@ namespace GameMessages {
float leadOut = -1.0f, bool leavePlayerLocked = false);
void HandleCinematicUpdate(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr);
void SendSetStunned(LWOOBJID objectId, eStunState stateChangeType, const SystemAddress& sysAddr,
void SendSetStunned(LWOOBJID objectId, eStateChangeType stateChangeType, const SystemAddress& sysAddr,
LWOOBJID originator = LWOOBJID_EMPTY, bool bCantAttack = false, bool bCantEquip = false,
bool bCantInteract = false, bool bCantJump = false, bool bCantMove = false, bool bCantTurn = false,
bool bCantUseItem = false, bool bDontTerminateInteract = false, bool bIgnoreImmunity = true,
@ -277,6 +277,35 @@ namespace GameMessages {
bool bCantMoveOutChangeWasApplied = false, bool bCantTurnOutChangeWasApplied = false,
bool bCantUseItemOutChangeWasApplied = false);
void SendSetStunImmunity(
LWOOBJID target,
eStateChangeType state,
const SystemAddress& sysAddr,
LWOOBJID originator = LWOOBJID_EMPTY,
bool bImmuneToStunAttack = false,
bool bImmuneToStunEquip = false,
bool bImmuneToStunInteract = false,
bool bImmuneToStunJump = false,
bool bImmuneToStunMove = false,
bool bImmuneToStunTurn = false,
bool bImmuneToStunUseItem = false
);
void SendSetStatusImmunity(
LWOOBJID objectId,
eStateChangeType state,
const SystemAddress& sysAddr,
bool bImmuneToBasicAttack = false,
bool bImmuneToDamageOverTime = false,
bool bImmuneToKnockback = false,
bool bImmuneToInterrupt = false,
bool bImmuneToSpeed = false,
bool bImmuneToImaginationGain = false,
bool bImmuneToImaginationLoss = false,
bool bImmuneToQuickbuildInterrupt = false,
bool bImmuneToPullToPoint = false
);
void SendOrientToAngle(LWOOBJID objectId, bool bRelativeToCurrent, float fAngle, const SystemAddress& sysAddr);
void SendAddRunSpeedModifier(LWOOBJID objectId, LWOOBJID caster, uint32_t modifier, const SystemAddress& sysAddr);

View File

@ -131,7 +131,7 @@ void BaseEnemyApe::StunApe(Entity* self, bool stunState) {
skillComponent->Interrupt();
}
GameMessages::SendSetStunned(self->GetObjectID(), stunState ? PUSH : POP, UNASSIGNED_SYSTEM_ADDRESS, self->GetObjectID(),
GameMessages::SendSetStunned(self->GetObjectID(), stunState ? eStateChangeType::PUSH : eStateChangeType::POP, UNASSIGNED_SYSTEM_ADDRESS, self->GetObjectID(),
true, true, true, true, true,
true, true, true, true);

View File

@ -147,21 +147,21 @@ void AmSkullkinDrill::OnUse(Entity* self, Entity* user) {
}
void AmSkullkinDrill::FreezePlayer(Entity* self, Entity* player, bool bFreeze) {
eStunState eChangeType = POP;
auto StateChangeType = eStateChangeType::POP;
if (bFreeze) {
if (player->GetIsDead()) {
return;
}
eChangeType = PUSH;
StateChangeType = eStateChangeType::PUSH;
} else {
if (player->GetIsDead()) {
//
}
}
GameMessages::SendSetStunned(player->GetObjectID(), eChangeType, player->GetSystemAddress(), self->GetObjectID(),
GameMessages::SendSetStunned(player->GetObjectID(), StateChangeType, player->GetSystemAddress(), self->GetObjectID(),
true, false, true, false, true, false, true
);
}

View File

@ -13,7 +13,7 @@ void GfCaptainsCannon::OnUse(Entity* self, Entity* user) {
self->SetVar<bool>(u"bIsInUse", true);
self->SetNetworkVar<bool>(u"bIsInUse", true);
GameMessages::SendSetStunned(user->GetObjectID(), PUSH, user->GetSystemAddress(),
GameMessages::SendSetStunned(user->GetObjectID(), eStateChangeType::PUSH, user->GetSystemAddress(),
LWOOBJID_EMPTY, true, true, true, true, true, true, true, true
);
@ -63,7 +63,7 @@ void GfCaptainsCannon::OnTimerDone(Entity* self, std::string timerName) {
GameMessages::SendPlay2DAmbientSound(player, "{7457d85c-4537-4317-ac9d-2f549219ea87}");
} else if (timerName == "cinematicTimer") {
GameMessages::SendSetStunned(playerId, POP, player->GetSystemAddress(),
GameMessages::SendSetStunned(playerId, eStateChangeType::POP, player->GetSystemAddress(),
LWOOBJID_EMPTY, true, true, true, true, true, true, true, true
);

View File

@ -16,7 +16,7 @@ void MastTeleport::OnRebuildComplete(Entity* self, Entity* target) {
if (Preconditions::Check(target, 154) && Preconditions::Check(target, 44)) {
self->SetVar<LWOOBJID>(u"userID", target->GetObjectID());
GameMessages::SendSetStunned(target->GetObjectID(), PUSH, target->GetSystemAddress(),
GameMessages::SendSetStunned(target->GetObjectID(), eStateChangeType::PUSH, target->GetSystemAddress(),
LWOOBJID_EMPTY, true, true, true, true, true, true, true
);
@ -81,7 +81,7 @@ void MastTeleport::OnTimerDone(Entity* self, std::string timerName) {
GameMessages::SendTeleport(playerId, position, NiQuaternion::IDENTITY, player->GetSystemAddress());
GameMessages::SendSetStunned(playerId, POP, player->GetSystemAddress(),
GameMessages::SendSetStunned(playerId, eStateChangeType::POP, player->GetSystemAddress(),
LWOOBJID_EMPTY, true, true, true, true, true, true, true
);
}

View File

@ -36,7 +36,7 @@ void NtAssemblyTubeServer::RunAssemblyTube(Entity* self, Entity* player) {
if (player->IsPlayer() && !bPlayerBeingTeleported) {
auto teleCinematic = self->GetVar<std::u16string>(u"Cinematic");
GameMessages::SendSetStunned(playerID, PUSH, player->GetSystemAddress(), LWOOBJID_EMPTY,
GameMessages::SendSetStunned(playerID, eStateChangeType::PUSH, player->GetSystemAddress(), LWOOBJID_EMPTY,
true, true, true, true, true, true, true
);
@ -108,7 +108,7 @@ void NtAssemblyTubeServer::UnlockPlayer(Entity* self, Entity* player) {
m_TeleportingPlayerTable[playerID] = false;
GameMessages::SendSetStunned(playerID, POP, player->GetSystemAddress(), LWOOBJID_EMPTY,
GameMessages::SendSetStunned(playerID, eStateChangeType::POP, player->GetSystemAddress(), LWOOBJID_EMPTY,
true, true, true, true, true, true, true
);
}

View File

@ -34,11 +34,11 @@ void NtParadoxPanelServer::OnUse(Entity* self, Entity* user) {
GameMessages::SendPlayAnimation(player, u"rebuild-celebrate");
GameMessages::SendNotifyClientObject(self->GetObjectID(), u"SparkStop", 0, 0, player->GetObjectID(), "", player->GetSystemAddress());
GameMessages::SendSetStunned(player->GetObjectID(), eStunState::POP, player->GetSystemAddress(), LWOOBJID_EMPTY, false, false, true, false, true, true, false, false, true);
GameMessages::SendSetStunned(player->GetObjectID(), eStateChangeType::POP, player->GetSystemAddress(), LWOOBJID_EMPTY, false, false, true, false, true, true, false, false, true);
self->SetVar(u"bActive", false);
});
GameMessages::SendPlayAnimation(user, u"nexus-powerpanel", 6.0f);
GameMessages::SendSetStunned(user->GetObjectID(), eStunState::PUSH, user->GetSystemAddress(), LWOOBJID_EMPTY, false, false, true, false, true, true, false, false, true);
GameMessages::SendSetStunned(user->GetObjectID(), eStateChangeType::PUSH, user->GetSystemAddress(), LWOOBJID_EMPTY, false, false, true, false, true, true, false, false, true);
return;
}

View File

@ -22,7 +22,7 @@ void NtParadoxTeleServer::OnProximityUpdate(Entity* self, Entity* entering, std:
const auto bPlayerBeingTeleported = m_TeleportingPlayerTable[playerID];
if (player->IsPlayer() && !bPlayerBeingTeleported) {
GameMessages::SendSetStunned(playerID, PUSH, player->GetSystemAddress(), LWOOBJID_EMPTY,
GameMessages::SendSetStunned(playerID, eStateChangeType::PUSH, player->GetSystemAddress(), LWOOBJID_EMPTY,
true, true, true, true, true, true, true
);
@ -100,7 +100,7 @@ void NtParadoxTeleServer::UnlockPlayer(Entity* self, Entity* player) {
m_TeleportingPlayerTable[playerID] = false;
GameMessages::SendSetStunned(playerID, POP, player->GetSystemAddress(), LWOOBJID_EMPTY,
GameMessages::SendSetStunned(playerID, eStateChangeType::POP, player->GetSystemAddress(), LWOOBJID_EMPTY,
true, true, true, true, true, true, true
);

View File

@ -14,7 +14,7 @@ void NtVentureCannonServer::OnUse(Entity* self, Entity* user) {
self->SetNetworkVar(u"bIsInUse", true);
GameMessages::SendSetStunned(playerID, PUSH, player->GetSystemAddress(), LWOOBJID_EMPTY,
GameMessages::SendSetStunned(playerID, eStateChangeType::PUSH, player->GetSystemAddress(), LWOOBJID_EMPTY,
true, true, true, true, true, true, true
);
@ -92,7 +92,7 @@ void NtVentureCannonServer::ExitCannonEnded(Entity* self, Entity* player) {
}
void NtVentureCannonServer::UnlockCannonPlayer(Entity* self, Entity* player) {
GameMessages::SendSetStunned(player->GetObjectID(), POP, player->GetSystemAddress(), LWOOBJID_EMPTY,
GameMessages::SendSetStunned(player->GetObjectID(), eStateChangeType::POP, player->GetSystemAddress(), LWOOBJID_EMPTY,
true, true, true, true, true, true, true
);

View File

@ -15,7 +15,8 @@ void BaseConsoleTeleportServer::BaseOnMessageBoxResponse(Entity* self, Entity* s
if (button == 1) {
GameMessages::SendSetStunned(player->GetObjectID(), PUSH, player->GetSystemAddress(), player->GetObjectID(),
GameMessages::SendSetStunned(
player->GetObjectID(), eStateChangeType::PUSH, player->GetSystemAddress(), player->GetObjectID(),
true, true, true, true, true, true, true
);
@ -82,11 +83,10 @@ void BaseConsoleTeleportServer::TransferPlayer(Entity* self, Entity* player, int
return;
}
// Ignoring extra effects for now
/*GameMessages::SendSetStunned(player->GetObjectID(), POP, player->GetSystemAddress(), player->GetObjectID(),
GameMessages::SendSetStunned(
player->GetObjectID(), eStateChangeType::POP, player->GetSystemAddress(), player->GetObjectID(),
true, true, true, true, true, true, true
);*/
);
GameMessages::SendTerminateInteraction(player->GetObjectID(), FROM_INTERACTION, player->GetObjectID());

View File

@ -2,49 +2,56 @@
#include "GameMessages.h"
#include "SkillComponent.h"
#include "DestroyableComponent.h"
#include "ControllablePhysicsComponent.h"
#include "EntityManager.h"
void PersonalFortress::OnStartup(Entity* self) {
auto* owner = self->GetOwner();
self->AddTimer("FireSkill", 1.5);
GameMessages::SendSetStunned(owner->GetObjectID(), PUSH, owner->GetSystemAddress(), LWOOBJID_EMPTY,
true, true, true, true, true, true, true, true, true
);
auto* destroyableComponent = owner->GetComponent<DestroyableComponent>();
if (destroyableComponent) destroyableComponent->SetStatusImmunity(
eStateChangeType::PUSH,
true, true, true, true, true, false, true, false, false
);
if (destroyableComponent != nullptr) {
destroyableComponent->PushImmunity();
}
auto* controllablePhysicsComponent = owner->GetComponent<ControllablePhysicsComponent>();
if (controllablePhysicsComponent) controllablePhysicsComponent->SetStunImmunity(
eStateChangeType::PUSH, LWOOBJID_EMPTY,
true, true, true, true, true, true
);
GameMessages::SendSetStunned(owner->GetObjectID(), eStateChangeType::PUSH, owner->GetSystemAddress(), LWOOBJID_EMPTY,
true, true, true, true, true, true, true, true, true
);
EntityManager::Instance()->SerializeEntity(owner);
}
void PersonalFortress::OnDie(Entity* self, Entity* killer) {
auto* owner = self->GetOwner();
GameMessages::SendSetStunned(owner->GetObjectID(), POP, owner->GetSystemAddress(), LWOOBJID_EMPTY,
auto* destroyableComponent = owner->GetComponent<DestroyableComponent>();
if (destroyableComponent) destroyableComponent->SetStatusImmunity(
eStateChangeType::POP,
true, true, true, true, true, false, true, false, false
);
auto* controllablePhysicsComponent = owner->GetComponent<ControllablePhysicsComponent>();
if (controllablePhysicsComponent) controllablePhysicsComponent->SetStunImmunity(
eStateChangeType::POP, LWOOBJID_EMPTY,
true, true, true, true, true, true
);
GameMessages::SendSetStunned(owner->GetObjectID(), eStateChangeType::POP, owner->GetSystemAddress(), LWOOBJID_EMPTY,
true, true, true, true, true, true, true, true, true
);
auto* destroyableComponent = owner->GetComponent<DestroyableComponent>();
if (destroyableComponent != nullptr) {
destroyableComponent->PopImmunity();
}
EntityManager::Instance()->SerializeEntity(owner);
}
void PersonalFortress::OnTimerDone(Entity* self, std::string timerName) {
if (timerName == "FireSkill") {
auto* owner = self->GetOwner();
auto* skillComponent = self->GetComponent<SkillComponent>();
if (skillComponent == nullptr) {
return;
}
skillComponent->CalculateBehavior(650, 13364, LWOOBJID_EMPTY, true, false);
if (skillComponent) skillComponent->CalculateBehavior(650, 13364, LWOOBJID_EMPTY, true, false);
}
}

View File

@ -77,7 +77,7 @@ void SGCannon::OnActivityStateChangeRequest(Entity* self, LWOOBJID senderID, int
auto* player = EntityManager::Instance()->GetEntity(self->GetVar<LWOOBJID>(PlayerIDVariable));
if (player != nullptr) {
Game::logger->Log("SGCannon", "Player is ready");
/*GameMessages::SendSetStunned(player->GetObjectID(), PUSH, player->GetSystemAddress(), LWOOBJID_EMPTY,
/*GameMessages::SendSetStunned(player->GetObjectID(), eStateChangeType::PUSH, player->GetSystemAddress(), LWOOBJID_EMPTY,
true, true, true, true, true, true, true);*/
Game::logger->Log("SGCannon", "Sending ActivityEnter");

View File

@ -41,10 +41,19 @@ protected:
TEST_F(DestroyableTest, DestroyableComponentSerializeConstructionTest) {
destroyableComponent->Serialize(&bitStream, true, flags);
// Assert that the full number of bits are present
ASSERT_EQ(bitStream.GetNumberOfUnreadBits(), 460);
ASSERT_EQ(bitStream.GetNumberOfUnreadBits(), 748);
{
// Now read in the full serialized construction BitStream
bool optionStatusImmunityInfo{}; // Values under this option are unused.
bool optionStatusImmunityInfo{};
uint32_t ImmuneToBasicAttackCount{};
uint32_t ImmuneToDamageOverTimeCount{};
uint32_t ImmuneToKnockbackCount{};
uint32_t ImmuneToInterruptCount{};
uint32_t ImmuneToSpeedCount{};
uint32_t ImmuneToImaginationGainCount{};
uint32_t ImmuneToImaginationLossCount{};
uint32_t ImmuneToQuickbuildInterruptCount{};
uint32_t ImmuneToPullToPointCount{};
bool optionStatsInfo{};
uint32_t currentHealth{};
float maxHealth{};
@ -70,7 +79,15 @@ TEST_F(DestroyableTest, DestroyableComponentSerializeConstructionTest) {
bool optionIsOnThreatList{};
bool isThreatened{};
bitStream.Read(optionStatusImmunityInfo);
bitStream.Read(ImmuneToBasicAttackCount);
bitStream.Read(ImmuneToDamageOverTimeCount);
bitStream.Read(ImmuneToKnockbackCount);
bitStream.Read(ImmuneToInterruptCount);
bitStream.Read(ImmuneToSpeedCount);
bitStream.Read(ImmuneToImaginationGainCount);
bitStream.Read(ImmuneToImaginationLossCount);
bitStream.Read(ImmuneToQuickbuildInterruptCount);
bitStream.Read(ImmuneToPullToPointCount);
bitStream.Read(optionStatsInfo);
bitStream.Read(currentHealth);
bitStream.Read(maxHealth);
@ -101,7 +118,16 @@ TEST_F(DestroyableTest, DestroyableComponentSerializeConstructionTest) {
bitStream.Read(optionIsOnThreatList);
bitStream.Read(isThreatened);
EXPECT_EQ(optionStatusImmunityInfo, false);
EXPECT_EQ(optionStatusImmunityInfo, true);
EXPECT_EQ(ImmuneToBasicAttackCount, 0);
EXPECT_EQ(ImmuneToDamageOverTimeCount, 0);
EXPECT_EQ(ImmuneToKnockbackCount, 0);
EXPECT_EQ(ImmuneToInterruptCount, 0);
EXPECT_EQ(ImmuneToSpeedCount, 0);
EXPECT_EQ(ImmuneToImaginationGainCount, 0);
EXPECT_EQ(ImmuneToImaginationLossCount, 0);
EXPECT_EQ(ImmuneToQuickbuildInterruptCount, 0);
EXPECT_EQ(ImmuneToPullToPointCount, 0);
EXPECT_EQ(optionStatsInfo, true);
EXPECT_EQ(currentHealth, 23);
@ -298,3 +324,208 @@ TEST_F(DestroyableTest, DestroyableComponentValiditiyTest) {
EXPECT_FALSE(destroyableComponent->IsFriend(enemyEntity));
delete enemyEntity;
}
TEST_F(DestroyableTest, DestroyableComponentImmunityTest) {
// assert to show that they are empty
ASSERT_FALSE(destroyableComponent->GetImmuneToBasicAttack());
ASSERT_FALSE(destroyableComponent->GetImmuneToDamageOverTime());
ASSERT_FALSE(destroyableComponent->GetImmuneToKnockback());
ASSERT_FALSE(destroyableComponent->GetImmuneToInterrupt());
ASSERT_FALSE(destroyableComponent->GetImmuneToSpeed());
ASSERT_FALSE(destroyableComponent->GetImmuneToImaginationGain());
ASSERT_FALSE(destroyableComponent->GetImmuneToImaginationLoss());
ASSERT_FALSE(destroyableComponent->GetImmuneToQuickbuildInterrupt());
ASSERT_FALSE(destroyableComponent->GetImmuneToPullToPoint());
// set them all to true (count 1) and check
destroyableComponent->SetStatusImmunity(eStateChangeType::PUSH, true, true, true, true, true, true, true, true, true);
ASSERT_TRUE(destroyableComponent->GetImmuneToBasicAttack());
ASSERT_TRUE(destroyableComponent->GetImmuneToDamageOverTime());
ASSERT_TRUE(destroyableComponent->GetImmuneToKnockback());
ASSERT_TRUE(destroyableComponent->GetImmuneToInterrupt());
ASSERT_TRUE(destroyableComponent->GetImmuneToSpeed());
ASSERT_TRUE(destroyableComponent->GetImmuneToImaginationGain());
ASSERT_TRUE(destroyableComponent->GetImmuneToImaginationLoss());
ASSERT_TRUE(destroyableComponent->GetImmuneToQuickbuildInterrupt());
ASSERT_TRUE(destroyableComponent->GetImmuneToPullToPoint());
// remove them to check that they get removed properly
destroyableComponent->SetStatusImmunity(eStateChangeType::POP, true, true, true, true, true, true, true, true, true);
ASSERT_FALSE(destroyableComponent->GetImmuneToBasicAttack());
ASSERT_FALSE(destroyableComponent->GetImmuneToDamageOverTime());
ASSERT_FALSE(destroyableComponent->GetImmuneToKnockback());
ASSERT_FALSE(destroyableComponent->GetImmuneToInterrupt());
ASSERT_FALSE(destroyableComponent->GetImmuneToSpeed());
ASSERT_FALSE(destroyableComponent->GetImmuneToImaginationGain());
ASSERT_FALSE(destroyableComponent->GetImmuneToImaginationLoss());
ASSERT_FALSE(destroyableComponent->GetImmuneToQuickbuildInterrupt());
ASSERT_FALSE(destroyableComponent->GetImmuneToPullToPoint());
// should not crash to remove them again
destroyableComponent->SetStatusImmunity(eStateChangeType::POP, true, true, true, true, true, true, true, true, true);
ASSERT_FALSE(destroyableComponent->GetImmuneToBasicAttack());
ASSERT_FALSE(destroyableComponent->GetImmuneToDamageOverTime());
ASSERT_FALSE(destroyableComponent->GetImmuneToKnockback());
ASSERT_FALSE(destroyableComponent->GetImmuneToInterrupt());
ASSERT_FALSE(destroyableComponent->GetImmuneToSpeed());
ASSERT_FALSE(destroyableComponent->GetImmuneToImaginationGain());
ASSERT_FALSE(destroyableComponent->GetImmuneToImaginationLoss());
ASSERT_FALSE(destroyableComponent->GetImmuneToQuickbuildInterrupt());
ASSERT_FALSE(destroyableComponent->GetImmuneToPullToPoint());
// just do one
destroyableComponent->SetStatusImmunity(eStateChangeType::PUSH, true);
ASSERT_TRUE(destroyableComponent->GetImmuneToBasicAttack());
ASSERT_FALSE(destroyableComponent->GetImmuneToDamageOverTime());
ASSERT_FALSE(destroyableComponent->GetImmuneToKnockback());
ASSERT_FALSE(destroyableComponent->GetImmuneToInterrupt());
ASSERT_FALSE(destroyableComponent->GetImmuneToSpeed());
ASSERT_FALSE(destroyableComponent->GetImmuneToImaginationGain());
ASSERT_FALSE(destroyableComponent->GetImmuneToImaginationLoss());
ASSERT_FALSE(destroyableComponent->GetImmuneToQuickbuildInterrupt());
ASSERT_FALSE(destroyableComponent->GetImmuneToPullToPoint());
// now stack it to 2 on basic attack
destroyableComponent->SetStatusImmunity(eStateChangeType::PUSH, true);
ASSERT_TRUE(destroyableComponent->GetImmuneToBasicAttack());
ASSERT_FALSE(destroyableComponent->GetImmuneToDamageOverTime());
ASSERT_FALSE(destroyableComponent->GetImmuneToKnockback());
ASSERT_FALSE(destroyableComponent->GetImmuneToInterrupt());
ASSERT_FALSE(destroyableComponent->GetImmuneToSpeed());
ASSERT_FALSE(destroyableComponent->GetImmuneToImaginationGain());
ASSERT_FALSE(destroyableComponent->GetImmuneToImaginationLoss());
ASSERT_FALSE(destroyableComponent->GetImmuneToQuickbuildInterrupt());
ASSERT_FALSE(destroyableComponent->GetImmuneToPullToPoint());
// remove one and still shoudl be true
destroyableComponent->SetStatusImmunity(eStateChangeType::POP, true);
ASSERT_TRUE(destroyableComponent->GetImmuneToBasicAttack());
ASSERT_FALSE(destroyableComponent->GetImmuneToDamageOverTime());
ASSERT_FALSE(destroyableComponent->GetImmuneToKnockback());
ASSERT_FALSE(destroyableComponent->GetImmuneToInterrupt());
ASSERT_FALSE(destroyableComponent->GetImmuneToSpeed());
ASSERT_FALSE(destroyableComponent->GetImmuneToImaginationGain());
ASSERT_FALSE(destroyableComponent->GetImmuneToImaginationLoss());
ASSERT_FALSE(destroyableComponent->GetImmuneToQuickbuildInterrupt());
ASSERT_FALSE(destroyableComponent->GetImmuneToPullToPoint());
// go back to 0
destroyableComponent->SetStatusImmunity(eStateChangeType::POP, true);
ASSERT_FALSE(destroyableComponent->GetImmuneToBasicAttack());
ASSERT_FALSE(destroyableComponent->GetImmuneToDamageOverTime());
ASSERT_FALSE(destroyableComponent->GetImmuneToKnockback());
ASSERT_FALSE(destroyableComponent->GetImmuneToInterrupt());
ASSERT_FALSE(destroyableComponent->GetImmuneToSpeed());
ASSERT_FALSE(destroyableComponent->GetImmuneToImaginationGain());
ASSERT_FALSE(destroyableComponent->GetImmuneToImaginationLoss());
ASSERT_FALSE(destroyableComponent->GetImmuneToQuickbuildInterrupt());
ASSERT_FALSE(destroyableComponent->GetImmuneToPullToPoint());
// check individual ones now
destroyableComponent->SetStatusImmunity(eStateChangeType::PUSH, true, false, false, false, false, false, false, false, false);
ASSERT_TRUE(destroyableComponent->GetImmuneToBasicAttack());
ASSERT_FALSE(destroyableComponent->GetImmuneToDamageOverTime());
ASSERT_FALSE(destroyableComponent->GetImmuneToKnockback());
ASSERT_FALSE(destroyableComponent->GetImmuneToInterrupt());
ASSERT_FALSE(destroyableComponent->GetImmuneToSpeed());
ASSERT_FALSE(destroyableComponent->GetImmuneToImaginationGain());
ASSERT_FALSE(destroyableComponent->GetImmuneToImaginationLoss());
ASSERT_FALSE(destroyableComponent->GetImmuneToQuickbuildInterrupt());
ASSERT_FALSE(destroyableComponent->GetImmuneToPullToPoint());
destroyableComponent->SetStatusImmunity(eStateChangeType::POP, true, false, false, false, false, false, false, false, false);
destroyableComponent->SetStatusImmunity(eStateChangeType::PUSH, false, true, false, false, false, false, false, false, false);
ASSERT_FALSE(destroyableComponent->GetImmuneToBasicAttack());
ASSERT_TRUE(destroyableComponent->GetImmuneToDamageOverTime());
ASSERT_FALSE(destroyableComponent->GetImmuneToKnockback());
ASSERT_FALSE(destroyableComponent->GetImmuneToInterrupt());
ASSERT_FALSE(destroyableComponent->GetImmuneToSpeed());
ASSERT_FALSE(destroyableComponent->GetImmuneToImaginationGain());
ASSERT_FALSE(destroyableComponent->GetImmuneToImaginationLoss());
ASSERT_FALSE(destroyableComponent->GetImmuneToQuickbuildInterrupt());
ASSERT_FALSE(destroyableComponent->GetImmuneToPullToPoint());
destroyableComponent->SetStatusImmunity(eStateChangeType::POP, false, true, false, false, false, false, false, false, false);
destroyableComponent->SetStatusImmunity(eStateChangeType::PUSH, false, false, true, false, false, false, false, false, false);
ASSERT_FALSE(destroyableComponent->GetImmuneToBasicAttack());
ASSERT_FALSE(destroyableComponent->GetImmuneToDamageOverTime());
ASSERT_TRUE(destroyableComponent->GetImmuneToKnockback());
ASSERT_FALSE(destroyableComponent->GetImmuneToInterrupt());
ASSERT_FALSE(destroyableComponent->GetImmuneToSpeed());
ASSERT_FALSE(destroyableComponent->GetImmuneToImaginationGain());
ASSERT_FALSE(destroyableComponent->GetImmuneToImaginationLoss());
ASSERT_FALSE(destroyableComponent->GetImmuneToQuickbuildInterrupt());
ASSERT_FALSE(destroyableComponent->GetImmuneToPullToPoint());
destroyableComponent->SetStatusImmunity(eStateChangeType::POP, false, false, true, false, false, false, false, false, false);
destroyableComponent->SetStatusImmunity(eStateChangeType::PUSH, false, false, false, true, false, false, false, false, false);
ASSERT_FALSE(destroyableComponent->GetImmuneToBasicAttack());
ASSERT_FALSE(destroyableComponent->GetImmuneToDamageOverTime());
ASSERT_FALSE(destroyableComponent->GetImmuneToKnockback());
ASSERT_TRUE(destroyableComponent->GetImmuneToInterrupt());
ASSERT_FALSE(destroyableComponent->GetImmuneToSpeed());
ASSERT_FALSE(destroyableComponent->GetImmuneToImaginationGain());
ASSERT_FALSE(destroyableComponent->GetImmuneToImaginationLoss());
ASSERT_FALSE(destroyableComponent->GetImmuneToQuickbuildInterrupt());
ASSERT_FALSE(destroyableComponent->GetImmuneToPullToPoint());
destroyableComponent->SetStatusImmunity(eStateChangeType::POP, false, false, false, true, false, false, false, false, false);
destroyableComponent->SetStatusImmunity(eStateChangeType::PUSH, false, false, false, false, true, false, false, false, false);
ASSERT_FALSE(destroyableComponent->GetImmuneToBasicAttack());
ASSERT_FALSE(destroyableComponent->GetImmuneToDamageOverTime());
ASSERT_FALSE(destroyableComponent->GetImmuneToKnockback());
ASSERT_FALSE(destroyableComponent->GetImmuneToInterrupt());
ASSERT_TRUE(destroyableComponent->GetImmuneToSpeed());
ASSERT_FALSE(destroyableComponent->GetImmuneToImaginationGain());
ASSERT_FALSE(destroyableComponent->GetImmuneToImaginationLoss());
ASSERT_FALSE(destroyableComponent->GetImmuneToQuickbuildInterrupt());
ASSERT_FALSE(destroyableComponent->GetImmuneToPullToPoint());
destroyableComponent->SetStatusImmunity(eStateChangeType::POP, false, false, false, false, true, false, false, false, false);
destroyableComponent->SetStatusImmunity(eStateChangeType::PUSH, false, false, false, false, false, true, false, false, false);
ASSERT_FALSE(destroyableComponent->GetImmuneToBasicAttack());
ASSERT_FALSE(destroyableComponent->GetImmuneToDamageOverTime());
ASSERT_FALSE(destroyableComponent->GetImmuneToKnockback());
ASSERT_FALSE(destroyableComponent->GetImmuneToInterrupt());
ASSERT_FALSE(destroyableComponent->GetImmuneToSpeed());
ASSERT_TRUE(destroyableComponent->GetImmuneToImaginationGain());
ASSERT_FALSE(destroyableComponent->GetImmuneToImaginationLoss());
ASSERT_FALSE(destroyableComponent->GetImmuneToQuickbuildInterrupt());
ASSERT_FALSE(destroyableComponent->GetImmuneToPullToPoint());
destroyableComponent->SetStatusImmunity(eStateChangeType::POP, false, false, false, false, false, true, false, false, false);
destroyableComponent->SetStatusImmunity(eStateChangeType::PUSH, false, false, false, false, false, false, true, false, false);
ASSERT_FALSE(destroyableComponent->GetImmuneToBasicAttack());
ASSERT_FALSE(destroyableComponent->GetImmuneToDamageOverTime());
ASSERT_FALSE(destroyableComponent->GetImmuneToKnockback());
ASSERT_FALSE(destroyableComponent->GetImmuneToInterrupt());
ASSERT_FALSE(destroyableComponent->GetImmuneToSpeed());
ASSERT_FALSE(destroyableComponent->GetImmuneToImaginationGain());
ASSERT_TRUE(destroyableComponent->GetImmuneToImaginationLoss());
ASSERT_FALSE(destroyableComponent->GetImmuneToQuickbuildInterrupt());
ASSERT_FALSE(destroyableComponent->GetImmuneToPullToPoint());
destroyableComponent->SetStatusImmunity(eStateChangeType::POP, false, false, false, false, false, false, true, false, false);
destroyableComponent->SetStatusImmunity(eStateChangeType::PUSH, false, false, false, false, false, false, false, true, false);
ASSERT_FALSE(destroyableComponent->GetImmuneToBasicAttack());
ASSERT_FALSE(destroyableComponent->GetImmuneToDamageOverTime());
ASSERT_FALSE(destroyableComponent->GetImmuneToKnockback());
ASSERT_FALSE(destroyableComponent->GetImmuneToInterrupt());
ASSERT_FALSE(destroyableComponent->GetImmuneToSpeed());
ASSERT_FALSE(destroyableComponent->GetImmuneToImaginationGain());
ASSERT_FALSE(destroyableComponent->GetImmuneToImaginationLoss());
ASSERT_TRUE(destroyableComponent->GetImmuneToQuickbuildInterrupt());
ASSERT_FALSE(destroyableComponent->GetImmuneToPullToPoint());
destroyableComponent->SetStatusImmunity(eStateChangeType::POP, false, false, false, false, false, false, false, true, false);
destroyableComponent->SetStatusImmunity(eStateChangeType::PUSH, false, false, false, false, false, false, false, false, true);
ASSERT_FALSE(destroyableComponent->GetImmuneToBasicAttack());
ASSERT_FALSE(destroyableComponent->GetImmuneToDamageOverTime());
ASSERT_FALSE(destroyableComponent->GetImmuneToKnockback());
ASSERT_FALSE(destroyableComponent->GetImmuneToInterrupt());
ASSERT_FALSE(destroyableComponent->GetImmuneToSpeed());
ASSERT_FALSE(destroyableComponent->GetImmuneToImaginationGain());
ASSERT_FALSE(destroyableComponent->GetImmuneToImaginationLoss());
ASSERT_FALSE(destroyableComponent->GetImmuneToQuickbuildInterrupt());
ASSERT_TRUE(destroyableComponent->GetImmuneToPullToPoint());
destroyableComponent->SetStatusImmunity(eStateChangeType::POP, false, false, false, false, false, false, false, false, true);
}