2021-12-05 17:54:36 +00:00
# include "dCommonVars.h"
# include "Entity.h"
# include "CDClientManager.h"
# include "Game.h"
# include "dLogger.h"
# include "dServer.h"
# include "GameMessages.h"
# include "EntityManager.h"
# include "dZoneManager.h"
# include "Zone.h"
# include "Spawner.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-06-08 15:29:17 +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"
2023-06-09 22:12:57 +00:00
# include "QuickBuildComponent.h"
2021-12-05 17:54:36 +00:00
# include "BuildBorderComponent.h"
# include "MovementAIComponent.h"
# include "VendorComponent.h"
# include "RocketLaunchpadControlComponent.h"
# include "PropertyComponent.h"
2023-06-10 11:46:48 +00:00
# include "CollectibleComponent.h"
2021-12-05 17:54:36 +00:00
# include "BaseCombatAIComponent.h"
# include "PropertyManagementComponent.h"
# include "PropertyVendorComponent.h"
# include "ProximityMonitorComponent.h"
# include "PropertyEntranceComponent.h"
2023-06-08 15:29:17 +00:00
# include "ModelBehaviorComponent.h"
2021-12-05 17:54:36 +00:00
# include "PetComponent.h"
2023-06-08 15:29:17 +00:00
# include "HavokVehiclePhysicsComponent.h"
2021-12-05 17:54:36 +00:00
# include "PossessableComponent.h"
2023-06-26 17:36:36 +00:00
# include "PossessionComponent.h"
2021-12-05 17:54:36 +00:00
# include "ModuleAssemblyComponent.h"
# include "SoundTriggerComponent.h"
# include "ShootingGalleryComponent.h"
# include "RailActivatorComponent.h"
# include "LUPExhibitComponent.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-06-09 11:05:04 +00:00
# include "RacingStatsComponent.h"
# include "MinigameControlComponent.h"
2023-06-10 11:46:48 +00:00
# include "ItemComponent.h"
2023-06-23 05:56:25 +00:00
# include "DonationVendorComponent.h"
2023-06-26 20:06:33 +00:00
# include "GateRushComponent.h"
2023-06-23 15:30:03 +00:00
# include "RacingSoundTriggerComponent.h"
2023-06-23 15:56:05 +00:00
# include "AchievementVendorComponent.h"
2023-06-23 17:01:41 +00:00
# include "MutableModelBehaviorComponent.h"
2023-06-26 20:06:33 +00:00
# include "RacingComponent.h"
2021-12-05 17:54:36 +00:00
2023-03-17 14:36:21 +00:00
// Table includes
# include "CDComponentsRegistryTable.h"
# include "CDObjectSkillsTable.h"
# include "CDObjectsTable.h"
# include "CDSkillBehaviorTable.h"
2023-07-10 05:17:57 +00:00
# include "CppScripts.h"
# include "InvalidScript.h"
2023-03-17 14:36:21 +00:00
2023-06-10 06:02:28 +00:00
const std : : vector < ComponentWhitelist > Entity : : m_ComponentWhitelists = {
{ // Unknown use case
eReplicaComponentType : : CONTROLLABLE_PHYSICS ,
eReplicaComponentType : : SIMPLE_PHYSICS ,
eReplicaComponentType : : RENDER
} ,
{ // Used for BBB
eReplicaComponentType : : RENDER ,
eReplicaComponentType : : DESTROYABLE ,
eReplicaComponentType : : ITEM ,
eReplicaComponentType : : BLUEPRINT ,
eReplicaComponentType : : MODEL_BEHAVIOR ,
eReplicaComponentType : : CONTROLLABLE_PHYSICS ,
eReplicaComponentType : : SIMPLE_PHYSICS ,
eReplicaComponentType : : SPAWN
} ,
{ // Unknown use case
eReplicaComponentType : : RENDER ,
eReplicaComponentType : : ITEM ,
eReplicaComponentType : : BLUEPRINT ,
} ,
{ // Used for Pets
eReplicaComponentType : : PET ,
eReplicaComponentType : : SKILL ,
eReplicaComponentType : : DESTROYABLE ,
eReplicaComponentType : : RENDER ,
eReplicaComponentType : : CONTROLLABLE_PHYSICS
} ,
{ // Unknown use case
eReplicaComponentType : : CONTROLLABLE_PHYSICS ,
eReplicaComponentType : : SIMPLE_PHYSICS ,
eReplicaComponentType : : RENDER ,
} ,
} ;
2023-06-29 17:44:06 +00:00
const std : : array < eReplicaComponentType , 80 > Entity : : m_ComponentOrder = {
eReplicaComponentType : : POSSESSABLE ,
eReplicaComponentType : : BLUEPRINT ,
eReplicaComponentType : : MODULE_ASSEMBLY ,
eReplicaComponentType : : CONTROLLABLE_PHYSICS ,
eReplicaComponentType : : PROJECTILE_PHYSICS ,
eReplicaComponentType : : PHYSICS_SYSTEM ,
eReplicaComponentType : : VEHICLE_PHYSICS ,
eReplicaComponentType : : HAVOK_VEHICLE_PHYSICS ,
eReplicaComponentType : : RIGID_BODY_PHANTOM_PHYSICS ,
eReplicaComponentType : : SIMPLE_PHYSICS ,
eReplicaComponentType : : PHANTOM_PHYSICS ,
eReplicaComponentType : : DESTROYABLE ,
eReplicaComponentType : : MINIFIG ,
eReplicaComponentType : : CHARACTER ,
eReplicaComponentType : : PLAYER_FORCED_MOVEMENT ,
eReplicaComponentType : : POSSESSION ,
eReplicaComponentType : : MOUNT_CONTROL ,
eReplicaComponentType : : PET ,
eReplicaComponentType : : INVENTORY ,
eReplicaComponentType : : PROXIMITY_MONITOR ,
eReplicaComponentType : : MOVEMENT_AI ,
eReplicaComponentType : : SCRIPT ,
eReplicaComponentType : : SKILL ,
eReplicaComponentType : : BASE_COMBAT_AI ,
eReplicaComponentType : : SPAWN ,
eReplicaComponentType : : ITEM ,
eReplicaComponentType : : QUICK_BUILD ,
eReplicaComponentType : : BUILD_BORDER ,
eReplicaComponentType : : MODULE ,
eReplicaComponentType : : BUILD_CONTROLLER ,
eReplicaComponentType : : BUILD_ACTIVATOR ,
eReplicaComponentType : : QUICK_BUILD ,
eReplicaComponentType : : MISSION_OFFER ,
eReplicaComponentType : : VENDOR ,
eReplicaComponentType : : DONATION_VENDOR ,
eReplicaComponentType : : ACHIEVEMENT_VENDOR ,
eReplicaComponentType : : SHOOTING_GALLERY ,
eReplicaComponentType : : ROLLER ,
eReplicaComponentType : : SCRIPTED_ACTIVITY ,
eReplicaComponentType : : COLLECTIBLE ,
eReplicaComponentType : : MOVING_PLATFORM ,
eReplicaComponentType : : CHANGLING_BUILD ,
eReplicaComponentType : : CHOICE_BUILD ,
eReplicaComponentType : : PACKAGE ,
eReplicaComponentType : : PLATFORM_BOUNDARY ,
eReplicaComponentType : : HF_LIGHT_DIRECTION_GADGET ,
eReplicaComponentType : : CULLING_PLANE ,
eReplicaComponentType : : EXHIBIT ,
eReplicaComponentType : : LUP_EXHIBIT ,
eReplicaComponentType : : PROPERTY ,
eReplicaComponentType : : PROPERTY_PLAQUE ,
eReplicaComponentType : : MODEL_BEHAVIOR ,
eReplicaComponentType : : PROPERTY_ENTRANCE ,
eReplicaComponentType : : MULTI_ZONE_ENTRANCE ,
eReplicaComponentType : : PROPERTY_MANAGEMENT ,
eReplicaComponentType : : RAIL_ACTIVATOR ,
eReplicaComponentType : : BOUNCER ,
eReplicaComponentType : : SPRINGPAD ,
eReplicaComponentType : : SWITCH ,
eReplicaComponentType : : MINIGAME_CONTROL ,
eReplicaComponentType : : MODEL_BUILDER ,
eReplicaComponentType : : SOUND_REPEATER ,
eReplicaComponentType : : CHEST ,
eReplicaComponentType : : SHOWCASE_MODEL_HANDLER ,
eReplicaComponentType : : JETPACKPAD ,
eReplicaComponentType : : RENDER ,
eReplicaComponentType : : SOUND_AMBIENT_2D ,
eReplicaComponentType : : SOUND_AMBIENT_3D ,
eReplicaComponentType : : SOUND_TRIGGER ,
eReplicaComponentType : : RACING_SOUND_TRIGGER ,
eReplicaComponentType : : CUSTOM_BUILD_ASSEMBLY ,
eReplicaComponentType : : GENERIC_ACTIVATOR ,
eReplicaComponentType : : PROPERTY_VENDOR ,
eReplicaComponentType : : ROCKET_LAUNCHPAD_CONTROL ,
eReplicaComponentType : : ROCKET_ANIMATION_CONTROL ,
eReplicaComponentType : : FACTION_TRIGGER ,
eReplicaComponentType : : RACING_CONTROL ,
eReplicaComponentType : : GATE_RUSH_CONTROL ,
eReplicaComponentType : : BBB ,
eReplicaComponentType : : CRAFTING
} ;
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 ;
2023-06-09 08:04:42 +00:00
m_Observers = 0 ;
2021-12-05 17:54:36 +00:00
m_OwnerOverride = LWOOBJID_EMPTY ;
2023-06-09 09:46:01 +00:00
m_Groups . clear ( ) ;
m_Timers . clear ( ) ;
m_ChildEntities . clear ( ) ;
m_TargetsInPhantom . clear ( ) ;
m_DieCallbacks . clear ( ) ;
m_PhantomCollisionCallbacks . clear ( ) ;
2021-12-05 17:54:36 +00:00
m_ScheduleKiller = nullptr ;
2022-06-16 05:58:38 +00:00
m_IsParentChildDirty = true ;
2023-06-26 04:01:10 +00:00
m_IsGhostingCandidate = true ;
2023-06-09 08:04:42 +00:00
m_PlayerIsReadyForUpdates = false ;
m_ShouldDestroyAfterUpdate = false ;
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 ( ) {
2023-06-07 03:48:30 +00:00
if ( m_Character ) m_Character - > SaveXMLToDatabase ( ) ;
2021-12-05 17:54:36 +00:00
CancelAllTimers ( ) ;
CancelCallbackTimers ( ) ;
2023-06-07 03:48:30 +00:00
for ( auto child : m_ChildEntities ) if ( child ) child - > RemoveParent ( ) ;
2022-07-17 04:39:13 +00:00
2023-06-07 03:48:30 +00:00
if ( m_ParentEntity ) m_ParentEntity - > RemoveChild ( this ) ;
2021-12-05 17:54:36 +00:00
}
2023-06-10 11:46:48 +00:00
void Entity : : ApplyComponentWhitelist ( TemplateComponents & components ) const {
2023-06-10 06:02:28 +00:00
const auto whitelistIndex = GetVar < int32_t > ( u " componentWhitelist " ) ;
if ( whitelistIndex < 0 | | whitelistIndex > = m_ComponentWhitelists . size ( ) ) return ;
2023-06-10 07:03:07 +00:00
const auto & whitelist = m_ComponentWhitelists . at ( whitelistIndex ) ;
2023-06-10 07:14:20 +00:00
const auto endRange = std : : remove_if ( components . begin ( ) , components . end ( ) , [ & whitelist ] ( const auto & componentCandidate ) {
return std : : find ( whitelist . begin ( ) , whitelist . end ( ) , componentCandidate . first ) = = whitelist . end ( ) ;
2023-06-10 11:46:48 +00:00
} ) ;
2023-06-10 07:03:07 +00:00
components . erase ( endRange , components . end ( ) ) ;
2023-06-10 06:02:28 +00:00
}
2023-06-10 11:46:48 +00:00
void Entity : : ApplyComponentBlacklist ( TemplateComponents & components ) const {
bool hasPetComponent = std : : find_if ( components . begin ( ) , components . end ( ) , [ ] ( const auto & componentCandidate ) {
return componentCandidate . first = = eReplicaComponentType : : PET ;
2023-06-10 12:10:00 +00:00
} ) ! = components . end ( ) ;
if ( hasPetComponent ) {
auto toRemove = std : : remove_if ( components . begin ( ) , components . end ( ) , [ ] ( const auto & componentCandidate ) {
return componentCandidate . first = = eReplicaComponentType : : MODEL_BEHAVIOR | | componentCandidate . first = = eReplicaComponentType : : ITEM ;
} ) ;
components . erase ( toRemove , components . end ( ) ) ;
}
2023-06-10 11:46:48 +00:00
}
void Entity : : ApplyComponentConfig ( TemplateComponents & components ) const {
if ( GetVar < bool > ( u " markedAsPhantom " ) ) {
auto toRemove = std : : remove_if ( components . begin ( ) , components . end ( ) , [ ] ( const auto & componentCandidate ) {
return componentCandidate . first = = eReplicaComponentType : : SIMPLE_PHYSICS | |
componentCandidate . first = = eReplicaComponentType : : PHANTOM_PHYSICS ; // Just make sure we dont have phantom physics already
} ) ;
components . erase ( toRemove , components . end ( ) ) ;
components . emplace_back ( eReplicaComponentType : : PHANTOM_PHYSICS , 0U ) ;
}
}
2023-06-12 08:29:43 +00:00
void Entity : : AddPathComponent ( TemplateComponents & components ) const {
const Path * path = dZoneManager : : Instance ( ) - > GetZone ( ) - > GetPath ( GetVarAsString ( u " attached_path " ) ) ;
//Check to see if we have an attached path and add the appropiate component to handle it:
if ( path ) {
// if we have a moving platform path, then we need a moving platform component
if ( path - > pathType = = PathType : : MovingPlatform ) {
bool hasMovingPlatform = std : : count_if ( components . begin ( ) , components . end ( ) , [ ] ( const auto & componentCandidate ) {
return componentCandidate . first = = eReplicaComponentType : : MOVING_PLATFORM ;
} ) > 0 ;
if ( ! hasMovingPlatform ) components . emplace_back ( eReplicaComponentType : : MOVING_PLATFORM , 0U ) ;
} else if ( path - > pathType = = PathType : : Movement ) {
bool hasMovementAi = std : : count_if ( components . begin ( ) , components . end ( ) , [ ] ( const auto & componentCandidate ) {
return componentCandidate . first = = eReplicaComponentType : : MOVEMENT_AI ;
} ) > 0 ;
if ( ! hasMovementAi ) {
components . emplace_back ( eReplicaComponentType : : MOVEMENT_AI , 0U ) ;
}
} else {
Game : : logger - > Log ( " Entity " , " Unsupported path type %i provided for lot %i. " , path - > pathType , GetLOT ( ) ) ;
}
}
}
2022-07-28 13:39:57 +00:00
void Entity : : Initialize ( ) {
2023-06-24 06:56:13 +00:00
bool hasPhysicsComponent = false ;
bool hasDestroyableComponent = false ;
bool hasPathFindingComponent = false ;
bool hasProximityMonitorComponent = false ;
bool hasScriptComponent = false ;
bool hasDroppedLootComponent = false ;
uint32_t physicsComponentID = - 1 ;
2023-06-23 17:01:41 +00:00
2023-06-09 11:05:04 +00:00
// A few edge cases to tackle first
const auto triggerInfo = GetVarAsString ( u " trigger_id " ) ;
if ( ! triggerInfo . empty ( ) ) AddComponent < TriggerComponent > ( triggerInfo ) ;
const auto groupIDs = GetVarAsString ( u " groupID " ) ;
if ( ! groupIDs . empty ( ) ) {
m_Groups = GeneralUtils : : SplitString ( groupIDs , ' ; ' ) ;
if ( m_Groups . back ( ) . empty ( ) ) m_Groups . erase ( m_Groups . end ( ) - 1 ) ;
}
if ( m_ParentEntity ) m_ParentEntity - > AddChild ( this ) ;
2023-06-07 03:48:30 +00:00
auto * componentsRegistry = CDClientManager : : Instance ( ) . GetTable < CDComponentsRegistryTable > ( ) ;
2023-06-10 07:14:20 +00:00
TemplateComponents components = componentsRegistry - > GetTemplateComponents ( m_TemplateID ) ;
ApplyComponentWhitelist ( components ) ;
2023-06-10 11:46:48 +00:00
ApplyComponentBlacklist ( components ) ;
2023-06-12 08:29:43 +00:00
AddPathComponent ( components ) ;
2023-06-23 17:01:41 +00:00
2023-06-07 03:48:30 +00:00
for ( const auto & [ componentTemplate , componentId ] : components ) {
switch ( componentTemplate ) {
2023-06-26 04:47:35 +00:00
case eReplicaComponentType : : CONTROLLABLE_PHYSICS :
if ( hasPhysicsComponent ) continue ;
AddComponent < ControllablePhysicsComponent > ( ) ;
physicsComponentID = componentId ;
hasPhysicsComponent = true ;
break ;
case eReplicaComponentType : : RENDER :
AddComponent < RenderComponent > ( ) ;
break ;
case eReplicaComponentType : : SIMPLE_PHYSICS :
if ( hasPhysicsComponent ) continue ;
AddComponent < SimplePhysicsComponent > ( componentId ) ;
physicsComponentID = componentId ;
hasPhysicsComponent = true ;
break ;
case eReplicaComponentType : : CHARACTER :
AddComponent < CharacterComponent > ( m_Character ) ;
AddComponent < MissionComponent > ( ) ;
2023-06-26 17:36:36 +00:00
AddComponent < PossessionComponent > ( ) ;
2023-06-26 04:47:35 +00:00
AddComponent < LevelProgressionComponent > ( ) ;
AddComponent < PlayerForcedMovementComponent > ( ) ;
break ;
case eReplicaComponentType : : SCRIPT : {
std : : string script ;
if ( m_TemplateID = = LOT_ZONE_CONTROL ) {
script = ScriptComponent : : GetZoneScriptName ( componentId ) ;
} else {
script = ScriptComponent : : GetScriptName ( this , componentId ) ;
}
AddComponent < ScriptComponent > ( script ) ; // Technically this should check for if the script name is empty and not create a component if it is.
hasScriptComponent = true ;
break ;
}
case eReplicaComponentType : : BOUNCER :
AddComponent < BouncerComponent > ( ) ;
break ;
case eReplicaComponentType : : DESTROYABLE :
if ( hasDestroyableComponent ) continue ;
AddComponent < DestroyableComponent > ( componentId ) ;
hasDestroyableComponent = true ;
break ;
case eReplicaComponentType : : SKILL :
AddComponent < SkillComponent > ( ) ;
break ;
case eReplicaComponentType : : ITEM :
AddComponent < ItemComponent > ( ) ;
break ;
case eReplicaComponentType : : VENDOR :
AddComponent < VendorComponent > ( ) ;
if ( hasProximityMonitorComponent ) continue ;
AddComponent < ProximityMonitorComponent > ( ) ;
hasProximityMonitorComponent = true ;
break ;
case eReplicaComponentType : : INVENTORY :
AddComponent < InventoryComponent > ( ) ;
break ;
case eReplicaComponentType : : SHOOTING_GALLERY :
2023-06-27 05:39:15 +00:00
AddComponent < ShootingGalleryComponent > ( componentId ) ;
2023-06-26 04:47:35 +00:00
break ;
case eReplicaComponentType : : RIGID_BODY_PHANTOM_PHYSICS :
if ( hasPhysicsComponent ) continue ;
AddComponent < RigidbodyPhantomPhysicsComponent > ( ) ;
physicsComponentID = componentId ;
hasPhysicsComponent = true ;
break ;
case eReplicaComponentType : : COLLECTIBLE :
AddComponent < CollectibleComponent > ( ) ;
if ( ! hasDestroyableComponent ) AddComponent < DestroyableComponent > ( componentId ) ;
break ;
case eReplicaComponentType : : MOVING_PLATFORM :
AddComponent < MovingPlatformComponent > ( GetVarAsString ( u " attached_path " ) ) ;
m_IsGhostingCandidate = false ;
break ;
case eReplicaComponentType : : PET :
AddComponent < PetComponent > ( componentId ) ;
AddComponent < MovementAIComponent > ( ) ;
break ;
case eReplicaComponentType : : HAVOK_VEHICLE_PHYSICS : {
if ( hasPhysicsComponent ) continue ;
if ( GetVar < bool > ( u " use_simple_physics " ) ) {
2023-06-24 06:56:13 +00:00
AddComponent < SimplePhysicsComponent > ( componentId ) ;
2023-06-26 04:47:35 +00:00
} else {
auto * havokVehiclePhysicsComponent = AddComponent < HavokVehiclePhysicsComponent > ( ) ;
if ( havokVehiclePhysicsComponent ) {
havokVehiclePhysicsComponent - > SetPosition ( m_DefaultPosition ) ;
havokVehiclePhysicsComponent - > SetRotation ( m_DefaultRotation ) ;
2023-06-24 06:56:13 +00:00
}
2023-06-11 11:37:53 +00:00
}
2023-06-26 04:47:35 +00:00
physicsComponentID = componentId ;
m_IsGhostingCandidate = false ;
hasPhysicsComponent = true ;
break ;
}
case eReplicaComponentType : : MOVEMENT_AI :
AddComponent < MovementAIComponent > ( ) ;
break ;
case eReplicaComponentType : : PROPERTY :
AddComponent < PropertyComponent > ( ) ;
m_IsGhostingCandidate = false ;
break ;
case eReplicaComponentType : : SCRIPTED_ACTIVITY :
AddComponent < ScriptedActivityComponent > ( componentId ) ;
m_IsGhostingCandidate = false ;
break ;
case eReplicaComponentType : : PHANTOM_PHYSICS : {
if ( hasPhysicsComponent ) continue ;
auto * phantomPhysicsComponent = AddComponent < PhantomPhysicsComponent > ( ) ;
if ( phantomPhysicsComponent ) phantomPhysicsComponent - > SetPhysicsEffectActive ( false ) ;
physicsComponentID = componentId ;
hasPhysicsComponent = true ;
m_IsGhostingCandidate = false ;
break ;
}
case eReplicaComponentType : : MODEL_BEHAVIOR : {
AddComponent < ModelBehaviorComponent > ( ) ;
// Get Model Type form ldf
if ( ! hasPhysicsComponent ) {
uint32_t modelType = - 1 ;
if ( modelType = = 0 ) {
if ( physicsComponentID = = - 1 ) physicsComponentID = 4246U ;
AddComponent < ControllablePhysicsComponent > ( ) ;
hasPhysicsComponent = true ;
2023-06-23 17:01:41 +00:00
} else {
2023-06-26 04:47:35 +00:00
if ( physicsComponentID = = - 1 ) physicsComponentID = 4247U ;
2023-06-24 06:56:13 +00:00
AddComponent < SimplePhysicsComponent > ( physicsComponentID ) ;
hasPhysicsComponent = true ;
}
2023-06-11 11:37:53 +00:00
}
2023-06-26 04:47:35 +00:00
if ( hasDestroyableComponent ) continue ;
auto * destroyableComponent = AddComponent < DestroyableComponent > ( componentId ) ;
if ( ! destroyableComponent ) continue ;
destroyableComponent - > SetHealth ( 1 ) ;
destroyableComponent - > SetMaxHealth ( 1.0f ) ;
destroyableComponent - > SetFaction ( - 1 , true ) ;
destroyableComponent - > SetIsSmashable ( true ) ;
hasDestroyableComponent = true ;
break ;
}
case eReplicaComponentType : : PROPERTY_ENTRANCE :
AddComponent < PropertyEntranceComponent > ( componentId ) ;
break ;
case eReplicaComponentType : : PROPERTY_MANAGEMENT :
AddComponent < PropertyManagementComponent > ( ) ;
break ;
case eReplicaComponentType : : QUICK_BUILD :
AddComponent < QuickBuildComponent > ( componentId ) ;
if ( hasDestroyableComponent ) continue ;
AddComponent < DestroyableComponent > ( componentId ) ;
hasDestroyableComponent = true ;
break ;
case eReplicaComponentType : : SWITCH :
AddComponent < SwitchComponent > ( ) ;
break ;
case eReplicaComponentType : : MINIGAME_CONTROL :
2023-06-27 05:39:15 +00:00
AddComponent < MinigameControlComponent > ( componentId ) ;
2023-06-26 04:47:35 +00:00
break ;
case eReplicaComponentType : : BASE_COMBAT_AI : {
auto * baseCombatAiComponent = AddComponent < BaseCombatAIComponent > ( componentId ) ;
if ( baseCombatAiComponent & & baseCombatAiComponent - > GetTetherSpeed ( ) > 0.0f ) {
auto * movementAiComponent = AddComponent < MovementAIComponent > ( ) ;
if ( ! movementAiComponent ) break ;
MovementAIInfo movementAiInfo { } ;
movementAiInfo . movementType = " " ;
movementAiInfo . wanderChance = 0 ;
movementAiInfo . wanderRadius = 16 ;
movementAiInfo . wanderSpeed = 2.5f ;
movementAiInfo . wanderDelayMax = 5 ;
movementAiInfo . wanderDelayMin = 2 ;
movementAiComponent - > SetMoveInfo ( movementAiInfo ) ;
2023-06-12 08:29:43 +00:00
}
2023-06-26 04:47:35 +00:00
break ;
}
case eReplicaComponentType : : MODULE_ASSEMBLY :
AddComponent < ModuleAssemblyComponent > ( ) ;
break ;
case eReplicaComponentType : : PROPERTY_VENDOR :
AddComponent < PropertyVendorComponent > ( ) ;
break ;
case eReplicaComponentType : : ROCKET_LAUNCHPAD_CONTROL :
AddComponent < RocketLaunchpadControlComponent > ( componentId ) ;
break ;
case eReplicaComponentType : : RACING_CONTROL :
2023-06-26 20:06:33 +00:00
AddComponent < RacingComponent > ( componentId ) ;
2023-06-26 04:47:35 +00:00
m_IsGhostingCandidate = false ;
break ;
case eReplicaComponentType : : MISSION_OFFER :
2023-07-06 03:30:52 +00:00
AddComponent < MissionOfferComponent > ( componentId ) ;
2023-06-26 04:47:35 +00:00
break ;
case eReplicaComponentType : : RACING_STATS :
AddComponent < RacingStatsComponent > ( ) ;
break ;
case eReplicaComponentType : : LUP_EXHIBIT :
AddComponent < LUPExhibitComponent > ( ) ;
break ;
case eReplicaComponentType : : SOUND_TRIGGER :
AddComponent < SoundTriggerComponent > ( ) ;
break ;
case eReplicaComponentType : : PROXIMITY_MONITOR :
AddComponent < ProximityMonitorComponent > ( ) ;
break ;
case eReplicaComponentType : : MULTI_ZONE_ENTRANCE :
AddComponent < MultiZoneEntranceComponent > ( ) ;
break ;
case eReplicaComponentType : : BUFF :
AddComponent < BuffComponent > ( ) ;
break ;
case eReplicaComponentType : : RAIL_ACTIVATOR :
AddComponent < RailActivatorComponent > ( componentId ) ;
break ;
case eReplicaComponentType : : POSSESSABLE :
AddComponent < PossessableComponent > ( componentId ) ;
break ;
case eReplicaComponentType : : BUILD_BORDER :
AddComponent < BuildBorderComponent > ( ) ;
break ;
case eReplicaComponentType : : DONATION_VENDOR :
AddComponent < DonationVendorComponent > ( ) ;
if ( hasProximityMonitorComponent ) continue ;
AddComponent < ProximityMonitorComponent > ( ) ;
hasProximityMonitorComponent = true ;
break ;
case eReplicaComponentType : : GATE_RUSH_CONTROL :
2023-06-26 20:06:33 +00:00
AddComponent < GateRushComponent > ( componentId ) ;
2023-06-26 04:47:35 +00:00
break ;
case eReplicaComponentType : : RACING_SOUND_TRIGGER :
AddComponent < RacingSoundTriggerComponent > ( ) ;
break ;
case eReplicaComponentType : : ACHIEVEMENT_VENDOR :
AddComponent < AchievementVendorComponent > ( ) ;
break ;
case eReplicaComponentType : : PROJECTILE_PHYSICS :
if ( hasPhysicsComponent ) continue ;
// AddComponent<ProjectilePhysicsComponent>();
physicsComponentID = componentId ;
hasPhysicsComponent = true ;
break ;
case eReplicaComponentType : : VEHICLE_PHYSICS :
if ( hasPhysicsComponent ) continue ;
// AddComponent<VehiclePhysicsComponent>();
physicsComponentID = componentId ;
hasPhysicsComponent = true ;
break ;
case eReplicaComponentType : : PHYSICS_SYSTEM :
// AddComponent<PhysicsSystemComponent>();
physicsComponentID = componentId ;
hasPhysicsComponent = true ;
break ;
case eReplicaComponentType : : GHOST :
case eReplicaComponentType : : SPAWN :
case eReplicaComponentType : : MODULAR_BUILD :
case eReplicaComponentType : : BUILD_CONTROLLER :
case eReplicaComponentType : : BUILD_ACTIVATOR :
case eReplicaComponentType : : ICON_ONLY :
case eReplicaComponentType : : DROP_EFFECT :
case eReplicaComponentType : : CHEST :
case eReplicaComponentType : : BLUEPRINT :
case eReplicaComponentType : : PLATFORM_BOUNDARY :
case eReplicaComponentType : : MODULE :
case eReplicaComponentType : : JETPACKPAD :
case eReplicaComponentType : : EXHIBIT :
case eReplicaComponentType : : OVERHEAD_ICON :
case eReplicaComponentType : : PET_CONTROL :
case eReplicaComponentType : : MINIFIG :
case eReplicaComponentType : : PET_CREATOR :
case eReplicaComponentType : : MODEL_BUILDER :
case eReplicaComponentType : : SPRINGPAD :
case eReplicaComponentType : : FX :
case eReplicaComponentType : : CHANGLING_BUILD :
case eReplicaComponentType : : CHOICE_BUILD :
case eReplicaComponentType : : PACKAGE :
case eReplicaComponentType : : SOUND_REPEATER :
case eReplicaComponentType : : SOUND_AMBIENT_2D :
case eReplicaComponentType : : SOUND_AMBIENT_3D :
case eReplicaComponentType : : PRECONDITION :
case eReplicaComponentType : : FLAG :
case eReplicaComponentType : : CUSTOM_BUILD_ASSEMBLY :
case eReplicaComponentType : : SHOWCASE_MODEL_HANDLER :
case eReplicaComponentType : : RACING_MODULE :
case eReplicaComponentType : : GENERIC_ACTIVATOR :
case eReplicaComponentType : : HF_LIGHT_DIRECTION_GADGET :
case eReplicaComponentType : : ROCKET_ANIMATION_CONTROL :
case eReplicaComponentType : : TRIGGER :
case eReplicaComponentType : : DROPPED_LOOT :
case eReplicaComponentType : : FACTION_TRIGGER :
case eReplicaComponentType : : BBB :
case eReplicaComponentType : : CHAT_BUBBLE :
case eReplicaComponentType : : FRIENDS_LIST :
case eReplicaComponentType : : GUILD :
case eReplicaComponentType : : LOCAL_SYSTEM :
case eReplicaComponentType : : MISSION :
case eReplicaComponentType : : MUTABLE_MODEL_BEHAVIORS :
case eReplicaComponentType : : PATHFINDING :
case eReplicaComponentType : : PET_TAMING_CONTROL :
case eReplicaComponentType : : PROPERTY_EDITOR :
case eReplicaComponentType : : SKINNED_RENDER :
case eReplicaComponentType : : SLASH_COMMAND :
case eReplicaComponentType : : STATUS_EFFECT :
case eReplicaComponentType : : TEAMS :
case eReplicaComponentType : : TEXT_EFFECT :
case eReplicaComponentType : : TRADE :
case eReplicaComponentType : : USER_CONTROL :
case eReplicaComponentType : : IGNORE_LIST :
case eReplicaComponentType : : INTERACTION_MANAGER :
case eReplicaComponentType : : COMBAT_MEDIATOR :
case eReplicaComponentType : : ROLLER :
case eReplicaComponentType : : PLAYER_FORCED_MOVEMENT :
case eReplicaComponentType : : CRAFTING :
case eReplicaComponentType : : LEVEL_PROGRESSION :
2023-06-27 05:39:15 +00:00
case eReplicaComponentType : : POSSESSION :
2023-06-26 04:47:35 +00:00
case eReplicaComponentType : : MOUNT_CONTROL :
case eReplicaComponentType : : UNKNOWN_112 :
case eReplicaComponentType : : PROPERTY_PLAQUE :
case eReplicaComponentType : : UNKNOWN_115 :
case eReplicaComponentType : : CULLING_PLANE :
case eReplicaComponentType : : NUMBER_OF_COMPONENTS :
case eReplicaComponentType : : INVALID :
default :
Game : : logger - > Log ( " Entity " , " Attempted to create component %i for lot %i but no creator exists. Component will not be created. " , componentId , m_TemplateID ) ;
2021-12-05 17:54:36 +00:00
}
}
2023-06-09 09:46:01 +00:00
2023-06-12 08:29:43 +00:00
AddCallbackTimer ( 0.0f , [ this ] ( ) {
2023-06-12 22:32:46 +00:00
GetScript ( ) - > OnStartup ( this ) ;
2023-06-12 08:29:43 +00:00
} ) ;
2023-06-12 11:37:38 +00:00
// Load data specific to this LOT first. These act as defaults for the components.
2023-06-11 10:06:18 +00:00
std : : for_each ( m_Components . begin ( ) , m_Components . end ( ) , [ this ] ( auto & component ) {
component . second - > LoadTemplateData ( ) ;
} ) ;
2023-06-09 09:46:01 +00:00
2023-06-12 11:27:14 +00:00
// Then load data specific to this Entity. This will vary on an Entity to Entity basis.
// If there is data you want to override the LOT default value, generally you would attach it via LDF
// and it would get loaded and overridden here.
2023-06-11 10:06:18 +00:00
std : : for_each ( m_Components . begin ( ) , m_Components . end ( ) , [ this ] ( auto & component ) {
component . second - > LoadConfigData ( ) ;
} ) ;
2023-06-09 09:46:01 +00:00
2023-06-12 11:27:14 +00:00
/**
2023-06-12 22:32:46 +00:00
* Startup all the components . Some components need or want data from other components so
2023-06-12 11:27:14 +00:00
* we want to ensure that
* A ) Most if not all components are newed and ready to be accessed .
* B ) All components have their personal data loaded and ready to be used .
*/
2023-06-11 10:06:18 +00:00
std : : for_each ( m_Components . begin ( ) , m_Components . end ( ) , [ this ] ( auto & component ) {
component . second - > Startup ( ) ;
} ) ;
2023-06-12 11:27:14 +00:00
/**
2023-06-12 22:32:46 +00:00
* Load the player save data from XML . Ideally we do this after all initialization so the player
2023-06-12 11:27:14 +00:00
* save data overrides any defaults that may be applied .
*/
2023-06-12 08:29:43 +00:00
if ( ! IsPlayer ( ) ) std : : for_each ( m_Components . begin ( ) , m_Components . end ( ) , [ this ] ( auto & component ) {
2023-06-11 10:06:18 +00:00
component . second - > LoadFromXml ( m_Character - > GetXMLDoc ( ) ) ;
} ) ;
2023-06-12 08:29:43 +00:00
TriggerEvent ( eTriggerEventType : : CREATE , this ) ;
2023-06-12 11:27:14 +00:00
if ( ! m_Character & & EntityManager : : Instance ( ) - > GetGhostingEnabled ( ) ) IsGhosted ( ) ;
2023-06-12 08:29:43 +00:00
}
void Entity : : IsGhosted ( ) {
2023-06-12 11:27:14 +00:00
// Don't ghost what is likely large scene elements
2023-06-26 04:01:10 +00:00
if ( m_Components . size ( ) = = 2 & & HasComponent ( eReplicaComponentType : : SIMPLE_PHYSICS ) & & HasComponent ( eReplicaComponentType : : RENDER ) ) {
m_IsGhostingCandidate = false ;
} else if ( m_Components . size ( ) = = 3 & & HasComponent ( eReplicaComponentType : : SIMPLE_PHYSICS ) & & HasComponent ( eReplicaComponentType : : RENDER ) & & HasComponent ( eReplicaComponentType : : TRIGGER ) ) {
m_IsGhostingCandidate = false ;
} else if ( EntityManager : : IsExcludedFromGhosting ( GetLOT ( ) ) ) {
m_IsGhostingCandidate = false ;
2023-06-12 08:29:43 +00:00
}
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 {
2023-06-09 08:04:42 +00:00
return ! ( other . m_ObjectID = = m_ObjectID ) ;
2021-12-05 17:54:36 +00:00
}
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 ( ) ;
}
2023-06-15 02:01:31 +00:00
// Fine
2023-06-16 08:56:02 +00:00
void Entity : : Subscribe ( CppScripts : : Script * scriptToAdd , const std : : string & notificationName ) {
Game : : logger - > Log ( " Entity " , " Subscribing a script with notification %s " , notificationName . c_str ( ) ) ;
2022-12-21 22:33:41 +00:00
if ( notificationName = = " HitOrHealResult " | | notificationName = = " Hit " ) {
2023-06-12 11:00:44 +00:00
auto * destroyableComponent = GetComponent < DestroyableComponent > ( ) ;
2023-06-16 08:56:02 +00:00
if ( destroyableComponent ) destroyableComponent - > Subscribe ( scriptToAdd ) ;
2022-12-21 22:33:41 +00:00
}
}
2023-06-15 02:01:31 +00:00
// Fine
2023-06-16 08:56:02 +00:00
void Entity : : Unsubscribe ( CppScripts : : Script * scriptToRemove , const std : : string & notificationName ) {
Game : : logger - > Log ( " Entity " , " Unsubscribing a script with notification %s " , notificationName . c_str ( ) ) ;
2022-12-21 22:33:41 +00:00
if ( notificationName = = " HitOrHealResult " | | notificationName = = " Hit " ) {
2023-06-12 11:00:44 +00:00
auto * destroyableComponent = GetComponent < DestroyableComponent > ( ) ;
2023-06-16 08:56:02 +00:00
if ( destroyableComponent ) destroyableComponent - > Unsubscribe ( scriptToRemove ) ;
2022-12-21 22:33:41 +00:00
}
}
2023-06-15 02:01:31 +00:00
// Fine
2023-06-17 02:53:22 +00:00
void Entity : : AddProximityRadius ( const float proxRadius , const std : : string & name ) {
2023-06-12 11:04:45 +00:00
auto * proximityMonitorComponent = AddComponent < ProximityMonitorComponent > ( ) ;
2023-06-17 02:53:22 +00:00
if ( proximityMonitorComponent ) proximityMonitorComponent - > AddProximityRadius ( proxRadius , name ) ;
2021-12-05 17:54:36 +00:00
}
2023-06-15 02:01:31 +00:00
// Remove in favor of a square constructor
2023-06-17 02:53:22 +00:00
void Entity : : AddProximityRadius ( const BoxDimensions & dimensions , const std : : string & name ) {
2023-06-12 11:04:45 +00:00
auto * proximityMonitorComponent = AddComponent < ProximityMonitorComponent > ( ) ;
2023-06-17 02:53:22 +00:00
if ( proximityMonitorComponent ) proximityMonitorComponent - > AddProximityRadius ( dimensions , name ) ;
2021-12-05 17:54:36 +00:00
}
2023-03-24 23:16:45 +00:00
void Entity : : SetGMLevel ( eGameMasterLevel value ) {
2021-12-05 17:54:36 +00:00
m_GMLevel = value ;
2023-06-15 02:01:31 +00:00
// User m_Character?
2021-12-05 17:54:36 +00:00
if ( GetParentUser ( ) ) {
Character * character = GetParentUser ( ) - > GetLastUsedChar ( ) ;
if ( character ) {
character - > SetGMLevel ( value ) ;
}
}
2023-06-12 11:00:44 +00:00
auto * character = GetComponent < CharacterComponent > ( ) ;
2021-12-05 17:54:36 +00:00
if ( character ) character - > SetGMLevel ( value ) ;
GameMessages : : SendGMLevelBroadcast ( m_ObjectID , value ) ;
}
2023-06-12 22:32:46 +00:00
void Entity : : WriteBaseReplicaData ( RakNet : : BitStream * outBitStream , const 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.
2023-06-15 02:01:31 +00:00
// PetComponent check un-needed since we should be removing the component during construction.
2023-06-08 15:29:17 +00:00
if ( m_Settings . size ( ) > 0 & & ( GetComponent < ModelBehaviorComponent > ( ) & & ! 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 ;
settingStream . Write < uint32_t > ( m_Settings . size ( ) ) ;
for ( LDFBaseData * data : m_Settings ) {
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 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-06-12 11:00:44 +00:00
auto * triggerComponent = GetComponent < TriggerComponent > ( ) ;
2023-06-07 03:48:30 +00:00
if ( 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-06-15 02:01:31 +00:00
outBitStream - > Write < bool > ( m_ParentEntity ! = nullptr | | m_SpawnerID ! = 0 ) ;
2021-12-05 17:54:36 +00:00
if ( m_ParentEntity ! = nullptr | | m_SpawnerID ! = 0 ) {
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 ) ) ) ;
2023-06-15 02:01:31 +00:00
}
2021-12-05 17:54:36 +00:00
outBitStream - > Write ( m_HasSpawnerNodeID ) ;
if ( m_HasSpawnerNodeID ) outBitStream - > Write ( m_SpawnerNodeID ) ;
//outBitStream->Write0(); //Spawner node id
2023-06-15 02:01:31 +00:00
outBitStream - > Write < bool > ( m_Scale ! = 1.0f | | m_Scale ! = 0.0f ) ;
if ( m_Scale ! = 1.0f | | m_Scale ! = 0.0f ) outBitStream - > Write ( m_Scale ) ;
2021-12-05 17:54:36 +00:00
outBitStream - > Write0 ( ) ; //ObjectWorldState
2023-06-15 02:01:31 +00:00
outBitStream - > Write ( m_GMLevel ! = eGameMasterLevel : : CIVILIAN ) ;
2023-03-24 23:16:45 +00:00
if ( m_GMLevel ! = eGameMasterLevel : : CIVILIAN ) {
2021-12-05 17:54:36 +00:00
outBitStream - > Write ( m_GMLevel ) ;
2023-06-15 02:01:31 +00:00
}
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-06-15 02:01:31 +00:00
outBitStream - > Write < uint16_t > ( m_ChildEntities . size ( ) ) ;
2021-12-05 17:54:36 +00:00
for ( Entity * child : m_ChildEntities ) {
2023-06-15 02:01:31 +00:00
outBitStream - > Write < LWOOBJID > ( child - > GetObjectID ( ) ) ;
2021-12-05 17:54:36 +00:00
}
}
}
}
2023-06-15 02:01:31 +00:00
// uh
2023-06-12 22:32:46 +00:00
void Entity : : WriteComponents ( RakNet : : BitStream * outBitStream , const eReplicaPacketType packetType ) {
2021-12-05 17:54:36 +00:00
}
2023-06-15 02:01:31 +00:00
// We should be able to use this at some point
2021-12-05 17:54:36 +00:00
void Entity : : ResetFlags ( ) {
// Unused
}
void Entity : : UpdateXMLDoc ( tinyxml2 : : XMLDocument * doc ) {
2023-06-15 02:01:31 +00:00
DluAssert ( doc ! = nullptr ) ;
2023-06-26 04:01:10 +00:00
for ( const auto & [ componentId , component ] : m_Components ) {
2023-06-17 09:39:33 +00:00
if ( component ) component - > UpdateXml ( doc ) ;
2021-12-05 17:54:36 +00:00
}
}
2023-06-12 22:32:46 +00:00
CppScripts : : Script * Entity : : GetScript ( ) const {
auto * scriptComponent = GetComponent < ScriptComponent > ( ) ;
2023-06-14 02:47:14 +00:00
if ( ! scriptComponent ) return CppScripts : : invalidScript . get ( ) ;
2023-06-12 22:32:46 +00:00
auto * script = scriptComponent - > GetScript ( ) ;
DluAssert ( script ! = nullptr ) ;
return script ;
}
2021-12-05 17:54:36 +00:00
void Entity : : Update ( const float deltaTime ) {
2023-06-15 06:16:31 +00:00
auto namedTimerItr = std : : remove_if ( m_Timers . begin ( ) , m_Timers . end ( ) , [ this , & deltaTime ] ( const std : : unique_ptr < EntityTimer > & timer ) {
2023-06-12 22:32:46 +00:00
timer - > Update ( deltaTime ) ;
if ( timer - > GetTime ( ) < = 0 ) {
GetScript ( ) - > OnTimerDone ( this , timer - > GetName ( ) ) ;
2023-04-18 17:48:03 +00:00
TriggerEvent ( eTriggerEventType : : TIMER_DONE , this ) ;
2023-06-12 22:32:46 +00:00
return true ;
2021-12-05 17:54:36 +00:00
}
2023-06-12 22:32:46 +00:00
return false ;
} ) ;
m_Timers . erase ( namedTimerItr , m_Timers . end ( ) ) ;
2021-12-05 17:54:36 +00:00
2023-06-15 06:16:31 +00:00
auto callbackTimerItr = std : : remove_if ( m_CallbackTimers . begin ( ) , m_CallbackTimers . end ( ) , [ this , & deltaTime ] ( const std : : unique_ptr < EntityCallbackTimer > & timer ) {
2023-06-12 22:32:46 +00:00
timer - > Update ( deltaTime ) ;
if ( timer - > GetTime ( ) < = 0 ) {
2023-06-15 02:01:31 +00:00
timer - > ExecuteCallback ( ) ;
2023-06-12 22:32:46 +00:00
return true ;
2021-12-05 17:54:36 +00:00
}
2023-06-12 22:32:46 +00:00
return false ;
} ) ;
m_CallbackTimers . erase ( callbackTimerItr , m_CallbackTimers . end ( ) ) ;
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.
2023-06-15 06:16:31 +00:00
if ( ! m_PendingTimers . empty ( ) ) {
this - > m_Timers . reserve ( m_Timers . size ( ) + m_PendingTimers . size ( ) ) ;
for ( auto & timer : m_PendingTimers ) {
this - > m_Timers . push_back ( std : : move ( timer ) ) ;
}
2022-07-17 01:21:35 +00:00
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 ;
}
2023-06-15 02:01:31 +00:00
Wake ( ) ;
2021-12-05 17:54:36 +00:00
2023-06-14 03:01:51 +00:00
GetScript ( ) - > OnUpdate ( this ) ;
2021-12-05 17:54:36 +00:00
2023-06-15 02:01:31 +00:00
for ( const auto & [ componentId , component ] : m_Components ) {
if ( component ) component - > Update ( deltaTime ) ;
2021-12-05 17:54:36 +00:00
}
2023-06-15 02:01:31 +00:00
if ( m_ShouldDestroyAfterUpdate ) EntityManager : : Instance ( ) - > DestroyEntity ( this ) ;
2021-12-05 17:54:36 +00:00
}
void Entity : : OnCollisionProximity ( LWOOBJID otherEntity , const std : : string & proxName , const std : : string & status ) {
2023-06-15 02:01:31 +00:00
auto * other = EntityManager : : Instance ( ) - > GetEntity ( otherEntity ) ;
2021-12-05 17:54:36 +00:00
if ( ! other ) return ;
2023-06-14 03:01:51 +00:00
GetScript ( ) - > OnProximityUpdate ( this , other , proxName , status ) ;
2021-12-05 17:54:36 +00:00
2023-06-15 02:01:31 +00:00
auto * rocketLaunchpadControlComponent = GetComponent < RocketLaunchpadControlComponent > ( ) ;
if ( ! rocketLaunchpadControlComponent ) return ;
2021-12-05 17:54:36 +00:00
2023-06-15 02:01:31 +00:00
rocketLaunchpadControlComponent - > OnProximityUpdate ( other , proxName , status ) ;
2021-12-05 17:54:36 +00:00
}
void Entity : : OnCollisionPhantom ( const LWOOBJID otherEntity ) {
auto * other = EntityManager : : Instance ( ) - > GetEntity ( otherEntity ) ;
if ( ! other ) return ;
2023-06-14 03:01:51 +00:00
GetScript ( ) - > OnCollisionPhantom ( this , other ) ;
2021-12-05 17:54:36 +00:00
2023-06-15 02:01:31 +00:00
std : : for_each ( m_PhantomCollisionCallbacks . begin ( ) , m_PhantomCollisionCallbacks . end ( ) , [ other ] ( const auto & callback ) {
2022-07-28 13:39:57 +00:00
callback ( other ) ;
2023-06-15 02:01:31 +00:00
} ) ;
2021-12-05 17:54:36 +00:00
2023-06-15 02:01:31 +00:00
auto * switchComponent = GetComponent < SwitchComponent > ( ) ;
if ( switchComponent ) switchComponent - > EntityEnter ( other ) ;
2021-12-05 17:54:36 +00:00
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 ( ) ) {
2023-06-09 08:27:05 +00:00
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
}
}
2023-06-16 08:56:02 +00:00
if ( ! other - > IsDead ( ) ) {
2023-06-12 11:00:44 +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 ) {
2021-12-05 17:54:36 +00:00
auto * other = EntityManager : : Instance ( ) - > GetEntity ( otherEntity ) ;
if ( ! other ) return ;
2023-06-14 03:01:51 +00:00
GetScript ( ) - > OnOffCollisionPhantom ( this , other ) ;
2023-04-12 16:46:31 +00:00
2023-02-10 08:29:53 +00:00
TriggerEvent ( eTriggerEventType : : EXIT , other ) ;
2021-12-05 17:54:36 +00:00
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 ) {
2023-06-14 03:01:51 +00:00
GetScript ( ) - > 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 ) {
2023-06-14 03:01:51 +00:00
GetScript ( ) - > 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 ) {
2023-06-14 03:01:51 +00:00
GetScript ( ) - > OnCinematicUpdate ( self , sender , event , pathName , pathTime , totalTime , waypoint ) ;
2021-12-05 17:54:36 +00:00
}
2023-06-16 08:01:13 +00:00
void Entity : : CancelCallbackTimers ( ) {
m_CallbackTimers . clear ( ) ;
}
void Entity : : NotifyObject ( Entity * sender , const std : : u16string & name , int32_t param1 , int32_t param2 ) {
GameMessages : : SendNotifyObject ( GetObjectID ( ) , sender - > GetObjectID ( ) , name , UNASSIGNED_SYSTEM_ADDRESS , param1 , param2 ) ;
2021-12-05 17:54:36 +00:00
2023-06-14 03:01:51 +00:00
GetScript ( ) - > 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 ) {
2023-06-14 03:01:51 +00:00
GetScript ( ) - > OnEmoteReceived ( this , emote , target ) ;
2021-12-05 17:54:36 +00:00
}
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
2023-06-14 03:01:51 +00:00
GetScript ( ) - > OnUse ( this , originator ) ;
2021-12-05 17:54:36 +00:00
2023-06-15 02:01:31 +00:00
for ( const auto & [ componentId , component ] : m_Components ) {
if ( component ) component - > OnUse ( originator ) ;
2021-12-05 17:54:36 +00:00
}
}
void Entity : : OnHitOrHealResult ( Entity * attacker , int32_t damage ) {
2023-06-14 03:01:51 +00:00
GetScript ( ) - > OnHitOrHealResult ( this , attacker , damage ) ;
2021-12-05 17:54:36 +00:00
}
void Entity : : OnHit ( Entity * attacker ) {
2023-03-25 10:26:39 +00:00
TriggerEvent ( eTriggerEventType : : HIT , attacker ) ;
2023-06-14 03:01:51 +00:00
GetScript ( ) - > OnHit ( this , attacker ) ;
2021-12-05 17:54:36 +00:00
}
2022-07-28 13:39:57 +00:00
void Entity : : OnZonePropertyEditBegin ( ) {
2023-06-14 03:01:51 +00:00
GetScript ( ) - > OnZonePropertyEditBegin ( this ) ;
2021-12-05 17:54:36 +00:00
}
2022-07-28 13:39:57 +00:00
void Entity : : OnZonePropertyEditEnd ( ) {
2023-06-14 03:01:51 +00:00
GetScript ( ) - > OnZonePropertyEditEnd ( this ) ;
2021-12-05 17:54:36 +00:00
}
2022-07-28 13:39:57 +00:00
void Entity : : OnZonePropertyModelEquipped ( ) {
2023-06-14 03:01:51 +00:00
GetScript ( ) - > OnZonePropertyModelEquipped ( this ) ;
2021-12-05 17:54:36 +00:00
}
2022-07-28 13:39:57 +00:00
void Entity : : OnZonePropertyModelPlaced ( Entity * player ) {
2023-06-14 03:01:51 +00:00
GetScript ( ) - > OnZonePropertyModelPlaced ( this , player ) ;
2021-12-05 17:54:36 +00:00
}
2022-07-28 13:39:57 +00:00
void Entity : : OnZonePropertyModelPickedUp ( Entity * player ) {
2023-06-14 03:01:51 +00:00
GetScript ( ) - > OnZonePropertyModelPickedUp ( this , player ) ;
2021-12-05 17:54:36 +00:00
}
2022-07-28 13:39:57 +00:00
void Entity : : OnZonePropertyModelRemoved ( Entity * player ) {
2023-06-14 03:01:51 +00:00
GetScript ( ) - > OnZonePropertyModelRemoved ( this , player ) ;
2021-12-05 17:54:36 +00:00
}
2022-07-28 13:39:57 +00:00
void Entity : : OnZonePropertyModelRemovedWhileEquipped ( Entity * player ) {
2023-06-14 03:01:51 +00:00
GetScript ( ) - > OnZonePropertyModelRemovedWhileEquipped ( this , player ) ;
2021-12-05 17:54:36 +00:00
}
2022-07-28 13:39:57 +00:00
void Entity : : OnZonePropertyModelRotated ( Entity * player ) {
2023-06-14 03:01:51 +00:00
GetScript ( ) - > OnZonePropertyModelRotated ( this , player ) ;
2021-12-05 17:54:36 +00:00
}
2022-07-28 13:39:57 +00:00
void Entity : : OnMessageBoxResponse ( Entity * sender , int32_t button , const std : : u16string & identifier , const std : : u16string & userData ) {
2023-06-14 03:01:51 +00:00
GetScript ( ) - > OnMessageBoxResponse ( this , sender , button , identifier , userData ) ;
2021-12-05 17:54:36 +00:00
}
2022-07-28 13:39:57 +00:00
void Entity : : OnChoiceBoxResponse ( Entity * sender , int32_t button , const std : : u16string & buttonIdentifier , const std : : u16string & identifier ) {
2023-06-14 03:01:51 +00:00
GetScript ( ) - > OnChoiceBoxResponse ( this , sender , button , buttonIdentifier , identifier ) ;
2021-12-05 17:54:36 +00:00
}
2023-06-09 08:04:42 +00:00
void Entity : : RequestActivityExit ( Entity * sender , const LWOOBJID & player , const bool canceled ) {
2023-06-14 03:01:51 +00:00
GetScript ( ) - > OnRequestActivityExit ( sender , player , canceled ) ;
2023-05-11 00:26:04 +00:00
}
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 ;
2023-06-12 11:00:44 +00:00
auto * destroyableComponent = GetComponent < DestroyableComponent > ( ) ;
2023-06-15 02:01:31 +00:00
if ( ! destroyableComponent ) {
2021-12-05 17:54:36 +00:00
Kill ( EntityManager : : Instance ( ) - > GetEntity ( source ) ) ;
return ;
}
2023-06-26 17:36:36 +00:00
auto * possessionComponent = GetComponent < PossessionComponent > ( ) ;
if ( possessionComponent ) {
if ( possessionComponent - > GetPossessable ( ) ! = LWOOBJID_EMPTY ) {
auto * mount = EntityManager : : Instance ( ) - > GetEntity ( possessionComponent - > GetPossessable ( ) ) ;
if ( mount ) possessionComponent - > Dismount ( mount , true ) ;
2022-09-02 18:49:19 +00:00
}
}
2021-12-05 17:54:36 +00:00
destroyableComponent - > Smash ( source , killType , deathType ) ;
}
void Entity : : Kill ( Entity * murderer ) {
if ( ! m_PlayerIsReadyForUpdates ) return ;
2023-06-15 02:01:31 +00:00
for ( const auto & cb : m_DieCallbacks ) cb ( ) ;
2021-12-05 17:54:36 +00:00
m_DieCallbacks . clear ( ) ;
//OMAI WA MOU, SHINDERIU
2023-06-14 03:01:51 +00:00
GetScript ( ) - > OnDie ( this , murderer ) ;
2021-12-05 17:54:36 +00:00
2023-06-15 02:01:31 +00:00
if ( m_Spawner ) m_Spawner - > NotifyOfEntityDeath ( m_ObjectID ) ;
2021-12-05 17:54:36 +00:00
2023-06-15 02:01:31 +00:00
if ( ! IsPlayer ( ) ) EntityManager : : Instance ( ) - > DestroyEntity ( this ) ;
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 ( ) ) {
2021-12-05 17:54:36 +00:00
auto spawners = dZoneManager : : Instance ( ) - > GetSpawnersByName ( grpNameQBShowBricks ) ;
Spawner * spawner = nullptr ;
2022-07-28 13:39:57 +00:00
if ( ! spawners . empty ( ) ) {
2023-06-15 02:01:31 +00:00
spawner = spawners . front ( ) ;
2022-07-28 13:39:57 +00:00
} else {
2021-12-05 17:54:36 +00:00
spawners = dZoneManager : : Instance ( ) - > GetSpawnersInGroup ( grpNameQBShowBricks ) ;
2023-06-15 02:01:31 +00:00
if ( ! spawners . empty ( ) ) spawner = spawners . front ( ) ;
2021-12-05 17:54:36 +00:00
}
2023-06-15 02:01:31 +00:00
if ( spawner ) spawner - > Spawn ( ) ;
2021-12-05 17:54:36 +00:00
}
2022-07-28 13:39:57 +00:00
// Track a player being smashed
2023-06-12 11:00:44 +00:00
auto * characterComponent = GetComponent < CharacterComponent > ( ) ;
2023-06-15 02:01:31 +00:00
if ( characterComponent ) {
2022-07-28 13:39:57 +00:00
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
2023-06-16 08:01:13 +00:00
if ( ! murderer ) return ;
auto * murdererCharacterComponent = murderer - > GetComponent < CharacterComponent > ( ) ;
if ( murdererCharacterComponent ) {
murdererCharacterComponent - > UpdatePlayerStatistic ( SmashablesSmashed ) ;
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 : : AddRebuildCompleteCallback ( const std : : function < void ( Entity * user ) > & callback ) const {
2023-06-12 11:00:44 +00:00
auto * quickBuildComponent = GetComponent < QuickBuildComponent > ( ) ;
2023-06-15 02:01:31 +00:00
if ( quickBuildComponent ) quickBuildComponent - > AddRebuildCompleteCallback ( callback ) ;
2021-12-05 17:54:36 +00:00
}
2023-06-16 08:56:02 +00:00
bool Entity : : IsDead ( ) const {
2023-06-12 11:00:44 +00:00
auto * dest = GetComponent < DestroyableComponent > ( ) ;
2023-06-15 02:01:31 +00:00
return dest & & dest - > GetArmor ( ) = = 0 & & dest - > GetHealth ( ) = = 0 ;
2021-12-05 17:54:36 +00:00
}
void Entity : : AddLootItem ( const Loot : : Info & info ) {
if ( ! IsPlayer ( ) ) return ;
2023-06-16 08:01:13 +00:00
auto * player = dynamic_cast < Player * > ( this ) ;
if ( player ) player - > GetDroppedLoot ( ) . insert ( std : : make_pair ( info . id , info ) ) ; // Move this to Player
2021-12-05 17:54:36 +00:00
}
2023-06-15 02:01:31 +00:00
// Replace static_cast with dynamic_cast
2021-12-05 17:54:36 +00:00
void Entity : : PickupItem ( const LWOOBJID & objectID ) {
if ( ! IsPlayer ( ) ) return ;
2023-06-15 02:01:31 +00:00
auto * inventoryComponent = GetComponent < InventoryComponent > ( ) ;
if ( ! inventoryComponent ) return ;
2021-12-05 17:54:36 +00:00
2023-06-15 02:01:31 +00:00
auto * objectsTable = CDClientManager : : Instance ( ) . GetTable < CDObjectsTable > ( ) ;
auto * skillsTable = CDClientManager : : Instance ( ) . GetTable < CDObjectSkillsTable > ( ) ;
2022-07-28 13:39:57 +00:00
2023-06-16 08:01:13 +00:00
auto * player = dynamic_cast < Player * > ( this ) ;
if ( ! player ) return ;
auto & droppedLoot = player - > GetDroppedLoot ( ) ;
2021-12-05 17:54:36 +00:00
2023-06-16 08:01:13 +00:00
auto lootIterator = droppedLoot . find ( objectID ) ;
if ( lootIterator = = droppedLoot . end ( ) ) return ;
const auto & [ objId , loot ] = * lootIterator ;
2023-06-15 02:01:31 +00:00
2023-06-16 08:01:13 +00:00
auto * characterComponent = GetComponent < CharacterComponent > ( ) ;
if ( characterComponent ) characterComponent - > TrackLOTCollection ( loot . lot ) ;
2023-06-15 02:01:31 +00:00
2023-06-16 08:01:13 +00:00
const CDObjects & object = objectsTable - > GetByID ( loot . lot ) ;
if ( object . id ! = 0 & & object . type = = " Powerup " ) {
const auto lootLot = loot . lot ;
auto skills = skillsTable - > Query ( [ lootLot ] ( CDObjectSkills entry ) { return ( entry . objectTemplate = = lootLot ) ; } ) ;
auto * skillBehaviorTable = CDClientManager : : Instance ( ) . GetTable < CDSkillBehaviorTable > ( ) ;
for ( const auto & skill : skills ) {
auto behaviorData = skillBehaviorTable - > GetSkillByID ( skill . skillID ) ;
// This should take a skillID, not a behaviorID.
SkillComponent : : HandleUnmanaged ( behaviorData . behaviorID , GetObjectID ( ) ) ;
2023-06-15 02:01:31 +00:00
2023-06-16 08:01:13 +00:00
auto * missionComponent = GetComponent < MissionComponent > ( ) ;
if ( missionComponent ) missionComponent - > Progress ( eMissionTaskType : : POWERUP , skill . skillID ) ;
2021-12-05 17:54:36 +00:00
}
2023-06-16 08:01:13 +00:00
} else {
inventoryComponent - > AddItem ( loot . lot , loot . count , eLootSourceType : : PICKUP , eInventoryType : : INVALID , { } , LWOOBJID_EMPTY , true , false , LWOOBJID_EMPTY , eInventoryType : : INVALID , 1 ) ;
2021-12-05 17:54:36 +00:00
}
2023-06-16 08:01:13 +00:00
droppedLoot . erase ( lootIterator ) ;
2021-12-05 17:54:36 +00:00
}
2023-06-15 02:01:31 +00:00
// This functions name is misleading and should not modify the number of dropped coins.
// A separate function, PickupCoins should modify that.
// Replace static_cast with dynamic_cast
2023-06-16 08:01:13 +00:00
bool Entity : : CanPickupCoins ( const uint64_t & count ) const {
2021-12-11 13:21:00 +00:00
if ( ! IsPlayer ( ) ) return false ;
2023-06-16 08:01:13 +00:00
const auto * player = dynamic_cast < const Player * > ( this ) ;
return count < = player - > GetDroppedCoins ( ) ;
}
void Entity : : PickupCoins ( const uint64_t & count ) {
if ( ! IsPlayer ( ) ) return ;
auto * player = dynamic_cast < Player * > ( this ) ;
if ( ! player ) return ;
const auto droppedCoins = player - > GetDroppedCoins ( ) ;
if ( count < = droppedCoins ) player - > SetDroppedCoins ( droppedCoins - count ) ;
2021-12-11 13:21:00 +00:00
}
2023-06-15 02:01:31 +00:00
void Entity : : RegisterCoinDrop ( const uint64_t & coinsDropped ) {
2021-12-11 13:21:00 +00:00
if ( ! IsPlayer ( ) ) return ;
2023-06-16 08:01:13 +00:00
auto * player = dynamic_cast < Player * > ( this ) ;
if ( ! player ) return ;
2023-06-15 02:01:31 +00:00
player - > SetDroppedCoins ( player - > GetDroppedCoins ( ) + coinsDropped ) ;
2021-12-11 13:21:00 +00:00
}
2021-12-05 17:54:36 +00:00
void Entity : : AddChild ( Entity * child ) {
2023-06-17 09:39:33 +00:00
if ( ! child ) return ;
2022-06-16 05:58:38 +00:00
m_IsParentChildDirty = true ;
2023-06-17 09:39:33 +00:00
if ( std : : find ( m_ChildEntities . begin ( ) , m_ChildEntities . end ( ) , child ) = = m_ChildEntities . end ( ) ) m_ChildEntities . push_back ( child ) ;
else Game : : logger - > Log ( " Entity " , " WARNING: Entity (objid:lot) %llu:%i already has (%llu:%i) as a child " , GetObjectID ( ) , GetLOT ( ) , child - > GetObjectID ( ) , child - > GetLOT ( ) ) ;
2021-12-05 17:54:36 +00:00
}
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 ;
2023-06-15 02:01:31 +00:00
auto toRemove = std : : remove ( m_ChildEntities . begin ( ) , m_ChildEntities . end ( ) , child ) ;
2023-06-16 08:01:13 +00:00
if ( toRemove ! = m_ChildEntities . end ( ) ) {
m_ChildEntities . erase ( toRemove , m_ChildEntities . end ( ) ) ;
m_IsParentChildDirty = true ;
}
2022-06-17 00:50:33 +00:00
}
2022-07-17 04:39:13 +00:00
void Entity : : RemoveParent ( ) {
2023-06-15 02:01:31 +00:00
if ( m_ParentEntity ) m_IsParentChildDirty = true ;
2023-06-17 09:39:33 +00:00
else Game : : logger - > Log ( " Entity " , " WARNING: Attempted to remove parent from (objid:lot) (%llu:%i) when no parent existed " , GetObjectID ( ) , GetLOT ( ) ) ;
2022-07-17 04:39:13 +00:00
this - > m_ParentEntity = nullptr ;
}
2023-06-09 08:04:42 +00:00
void Entity : : AddTimer ( const std : : string & name , float time ) {
2023-06-15 06:16:31 +00:00
m_PendingTimers . emplace_back ( std : : make_unique < EntityTimer > ( name , time ) ) ;
2021-12-05 17:54:36 +00:00
}
2023-06-09 08:04:42 +00:00
void Entity : : AddCallbackTimer ( const float time , const std : : function < void ( ) > & callback ) {
2023-06-15 06:16:31 +00:00
m_CallbackTimers . emplace_back ( std : : make_unique < EntityCallbackTimer > ( time , callback ) ) ;
2021-12-05 17:54:36 +00:00
}
2022-07-28 13:39:57 +00:00
bool Entity : : HasTimer ( const std : : string & name ) {
2023-06-15 06:16:31 +00:00
auto possibleTimer = std : : find_if ( m_Timers . begin ( ) , m_Timers . end ( ) , [ name ] ( const std : : unique_ptr < EntityTimer > & timer ) {
2023-06-15 02:01:31 +00:00
return timer - > GetName ( ) = = name ;
} ) ;
return possibleTimer ! = m_Timers . end ( ) ;
2021-12-05 17:54:36 +00:00
}
void Entity : : ScheduleKillAfterUpdate ( Entity * murderer ) {
EntityManager : : Instance ( ) - > ScheduleForKill ( this ) ;
if ( murderer ) m_ScheduleKiller = murderer ;
}
void Entity : : CancelTimer ( const std : : string & name ) {
2023-06-15 06:16:31 +00:00
auto toErase = std : : remove_if ( m_Timers . begin ( ) , m_Timers . end ( ) , [ & name ] ( const std : : unique_ptr < EntityTimer > & timer ) {
return timer - > GetName ( ) = = name ;
} ) ;
2023-06-15 02:01:31 +00:00
m_Timers . erase ( m_Timers . begin ( ) , toErase ) ;
2021-12-05 17:54:36 +00:00
}
2023-06-16 08:01:13 +00:00
2021-12-05 17:54:36 +00:00
void Entity : : CancelAllTimers ( ) {
m_Timers . clear ( ) ;
2023-06-16 08:01:13 +00:00
CancelCallbackTimers ( ) ;
2021-12-05 17:54:36 +00:00
}
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 ) {
2023-06-12 11:00:44 +00:00
auto * triggerComponent = GetComponent < TriggerComponent > ( ) ;
2023-02-10 08:29:53 +00:00
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 ) {
2021-12-05 17:54:36 +00:00
auto * other = EntityManager : : Instance ( ) - > GetEntity ( m_OwnerOverride ) ;
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
void Entity : : SetObservers ( int8_t value ) {
2023-06-16 08:01:13 +00:00
if ( value < 0 ) value = 0 ;
2021-12-05 17:54:36 +00:00
m_Observers = value ;
}
2022-07-28 13:39:57 +00:00
void Entity : : Sleep ( ) {
2023-06-12 11:00:44 +00:00
auto * baseCombatAIComponent = GetComponent < BaseCombatAIComponent > ( ) ;
2023-06-15 09:13:25 +00:00
if ( baseCombatAIComponent ) baseCombatAIComponent - > Sleep ( ) ;
2021-12-05 17:54:36 +00:00
}
2022-07-28 13:39:57 +00:00
void Entity : : Wake ( ) {
2023-06-12 11:00:44 +00:00
auto * baseCombatAIComponent = GetComponent < BaseCombatAIComponent > ( ) ;
2023-06-15 09:13:25 +00:00
if ( baseCombatAIComponent ) baseCombatAIComponent - > Wake ( ) ;
2021-12-05 17:54:36 +00:00
}
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 ;
}
2023-06-16 08:01:13 +00:00
// The following 3 should share a base component class so we can else if it.
2022-07-28 13:39:57 +00:00
const NiPoint3 & Entity : : GetPosition ( ) const {
2023-06-15 09:13:25 +00:00
auto * controllablePhysicsComponent = GetComponent < ControllablePhysicsComponent > ( ) ;
2021-12-05 17:54:36 +00:00
2023-06-15 09:13:25 +00:00
if ( controllablePhysicsComponent ! = nullptr ) {
return controllablePhysicsComponent - > GetPosition ( ) ;
2021-12-05 17:54:36 +00:00
}
2023-06-15 09:13:25 +00:00
auto * phantomPhysicsComponent = GetComponent < PhantomPhysicsComponent > ( ) ;
2021-12-05 17:54:36 +00:00
2023-06-15 09:13:25 +00:00
if ( phantomPhysicsComponent ! = nullptr ) {
return phantomPhysicsComponent - > GetPosition ( ) ;
2021-12-05 17:54:36 +00:00
}
2023-06-15 09:13:25 +00:00
auto * simplePhysicsComponent = GetComponent < SimplePhysicsComponent > ( ) ;
2021-12-05 17:54:36 +00:00
2023-06-15 09:13:25 +00:00
if ( simplePhysicsComponent ! = nullptr ) {
return simplePhysicsComponent - > GetPosition ( ) ;
2021-12-05 17:54:36 +00:00
}
2023-06-15 09:13:25 +00:00
auto * vehiclePhysicsComponent = GetComponent < HavokVehiclePhysicsComponent > ( ) ;
2021-12-05 17:54:36 +00:00
2023-06-15 09:13:25 +00:00
if ( vehiclePhysicsComponent ! = nullptr ) {
return vehiclePhysicsComponent - > GetPosition ( ) ;
2021-12-05 17:54:36 +00:00
}
return NiPoint3 : : ZERO ;
}
2022-07-28 13:39:57 +00:00
const NiQuaternion & Entity : : GetRotation ( ) const {
2023-06-15 09:13:25 +00:00
auto * controllablePhysicsComponent = GetComponent < ControllablePhysicsComponent > ( ) ;
2021-12-05 17:54:36 +00:00
2023-06-15 09:13:25 +00:00
if ( controllablePhysicsComponent ! = nullptr ) {
return controllablePhysicsComponent - > GetRotation ( ) ;
2021-12-05 17:54:36 +00:00
}
2023-06-15 09:13:25 +00:00
auto * phantomPhysicsComponent = GetComponent < PhantomPhysicsComponent > ( ) ;
2021-12-05 17:54:36 +00:00
2023-06-15 09:13:25 +00:00
if ( phantomPhysicsComponent ! = nullptr ) {
return phantomPhysicsComponent - > GetRotation ( ) ;
2021-12-05 17:54:36 +00:00
}
2023-06-15 09:13:25 +00:00
auto * simplePhysicsComponent = GetComponent < SimplePhysicsComponent > ( ) ;
2021-12-05 17:54:36 +00:00
2023-06-15 09:13:25 +00:00
if ( simplePhysicsComponent ! = nullptr ) {
return simplePhysicsComponent - > GetRotation ( ) ;
2021-12-05 17:54:36 +00:00
}
2022-07-28 13:39:57 +00:00
2023-06-15 09:13:25 +00:00
auto * vehiclePhysicsComponent = GetComponent < HavokVehiclePhysicsComponent > ( ) ;
2021-12-05 17:54:36 +00:00
2023-06-15 09:13:25 +00:00
if ( vehiclePhysicsComponent ! = nullptr ) {
return vehiclePhysicsComponent - > GetRotation ( ) ;
2021-12-05 17:54:36 +00:00
}
return NiQuaternion : : IDENTITY ;
}
2023-06-09 08:04:42 +00:00
void Entity : : SetPosition ( const NiPoint3 & position ) {
2023-06-15 09:13:25 +00:00
auto * controllablePhysicsComponent = GetComponent < ControllablePhysicsComponent > ( ) ;
2021-12-05 17:54:36 +00:00
2023-06-15 09:13:25 +00:00
if ( controllablePhysicsComponent ! = nullptr ) {
controllablePhysicsComponent - > SetPosition ( position ) ;
2021-12-05 17:54:36 +00:00
}
2023-06-15 09:13:25 +00:00
auto * phantomPhysicsComponent = GetComponent < PhantomPhysicsComponent > ( ) ;
2021-12-05 17:54:36 +00:00
2023-06-15 09:13:25 +00:00
if ( phantomPhysicsComponent ! = nullptr ) {
phantomPhysicsComponent - > SetPosition ( position ) ;
2021-12-05 17:54:36 +00:00
}
2023-06-15 09:13:25 +00:00
auto * simplePhysicsComponent = GetComponent < SimplePhysicsComponent > ( ) ;
2021-12-05 17:54:36 +00:00
2023-06-15 09:13:25 +00:00
if ( simplePhysicsComponent ! = nullptr ) {
simplePhysicsComponent - > SetPosition ( position ) ;
2021-12-05 17:54:36 +00:00
}
2023-06-15 09:13:25 +00:00
auto * vehiclePhysicsComponent = GetComponent < HavokVehiclePhysicsComponent > ( ) ;
2021-12-05 17:54:36 +00:00
2023-06-15 09:13:25 +00:00
if ( vehiclePhysicsComponent ! = nullptr ) {
vehiclePhysicsComponent - > SetPosition ( position ) ;
2021-12-05 17:54:36 +00:00
}
EntityManager : : Instance ( ) - > SerializeEntity ( this ) ;
}
2023-06-09 08:04:42 +00:00
void Entity : : SetRotation ( const NiQuaternion & rotation ) {
2023-06-15 09:13:25 +00:00
auto * controllablePhysicsComponent = GetComponent < ControllablePhysicsComponent > ( ) ;
2021-12-05 17:54:36 +00:00
2023-06-15 09:13:25 +00:00
if ( controllablePhysicsComponent ! = nullptr ) {
controllablePhysicsComponent - > SetRotation ( rotation ) ;
2021-12-05 17:54:36 +00:00
}
2023-06-15 09:13:25 +00:00
auto * phantomPhysicsComponent = GetComponent < PhantomPhysicsComponent > ( ) ;
2021-12-05 17:54:36 +00:00
2023-06-15 09:13:25 +00:00
if ( phantomPhysicsComponent ! = nullptr ) {
phantomPhysicsComponent - > SetRotation ( rotation ) ;
2021-12-05 17:54:36 +00:00
}
2023-06-15 09:13:25 +00:00
auto * simplePhysicsComponent = GetComponent < SimplePhysicsComponent > ( ) ;
2021-12-05 17:54:36 +00:00
2023-06-15 09:13:25 +00:00
if ( simplePhysicsComponent ! = nullptr ) {
simplePhysicsComponent - > SetRotation ( rotation ) ;
2021-12-05 17:54:36 +00:00
}
2023-06-15 09:13:25 +00:00
auto * vehiclePhysicsComponent = GetComponent < HavokVehiclePhysicsComponent > ( ) ;
2021-12-05 17:54:36 +00:00
2023-06-15 09:13:25 +00:00
if ( vehiclePhysicsComponent ! = nullptr ) {
vehiclePhysicsComponent - > SetRotation ( rotation ) ;
2021-12-05 17:54:36 +00:00
}
EntityManager : : Instance ( ) - > SerializeEntity ( this ) ;
}
2022-07-28 13:39:57 +00:00
bool Entity : : HasVar ( const std : : u16string & name ) const {
2023-06-15 09:13:25 +00:00
auto hasVar = std : : find_if ( m_Settings . begin ( ) , m_Settings . end ( ) , [ & name ] ( const LDFBaseData * data ) {
return data - > GetKey ( ) = = name ;
} ) ;
return hasVar ! = m_Settings . end ( ) ;
2021-12-05 17:54:36 +00:00
}
2022-07-28 13:39:57 +00:00
std : : vector < LWOOBJID > & Entity : : GetTargetsInPhantom ( ) {
2023-06-15 09:13:25 +00:00
auto toRemove = std : : remove_if ( m_TargetsInPhantom . begin ( ) , m_TargetsInPhantom . end ( ) , [ this ] ( const LWOOBJID & id ) {
return EntityManager : : Instance ( ) - > GetEntity ( id ) = = nullptr ;
} ) ;
m_TargetsInPhantom . erase ( toRemove , m_TargetsInPhantom . end ( ) ) ;
2021-12-05 17:54:36 +00:00
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 ) {
2023-06-15 09:13:25 +00:00
if ( data & & data - > GetKey ( ) = = name ) return data ;
2021-12-05 17:54:36 +00:00
}
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 ) ;
2023-06-15 09:13:25 +00:00
return data ? data - > GetValueAsString ( ) : " " ;
2021-12-05 17:54:36 +00:00
}
void Entity : : Resurrect ( ) {
2023-06-15 09:13:25 +00:00
if ( IsPlayer ( ) ) GameMessages : : SendResurrect ( this ) ;
2021-12-05 17:54:36 +00:00
}
2023-06-17 09:39:33 +00:00
void Entity : : AddGroup ( 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 ( ) {
2023-06-12 11:00:44 +00:00
auto * inventoryComponent = GetComponent < InventoryComponent > ( ) ;
2022-04-13 08:49:55 +00:00
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 ( ) ) ;
}