Skip to content

[Minor] Fix ForceWeapon.InRange not taking effect when attacking non-techno #1693

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
Jun 4, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion docs/New-or-Enhanced-Logics.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand All @@ -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
Expand Down
2 changes: 1 addition & 1 deletion src/Ext/Techno/Body.h
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,7 @@ class TechnoExt
bool HasAttachedEffects(std::vector<AttachEffectTypeClass*> attachEffectTypes, bool requireAll, bool ignoreSameSource, TechnoClass* pInvoker, AbstractClass* pSource, std::vector<int> const* minCounts, std::vector<int> 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;

Expand Down
51 changes: 6 additions & 45 deletions src/Ext/Techno/Hooks.Firing.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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 };
Expand Down Expand Up @@ -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<TechnoClass*>(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;
Expand Down
2 changes: 1 addition & 1 deletion src/Ext/Techno/WeaponHelpers.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down
64 changes: 64 additions & 0 deletions src/Ext/TechnoType/Body.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
#include <Utilities/GeneralUtils.h>

TechnoTypeExt::ExtContainer TechnoTypeExt::ExtMap;
bool TechnoTypeExt::SelectWeaponMutex = false;

void TechnoTypeExt::ExtData::Initialize()
{
Expand All @@ -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<TechnoClass*>(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
{
Expand Down Expand Up @@ -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");
Expand Down Expand Up @@ -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)
Expand Down
8 changes: 8 additions & 0 deletions src/Ext/TechnoType/Body.h
Original file line number Diff line number Diff line change
Expand Up @@ -165,10 +165,13 @@ class TechnoTypeExt
Valueable<bool> DeployingAnim_UseUnitDrawer;

Valueable<CSFText> EnemyUIName;

bool ForceWeapon_Check;
Valueable<int> ForceWeapon_Naval_Decloaked;
Valueable<int> ForceWeapon_Cloaked;
Valueable<int> ForceWeapon_Disguised;
Valueable<int> ForceWeapon_UnderEMP;
Valueable<bool> ForceWeapon_InRange_TechnoOnly;
ValueableVector<int> ForceWeapon_InRange;
ValueableVector<double> ForceWeapon_InRange_Overrides;
Valueable<bool> ForceWeapon_InRange_ApplyRangeModifiers;
Expand Down Expand Up @@ -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 }
Expand Down Expand Up @@ -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;

Expand All @@ -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);
Expand Down
Loading