diff --git a/dGame/Entity.cpp b/dGame/Entity.cpp index 911a72079..198a584fb 100644 --- a/dGame/Entity.cpp +++ b/dGame/Entity.cpp @@ -625,57 +625,13 @@ void Entity::Initialize() { case eReplicaComponentType::QUICK_BUILD: { const auto quickBuildComponentID = compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::QUICK_BUILD); if (quickBuildComponentID > 0) { - auto* const quickBuildComponent = AddComponent(quickBuildComponentID); + AddComponent(quickBuildComponentID); // A quick build without a destroyable gets one (componentID -1) and is smashable, as the client makes it // (DoObjectComponentLoad); live: health 1 / 1.0, armor 1 / 0, faction -1, smashable (AG LOT 7804) if (!HasComponent(eReplicaComponentType::DESTROYABLE)) { AddComponent(-1, true); } - - CDRebuildComponentTable* const rebCompTable = CDClientManager::GetTable(); - const std::vector rebCompData = rebCompTable->Query([quickBuildComponentID](CDRebuildComponent entry) { return (entry.id == quickBuildComponentID); }); - - if (!rebCompData.empty()) { - quickBuildComponent->SetResetTime(rebCompData[0].reset_time); - quickBuildComponent->SetCompleteTime(rebCompData[0].complete_time); - quickBuildComponent->SetTakeImagination(rebCompData[0].take_imagination); - quickBuildComponent->SetInterruptible(rebCompData[0].interruptible); - quickBuildComponent->SetSelfActivator(rebCompData[0].self_activator); - quickBuildComponent->SetActivityId(rebCompData[0].activityID); - quickBuildComponent->SetPostImaginationCost(rebCompData[0].post_imagination_cost); - quickBuildComponent->SetTimeBeforeSmash(rebCompData[0].time_before_smash); - - const auto rebuildResetTime = GetVar(u"rebuild_reset_time"); - - if (rebuildResetTime != 0.0f) { - quickBuildComponent->SetResetTime(rebuildResetTime); - } - - - // The level's activityID replaces the template's. The client (LWOQuickBuildComponent::LoadDataFromTemplate) - // reads RebuildComponent.activityID over it unless the level sets actIDovrd, but live used the level's: - // the AM Center draw bridge (LOT 12047: level activityID 12047 without actIDovrd, template activity 6, - // the quickbuild rewards) dropped no loot in 4 of 4 live completions. - const auto activityID = GetVar(u"activityID"); - - if (activityID > 0) { - quickBuildComponent->SetActivityId(activityID); - Loot::CacheMatrix(activityID); - } - - const auto timeBeforeSmash = GetVar(u"tmeSmsh"); - - if (timeBeforeSmash > 0) { - quickBuildComponent->SetTimeBeforeSmash(timeBeforeSmash); - } - - const auto compTime = GetVar(u"compTime"); - - if (compTime > 0) { - quickBuildComponent->SetCompleteTime(compTime); - } - } } break; } diff --git a/dGame/dComponents/QuickBuildComponent.cpp b/dGame/dComponents/QuickBuildComponent.cpp index 3c29ddf57..477496ab4 100644 --- a/dGame/dComponents/QuickBuildComponent.cpp +++ b/dGame/dComponents/QuickBuildComponent.cpp @@ -1,4 +1,6 @@ #include "QuickBuildComponent.h" +#include "CDClientManager.h" +#include "CDRebuildComponentTable.h" #include "Entity.h" #include "DestroyableComponent.h" #include "GameMessages.h" @@ -31,12 +33,30 @@ #include "Amf3.h" #include "EconomyLedger.h" -QuickBuildComponent::QuickBuildComponent(Entity* const entity, const int32_t componentID) : Component{ entity, componentID } { +QuickBuildComponent::QuickBuildComponent(Entity* const entity, const int32_t componentID) : ActivityComponent{ entity, componentID } { RegisterMsg(&QuickBuildComponent::OnRequestUse); RegisterMsg(&QuickBuildComponent::OnGetObjectReportInfo); } // The level config: the precondition and the activator's position, then the activator +// The RebuildComponent row, its activity among them (LWOQuickBuildComponent is an activity component in the client) +void QuickBuildComponent::LoadDataFromTemplate() { + const auto componentID = m_ComponentID; + const std::vector rebCompData = CDClientManager::GetTable()->Query([componentID](CDRebuildComponent entry) { return (entry.id == static_cast(componentID)); }); + if (rebCompData.empty()) return; + + SetResetTime(rebCompData[0].reset_time); + SetCompleteTime(rebCompData[0].complete_time); + SetTakeImagination(rebCompData[0].take_imagination); + SetInterruptible(rebCompData[0].interruptible); + SetSelfActivator(rebCompData[0].self_activator); + SetActivityId(rebCompData[0].activityID); + SetPostImaginationCost(rebCompData[0].post_imagination_cost); + SetTimeBeforeSmash(rebCompData[0].time_before_smash); + LoadActivityData(rebCompData[0].activityID); + m_HasRow = true; +} + void QuickBuildComponent::LoadConfigData() { std::u16string checkPreconditions = m_Parent->GetVar(u"CheckPrecondition"); @@ -55,7 +75,34 @@ void QuickBuildComponent::LoadConfigData() { m_ActivatorPosition = m_Parent->GetPosition(); } + // The activator is spawned as it was before the row loaded in LoadDataFromTemplate: without looking at + // self_activator (unchanged behaviour; whether live made activators for self-activating quickbuilds is unchecked) + const bool selfActivator = m_SelfActivator; + m_SelfActivator = false; SpawnActivator(); + m_SelfActivator = selfActivator; + + // The level's settings over the row's + if (!m_HasRow) return; + + const auto rebuildResetTime = m_Parent->GetVar(u"rebuild_reset_time"); + if (rebuildResetTime != 0.0f) SetResetTime(rebuildResetTime); + + // The level's activityID replaces the template's. The client (LWOQuickBuildComponent::LoadDataFromTemplate) + // reads RebuildComponent.activityID over it unless the level sets actIDovrd, but live used the level's: + // the AM Center draw bridge (LOT 12047: level activityID 12047 without actIDovrd, template activity 6, + // the quickbuild rewards) dropped no loot in 4 of 4 live completions. + const auto activityID = m_Parent->GetVar(u"activityID"); + if (activityID > 0) { + SetActivityId(activityID); + Loot::CacheMatrix(activityID); + } + + const auto timeBeforeSmash = m_Parent->GetVar(u"tmeSmsh"); + if (timeBeforeSmash > 0) SetTimeBeforeSmash(timeBeforeSmash); + + const auto compTime = m_Parent->GetVar(u"compTime"); + if (compTime > 0) SetCompleteTime(compTime); } QuickBuildComponent::~QuickBuildComponent() { diff --git a/dGame/dComponents/QuickBuildComponent.h b/dGame/dComponents/QuickBuildComponent.h index 064260088..f897e0fcf 100644 --- a/dGame/dComponents/QuickBuildComponent.h +++ b/dGame/dComponents/QuickBuildComponent.h @@ -6,6 +6,7 @@ #include #include "dCommonVars.h" #include "NiPoint3.h" +#include "ActivityComponent.h" #include "ScriptedActivityComponent.h" #include "Preconditions.h" #include "Component.h" @@ -20,12 +21,13 @@ enum class eQuickBuildFailReason : uint32_t; * consists of an activator that shows a popup and then the actual entity that the bricks are built into. Note * that quick builds are also scripted activities so this shared some logic with the ScriptedActivityComponent. */ -class QuickBuildComponent final : public Component { +class QuickBuildComponent final : public ActivityComponent { public: static constexpr eReplicaComponentType ComponentType = eReplicaComponentType::QUICK_BUILD; QuickBuildComponent(Entity* const entity, const int32_t componentID); + void LoadDataFromTemplate() override; void LoadConfigData() override; ~QuickBuildComponent() override; @@ -361,6 +363,9 @@ private: */ int32_t m_ActivityId = 0; + // Whether the RebuildComponent row was found (the level's settings only apply over a row) + bool m_HasRow = false; + /** * Currently unused */