2021-12-05 17:54:36 +00:00
# include "DestroyableComponent.h"
# include <BitStream.h>
# include "dLogger.h"
# include "Game.h"
2023-01-11 19:08:54 +00:00
# include "dConfig.h"
2021-12-05 17:54:36 +00:00
2023-05-13 22:22:00 +00:00
# include "Amf3.h"
# include "AmfSerialize.h"
2021-12-05 17:54:36 +00:00
# include "GameMessages.h"
# include "User.h"
# include "CDClientManager.h"
# include "CDDestructibleComponentTable.h"
# include "EntityManager.h"
2023-06-09 22:12:57 +00:00
# include "QuickBuildComponent.h"
2021-12-05 17:54:36 +00:00
# include "CppScripts.h"
# include "Loot.h"
# include "Character.h"
# include "Spawner.h"
# include "BaseCombatAIComponent.h"
# include "TeamManager.h"
# include "BuffComponent.h"
# include "SkillComponent.h"
# include "Item.h"
# include <sstream>
# include <algorithm>
# include "MissionComponent.h"
# include "CharacterComponent.h"
2022-09-02 18:49:19 +00:00
# include "PossessableComponent.h"
# include "PossessorComponent.h"
2022-12-18 15:46:04 +00:00
# include "InventoryComponent.h"
2022-02-05 12:27:24 +00:00
# include "dZoneManager.h"
2023-01-01 12:51:22 +00:00
# include "WorldConfig.h"
2021-12-05 17:54:36 +00:00
# include "eMissionTaskType.h"
2023-05-02 22:39:21 +00:00
# include "eStateChangeType.h"
# include "eGameActivity.h"
2021-12-05 17:54:36 +00:00
2023-03-17 14:36:21 +00:00
# include "CDComponentsRegistryTable.h"
2023-06-12 08:29:43 +00:00
# include "CDCurrencyTableTable.h"
2023-03-17 14:36:21 +00:00
2023-06-12 08:29:43 +00:00
DestroyableComponent : : DestroyableComponent ( Entity * parent , int32_t componentId ) : Component ( parent ) {
2021-12-05 17:54:36 +00:00
m_iArmor = 0 ;
m_fMaxArmor = 0.0f ;
m_iImagination = 0 ;
m_fMaxImagination = 0.0f ;
m_FactionIDs = std : : vector < int32_t > ( ) ;
m_EnemyFactionIDs = std : : vector < int32_t > ( ) ;
m_IsSmashable = false ;
m_IsDead = false ;
m_IsSmashed = false ;
m_IsGMImmune = false ;
m_IsShielded = false ;
m_DamageToAbsorb = 0 ;
m_HasBricks = false ;
m_DirtyThreatList = false ;
m_HasThreats = false ;
m_ExplodeFactor = 1.0f ;
m_iHealth = 0 ;
m_fMaxHealth = 0 ;
m_AttacksToBlock = 0 ;
m_LootMatrixID = 0 ;
m_MinCoins = 0 ;
m_MaxCoins = 0 ;
m_DamageReduction = 0 ;
2023-06-12 08:29:43 +00:00
m_ComponentId = componentId ;
2023-01-07 05:59:19 +00:00
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 ;
2021-12-05 17:54:36 +00:00
}
2023-06-12 08:29:43 +00:00
void DestroyableComponent : : Startup ( ) {
2021-12-05 17:54:36 +00:00
}
2023-06-12 08:29:43 +00:00
void DestroyableComponent : : LoadConfigData ( ) {
SetIsSmashable ( m_ParentEntity - > GetVarAs < int32_t > ( u " is_smashable " ) ! = 0 ) ;
}
void DestroyableComponent : : LoadTemplateData ( ) {
2023-06-12 11:27:14 +00:00
if ( m_ParentEntity - > IsPlayer ( ) ) return ;
2023-06-12 08:29:43 +00:00
auto * destroyableComponentTable = CDClientManager : : Instance ( ) . GetTable < CDDestructibleComponentTable > ( ) ;
auto destroyableDataLookup = destroyableComponentTable - > Query ( [ this ] ( CDDestructibleComponent entry ) { return ( entry . id = = this - > m_ComponentId ) ; } ) ;
if ( m_ComponentId = = - 1 | | destroyableDataLookup . empty ( ) ) {
SetHealth ( 1 ) ;
SetArmor ( 0 ) ;
2021-12-05 17:54:36 +00:00
2023-06-12 08:29:43 +00:00
SetMaxHealth ( 1 ) ;
SetMaxArmor ( 0 ) ;
2021-12-05 17:54:36 +00:00
2023-06-12 08:29:43 +00:00
SetIsSmashable ( true ) ;
AddFaction ( - 1 ) ;
AddFaction ( 6 ) ; //Smashables
2021-12-05 17:54:36 +00:00
2023-06-12 08:29:43 +00:00
// A race car has 60 imagination, other entities defaults to 0.
SetImagination ( m_ParentEntity - > HasComponent ( eReplicaComponentType : : RACING_STATS ) ? 60 : 0 ) ;
SetMaxImagination ( m_ParentEntity - > HasComponent ( eReplicaComponentType : : RACING_STATS ) ? 60 : 0 ) ;
return ;
}
2021-12-05 17:54:36 +00:00
2023-06-12 08:29:43 +00:00
auto destroyableData = destroyableDataLookup . at ( 0 ) ;
if ( m_ParentEntity - > HasComponent ( eReplicaComponentType : : RACING_STATS ) ) {
destroyableData . imagination = 60 ;
}
2021-12-05 17:54:36 +00:00
2023-06-12 08:29:43 +00:00
SetHealth ( destroyableData . life ) ;
SetImagination ( destroyableData . imagination ) ;
SetArmor ( destroyableData . armor ) ;
2021-12-05 17:54:36 +00:00
2023-06-12 08:29:43 +00:00
SetMaxHealth ( destroyableData . life ) ;
SetMaxImagination ( destroyableData . imagination ) ;
SetMaxArmor ( destroyableData . armor ) ;
2021-12-05 17:54:36 +00:00
2023-06-12 08:29:43 +00:00
SetIsSmashable ( destroyableData . isSmashable ) ;
2021-12-05 17:54:36 +00:00
2023-06-12 08:29:43 +00:00
SetLootMatrixID ( destroyableData . LootMatrixIndex ) ;
2021-12-05 17:54:36 +00:00
2023-06-12 08:29:43 +00:00
// Now get currency information
uint32_t npcMinLevel = destroyableData . level ;
uint32_t currencyIndex = destroyableData . CurrencyIndex ;
2021-12-05 17:54:36 +00:00
2023-06-12 08:29:43 +00:00
auto * currencyTable = CDClientManager : : Instance ( ) . GetTable < CDCurrencyTableTable > ( ) ;
auto currencyValues = currencyTable - > Query ( [ = ] ( CDCurrencyTable entry ) { return ( entry . currencyIndex = = currencyIndex & & entry . npcminlevel = = npcMinLevel ) ; } ) ;
if ( currencyValues . size ( ) > 0 ) {
// Set the coins
SetMinCoins ( currencyValues . at ( 0 ) . minvalue ) ;
SetMaxCoins ( currencyValues . at ( 0 ) . maxvalue ) ;
}
AddFaction ( destroyableData . faction ) ;
std : : stringstream ss ( destroyableData . factionList ) ;
std : : string tokenStr ;
while ( std : : getline ( ss , tokenStr , ' , ' ) ) {
int32_t factionToAdd = - 2 ;
if ( ! GeneralUtils : : TryParse ( tokenStr , factionToAdd ) | | factionToAdd = = - 2 | | factionToAdd = = destroyableData . faction ) continue ;
AddFaction ( factionToAdd ) ;
2021-12-05 17:54:36 +00:00
}
}
void DestroyableComponent : : Serialize ( RakNet : : BitStream * outBitStream , bool bIsInitialUpdate , uint32_t & flags ) {
if ( bIsInitialUpdate ) {
2023-01-07 05:59:19 +00:00
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 ) ;
2021-12-05 17:54:36 +00:00
}
2022-07-28 13:39:57 +00:00
2022-01-15 19:02:14 +00:00
outBitStream - > Write ( m_DirtyHealth | | bIsInitialUpdate ) ;
2021-12-05 17:54:36 +00:00
if ( m_DirtyHealth | | bIsInitialUpdate ) {
outBitStream - > Write ( m_iHealth ) ;
outBitStream - > Write ( m_fMaxHealth ) ;
outBitStream - > Write ( m_iArmor ) ;
outBitStream - > Write ( m_fMaxArmor ) ;
outBitStream - > Write ( m_iImagination ) ;
outBitStream - > Write ( m_fMaxImagination ) ;
2022-07-28 13:39:57 +00:00
2021-12-05 17:54:36 +00:00
outBitStream - > Write ( m_DamageToAbsorb ) ;
outBitStream - > Write ( IsImmune ( ) ) ;
outBitStream - > Write ( m_IsGMImmune ) ;
outBitStream - > Write ( m_IsShielded ) ;
2022-07-28 13:39:57 +00:00
2021-12-05 17:54:36 +00:00
outBitStream - > Write ( m_fMaxHealth ) ;
outBitStream - > Write ( m_fMaxArmor ) ;
outBitStream - > Write ( m_fMaxImagination ) ;
outBitStream - > Write ( uint32_t ( m_FactionIDs . size ( ) ) ) ;
for ( size_t i = 0 ; i < m_FactionIDs . size ( ) ; + + i ) {
outBitStream - > Write ( m_FactionIDs [ i ] ) ;
}
outBitStream - > Write ( m_IsSmashable ) ;
2022-01-15 19:02:14 +00:00
2021-12-05 17:54:36 +00:00
if ( bIsInitialUpdate ) {
outBitStream - > Write ( m_IsDead ) ;
outBitStream - > Write ( m_IsSmashed ) ;
2022-01-15 19:02:14 +00:00
2021-12-05 17:54:36 +00:00
if ( m_IsSmashable ) {
outBitStream - > Write ( m_HasBricks ) ;
2022-11-07 08:12:35 +00:00
outBitStream - > Write ( m_ExplodeFactor ! = 1.0f ) ;
if ( m_ExplodeFactor ! = 1.0f ) outBitStream - > Write ( m_ExplodeFactor ) ;
2021-12-05 17:54:36 +00:00
}
}
m_DirtyHealth = false ;
}
2022-01-15 19:02:14 +00:00
2022-11-07 08:12:35 +00:00
outBitStream - > Write ( m_DirtyThreatList | | bIsInitialUpdate ) ;
2021-12-05 17:54:36 +00:00
if ( m_DirtyThreatList | | bIsInitialUpdate ) {
outBitStream - > Write ( m_HasThreats ) ;
m_DirtyThreatList = false ;
}
}
2022-07-25 02:03:22 +00:00
void DestroyableComponent : : LoadFromXml ( tinyxml2 : : XMLDocument * doc ) {
2021-12-05 17:54:36 +00:00
tinyxml2 : : XMLElement * dest = doc - > FirstChildElement ( " obj " ) - > FirstChildElement ( " dest " ) ;
if ( ! dest ) {
2022-07-25 02:26:51 +00:00
Game : : logger - > Log ( " DestroyableComponent " , " Failed to find dest tag! " ) ;
2021-12-05 17:54:36 +00:00
return ;
}
2023-06-09 09:46:01 +00:00
auto * buffComponent = m_ParentEntity - > GetComponent < BuffComponent > ( ) ;
2022-01-15 19:02:14 +00:00
2021-12-05 17:54:36 +00:00
if ( buffComponent ! = nullptr ) {
2022-07-25 02:03:22 +00:00
buffComponent - > LoadFromXml ( doc ) ;
2021-12-05 17:54:36 +00:00
}
dest - > QueryAttribute ( " hc " , & m_iHealth ) ;
dest - > QueryAttribute ( " hm " , & m_fMaxHealth ) ;
dest - > QueryAttribute ( " im " , & m_fMaxImagination ) ;
dest - > QueryAttribute ( " ic " , & m_iImagination ) ;
dest - > QueryAttribute ( " ac " , & m_iArmor ) ;
dest - > QueryAttribute ( " am " , & m_fMaxArmor ) ;
m_DirtyHealth = true ;
}
void DestroyableComponent : : UpdateXml ( tinyxml2 : : XMLDocument * doc ) {
tinyxml2 : : XMLElement * dest = doc - > FirstChildElement ( " obj " ) - > FirstChildElement ( " dest " ) ;
if ( ! dest ) {
2022-07-25 02:26:51 +00:00
Game : : logger - > Log ( " DestroyableComponent " , " Failed to find dest tag! " ) ;
2021-12-05 17:54:36 +00:00
return ;
}
2022-01-15 19:02:14 +00:00
2023-06-09 09:46:01 +00:00
auto * buffComponent = m_ParentEntity - > GetComponent < BuffComponent > ( ) ;
2022-01-15 19:02:14 +00:00
2021-12-05 17:54:36 +00:00
if ( buffComponent ! = nullptr ) {
buffComponent - > UpdateXml ( doc ) ;
}
dest - > SetAttribute ( " hc " , m_iHealth ) ;
dest - > SetAttribute ( " hm " , m_fMaxHealth ) ;
dest - > SetAttribute ( " im " , m_fMaxImagination ) ;
dest - > SetAttribute ( " ic " , m_iImagination ) ;
dest - > SetAttribute ( " ac " , m_iArmor ) ;
dest - > SetAttribute ( " am " , m_fMaxArmor ) ;
}
void DestroyableComponent : : SetHealth ( int32_t value ) {
m_DirtyHealth = true ;
2023-06-09 09:46:01 +00:00
auto * characterComponent = m_ParentEntity - > GetComponent < CharacterComponent > ( ) ;
2021-12-05 17:54:36 +00:00
if ( characterComponent ! = nullptr ) {
characterComponent - > TrackHealthDelta ( value - m_iHealth ) ;
}
m_iHealth = value ;
}
void DestroyableComponent : : SetMaxHealth ( float value , bool playAnim ) {
m_DirtyHealth = true ;
2022-04-25 00:25:45 +00:00
// Used for playAnim if opted in for.
int32_t difference = static_cast < int32_t > ( std : : abs ( m_fMaxHealth - value ) ) ;
2021-12-05 17:54:36 +00:00
m_fMaxHealth = value ;
if ( m_iHealth > m_fMaxHealth ) {
m_iHealth = m_fMaxHealth ;
}
if ( playAnim ) {
// Now update the player bar
2023-06-09 09:46:01 +00:00
if ( ! m_ParentEntity - > GetParentUser ( ) ) return ;
2021-12-05 17:54:36 +00:00
AMFArrayValue args ;
2023-05-13 22:22:00 +00:00
args . Insert ( " amount " , std : : to_string ( difference ) ) ;
args . Insert ( " type " , " health " ) ;
2022-01-15 19:02:14 +00:00
2023-06-09 09:46:01 +00:00
GameMessages : : SendUIMessageServerToSingleClient ( m_ParentEntity , m_ParentEntity - > GetParentUser ( ) - > GetSystemAddress ( ) , " MaxPlayerBarUpdate " , args ) ;
2021-12-05 17:54:36 +00:00
}
2022-04-25 00:25:45 +00:00
2023-06-09 09:46:01 +00:00
EntityManager : : Instance ( ) - > SerializeEntity ( m_ParentEntity ) ;
2021-12-05 17:54:36 +00:00
}
void DestroyableComponent : : SetArmor ( int32_t value ) {
m_DirtyHealth = true ;
2022-02-05 11:59:07 +00:00
// If Destroyable Component already has zero armor do not trigger the passive ability again.
bool hadArmor = m_iArmor > 0 ;
2022-07-25 02:26:51 +00:00
2023-06-09 09:46:01 +00:00
auto * characterComponent = m_ParentEntity - > GetComponent < CharacterComponent > ( ) ;
2021-12-05 17:54:36 +00:00
if ( characterComponent ! = nullptr ) {
characterComponent - > TrackArmorDelta ( value - m_iArmor ) ;
}
m_iArmor = value ;
2023-06-09 09:46:01 +00:00
auto * inventroyComponent = m_ParentEntity - > GetComponent < InventoryComponent > ( ) ;
2022-02-05 11:59:07 +00:00
if ( m_iArmor = = 0 & & inventroyComponent ! = nullptr & & hadArmor ) {
2021-12-05 17:54:36 +00:00
inventroyComponent - > TriggerPassiveAbility ( PassiveAbilityTrigger : : SentinelArmor ) ;
}
}
void DestroyableComponent : : SetMaxArmor ( float value , bool playAnim ) {
m_DirtyHealth = true ;
m_fMaxArmor = value ;
if ( m_iArmor > m_fMaxArmor ) {
m_iArmor = m_fMaxArmor ;
}
if ( playAnim ) {
// Now update the player bar
2023-06-09 09:46:01 +00:00
if ( ! m_ParentEntity - > GetParentUser ( ) ) return ;
2021-12-05 17:54:36 +00:00
AMFArrayValue args ;
2023-05-13 22:22:00 +00:00
args . Insert ( " amount " , std : : to_string ( value ) ) ;
args . Insert ( " type " , " armor " ) ;
2021-12-05 17:54:36 +00:00
2023-06-09 09:46:01 +00:00
GameMessages : : SendUIMessageServerToSingleClient ( m_ParentEntity , m_ParentEntity - > GetParentUser ( ) - > GetSystemAddress ( ) , " MaxPlayerBarUpdate " , args ) ;
2021-12-05 17:54:36 +00:00
}
2022-04-25 00:25:45 +00:00
2023-06-09 09:46:01 +00:00
EntityManager : : Instance ( ) - > SerializeEntity ( m_ParentEntity ) ;
2021-12-05 17:54:36 +00:00
}
void DestroyableComponent : : SetImagination ( int32_t value ) {
m_DirtyHealth = true ;
2023-06-09 09:46:01 +00:00
auto * characterComponent = m_ParentEntity - > GetComponent < CharacterComponent > ( ) ;
2021-12-05 17:54:36 +00:00
if ( characterComponent ! = nullptr ) {
characterComponent - > TrackImaginationDelta ( value - m_iImagination ) ;
}
m_iImagination = value ;
2023-06-09 09:46:01 +00:00
auto * inventroyComponent = m_ParentEntity - > GetComponent < InventoryComponent > ( ) ;
2021-12-05 17:54:36 +00:00
if ( m_iImagination = = 0 & & inventroyComponent ! = nullptr ) {
inventroyComponent - > TriggerPassiveAbility ( PassiveAbilityTrigger : : AssemblyImagination ) ;
}
}
void DestroyableComponent : : SetMaxImagination ( float value , bool playAnim ) {
m_DirtyHealth = true ;
2022-04-25 00:25:45 +00:00
// Used for playAnim if opted in for.
int32_t difference = static_cast < int32_t > ( std : : abs ( m_fMaxImagination - value ) ) ;
2021-12-05 17:54:36 +00:00
m_fMaxImagination = value ;
if ( m_iImagination > m_fMaxImagination ) {
m_iImagination = m_fMaxImagination ;
}
if ( playAnim ) {
// Now update the player bar
2023-06-09 09:46:01 +00:00
if ( ! m_ParentEntity - > GetParentUser ( ) ) return ;
2021-12-05 17:54:36 +00:00
AMFArrayValue args ;
2023-05-13 22:22:00 +00:00
args . Insert ( " amount " , std : : to_string ( difference ) ) ;
args . Insert ( " type " , " imagination " ) ;
2022-01-15 19:02:14 +00:00
2023-06-09 09:46:01 +00:00
GameMessages : : SendUIMessageServerToSingleClient ( m_ParentEntity , m_ParentEntity - > GetParentUser ( ) - > GetSystemAddress ( ) , " MaxPlayerBarUpdate " , args ) ;
2021-12-05 17:54:36 +00:00
}
2023-06-09 09:46:01 +00:00
EntityManager : : Instance ( ) - > SerializeEntity ( m_ParentEntity ) ;
2021-12-05 17:54:36 +00:00
}
void DestroyableComponent : : SetDamageToAbsorb ( int32_t value ) {
m_DirtyHealth = true ;
m_DamageToAbsorb = value ;
}
2022-01-15 19:02:14 +00:00
void DestroyableComponent : : SetDamageReduction ( int32_t value ) {
2021-12-05 17:54:36 +00:00
m_DirtyHealth = true ;
m_DamageReduction = value ;
}
void DestroyableComponent : : SetIsImmune ( bool value ) {
m_DirtyHealth = true ;
2023-01-07 05:59:19 +00:00
m_ImmuneToBasicAttackCount = value ? 1 : 0 ;
2021-12-05 17:54:36 +00:00
}
2022-01-15 19:02:14 +00:00
void DestroyableComponent : : SetIsGMImmune ( bool value ) {
2021-12-05 17:54:36 +00:00
m_DirtyHealth = true ;
m_IsGMImmune = value ;
}
void DestroyableComponent : : SetIsShielded ( bool value ) {
m_DirtyHealth = true ;
m_IsShielded = value ;
}
void DestroyableComponent : : AddFaction ( const int32_t factionID , const bool ignoreChecks ) {
// Ignore factionID -1
if ( factionID = = - 1 & & ! ignoreChecks ) {
return ;
}
m_FactionIDs . push_back ( factionID ) ;
m_DirtyHealth = true ;
2022-01-13 03:48:27 +00:00
auto query = CDClientDatabase : : CreatePreppedStmt (
" SELECT enemyList FROM Factions WHERE faction = ?; " ) ;
2022-01-15 19:02:14 +00:00
query . bind ( 1 , ( int ) factionID ) ;
2022-01-13 03:48:27 +00:00
auto result = query . execQuery ( ) ;
2021-12-05 17:54:36 +00:00
if ( result . eof ( ) ) return ;
if ( result . fieldIsNull ( 0 ) ) return ;
const auto * list_string = result . getStringField ( 0 ) ;
std : : stringstream ss ( list_string ) ;
std : : string token ;
2022-01-15 19:02:14 +00:00
2021-12-05 17:54:36 +00:00
while ( std : : getline ( ss , token , ' , ' ) ) {
if ( token . empty ( ) ) continue ;
2022-01-15 19:02:14 +00:00
2021-12-05 17:54:36 +00:00
auto id = std : : stoi ( token ) ;
auto exclude = std : : find ( m_FactionIDs . begin ( ) , m_FactionIDs . end ( ) , id ) ! = m_FactionIDs . end ( ) ;
if ( ! exclude ) {
exclude = std : : find ( m_EnemyFactionIDs . begin ( ) , m_EnemyFactionIDs . end ( ) , id ) ! = m_EnemyFactionIDs . end ( ) ;
}
if ( exclude ) {
continue ;
}
2022-01-15 19:02:14 +00:00
2021-12-05 17:54:36 +00:00
AddEnemyFaction ( id ) ;
}
result . finalize ( ) ;
}
bool DestroyableComponent : : IsEnemy ( const Entity * other ) const {
2023-06-09 08:27:05 +00:00
const auto * otherDestroyableComponent = other - > GetComponent < DestroyableComponent > ( ) ;
2021-12-05 17:54:36 +00:00
if ( otherDestroyableComponent ! = nullptr ) {
for ( const auto enemyFaction : m_EnemyFactionIDs ) {
for ( const auto otherFaction : otherDestroyableComponent - > GetFactionIDs ( ) ) {
if ( enemyFaction = = otherFaction )
return true ;
}
}
}
return false ;
}
bool DestroyableComponent : : IsFriend ( const Entity * other ) const {
2023-06-09 08:27:05 +00:00
const auto * otherDestroyableComponent = other - > GetComponent < DestroyableComponent > ( ) ;
2021-12-05 17:54:36 +00:00
if ( otherDestroyableComponent ! = nullptr ) {
for ( const auto enemyFaction : m_EnemyFactionIDs ) {
for ( const auto otherFaction : otherDestroyableComponent - > GetFactionIDs ( ) ) {
if ( enemyFaction = = otherFaction )
return false ;
}
}
return true ;
}
return false ;
}
void DestroyableComponent : : AddEnemyFaction ( int32_t factionID ) {
m_EnemyFactionIDs . push_back ( factionID ) ;
}
void DestroyableComponent : : SetIsSmashable ( bool value ) {
m_DirtyHealth = true ;
m_IsSmashable = value ;
}
void DestroyableComponent : : SetAttacksToBlock ( const uint32_t value ) {
m_AttacksToBlock = value ;
}
bool DestroyableComponent : : IsImmune ( ) const {
2023-01-07 05:59:19 +00:00
return m_IsGMImmune | | m_ImmuneToBasicAttackCount > 0 ;
2021-12-05 17:54:36 +00:00
}
bool DestroyableComponent : : IsKnockbackImmune ( ) const {
2023-06-09 09:46:01 +00:00
auto * characterComponent = m_ParentEntity - > GetComponent < CharacterComponent > ( ) ;
auto * inventoryComponent = m_ParentEntity - > GetComponent < InventoryComponent > ( ) ;
2021-12-05 17:54:36 +00:00
2023-05-02 22:39:21 +00:00
if ( characterComponent ! = nullptr & & inventoryComponent ! = nullptr & & characterComponent - > GetCurrentActivity ( ) = = eGameActivity : : QUICKBUILDING ) {
2021-12-05 17:54:36 +00:00
const auto hasPassive = inventoryComponent - > HasAnyPassive ( {
eItemSetPassiveAbilityID : : EngineerRank2 , eItemSetPassiveAbilityID : : EngineerRank3 ,
eItemSetPassiveAbilityID : : SummonerRank2 , eItemSetPassiveAbilityID : : SummonerRank3 ,
eItemSetPassiveAbilityID : : InventorRank2 , eItemSetPassiveAbilityID : : InventorRank3 ,
} , 5 ) ;
if ( hasPassive ) {
return true ;
}
}
return IsImmune ( ) | | m_IsShielded | | m_AttacksToBlock > 0 ;
}
bool DestroyableComponent : : HasFaction ( int32_t factionID ) const {
return std : : find ( m_FactionIDs . begin ( ) , m_FactionIDs . end ( ) , factionID ) ! = m_FactionIDs . end ( ) ;
}
LWOOBJID DestroyableComponent : : GetKillerID ( ) const {
return m_KillerID ;
}
Entity * DestroyableComponent : : GetKiller ( ) const {
return EntityManager : : Instance ( ) - > GetEntity ( m_KillerID ) ;
}
2022-01-02 20:37:03 +00:00
bool DestroyableComponent : : CheckValidity ( const LWOOBJID target , const bool ignoreFactions , const bool targetEnemy , const bool targetFriend ) const {
2022-01-02 21:01:29 +00:00
auto * targetEntity = EntityManager : : Instance ( ) - > GetEntity ( target ) ;
2021-12-05 17:54:36 +00:00
2022-01-02 21:01:29 +00:00
if ( targetEntity = = nullptr ) {
2022-07-25 02:26:51 +00:00
Game : : logger - > Log ( " DestroyableComponent " , " Invalid entity for checking validity (%llu)! " , target ) ;
2021-12-05 17:54:36 +00:00
return false ;
}
2023-06-09 08:27:05 +00:00
auto * targetDestroyable = targetEntity - > GetComponent < DestroyableComponent > ( ) ;
2021-12-05 17:54:36 +00:00
2022-01-02 21:01:29 +00:00
if ( targetDestroyable = = nullptr ) {
2021-12-05 17:54:36 +00:00
return false ;
}
2023-06-09 22:12:57 +00:00
auto * targetQuickbuild = targetEntity - > GetComponent < QuickBuildComponent > ( ) ;
2021-12-05 17:54:36 +00:00
2022-01-02 21:01:29 +00:00
if ( targetQuickbuild ! = nullptr ) {
const auto state = targetQuickbuild - > GetState ( ) ;
2022-01-15 19:02:14 +00:00
2023-05-02 22:39:21 +00:00
if ( state ! = eRebuildState : : COMPLETED ) {
2021-12-05 17:54:36 +00:00
return false ;
}
}
if ( ignoreFactions ) {
return true ;
}
2022-01-04 18:11:23 +00:00
// Get if the target entity is an enemy and friend
2022-01-02 21:01:29 +00:00
bool isEnemy = IsEnemy ( targetEntity ) ;
2022-01-04 18:11:23 +00:00
bool isFriend = IsFriend ( targetEntity ) ;
2021-12-05 17:54:36 +00:00
2022-01-02 21:01:29 +00:00
// Return true if the target type matches what we are targeting
2022-01-04 18:11:23 +00:00
return ( isEnemy & & targetEnemy ) | | ( isFriend & & targetFriend ) ;
2021-12-05 17:54:36 +00:00
}
void DestroyableComponent : : Heal ( const uint32_t health ) {
auto current = static_cast < uint32_t > ( GetHealth ( ) ) ;
const auto max = static_cast < uint32_t > ( GetMaxHealth ( ) ) ;
current + = health ;
current = std : : min ( current , max ) ;
SetHealth ( current ) ;
2023-06-09 09:46:01 +00:00
EntityManager : : Instance ( ) - > SerializeEntity ( m_ParentEntity ) ;
2021-12-05 17:54:36 +00:00
}
void DestroyableComponent : : Imagine ( const int32_t deltaImagination ) {
auto current = static_cast < int32_t > ( GetImagination ( ) ) ;
const auto max = static_cast < int32_t > ( GetMaxImagination ( ) ) ;
2022-01-15 19:02:14 +00:00
2021-12-05 17:54:36 +00:00
current + = deltaImagination ;
current = std : : min ( current , max ) ;
if ( current < 0 ) {
current = 0 ;
}
SetImagination ( current ) ;
2023-06-09 09:46:01 +00:00
EntityManager : : Instance ( ) - > SerializeEntity ( m_ParentEntity ) ;
2021-12-05 17:54:36 +00:00
}
void DestroyableComponent : : Repair ( const uint32_t armor ) {
auto current = static_cast < uint32_t > ( GetArmor ( ) ) ;
const auto max = static_cast < uint32_t > ( GetMaxArmor ( ) ) ;
current + = armor ;
current = std : : min ( current , max ) ;
SetArmor ( current ) ;
2023-06-09 09:46:01 +00:00
EntityManager : : Instance ( ) - > SerializeEntity ( m_ParentEntity ) ;
2021-12-05 17:54:36 +00:00
}
2022-04-25 10:25:07 +00:00
void DestroyableComponent : : Damage ( uint32_t damage , const LWOOBJID source , uint32_t skillID , bool echo ) {
2021-12-05 17:54:36 +00:00
if ( GetHealth ( ) < = 0 ) {
return ;
}
if ( IsImmune ( ) ) {
return ;
}
if ( m_AttacksToBlock > 0 ) {
m_AttacksToBlock - - ;
return ;
}
// If this entity has damage reduction, reduce the damage to a minimum of 1
if ( m_DamageReduction > 0 & & damage > 0 ) {
if ( damage > m_DamageReduction ) {
damage - = m_DamageReduction ;
} else {
damage = 1 ;
}
}
const auto sourceDamage = damage ;
auto absorb = static_cast < uint32_t > ( GetDamageToAbsorb ( ) ) ;
auto armor = static_cast < uint32_t > ( GetArmor ( ) ) ;
auto health = static_cast < uint32_t > ( GetHealth ( ) ) ;
const auto absorbDamage = std : : min ( damage , absorb ) ;
damage - = absorbDamage ;
absorb - = absorbDamage ;
2022-01-15 19:02:14 +00:00
2021-12-05 17:54:36 +00:00
const auto armorDamage = std : : min ( damage , armor ) ;
damage - = armorDamage ;
armor - = armorDamage ;
health - = std : : min ( damage , health ) ;
SetDamageToAbsorb ( absorb ) ;
SetArmor ( armor ) ;
SetHealth ( health ) ;
SetIsShielded ( absorb > 0 ) ;
2022-09-02 18:49:19 +00:00
// Dismount on the possessable hit
2023-06-09 09:46:01 +00:00
auto * possessable = m_ParentEntity - > GetComponent < PossessableComponent > ( ) ;
2022-09-02 18:49:19 +00:00
if ( possessable & & possessable - > GetDepossessOnHit ( ) ) {
possessable - > Dismount ( ) ;
}
// Dismount on the possessor hit
2023-06-09 09:46:01 +00:00
auto * possessor = m_ParentEntity - > GetComponent < PossessorComponent > ( ) ;
2022-09-02 18:49:19 +00:00
if ( possessor ) {
auto possessableId = possessor - > GetPossessable ( ) ;
if ( possessableId ! = LWOOBJID_EMPTY ) {
auto possessable = EntityManager : : Instance ( ) - > GetEntity ( possessableId ) ;
if ( possessable ) {
possessor - > Dismount ( possessable ) ;
}
}
}
2023-06-09 09:46:01 +00:00
if ( m_ParentEntity - > GetLOT ( ) ! = 1 ) {
2021-12-05 17:54:36 +00:00
echo = true ;
}
if ( echo ) {
2023-06-09 09:46:01 +00:00
EntityManager : : Instance ( ) - > SerializeEntity ( m_ParentEntity ) ;
2021-12-05 17:54:36 +00:00
}
2022-01-15 19:02:14 +00:00
2021-12-05 17:54:36 +00:00
auto * attacker = EntityManager : : Instance ( ) - > GetEntity ( source ) ;
2023-06-09 09:46:01 +00:00
m_ParentEntity - > OnHit ( attacker ) ;
m_ParentEntity - > OnHitOrHealResult ( attacker , sourceDamage ) ;
2022-12-21 22:33:41 +00:00
NotifySubscribers ( attacker , sourceDamage ) ;
2021-12-05 17:54:36 +00:00
for ( const auto & cb : m_OnHitCallbacks ) {
cb ( attacker ) ;
}
if ( health ! = 0 ) {
2023-06-09 09:46:01 +00:00
auto * combatComponent = m_ParentEntity - > GetComponent < BaseCombatAIComponent > ( ) ;
2021-12-05 17:54:36 +00:00
if ( combatComponent ! = nullptr ) {
combatComponent - > Taunt ( source , sourceDamage * 10 ) ; // * 10 is arbatrary
}
return ;
}
2023-01-11 19:08:54 +00:00
//check if hardcore mode is enabled
2023-06-12 08:29:43 +00:00
if ( EntityManager : : Instance ( ) - > GetHardcoreMode ( ) ) {
2023-01-12 19:16:24 +00:00
DoHardcoreModeDrops ( source ) ;
2023-06-12 08:29:43 +00:00
}
2023-01-12 19:16:24 +00:00
2023-01-11 20:50:21 +00:00
Smash ( source , eKillType : : VIOLENT , u " " , skillID ) ;
2021-12-05 17:54:36 +00:00
}
2022-12-21 22:33:41 +00:00
void DestroyableComponent : : Subscribe ( LWOOBJID scriptObjId , CppScripts : : Script * scriptToAdd ) {
m_SubscribedScripts . insert ( std : : make_pair ( scriptObjId , scriptToAdd ) ) ;
2023-06-09 09:46:01 +00:00
Game : : logger - > LogDebug ( " DestroyableComponent " , " Added script %llu to entity %llu " , scriptObjId , m_ParentEntity - > GetObjectID ( ) ) ;
2022-12-21 22:33:41 +00:00
Game : : logger - > LogDebug ( " DestroyableComponent " , " Number of subscribed scripts %i " , m_SubscribedScripts . size ( ) ) ;
}
void DestroyableComponent : : Unsubscribe ( LWOOBJID scriptObjId ) {
auto foundScript = m_SubscribedScripts . find ( scriptObjId ) ;
if ( foundScript ! = m_SubscribedScripts . end ( ) ) {
m_SubscribedScripts . erase ( foundScript ) ;
2023-06-09 09:46:01 +00:00
Game : : logger - > LogDebug ( " DestroyableComponent " , " Removed script %llu from entity %llu " , scriptObjId , m_ParentEntity - > GetObjectID ( ) ) ;
2022-12-21 22:33:41 +00:00
} else {
2023-06-09 09:46:01 +00:00
Game : : logger - > LogDebug ( " DestroyableComponent " , " Tried to remove a script for Entity %llu but script %llu didnt exist " , m_ParentEntity - > GetObjectID ( ) , scriptObjId ) ;
2022-12-21 22:33:41 +00:00
}
Game : : logger - > LogDebug ( " DestroyableComponent " , " Number of subscribed scripts %i " , m_SubscribedScripts . size ( ) ) ;
}
void DestroyableComponent : : NotifySubscribers ( Entity * attacker , uint32_t damage ) {
for ( auto script : m_SubscribedScripts ) {
2023-06-09 09:46:01 +00:00
script . second - > NotifyHitOrHealResult ( m_ParentEntity , attacker , damage ) ;
2022-12-21 22:33:41 +00:00
}
}
2022-04-25 10:25:07 +00:00
void DestroyableComponent : : Smash ( const LWOOBJID source , const eKillType killType , const std : : u16string & deathType , uint32_t skillID ) {
2021-12-05 17:54:36 +00:00
if ( m_iHealth > 0 ) {
SetArmor ( 0 ) ;
SetHealth ( 0 ) ;
2023-06-09 09:46:01 +00:00
EntityManager : : Instance ( ) - > SerializeEntity ( m_ParentEntity ) ;
2021-12-05 17:54:36 +00:00
}
m_KillerID = source ;
auto * owner = EntityManager : : Instance ( ) - > GetEntity ( source ) ;
if ( owner ! = nullptr ) {
owner = owner - > GetOwner ( ) ; // If the owner is overwritten, we collect that here
2022-06-12 03:50:01 +00:00
auto * team = TeamManager : : Instance ( ) - > GetTeam ( owner - > GetObjectID ( ) ) ;
2023-06-12 11:01:45 +00:00
const auto isEnemy = m_ParentEntity - > GetComponent < BaseCombatAIComponent > ( ) ! = nullptr ;
2021-12-05 17:54:36 +00:00
2023-06-09 08:27:05 +00:00
auto * inventoryComponent = owner - > GetComponent < InventoryComponent > ( ) ;
2021-12-05 17:54:36 +00:00
if ( inventoryComponent ! = nullptr & & isEnemy ) {
2023-06-09 09:46:01 +00:00
inventoryComponent - > TriggerPassiveAbility ( PassiveAbilityTrigger : : EnemySmashed , m_ParentEntity ) ;
2021-12-05 17:54:36 +00:00
}
2023-06-09 08:27:05 +00:00
auto * missions = owner - > GetComponent < MissionComponent > ( ) ;
2021-12-05 17:54:36 +00:00
if ( missions ! = nullptr ) {
2023-01-07 05:06:24 +00:00
if ( team ! = nullptr ) {
2021-12-05 17:54:36 +00:00
for ( const auto memberId : team - > members ) {
auto * member = EntityManager : : Instance ( ) - > GetEntity ( memberId ) ;
if ( member = = nullptr ) continue ;
2023-06-09 08:27:05 +00:00
auto * memberMissions = member - > GetComponent < MissionComponent > ( ) ;
2021-12-05 17:54:36 +00:00
if ( memberMissions = = nullptr ) continue ;
2023-06-09 09:46:01 +00:00
memberMissions - > Progress ( eMissionTaskType : : SMASH , m_ParentEntity - > GetLOT ( ) ) ;
memberMissions - > Progress ( eMissionTaskType : : USE_SKILL , m_ParentEntity - > GetLOT ( ) , skillID ) ;
2021-12-05 17:54:36 +00:00
}
} else {
2023-06-09 09:46:01 +00:00
missions - > Progress ( eMissionTaskType : : SMASH , m_ParentEntity - > GetLOT ( ) ) ;
missions - > Progress ( eMissionTaskType : : USE_SKILL , m_ParentEntity - > GetLOT ( ) , skillID ) ;
2021-12-05 17:54:36 +00:00
}
}
}
2022-01-15 19:02:14 +00:00
2023-06-09 09:46:01 +00:00
const auto isPlayer = m_ParentEntity - > IsPlayer ( ) ;
2021-12-05 17:54:36 +00:00
2023-06-09 09:46:01 +00:00
GameMessages : : SendDie ( m_ParentEntity , source , source , true , killType , deathType , 0 , 0 , 0 , isPlayer , false , 1 ) ;
2021-12-05 17:54:36 +00:00
//NANI?!
if ( ! isPlayer ) {
if ( owner ! = nullptr ) {
auto * team = TeamManager : : Instance ( ) - > GetTeam ( owner - > GetObjectID ( ) ) ;
2023-06-09 09:46:01 +00:00
if ( team ! = nullptr & & m_ParentEntity - > GetComponent < BaseCombatAIComponent > ( ) ! = nullptr ) {
2021-12-05 17:54:36 +00:00
LWOOBJID specificOwner = LWOOBJID_EMPTY ;
2023-06-09 09:46:01 +00:00
auto * scriptedActivityComponent = m_ParentEntity - > GetComponent < ScriptedActivityComponent > ( ) ;
2021-12-24 00:25:52 +00:00
uint32_t teamSize = team - > members . size ( ) ;
uint32_t lootMatrixId = GetLootMatrixID ( ) ;
2021-12-05 17:54:36 +00:00
2021-12-24 00:25:52 +00:00
if ( scriptedActivityComponent ) {
lootMatrixId = scriptedActivityComponent - > GetLootMatrixForTeamSize ( teamSize ) ;
2021-12-05 17:54:36 +00:00
}
2021-12-24 00:25:52 +00:00
if ( team - > lootOption = = 0 ) { // Round robin
specificOwner = TeamManager : : Instance ( ) - > GetNextLootOwner ( team ) ;
2021-12-05 17:54:36 +00:00
2021-12-24 00:25:52 +00:00
auto * member = EntityManager : : Instance ( ) - > GetEntity ( specificOwner ) ;
2021-12-05 17:54:36 +00:00
2023-06-09 09:46:01 +00:00
if ( member ) LootGenerator : : Instance ( ) . DropLoot ( member , m_ParentEntity , lootMatrixId , GetMinCoins ( ) , GetMaxCoins ( ) ) ;
2021-12-24 00:25:52 +00:00
} else {
for ( const auto memberId : team - > members ) { // Free for all
auto * member = EntityManager : : Instance ( ) - > GetEntity ( memberId ) ;
if ( member = = nullptr ) continue ;
2021-12-05 17:54:36 +00:00
2023-06-09 09:46:01 +00:00
LootGenerator : : Instance ( ) . DropLoot ( member , m_ParentEntity , lootMatrixId , GetMinCoins ( ) , GetMaxCoins ( ) ) ;
2021-12-24 00:25:52 +00:00
}
2021-12-05 17:54:36 +00:00
}
2021-12-24 00:25:52 +00:00
} else { // drop loot for non team user
2023-06-09 09:46:01 +00:00
LootGenerator : : Instance ( ) . DropLoot ( owner , m_ParentEntity , GetLootMatrixID ( ) , GetMinCoins ( ) , GetMaxCoins ( ) ) ;
2021-12-05 17:54:36 +00:00
}
}
} else {
2022-02-05 12:27:24 +00:00
//Check if this zone allows coin drops
2022-07-25 02:26:51 +00:00
if ( dZoneManager : : Instance ( ) - > GetPlayerLoseCoinOnDeath ( ) ) {
2023-06-09 09:46:01 +00:00
auto * character = m_ParentEntity - > GetCharacter ( ) ;
2022-02-05 12:27:24 +00:00
uint64_t coinsTotal = character - > GetCoins ( ) ;
2023-01-02 00:36:10 +00:00
const uint64_t minCoinsToLose = dZoneManager : : Instance ( ) - > GetWorldConfig ( ) - > coinsLostOnDeathMin ;
if ( coinsTotal > = minCoinsToLose ) {
2023-01-01 12:51:22 +00:00
const uint64_t maxCoinsToLose = dZoneManager : : Instance ( ) - > GetWorldConfig ( ) - > coinsLostOnDeathMax ;
const float coinPercentageToLose = dZoneManager : : Instance ( ) - > GetWorldConfig ( ) - > coinsLostOnDeathPercent ;
2021-12-05 17:54:36 +00:00
2023-01-01 12:51:22 +00:00
uint64_t coinsToLose = std : : max ( static_cast < uint64_t > ( coinsTotal * coinPercentageToLose ) , minCoinsToLose ) ;
coinsToLose = std : : min ( maxCoinsToLose , coinsToLose ) ;
2022-01-15 19:02:14 +00:00
2023-01-01 12:51:22 +00:00
coinsTotal - = coinsToLose ;
2021-12-05 17:54:36 +00:00
2023-06-09 09:46:01 +00:00
LootGenerator : : Instance ( ) . DropLoot ( m_ParentEntity , m_ParentEntity , - 1 , coinsToLose , coinsToLose ) ;
2023-05-02 22:39:21 +00:00
character - > SetCoins ( coinsTotal , eLootSourceType : : PICKUP ) ;
2022-02-05 12:27:24 +00:00
}
}
2021-12-05 17:54:36 +00:00
Entity * zoneControl = EntityManager : : Instance ( ) - > GetZoneControlEntity ( ) ;
for ( CppScripts : : Script * script : CppScripts : : GetEntityScripts ( zoneControl ) ) {
2023-06-09 09:46:01 +00:00
script - > OnPlayerDied ( zoneControl , m_ParentEntity ) ;
2021-12-05 17:54:36 +00:00
}
2023-03-04 07:16:37 +00:00
std : : vector < Entity * > scriptedActs = EntityManager : : Instance ( ) - > GetEntitiesByComponent ( eReplicaComponentType : : SCRIPTED_ACTIVITY ) ;
2021-12-05 17:54:36 +00:00
for ( Entity * scriptEntity : scriptedActs ) {
if ( scriptEntity - > GetObjectID ( ) ! = zoneControl - > GetObjectID ( ) ) { // Don't want to trigger twice on instance worlds
for ( CppScripts : : Script * script : CppScripts : : GetEntityScripts ( scriptEntity ) ) {
2023-06-09 09:46:01 +00:00
script - > OnPlayerDied ( scriptEntity , m_ParentEntity ) ;
2021-12-05 17:54:36 +00:00
}
}
}
}
2023-06-09 09:46:01 +00:00
m_ParentEntity - > Kill ( owner ) ;
2021-12-05 17:54:36 +00:00
}
2022-07-19 21:51:35 +00:00
void DestroyableComponent : : SetFaction ( int32_t factionID , bool ignoreChecks ) {
2021-12-05 17:54:36 +00:00
m_FactionIDs . clear ( ) ;
m_EnemyFactionIDs . clear ( ) ;
2022-07-19 21:51:35 +00:00
AddFaction ( factionID , ignoreChecks ) ;
2021-12-05 17:54:36 +00:00
}
2023-01-07 05:59:19 +00:00
void DestroyableComponent : : SetStatusImmunity (
2023-06-12 08:29:43 +00:00
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 ) {
2023-01-07 05:59:19 +00:00
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 ;
2023-06-12 08:29:43 +00:00
} else if ( state = = eStateChangeType : : PUSH ) {
2023-01-07 05:59:19 +00:00
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 (
2023-06-09 09:46:01 +00:00
m_ParentEntity - > GetObjectID ( ) , state , m_ParentEntity - > GetSystemAddress ( ) ,
2023-01-07 05:59:19 +00:00
bImmuneToBasicAttack ,
bImmuneToDamageOverTime ,
bImmuneToKnockback ,
bImmuneToInterrupt ,
bImmuneToSpeed ,
bImmuneToImaginationGain ,
bImmuneToImaginationLoss ,
bImmuneToQuickbuildInterrupt ,
bImmuneToPullToPoint
) ;
2021-12-05 17:54:36 +00:00
}
2022-01-15 19:02:14 +00:00
void DestroyableComponent : : FixStats ( ) {
2023-06-09 08:28:01 +00:00
auto * entity = GetParentEntity ( ) ;
2021-12-05 17:54:36 +00:00
if ( entity = = nullptr ) return ;
// Reset skill component and buff component
2023-06-09 08:27:05 +00:00
auto * skillComponent = entity - > GetComponent < SkillComponent > ( ) ;
auto * buffComponent = entity - > GetComponent < BuffComponent > ( ) ;
auto * missionComponent = entity - > GetComponent < MissionComponent > ( ) ;
auto * inventoryComponent = entity - > GetComponent < InventoryComponent > ( ) ;
auto * destroyableComponent = entity - > GetComponent < DestroyableComponent > ( ) ;
2021-12-05 17:54:36 +00:00
// If any of the components are nullptr, return
if ( skillComponent = = nullptr | | buffComponent = = nullptr | | missionComponent = = nullptr | | inventoryComponent = = nullptr | | destroyableComponent = = nullptr ) {
return ;
}
// Save the current stats
int32_t currentHealth = destroyableComponent - > GetHealth ( ) ;
int32_t currentArmor = destroyableComponent - > GetArmor ( ) ;
int32_t currentImagination = destroyableComponent - > GetImagination ( ) ;
// Unequip all items
auto equipped = inventoryComponent - > GetEquippedItems ( ) ;
for ( auto & equippedItem : equipped ) {
// Get the item with the item ID
auto * item = inventoryComponent - > FindItemById ( equippedItem . second . id ) ;
if ( item = = nullptr ) {
continue ;
}
// Unequip the item
item - > UnEquip ( ) ;
}
// Base stats
int32_t maxHealth = 4 ;
int32_t maxArmor = 0 ;
int32_t maxImagination = 0 ;
// Go through all completed missions and add the reward stats
for ( auto & pair : missionComponent - > GetMissions ( ) ) {
auto * mission = pair . second ;
if ( ! mission - > IsComplete ( ) ) {
continue ;
}
// Add the stats
const auto & info = mission - > GetClientInfo ( ) ;
2022-01-15 19:02:14 +00:00
2021-12-05 17:54:36 +00:00
maxHealth + = info . reward_maxhealth ;
maxImagination + = info . reward_maximagination ;
}
// Set the base stats
destroyableComponent - > SetMaxHealth ( maxHealth ) ;
destroyableComponent - > SetMaxArmor ( maxArmor ) ;
destroyableComponent - > SetMaxImagination ( maxImagination ) ;
// Re-apply all buffs
buffComponent - > ReApplyBuffs ( ) ;
// Requip all items
for ( auto & equippedItem : equipped ) {
// Get the item with the item ID
auto * item = inventoryComponent - > FindItemById ( equippedItem . second . id ) ;
if ( item = = nullptr ) {
continue ;
}
// Equip the item
item - > Equip ( ) ;
}
// Fetch correct max stats after everything is done
maxHealth = destroyableComponent - > GetMaxHealth ( ) ;
maxArmor = destroyableComponent - > GetMaxArmor ( ) ;
maxImagination = destroyableComponent - > GetMaxImagination ( ) ;
// If any of the current stats are more than their max, set them to the max
if ( currentHealth > maxHealth ) currentHealth = maxHealth ;
if ( currentArmor > maxArmor ) currentArmor = maxArmor ;
if ( currentImagination > maxImagination ) currentImagination = maxImagination ;
// Restore current stats
destroyableComponent - > SetHealth ( currentHealth ) ;
destroyableComponent - > SetArmor ( currentArmor ) ;
destroyableComponent - > SetImagination ( currentImagination ) ;
// Serialize the entity
EntityManager : : Instance ( ) - > SerializeEntity ( entity ) ;
}
void DestroyableComponent : : AddOnHitCallback ( const std : : function < void ( Entity * ) > & callback ) {
m_OnHitCallbacks . push_back ( callback ) ;
}
2023-01-12 19:16:24 +00:00
2023-06-12 08:29:43 +00:00
void DestroyableComponent : : DoHardcoreModeDrops ( const LWOOBJID source ) {
2023-01-12 19:16:24 +00:00
//check if this is a player:
2023-06-09 09:46:01 +00:00
if ( m_ParentEntity - > IsPlayer ( ) ) {
2023-01-12 19:16:24 +00:00
//remove hardcore_lose_uscore_on_death_percent from the player's uscore:
2023-06-09 09:46:01 +00:00
auto * character = m_ParentEntity - > GetComponent < CharacterComponent > ( ) ;
2023-01-12 19:16:24 +00:00
auto uscore = character - > GetUScore ( ) ;
auto uscoreToLose = uscore * ( EntityManager : : Instance ( ) - > GetHardcoreLoseUscoreOnDeathPercent ( ) / 100 ) ;
character - > SetUScore ( uscore - uscoreToLose ) ;
2023-06-09 09:46:01 +00:00
GameMessages : : SendModifyLEGOScore ( m_ParentEntity , m_ParentEntity - > GetSystemAddress ( ) , - uscoreToLose , eLootSourceType : : MISSION ) ;
2023-01-12 19:16:24 +00:00
if ( EntityManager : : Instance ( ) - > GetHardcoreDropinventoryOnDeath ( ) ) {
//drop all items from inventory:
2023-06-09 09:46:01 +00:00
auto * inventory = m_ParentEntity - > GetComponent < InventoryComponent > ( ) ;
2023-01-12 19:16:24 +00:00
if ( inventory ) {
//get the items inventory:
auto items = inventory - > GetInventory ( eInventoryType : : ITEMS ) ;
2023-06-12 08:29:43 +00:00
if ( items ) {
2023-01-12 19:16:24 +00:00
auto itemMap = items - > GetItems ( ) ;
2023-06-12 08:29:43 +00:00
if ( ! itemMap . empty ( ) ) {
2023-01-12 19:16:24 +00:00
for ( const auto & item : itemMap ) {
//drop the item:
if ( ! item . second ) continue ;
// don't drop the thinkng cap
if ( item . second - > GetLot ( ) = = 6086 ) continue ;
2023-06-09 09:46:01 +00:00
GameMessages : : SendDropClientLoot ( m_ParentEntity , source , item . second - > GetLot ( ) , 0 , m_ParentEntity - > GetPosition ( ) , item . second - > GetCount ( ) ) ;
2023-01-12 19:16:24 +00:00
item . second - > SetCount ( 0 , false , false ) ;
}
2023-06-09 09:46:01 +00:00
EntityManager : : Instance ( ) - > SerializeEntity ( m_ParentEntity ) ;
2023-01-12 19:16:24 +00:00
}
}
}
}
//get character:
2023-06-09 09:46:01 +00:00
auto * chars = m_ParentEntity - > GetCharacter ( ) ;
2023-01-12 19:16:24 +00:00
if ( chars ) {
auto coins = chars - > GetCoins ( ) ;
//lose all coins:
2023-05-02 22:39:21 +00:00
chars - > SetCoins ( 0 , eLootSourceType : : NONE ) ;
2023-01-12 19:16:24 +00:00
//drop all coins:
2023-06-09 09:46:01 +00:00
GameMessages : : SendDropClientLoot ( m_ParentEntity , source , LOT_NULL , coins , m_ParentEntity - > GetPosition ( ) ) ;
2023-01-12 19:16:24 +00:00
}
// Reload the player since we can't normally reduce uscore from the server and we want the UI to update
// do this last so we don't get killed.... again
2023-06-09 09:46:01 +00:00
EntityManager : : Instance ( ) - > DestructEntity ( m_ParentEntity ) ;
EntityManager : : Instance ( ) - > ConstructEntity ( m_ParentEntity ) ;
2023-01-12 19:16:24 +00:00
return ;
}
//award the player some u-score:
auto * player = EntityManager : : Instance ( ) - > GetEntity ( source ) ;
if ( player & & player - > IsPlayer ( ) ) {
2023-06-09 08:27:05 +00:00
auto * playerStats = player - > GetComponent < CharacterComponent > ( ) ;
2023-01-12 19:16:24 +00:00
if ( playerStats ) {
//get the maximum health from this enemy:
auto maxHealth = GetMaxHealth ( ) ;
int uscore = maxHealth * EntityManager : : Instance ( ) - > GetHardcoreUscoreEnemiesMultiplier ( ) ;
playerStats - > SetUScore ( playerStats - > GetUScore ( ) + uscore ) ;
2023-05-02 22:39:21 +00:00
GameMessages : : SendModifyLEGOScore ( player , player - > GetSystemAddress ( ) , uscore , eLootSourceType : : MISSION ) ;
2023-01-12 19:16:24 +00:00
2023-06-09 09:46:01 +00:00
EntityManager : : Instance ( ) - > SerializeEntity ( m_ParentEntity ) ;
2023-01-12 19:16:24 +00:00
}
}
}