2021-12-05 17:54:36 +00:00
# include "dCommonVars.h"
# include "Entity.h"
# include "CDClientManager.h"
# include "Game.h"
2023-10-21 23:31:55 +00:00
# include "Logger.h"
2021-12-05 17:54:36 +00:00
# include <PacketUtils.h>
# include <functional>
# include "CDDestructibleComponentTable.h"
# include "CDClientDatabase.h"
# include <sstream>
# include "dServer.h"
# include "GameMessages.h"
# include "EntityManager.h"
# include "dZoneManager.h"
# include "Zone.h"
# include "Spawner.h"
# include "UserManager.h"
# include "dpWorld.h"
# include "Player.h"
2023-01-07 05:17:05 +00:00
# include "LUTriggers.h"
# include "User.h"
# include "EntityTimer.h"
# include "EntityCallbackTimer.h"
# include "Loot.h"
2023-01-22 23:38:47 +00:00
# include "eMissionTaskType.h"
2023-02-10 08:29:53 +00:00
# include "eTriggerEventType.h"
2023-04-25 18:17:40 +00:00
# include "eObjectBits.h"
2021-12-05 17:54:36 +00:00
//Component includes:
# include "Component.h"
# include "ControllablePhysicsComponent.h"
# include "RenderComponent.h"
2023-08-18 19:14:40 +00:00
# include "MultiZoneEntranceComponent.h"
2021-12-05 17:54:36 +00:00
# include "CharacterComponent.h"
# include "DestroyableComponent.h"
# include "BuffComponent.h"
# include "BouncerComponent.h"
# include "InventoryComponent.h"
2022-07-24 18:04:02 +00:00
# include "LevelProgressionComponent.h"
2022-07-24 18:25:10 +00:00
# include "PlayerForcedMovementComponent.h"
2021-12-05 17:54:36 +00:00
# include "ScriptComponent.h"
# include "SkillComponent.h"
# include "SimplePhysicsComponent.h"
# include "SwitchComponent.h"
# include "PhantomPhysicsComponent.h"
# include "RigidbodyPhantomPhysicsComponent.h"
# include "MovingPlatformComponent.h"
# include "MissionComponent.h"
# include "MissionOfferComponent.h"
# include "RebuildComponent.h"
# include "BuildBorderComponent.h"
# include "MovementAIComponent.h"
# include "VendorComponent.h"
2023-08-04 02:44:03 +00:00
# include "DonationVendorComponent.h"
2021-12-05 17:54:36 +00:00
# include "RocketLaunchpadControlComponent.h"
# include "PropertyComponent.h"
# include "BaseCombatAIComponent.h"
# include "PropertyManagementComponent.h"
# include "PropertyVendorComponent.h"
# include "ProximityMonitorComponent.h"
# include "PropertyEntranceComponent.h"
# include "ModelComponent.h"
# include "ZCompression.h"
# include "PetComponent.h"
2023-12-04 15:20:41 +00:00
# include "HavokVehiclePhysicsComponent.h"
2021-12-05 17:54:36 +00:00
# include "PossessableComponent.h"
# include "PossessorComponent.h"
# include "ModuleAssemblyComponent.h"
# include "RacingControlComponent.h"
# include "SoundTriggerComponent.h"
# include "ShootingGalleryComponent.h"
# include "RailActivatorComponent.h"
# include "LUPExhibitComponent.h"
2023-08-06 20:38:12 +00:00
# include "RacingSoundTriggerComponent.h"
2023-02-10 08:29:53 +00:00
# include "TriggerComponent.h"
2023-03-24 23:16:45 +00:00
# include "eGameMasterLevel.h"
2023-03-04 07:16:37 +00:00
# include "eReplicaComponentType.h"
2023-05-02 22:39:21 +00:00
# include "eReplicaPacketType.h"
2023-12-05 02:59:08 +00:00
# include "MiniGameControlComponent.h"
2023-10-23 01:08:49 +00:00
# include "RacingStatsComponent.h"
# include "CollectibleComponent.h"
# include "ItemComponent.h"
2021-12-05 17:54:36 +00:00
2023-03-17 14:36:21 +00:00
// Table includes
# include "CDComponentsRegistryTable.h"
# include "CDCurrencyTableTable.h"
# include "CDMovementAIComponentTable.h"
# include "CDProximityMonitorComponentTable.h"
# include "CDRebuildComponentTable.h"
# include "CDObjectSkillsTable.h"
# include "CDObjectsTable.h"
# include "CDScriptComponentTable.h"
# include "CDSkillBehaviorTable.h"
# include "CDZoneTableTable.h"
2021-12-05 17:54:36 +00:00
Entity : : Entity ( const LWOOBJID & objectID , EntityInfo info , Entity * parentEntity ) {
m_ObjectID = objectID ;
m_TemplateID = info . lot ;
m_ParentEntity = parentEntity ;
m_Character = nullptr ;
2023-03-24 23:16:45 +00:00
m_GMLevel = eGameMasterLevel : : CIVILIAN ;
2021-12-05 17:54:36 +00:00
m_NetworkID = 0 ;
m_Groups = { } ;
m_OwnerOverride = LWOOBJID_EMPTY ;
m_Timers = { } ;
m_ChildEntities = { } ;
m_ScheduleKiller = nullptr ;
m_TargetsInPhantom = { } ;
m_Components = { } ;
m_DieCallbacks = { } ;
m_PhantomCollisionCallbacks = { } ;
2022-06-16 05:58:38 +00:00
m_IsParentChildDirty = true ;
2021-12-05 17:54:36 +00:00
m_Settings = info . settings ;
m_NetworkSettings = info . networkSettings ;
m_DefaultPosition = info . pos ;
m_DefaultRotation = info . rot ;
m_Scale = info . scale ;
m_Spawner = info . spawner ;
m_SpawnerID = info . spawnerID ;
2022-07-28 13:39:57 +00:00
m_HasSpawnerNodeID = info . hasSpawnerNodeID ;
m_SpawnerNodeID = info . spawnerNodeID ;
2021-12-05 17:54:36 +00:00
if ( info . lot ! = 1 ) m_PlayerIsReadyForUpdates = true ;
}
Entity : : ~ Entity ( ) {
if ( m_Character ) {
m_Character - > SaveXMLToDatabase ( ) ;
}
CancelAllTimers ( ) ;
CancelCallbackTimers ( ) ;
const auto components = m_Components ;
2022-07-28 13:39:57 +00:00
2021-12-05 17:54:36 +00:00
for ( const auto & pair : components ) {
delete pair . second ;
m_Components . erase ( pair . first ) ;
}
2022-07-17 04:39:13 +00:00
for ( auto child : m_ChildEntities ) {
if ( child ) child - > RemoveParent ( ) ;
}
2022-06-17 00:50:33 +00:00
if ( m_ParentEntity ) {
m_ParentEntity - > RemoveChild ( this ) ;
}
2021-12-05 17:54:36 +00:00
}
2022-07-28 13:39:57 +00:00
void Entity : : Initialize ( ) {
2021-12-05 17:54:36 +00:00
/**
* Setup trigger
*/
2023-02-10 08:29:53 +00:00
const auto triggerInfo = GetVarAsString ( u " trigger_id " ) ;
2021-12-05 17:54:36 +00:00
2023-10-23 01:08:49 +00:00
if ( ! triggerInfo . empty ( ) ) AddComponent < TriggerComponent > ( triggerInfo ) ;
2021-12-05 17:54:36 +00:00
/**
* Setup groups
*/
const auto groupIDs = GetVarAsString ( u " groupID " ) ;
if ( ! groupIDs . empty ( ) ) {
m_Groups = GeneralUtils : : SplitString ( groupIDs , ' ; ' ) ;
2023-12-23 17:50:14 +00:00
if ( ! m_Groups . empty ( ) ) {
if ( m_Groups . back ( ) . empty ( ) ) m_Groups . erase ( m_Groups . end ( ) - 1 ) ;
}
2021-12-05 17:54:36 +00:00
}
/**
* Set ourselves as a child of our parent
*/
if ( m_ParentEntity ! = nullptr ) {
m_ParentEntity - > AddChild ( this ) ;
}
// Get the registry table
2023-03-17 14:36:21 +00:00
CDComponentsRegistryTable * compRegistryTable = CDClientManager : : Instance ( ) . GetTable < CDComponentsRegistryTable > ( ) ;
2021-12-05 17:54:36 +00:00
/**
* Special case for BBB models . They have components not corresponding to the registry .
*/
if ( m_TemplateID = = 14 ) {
2023-03-04 07:16:37 +00:00
const auto simplePhysicsComponentID = compRegistryTable - > GetByIDAndType ( m_TemplateID , eReplicaComponentType : : SIMPLE_PHYSICS ) ;
2021-12-05 17:54:36 +00:00
2023-10-23 01:08:49 +00:00
AddComponent < SimplePhysicsComponent > ( simplePhysicsComponentID ) ;
2021-12-05 17:54:36 +00:00
2023-10-23 01:08:49 +00:00
AddComponent < ModelComponent > ( ) ;
2021-12-05 17:54:36 +00:00
2023-10-23 01:08:49 +00:00
AddComponent < RenderComponent > ( ) ;
2021-12-05 17:54:36 +00:00
2023-10-23 01:08:49 +00:00
auto * destroyableComponent = AddComponent < DestroyableComponent > ( ) ;
2022-07-19 21:51:35 +00:00
destroyableComponent - > SetHealth ( 1 ) ;
destroyableComponent - > SetMaxHealth ( 1.0f ) ;
destroyableComponent - > SetFaction ( - 1 , true ) ;
destroyableComponent - > SetIsSmashable ( true ) ;
2021-12-05 17:54:36 +00:00
// We have all our components.
2022-07-28 13:39:57 +00:00
return ;
2021-12-05 17:54:36 +00:00
}
/**
* Go through all the components and check if this entity has them .
2022-07-28 13:39:57 +00:00
*
2021-12-05 17:54:36 +00:00
* Not all components are implemented . Some are represented by a nullptr , as they hold no data .
*/
if ( GetParentUser ( ) ) {
2023-10-23 01:08:49 +00:00
AddComponent < MissionComponent > ( ) - > LoadFromXml ( m_Character - > GetXMLDoc ( ) ) ;
2021-12-05 17:54:36 +00:00
}
2023-03-04 07:16:37 +00:00
uint32_t petComponentId = compRegistryTable - > GetByIDAndType ( m_TemplateID , eReplicaComponentType : : PET ) ;
2021-12-05 17:54:36 +00:00
if ( petComponentId > 0 ) {
2023-10-23 01:08:49 +00:00
AddComponent < PetComponent > ( petComponentId ) ;
2021-12-05 17:54:36 +00:00
}
2023-12-05 02:59:08 +00:00
if ( compRegistryTable - > GetByIDAndType ( m_TemplateID , eReplicaComponentType : : MINI_GAME_CONTROL ) > 0 ) {
AddComponent < MiniGameControlComponent > ( ) ;
2021-12-05 17:54:36 +00:00
}
2023-03-04 07:16:37 +00:00
uint32_t possessableComponentId = compRegistryTable - > GetByIDAndType ( m_TemplateID , eReplicaComponentType : : POSSESSABLE ) ;
2022-07-09 03:25:15 +00:00
if ( possessableComponentId > 0 ) {
2023-10-23 01:08:49 +00:00
AddComponent < PossessableComponent > ( possessableComponentId ) ;
2021-12-05 17:54:36 +00:00
}
2023-03-04 07:16:37 +00:00
if ( compRegistryTable - > GetByIDAndType ( m_TemplateID , eReplicaComponentType : : MODULE_ASSEMBLY ) > 0 ) {
2023-10-23 01:08:49 +00:00
AddComponent < ModuleAssemblyComponent > ( ) ;
2021-12-05 17:54:36 +00:00
}
2023-03-04 07:16:37 +00:00
if ( compRegistryTable - > GetByIDAndType ( m_TemplateID , eReplicaComponentType : : RACING_STATS ) > 0 ) {
2023-10-23 01:08:49 +00:00
AddComponent < RacingStatsComponent > ( ) ;
2021-12-05 17:54:36 +00:00
}
2023-03-04 07:16:37 +00:00
if ( compRegistryTable - > GetByIDAndType ( m_TemplateID , eReplicaComponentType : : LUP_EXHIBIT , - 1 ) > = 0 ) {
2023-10-23 01:08:49 +00:00
AddComponent < LUPExhibitComponent > ( ) ;
2021-12-05 17:54:36 +00:00
}
2023-03-04 07:16:37 +00:00
if ( compRegistryTable - > GetByIDAndType ( m_TemplateID , eReplicaComponentType : : RACING_CONTROL ) > 0 ) {
2023-10-23 01:08:49 +00:00
AddComponent < RacingControlComponent > ( ) ;
2021-12-05 17:54:36 +00:00
}
2023-03-04 07:16:37 +00:00
const auto propertyEntranceComponentID = compRegistryTable - > GetByIDAndType ( m_TemplateID , eReplicaComponentType : : PROPERTY_ENTRANCE ) ;
2021-12-05 17:54:36 +00:00
if ( propertyEntranceComponentID > 0 ) {
2023-10-23 01:08:49 +00:00
AddComponent < PropertyEntranceComponent > ( propertyEntranceComponentID ) ;
2021-12-05 17:54:36 +00:00
}
2023-03-04 07:16:37 +00:00
if ( compRegistryTable - > GetByIDAndType ( m_TemplateID , eReplicaComponentType : : CONTROLLABLE_PHYSICS ) > 0 ) {
2023-10-23 01:08:49 +00:00
auto * controllablePhysics = AddComponent < ControllablePhysicsComponent > ( ) ;
2021-12-05 17:54:36 +00:00
if ( m_Character ) {
2022-07-25 02:03:22 +00:00
controllablePhysics - > LoadFromXml ( m_Character - > GetXMLDoc ( ) ) ;
2021-12-05 17:54:36 +00:00
const auto mapID = Game : : server - > GetZoneID ( ) ;
//If we came from another zone, put us in the starting loc
if ( m_Character - > GetZoneID ( ) ! = Game : : server - > GetZoneID ( ) | | mapID = = 1603 ) { // Exception for Moon Base as you tend to spawn on the roof.
NiPoint3 pos ;
NiQuaternion rot ;
const auto & targetSceneName = m_Character - > GetTargetScene ( ) ;
2023-07-15 20:56:33 +00:00
auto * targetScene = Game : : entityManager - > GetSpawnPointEntity ( targetSceneName ) ;
2021-12-05 17:54:36 +00:00
if ( m_Character - > HasBeenToWorld ( mapID ) & & targetSceneName . empty ( ) ) {
pos = m_Character - > GetRespawnPoint ( mapID ) ;
2023-07-17 22:55:33 +00:00
rot = Game : : zoneManager - > GetZone ( ) - > GetSpawnRot ( ) ;
2022-07-28 13:39:57 +00:00
} else if ( targetScene ! = nullptr ) {
2021-12-05 17:54:36 +00:00
pos = targetScene - > GetPosition ( ) ;
rot = targetScene - > GetRotation ( ) ;
2022-07-28 13:39:57 +00:00
} else {
2023-07-17 22:55:33 +00:00
pos = Game : : zoneManager - > GetZone ( ) - > GetSpawnPos ( ) ;
rot = Game : : zoneManager - > GetZone ( ) - > GetSpawnRot ( ) ;
2021-12-05 17:54:36 +00:00
}
controllablePhysics - > SetPosition ( pos ) ;
controllablePhysics - > SetRotation ( rot ) ;
}
2022-07-28 13:39:57 +00:00
} else {
2021-12-05 17:54:36 +00:00
controllablePhysics - > SetPosition ( m_DefaultPosition ) ;
controllablePhysics - > SetRotation ( m_DefaultRotation ) ;
}
}
// If an entity is marked a phantom, simple physics is made into phantom phyics.
bool markedAsPhantom = GetVar < bool > ( u " markedAsPhantom " ) ;
2023-03-04 07:16:37 +00:00
const auto simplePhysicsComponentID = compRegistryTable - > GetByIDAndType ( m_TemplateID , eReplicaComponentType : : SIMPLE_PHYSICS ) ;
2021-12-05 17:54:36 +00:00
if ( ! markedAsPhantom & & simplePhysicsComponentID > 0 ) {
2023-10-23 01:08:49 +00:00
AddComponent < SimplePhysicsComponent > ( simplePhysicsComponentID ) ;
2021-12-05 17:54:36 +00:00
}
2023-03-04 07:16:37 +00:00
if ( compRegistryTable - > GetByIDAndType ( m_TemplateID , eReplicaComponentType : : RIGID_BODY_PHANTOM_PHYSICS ) > 0 ) {
2023-10-23 01:08:49 +00:00
AddComponent < RigidbodyPhantomPhysicsComponent > ( ) ;
2021-12-05 17:54:36 +00:00
}
2023-03-04 07:16:37 +00:00
if ( markedAsPhantom | | compRegistryTable - > GetByIDAndType ( m_TemplateID , eReplicaComponentType : : PHANTOM_PHYSICS ) > 0 ) {
2023-10-23 01:08:49 +00:00
AddComponent < PhantomPhysicsComponent > ( ) - > SetPhysicsEffectActive ( false ) ;
2021-12-05 17:54:36 +00:00
}
2023-12-04 15:20:41 +00:00
if ( compRegistryTable - > GetByIDAndType ( m_TemplateID , eReplicaComponentType : : HAVOK_VEHICLE_PHYSICS ) > 0 ) {
auto * havokVehiclePhysicsComponent = AddComponent < HavokVehiclePhysicsComponent > ( ) ;
havokVehiclePhysicsComponent - > SetPosition ( m_DefaultPosition ) ;
havokVehiclePhysicsComponent - > SetRotation ( m_DefaultRotation ) ;
2021-12-05 17:54:36 +00:00
}
2022-07-28 13:39:57 +00:00
2023-03-04 07:16:37 +00:00
if ( compRegistryTable - > GetByIDAndType ( m_TemplateID , eReplicaComponentType : : SOUND_TRIGGER , - 1 ) ! = - 1 ) {
2023-10-23 01:08:49 +00:00
AddComponent < SoundTriggerComponent > ( ) ;
2023-08-06 20:38:12 +00:00
} else if ( compRegistryTable - > GetByIDAndType ( m_TemplateID , eReplicaComponentType : : RACING_SOUND_TRIGGER , - 1 ) ! = - 1 ) {
2023-10-23 01:08:49 +00:00
AddComponent < RacingSoundTriggerComponent > ( ) ;
2021-12-05 17:54:36 +00:00
}
2023-03-04 07:16:37 +00:00
if ( compRegistryTable - > GetByIDAndType ( m_TemplateID , eReplicaComponentType : : BUFF ) > 0 ) {
2023-10-23 01:08:49 +00:00
AddComponent < BuffComponent > ( ) ;
2021-12-05 17:54:36 +00:00
}
2023-03-04 07:16:37 +00:00
int collectibleComponentID = compRegistryTable - > GetByIDAndType ( m_TemplateID , eReplicaComponentType : : COLLECTIBLE ) ;
2021-12-05 17:54:36 +00:00
2022-07-28 13:39:57 +00:00
if ( collectibleComponentID > 0 ) {
2023-10-23 01:08:49 +00:00
AddComponent < CollectibleComponent > ( GetVarAs < int32_t > ( u " collectible_id " ) ) ;
2021-12-05 17:54:36 +00:00
}
/**
2022-02-05 11:28:17 +00:00
* Multiple components require the destructible component .
2021-12-05 17:54:36 +00:00
*/
2023-03-04 07:16:37 +00:00
int buffComponentID = compRegistryTable - > GetByIDAndType ( m_TemplateID , eReplicaComponentType : : BUFF ) ;
int rebuildComponentID = compRegistryTable - > GetByIDAndType ( m_TemplateID , eReplicaComponentType : : QUICK_BUILD ) ;
2021-12-05 17:54:36 +00:00
2023-10-19 17:42:43 +00:00
int componentID = - 1 ;
2021-12-05 17:54:36 +00:00
if ( collectibleComponentID > 0 ) componentID = collectibleComponentID ;
if ( rebuildComponentID > 0 ) componentID = rebuildComponentID ;
if ( buffComponentID > 0 ) componentID = buffComponentID ;
2023-03-17 14:36:21 +00:00
CDDestructibleComponentTable * destCompTable = CDClientManager : : Instance ( ) . GetTable < CDDestructibleComponentTable > ( ) ;
2021-12-05 17:54:36 +00:00
std : : vector < CDDestructibleComponent > destCompData = destCompTable - > Query ( [ = ] ( CDDestructibleComponent entry ) { return ( entry . id = = componentID ) ; } ) ;
2023-12-24 00:11:00 +00:00
2023-10-19 17:42:43 +00:00
bool isSmashable = GetVarAs < int32_t > ( u " is_smashable " ) ! = 0 ;
if ( buffComponentID > 0 | | collectibleComponentID > 0 | | isSmashable ) {
2023-10-23 01:08:49 +00:00
DestroyableComponent * comp = AddComponent < DestroyableComponent > ( ) ;
2021-12-05 17:54:36 +00:00
if ( m_Character ) {
2022-07-25 02:03:22 +00:00
comp - > LoadFromXml ( m_Character - > GetXMLDoc ( ) ) ;
2022-07-28 13:39:57 +00:00
} else {
2021-12-05 17:54:36 +00:00
if ( componentID > 0 ) {
std : : vector < CDDestructibleComponent > destCompData = destCompTable - > Query ( [ = ] ( CDDestructibleComponent entry ) { return ( entry . id = = componentID ) ; } ) ;
if ( destCompData . size ( ) > 0 ) {
2023-03-04 07:16:37 +00:00
if ( HasComponent ( eReplicaComponentType : : RACING_STATS ) ) {
2021-12-05 17:54:36 +00:00
destCompData [ 0 ] . imagination = 60 ;
}
comp - > SetHealth ( destCompData [ 0 ] . life ) ;
comp - > SetImagination ( destCompData [ 0 ] . imagination ) ;
comp - > SetArmor ( destCompData [ 0 ] . armor ) ;
comp - > SetMaxHealth ( destCompData [ 0 ] . life ) ;
comp - > SetMaxImagination ( destCompData [ 0 ] . imagination ) ;
comp - > SetMaxArmor ( destCompData [ 0 ] . armor ) ;
2023-10-18 14:17:57 +00:00
comp - > SetDeathBehavior ( destCompData [ 0 ] . death_behavior ) ;
2021-12-05 17:54:36 +00:00
comp - > SetIsSmashable ( destCompData [ 0 ] . isSmashable ) ;
comp - > SetLootMatrixID ( destCompData [ 0 ] . LootMatrixIndex ) ;
2023-10-09 20:33:22 +00:00
Loot : : CacheMatrix ( destCompData [ 0 ] . LootMatrixIndex ) ;
2021-12-05 17:54:36 +00:00
// Now get currency information
uint32_t npcMinLevel = destCompData [ 0 ] . level ;
uint32_t currencyIndex = destCompData [ 0 ] . CurrencyIndex ;
2023-03-17 14:36:21 +00:00
CDCurrencyTableTable * currencyTable = CDClientManager : : Instance ( ) . GetTable < CDCurrencyTableTable > ( ) ;
2021-12-05 17:54:36 +00:00
std : : vector < CDCurrencyTable > currencyValues = currencyTable - > Query ( [ = ] ( CDCurrencyTable entry ) { return ( entry . currencyIndex = = currencyIndex & & entry . npcminlevel = = npcMinLevel ) ; } ) ;
if ( currencyValues . size ( ) > 0 ) {
// Set the coins
comp - > SetMinCoins ( currencyValues [ 0 ] . minvalue ) ;
comp - > SetMaxCoins ( currencyValues [ 0 ] . maxvalue ) ;
}
2023-06-14 22:44:22 +00:00
// extraInfo overrides. Client ORs the database smashable and the luz smashable.
2023-10-19 17:42:43 +00:00
comp - > SetIsSmashable ( comp - > GetIsSmashable ( ) | isSmashable ) ;
2021-12-05 17:54:36 +00:00
}
2022-07-28 13:39:57 +00:00
} else {
2021-12-05 17:54:36 +00:00
comp - > SetHealth ( 1 ) ;
comp - > SetArmor ( 0 ) ;
comp - > SetMaxHealth ( 1 ) ;
comp - > SetMaxArmor ( 0 ) ;
comp - > SetIsSmashable ( true ) ;
comp - > AddFaction ( - 1 ) ;
comp - > AddFaction ( 6 ) ; //Smashables
// A race car has 60 imagination, other entities defaults to 0.
2023-03-04 07:16:37 +00:00
comp - > SetImagination ( HasComponent ( eReplicaComponentType : : RACING_STATS ) ? 60 : 0 ) ;
comp - > SetMaxImagination ( HasComponent ( eReplicaComponentType : : RACING_STATS ) ? 60 : 0 ) ;
2021-12-05 17:54:36 +00:00
}
}
if ( destCompData . size ( ) > 0 ) {
comp - > AddFaction ( destCompData [ 0 ] . faction ) ;
std : : stringstream ss ( destCompData [ 0 ] . factionList ) ;
std : : string token ;
while ( std : : getline ( ss , token , ' , ' ) ) {
if ( std : : stoi ( token ) = = destCompData [ 0 ] . faction ) continue ;
if ( token ! = " " ) {
comp - > AddFaction ( std : : stoi ( token ) ) ;
}
}
}
2023-10-19 17:42:43 +00:00
// override the factions if needed.
auto setFaction = GetVarAsString ( u " set_faction " ) ;
if ( ! setFaction . empty ( ) ) {
// TODO also split on space here however we do not have a general util for splitting on multiple characters yet.
std : : vector < std : : string > factionsToAdd = GeneralUtils : : SplitString ( setFaction , ' ; ' ) ;
int32_t factionToAdd ;
for ( const auto faction : factionsToAdd ) {
if ( GeneralUtils : : TryParse ( faction , factionToAdd ) ) {
comp - > AddFaction ( factionToAdd , true ) ;
}
}
}
2021-12-05 17:54:36 +00:00
}
2023-03-04 07:16:37 +00:00
if ( compRegistryTable - > GetByIDAndType ( m_TemplateID , eReplicaComponentType : : CHARACTER ) > 0 | | m_Character ) {
2022-07-24 18:25:10 +00:00
// Character Component always has a possessor, level, and forced movement components
2023-10-23 01:08:49 +00:00
AddComponent < PossessorComponent > ( ) ;
2022-07-24 18:04:02 +00:00
// load in the xml for the level
2023-10-23 01:08:49 +00:00
AddComponent < LevelProgressionComponent > ( ) - > LoadFromXml ( m_Character - > GetXMLDoc ( ) ) ;
2022-07-24 18:04:02 +00:00
2023-10-23 01:08:49 +00:00
AddComponent < PlayerForcedMovementComponent > ( ) ;
2022-07-24 18:25:10 +00:00
2023-10-23 01:08:49 +00:00
AddComponent < CharacterComponent > ( m_Character ) - > LoadFromXml ( m_Character - > GetXMLDoc ( ) ) ;
2021-12-05 17:54:36 +00:00
}
2023-03-04 07:16:37 +00:00
if ( compRegistryTable - > GetByIDAndType ( m_TemplateID , eReplicaComponentType : : INVENTORY ) > 0 | | m_Character ) {
2023-10-23 01:08:49 +00:00
auto * xmlDoc = m_Character ? m_Character - > GetXMLDoc ( ) : nullptr ;
AddComponent < InventoryComponent > ( xmlDoc ) ;
2021-12-05 17:54:36 +00:00
}
2022-05-03 20:05:29 +00:00
// if this component exists, then we initialize it. it's value is always 0
2023-08-18 19:14:40 +00:00
if ( compRegistryTable - > GetByIDAndType ( m_TemplateID , eReplicaComponentType : : MULTI_ZONE_ENTRANCE , - 1 ) ! = - 1 ) {
2023-10-23 01:08:49 +00:00
AddComponent < MultiZoneEntranceComponent > ( ) ;
2021-12-05 17:54:36 +00:00
}
/**
* This is a bit of a mess
*/
2023-03-17 14:36:21 +00:00
CDScriptComponentTable * scriptCompTable = CDClientManager : : Instance ( ) . GetTable < CDScriptComponentTable > ( ) ;
2023-03-04 07:16:37 +00:00
int32_t scriptComponentID = compRegistryTable - > GetByIDAndType ( m_TemplateID , eReplicaComponentType : : SCRIPT , - 1 ) ;
2021-12-05 17:54:36 +00:00
std : : string scriptName = " " ;
bool client = false ;
if ( scriptComponentID > 0 | | m_Character ) {
std : : string clientScriptName ;
if ( ! m_Character ) {
CDScriptComponent scriptCompData = scriptCompTable - > GetByID ( scriptComponentID ) ;
scriptName = scriptCompData . script_name ;
clientScriptName = scriptCompData . client_script_name ;
2022-07-28 13:39:57 +00:00
} else {
2021-12-05 17:54:36 +00:00
scriptName = " " ;
}
if ( scriptName ! = " " | | ( scriptName = = " " & & m_Character ) ) {
2022-07-28 13:39:57 +00:00
} else if ( clientScriptName ! = " " ) {
2021-12-05 17:54:36 +00:00
client = true ;
2022-07-28 13:39:57 +00:00
} else if ( ! m_Character ) {
2021-12-05 17:54:36 +00:00
client = true ;
}
}
std : : string customScriptServer ;
bool hasCustomServerScript = false ;
const auto customScriptServerName = GetVarAsString ( u " custom_script_server " ) ;
const auto customScriptClientName = GetVarAsString ( u " custom_script_client " ) ;
if ( ! customScriptServerName . empty ( ) ) {
customScriptServer = customScriptServerName ;
hasCustomServerScript = true ;
}
if ( ! customScriptClientName . empty ( ) ) {
client = true ;
}
if ( hasCustomServerScript & & scriptName . empty ( ) ) {
scriptName = customScriptServer ;
}
2022-11-27 12:03:30 +00:00
if ( ! scriptName . empty ( ) | | client | | m_Character | | scriptComponentID > = 0 ) {
2023-10-23 01:08:49 +00:00
AddComponent < ScriptComponent > ( scriptName , true , client & & scriptName . empty ( ) ) ;
2021-12-05 17:54:36 +00:00
}
// ZoneControl script
if ( m_TemplateID = = 2365 ) {
2023-03-17 14:36:21 +00:00
CDZoneTableTable * zoneTable = CDClientManager : : Instance ( ) . GetTable < CDZoneTableTable > ( ) ;
2023-07-17 22:55:33 +00:00
const auto zoneID = Game : : zoneManager - > GetZoneID ( ) ;
2021-12-05 17:54:36 +00:00
const CDZoneTable * zoneData = zoneTable - > Query ( zoneID . GetMapID ( ) ) ;
2022-07-28 13:39:57 +00:00
if ( zoneData ! = nullptr ) {
2021-12-05 17:54:36 +00:00
int zoneScriptID = zoneData - > scriptID ;
CDScriptComponent zoneScriptData = scriptCompTable - > GetByID ( zoneScriptID ) ;
2023-10-23 01:08:49 +00:00
AddComponent < ScriptComponent > ( zoneScriptData . script_name , true ) ;
2021-12-05 17:54:36 +00:00
}
}
2023-03-04 07:16:37 +00:00
if ( compRegistryTable - > GetByIDAndType ( m_TemplateID , eReplicaComponentType : : SKILL , - 1 ) ! = - 1 | | m_Character ) {
2023-10-23 01:08:49 +00:00
AddComponent < SkillComponent > ( ) ;
2021-12-05 17:54:36 +00:00
}
2023-03-04 07:16:37 +00:00
const auto combatAiId = compRegistryTable - > GetByIDAndType ( m_TemplateID , eReplicaComponentType : : BASE_COMBAT_AI ) ;
2021-12-05 17:54:36 +00:00
if ( combatAiId > 0 ) {
2023-10-23 01:08:49 +00:00
AddComponent < BaseCombatAIComponent > ( combatAiId ) ;
2021-12-05 17:54:36 +00:00
}
2023-03-04 07:16:37 +00:00
if ( int componentID = compRegistryTable - > GetByIDAndType ( m_TemplateID , eReplicaComponentType : : QUICK_BUILD ) > 0 ) {
2023-10-23 01:08:49 +00:00
auto * rebuildComponent = AddComponent < RebuildComponent > ( ) ;
2021-12-05 17:54:36 +00:00
2023-03-17 14:36:21 +00:00
CDRebuildComponentTable * rebCompTable = CDClientManager : : Instance ( ) . GetTable < CDRebuildComponentTable > ( ) ;
2021-12-05 17:54:36 +00:00
std : : vector < CDRebuildComponent > rebCompData = rebCompTable - > Query ( [ = ] ( CDRebuildComponent entry ) { return ( entry . id = = rebuildComponentID ) ; } ) ;
if ( rebCompData . size ( ) > 0 ) {
2023-10-23 01:08:49 +00:00
rebuildComponent - > SetResetTime ( rebCompData [ 0 ] . reset_time ) ;
rebuildComponent - > SetCompleteTime ( rebCompData [ 0 ] . complete_time ) ;
rebuildComponent - > SetTakeImagination ( rebCompData [ 0 ] . take_imagination ) ;
rebuildComponent - > SetInterruptible ( rebCompData [ 0 ] . interruptible ) ;
rebuildComponent - > SetSelfActivator ( rebCompData [ 0 ] . self_activator ) ;
rebuildComponent - > SetActivityId ( rebCompData [ 0 ] . activityID ) ;
rebuildComponent - > SetPostImaginationCost ( rebCompData [ 0 ] . post_imagination_cost ) ;
rebuildComponent - > SetTimeBeforeSmash ( rebCompData [ 0 ] . time_before_smash ) ;
2021-12-05 17:54:36 +00:00
const auto rebuildResetTime = GetVar < float > ( u " rebuild_reset_time " ) ;
if ( rebuildResetTime ! = 0.0f ) {
2023-10-23 01:08:49 +00:00
rebuildComponent - > SetResetTime ( rebuildResetTime ) ;
2021-12-05 17:54:36 +00:00
2023-10-23 01:08:49 +00:00
// Known bug with moving platform in FV that casues it to build at the end instead of the start.
// This extends the smash time so players can ride up the lift.
2023-12-24 00:11:00 +00:00
if ( m_TemplateID = = 9483 ) {
2023-10-23 01:08:49 +00:00
rebuildComponent - > SetResetTime ( rebuildComponent - > GetResetTime ( ) + 25 ) ;
2021-12-05 17:54:36 +00:00
}
}
const auto activityID = GetVar < int32_t > ( u " activityID " ) ;
if ( activityID > 0 ) {
2023-10-23 01:08:49 +00:00
rebuildComponent - > SetActivityId ( activityID ) ;
2023-10-09 20:33:22 +00:00
Loot : : CacheMatrix ( activityID ) ;
2021-12-05 17:54:36 +00:00
}
2023-11-26 04:50:20 +00:00
const auto timeBeforeSmash = GetVar < float > ( u " tmeSmsh " ) ;
if ( timeBeforeSmash > 0 ) {
rebuildComponent - > SetTimeBeforeSmash ( timeBeforeSmash ) ;
}
2021-12-05 17:54:36 +00:00
const auto compTime = GetVar < float > ( u " compTime " ) ;
if ( compTime > 0 ) {
2023-10-23 01:08:49 +00:00
rebuildComponent - > SetCompleteTime ( compTime ) ;
2021-12-05 17:54:36 +00:00
}
}
}
2023-03-04 07:16:37 +00:00
if ( compRegistryTable - > GetByIDAndType ( m_TemplateID , eReplicaComponentType : : SWITCH , - 1 ) ! = - 1 ) {
2023-10-23 01:08:49 +00:00
AddComponent < SwitchComponent > ( ) ;
2021-12-05 17:54:36 +00:00
}
2023-03-04 07:16:37 +00:00
if ( ( compRegistryTable - > GetByIDAndType ( m_TemplateID , eReplicaComponentType : : VENDOR ) > 0 ) ) {
2023-10-23 01:08:49 +00:00
AddComponent < VendorComponent > ( ) ;
2023-08-04 02:44:03 +00:00
} else if ( ( compRegistryTable - > GetByIDAndType ( m_TemplateID , eReplicaComponentType : : DONATION_VENDOR , - 1 ) ! = - 1 ) ) {
2023-10-23 01:08:49 +00:00
AddComponent < DonationVendorComponent > ( ) ;
2021-12-05 17:54:36 +00:00
}
2023-03-04 07:16:37 +00:00
if ( compRegistryTable - > GetByIDAndType ( m_TemplateID , eReplicaComponentType : : PROPERTY_VENDOR , - 1 ) ! = - 1 ) {
2023-10-23 01:08:49 +00:00
AddComponent < PropertyVendorComponent > ( ) ;
2021-12-05 17:54:36 +00:00
}
2023-03-04 07:16:37 +00:00
if ( compRegistryTable - > GetByIDAndType ( m_TemplateID , eReplicaComponentType : : PROPERTY_MANAGEMENT , - 1 ) ! = - 1 ) {
2023-10-23 01:08:49 +00:00
AddComponent < PropertyManagementComponent > ( ) ;
2021-12-05 17:54:36 +00:00
}
2023-03-04 07:16:37 +00:00
if ( compRegistryTable - > GetByIDAndType ( m_TemplateID , eReplicaComponentType : : BOUNCER , - 1 ) ! = - 1 ) { // you have to determine it like this because all bouncers have a componentID of 0
2023-10-23 01:08:49 +00:00
AddComponent < BouncerComponent > ( ) ;
2021-12-05 17:54:36 +00:00
}
2023-03-26 10:09:04 +00:00
int32_t renderComponentId = compRegistryTable - > GetByIDAndType ( m_TemplateID , eReplicaComponentType : : RENDER ) ;
if ( ( renderComponentId > 0 & & m_TemplateID ! = 2365 ) | | m_Character ) {
2023-10-23 01:08:49 +00:00
AddComponent < RenderComponent > ( renderComponentId ) ;
2021-12-05 17:54:36 +00:00
}
2023-03-04 07:16:37 +00:00
if ( ( compRegistryTable - > GetByIDAndType ( m_TemplateID , eReplicaComponentType : : MISSION_OFFER ) > 0 ) | | m_Character ) {
2023-10-23 01:08:49 +00:00
AddComponent < MissionOfferComponent > ( m_TemplateID ) ;
2021-12-05 17:54:36 +00:00
}
2023-03-04 07:16:37 +00:00
if ( compRegistryTable - > GetByIDAndType ( m_TemplateID , eReplicaComponentType : : BUILD_BORDER , - 1 ) ! = - 1 ) {
2023-10-23 01:08:49 +00:00
AddComponent < BuildBorderComponent > ( ) ;
2021-12-05 17:54:36 +00:00
}
// Scripted activity component
2023-03-04 07:16:37 +00:00
int scriptedActivityID = compRegistryTable - > GetByIDAndType ( m_TemplateID , eReplicaComponentType : : SCRIPTED_ACTIVITY ) ;
2021-12-05 17:54:36 +00:00
if ( ( scriptedActivityID > 0 ) ) {
2023-10-23 01:08:49 +00:00
AddComponent < ScriptedActivityComponent > ( scriptedActivityID ) ;
2021-12-05 17:54:36 +00:00
}
2023-03-04 07:16:37 +00:00
if ( compRegistryTable - > GetByIDAndType ( m_TemplateID , eReplicaComponentType : : MODEL , - 1 ) ! = - 1 & & ! GetComponent < PetComponent > ( ) ) {
2023-10-23 01:08:49 +00:00
AddComponent < ModelComponent > ( ) ;
if ( ! HasComponent ( eReplicaComponentType : : DESTROYABLE ) ) {
auto * destroyableComponent = AddComponent < DestroyableComponent > ( ) ;
2022-07-19 21:51:35 +00:00
destroyableComponent - > SetHealth ( 1 ) ;
destroyableComponent - > SetMaxHealth ( 1.0f ) ;
destroyableComponent - > SetFaction ( - 1 , true ) ;
destroyableComponent - > SetIsSmashable ( true ) ;
}
2022-07-28 13:39:57 +00:00
}
2022-07-19 21:51:35 +00:00
PetComponent * petComponent ;
2023-03-04 07:16:37 +00:00
if ( compRegistryTable - > GetByIDAndType ( m_TemplateID , eReplicaComponentType : : ITEM ) > 0 & & ! TryGetComponent ( eReplicaComponentType : : PET , petComponent ) & & ! HasComponent ( eReplicaComponentType : : MODEL ) ) {
2023-10-23 01:08:49 +00:00
AddComponent < ItemComponent > ( ) ;
2022-07-19 21:51:35 +00:00
}
2021-12-05 17:54:36 +00:00
// Shooting gallery component
2023-03-04 07:16:37 +00:00
if ( compRegistryTable - > GetByIDAndType ( m_TemplateID , eReplicaComponentType : : SHOOTING_GALLERY ) > 0 ) {
2023-10-23 01:08:49 +00:00
AddComponent < ShootingGalleryComponent > ( ) ;
2022-07-28 13:39:57 +00:00
}
2021-12-05 17:54:36 +00:00
2023-03-04 07:16:37 +00:00
if ( compRegistryTable - > GetByIDAndType ( m_TemplateID , eReplicaComponentType : : PROPERTY , - 1 ) ! = - 1 ) {
2023-10-23 01:08:49 +00:00
AddComponent < PropertyComponent > ( ) ;
2021-12-05 17:54:36 +00:00
}
2023-03-04 07:16:37 +00:00
const int rocketId = compRegistryTable - > GetByIDAndType ( m_TemplateID , eReplicaComponentType : : ROCKET_LAUNCH ) ;
2021-12-05 17:54:36 +00:00
if ( ( rocketId > 0 ) ) {
2023-10-23 01:08:49 +00:00
AddComponent < RocketLaunchpadControlComponent > ( rocketId ) ;
2021-12-05 17:54:36 +00:00
}
2023-03-04 07:16:37 +00:00
const int32_t railComponentID = compRegistryTable - > GetByIDAndType ( m_TemplateID , eReplicaComponentType : : RAIL_ACTIVATOR ) ;
2021-12-05 17:54:36 +00:00
if ( railComponentID > 0 ) {
2023-10-23 01:08:49 +00:00
AddComponent < RailActivatorComponent > ( railComponentID ) ;
2021-12-05 17:54:36 +00:00
}
2023-03-04 07:16:37 +00:00
int movementAIID = compRegistryTable - > GetByIDAndType ( m_TemplateID , eReplicaComponentType : : MOVEMENT_AI ) ;
2021-12-05 17:54:36 +00:00
if ( movementAIID > 0 ) {
2023-03-17 14:36:21 +00:00
CDMovementAIComponentTable * moveAITable = CDClientManager : : Instance ( ) . GetTable < CDMovementAIComponentTable > ( ) ;
2021-12-05 17:54:36 +00:00
std : : vector < CDMovementAIComponent > moveAIComp = moveAITable - > Query ( [ = ] ( CDMovementAIComponent entry ) { return ( entry . id = = movementAIID ) ; } ) ;
if ( moveAIComp . size ( ) > 0 ) {
MovementAIInfo moveInfo = MovementAIInfo ( ) ;
moveInfo . movementType = moveAIComp [ 0 ] . MovementType ;
moveInfo . wanderChance = moveAIComp [ 0 ] . WanderChance ;
moveInfo . wanderRadius = moveAIComp [ 0 ] . WanderRadius ;
moveInfo . wanderSpeed = moveAIComp [ 0 ] . WanderSpeed ;
moveInfo . wanderDelayMax = moveAIComp [ 0 ] . WanderDelayMax ;
moveInfo . wanderDelayMin = moveAIComp [ 0 ] . WanderDelayMin ;
bool useWanderDB = GetVar < bool > ( u " usewanderdb " ) ;
if ( ! useWanderDB ) {
const auto wanderOverride = GetVarAs < float > ( u " wanderRadius " ) ;
if ( wanderOverride ! = 0.0f ) {
moveInfo . wanderRadius = wanderOverride ;
}
}
2023-10-23 01:08:49 +00:00
AddComponent < MovementAIComponent > ( moveInfo ) ;
2021-12-05 17:54:36 +00:00
}
2022-07-28 13:39:57 +00:00
} else if ( petComponentId > 0 | | combatAiId > 0 & & GetComponent < BaseCombatAIComponent > ( ) - > GetTetherSpeed ( ) > 0 ) {
2021-12-05 17:54:36 +00:00
MovementAIInfo moveInfo = MovementAIInfo ( ) ;
moveInfo . movementType = " " ;
moveInfo . wanderChance = 0 ;
moveInfo . wanderRadius = 16 ;
moveInfo . wanderSpeed = 2.5f ;
moveInfo . wanderDelayMax = 5 ;
moveInfo . wanderDelayMin = 2 ;
2023-10-23 01:08:49 +00:00
AddComponent < MovementAIComponent > ( moveInfo ) ;
2021-12-05 17:54:36 +00:00
}
2022-11-12 14:44:27 +00:00
std : : string pathName = GetVarAsString ( u " attached_path " ) ;
2023-07-17 22:55:33 +00:00
const Path * path = Game : : zoneManager - > GetZone ( ) - > GetPath ( pathName ) ;
2022-11-12 14:44:27 +00:00
//Check to see if we have an attached path and add the appropiate component to handle it:
2023-10-17 13:45:46 +00:00
if ( path ) {
2022-11-12 14:44:27 +00:00
// if we have a moving platform path, then we need a moving platform component
if ( path - > pathType = = PathType : : MovingPlatform ) {
2023-10-23 01:08:49 +00:00
AddComponent < MovingPlatformComponent > ( pathName ) ;
2023-10-17 13:45:46 +00:00
// else if we are a movement path
2022-11-12 14:44:27 +00:00
} /*else if (path->pathType == PathType::Movement) {
auto movementAIcomp = GetComponent < MovementAIComponent > ( ) ;
if ( movementAIcomp ) {
// TODO: set path in existing movementAIComp
} else {
// TODO: create movementAIcomp and set path
}
} */
2023-05-13 20:47:28 +00:00
} else {
// else we still need to setup moving platform if it has a moving platform comp but no path
int32_t movingPlatformComponentId = compRegistryTable - > GetByIDAndType ( m_TemplateID , eReplicaComponentType : : MOVING_PLATFORM , - 1 ) ;
if ( movingPlatformComponentId > = 0 ) {
2023-10-23 01:08:49 +00:00
AddComponent < MovingPlatformComponent > ( pathName ) ;
2023-05-13 20:47:28 +00:00
}
2022-11-12 14:44:27 +00:00
}
2023-03-04 07:16:37 +00:00
int proximityMonitorID = compRegistryTable - > GetByIDAndType ( m_TemplateID , eReplicaComponentType : : PROXIMITY_MONITOR ) ;
2021-12-05 17:54:36 +00:00
if ( proximityMonitorID > 0 ) {
2023-03-17 14:36:21 +00:00
CDProximityMonitorComponentTable * proxCompTable = CDClientManager : : Instance ( ) . GetTable < CDProximityMonitorComponentTable > ( ) ;
2021-12-05 17:54:36 +00:00
std : : vector < CDProximityMonitorComponent > proxCompData = proxCompTable - > Query ( [ = ] ( CDProximityMonitorComponent entry ) { return ( entry . id = = proximityMonitorID ) ; } ) ;
if ( proxCompData . size ( ) > 0 ) {
std : : vector < std : : string > proximityStr = GeneralUtils : : SplitString ( proxCompData [ 0 ] . Proximities , ' , ' ) ;
2023-10-23 01:08:49 +00:00
AddComponent < ProximityMonitorComponent > ( std : : stoi ( proximityStr [ 0 ] ) , std : : stoi ( proximityStr [ 1 ] ) ) ;
2021-12-05 17:54:36 +00:00
}
}
// Hacky way to trigger these when the object has had a chance to get constructed
AddCallbackTimer ( 0 , [ this ] ( ) {
for ( CppScripts : : Script * script : CppScripts : : GetEntityScripts ( this ) ) {
script - > OnStartup ( this ) ;
}
2022-07-28 13:39:57 +00:00
} ) ;
2021-12-05 17:54:36 +00:00
2023-07-15 20:56:33 +00:00
if ( ! m_Character & & Game : : entityManager - > GetGhostingEnabled ( ) ) {
2021-12-05 17:54:36 +00:00
// Don't ghost what is likely large scene elements
2023-04-17 19:19:26 +00:00
if ( HasComponent ( eReplicaComponentType : : SIMPLE_PHYSICS ) & & HasComponent ( eReplicaComponentType : : RENDER ) & & ( m_Components . size ( ) = = 2 | | ( HasComponent ( eReplicaComponentType : : TRIGGER ) & & m_Components . size ( ) = = 3 ) ) ) {
2021-12-05 17:54:36 +00:00
goto no_ghosting ;
}
/* Filter for ghosting candidates.
2022-07-28 13:39:57 +00:00
*
2021-12-05 17:54:36 +00:00
* Don ' t ghost moving platforms , until we ' ve got proper syncing for those .
* Don ' t ghost big phantom physics triggers , as putting those to sleep might prevent interactions .
* Don ' t ghost property related objects , as the client expects those to always be loaded .
*/
if (
! EntityManager : : IsExcludedFromGhosting ( GetLOT ( ) ) & &
2023-03-04 07:16:37 +00:00
! HasComponent ( eReplicaComponentType : : SCRIPTED_ACTIVITY ) & &
! HasComponent ( eReplicaComponentType : : MOVING_PLATFORM ) & &
! HasComponent ( eReplicaComponentType : : PHANTOM_PHYSICS ) & &
! HasComponent ( eReplicaComponentType : : PROPERTY ) & &
! HasComponent ( eReplicaComponentType : : RACING_CONTROL ) & &
2023-12-04 15:20:41 +00:00
! HasComponent ( eReplicaComponentType : : HAVOK_VEHICLE_PHYSICS )
2022-07-28 13:39:57 +00:00
)
2023-03-04 07:16:37 +00:00
//if (HasComponent(eReplicaComponentType::BASE_COMBAT_AI))
2021-12-05 17:54:36 +00:00
{
m_IsGhostingCandidate = true ;
}
2022-07-28 13:39:57 +00:00
if ( GetLOT ( ) = = 6368 ) {
2021-12-05 17:54:36 +00:00
m_IsGhostingCandidate = true ;
}
// Special case for collectibles in Ninjago
2023-03-04 07:16:37 +00:00
if ( HasComponent ( eReplicaComponentType : : COLLECTIBLE ) & & Game : : server - > GetZoneID ( ) = = 2000 ) {
2021-12-05 17:54:36 +00:00
m_IsGhostingCandidate = true ;
}
}
2022-07-28 13:39:57 +00:00
no_ghosting :
2021-12-05 17:54:36 +00:00
2023-03-25 10:26:39 +00:00
TriggerEvent ( eTriggerEventType : : CREATE , this ) ;
2021-12-05 17:54:36 +00:00
if ( m_Character ) {
auto * controllablePhysicsComponent = GetComponent < ControllablePhysicsComponent > ( ) ;
2022-07-24 18:04:02 +00:00
auto * levelComponent = GetComponent < LevelProgressionComponent > ( ) ;
2021-12-05 17:54:36 +00:00
2022-12-19 19:45:50 +00:00
if ( controllablePhysicsComponent & & levelComponent ) {
controllablePhysicsComponent - > SetSpeedMultiplier ( levelComponent - > GetSpeedBase ( ) / 500.0f ) ;
2021-12-05 17:54:36 +00:00
}
}
}
bool Entity : : operator = = ( const Entity & other ) const {
return other . m_ObjectID = = m_ObjectID ;
}
bool Entity : : operator ! = ( const Entity & other ) const {
return other . m_ObjectID ! = m_ObjectID ;
}
2022-07-28 13:39:57 +00:00
User * Entity : : GetParentUser ( ) const {
if ( ! IsPlayer ( ) ) {
2021-12-05 17:54:36 +00:00
return nullptr ;
}
return static_cast < const Player * > ( this ) - > GetParentUser ( ) ;
}
2023-03-04 07:16:37 +00:00
Component * Entity : : GetComponent ( eReplicaComponentType componentID ) const {
2021-12-05 17:54:36 +00:00
const auto & index = m_Components . find ( componentID ) ;
2022-07-28 13:39:57 +00:00
if ( index = = m_Components . end ( ) ) {
2021-12-05 17:54:36 +00:00
return nullptr ;
}
2022-07-28 13:39:57 +00:00
2021-12-05 17:54:36 +00:00
return index - > second ;
}
2023-03-04 07:16:37 +00:00
bool Entity : : HasComponent ( const eReplicaComponentType componentId ) const {
2021-12-05 17:54:36 +00:00
return m_Components . find ( componentId ) ! = m_Components . end ( ) ;
}
std : : vector < ScriptComponent * > Entity : : GetScriptComponents ( ) {
std : : vector < ScriptComponent * > comps ;
2023-03-04 07:16:37 +00:00
for ( std : : pair < eReplicaComponentType , void * > p : m_Components ) {
if ( p . first = = eReplicaComponentType : : SCRIPT ) {
2021-12-05 17:54:36 +00:00
comps . push_back ( static_cast < ScriptComponent * > ( p . second ) ) ;
}
}
2022-07-28 13:39:57 +00:00
2021-12-05 17:54:36 +00:00
return comps ;
}
2022-12-21 22:33:41 +00:00
void Entity : : Subscribe ( LWOOBJID scriptObjId , CppScripts : : Script * scriptToAdd , const std : : string & notificationName ) {
if ( notificationName = = " HitOrHealResult " | | notificationName = = " Hit " ) {
auto * destroyableComponent = GetComponent < DestroyableComponent > ( ) ;
if ( ! destroyableComponent ) return ;
destroyableComponent - > Subscribe ( scriptObjId , scriptToAdd ) ;
}
}
void Entity : : Unsubscribe ( LWOOBJID scriptObjId , const std : : string & notificationName ) {
if ( notificationName = = " HitOrHealResult " | | notificationName = = " Hit " ) {
auto * destroyableComponent = GetComponent < DestroyableComponent > ( ) ;
if ( ! destroyableComponent ) return ;
destroyableComponent - > Unsubscribe ( scriptObjId ) ;
}
}
2021-12-05 17:54:36 +00:00
void Entity : : SetProximityRadius ( float proxRadius , std : : string name ) {
2023-10-23 17:24:17 +00:00
auto * proxMon = GetComponent < ProximityMonitorComponent > ( ) ;
if ( ! proxMon ) proxMon = AddComponent < ProximityMonitorComponent > ( ) ;
2021-12-05 17:54:36 +00:00
proxMon - > SetProximityRadius ( proxRadius , name ) ;
}
void Entity : : SetProximityRadius ( dpEntity * entity , std : : string name ) {
2023-10-23 01:08:49 +00:00
ProximityMonitorComponent * proxMon = AddComponent < ProximityMonitorComponent > ( ) ;
2021-12-05 17:54:36 +00:00
proxMon - > SetProximityRadius ( entity , name ) ;
}
2023-03-24 23:16:45 +00:00
void Entity : : SetGMLevel ( eGameMasterLevel value ) {
2021-12-05 17:54:36 +00:00
m_GMLevel = value ;
if ( GetParentUser ( ) ) {
Character * character = GetParentUser ( ) - > GetLastUsedChar ( ) ;
if ( character ) {
character - > SetGMLevel ( value ) ;
}
}
CharacterComponent * character = GetComponent < CharacterComponent > ( ) ;
if ( character ) character - > SetGMLevel ( value ) ;
GameMessages : : SendGMLevelBroadcast ( m_ObjectID , value ) ;
}
void Entity : : WriteBaseReplicaData ( RakNet : : BitStream * outBitStream , eReplicaPacketType packetType ) {
2023-05-02 22:39:21 +00:00
if ( packetType = = eReplicaPacketType : : CONSTRUCTION ) {
2021-12-05 17:54:36 +00:00
outBitStream - > Write ( m_ObjectID ) ;
outBitStream - > Write ( m_TemplateID ) ;
if ( IsPlayer ( ) ) {
std : : string name = m_Character ! = nullptr ? m_Character - > GetName ( ) : " Invalid " ;
outBitStream - > Write < uint8_t > ( uint8_t ( name . size ( ) ) ) ;
for ( size_t i = 0 ; i < name . size ( ) ; + + i ) {
outBitStream - > Write < uint16_t > ( name [ i ] ) ;
}
2022-07-28 13:39:57 +00:00
} else {
2021-12-05 17:54:36 +00:00
const auto & name = GetVar < std : : string > ( u " npcName " ) ;
outBitStream - > Write < uint8_t > ( uint8_t ( name . size ( ) ) ) ;
for ( size_t i = 0 ; i < name . size ( ) ; + + i ) {
outBitStream - > Write < uint16_t > ( name [ i ] ) ;
}
}
outBitStream - > Write < uint32_t > ( 0 ) ; //Time since created on server
const auto & syncLDF = GetVar < std : : vector < std : : u16string > > ( u " syncLDF " ) ;
2022-07-19 21:51:35 +00:00
// Only sync for models.
if ( m_Settings . size ( ) > 0 & & ( GetComponent < ModelComponent > ( ) & & ! GetComponent < PetComponent > ( ) ) ) {
2021-12-05 17:54:36 +00:00
outBitStream - > Write1 ( ) ; //ldf data
2022-07-28 13:39:57 +00:00
2021-12-05 17:54:36 +00:00
RakNet : : BitStream settingStream ;
2023-10-17 13:45:46 +00:00
int32_t numberOfValidKeys = m_Settings . size ( ) ;
2021-12-05 17:54:36 +00:00
2023-10-17 13:45:46 +00:00
// Writing keys value pairs the client does not expect to receive or interpret will result in undefined behavior,
// so we need to filter out any keys that are not valid and fix the number of valid keys to be correct.
// TODO should make this more efficient so that we dont waste loops evaluating the same condition twice
2021-12-05 17:54:36 +00:00
for ( LDFBaseData * data : m_Settings ) {
2023-10-17 13:45:46 +00:00
if ( ! data | | data - > GetValueType ( ) = = eLDFType : : LDF_TYPE_UNKNOWN ) {
numberOfValidKeys - - ;
}
}
settingStream . Write < uint32_t > ( numberOfValidKeys ) ;
for ( LDFBaseData * data : m_Settings ) {
if ( data & & data - > GetValueType ( ) ! = eLDFType : : LDF_TYPE_UNKNOWN ) {
2021-12-05 17:54:36 +00:00
data - > WriteToPacket ( & settingStream ) ;
}
}
outBitStream - > Write ( settingStream . GetNumberOfBytesUsed ( ) + 1 ) ;
outBitStream - > Write < uint8_t > ( 0 ) ; //no compression used
outBitStream - > Write ( settingStream ) ;
2022-07-28 13:39:57 +00:00
} else if ( ! syncLDF . empty ( ) ) {
2021-12-05 17:54:36 +00:00
std : : vector < LDFBaseData * > ldfData ;
for ( const auto & data : syncLDF ) {
ldfData . push_back ( GetVarData ( data ) ) ;
}
outBitStream - > Write1 ( ) ; //ldf data
RakNet : : BitStream settingStream ;
settingStream . Write < uint32_t > ( ldfData . size ( ) ) ;
for ( LDFBaseData * data : ldfData ) {
if ( data ) {
data - > WriteToPacket ( & settingStream ) ;
}
}
outBitStream - > Write ( settingStream . GetNumberOfBytesUsed ( ) + 1 ) ;
outBitStream - > Write < uint8_t > ( 0 ) ; //no compression used
outBitStream - > Write ( settingStream ) ;
2022-07-28 13:39:57 +00:00
} else {
outBitStream - > Write0 ( ) ; //No ldf data
2021-12-05 17:54:36 +00:00
}
2023-02-10 08:29:53 +00:00
TriggerComponent * triggerComponent ;
2023-03-04 07:16:37 +00:00
if ( TryGetComponent ( eReplicaComponentType : : TRIGGER , triggerComponent ) ) {
2023-02-10 08:29:53 +00:00
// has trigger component, check to see if we have events to handle
auto * trigger = triggerComponent - > GetTrigger ( ) ;
outBitStream - > Write < bool > ( trigger & & trigger - > events . size ( ) > 0 ) ;
} else { // no trigger componenet, so definitely no triggers
2021-12-05 17:54:36 +00:00
outBitStream - > Write0 ( ) ;
}
2023-02-10 08:29:53 +00:00
2021-12-05 17:54:36 +00:00
if ( m_ParentEntity ! = nullptr | | m_SpawnerID ! = 0 ) {
outBitStream - > Write1 ( ) ;
2023-04-25 18:17:40 +00:00
if ( m_ParentEntity ! = nullptr ) outBitStream - > Write ( GeneralUtils : : SetBit ( m_ParentEntity - > GetObjectID ( ) , static_cast < uint32_t > ( eObjectBits : : CLIENT ) ) ) ;
2021-12-05 17:54:36 +00:00
else if ( m_Spawner ! = nullptr & & m_Spawner - > m_Info . isNetwork ) outBitStream - > Write ( m_SpawnerID ) ;
2023-04-25 18:17:40 +00:00
else outBitStream - > Write ( GeneralUtils : : SetBit ( m_SpawnerID , static_cast < uint32_t > ( eObjectBits : : CLIENT ) ) ) ;
2022-07-28 13:39:57 +00:00
} else outBitStream - > Write0 ( ) ;
2021-12-05 17:54:36 +00:00
outBitStream - > Write ( m_HasSpawnerNodeID ) ;
if ( m_HasSpawnerNodeID ) outBitStream - > Write ( m_SpawnerNodeID ) ;
//outBitStream->Write0(); //Spawner node id
if ( m_Scale = = 1.0f | | m_Scale = = 0.0f ) outBitStream - > Write0 ( ) ;
else {
outBitStream - > Write1 ( ) ;
outBitStream - > Write ( m_Scale ) ;
}
outBitStream - > Write0 ( ) ; //ObjectWorldState
2023-03-24 23:16:45 +00:00
if ( m_GMLevel ! = eGameMasterLevel : : CIVILIAN ) {
2021-12-05 17:54:36 +00:00
outBitStream - > Write1 ( ) ;
outBitStream - > Write ( m_GMLevel ) ;
2022-07-28 13:39:57 +00:00
} else outBitStream - > Write0 ( ) ; //No GM Level
2021-12-05 17:54:36 +00:00
}
2022-07-28 13:39:57 +00:00
2022-06-16 06:04:03 +00:00
// Only serialize parent / child info should the info be dirty (changed) or if this is the construction of the entity.
2023-05-02 22:39:21 +00:00
outBitStream - > Write ( m_IsParentChildDirty | | packetType = = eReplicaPacketType : : CONSTRUCTION ) ;
if ( m_IsParentChildDirty | | packetType = = eReplicaPacketType : : CONSTRUCTION ) {
2022-06-16 05:58:38 +00:00
m_IsParentChildDirty = false ;
2021-12-05 17:54:36 +00:00
outBitStream - > Write ( m_ParentEntity ! = nullptr ) ;
if ( m_ParentEntity ) {
outBitStream - > Write ( m_ParentEntity - > GetObjectID ( ) ) ;
outBitStream - > Write0 ( ) ;
}
outBitStream - > Write ( m_ChildEntities . size ( ) > 0 ) ;
if ( m_ChildEntities . size ( ) > 0 ) {
2023-12-28 04:18:20 +00:00
outBitStream - > Write < uint16_t > ( m_ChildEntities . size ( ) ) ;
2021-12-05 17:54:36 +00:00
for ( Entity * child : m_ChildEntities ) {
2023-12-28 04:18:20 +00:00
outBitStream - > Write < uint64_t > ( child - > GetObjectID ( ) ) ;
2021-12-05 17:54:36 +00:00
}
}
}
}
void Entity : : WriteComponents ( RakNet : : BitStream * outBitStream , eReplicaPacketType packetType ) {
/**
* This has to be done in a specific order .
*/
bool destroyableSerialized = false ;
2023-08-10 21:33:15 +00:00
bool bIsInitialUpdate = packetType = = eReplicaPacketType : : CONSTRUCTION ;
2021-12-05 17:54:36 +00:00
PossessableComponent * possessableComponent ;
2023-03-04 07:16:37 +00:00
if ( TryGetComponent ( eReplicaComponentType : : POSSESSABLE , possessableComponent ) ) {
2023-08-10 21:33:15 +00:00
possessableComponent - > Serialize ( outBitStream , bIsInitialUpdate ) ;
2021-12-05 17:54:36 +00:00
}
ModuleAssemblyComponent * moduleAssemblyComponent ;
2023-03-04 07:16:37 +00:00
if ( TryGetComponent ( eReplicaComponentType : : MODULE_ASSEMBLY , moduleAssemblyComponent ) ) {
2023-08-10 21:33:15 +00:00
moduleAssemblyComponent - > Serialize ( outBitStream , bIsInitialUpdate ) ;
2021-12-05 17:54:36 +00:00
}
2022-07-28 13:39:57 +00:00
2021-12-05 17:54:36 +00:00
ControllablePhysicsComponent * controllablePhysicsComponent ;
2023-03-04 07:16:37 +00:00
if ( TryGetComponent ( eReplicaComponentType : : CONTROLLABLE_PHYSICS , controllablePhysicsComponent ) ) {
2023-08-10 21:33:15 +00:00
controllablePhysicsComponent - > Serialize ( outBitStream , bIsInitialUpdate ) ;
2021-12-05 17:54:36 +00:00
}
SimplePhysicsComponent * simplePhysicsComponent ;
2023-03-04 07:16:37 +00:00
if ( TryGetComponent ( eReplicaComponentType : : SIMPLE_PHYSICS , simplePhysicsComponent ) ) {
2023-08-10 21:33:15 +00:00
simplePhysicsComponent - > Serialize ( outBitStream , bIsInitialUpdate ) ;
2021-12-05 17:54:36 +00:00
}
RigidbodyPhantomPhysicsComponent * rigidbodyPhantomPhysics ;
2023-03-04 07:16:37 +00:00
if ( TryGetComponent ( eReplicaComponentType : : RIGID_BODY_PHANTOM_PHYSICS , rigidbodyPhantomPhysics ) ) {
2023-08-10 21:33:15 +00:00
rigidbodyPhantomPhysics - > Serialize ( outBitStream , bIsInitialUpdate ) ;
2021-12-05 17:54:36 +00:00
}
2023-12-04 15:20:41 +00:00
HavokVehiclePhysicsComponent * havokVehiclePhysicsComponent ;
if ( TryGetComponent ( eReplicaComponentType : : HAVOK_VEHICLE_PHYSICS , havokVehiclePhysicsComponent ) ) {
havokVehiclePhysicsComponent - > Serialize ( outBitStream , bIsInitialUpdate ) ;
2021-12-05 17:54:36 +00:00
}
PhantomPhysicsComponent * phantomPhysicsComponent ;
2023-03-04 07:16:37 +00:00
if ( TryGetComponent ( eReplicaComponentType : : PHANTOM_PHYSICS , phantomPhysicsComponent ) ) {
2023-08-10 21:33:15 +00:00
phantomPhysicsComponent - > Serialize ( outBitStream , bIsInitialUpdate ) ;
2021-12-05 17:54:36 +00:00
}
SoundTriggerComponent * soundTriggerComponent ;
2023-03-04 07:16:37 +00:00
if ( TryGetComponent ( eReplicaComponentType : : SOUND_TRIGGER , soundTriggerComponent ) ) {
2023-08-10 21:33:15 +00:00
soundTriggerComponent - > Serialize ( outBitStream , bIsInitialUpdate ) ;
2021-12-05 17:54:36 +00:00
}
2023-08-06 20:38:12 +00:00
RacingSoundTriggerComponent * racingSoundTriggerComponent ;
if ( TryGetComponent ( eReplicaComponentType : : RACING_SOUND_TRIGGER , racingSoundTriggerComponent ) ) {
2023-08-10 21:33:15 +00:00
racingSoundTriggerComponent - > Serialize ( outBitStream , bIsInitialUpdate ) ;
2023-08-06 20:38:12 +00:00
}
2021-12-05 17:54:36 +00:00
BuffComponent * buffComponent ;
2023-03-04 07:16:37 +00:00
if ( TryGetComponent ( eReplicaComponentType : : BUFF , buffComponent ) ) {
2023-08-10 21:33:15 +00:00
buffComponent - > Serialize ( outBitStream , bIsInitialUpdate ) ;
2021-12-05 17:54:36 +00:00
DestroyableComponent * destroyableComponent ;
2023-03-04 07:16:37 +00:00
if ( TryGetComponent ( eReplicaComponentType : : DESTROYABLE , destroyableComponent ) ) {
2023-08-10 21:33:15 +00:00
destroyableComponent - > Serialize ( outBitStream , bIsInitialUpdate ) ;
2021-12-05 17:54:36 +00:00
}
destroyableSerialized = true ;
}
2023-10-23 01:08:49 +00:00
CollectibleComponent * collectibleComponent ;
if ( TryGetComponent ( eReplicaComponentType : : COLLECTIBLE , collectibleComponent ) ) {
2021-12-05 17:54:36 +00:00
DestroyableComponent * destroyableComponent ;
2023-03-04 07:16:37 +00:00
if ( TryGetComponent ( eReplicaComponentType : : DESTROYABLE , destroyableComponent ) & & ! destroyableSerialized ) {
2023-08-10 21:33:15 +00:00
destroyableComponent - > Serialize ( outBitStream , bIsInitialUpdate ) ;
2021-12-05 17:54:36 +00:00
}
destroyableSerialized = true ;
2023-10-23 01:08:49 +00:00
collectibleComponent - > Serialize ( outBitStream , bIsInitialUpdate ) ;
2021-12-05 17:54:36 +00:00
}
PetComponent * petComponent ;
2023-03-04 07:16:37 +00:00
if ( TryGetComponent ( eReplicaComponentType : : PET , petComponent ) ) {
2023-08-10 21:33:15 +00:00
petComponent - > Serialize ( outBitStream , bIsInitialUpdate ) ;
2021-12-05 17:54:36 +00:00
}
CharacterComponent * characterComponent ;
2023-03-04 07:16:37 +00:00
if ( TryGetComponent ( eReplicaComponentType : : CHARACTER , characterComponent ) ) {
2022-06-29 23:50:24 +00:00
PossessorComponent * possessorComponent ;
2023-03-04 07:16:37 +00:00
if ( TryGetComponent ( eReplicaComponentType : : POSSESSOR , possessorComponent ) ) {
2023-08-10 21:33:15 +00:00
possessorComponent - > Serialize ( outBitStream , bIsInitialUpdate ) ;
2022-06-29 23:50:24 +00:00
} else {
// Should never happen, but just to be safe
outBitStream - > Write0 ( ) ;
}
2022-07-24 18:04:02 +00:00
LevelProgressionComponent * levelProgressionComponent ;
2023-03-04 07:16:37 +00:00
if ( TryGetComponent ( eReplicaComponentType : : LEVEL_PROGRESSION , levelProgressionComponent ) ) {
2023-08-10 21:33:15 +00:00
levelProgressionComponent - > Serialize ( outBitStream , bIsInitialUpdate ) ;
2022-07-24 18:04:02 +00:00
} else {
// Should never happen, but just to be safe
outBitStream - > Write0 ( ) ;
}
2022-07-24 18:25:10 +00:00
PlayerForcedMovementComponent * playerForcedMovementComponent ;
2023-03-04 07:16:37 +00:00
if ( TryGetComponent ( eReplicaComponentType : : PLAYER_FORCED_MOVEMENT , playerForcedMovementComponent ) ) {
2023-08-10 21:33:15 +00:00
playerForcedMovementComponent - > Serialize ( outBitStream , bIsInitialUpdate ) ;
2022-07-24 18:25:10 +00:00
} else {
// Should never happen, but just to be safe
outBitStream - > Write0 ( ) ;
}
2023-08-10 21:33:15 +00:00
characterComponent - > Serialize ( outBitStream , bIsInitialUpdate ) ;
2021-12-05 17:54:36 +00:00
}
2023-10-23 01:08:49 +00:00
ItemComponent * itemComponent ;
if ( TryGetComponent ( eReplicaComponentType : : ITEM , itemComponent ) ) {
itemComponent - > Serialize ( outBitStream , bIsInitialUpdate ) ;
2021-12-05 17:54:36 +00:00
}
InventoryComponent * inventoryComponent ;
2023-03-04 07:16:37 +00:00
if ( TryGetComponent ( eReplicaComponentType : : INVENTORY , inventoryComponent ) ) {
2023-08-10 21:33:15 +00:00
inventoryComponent - > Serialize ( outBitStream , bIsInitialUpdate ) ;
2021-12-05 17:54:36 +00:00
}
ScriptComponent * scriptComponent ;
2023-03-04 07:16:37 +00:00
if ( TryGetComponent ( eReplicaComponentType : : SCRIPT , scriptComponent ) ) {
2023-08-10 21:33:15 +00:00
scriptComponent - > Serialize ( outBitStream , bIsInitialUpdate ) ;
2021-12-05 17:54:36 +00:00
}
SkillComponent * skillComponent ;
2023-03-04 07:16:37 +00:00
if ( TryGetComponent ( eReplicaComponentType : : SKILL , skillComponent ) ) {
2023-08-10 21:33:15 +00:00
skillComponent - > Serialize ( outBitStream , bIsInitialUpdate ) ;
2021-12-05 17:54:36 +00:00
}
BaseCombatAIComponent * baseCombatAiComponent ;
2023-03-04 07:16:37 +00:00
if ( TryGetComponent ( eReplicaComponentType : : BASE_COMBAT_AI , baseCombatAiComponent ) ) {
2023-08-10 21:33:15 +00:00
baseCombatAiComponent - > Serialize ( outBitStream , bIsInitialUpdate ) ;
2021-12-05 17:54:36 +00:00
}
RebuildComponent * rebuildComponent ;
2023-03-04 07:16:37 +00:00
if ( TryGetComponent ( eReplicaComponentType : : QUICK_BUILD , rebuildComponent ) ) {
2021-12-05 17:54:36 +00:00
DestroyableComponent * destroyableComponent ;
2023-03-04 07:16:37 +00:00
if ( TryGetComponent ( eReplicaComponentType : : DESTROYABLE , destroyableComponent ) & & ! destroyableSerialized ) {
2023-08-10 21:33:15 +00:00
destroyableComponent - > Serialize ( outBitStream , bIsInitialUpdate ) ;
2021-12-05 17:54:36 +00:00
}
destroyableSerialized = true ;
2023-08-10 21:33:15 +00:00
rebuildComponent - > Serialize ( outBitStream , bIsInitialUpdate ) ;
2021-12-05 17:54:36 +00:00
}
MovingPlatformComponent * movingPlatformComponent ;
2023-03-04 07:16:37 +00:00
if ( TryGetComponent ( eReplicaComponentType : : MOVING_PLATFORM , movingPlatformComponent ) ) {
2023-08-10 21:33:15 +00:00
movingPlatformComponent - > Serialize ( outBitStream , bIsInitialUpdate ) ;
2021-12-05 17:54:36 +00:00
}
SwitchComponent * switchComponent ;
2023-03-04 07:16:37 +00:00
if ( TryGetComponent ( eReplicaComponentType : : SWITCH , switchComponent ) ) {
2023-08-10 21:33:15 +00:00
switchComponent - > Serialize ( outBitStream , bIsInitialUpdate ) ;
2021-12-05 17:54:36 +00:00
}
VendorComponent * vendorComponent ;
2023-03-04 07:16:37 +00:00
if ( TryGetComponent ( eReplicaComponentType : : VENDOR , vendorComponent ) ) {
2023-08-10 21:33:15 +00:00
vendorComponent - > Serialize ( outBitStream , bIsInitialUpdate ) ;
2021-12-05 17:54:36 +00:00
}
2023-08-04 02:44:03 +00:00
DonationVendorComponent * donationVendorComponent ;
if ( TryGetComponent ( eReplicaComponentType : : DONATION_VENDOR , donationVendorComponent ) ) {
2023-08-10 21:33:15 +00:00
donationVendorComponent - > Serialize ( outBitStream , bIsInitialUpdate ) ;
2023-08-04 02:44:03 +00:00
}
2021-12-05 17:54:36 +00:00
BouncerComponent * bouncerComponent ;
2023-03-04 07:16:37 +00:00
if ( TryGetComponent ( eReplicaComponentType : : BOUNCER , bouncerComponent ) ) {
2023-08-10 21:33:15 +00:00
bouncerComponent - > Serialize ( outBitStream , bIsInitialUpdate ) ;
2021-12-05 17:54:36 +00:00
}
ScriptedActivityComponent * scriptedActivityComponent ;
2023-03-04 07:16:37 +00:00
if ( TryGetComponent ( eReplicaComponentType : : SCRIPTED_ACTIVITY , scriptedActivityComponent ) ) {
2023-08-10 21:33:15 +00:00
scriptedActivityComponent - > Serialize ( outBitStream , bIsInitialUpdate ) ;
2021-12-05 17:54:36 +00:00
}
2022-07-28 13:39:57 +00:00
ShootingGalleryComponent * shootingGalleryComponent ;
2023-03-04 07:16:37 +00:00
if ( TryGetComponent ( eReplicaComponentType : : SHOOTING_GALLERY , shootingGalleryComponent ) ) {
2023-08-10 21:33:15 +00:00
shootingGalleryComponent - > Serialize ( outBitStream , bIsInitialUpdate ) ;
2022-07-28 13:39:57 +00:00
}
2021-12-05 17:54:36 +00:00
RacingControlComponent * racingControlComponent ;
2023-03-04 07:16:37 +00:00
if ( TryGetComponent ( eReplicaComponentType : : RACING_CONTROL , racingControlComponent ) ) {
2023-08-10 21:33:15 +00:00
racingControlComponent - > Serialize ( outBitStream , bIsInitialUpdate ) ;
2021-12-05 17:54:36 +00:00
}
LUPExhibitComponent * lupExhibitComponent ;
2023-03-04 07:16:37 +00:00
if ( TryGetComponent ( eReplicaComponentType : : LUP_EXHIBIT , lupExhibitComponent ) ) {
2023-08-10 21:33:15 +00:00
lupExhibitComponent - > Serialize ( outBitStream , bIsInitialUpdate ) ;
2021-12-05 17:54:36 +00:00
}
ModelComponent * modelComponent ;
2023-03-04 07:16:37 +00:00
if ( TryGetComponent ( eReplicaComponentType : : MODEL , modelComponent ) ) {
2023-08-10 21:33:15 +00:00
modelComponent - > Serialize ( outBitStream , bIsInitialUpdate ) ;
2021-12-05 17:54:36 +00:00
}
RenderComponent * renderComponent ;
2023-03-04 07:16:37 +00:00
if ( TryGetComponent ( eReplicaComponentType : : RENDER , renderComponent ) ) {
2023-08-10 21:33:15 +00:00
renderComponent - > Serialize ( outBitStream , bIsInitialUpdate ) ;
2021-12-05 17:54:36 +00:00
}
2023-10-19 17:42:43 +00:00
if ( modelComponent | | ! destroyableSerialized ) {
2022-07-19 21:51:35 +00:00
DestroyableComponent * destroyableComponent ;
2023-03-04 07:16:37 +00:00
if ( TryGetComponent ( eReplicaComponentType : : DESTROYABLE , destroyableComponent ) & & ! destroyableSerialized ) {
2023-08-10 21:33:15 +00:00
destroyableComponent - > Serialize ( outBitStream , bIsInitialUpdate ) ;
2022-07-19 21:51:35 +00:00
destroyableSerialized = true ;
}
}
2023-12-05 02:59:08 +00:00
MiniGameControlComponent * miniGameControlComponent ;
if ( TryGetComponent ( eReplicaComponentType : : MINI_GAME_CONTROL , miniGameControlComponent ) ) {
miniGameControlComponent - > Serialize ( outBitStream , bIsInitialUpdate ) ;
2021-12-05 17:54:36 +00:00
}
2022-06-29 23:50:24 +00:00
// BBB Component, unused currently
2022-07-19 21:51:35 +00:00
// Need to to write0 so that is serialized correctly
2022-06-29 23:50:24 +00:00
// TODO: Implement BBB Component
outBitStream - > Write0 ( ) ;
2021-12-05 17:54:36 +00:00
}
void Entity : : UpdateXMLDoc ( tinyxml2 : : XMLDocument * doc ) {
//This function should only ever be called from within Character, meaning doc should always exist when this is called.
//Naturally, we don't include any non-player components in this update function.
2022-07-28 13:39:57 +00:00
for ( const auto & pair : m_Components ) {
2021-12-05 17:54:36 +00:00
if ( pair . second = = nullptr ) continue ;
pair . second - > UpdateXml ( doc ) ;
}
}
void Entity : : Update ( const float deltaTime ) {
2022-07-17 01:21:35 +00:00
uint32_t timerPosition ;
timerPosition = 0 ;
while ( timerPosition < m_Timers . size ( ) ) {
m_Timers [ timerPosition ] - > Update ( deltaTime ) ;
if ( m_Timers [ timerPosition ] - > GetTime ( ) < = 0 ) {
const auto timerName = m_Timers [ timerPosition ] - > GetName ( ) ;
2021-12-05 17:54:36 +00:00
2022-07-17 01:21:35 +00:00
delete m_Timers [ timerPosition ] ;
m_Timers . erase ( m_Timers . begin ( ) + timerPosition ) ;
2021-12-05 17:54:36 +00:00
for ( CppScripts : : Script * script : CppScripts : : GetEntityScripts ( this ) ) {
script - > OnTimerDone ( this , timerName ) ;
}
2023-04-18 17:48:03 +00:00
TriggerEvent ( eTriggerEventType : : TIMER_DONE , this ) ;
2022-07-17 01:21:35 +00:00
} else {
timerPosition + + ;
2021-12-05 17:54:36 +00:00
}
}
for ( int i = 0 ; i < m_CallbackTimers . size ( ) ; i + + ) {
m_CallbackTimers [ i ] - > Update ( deltaTime ) ;
if ( m_CallbackTimers [ i ] - > GetTime ( ) < = 0 ) {
m_CallbackTimers [ i ] - > GetCallback ( ) ( ) ;
delete m_CallbackTimers [ i ] ;
m_CallbackTimers . erase ( m_CallbackTimers . begin ( ) + i ) ;
}
}
2022-07-28 13:39:57 +00:00
2022-07-17 01:21:35 +00:00
// Add pending timers to the list of timers so they start next tick.
if ( m_PendingTimers . size ( ) > 0 ) {
for ( auto namedTimer : m_PendingTimers ) {
m_Timers . push_back ( namedTimer ) ;
}
m_PendingTimers . clear ( ) ;
}
2021-12-05 17:54:36 +00:00
2022-07-28 13:39:57 +00:00
if ( IsSleeping ( ) ) {
2021-12-05 17:54:36 +00:00
Sleep ( ) ;
return ;
2022-07-28 13:39:57 +00:00
} else {
2021-12-05 17:54:36 +00:00
Wake ( ) ;
}
for ( CppScripts : : Script * script : CppScripts : : GetEntityScripts ( this ) ) {
script - > OnUpdate ( this ) ;
}
2022-07-28 13:39:57 +00:00
for ( const auto & pair : m_Components ) {
2021-12-05 17:54:36 +00:00
if ( pair . second = = nullptr ) continue ;
pair . second - > Update ( deltaTime ) ;
}
if ( m_ShouldDestroyAfterUpdate ) {
2023-07-15 20:56:33 +00:00
Game : : entityManager - > DestroyEntity ( this - > GetObjectID ( ) ) ;
2021-12-05 17:54:36 +00:00
}
}
void Entity : : OnCollisionProximity ( LWOOBJID otherEntity , const std : : string & proxName , const std : : string & status ) {
2023-07-15 20:56:33 +00:00
Entity * other = Game : : entityManager - > GetEntity ( otherEntity ) ;
2021-12-05 17:54:36 +00:00
if ( ! other ) return ;
for ( CppScripts : : Script * script : CppScripts : : GetEntityScripts ( this ) ) {
script - > OnProximityUpdate ( this , other , proxName , status ) ;
}
RocketLaunchpadControlComponent * rocketComp = GetComponent < RocketLaunchpadControlComponent > ( ) ;
if ( ! rocketComp ) return ;
rocketComp - > OnProximityUpdate ( other , proxName , status ) ;
}
void Entity : : OnCollisionPhantom ( const LWOOBJID otherEntity ) {
2023-07-15 20:56:33 +00:00
auto * other = Game : : entityManager - > GetEntity ( otherEntity ) ;
2021-12-05 17:54:36 +00:00
if ( ! other ) return ;
for ( CppScripts : : Script * script : CppScripts : : GetEntityScripts ( this ) ) {
script - > OnCollisionPhantom ( this , other ) ;
}
2022-07-28 13:39:57 +00:00
for ( const auto & callback : m_PhantomCollisionCallbacks ) {
callback ( other ) ;
2021-12-05 17:54:36 +00:00
}
SwitchComponent * switchComp = GetComponent < SwitchComponent > ( ) ;
if ( switchComp ) {
switchComp - > EntityEnter ( other ) ;
}
2023-02-10 08:29:53 +00:00
TriggerEvent ( eTriggerEventType : : ENTER , other ) ;
2021-12-05 17:54:36 +00:00
// POI system
const auto & poi = GetVar < std : : u16string > ( u " POI " ) ;
if ( ! poi . empty ( ) ) {
auto * missionComponent = other - > GetComponent < MissionComponent > ( ) ;
2022-07-28 13:39:57 +00:00
if ( missionComponent ! = nullptr ) {
2023-01-22 23:38:47 +00:00
missionComponent - > Progress ( eMissionTaskType : : EXPLORE , 0 , 0 , GeneralUtils : : UTF16ToWTF8 ( poi ) ) ;
2021-12-05 17:54:36 +00:00
}
}
2022-07-28 13:39:57 +00:00
if ( ! other - > GetIsDead ( ) ) {
2021-12-05 17:54:36 +00:00
auto * combat = GetComponent < BaseCombatAIComponent > ( ) ;
2022-07-28 13:39:57 +00:00
if ( combat ! = nullptr ) {
2021-12-05 17:54:36 +00:00
const auto index = std : : find ( m_TargetsInPhantom . begin ( ) , m_TargetsInPhantom . end ( ) , otherEntity ) ;
if ( index ! = m_TargetsInPhantom . end ( ) ) return ;
const auto valid = combat - > IsEnemy ( otherEntity ) ;
if ( ! valid ) return ;
m_TargetsInPhantom . push_back ( otherEntity ) ;
}
}
}
2022-07-28 13:39:57 +00:00
void Entity : : OnCollisionLeavePhantom ( const LWOOBJID otherEntity ) {
2023-07-15 20:56:33 +00:00
auto * other = Game : : entityManager - > GetEntity ( otherEntity ) ;
2021-12-05 17:54:36 +00:00
if ( ! other ) return ;
2023-04-12 16:46:31 +00:00
for ( CppScripts : : Script * script : CppScripts : : GetEntityScripts ( this ) ) {
script - > OnOffCollisionPhantom ( this , other ) ;
}
2023-02-10 08:29:53 +00:00
TriggerEvent ( eTriggerEventType : : EXIT , other ) ;
2021-12-05 17:54:36 +00:00
SwitchComponent * switchComp = GetComponent < SwitchComponent > ( ) ;
if ( switchComp ) {
switchComp - > EntityLeave ( other ) ;
}
const auto index = std : : find ( m_TargetsInPhantom . begin ( ) , m_TargetsInPhantom . end ( ) , otherEntity ) ;
2022-07-28 13:39:57 +00:00
2021-12-05 17:54:36 +00:00
if ( index = = m_TargetsInPhantom . end ( ) ) return ;
m_TargetsInPhantom . erase ( index ) ;
}
void Entity : : OnFireEventServerSide ( Entity * sender , std : : string args , int32_t param1 , int32_t param2 , int32_t param3 ) {
2022-07-28 13:39:57 +00:00
for ( CppScripts : : Script * script : CppScripts : : GetEntityScripts ( this ) ) {
script - > OnFireEventServerSide ( this , sender , args , param1 , param2 , param3 ) ;
2021-12-05 17:54:36 +00:00
}
}
void Entity : : OnActivityStateChangeRequest ( LWOOBJID senderID , int32_t value1 , int32_t value2 , const std : : u16string & stringValue ) {
2022-07-28 13:39:57 +00:00
for ( CppScripts : : Script * script : CppScripts : : GetEntityScripts ( this ) ) {
script - > OnActivityStateChangeRequest ( this , senderID , value1 , value2 , stringValue ) ;
2021-12-05 17:54:36 +00:00
}
}
2022-07-28 13:39:57 +00:00
void Entity : : OnCinematicUpdate ( Entity * self , Entity * sender , eCinematicEvent event , const std : : u16string & pathName ,
float_t pathTime , float_t totalTime , int32_t waypoint ) {
for ( CppScripts : : Script * script : CppScripts : : GetEntityScripts ( this ) ) {
script - > OnCinematicUpdate ( self , sender , event , pathName , pathTime , totalTime , waypoint ) ;
}
2021-12-05 17:54:36 +00:00
}
2022-07-28 13:39:57 +00:00
void Entity : : NotifyObject ( Entity * sender , const std : : string & name , int32_t param1 , int32_t param2 ) {
2021-12-05 17:54:36 +00:00
GameMessages : : SendNotifyObject ( GetObjectID ( ) , sender - > GetObjectID ( ) , GeneralUtils : : ASCIIToUTF16 ( name ) , UNASSIGNED_SYSTEM_ADDRESS ) ;
2022-07-28 13:39:57 +00:00
for ( CppScripts : : Script * script : CppScripts : : GetEntityScripts ( this ) ) {
script - > OnNotifyObject ( this , sender , name , param1 , param2 ) ;
2021-12-05 17:54:36 +00:00
}
}
2022-07-28 13:39:57 +00:00
void Entity : : OnEmoteReceived ( const int32_t emote , Entity * target ) {
for ( auto * script : CppScripts : : GetEntityScripts ( this ) ) {
2021-12-05 17:54:36 +00:00
script - > OnEmoteReceived ( this , emote , target ) ;
}
}
void Entity : : OnUse ( Entity * originator ) {
2023-03-25 10:26:39 +00:00
TriggerEvent ( eTriggerEventType : : INTERACT , originator ) ;
2021-12-05 17:54:36 +00:00
for ( CppScripts : : Script * script : CppScripts : : GetEntityScripts ( this ) ) {
script - > OnUse ( this , originator ) ;
}
// component base class when
2022-07-28 13:39:57 +00:00
for ( const auto & pair : m_Components ) {
2021-12-05 17:54:36 +00:00
if ( pair . second = = nullptr ) continue ;
pair . second - > OnUse ( originator ) ;
}
}
void Entity : : OnHitOrHealResult ( Entity * attacker , int32_t damage ) {
for ( CppScripts : : Script * script : CppScripts : : GetEntityScripts ( this ) ) {
script - > OnHitOrHealResult ( this , attacker , damage ) ;
}
}
void Entity : : OnHit ( Entity * attacker ) {
2023-03-25 10:26:39 +00:00
TriggerEvent ( eTriggerEventType : : HIT , attacker ) ;
2021-12-05 17:54:36 +00:00
for ( CppScripts : : Script * script : CppScripts : : GetEntityScripts ( this ) ) {
script - > OnHit ( this , attacker ) ;
}
}
2022-07-28 13:39:57 +00:00
void Entity : : OnZonePropertyEditBegin ( ) {
2021-12-05 17:54:36 +00:00
for ( CppScripts : : Script * script : CppScripts : : GetEntityScripts ( this ) ) {
script - > OnZonePropertyEditBegin ( this ) ;
}
}
2022-07-28 13:39:57 +00:00
void Entity : : OnZonePropertyEditEnd ( ) {
2021-12-05 17:54:36 +00:00
for ( CppScripts : : Script * script : CppScripts : : GetEntityScripts ( this ) ) {
script - > OnZonePropertyEditEnd ( this ) ;
}
}
2022-07-28 13:39:57 +00:00
void Entity : : OnZonePropertyModelEquipped ( ) {
2021-12-05 17:54:36 +00:00
for ( CppScripts : : Script * script : CppScripts : : GetEntityScripts ( this ) ) {
script - > OnZonePropertyModelEquipped ( this ) ;
}
}
2022-07-28 13:39:57 +00:00
void Entity : : OnZonePropertyModelPlaced ( Entity * player ) {
2021-12-05 17:54:36 +00:00
for ( CppScripts : : Script * script : CppScripts : : GetEntityScripts ( this ) ) {
script - > OnZonePropertyModelPlaced ( this , player ) ;
}
}
2022-07-28 13:39:57 +00:00
void Entity : : OnZonePropertyModelPickedUp ( Entity * player ) {
2021-12-05 17:54:36 +00:00
for ( CppScripts : : Script * script : CppScripts : : GetEntityScripts ( this ) ) {
script - > OnZonePropertyModelPickedUp ( this , player ) ;
}
}
2022-07-28 13:39:57 +00:00
void Entity : : OnZonePropertyModelRemoved ( Entity * player ) {
2021-12-05 17:54:36 +00:00
for ( CppScripts : : Script * script : CppScripts : : GetEntityScripts ( this ) ) {
script - > OnZonePropertyModelRemoved ( this , player ) ;
}
}
2022-07-28 13:39:57 +00:00
void Entity : : OnZonePropertyModelRemovedWhileEquipped ( Entity * player ) {
2021-12-05 17:54:36 +00:00
for ( CppScripts : : Script * script : CppScripts : : GetEntityScripts ( this ) ) {
script - > OnZonePropertyModelRemovedWhileEquipped ( this , player ) ;
}
}
2022-07-28 13:39:57 +00:00
void Entity : : OnZonePropertyModelRotated ( Entity * player ) {
2021-12-05 17:54:36 +00:00
for ( CppScripts : : Script * script : CppScripts : : GetEntityScripts ( this ) ) {
script - > OnZonePropertyModelRotated ( this , player ) ;
}
}
2022-07-28 13:39:57 +00:00
void Entity : : OnMessageBoxResponse ( Entity * sender , int32_t button , const std : : u16string & identifier , const std : : u16string & userData ) {
2021-12-05 17:54:36 +00:00
for ( CppScripts : : Script * script : CppScripts : : GetEntityScripts ( this ) ) {
script - > OnMessageBoxResponse ( this , sender , button , identifier , userData ) ;
}
}
2022-07-28 13:39:57 +00:00
void Entity : : OnChoiceBoxResponse ( Entity * sender , int32_t button , const std : : u16string & buttonIdentifier , const std : : u16string & identifier ) {
2021-12-05 17:54:36 +00:00
for ( CppScripts : : Script * script : CppScripts : : GetEntityScripts ( this ) ) {
script - > OnChoiceBoxResponse ( this , sender , button , buttonIdentifier , identifier ) ;
}
}
2023-05-11 00:26:04 +00:00
void Entity : : RequestActivityExit ( Entity * sender , LWOOBJID player , bool canceled ) {
for ( CppScripts : : Script * script : CppScripts : : GetEntityScripts ( this ) ) {
script - > OnRequestActivityExit ( sender , player , canceled ) ;
}
}
2022-07-28 13:39:57 +00:00
void Entity : : Smash ( const LWOOBJID source , const eKillType killType , const std : : u16string & deathType ) {
2021-12-05 17:54:36 +00:00
if ( ! m_PlayerIsReadyForUpdates ) return ;
auto * destroyableComponent = GetComponent < DestroyableComponent > ( ) ;
2022-07-28 13:39:57 +00:00
if ( destroyableComponent = = nullptr ) {
2023-07-15 20:56:33 +00:00
Kill ( Game : : entityManager - > GetEntity ( source ) ) ;
2021-12-05 17:54:36 +00:00
return ;
}
2022-09-02 18:49:19 +00:00
auto * possessorComponent = GetComponent < PossessorComponent > ( ) ;
if ( possessorComponent ) {
if ( possessorComponent - > GetPossessable ( ) ! = LWOOBJID_EMPTY ) {
2023-07-15 20:56:33 +00:00
auto * mount = Game : : entityManager - > GetEntity ( possessorComponent - > GetPossessable ( ) ) ;
2022-09-02 18:49:19 +00:00
if ( mount ) possessorComponent - > Dismount ( mount , true ) ;
}
}
2021-12-05 17:54:36 +00:00
destroyableComponent - > Smash ( source , killType , deathType ) ;
}
2023-11-26 04:50:28 +00:00
void Entity : : Kill ( Entity * murderer , const eKillType killType ) {
2021-12-05 17:54:36 +00:00
if ( ! m_PlayerIsReadyForUpdates ) return ;
for ( const auto & cb : m_DieCallbacks ) {
cb ( ) ;
}
m_DieCallbacks . clear ( ) ;
//OMAI WA MOU, SHINDERIU
2022-07-28 13:39:57 +00:00
for ( CppScripts : : Script * script : CppScripts : : GetEntityScripts ( this ) ) {
2021-12-05 17:54:36 +00:00
script - > OnDie ( this , murderer ) ;
}
2022-07-28 13:39:57 +00:00
if ( m_Spawner ! = nullptr ) {
2021-12-05 17:54:36 +00:00
m_Spawner - > NotifyOfEntityDeath ( m_ObjectID ) ;
}
2022-07-28 13:39:57 +00:00
if ( ! IsPlayer ( ) ) {
2023-10-18 14:17:57 +00:00
auto * destroyableComponent = GetComponent < DestroyableComponent > ( ) ;
bool waitForDeathAnimation = false ;
if ( destroyableComponent ) {
2023-11-26 04:50:28 +00:00
waitForDeathAnimation = destroyableComponent - > GetDeathBehavior ( ) = = 0 & & killType ! = eKillType : : SILENT ;
2023-10-18 14:17:57 +00:00
}
// Live waited a hard coded 12 seconds for death animations of type 0 before networking destruction!
constexpr float DelayDeathTime = 12.0f ;
if ( waitForDeathAnimation ) AddCallbackTimer ( DelayDeathTime , [ this ] ( ) { Game : : entityManager - > DestroyEntity ( this ) ; } ) ;
else Game : : entityManager - > DestroyEntity ( this ) ;
2021-12-05 17:54:36 +00:00
}
2022-07-28 13:39:57 +00:00
2021-12-05 17:54:36 +00:00
const auto & grpNameQBShowBricks = GetVar < std : : string > ( u " grpNameQBShowBricks " ) ;
2022-07-28 13:39:57 +00:00
if ( ! grpNameQBShowBricks . empty ( ) ) {
2023-07-17 22:55:33 +00:00
auto spawners = Game : : zoneManager - > GetSpawnersByName ( grpNameQBShowBricks ) ;
2021-12-05 17:54:36 +00:00
Spawner * spawner = nullptr ;
2022-07-28 13:39:57 +00:00
if ( ! spawners . empty ( ) ) {
2021-12-05 17:54:36 +00:00
spawner = spawners [ 0 ] ;
2022-07-28 13:39:57 +00:00
} else {
2023-07-17 22:55:33 +00:00
spawners = Game : : zoneManager - > GetSpawnersInGroup ( grpNameQBShowBricks ) ;
2021-12-05 17:54:36 +00:00
2022-07-28 13:39:57 +00:00
if ( ! spawners . empty ( ) ) {
2021-12-05 17:54:36 +00:00
spawner = spawners [ 0 ] ;
}
}
2022-07-28 13:39:57 +00:00
if ( spawner ! = nullptr ) {
2021-12-05 17:54:36 +00:00
spawner - > Spawn ( ) ;
}
}
2022-07-28 13:39:57 +00:00
// Track a player being smashed
auto * characterComponent = GetComponent < CharacterComponent > ( ) ;
if ( characterComponent ! = nullptr ) {
characterComponent - > UpdatePlayerStatistic ( TimesSmashed ) ;
}
2021-12-05 17:54:36 +00:00
2022-07-28 13:39:57 +00:00
// Track a player smashing something else
if ( murderer ! = nullptr ) {
auto * murdererCharacterComponent = murderer - > GetComponent < CharacterComponent > ( ) ;
if ( murdererCharacterComponent ! = nullptr ) {
murdererCharacterComponent - > UpdatePlayerStatistic ( SmashablesSmashed ) ;
}
}
2021-12-05 17:54:36 +00:00
}
void Entity : : AddDieCallback ( const std : : function < void ( ) > & callback ) {
m_DieCallbacks . push_back ( callback ) ;
}
void Entity : : AddCollisionPhantomCallback ( const std : : function < void ( Entity * target ) > & callback ) {
2022-07-28 13:39:57 +00:00
m_PhantomCollisionCallbacks . push_back ( callback ) ;
2021-12-05 17:54:36 +00:00
}
2022-07-28 13:39:57 +00:00
void Entity : : AddRebuildCompleteCallback ( const std : : function < void ( Entity * user ) > & callback ) const {
auto * rebuildComponent = GetComponent < RebuildComponent > ( ) ;
if ( rebuildComponent ! = nullptr ) {
rebuildComponent - > AddRebuildCompleteCallback ( callback ) ;
}
2021-12-05 17:54:36 +00:00
}
bool Entity : : GetIsDead ( ) const {
DestroyableComponent * dest = GetComponent < DestroyableComponent > ( ) ;
if ( dest & & dest - > GetArmor ( ) = = 0 & & dest - > GetHealth ( ) = = 0 ) return true ;
return false ;
}
void Entity : : AddLootItem ( const Loot : : Info & info ) {
if ( ! IsPlayer ( ) ) return ;
auto & droppedLoot = static_cast < Player * > ( this ) - > GetDroppedLoot ( ) ;
droppedLoot . insert ( std : : make_pair ( info . id , info ) ) ;
}
void Entity : : PickupItem ( const LWOOBJID & objectID ) {
if ( ! IsPlayer ( ) ) return ;
InventoryComponent * inv = GetComponent < InventoryComponent > ( ) ;
if ( ! inv ) return ;
2023-03-17 14:36:21 +00:00
CDObjectsTable * objectsTable = CDClientManager : : Instance ( ) . GetTable < CDObjectsTable > ( ) ;
2022-07-28 13:39:57 +00:00
2021-12-05 17:54:36 +00:00
auto & droppedLoot = static_cast < Player * > ( this ) - > GetDroppedLoot ( ) ;
for ( const auto & p : droppedLoot ) {
if ( p . first = = objectID ) {
2022-07-28 13:39:57 +00:00
auto * characterComponent = GetComponent < CharacterComponent > ( ) ;
if ( characterComponent ! = nullptr ) {
characterComponent - > TrackLOTCollection ( p . second . lot ) ;
}
2021-12-05 17:54:36 +00:00
const CDObjects & object = objectsTable - > GetByID ( p . second . lot ) ;
if ( object . id ! = 0 & & object . type = = " Powerup " ) {
2023-03-17 14:36:21 +00:00
CDObjectSkillsTable * skillsTable = CDClientManager : : Instance ( ) . GetTable < CDObjectSkillsTable > ( ) ;
2021-12-05 17:54:36 +00:00
std : : vector < CDObjectSkills > skills = skillsTable - > Query ( [ = ] ( CDObjectSkills entry ) { return ( entry . objectTemplate = = p . second . lot ) ; } ) ;
for ( CDObjectSkills skill : skills ) {
2023-03-17 14:36:21 +00:00
CDSkillBehaviorTable * skillBehTable = CDClientManager : : Instance ( ) . GetTable < CDSkillBehaviorTable > ( ) ;
2021-12-05 17:54:36 +00:00
CDSkillBehavior behaviorData = skillBehTable - > GetSkillByID ( skill . skillID ) ;
SkillComponent : : HandleUnmanaged ( behaviorData . behaviorID , GetObjectID ( ) ) ;
auto * missionComponent = GetComponent < MissionComponent > ( ) ;
2022-07-28 13:39:57 +00:00
if ( missionComponent ! = nullptr ) {
2023-01-22 23:38:47 +00:00
missionComponent - > Progress ( eMissionTaskType : : POWERUP , skill . skillID ) ;
2021-12-05 17:54:36 +00:00
}
}
2022-07-28 13:39:57 +00:00
} else {
2023-05-02 22:39:21 +00:00
inv - > AddItem ( p . second . lot , p . second . count , eLootSourceType : : PICKUP , eInventoryType : : INVALID , { } , LWOOBJID_EMPTY , true , false , LWOOBJID_EMPTY , eInventoryType : : INVALID , 1 ) ;
2021-12-05 17:54:36 +00:00
}
}
}
droppedLoot . erase ( objectID ) ;
}
2021-12-11 16:33:54 +00:00
bool Entity : : CanPickupCoins ( uint64_t count ) {
2021-12-11 13:21:00 +00:00
if ( ! IsPlayer ( ) ) return false ;
2021-12-11 16:33:54 +00:00
auto * player = static_cast < Player * > ( this ) ;
auto droppedCoins = player - > GetDroppedCoins ( ) ;
2022-07-28 13:39:57 +00:00
if ( count > droppedCoins ) {
2021-12-11 13:21:00 +00:00
return false ;
} else {
2021-12-11 16:33:54 +00:00
player - > SetDroppedCoins ( droppedCoins - count ) ;
2021-12-11 13:21:00 +00:00
return true ;
}
}
2021-12-11 13:57:15 +00:00
void Entity : : RegisterCoinDrop ( uint64_t count ) {
2021-12-11 13:21:00 +00:00
if ( ! IsPlayer ( ) ) return ;
2021-12-11 16:33:54 +00:00
auto * player = static_cast < Player * > ( this ) ;
auto droppedCoins = player - > GetDroppedCoins ( ) ;
droppedCoins + = count ;
player - > SetDroppedCoins ( droppedCoins ) ;
2021-12-11 13:21:00 +00:00
}
2021-12-05 17:54:36 +00:00
void Entity : : AddChild ( Entity * child ) {
2022-06-16 05:58:38 +00:00
m_IsParentChildDirty = true ;
2021-12-05 17:54:36 +00:00
m_ChildEntities . push_back ( child ) ;
}
2022-06-17 00:50:33 +00:00
void Entity : : RemoveChild ( Entity * child ) {
if ( ! child ) return ;
2022-07-17 04:39:13 +00:00
uint32_t entityPosition = 0 ;
while ( entityPosition < m_ChildEntities . size ( ) ) {
if ( ! m_ChildEntities [ entityPosition ] | | ( m_ChildEntities [ entityPosition ] ) - > GetObjectID ( ) = = child - > GetObjectID ( ) ) {
2022-06-17 00:50:33 +00:00
m_IsParentChildDirty = true ;
2022-07-17 04:39:13 +00:00
m_ChildEntities . erase ( m_ChildEntities . begin ( ) + entityPosition ) ;
} else {
entityPosition + + ;
2022-06-17 00:50:33 +00:00
}
}
}
2022-07-17 04:39:13 +00:00
void Entity : : RemoveParent ( ) {
this - > m_ParentEntity = nullptr ;
}
2021-12-05 17:54:36 +00:00
void Entity : : AddTimer ( std : : string name , float time ) {
EntityTimer * timer = new EntityTimer ( name , time ) ;
2022-07-17 01:21:35 +00:00
m_PendingTimers . push_back ( timer ) ;
2021-12-05 17:54:36 +00:00
}
void Entity : : AddCallbackTimer ( float time , std : : function < void ( ) > callback ) {
EntityCallbackTimer * timer = new EntityCallbackTimer ( time , callback ) ;
m_CallbackTimers . push_back ( timer ) ;
}
2022-07-28 13:39:57 +00:00
bool Entity : : HasTimer ( const std : : string & name ) {
for ( auto * timer : m_Timers ) {
if ( timer - > GetName ( ) = = name ) {
2021-12-05 17:54:36 +00:00
return true ;
}
}
return false ;
}
2022-07-28 13:39:57 +00:00
void Entity : : CancelCallbackTimers ( ) {
for ( auto * callback : m_CallbackTimers ) {
2021-12-05 17:54:36 +00:00
delete callback ;
}
2022-07-28 13:39:57 +00:00
2021-12-05 17:54:36 +00:00
m_CallbackTimers . clear ( ) ;
}
void Entity : : ScheduleKillAfterUpdate ( Entity * murderer ) {
//if (m_Info.spawner) m_Info.spawner->ScheduleKill(this);
2023-07-15 20:56:33 +00:00
Game : : entityManager - > ScheduleForKill ( this ) ;
2021-12-05 17:54:36 +00:00
if ( murderer ) m_ScheduleKiller = murderer ;
}
void Entity : : CancelTimer ( const std : : string & name ) {
2022-07-28 13:39:57 +00:00
for ( int i = 0 ; i < m_Timers . size ( ) ; i + + ) {
if ( m_Timers [ i ] - > GetName ( ) = = name ) {
delete m_Timers [ i ] ;
m_Timers . erase ( m_Timers . begin ( ) + i ) ;
return ;
}
}
2021-12-05 17:54:36 +00:00
}
void Entity : : CancelAllTimers ( ) {
/*for (auto timer : m_Timers) {
if ( timer ) delete timer ;
} */
2022-07-28 13:39:57 +00:00
for ( auto * timer : m_Timers ) {
2021-12-05 17:54:36 +00:00
delete timer ;
}
m_Timers . clear ( ) ;
for ( auto * callBackTimer : m_CallbackTimers ) {
delete callBackTimer ;
}
m_CallbackTimers . clear ( ) ;
}
bool Entity : : IsPlayer ( ) const {
2022-04-24 03:35:39 +00:00
return m_TemplateID = = 1 & & GetSystemAddress ( ) ! = UNASSIGNED_SYSTEM_ADDRESS ;
2021-12-05 17:54:36 +00:00
}
2023-02-10 08:29:53 +00:00
void Entity : : TriggerEvent ( eTriggerEventType event , Entity * optionalTarget ) {
auto * triggerComponent = GetComponent < TriggerComponent > ( ) ;
if ( triggerComponent ) triggerComponent - > TriggerEvent ( event , optionalTarget ) ;
2021-12-05 17:54:36 +00:00
}
2022-07-28 13:39:57 +00:00
Entity * Entity : : GetOwner ( ) const {
if ( m_OwnerOverride ! = LWOOBJID_EMPTY ) {
2023-07-15 20:56:33 +00:00
auto * other = Game : : entityManager - > GetEntity ( m_OwnerOverride ) ;
2021-12-05 17:54:36 +00:00
2022-07-28 13:39:57 +00:00
if ( other ! = nullptr ) {
2021-12-05 17:54:36 +00:00
return other - > GetOwner ( ) ;
}
}
return const_cast < Entity * > ( this ) ;
}
2022-07-28 13:39:57 +00:00
const NiPoint3 & Entity : : GetDefaultPosition ( ) const {
2021-12-05 17:54:36 +00:00
return m_DefaultPosition ;
}
2022-07-28 13:39:57 +00:00
const NiQuaternion & Entity : : GetDefaultRotation ( ) const {
2021-12-05 17:54:36 +00:00
return m_DefaultRotation ;
}
2022-07-28 13:39:57 +00:00
float Entity : : GetDefaultScale ( ) const {
2021-12-05 17:54:36 +00:00
return m_Scale ;
}
2022-07-28 13:39:57 +00:00
void Entity : : SetOwnerOverride ( const LWOOBJID value ) {
2021-12-05 17:54:36 +00:00
m_OwnerOverride = value ;
}
2022-07-28 13:39:57 +00:00
bool Entity : : GetIsGhostingCandidate ( ) const {
2021-12-05 17:54:36 +00:00
return m_IsGhostingCandidate ;
}
2022-07-28 13:39:57 +00:00
int8_t Entity : : GetObservers ( ) const {
2021-12-05 17:54:36 +00:00
return m_Observers ;
}
2022-07-28 13:39:57 +00:00
void Entity : : SetObservers ( int8_t value ) {
if ( value < 0 ) {
2021-12-05 17:54:36 +00:00
value = 0 ;
}
m_Observers = value ;
}
2022-07-28 13:39:57 +00:00
void Entity : : Sleep ( ) {
2021-12-05 17:54:36 +00:00
auto * baseCombatAIComponent = GetComponent < BaseCombatAIComponent > ( ) ;
2022-07-28 13:39:57 +00:00
if ( baseCombatAIComponent ! = nullptr ) {
2021-12-05 17:54:36 +00:00
baseCombatAIComponent - > Sleep ( ) ;
2022-07-28 13:39:57 +00:00
}
2021-12-05 17:54:36 +00:00
}
2022-07-28 13:39:57 +00:00
void Entity : : Wake ( ) {
2021-12-05 17:54:36 +00:00
auto * baseCombatAIComponent = GetComponent < BaseCombatAIComponent > ( ) ;
2022-07-28 13:39:57 +00:00
if ( baseCombatAIComponent ! = nullptr ) {
2021-12-05 17:54:36 +00:00
baseCombatAIComponent - > Wake ( ) ;
}
}
2022-07-28 13:39:57 +00:00
bool Entity : : IsSleeping ( ) const {
2021-12-05 17:54:36 +00:00
return m_IsGhostingCandidate & & m_Observers = = 0 ;
}
2022-07-28 13:39:57 +00:00
const NiPoint3 & Entity : : GetPosition ( ) const {
2021-12-05 17:54:36 +00:00
auto * controllable = GetComponent < ControllablePhysicsComponent > ( ) ;
2022-07-28 13:39:57 +00:00
if ( controllable ! = nullptr ) {
2021-12-05 17:54:36 +00:00
return controllable - > GetPosition ( ) ;
}
auto * phantom = GetComponent < PhantomPhysicsComponent > ( ) ;
2022-07-28 13:39:57 +00:00
if ( phantom ! = nullptr ) {
2021-12-05 17:54:36 +00:00
return phantom - > GetPosition ( ) ;
}
auto * simple = GetComponent < SimplePhysicsComponent > ( ) ;
2022-07-28 13:39:57 +00:00
if ( simple ! = nullptr ) {
2021-12-05 17:54:36 +00:00
return simple - > GetPosition ( ) ;
}
2023-12-04 15:20:41 +00:00
auto * vehicel = GetComponent < HavokVehiclePhysicsComponent > ( ) ;
2021-12-05 17:54:36 +00:00
2022-07-28 13:39:57 +00:00
if ( vehicel ! = nullptr ) {
2021-12-05 17:54:36 +00:00
return vehicel - > GetPosition ( ) ;
}
return NiPoint3 : : ZERO ;
}
2022-07-28 13:39:57 +00:00
const NiQuaternion & Entity : : GetRotation ( ) const {
2021-12-05 17:54:36 +00:00
auto * controllable = GetComponent < ControllablePhysicsComponent > ( ) ;
2022-07-28 13:39:57 +00:00
if ( controllable ! = nullptr ) {
2021-12-05 17:54:36 +00:00
return controllable - > GetRotation ( ) ;
}
auto * phantom = GetComponent < PhantomPhysicsComponent > ( ) ;
2022-07-28 13:39:57 +00:00
if ( phantom ! = nullptr ) {
2021-12-05 17:54:36 +00:00
return phantom - > GetRotation ( ) ;
}
auto * simple = GetComponent < SimplePhysicsComponent > ( ) ;
2022-07-28 13:39:57 +00:00
if ( simple ! = nullptr ) {
2021-12-05 17:54:36 +00:00
return simple - > GetRotation ( ) ;
}
2022-07-28 13:39:57 +00:00
2023-12-04 15:20:41 +00:00
auto * vehicel = GetComponent < HavokVehiclePhysicsComponent > ( ) ;
2021-12-05 17:54:36 +00:00
2022-07-28 13:39:57 +00:00
if ( vehicel ! = nullptr ) {
2021-12-05 17:54:36 +00:00
return vehicel - > GetRotation ( ) ;
}
return NiQuaternion : : IDENTITY ;
}
2022-07-28 13:39:57 +00:00
void Entity : : SetPosition ( NiPoint3 position ) {
2021-12-05 17:54:36 +00:00
auto * controllable = GetComponent < ControllablePhysicsComponent > ( ) ;
2022-07-28 13:39:57 +00:00
if ( controllable ! = nullptr ) {
2021-12-05 17:54:36 +00:00
controllable - > SetPosition ( position ) ;
}
auto * phantom = GetComponent < PhantomPhysicsComponent > ( ) ;
2022-07-28 13:39:57 +00:00
if ( phantom ! = nullptr ) {
2021-12-05 17:54:36 +00:00
phantom - > SetPosition ( position ) ;
}
auto * simple = GetComponent < SimplePhysicsComponent > ( ) ;
2022-07-28 13:39:57 +00:00
if ( simple ! = nullptr ) {
2021-12-05 17:54:36 +00:00
simple - > SetPosition ( position ) ;
}
2023-12-04 15:20:41 +00:00
auto * vehicel = GetComponent < HavokVehiclePhysicsComponent > ( ) ;
2021-12-05 17:54:36 +00:00
2022-07-28 13:39:57 +00:00
if ( vehicel ! = nullptr ) {
2021-12-05 17:54:36 +00:00
vehicel - > SetPosition ( position ) ;
}
2023-07-15 20:56:33 +00:00
Game : : entityManager - > SerializeEntity ( this ) ;
2021-12-05 17:54:36 +00:00
}
2022-07-28 13:39:57 +00:00
void Entity : : SetRotation ( NiQuaternion rotation ) {
2021-12-05 17:54:36 +00:00
auto * controllable = GetComponent < ControllablePhysicsComponent > ( ) ;
2022-07-28 13:39:57 +00:00
if ( controllable ! = nullptr ) {
2021-12-05 17:54:36 +00:00
controllable - > SetRotation ( rotation ) ;
}
auto * phantom = GetComponent < PhantomPhysicsComponent > ( ) ;
2022-07-28 13:39:57 +00:00
if ( phantom ! = nullptr ) {
2021-12-05 17:54:36 +00:00
phantom - > SetRotation ( rotation ) ;
}
auto * simple = GetComponent < SimplePhysicsComponent > ( ) ;
2022-07-28 13:39:57 +00:00
if ( simple ! = nullptr ) {
2021-12-05 17:54:36 +00:00
simple - > SetRotation ( rotation ) ;
}
2023-12-04 15:20:41 +00:00
auto * vehicel = GetComponent < HavokVehiclePhysicsComponent > ( ) ;
2021-12-05 17:54:36 +00:00
2022-07-28 13:39:57 +00:00
if ( vehicel ! = nullptr ) {
2021-12-05 17:54:36 +00:00
vehicel - > SetRotation ( rotation ) ;
}
2023-07-15 20:56:33 +00:00
Game : : entityManager - > SerializeEntity ( this ) ;
2021-12-05 17:54:36 +00:00
}
2022-07-28 13:39:57 +00:00
bool Entity : : GetBoolean ( const std : : u16string & name ) const {
2021-12-05 17:54:36 +00:00
return GetVar < bool > ( name ) ;
}
2022-07-28 13:39:57 +00:00
int32_t Entity : : GetI32 ( const std : : u16string & name ) const {
2021-12-05 17:54:36 +00:00
return GetVar < int32_t > ( name ) ;
}
2022-07-28 13:39:57 +00:00
int64_t Entity : : GetI64 ( const std : : u16string & name ) const {
2021-12-05 17:54:36 +00:00
return GetVar < int64_t > ( name ) ;
}
2022-07-28 13:39:57 +00:00
void Entity : : SetBoolean ( const std : : u16string & name , const bool value ) {
2021-12-05 17:54:36 +00:00
SetVar ( name , value ) ;
}
2022-07-28 13:39:57 +00:00
void Entity : : SetI32 ( const std : : u16string & name , const int32_t value ) {
2021-12-05 17:54:36 +00:00
SetVar ( name , value ) ;
}
2022-07-28 13:39:57 +00:00
void Entity : : SetI64 ( const std : : u16string & name , const int64_t value ) {
2021-12-05 17:54:36 +00:00
SetVar ( name , value ) ;
}
2022-07-28 13:39:57 +00:00
bool Entity : : HasVar ( const std : : u16string & name ) const {
for ( auto * data : m_Settings ) {
if ( data - > GetKey ( ) = = name ) {
2021-12-05 17:54:36 +00:00
return true ;
}
}
2022-07-28 13:39:57 +00:00
2021-12-05 17:54:36 +00:00
return false ;
}
2022-07-28 13:39:57 +00:00
uint16_t Entity : : GetNetworkId ( ) const {
2021-12-05 17:54:36 +00:00
return m_NetworkID ;
}
2022-07-28 13:39:57 +00:00
void Entity : : SetNetworkId ( const uint16_t id ) {
2021-12-05 17:54:36 +00:00
m_NetworkID = id ;
}
2022-07-28 13:39:57 +00:00
std : : vector < LWOOBJID > & Entity : : GetTargetsInPhantom ( ) {
2021-12-05 17:54:36 +00:00
std : : vector < LWOOBJID > valid ;
// Clean up invalid targets, like disconnected players
2022-07-28 13:39:57 +00:00
for ( auto i = 0u ; i < m_TargetsInPhantom . size ( ) ; + + i ) {
2021-12-05 17:54:36 +00:00
const auto id = m_TargetsInPhantom . at ( i ) ;
2023-07-15 20:56:33 +00:00
auto * entity = Game : : entityManager - > GetEntity ( id ) ;
2021-12-05 17:54:36 +00:00
2022-07-28 13:39:57 +00:00
if ( entity = = nullptr ) {
2021-12-05 17:54:36 +00:00
continue ;
}
valid . push_back ( id ) ;
}
m_TargetsInPhantom = valid ;
return m_TargetsInPhantom ;
}
void Entity : : SendNetworkVar ( const std : : string & data , const SystemAddress & sysAddr ) {
2022-07-28 13:39:57 +00:00
GameMessages : : SendSetNetworkScriptVar ( this , sysAddr , data ) ;
2021-12-05 17:54:36 +00:00
}
2022-07-28 13:39:57 +00:00
LDFBaseData * Entity : : GetVarData ( const std : : u16string & name ) const {
for ( auto * data : m_Settings ) {
if ( data = = nullptr ) {
2021-12-05 17:54:36 +00:00
continue ;
}
2022-07-28 13:39:57 +00:00
if ( data - > GetKey ( ) ! = name ) {
2021-12-05 17:54:36 +00:00
continue ;
}
return data ;
}
return nullptr ;
}
2022-07-28 13:39:57 +00:00
std : : string Entity : : GetVarAsString ( const std : : u16string & name ) const {
2021-12-05 17:54:36 +00:00
auto * data = GetVarData ( name ) ;
2022-07-28 13:39:57 +00:00
if ( data = = nullptr ) {
2021-12-05 17:54:36 +00:00
return " " ;
}
return data - > GetValueAsString ( ) ;
}
void Entity : : Resurrect ( ) {
2022-07-28 13:39:57 +00:00
if ( IsPlayer ( ) ) {
GameMessages : : SendResurrect ( this ) ;
}
2021-12-05 17:54:36 +00:00
}
void Entity : : AddToGroup ( const std : : string & group ) {
2022-07-28 13:39:57 +00:00
if ( std : : find ( m_Groups . begin ( ) , m_Groups . end ( ) , group ) = = m_Groups . end ( ) ) {
m_Groups . push_back ( group ) ;
}
2021-12-05 17:54:36 +00:00
}
2022-04-13 08:49:55 +00:00
void Entity : : RetroactiveVaultSize ( ) {
auto inventoryComponent = GetComponent < InventoryComponent > ( ) ;
if ( ! inventoryComponent ) return ;
auto itemsVault = inventoryComponent - > GetInventory ( eInventoryType : : VAULT_ITEMS ) ;
auto modelVault = inventoryComponent - > GetInventory ( eInventoryType : : VAULT_MODELS ) ;
if ( itemsVault - > GetSize ( ) = = modelVault - > GetSize ( ) ) return ;
modelVault - > SetSize ( itemsVault - > GetSize ( ) ) ;
}
2023-10-23 01:08:49 +00:00
uint8_t Entity : : GetCollectibleID ( ) const {
auto * collectible = GetComponent < CollectibleComponent > ( ) ;
return collectible ? collectible - > GetCollectibleId ( ) : 0 ;
}