Fully re-implemented initialize

This commit is contained in:
David Markowitz 2023-06-12 01:29:43 -07:00
parent fc719cbb0a
commit 36c44ecc83
13 changed files with 444 additions and 260 deletions

View File

@ -56,7 +56,10 @@ const uint32_t LWOCLONEID_INVALID = -1; //!< Invalid LWOCLONEID
const uint16_t LWOINSTANCEID_INVALID = -1; //!< Invalid LWOINSTANCEID const uint16_t LWOINSTANCEID_INVALID = -1; //!< Invalid LWOINSTANCEID
const uint16_t LWOMAPID_INVALID = -1; //!< Invalid LWOMAPID const uint16_t LWOMAPID_INVALID = -1; //!< Invalid LWOMAPID
const uint64_t LWOZONEID_INVALID = 0; //!< Invalid LWOZONEID const uint64_t LWOZONEID_INVALID = 0; //!< Invalid LWOZONEID
const uint32_t ZONE_CONTROL_LOT = 2365; const LOT LOT_ZONE_CONTROL = 2365;
const LOT LOT_3D_AMBIENT_SOUND = 6368;
const LOT LOT_MODEL_IN_WORLD = 14;
const float PI = 3.14159f; const float PI = 3.14159f;

View File

@ -205,6 +205,29 @@ void Entity::ApplyComponentConfig(TemplateComponents& components) const {
} }
} }
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());
}
}
}
void Entity::Initialize() { void Entity::Initialize() {
// A few edge cases to tackle first // A few edge cases to tackle first
const auto triggerInfo = GetVarAsString(u"trigger_id"); const auto triggerInfo = GetVarAsString(u"trigger_id");
@ -222,11 +245,11 @@ void Entity::Initialize() {
TemplateComponents components = componentsRegistry->GetTemplateComponents(m_TemplateID); TemplateComponents components = componentsRegistry->GetTemplateComponents(m_TemplateID);
ApplyComponentWhitelist(components); ApplyComponentWhitelist(components);
ApplyComponentBlacklist(components); ApplyComponentBlacklist(components);
AddPathComponent(components);
// Brick-by-Brick models use custom physics depending on _something_ but the client uses 4246 as the simple // Brick-by-Brick models use custom physics depending on _something_ but the client uses 4246 as the simple
// physics component id and 4247 for phantom physics. We'll just use the simple physics component for now // physics component id and 4247 for phantom physics. We'll just use the simple physics component for now
// since we dont know what the phantom physics are for at the moment. // since we dont know what the phantom physics are for at the moment.
if (GetLOT() == 14) components.emplace_back(eReplicaComponentType::SIMPLE_PHYSICS, 4246U); if (GetLOT() == LOT_MODEL_IN_WORLD) components.emplace_back(eReplicaComponentType::SIMPLE_PHYSICS, 4246U);
for (const auto& [componentTemplate, componentId] : components) { for (const auto& [componentTemplate, componentId] : components) {
switch (componentTemplate) { switch (componentTemplate) {
case eReplicaComponentType::CONTROLLABLE_PHYSICS: case eReplicaComponentType::CONTROLLABLE_PHYSICS:
@ -247,7 +270,7 @@ void Entity::Initialize() {
break; break;
case eReplicaComponentType::SCRIPT: { case eReplicaComponentType::SCRIPT: {
AddComponent<ScriptComponent>(ScriptComponent::GetScriptName(this, componentId)); AddComponent<ScriptComponent>(ScriptComponent::GetScriptName(this, componentId));
if (m_TemplateID == ZONE_CONTROL_LOT) { if (m_TemplateID == LOT_ZONE_CONTROL) {
const auto zoneScript = ScriptComponent::GetZoneScriptName(componentId); const auto zoneScript = ScriptComponent::GetZoneScriptName(componentId);
if (!zoneScript.empty()) AddComponent<ScriptComponent>(zoneScript); if (!zoneScript.empty()) AddComponent<ScriptComponent>(zoneScript);
} }
@ -257,7 +280,7 @@ void Entity::Initialize() {
AddComponent<BouncerComponent>(); AddComponent<BouncerComponent>();
break; break;
case eReplicaComponentType::DESTROYABLE: case eReplicaComponentType::DESTROYABLE:
if (!HasComponent(eReplicaComponentType::DESTROYABLE)) AddComponent<DestroyableComponent>(); if (!HasComponent(eReplicaComponentType::DESTROYABLE)) AddComponent<DestroyableComponent>(componentId);
break; break;
case eReplicaComponentType::SKILL: case eReplicaComponentType::SKILL:
AddComponent<SkillComponent>(); AddComponent<SkillComponent>();
@ -279,13 +302,14 @@ void Entity::Initialize() {
break; break;
case eReplicaComponentType::COLLECTIBLE: case eReplicaComponentType::COLLECTIBLE:
AddComponent<CollectibleComponent>(); AddComponent<CollectibleComponent>();
if (!HasComponent(eReplicaComponentType::DESTROYABLE)) AddComponent<DestroyableComponent>(); if (!HasComponent(eReplicaComponentType::DESTROYABLE)) AddComponent<DestroyableComponent>(componentId);
break; break;
case eReplicaComponentType::MOVING_PLATFORM: case eReplicaComponentType::MOVING_PLATFORM:
AddComponent<MovingPlatformComponent>(GetVarAsString(u"attached_path")); AddComponent<MovingPlatformComponent>(GetVarAsString(u"attached_path"));
break; break;
case eReplicaComponentType::PET: case eReplicaComponentType::PET:
AddComponent<PetComponent>(componentId); AddComponent<PetComponent>(componentId);
AddComponent<MovementAIComponent>();
break; break;
case eReplicaComponentType::HAVOK_VEHICLE_PHYSICS: { case eReplicaComponentType::HAVOK_VEHICLE_PHYSICS: {
auto* havokVehiclePhysicsComponent = AddComponent<HavokVehiclePhysicsComponent>(); auto* havokVehiclePhysicsComponent = AddComponent<HavokVehiclePhysicsComponent>();
@ -295,6 +319,9 @@ void Entity::Initialize() {
} }
break; break;
} }
case eReplicaComponentType::MOVEMENT_AI:
AddComponent<MovementAIComponent>();
break;
case eReplicaComponentType::PROPERTY: case eReplicaComponentType::PROPERTY:
AddComponent<PropertyComponent>(); AddComponent<PropertyComponent>();
break; break;
@ -309,7 +336,7 @@ void Entity::Initialize() {
case eReplicaComponentType::MODEL_BEHAVIOR: { case eReplicaComponentType::MODEL_BEHAVIOR: {
AddComponent<ModelBehaviorComponent>(); AddComponent<ModelBehaviorComponent>();
if (!HasComponent(eReplicaComponentType::DESTROYABLE)) { if (!HasComponent(eReplicaComponentType::DESTROYABLE)) {
auto* destroyableComponent = AddComponent<DestroyableComponent>(); auto* destroyableComponent = AddComponent<DestroyableComponent>(componentId);
if (destroyableComponent) { if (destroyableComponent) {
destroyableComponent->SetHealth(1); destroyableComponent->SetHealth(1);
destroyableComponent->SetMaxHealth(1.0f); destroyableComponent->SetMaxHealth(1.0f);
@ -327,7 +354,7 @@ void Entity::Initialize() {
break; break;
case eReplicaComponentType::QUICK_BUILD: case eReplicaComponentType::QUICK_BUILD:
AddComponent<QuickBuildComponent>(componentId); AddComponent<QuickBuildComponent>(componentId);
if (!HasComponent(eReplicaComponentType::DESTROYABLE)) AddComponent<DestroyableComponent>(); if (!HasComponent(eReplicaComponentType::DESTROYABLE)) AddComponent<DestroyableComponent>(componentId);
break; break;
case eReplicaComponentType::SWITCH: case eReplicaComponentType::SWITCH:
AddComponent<SwitchComponent>(); AddComponent<SwitchComponent>();
@ -335,9 +362,22 @@ void Entity::Initialize() {
case eReplicaComponentType::MINIGAME_CONTROL: case eReplicaComponentType::MINIGAME_CONTROL:
AddComponent<MinigameControlComponent>(); AddComponent<MinigameControlComponent>();
break; break;
case eReplicaComponentType::BASE_COMBAT_AI: case eReplicaComponentType::BASE_COMBAT_AI: {
AddComponent<BaseCombatAIComponent>(componentId); 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);
}
break; break;
}
case eReplicaComponentType::MODULE_ASSEMBLY: case eReplicaComponentType::MODULE_ASSEMBLY:
AddComponent<ModuleAssemblyComponent>(); AddComponent<ModuleAssemblyComponent>();
break; break;
@ -362,6 +402,9 @@ void Entity::Initialize() {
case eReplicaComponentType::SOUND_TRIGGER: case eReplicaComponentType::SOUND_TRIGGER:
AddComponent<SoundTriggerComponent>(); AddComponent<SoundTriggerComponent>();
break; break;
case eReplicaComponentType::PROXIMITY_MONITOR:
AddComponent<ProximityMonitorComponent>();
break;
case eReplicaComponentType::MULTI_ZONE_ENTRANCE: case eReplicaComponentType::MULTI_ZONE_ENTRANCE:
AddComponent<MultiZoneEntranceComponent>(); AddComponent<MultiZoneEntranceComponent>();
break; break;
@ -390,7 +433,6 @@ void Entity::Initialize() {
case eReplicaComponentType::PLATFORM_BOUNDARY: case eReplicaComponentType::PLATFORM_BOUNDARY:
case eReplicaComponentType::MODULE: case eReplicaComponentType::MODULE:
case eReplicaComponentType::JETPACKPAD: case eReplicaComponentType::JETPACKPAD:
case eReplicaComponentType::MOVEMENT_AI:
case eReplicaComponentType::EXHIBIT: case eReplicaComponentType::EXHIBIT:
case eReplicaComponentType::OVERHEAD_ICON: case eReplicaComponentType::OVERHEAD_ICON:
case eReplicaComponentType::PET_CONTROL: case eReplicaComponentType::PET_CONTROL:
@ -419,7 +461,6 @@ void Entity::Initialize() {
case eReplicaComponentType::DROPPED_LOOT: case eReplicaComponentType::DROPPED_LOOT:
case eReplicaComponentType::FACTION_TRIGGER: case eReplicaComponentType::FACTION_TRIGGER:
case eReplicaComponentType::BBB: case eReplicaComponentType::BBB:
case eReplicaComponentType::PROXIMITY_MONITOR:
case eReplicaComponentType::RACING_SOUND_TRIGGER: case eReplicaComponentType::RACING_SOUND_TRIGGER:
case eReplicaComponentType::CHAT_BUBBLE: case eReplicaComponentType::CHAT_BUBBLE:
case eReplicaComponentType::FRIENDS_LIST: case eReplicaComponentType::FRIENDS_LIST:
@ -460,6 +501,13 @@ void Entity::Initialize() {
} }
} }
AddCallbackTimer(0.0f, [this]() {
auto scripts = CppScripts::GetEntityScripts(this);
std::for_each(scripts.begin(), scripts.end(), [this](const auto& script) {
script->OnStartup(this);
});
});
std::for_each(m_Components.begin(), m_Components.end(), [this](auto& component) { std::for_each(m_Components.begin(), m_Components.end(), [this](auto& component) {
component.second->LoadTemplateData(); component.second->LoadTemplateData();
}); });
@ -471,11 +519,47 @@ void Entity::Initialize() {
std::for_each(m_Components.begin(), m_Components.end(), [this](auto& component) { std::for_each(m_Components.begin(), m_Components.end(), [this](auto& component) {
component.second->Startup(); component.second->Startup();
}); });
if (!IsPlayer()) return; // No save data to load for non players // No save data to load for non players
if (!IsPlayer()) std::for_each(m_Components.begin(), m_Components.end(), [this](auto& component) {
std::for_each(m_Components.begin(), m_Components.end(), [this](auto& component) {
component.second->LoadFromXml(m_Character->GetXMLDoc()); component.second->LoadFromXml(m_Character->GetXMLDoc());
}); });
TriggerEvent(eTriggerEventType::CREATE, this);
IsGhosted();
}
void Entity::IsGhosted() {
if (!m_Character && EntityManager::Instance()->GetGhostingEnabled()) {
// Don't ghost what is likely large scene elements
if (HasComponent(eReplicaComponentType::SIMPLE_PHYSICS) && HasComponent(eReplicaComponentType::RENDER) && (m_Components.size() == 2 || (HasComponent(eReplicaComponentType::TRIGGER) && m_Components.size() == 3))) {
return;
}
/* Filter for ghosting candidates.
*
* 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()) &&
!HasComponent(eReplicaComponentType::SCRIPTED_ACTIVITY) &&
!HasComponent(eReplicaComponentType::MOVING_PLATFORM) &&
!HasComponent(eReplicaComponentType::PHANTOM_PHYSICS) &&
!HasComponent(eReplicaComponentType::PROPERTY) &&
!HasComponent(eReplicaComponentType::RACING_CONTROL) &&
!HasComponent(eReplicaComponentType::VEHICLE_PHYSICS)
) {
m_IsGhostingCandidate = true;
}
if (GetLOT() == LOT_3D_AMBIENT_SOUND) m_IsGhostingCandidate = true;
// Special case for collectibles in Ninjago
if (HasComponent(eReplicaComponentType::COLLECTIBLE) && Game::server->GetZoneID() == 2000) {
m_IsGhostingCandidate = true;
}
}
} }
bool Entity::operator==(const Entity& other) const { bool Entity::operator==(const Entity& other) const {

View File

@ -66,6 +66,11 @@ public:
// For adding and removing components based on LDF keys // For adding and removing components based on LDF keys
void ApplyComponentConfig(TemplateComponents& components) const; void ApplyComponentConfig(TemplateComponents& components) const;
// Paths have several components they could add. This function will add them.
void AddPathComponent(TemplateComponents& components) const;
void IsGhosted();
virtual void Initialize(); virtual void Initialize();
bool operator==(const Entity& other) const; bool operator==(const Entity& other) const;

View File

@ -1,4 +1,4 @@
Entity::Initialize() { // Entity::Initialize() {
/** /**
* Setup trigger * Setup trigger
*/ */
@ -204,75 +204,75 @@ Entity::Initialize() {
// if (destroyableComponentID > 0 || collectibleComponentID > 0) { // if (destroyableComponentID > 0 || collectibleComponentID > 0) {
// DestroyableComponent* comp = new DestroyableComponent(this); // DestroyableComponent* comp = new DestroyableComponent(this);
if (m_Character) { // if (m_Character) {
comp->LoadFromXml(m_Character->GetXMLDoc()); // comp->LoadFromXml(m_Character->GetXMLDoc());
} else { // } else {
if (componentID > 0) { // if (componentID > 0) {
// std::vector<CDDestructibleComponent> destCompData = destCompTable->Query([=](CDDestructibleComponent entry) { return (entry.id == componentID); }); // // std::vector<CDDestructibleComponent> destCompData = destCompTable->Query([=](CDDestructibleComponent entry) { return (entry.id == componentID); });
if (destCompData.size() > 0) { // if (destCompData.size() > 0) {
if (HasComponent(eReplicaComponentType::RACING_STATS)) { // if (HasComponent(eReplicaComponentType::RACING_STATS)) {
destCompData[0].imagination = 60; // destCompData[0].imagination = 60;
} // }
comp->SetHealth(destCompData[0].life); // comp->SetHealth(destCompData[0].life);
comp->SetImagination(destCompData[0].imagination); // comp->SetImagination(destCompData[0].imagination);
comp->SetArmor(destCompData[0].armor); // comp->SetArmor(destCompData[0].armor);
comp->SetMaxHealth(destCompData[0].life); // comp->SetMaxHealth(destCompData[0].life);
comp->SetMaxImagination(destCompData[0].imagination); // comp->SetMaxImagination(destCompData[0].imagination);
comp->SetMaxArmor(destCompData[0].armor); // comp->SetMaxArmor(destCompData[0].armor);
comp->SetIsSmashable(destCompData[0].isSmashable); // comp->SetIsSmashable(destCompData[0].isSmashable);
comp->SetLootMatrixID(destCompData[0].LootMatrixIndex); // comp->SetLootMatrixID(destCompData[0].LootMatrixIndex);
// Now get currency information // // Now get currency information
uint32_t npcMinLevel = destCompData[0].level; // uint32_t npcMinLevel = destCompData[0].level;
uint32_t currencyIndex = destCompData[0].CurrencyIndex; // uint32_t currencyIndex = destCompData[0].CurrencyIndex;
CDCurrencyTableTable* currencyTable = CDClientManager::Instance().GetTable<CDCurrencyTableTable>(); // CDCurrencyTableTable* currencyTable = CDClientManager::Instance().GetTable<CDCurrencyTableTable>();
std::vector<CDCurrencyTable> currencyValues = currencyTable->Query([=](CDCurrencyTable entry) { return (entry.currencyIndex == currencyIndex && entry.npcminlevel == npcMinLevel); }); // std::vector<CDCurrencyTable> currencyValues = currencyTable->Query([=](CDCurrencyTable entry) { return (entry.currencyIndex == currencyIndex && entry.npcminlevel == npcMinLevel); });
if (currencyValues.size() > 0) { // if (currencyValues.size() > 0) {
// Set the coins // // Set the coins
comp->SetMinCoins(currencyValues[0].minvalue); // comp->SetMinCoins(currencyValues[0].minvalue);
comp->SetMaxCoins(currencyValues[0].maxvalue); // comp->SetMaxCoins(currencyValues[0].maxvalue);
} // }
// extraInfo overrides // // extraInfo overrides
comp->SetIsSmashable(GetVarAs<int32_t>(u"is_smashable") != 0); // // comp->SetIsSmashable(GetVarAs<int32_t>(u"is_smashable") != 0);
} // }
} else { // } else {
comp->SetHealth(1); // comp->SetHealth(1);
comp->SetArmor(0); // comp->SetArmor(0);
comp->SetMaxHealth(1); // comp->SetMaxHealth(1);
comp->SetMaxArmor(0); // comp->SetMaxArmor(0);
comp->SetIsSmashable(true); // comp->SetIsSmashable(true);
comp->AddFaction(-1); // comp->AddFaction(-1);
comp->AddFaction(6); //Smashables // comp->AddFaction(6); //Smashables
// A race car has 60 imagination, other entities defaults to 0. // // A race car has 60 imagination, other entities defaults to 0.
comp->SetImagination(HasComponent(eReplicaComponentType::RACING_STATS) ? 60 : 0); // comp->SetImagination(HasComponent(eReplicaComponentType::RACING_STATS) ? 60 : 0);
comp->SetMaxImagination(HasComponent(eReplicaComponentType::RACING_STATS) ? 60 : 0); // comp->SetMaxImagination(HasComponent(eReplicaComponentType::RACING_STATS) ? 60 : 0);
} // }
} // }
if (destCompData.size() > 0) { // if (destCompData.size() > 0) {
comp->AddFaction(destCompData[0].faction); // comp->AddFaction(destCompData[0].faction);
std::stringstream ss(destCompData[0].factionList); // std::stringstream ss(destCompData[0].factionList);
std::string token; // std::string token;
while (std::getline(ss, token, ',')) { // while (std::getline(ss, token, ',')) {
if (std::stoi(token) == destCompData[0].faction) continue; // if (std::stoi(token) == destCompData[0].faction) continue;
if (token != "") { // if (token != "") {
comp->AddFaction(std::stoi(token)); // comp->AddFaction(std::stoi(token));
} // }
} // }
} // }
// m_Components.insert(std::make_pair(eReplicaComponentType::DESTROYABLE, comp)); // m_Components.insert(std::make_pair(eReplicaComponentType::DESTROYABLE, comp));
} }
@ -505,64 +505,64 @@ Entity::Initialize() {
// m_Components.insert(std::make_pair(eReplicaComponentType::RAIL_ACTIVATOR, new RailActivatorComponent(this, railComponentID))); // m_Components.insert(std::make_pair(eReplicaComponentType::RAIL_ACTIVATOR, new RailActivatorComponent(this, railComponentID)));
// } // }
int movementAIID = compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::MOVEMENT_AI); // int movementAIID = compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::MOVEMENT_AI);
if (movementAIID > 0) { // if (movementAIID > 0) {
CDMovementAIComponentTable* moveAITable = CDClientManager::Instance().GetTable<CDMovementAIComponentTable>(); // CDMovementAIComponentTable* moveAITable = CDClientManager::Instance().GetTable<CDMovementAIComponentTable>();
std::vector<CDMovementAIComponent> moveAIComp = moveAITable->Query([=](CDMovementAIComponent entry) {return (entry.id == movementAIID); }); // std::vector<CDMovementAIComponent> moveAIComp = moveAITable->Query([=](CDMovementAIComponent entry) {return (entry.id == movementAIID); });
if (moveAIComp.size() > 0) { // if (moveAIComp.size() > 0) {
MovementAIInfo moveInfo = MovementAIInfo(); // MovementAIInfo moveInfo = MovementAIInfo();
moveInfo.movementType = moveAIComp[0].MovementType; // moveInfo.movementType = moveAIComp[0].MovementType;
moveInfo.wanderChance = moveAIComp[0].WanderChance; // moveInfo.wanderChance = moveAIComp[0].WanderChance;
moveInfo.wanderRadius = moveAIComp[0].WanderRadius; // moveInfo.wanderRadius = moveAIComp[0].WanderRadius;
moveInfo.wanderSpeed = moveAIComp[0].WanderSpeed; // moveInfo.wanderSpeed = moveAIComp[0].WanderSpeed;
moveInfo.wanderDelayMax = moveAIComp[0].WanderDelayMax; // moveInfo.wanderDelayMax = moveAIComp[0].WanderDelayMax;
moveInfo.wanderDelayMin = moveAIComp[0].WanderDelayMin; // moveInfo.wanderDelayMin = moveAIComp[0].WanderDelayMin;
bool useWanderDB = GetVar<bool>(u"usewanderdb"); // bool useWanderDB = GetVar<bool>(u"usewanderdb");
if (!useWanderDB) { // if (!useWanderDB) {
const auto wanderOverride = GetVarAs<float>(u"wanderRadius"); // const auto wanderOverride = GetVarAs<float>(u"wanderRadius");
if (wanderOverride != 0.0f) { // if (wanderOverride != 0.0f) {
moveInfo.wanderRadius = wanderOverride; // moveInfo.wanderRadius = wanderOverride;
} // }
} // }
m_Components.insert(std::make_pair(eReplicaComponentType::MOVEMENT_AI, new MovementAIComponent(this, moveInfo))); // m_Components.insert(std::make_pair(eReplicaComponentType::MOVEMENT_AI, new MovementAIComponent(this, moveInfo)));
} // }
} else if (petComponentId > 0 || combatAiId > 0 && GetComponent<BaseCombatAIComponent>()->GetTetherSpeed() > 0) { // } else if (petComponentId > 0 || combatAiId > 0 && GetComponent<BaseCombatAIComponent>()->GetTetherSpeed() > 0) {
MovementAIInfo moveInfo = MovementAIInfo(); // MovementAIInfo moveInfo = MovementAIInfo();
moveInfo.movementType = ""; // moveInfo.movementType = "";
moveInfo.wanderChance = 0; // moveInfo.wanderChance = 0;
moveInfo.wanderRadius = 16; // moveInfo.wanderRadius = 16;
moveInfo.wanderSpeed = 2.5f; // moveInfo.wanderSpeed = 2.5f;
moveInfo.wanderDelayMax = 5; // moveInfo.wanderDelayMax = 5;
moveInfo.wanderDelayMin = 2; // moveInfo.wanderDelayMin = 2;
m_Components.insert(std::make_pair(eReplicaComponentType::MOVEMENT_AI, new MovementAIComponent(this, moveInfo))); // // m_Components.insert(std::make_pair(eReplicaComponentType::MOVEMENT_AI, new MovementAIComponent(this, moveInfo)));
} // }
std::string pathName = GetVarAsString(u"attached_path"); // std::string pathName = GetVarAsString(u"attached_path");
const Path* path = dZoneManager::Instance()->GetZone()->GetPath(pathName); // const Path* path = dZoneManager::Instance()->GetZone()->GetPath(pathName);
//Check to see if we have an attached path and add the appropiate component to handle it: // //Check to see if we have an attached path and add the appropiate component to handle it:
if (path){ // if (path){
// if we have a moving platform path, then we need a moving platform component // // if we have a moving platform path, then we need a moving platform component
if (path->pathType == PathType::MovingPlatform) { // if (path->pathType == PathType::MovingPlatform) {
MovingPlatformComponent* plat = new MovingPlatformComponent(this, pathName); // MovingPlatformComponent* plat = new MovingPlatformComponent(this, pathName);
m_Components.insert(std::make_pair(eReplicaComponentType::MOVING_PLATFORM, plat)); // m_Components.insert(std::make_pair(eReplicaComponentType::MOVING_PLATFORM, plat));
// else if we are a movement path // // else if we are a movement path
} /*else if (path->pathType == PathType::Movement) { // } /*else if (path->pathType == PathType::Movement) {
auto movementAIcomp = GetComponent<MovementAIComponent>(); // auto movementAIcomp = GetComponent<MovementAIComponent>();
if (movementAIcomp){ // if (movementAIcomp){
// TODO: set path in existing movementAIComp // // TODO: set path in existing movementAIComp
} else { // } else {
// TODO: create movementAIcomp and set path // // TODO: create movementAIcomp and set path
} // }
}*/ // }*/
} // }
// else { // else {
// else we still need to setup moving platform if it has a moving platform comp but no path // 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); // int32_t movingPlatformComponentId = compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::MOVING_PLATFORM, -1);
@ -572,70 +572,67 @@ Entity::Initialize() {
// } // }
// } // }
int proximityMonitorID = compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::PROXIMITY_MONITOR); // int proximityMonitorID = compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::PROXIMITY_MONITOR);
if (proximityMonitorID > 0) { // if (proximityMonitorID > 0) {
CDProximityMonitorComponentTable* proxCompTable = CDClientManager::Instance().GetTable<CDProximityMonitorComponentTable>(); // CDProximityMonitorComponentTable* proxCompTable = CDClientManager::Instance().GetTable<CDProximityMonitorComponentTable>();
std::vector<CDProximityMonitorComponent> proxCompData = proxCompTable->Query([=](CDProximityMonitorComponent entry) { return (entry.id == proximityMonitorID); }); // std::vector<CDProximityMonitorComponent> proxCompData = proxCompTable->Query([=](CDProximityMonitorComponent entry) { return (entry.id == proximityMonitorID); });
if (proxCompData.size() > 0) { // if (proxCompData.size() > 0) {
std::vector<std::string> proximityStr = GeneralUtils::SplitString(proxCompData[0].Proximities, ','); // std::vector<std::string> proximityStr = GeneralUtils::SplitString(proxCompData[0].Proximities, ',');
ProximityMonitorComponent* comp = new ProximityMonitorComponent(this, std::stoi(proximityStr[0]), std::stoi(proximityStr[1])); // ProximityMonitorComponent* comp = new ProximityMonitorComponent(this, std::stoi(proximityStr[0]), std::stoi(proximityStr[1]));
m_Components.insert(std::make_pair(eReplicaComponentType::PROXIMITY_MONITOR, comp)); // m_Components.insert(std::make_pair(eReplicaComponentType::PROXIMITY_MONITOR, comp));
} // }
} // }
// Hacky way to trigger these when the object has had a chance to get constructed // Hacky way to trigger these when the object has had a chance to get constructed
AddCallbackTimer(0, [this]() { // AddCallbackTimer(0, [this]() {
for (CppScripts::Script* script : CppScripts::GetEntityScripts(this)) { // for (CppScripts::Script* script : CppScripts::GetEntityScripts(this)) {
script->OnStartup(this); // script->OnStartup(this);
} // }
}); // });
if (!m_Character && EntityManager::Instance()->GetGhostingEnabled()) { // if (!m_Character && EntityManager::Instance()->GetGhostingEnabled()) {
// Don't ghost what is likely large scene elements // // Don't ghost what is likely large scene elements
if (HasComponent(eReplicaComponentType::SIMPLE_PHYSICS) && HasComponent(eReplicaComponentType::RENDER) && (m_Components.size() == 2 || (HasComponent(eReplicaComponentType::TRIGGER) && m_Components.size() == 3))) { // if (HasComponent(eReplicaComponentType::SIMPLE_PHYSICS) && HasComponent(eReplicaComponentType::RENDER) && (m_Components.size() == 2 || (HasComponent(eReplicaComponentType::TRIGGER) && m_Components.size() == 3))) {
goto no_ghosting; // goto no_ghosting;
} // }
/* Filter for ghosting candidates. // /* Filter for ghosting candidates.
* // *
* Don't ghost moving platforms, until we've got proper syncing for those. // * 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 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. // * Don't ghost property related objects, as the client expects those to always be loaded.
*/ // */
if ( // if (
!EntityManager::IsExcludedFromGhosting(GetLOT()) && // !EntityManager::IsExcludedFromGhosting(GetLOT()) &&
!HasComponent(eReplicaComponentType::SCRIPTED_ACTIVITY) && // !HasComponent(eReplicaComponentType::SCRIPTED_ACTIVITY) &&
!HasComponent(eReplicaComponentType::MOVING_PLATFORM) && // !HasComponent(eReplicaComponentType::MOVING_PLATFORM) &&
!HasComponent(eReplicaComponentType::PHANTOM_PHYSICS) && // !HasComponent(eReplicaComponentType::PHANTOM_PHYSICS) &&
!HasComponent(eReplicaComponentType::PROPERTY) && // !HasComponent(eReplicaComponentType::PROPERTY) &&
!HasComponent(eReplicaComponentType::RACING_CONTROL) && // !HasComponent(eReplicaComponentType::RACING_CONTROL) &&
!HasComponent(eReplicaComponentType::VEHICLE_PHYSICS) // !HasComponent(eReplicaComponentType::VEHICLE_PHYSICS)
) // )
//if (HasComponent(eReplicaComponentType::BASE_COMBAT_AI)) // {
{ // m_IsGhostingCandidate = true;
m_IsGhostingCandidate = true; // }
}
if (GetLOT() == 6368) { // if (GetLOT() == 6368) m_IsGhostingCandidate = true;
m_IsGhostingCandidate = true;
}
// Special case for collectibles in Ninjago // // Special case for collectibles in Ninjago
if (HasComponent(eReplicaComponentType::COLLECTIBLE) && Game::server->GetZoneID() == 2000) { // if (HasComponent(eReplicaComponentType::COLLECTIBLE) && Game::server->GetZoneID() == 2000) {
m_IsGhostingCandidate = true; // m_IsGhostingCandidate = true;
} // }
} // }
no_ghosting: // no_ghosting:
TriggerEvent(eTriggerEventType::CREATE, this); // TriggerEvent(eTriggerEventType::CREATE, this);
if (m_Character) { // if (m_Character) {
auto controllablePhysicsComponent = GetComponent<ControllablePhysicsComponent>(); // auto controllablePhysicsComponent = GetComponent<ControllablePhysicsComponent>();
auto levelComponent = GetComponent<LevelProgressionComponent>(); // auto levelComponent = GetComponent<LevelProgressionComponent>();
if (controllablePhysicsComponent && levelComponent) { // if (controllablePhysicsComponent && levelComponent) {
controllablePhysicsComponent->SetSpeedMultiplier(levelComponent->GetSpeedBase() / 500.0f); // controllablePhysicsComponent->SetSpeedMultiplier(levelComponent->GetSpeedBase() / 500.0f);
} // }
} // }
} // }

View File

@ -37,8 +37,9 @@
#include "eGameActivity.h" #include "eGameActivity.h"
#include "CDComponentsRegistryTable.h" #include "CDComponentsRegistryTable.h"
#include "CDCurrencyTableTable.h"
DestroyableComponent::DestroyableComponent(Entity* parent) : Component(parent) { DestroyableComponent::DestroyableComponent(Entity* parent, int32_t componentId) : Component(parent) {
m_iArmor = 0; m_iArmor = 0;
m_fMaxArmor = 0.0f; m_fMaxArmor = 0.0f;
m_iImagination = 0; m_iImagination = 0;
@ -62,6 +63,7 @@ DestroyableComponent::DestroyableComponent(Entity* parent) : Component(parent) {
m_MinCoins = 0; m_MinCoins = 0;
m_MaxCoins = 0; m_MaxCoins = 0;
m_DamageReduction = 0; m_DamageReduction = 0;
m_ComponentId = componentId;
m_ImmuneToBasicAttackCount = 0; m_ImmuneToBasicAttackCount = 0;
m_ImmuneToDamageOverTimeCount = 0; m_ImmuneToDamageOverTimeCount = 0;
@ -73,49 +75,71 @@ DestroyableComponent::DestroyableComponent(Entity* parent) : Component(parent) {
m_ImmuneToQuickbuildInterruptCount = 0; m_ImmuneToQuickbuildInterruptCount = 0;
m_ImmuneToPullToPointCount = 0; m_ImmuneToPullToPointCount = 0;
} }
void DestroyableComponent::Startup() {
DestroyableComponent::~DestroyableComponent() {
} }
void DestroyableComponent::LoadConfigData() {
void DestroyableComponent::Reinitialize(LOT templateID) { SetIsSmashable(m_ParentEntity->GetVarAs<int32_t>(u"is_smashable") != 0);
CDComponentsRegistryTable* compRegistryTable = CDClientManager::Instance().GetTable<CDComponentsRegistryTable>(); }
void DestroyableComponent::LoadTemplateData() {
int32_t buffComponentID = compRegistryTable->GetByIDAndType(templateID, eReplicaComponentType::BUFF); [[unlikely]] if (m_ParentEntity->IsPlayer()) return;
int32_t collectibleComponentID = compRegistryTable->GetByIDAndType(templateID, eReplicaComponentType::COLLECTIBLE); auto* destroyableComponentTable = CDClientManager::Instance().GetTable<CDDestructibleComponentTable>();
int32_t quickBuildComponentID = compRegistryTable->GetByIDAndType(templateID, eReplicaComponentType::QUICK_BUILD); auto destroyableDataLookup = destroyableComponentTable->Query([this](CDDestructibleComponent entry) { return (entry.id == this->m_ComponentId); });
if (m_ComponentId == -1 || destroyableDataLookup.empty()) {
int32_t componentID = 0;
if (collectibleComponentID > 0) componentID = collectibleComponentID;
if (quickBuildComponentID > 0) componentID = quickBuildComponentID;
if (buffComponentID > 0) componentID = buffComponentID;
CDDestructibleComponentTable* destCompTable = CDClientManager::Instance().GetTable<CDDestructibleComponentTable>();
std::vector<CDDestructibleComponent> destCompData = destCompTable->Query([=](CDDestructibleComponent entry) { return (entry.id == componentID); });
if (componentID > 0) {
std::vector<CDDestructibleComponent> destCompData = destCompTable->Query([=](CDDestructibleComponent entry) { return (entry.id == componentID); });
if (destCompData.size() > 0) {
SetHealth(destCompData[0].life);
SetImagination(destCompData[0].imagination);
SetArmor(destCompData[0].armor);
SetMaxHealth(destCompData[0].life);
SetMaxImagination(destCompData[0].imagination);
SetMaxArmor(destCompData[0].armor);
SetIsSmashable(destCompData[0].isSmashable);
}
} else {
SetHealth(1); SetHealth(1);
SetImagination(0);
SetArmor(0); SetArmor(0);
SetMaxHealth(1); SetMaxHealth(1);
SetMaxImagination(0);
SetMaxArmor(0); SetMaxArmor(0);
SetIsSmashable(true); SetIsSmashable(true);
AddFaction(-1);
AddFaction(6); //Smashables
// A race car has 60 imagination, other entities defaults to 0.
SetImagination(m_ParentEntity->HasComponent(eReplicaComponentType::RACING_STATS) ? 60 : 0);
SetMaxImagination(m_ParentEntity->HasComponent(eReplicaComponentType::RACING_STATS) ? 60 : 0);
return;
}
auto destroyableData = destroyableDataLookup.at(0);
if (m_ParentEntity->HasComponent(eReplicaComponentType::RACING_STATS)) {
destroyableData.imagination = 60;
}
SetHealth(destroyableData.life);
SetImagination(destroyableData.imagination);
SetArmor(destroyableData.armor);
SetMaxHealth(destroyableData.life);
SetMaxImagination(destroyableData.imagination);
SetMaxArmor(destroyableData.armor);
SetIsSmashable(destroyableData.isSmashable);
SetLootMatrixID(destroyableData.LootMatrixIndex);
// Now get currency information
uint32_t npcMinLevel = destroyableData.level;
uint32_t currencyIndex = destroyableData.CurrencyIndex;
auto* currencyTable = CDClientManager::Instance().GetTable<CDCurrencyTableTable>();
auto currencyValues = currencyTable->Query([=](CDCurrencyTable entry) { return (entry.currencyIndex == currencyIndex && entry.npcminlevel == npcMinLevel); });
if (currencyValues.size() > 0) {
// Set the coins
SetMinCoins(currencyValues.at(0).minvalue);
SetMaxCoins(currencyValues.at(0).maxvalue);
}
AddFaction(destroyableData.faction);
std::stringstream ss(destroyableData.factionList);
std::string tokenStr;
while (std::getline(ss, tokenStr, ',')) {
int32_t factionToAdd = -2;
if (!GeneralUtils::TryParse(tokenStr, factionToAdd) || factionToAdd == -2 || factionToAdd == destroyableData.faction) continue;
AddFaction(factionToAdd);
} }
} }
@ -661,9 +685,9 @@ void DestroyableComponent::Damage(uint32_t damage, const LWOOBJID source, uint32
} }
//check if hardcore mode is enabled //check if hardcore mode is enabled
if (EntityManager::Instance()->GetHardcoreMode()) { if (EntityManager::Instance()->GetHardcoreMode()) {
DoHardcoreModeDrops(source); DoHardcoreModeDrops(source);
} }
Smash(source, eKillType::VIOLENT, u"", skillID); Smash(source, eKillType::VIOLENT, u"", skillID);
} }
@ -823,16 +847,16 @@ void DestroyableComponent::SetFaction(int32_t factionID, bool ignoreChecks) {
} }
void DestroyableComponent::SetStatusImmunity( void DestroyableComponent::SetStatusImmunity(
const eStateChangeType state, const eStateChangeType state,
const bool bImmuneToBasicAttack, const bool bImmuneToBasicAttack,
const bool bImmuneToDamageOverTime, const bool bImmuneToDamageOverTime,
const bool bImmuneToKnockback, const bool bImmuneToKnockback,
const bool bImmuneToInterrupt, const bool bImmuneToInterrupt,
const bool bImmuneToSpeed, const bool bImmuneToSpeed,
const bool bImmuneToImaginationGain, const bool bImmuneToImaginationGain,
const bool bImmuneToImaginationLoss, const bool bImmuneToImaginationLoss,
const bool bImmuneToQuickbuildInterrupt, const bool bImmuneToQuickbuildInterrupt,
const bool bImmuneToPullToPoint) { const bool bImmuneToPullToPoint) {
if (state == eStateChangeType::POP) { if (state == eStateChangeType::POP) {
if (bImmuneToBasicAttack && m_ImmuneToBasicAttackCount > 0) m_ImmuneToBasicAttackCount -= 1; if (bImmuneToBasicAttack && m_ImmuneToBasicAttackCount > 0) m_ImmuneToBasicAttackCount -= 1;
@ -845,7 +869,7 @@ void DestroyableComponent::SetStatusImmunity(
if (bImmuneToQuickbuildInterrupt && m_ImmuneToQuickbuildInterruptCount > 0) m_ImmuneToQuickbuildInterruptCount -= 1; if (bImmuneToQuickbuildInterrupt && m_ImmuneToQuickbuildInterruptCount > 0) m_ImmuneToQuickbuildInterruptCount -= 1;
if (bImmuneToPullToPoint && m_ImmuneToPullToPointCount > 0) m_ImmuneToPullToPointCount -= 1; if (bImmuneToPullToPoint && m_ImmuneToPullToPointCount > 0) m_ImmuneToPullToPointCount -= 1;
} else if (state == eStateChangeType::PUSH){ } else if (state == eStateChangeType::PUSH) {
if (bImmuneToBasicAttack) m_ImmuneToBasicAttackCount += 1; if (bImmuneToBasicAttack) m_ImmuneToBasicAttackCount += 1;
if (bImmuneToDamageOverTime) m_ImmuneToDamageOverTimeCount += 1; if (bImmuneToDamageOverTime) m_ImmuneToDamageOverTimeCount += 1;
if (bImmuneToKnockback) m_ImmuneToKnockbackCount += 1; if (bImmuneToKnockback) m_ImmuneToKnockbackCount += 1;
@ -972,7 +996,7 @@ void DestroyableComponent::AddOnHitCallback(const std::function<void(Entity*)>&
m_OnHitCallbacks.push_back(callback); m_OnHitCallbacks.push_back(callback);
} }
void DestroyableComponent::DoHardcoreModeDrops(const LWOOBJID source){ void DestroyableComponent::DoHardcoreModeDrops(const LWOOBJID source) {
//check if this is a player: //check if this is a player:
if (m_ParentEntity->IsPlayer()) { if (m_ParentEntity->IsPlayer()) {
//remove hardcore_lose_uscore_on_death_percent from the player's uscore: //remove hardcore_lose_uscore_on_death_percent from the player's uscore:
@ -990,9 +1014,9 @@ void DestroyableComponent::DoHardcoreModeDrops(const LWOOBJID source){
if (inventory) { if (inventory) {
//get the items inventory: //get the items inventory:
auto items = inventory->GetInventory(eInventoryType::ITEMS); auto items = inventory->GetInventory(eInventoryType::ITEMS);
if (items){ if (items) {
auto itemMap = items->GetItems(); auto itemMap = items->GetItems();
if (!itemMap.empty()){ if (!itemMap.empty()) {
for (const auto& item : itemMap) { for (const auto& item : itemMap) {
//drop the item: //drop the item:
if (!item.second) continue; if (!item.second) continue;

View File

@ -21,19 +21,15 @@ class DestroyableComponent : public Component {
public: public:
inline static const eReplicaComponentType ComponentType = eReplicaComponentType::DESTROYABLE; inline static const eReplicaComponentType ComponentType = eReplicaComponentType::DESTROYABLE;
DestroyableComponent(Entity* parentEntity); DestroyableComponent(Entity* parentEntity, int32_t componentId = -1);
~DestroyableComponent() override;
void Startup() override;
void LoadConfigData() override;
void LoadTemplateData() override;
void Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate, uint32_t& flags); void Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate, uint32_t& flags);
void LoadFromXml(tinyxml2::XMLDocument* doc) override; void LoadFromXml(tinyxml2::XMLDocument* doc) override;
void UpdateXml(tinyxml2::XMLDocument* doc) override; void UpdateXml(tinyxml2::XMLDocument* doc) override;
/**
* Initializes the component using a different LOT
* @param templateID the ID to use for initialization
*/
void Reinitialize(LOT templateID);
/** /**
* Sets the health of this entity. Makes sure this is serialized on the next tick and if this is a character its * Sets the health of this entity. Makes sure this is serialized on the next tick and if this is a character its
* stats will also update. * stats will also update.
@ -458,6 +454,8 @@ public:
void DoHardcoreModeDrops(const LWOOBJID source); void DoHardcoreModeDrops(const LWOOBJID source);
private: private:
// The ID of this component
int32_t m_ComponentId;
/** /**
* Whether or not the health should be serialized * Whether or not the health should be serialized
*/ */

View File

@ -35,6 +35,10 @@ void LevelProgressionComponent::LoadFromXml(tinyxml2::XMLDocument* doc) {
uint32_t characterVersion; uint32_t characterVersion;
level->QueryAttribute("cv", &characterVersion); level->QueryAttribute("cv", &characterVersion);
m_CharacterVersion = static_cast<eCharacterVersion>(characterVersion); m_CharacterVersion = static_cast<eCharacterVersion>(characterVersion);
auto* controllablePhysicsComponent = m_ParentEntity->GetComponent<ControllablePhysicsComponent>();
if (!controllablePhysicsComponent) return;
controllablePhysicsComponent->SetSpeedMultiplier(GetSpeedBase() / 500.0f);
} }
void LevelProgressionComponent::Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate, unsigned int& flags) { void LevelProgressionComponent::Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate, unsigned int& flags) {
@ -68,7 +72,7 @@ void LevelProgressionComponent::HandleLevelUp() {
} }
break; break;
case 9: case 9:
SetSpeedBase(static_cast<float>(reward->value) ); SetSpeedBase(static_cast<float>(reward->value));
controllablePhysicsComponent->SetSpeedMultiplier(GetSpeedBase() / 500.0f); controllablePhysicsComponent->SetSpeedMultiplier(GetSpeedBase() / 500.0f);
break; break;
case 11: case 11:
@ -82,7 +86,7 @@ void LevelProgressionComponent::HandleLevelUp() {
if (rewardingItem) GameMessages::NotifyLevelRewards(m_ParentEntity->GetObjectID(), m_ParentEntity->GetSystemAddress(), m_Level, !rewardingItem); if (rewardingItem) GameMessages::NotifyLevelRewards(m_ParentEntity->GetObjectID(), m_ParentEntity->GetSystemAddress(), m_Level, !rewardingItem);
} }
void LevelProgressionComponent::SetRetroactiveBaseSpeed(){ void LevelProgressionComponent::SetRetroactiveBaseSpeed() {
if (m_Level >= 20) m_SpeedBase = 525.0f; if (m_Level >= 20) m_SpeedBase = 525.0f;
auto* controllablePhysicsComponent = m_ParentEntity->GetComponent<ControllablePhysicsComponent>(); auto* controllablePhysicsComponent = m_ParentEntity->GetComponent<ControllablePhysicsComponent>();
if (controllablePhysicsComponent) controllablePhysicsComponent->SetSpeedMultiplier(m_SpeedBase / 500.0f); if (controllablePhysicsComponent) controllablePhysicsComponent->SetSpeedMultiplier(m_SpeedBase / 500.0f);

View File

@ -13,22 +13,18 @@
#include "CDComponentsRegistryTable.h" #include "CDComponentsRegistryTable.h"
#include "CDPhysicsComponentTable.h" #include "CDPhysicsComponentTable.h"
#include "CDMovementAIComponentTable.h"
std::map<LOT, float> MovementAIComponent::m_PhysicsSpeedCache = {}; std::map<LOT, float> MovementAIComponent::m_PhysicsSpeedCache = {};
MovementAIComponent::MovementAIComponent(Entity* parent, MovementAIInfo info) : Component(parent) { MovementAIComponent::MovementAIComponent(Entity* parent, int32_t componentId) : Component(parent) {
m_Info = std::move(info); m_ComponentId = componentId;
m_Done = true; m_Done = true;
m_BaseCombatAI = nullptr; m_BaseCombatAI = nullptr;
m_BaseCombatAI = m_ParentEntity->GetComponent<BaseCombatAIComponent>(); m_BaseCombatAI = m_ParentEntity->GetComponent<BaseCombatAIComponent>();
//Try and fix the insane values:
if (m_Info.wanderRadius > 5.0f) m_Info.wanderRadius = m_Info.wanderRadius * 0.5f;
if (m_Info.wanderRadius > 8.0f) m_Info.wanderRadius = 8.0f;
if (m_Info.wanderSpeed > 0.5f) m_Info.wanderSpeed = m_Info.wanderSpeed * 0.5f;
m_BaseSpeed = GetBaseSpeed(m_ParentEntity->GetLOT()); m_BaseSpeed = GetBaseSpeed(m_ParentEntity->GetLOT());
m_NextWaypoint = GetCurrentPosition(); m_NextWaypoint = GetCurrentPosition();
@ -43,7 +39,48 @@ MovementAIComponent::MovementAIComponent(Entity* parent, MovementAIInfo info) :
m_LockRotation = false; m_LockRotation = false;
} }
MovementAIComponent::~MovementAIComponent() = default; void MovementAIComponent::Startup() {
}
void MovementAIComponent::LoadConfigData() {
bool useWanderDB = m_ParentEntity->GetVar<bool>(u"usewanderdb");
if (!useWanderDB) {
const auto wanderOverride = m_ParentEntity->GetVarAs<float>(u"wanderRadius");
if (wanderOverride != 0.0f) {
m_Info.wanderRadius = wanderOverride;
}
}
}
void MovementAIComponent::LoadTemplateData() {
if (m_ComponentId == -1) return;
auto* movementAiComponentTable = CDClientManager::Instance().GetTable<CDMovementAIComponentTable>();
auto movementEntries = movementAiComponentTable->Query([this](CDMovementAIComponent entry) {return (entry.id == this->m_ComponentId); });
if (movementEntries.empty()) return;
auto movementEntry = movementEntries.at(0);
MovementAIInfo moveInfo{};
moveInfo.movementType = movementEntry.MovementType;
moveInfo.wanderChance = movementEntry.WanderChance;
moveInfo.wanderRadius = movementEntry.WanderRadius;
moveInfo.wanderSpeed = movementEntry.WanderSpeed;
moveInfo.wanderDelayMax = movementEntry.WanderDelayMax;
moveInfo.wanderDelayMin = movementEntry.WanderDelayMin;
this->SetMoveInfo(moveInfo);
}
void MovementAIComponent::SetMoveInfo(const MovementAIInfo& info) {
m_Info = info;
//Try and fix the insane values:
if (m_Info.wanderRadius > 5.0f) m_Info.wanderRadius *= 0.5f;
if (m_Info.wanderRadius > 8.0f) m_Info.wanderRadius = 8.0f;
if (m_Info.wanderSpeed > 0.5f) m_Info.wanderSpeed *= 0.5f;
}
void MovementAIComponent::Update(const float deltaTime) { void MovementAIComponent::Update(const float deltaTime) {
if (m_Interrupted) { if (m_Interrupted) {

View File

@ -23,6 +23,10 @@ class BaseCombatAIComponent;
* Information that describes the different variables used to make an entity move around * Information that describes the different variables used to make an entity move around
*/ */
struct MovementAIInfo { struct MovementAIInfo {
// copy assignment
MovementAIInfo& operator=(const MovementAIInfo& other) = default;
std::string movementType; std::string movementType;
/** /**
@ -59,8 +63,10 @@ class MovementAIComponent : public Component {
public: public:
inline static const eReplicaComponentType ComponentType = eReplicaComponentType::MOVEMENT_AI; inline static const eReplicaComponentType ComponentType = eReplicaComponentType::MOVEMENT_AI;
MovementAIComponent(Entity* parentEntity, MovementAIInfo info); MovementAIComponent(Entity* parentEntity, int32_t componentId = -1);
~MovementAIComponent() override; void Startup() override;
void LoadTemplateData() override;
void LoadConfigData() override;
void Update(float deltaTime) override; void Update(float deltaTime) override;
@ -217,6 +223,7 @@ public:
*/ */
static float GetBaseSpeed(LOT lot); static float GetBaseSpeed(LOT lot);
void SetMoveInfo(const MovementAIInfo& value);
private: private:
/** /**
@ -326,6 +333,8 @@ private:
* Cache of all lots and their respective speeds * Cache of all lots and their respective speeds
*/ */
static std::map<LOT, float> m_PhysicsSpeedCache; static std::map<LOT, float> m_PhysicsSpeedCache;
int32_t m_ComponentId;
}; };
#endif // MOVEMENTAICOMPONENT_H #endif // MOVEMENTAICOMPONENT_H

View File

@ -4,14 +4,13 @@
#include "ControllablePhysicsComponent.h" #include "ControllablePhysicsComponent.h"
#include "EntityManager.h" #include "EntityManager.h"
#include "SimplePhysicsComponent.h" #include "SimplePhysicsComponent.h"
#include "CDClientManager.h"
#include "CDProximityMonitorComponentTable.h"
const std::map<LWOOBJID, dpEntity*> ProximityMonitorComponent::m_EmptyObjectMap = {}; const std::map<LWOOBJID, dpEntity*> ProximityMonitorComponent::m_EmptyObjectMap = {};
ProximityMonitorComponent::ProximityMonitorComponent(Entity* parent, int radiusSmall, int radiusLarge) : Component(parent) { ProximityMonitorComponent::ProximityMonitorComponent(Entity* parent, int32_t componentId) : Component(parent) {
if (radiusSmall != -1 && radiusLarge != -1) { m_ComponentId = componentId;
SetProximityRadius(radiusSmall, "rocketSmall");
SetProximityRadius(radiusLarge, "rocketLarge");
}
} }
ProximityMonitorComponent::~ProximityMonitorComponent() { ProximityMonitorComponent::~ProximityMonitorComponent() {
@ -24,6 +23,25 @@ ProximityMonitorComponent::~ProximityMonitorComponent() {
m_ProximitiesData.clear(); m_ProximitiesData.clear();
} }
void ProximityMonitorComponent::LoadTemplateData() {
if (m_ComponentId == -1) return;
auto* proxCompTable = CDClientManager::Instance().GetTable<CDProximityMonitorComponentTable>();
auto proxCompData = proxCompTable->Query([this](CDProximityMonitorComponent entry) { return (entry.id == this->m_ComponentId); });
if (!proxCompData.empty()) {
float radiusSmall = -1.0f;
float radiusLarge = -1.0f;
auto proximitySplit = GeneralUtils::SplitString(proxCompData[0].Proximities, ',');
if (proximitySplit.size() < 2) return;
GeneralUtils::TryParse(proximitySplit.at(0), radiusSmall);
GeneralUtils::TryParse(proximitySplit.at(1), radiusLarge);
if (radiusSmall != -1.0f && radiusLarge != -1.0f) {
SetProximityRadius(radiusSmall, "rocketSmall");
SetProximityRadius(radiusLarge, "rocketLarge");
}
}
}
void ProximityMonitorComponent::SetProximityRadius(float proxRadius, const std::string& name) { void ProximityMonitorComponent::SetProximityRadius(float proxRadius, const std::string& name) {
dpEntity* en = new dpEntity(m_ParentEntity->GetObjectID(), proxRadius); dpEntity* en = new dpEntity(m_ParentEntity->GetObjectID(), proxRadius);
en->SetPosition(m_ParentEntity->GetPosition()); en->SetPosition(m_ParentEntity->GetPosition());

View File

@ -21,8 +21,10 @@ class ProximityMonitorComponent : public Component {
public: public:
inline static const eReplicaComponentType ComponentType = eReplicaComponentType::PROXIMITY_MONITOR; inline static const eReplicaComponentType ComponentType = eReplicaComponentType::PROXIMITY_MONITOR;
ProximityMonitorComponent(Entity* parentEntity, int smallRadius = -1, int largeRadius = -1); ProximityMonitorComponent(Entity* parentEntity, int32_t componentId = -1);
~ProximityMonitorComponent() override; ~ProximityMonitorComponent() override;
void LoadTemplateData() override;
void Update(float deltaTime) override; void Update(float deltaTime) override;
/** /**
@ -71,6 +73,8 @@ private:
* Default value for the proximity data * Default value for the proximity data
*/ */
static const std::map<LWOOBJID, dpEntity*> m_EmptyObjectMap; static const std::map<LWOOBJID, dpEntity*> m_EmptyObjectMap;
int32_t m_ComponentId = 0;
}; };
#endif // PROXIMITYMONITORCOMPONENT_H #endif // PROXIMITYMONITORCOMPONENT_H

View File

@ -12,5 +12,6 @@ void AgStromlingProperty::OnStartup(Entity* self) {
4 4
}; };
self->AddComponent<MovementAIComponent>(movementInfo); auto* movementAiComponent = self->AddComponent<MovementAIComponent>(0U);
if (movementAiComponent) movementAiComponent->SetMoveInfo(movementInfo);
} }

View File

@ -287,11 +287,11 @@ void SGCannon::OnActivityTimerDone(Entity* self, const std::string& name) {
auto* enemy = EntityManager::Instance()->CreateEntity(info, nullptr, self); auto* enemy = EntityManager::Instance()->CreateEntity(info, nullptr, self);
EntityManager::Instance()->ConstructEntity(enemy); EntityManager::Instance()->ConstructEntity(enemy);
auto movementAI = enemy->AddComponent<MovementAIComponent, MovementAIInfo>({}); auto movementAiComponent = enemy->AddComponent<MovementAIComponent>(0U);
movementAI->SetSpeed(toSpawn.initialSpeed); movementAiComponent->SetSpeed(toSpawn.initialSpeed);
movementAI->SetCurrentSpeed(toSpawn.initialSpeed); movementAiComponent->SetCurrentSpeed(toSpawn.initialSpeed);
movementAI->SetHaltDistance(0.0f); movementAiComponent->SetHaltDistance(0.0f);
std::vector<NiPoint3> pathWaypoints; std::vector<NiPoint3> pathWaypoints;
@ -303,7 +303,7 @@ void SGCannon::OnActivityTimerDone(Entity* self, const std::string& name) {
std::reverse(pathWaypoints.begin(), pathWaypoints.end()); std::reverse(pathWaypoints.begin(), pathWaypoints.end());
} }
movementAI->SetPath(pathWaypoints); movementAiComponent->SetPath(pathWaypoints);
enemy->AddDieCallback([this, self, enemy, name]() { enemy->AddDieCallback([this, self, enemy, name]() {
RegisterHit(self, enemy, name); RegisterHit(self, enemy, name);