diff --git a/docs/New-or-Enhanced-Logics.md b/docs/New-or-Enhanced-Logics.md index 4f076826aa..6de98b30a6 100644 --- a/docs/New-or-Enhanced-Logics.md +++ b/docs/New-or-Enhanced-Logics.md @@ -1404,7 +1404,7 @@ FLHKEY.BurstN= ; integer - Forward,Lateral,Height. FLHKey refers to weapon-spec - `ForceWeapon.Cloaked` forces specified weapon to be used against any cloaked targets. - `ForceWeapon.Disguised` forces specified weapon to be used against any disguised targets. - `ForceWeapon.UnderEMP` forces specified weapon to be used if the target is under EMP effect. - - `ForceWeapon.InRange` forces specified a list of weapons to be used once the target is within their `Range`. The first weapon in the listed order satisfied will be selected. Can be applied to both ground and air target if `ForceAAWeapon.InRange` is not set. + - `ForceWeapon.InRange` forces specified a list of weapons to be used once the target is within their `Range`. If `ForceWeapon.InRange.TechnoOnly` set to true, it'll only be forced on TechnoTypes like other forced weapons, otherwise it'll also be forced when attacking empty grounds. The first weapon in the listed order satisfied will be selected. Can be applied to both ground and air target if `ForceAAWeapon.InRange` is not set. - `ForceAAWeapon.InRange` does the same thing but only for air target. Taking priority to `ForceWeapon.InRange`, which means that it can only be applied to ground target when they're both set. - `Force(AA)Weapon.InRange.Overrides` overrides the range when decides which weapon to use. Value from position matching the position from `Force(AA)Weapon.InRange` is used if found, or the weapon's own `Range` if not found or set to a value below 0. - If `Force(AA)Weapon.InRange.ApplyRangeModifiers` is set to true, any applicable weapon range modifiers from the firer are applied to the decision range. @@ -1419,6 +1419,7 @@ ForceWeapon.UnderEMP=-1 ; integer. 0 for primary weapon, ForceWeapon.InRange= ; List of integers. 0 for primary weapon, 1 for secondary weapon, -1 to disable ForceWeapon.InRange.Overrides= ; List of floating-point values ForceWeapon.InRange.ApplyRangeModifiers=false ; boolean +ForceWeapon.InRange.TechnoOnly=true ; boolean ForceAAWeapon.InRange= ; List of integers. 0 for primary weapon, 1 for secondary weapon, -1 to disable ForceAAWeapon.InRange.Overrides= ; List of floating-point values ForceAAWeapon.InRange.ApplyRangeModifiers=false ; boolean diff --git a/src/Ext/Techno/Body.h b/src/Ext/Techno/Body.h index 11e4c189a7..60baefe53d 100644 --- a/src/Ext/Techno/Body.h +++ b/src/Ext/Techno/Body.h @@ -148,7 +148,7 @@ class TechnoExt bool HasAttachedEffects(std::vector attachEffectTypes, bool requireAll, bool ignoreSameSource, TechnoClass* pInvoker, AbstractClass* pSource, std::vector const* minCounts, std::vector const* maxCounts) const; int GetAttachedEffectCumulativeCount(AttachEffectTypeClass* pAttachEffectType, bool ignoreSameSource = false, TechnoClass* pInvoker = nullptr, AbstractClass* pSource = nullptr) const; void ApplyMindControlRangeLimit(); - int ApplyForceWeaponInRange(TechnoClass* pTarget); + int ApplyForceWeaponInRange(AbstractClass* pTarget); UnitTypeClass* GetUnitTypeExtra() const; diff --git a/src/Ext/Techno/Hooks.Firing.cpp b/src/Ext/Techno/Hooks.Firing.cpp index e62671d6bc..c357b72501 100644 --- a/src/Ext/Techno/Hooks.Firing.cpp +++ b/src/Ext/Techno/Hooks.Firing.cpp @@ -12,11 +12,6 @@ #pragma region TechnoClass_SelectWeapon -namespace ForceWeaponInRangeTemp -{ - bool SelectWeaponByRange = false; -} - DEFINE_HOOK(0x6F3339, TechnoClass_WhatWeaponShouldIUse_Interceptor, 0x8) { enum { SkipGameCode = 0x6F3341, ReturnValue = 0x6F3406 }; @@ -84,48 +79,14 @@ DEFINE_HOOK(0x6F3428, TechnoClass_WhatWeaponShouldIUse_ForceWeapon, 0x6) GET(TechnoClass*, pThis, ECX); GET_STACK(AbstractClass*, pTarget, STACK_OFFSET(0x18, 0x4)); - if (ForceWeaponInRangeTemp::SelectWeaponByRange || !pThis) - return 0; + auto const pTypeExt = TechnoTypeExt::ExtMap.Find(pThis->GetTechnoType()); - if (auto const pTargetTechno = abstract_cast(pTarget)) + // Force weapon + const int forceWeaponIndex = pTypeExt->SelectForceWeapon(pThis, pTarget); + if (forceWeaponIndex >= 0) { - int forceWeaponIndex = -1; - auto const pTypeExt = TechnoTypeExt::ExtMap.Find(pThis->GetTechnoType()); - auto const pTargetType = pTargetTechno->GetTechnoType(); - - if (pTypeExt->ForceWeapon_Naval_Decloaked >= 0 && - pTargetType->Cloakable && pTargetType->Naval && - pTargetTechno->CloakState == CloakState::Uncloaked) - { - forceWeaponIndex = pTypeExt->ForceWeapon_Naval_Decloaked; - } - else if (pTypeExt->ForceWeapon_Cloaked >= 0 && - pTargetTechno->CloakState == CloakState::Cloaked) - { - forceWeaponIndex = pTypeExt->ForceWeapon_Cloaked; - } - else if (pTypeExt->ForceWeapon_Disguised >= 0 && - pTargetTechno->IsDisguised()) - { - forceWeaponIndex = pTypeExt->ForceWeapon_Disguised; - } - else if (pTypeExt->ForceWeapon_UnderEMP >= 0 && - pTargetTechno->IsUnderEMP()) - { - forceWeaponIndex = pTypeExt->ForceWeapon_UnderEMP; - } - else if (!pTypeExt->ForceWeapon_InRange.empty() || !pTypeExt->ForceAAWeapon_InRange.empty()) - { - ForceWeaponInRangeTemp::SelectWeaponByRange = true; - forceWeaponIndex = TechnoExt::ExtMap.Find(pThis)->ApplyForceWeaponInRange(pTargetTechno); - ForceWeaponInRangeTemp::SelectWeaponByRange = false; - } - - if (forceWeaponIndex >= 0) - { - R->EAX(forceWeaponIndex); - return UseWeaponIndex; - } + R->EAX(forceWeaponIndex); + return UseWeaponIndex; } return 0; diff --git a/src/Ext/Techno/WeaponHelpers.cpp b/src/Ext/Techno/WeaponHelpers.cpp index b73efc46d5..535ca0f7fb 100644 --- a/src/Ext/Techno/WeaponHelpers.cpp +++ b/src/Ext/Techno/WeaponHelpers.cpp @@ -255,7 +255,7 @@ void TechnoExt::ApplyRevengeWeapon(TechnoClass* pThis, TechnoClass* pSource, War } } -int TechnoExt::ExtData::ApplyForceWeaponInRange(TechnoClass* pTarget) +int TechnoExt::ExtData::ApplyForceWeaponInRange(AbstractClass* pTarget) { int forceWeaponIndex = -1; auto const pThis = this->OwnerObject(); diff --git a/src/Ext/TechnoType/Body.cpp b/src/Ext/TechnoType/Body.cpp index 5d190747ab..a89cffc3cb 100644 --- a/src/Ext/TechnoType/Body.cpp +++ b/src/Ext/TechnoType/Body.cpp @@ -16,6 +16,7 @@ #include TechnoTypeExt::ExtContainer TechnoTypeExt::ExtMap; +bool TechnoTypeExt::SelectWeaponMutex = false; void TechnoTypeExt::ExtData::Initialize() { @@ -33,6 +34,54 @@ void TechnoTypeExt::ExtData::ApplyTurretOffset(Matrix3D* mtx, double factor) mtx->Translate(x, y, z); } +int TechnoTypeExt::ExtData::SelectForceWeapon(TechnoClass* pThis, AbstractClass* pTarget) +{ + if (TechnoTypeExt::SelectWeaponMutex || !this->ForceWeapon_Check || !pTarget) // In theory, pTarget must exist + return -1; + + int forceWeaponIndex = -1; + const auto pTargetTechno = abstract_cast(pTarget); + + if (pTargetTechno) + { + const auto pTargetType = pTargetTechno->GetTechnoType(); + + if (this->ForceWeapon_Naval_Decloaked >= 0 + && pTargetType->Cloakable + && pTargetType->Naval + && pTargetTechno->CloakState == CloakState::Uncloaked) + { + forceWeaponIndex = this->ForceWeapon_Naval_Decloaked; + } + else if (this->ForceWeapon_Cloaked >= 0 + && pTargetTechno->CloakState == CloakState::Cloaked) + { + forceWeaponIndex = this->ForceWeapon_Cloaked; + } + else if (this->ForceWeapon_Disguised >= 0 + && pTargetTechno->IsDisguised()) + { + forceWeaponIndex = this->ForceWeapon_Disguised; + } + else if (this->ForceWeapon_UnderEMP >= 0 + && pTargetTechno->IsUnderEMP()) + { + forceWeaponIndex = this->ForceWeapon_UnderEMP; + } + } + + if (forceWeaponIndex == -1 + && (pTargetTechno || !this->ForceWeapon_InRange_TechnoOnly) + && (!this->ForceWeapon_InRange.empty() || !this->ForceAAWeapon_InRange.empty())) + { + TechnoTypeExt::SelectWeaponMutex = true; + forceWeaponIndex = TechnoExt::ExtMap.Find(pThis)->ApplyForceWeaponInRange(pTarget); + TechnoTypeExt::SelectWeaponMutex = false; + } + + return forceWeaponIndex; +} + // Ares 0.A source const char* TechnoTypeExt::ExtData::GetSelectionGroupID() const { @@ -405,16 +454,27 @@ void TechnoTypeExt::ExtData::LoadFromINIFile(CCINIClass* const pINI) this->DeployingAnim_UseUnitDrawer.Read(exINI, pSection, "DeployingAnim.UseUnitDrawer"); this->EnemyUIName.Read(exINI, pSection, "EnemyUIName"); + this->ForceWeapon_Naval_Decloaked.Read(exINI, pSection, "ForceWeapon.Naval.Decloaked"); this->ForceWeapon_Cloaked.Read(exINI, pSection, "ForceWeapon.Cloaked"); this->ForceWeapon_Disguised.Read(exINI, pSection, "ForceWeapon.Disguised"); this->ForceWeapon_UnderEMP.Read(exINI, pSection, "ForceWeapon.UnderEMP"); + this->ForceWeapon_InRange_TechnoOnly.Read(exINI, pSection, "ForceWeapon.InRange.TechnoOnly"); this->ForceWeapon_InRange.Read(exINI, pSection, "ForceWeapon.InRange"); this->ForceWeapon_InRange_Overrides.Read(exINI, pSection, "ForceWeapon.InRange.Overrides"); this->ForceWeapon_InRange_ApplyRangeModifiers.Read(exINI, pSection, "ForceWeapon.InRange.ApplyRangeModifiers"); this->ForceAAWeapon_InRange.Read(exINI, pSection, "ForceAAWeapon.InRange"); this->ForceAAWeapon_InRange_Overrides.Read(exINI, pSection, "ForceAAWeapon.InRange.Overrides"); this->ForceAAWeapon_InRange_ApplyRangeModifiers.Read(exINI, pSection, "ForceAAWeapon.InRange.ApplyRangeModifiers"); + this->ForceWeapon_Check = ( + this->ForceWeapon_Naval_Decloaked >= 0 + || this->ForceWeapon_Cloaked >= 0 + || this->ForceWeapon_Disguised >= 0 + || this->ForceWeapon_UnderEMP >= 0 + || !this->ForceWeapon_InRange.empty() + || !this->ForceAAWeapon_InRange.empty() + ); + this->Ammo_Shared.Read(exINI, pSection, "Ammo.Shared"); this->Ammo_Shared_Group.Read(exINI, pSection, "Ammo.Shared.Group"); this->SelfHealGainType.Read(exINI, pSection, "SelfHealGainType"); @@ -943,16 +1003,20 @@ void TechnoTypeExt::ExtData::Serialize(T& Stm) .Process(this->DeployingAnim_UseUnitDrawer) .Process(this->EnemyUIName) + + .Process(this->ForceWeapon_Check) .Process(this->ForceWeapon_Naval_Decloaked) .Process(this->ForceWeapon_Cloaked) .Process(this->ForceWeapon_Disguised) .Process(this->ForceWeapon_UnderEMP) + .Process(this->ForceWeapon_InRange_TechnoOnly) .Process(this->ForceWeapon_InRange) .Process(this->ForceWeapon_InRange_Overrides) .Process(this->ForceWeapon_InRange_ApplyRangeModifiers) .Process(this->ForceAAWeapon_InRange) .Process(this->ForceAAWeapon_InRange_Overrides) .Process(this->ForceAAWeapon_InRange_ApplyRangeModifiers) + .Process(this->Ammo_Shared) .Process(this->Ammo_Shared_Group) .Process(this->SelfHealGainType) diff --git a/src/Ext/TechnoType/Body.h b/src/Ext/TechnoType/Body.h index 820bf68de8..b3afcdd17c 100644 --- a/src/Ext/TechnoType/Body.h +++ b/src/Ext/TechnoType/Body.h @@ -165,10 +165,13 @@ class TechnoTypeExt Valueable DeployingAnim_UseUnitDrawer; Valueable EnemyUIName; + + bool ForceWeapon_Check; Valueable ForceWeapon_Naval_Decloaked; Valueable ForceWeapon_Cloaked; Valueable ForceWeapon_Disguised; Valueable ForceWeapon_UnderEMP; + Valueable ForceWeapon_InRange_TechnoOnly; ValueableVector ForceWeapon_InRange; ValueableVector ForceWeapon_InRange_Overrides; Valueable ForceWeapon_InRange_ApplyRangeModifiers; @@ -484,10 +487,12 @@ class TechnoTypeExt , VoiceCreated {} , VoicePickup {} + , ForceWeapon_Check { false } , ForceWeapon_Naval_Decloaked { -1 } , ForceWeapon_Cloaked { -1 } , ForceWeapon_Disguised { -1 } , ForceWeapon_UnderEMP { -1 } + , ForceWeapon_InRange_TechnoOnly { true } , ForceWeapon_InRange {} , ForceWeapon_InRange_Overrides {} , ForceWeapon_InRange_ApplyRangeModifiers { false } @@ -680,6 +685,8 @@ class TechnoTypeExt void ApplyTurretOffset(Matrix3D* mtx, double factor = 1.0); + int SelectForceWeapon(TechnoClass* pThis, AbstractClass* pTarget); + // Ares 0.A const char* GetSelectionGroupID() const; @@ -699,6 +706,7 @@ class TechnoTypeExt }; static ExtContainer ExtMap; + static bool SelectWeaponMutex; static void ApplyTurretOffset(TechnoTypeClass* pType, Matrix3D* mtx, double factor = 1.0); static TechnoTypeClass* GetTechnoType(ObjectTypeClass* pType);