From c74eb861d4ae701ebda9156e042807281b46d12d Mon Sep 17 00:00:00 2001 From: Fly-Star <100747645+a851903106@users.noreply.github.com> Date: Thu, 5 Feb 2026 19:48:07 +0800 Subject: [PATCH 01/10] update --- CREDITS.md | 1 + docs/Whats-New.md | 1 + src/Ext/Infantry/Hooks.cpp | 9 ++ src/Ext/TechnoType/Body.cpp | 28 ++--- src/Ext/TechnoType/Body.h | 2 +- src/Ext/TechnoType/Hooks.MultiWeapon.cpp | 148 ++++++++++++++++++++++- 6 files changed, 168 insertions(+), 21 deletions(-) diff --git a/CREDITS.md b/CREDITS.md index 33620628bf..b89b17f647 100644 --- a/CREDITS.md +++ b/CREDITS.md @@ -409,6 +409,7 @@ This page lists all the individual contributions to the project by their author. - Vehicle Deployment Enhancement - Fixed an issue where miners affected by `Passengers/DeployFire` were unable to unload minerals - Fixed an issue where mining vehicles could not move after leaving a tank bunker + - Separation of AutoTarget for `DeployFireWeapon`, `OpenTransportWeapon`, and `NoAmmoWeapon` - **NetsuNegi**: - Forbidding parallel AI queues by type - Jumpjet crash speed fix when crashing onto building diff --git a/docs/Whats-New.md b/docs/Whats-New.md index 2b52125b77..6411bcf398 100644 --- a/docs/Whats-New.md +++ b/docs/Whats-New.md @@ -535,6 +535,7 @@ New: - Option to scale `PowerSurplus` setting if enabled to current power drain with `PowerSurplus.ScaleToDrainAmount` (by Starkku) - Global default value for `DefaultToGuardArea` (by TaranDahl) - [Weapon range finding in cylinder](New-or-Enhanced-Logics.md#range-finding-in-cylinder) (by TaranDahl) +- Separation of AutoTarget for `DeployFireWeapon`, `OpenTransportWeapon`, and `NoAmmoWeapon` (by FlyStar) Vanilla fixes: - Fixed sidebar not updating queued unit numbers when adding or removing units when the production is on hold (by CrimRecya) diff --git a/src/Ext/Infantry/Hooks.cpp b/src/Ext/Infantry/Hooks.cpp index 168441c07b..3e63629230 100644 --- a/src/Ext/Infantry/Hooks.cpp +++ b/src/Ext/Infantry/Hooks.cpp @@ -84,6 +84,15 @@ DEFINE_HOOK(0x51EE6B, InfantryClass_WhatAction_ObjectClass_InfiltrateForceAttack return WhatActionObjectTemp::Fire ? 0x51F05E : 0; } +// Setting Ares' NoSelfGuardArea to yes will also disable this feature. I'm not sure if it should be removed. +DEFINE_HOOK(0x51E748, InfantryClass_WhatAction_ObjectClass_SkipGuardArea, 0x8) +{ + GET(InfantryClass* const, pThis, EDI); + enum { SkipGameCode = 0x51E7A6 }; + + return pThis->IsDeployed() ? SkipGameCode : 0; +} + DEFINE_HOOK(0x51ECC0, InfantryClass_WhatAction_ObjectClass_IsAreaFire, 0xA) { enum { IsAreaFire = 0x51ECE5, NotAreaFire = 0x51ECEC }; diff --git a/src/Ext/TechnoType/Body.cpp b/src/Ext/TechnoType/Body.cpp index 39560cc224..cd33d2b069 100644 --- a/src/Ext/TechnoType/Body.cpp +++ b/src/Ext/TechnoType/Body.cpp @@ -452,33 +452,27 @@ void TechnoTypeExt::ExtData::UpdateAdditionalAttributes() if (!pWeapon) return; + const int combatDamage = (pWeapon->Damage + pWeapon->AmbientDamage); + const ThreatType threats = pWeapon->Projectile ? pWeapon->AllowedThreats() : ThreatType::Normal; + const bool attackFriendlies = WeaponTypeExt::ExtMap.Find(pWeapon)->AttackFriendlies.Get(false); + if (isElite) { - if (pWeapon->Projectile) - this->ThreatTypes.Y |= pWeapon->AllowedThreats(); - - this->CombatDamages.Y += (pWeapon->Damage + pWeapon->AmbientDamage); + this->ThreatTypes.Y |= threats; + this->CombatDamages.Y += combatDamage; eliteNum++; - if (!this->AttackFriendlies.Y - && WeaponTypeExt::ExtMap.Find(pWeapon)->AttackFriendlies.Get(false)) - { + if (!this->AttackFriendlies.Y && attackFriendlies) this->AttackFriendlies.Y = true; - } } else { - if (pWeapon->Projectile) - this->ThreatTypes.X |= pWeapon->AllowedThreats(); - - this->CombatDamages.X += (pWeapon->Damage + pWeapon->AmbientDamage); + this->ThreatTypes.X |= threats; + this->CombatDamages.X += combatDamage; num++; - if (!this->AttackFriendlies.X - && WeaponTypeExt::ExtMap.Find(pWeapon)->AttackFriendlies.Get(false)) - { + if (!this->AttackFriendlies.X && attackFriendlies) this->AttackFriendlies.X = true; - } } }; @@ -1149,7 +1143,7 @@ void TechnoTypeExt::ExtData::LoadFromINIFile(CCINIClass* const pINI) this->ParadropMission.Read(exINI, pSection, "ParadropMission"); this->AIParadropMission.Read(exINI, pSection, "AIParadropMission"); - + // Ares 0.2 this->RadarJamRadius.Read(exINI, pSection, "RadarJamRadius"); diff --git a/src/Ext/TechnoType/Body.h b/src/Ext/TechnoType/Body.h index 7d161c89ca..f1afad135f 100644 --- a/src/Ext/TechnoType/Body.h +++ b/src/Ext/TechnoType/Body.h @@ -474,7 +474,7 @@ class TechnoTypeExt Nullable ParadropMission; Nullable AIParadropMission; - + ExtData(TechnoTypeClass* OwnerObject) : Extension(OwnerObject) , HealthBar_Hide { false } , HealthBar_HidePips { false } diff --git a/src/Ext/TechnoType/Hooks.MultiWeapon.cpp b/src/Ext/TechnoType/Hooks.MultiWeapon.cpp index c7d01b6110..7924fd6dfc 100644 --- a/src/Ext/TechnoType/Hooks.MultiWeapon.cpp +++ b/src/Ext/TechnoType/Hooks.MultiWeapon.cpp @@ -143,6 +143,24 @@ DEFINE_HOOK(0x7090A0, TechnoClass_VoiceAttack, 0x7) return 0x7091C7; } +bool __forceinline IsDeployed(TechnoClass* const pThis, const AbstractType rtti) +{ + switch (rtti) + { + case AbstractType::Infantry: + return static_cast(pThis)->IsDeployed(); + case AbstractType::Unit: + { + auto const pUnit = static_cast(pThis); + + return pUnit->Deployed || (pUnit->Type->DeployFire && + pThis->CurrentMission == Mission::Unload); + } + default: + return false; + } +} + static __forceinline ThreatType GetThreatType(TechnoClass* pThis, TechnoTypeExt::ExtData* pTypeExt, ThreatType result) { const ThreatType flags = pThis->Veterancy.IsElite() ? pTypeExt->ThreatTypes.Y : pTypeExt->ThreatTypes.X; @@ -157,9 +175,9 @@ DEFINE_HOOK(0x7431C9, FootClass_SelectAutoTarget_MultiWeapon, 0x7) // UnitClas GET(FootClass*, pThis, ESI); GET(const ThreatType, result, EDI); - const bool isUnit = R->Origin() == 0x7431C9; const auto pTypeExt = TechnoExt::ExtMap.Find(pThis)->TypeExtData; const auto pType = pTypeExt->OwnerObject(); + const bool isUnit = R->Origin() == 0x7431C9; if (isUnit && !pType->IsGattling && pType->TurretCount > 0 @@ -168,6 +186,46 @@ DEFINE_HOOK(0x7431C9, FootClass_SelectAutoTarget_MultiWeapon, 0x7) // UnitClas return UnitGunner; } + const AbstractType rtti = isUnit ? AbstractType::Unit : AbstractType::Infantry; + const int deployFireWeapon = pType->DeployFireWeapon; + + if (IsDeployed(pThis, rtti) && pType->DeployFire && deployFireWeapon >= 0) + { + ThreatType flags = result; + + if (const auto pWeapon = pThis->GetWeapon(deployFireWeapon)->WeaponType) + flags |= pWeapon->AllowedThreats(); + + R->EDI(flags); + return isUnit ? UnitReturn : InfantryReturn; + } + + const int openTransportWeapon = pType->OpenTransportWeapon; + + if (pThis->InOpenToppedTransport && openTransportWeapon >= 0) + { + ThreatType flags = result; + + if (const auto pWeapon = pThis->GetWeapon(openTransportWeapon)->WeaponType) + flags |= pWeapon->AllowedThreats(); + + R->EDI(flags); + return isUnit ? UnitReturn : InfantryReturn; + } + + const int noAmmoWeapon = pTypeExt->NoAmmoWeapon; + + if (pType->Ammo >= 0 && noAmmoWeapon >= 0 && pThis->Ammo <= pTypeExt->NoAmmoAmount) + { + ThreatType flags = result; + + if (const auto pWeapon = pThis->GetWeapon(noAmmoWeapon)->WeaponType) + flags |= pWeapon->AllowedThreats(); + + R->EDI(flags); + return isUnit ? UnitReturn : InfantryReturn; + } + R->EDI(GetThreatType(pThis, pTypeExt, result)); return isUnit ? UnitReturn : InfantryReturn; } @@ -185,7 +243,22 @@ DEFINE_HOOK(0x445F04, BuildingClass_SelectAutoTarget_MultiWeapon, 0xA) return Continue; } - R->EDI(GetThreatType(pThis, TechnoTypeExt::ExtMap.Find(pThis->Type), result)); + const auto pType = pThis->Type; + const auto pTypeExt = TechnoTypeExt::ExtMap.Find(pType); + const int noAmmoWeapon = pTypeExt->NoAmmoWeapon; + + if (pType->Ammo >= 0 && noAmmoWeapon >= 0 && pThis->Ammo <= pTypeExt->NoAmmoAmount) + { + ThreatType flags = result; + + if (const auto pWeapon = pThis->GetWeapon(noAmmoWeapon)->WeaponType) + flags |= pWeapon->AllowedThreats(); + + R->EDI(flags); + return ReturnThreatType; + } + + R->EDI(GetThreatType(pThis, pTypeExt, result)); return ReturnThreatType; } @@ -215,6 +288,45 @@ DEFINE_HOOK(0x6F398E, TechnoClass_CombatDamage_MultiWeapon, 0x7) return GunnerDamage; } + const int deployFireWeapon = pType->DeployFireWeapon; + + if (IsDeployed(pThis, rtti) && pType->DeployFire && deployFireWeapon >= 0) + { + int damage = 0; + + if (auto const pWeapon = pThis->GetWeapon(deployFireWeapon)->WeaponType) + damage = (pWeapon->Damage + pWeapon->AmbientDamage); + + R->EAX(damage); + return ReturnDamage; + } + + const int openTransportWeapon = pType->OpenTransportWeapon; + + if (pThis->InOpenToppedTransport && openTransportWeapon >= 0) + { + int damage = 0; + + if (auto const pWeapon = pThis->GetWeapon(openTransportWeapon)->WeaponType) + damage = (pWeapon->Damage + pWeapon->AmbientDamage); + + R->EAX(damage); + return ReturnDamage; + } + + const int noAmmoWeapon = pTypeExt->NoAmmoWeapon; + + if (pType->Ammo >= 0 && noAmmoWeapon >= 0 && pThis->Ammo <= pTypeExt->NoAmmoAmount) + { + int damage = 0; + + if (auto const pWeapon = pThis->GetWeapon(noAmmoWeapon)->WeaponType) + damage = (pWeapon->Damage + pWeapon->AmbientDamage); + + R->EAX(damage); + return ReturnDamage; + } + R->EAX(pThis->Veterancy.IsElite() ? pTypeExt->CombatDamages.Y : pTypeExt->CombatDamages.X); return ReturnDamage; } @@ -227,16 +339,46 @@ DEFINE_HOOK(0x707ED0, TechnoClass_GetGuardRange_MultiWeapon, 0x6) const auto pType = pThis->GetTechnoType(); const bool specialWeapon = !pType->IsGattling && (!pType->HasMultipleTurrets() || !pType->Gunner); + const AbstractType rtti = pThis->WhatAmI(); if (!pType->IsGattling && pType->TurretCount > 0 && (pType->Gunner || !specialWeapon) - && pThis->WhatAmI() == AbstractType::Unit) + && rtti == AbstractType::Unit) { R->EAX(pThis->GetWeaponRange(pThis->CurrentWeaponNumber)); return ReturnRange; } const auto pTypeExt = TechnoTypeExt::ExtMap.Find(pType); + const int deployFireWeapon = pType->DeployFireWeapon; + + if (IsDeployed(pThis, rtti) && pType->DeployFire && deployFireWeapon >= 0) + { + int range = pThis->GetWeaponRange(deployFireWeapon); + + R->EAX(range); + return ReturnRange; + } + + const int openTransportWeapon = pType->OpenTransportWeapon; + + if (pThis->InOpenToppedTransport && openTransportWeapon >= 0) + { + int range = pThis->GetWeaponRange(openTransportWeapon); + + R->EAX(range); + return ReturnRange; + } + + const int noAmmoWeapon = pTypeExt->NoAmmoWeapon; + + if (pType->Ammo >= 0 && noAmmoWeapon >= 0 && pThis->Ammo <= pTypeExt->NoAmmoAmount) + { + int range = pThis->GetWeaponRange(noAmmoWeapon); + + R->EAX(range); + return ReturnRange; + } if (pTypeExt->MultiWeapon && specialWeapon) { From bdc0408eee8e71d0eedc29412d7082a2f80af837 Mon Sep 17 00:00:00 2001 From: Fly-Star <100747645+a851903106@users.noreply.github.com> Date: Thu, 5 Feb 2026 21:39:35 +0800 Subject: [PATCH 02/10] Update Hooks.cpp --- src/Ext/Infantry/Hooks.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Ext/Infantry/Hooks.cpp b/src/Ext/Infantry/Hooks.cpp index 3e63629230..dbc645c54d 100644 --- a/src/Ext/Infantry/Hooks.cpp +++ b/src/Ext/Infantry/Hooks.cpp @@ -88,9 +88,10 @@ DEFINE_HOOK(0x51EE6B, InfantryClass_WhatAction_ObjectClass_InfiltrateForceAttack DEFINE_HOOK(0x51E748, InfantryClass_WhatAction_ObjectClass_SkipGuardArea, 0x8) { GET(InfantryClass* const, pThis, EDI); + GET(const Action, action, EBP); enum { SkipGameCode = 0x51E7A6 }; - return pThis->IsDeployed() ? SkipGameCode : 0; + return (action == Action::Self_Deploy || pThis->IsDeployed()) ? SkipGameCode : 0; } DEFINE_HOOK(0x51ECC0, InfantryClass_WhatAction_ObjectClass_IsAreaFire, 0xA) From 73044ca517fdb51c42eab4438ce82b36a766e99f Mon Sep 17 00:00:00 2001 From: Fly-Star <100747645+a851903106@users.noreply.github.com> Date: Sat, 7 Feb 2026 15:18:54 +0800 Subject: [PATCH 03/10] add switch --- docs/New-or-Enhanced-Logics.md | 14 ++ src/Ext/TechnoType/Body.cpp | 4 + src/Ext/TechnoType/Body.h | 6 +- src/Ext/TechnoType/Hooks.MultiWeapon.cpp | 179 ++++++++++++++--------- src/Utilities/Enum.h | 12 ++ src/Utilities/TemplateDef.h | 44 ++++++ 6 files changed, 187 insertions(+), 72 deletions(-) diff --git a/docs/New-or-Enhanced-Logics.md b/docs/New-or-Enhanced-Logics.md index 0e2c666d66..f02e1c73ba 100644 --- a/docs/New-or-Enhanced-Logics.md +++ b/docs/New-or-Enhanced-Logics.md @@ -2065,6 +2065,20 @@ SuppressRevengeWeapons=false ; boolean SuppressRevengeWeapons.Types= ; List of WeaponTypes ``` +### Separation AutoTarget + +- `DeployFireWeapon`, `OpenTransportWeapon`, and `NoAmmoWeapon` can use separate auto-targeting instead of all weapons sharing a common decision. + +In `rulesmd.ini`: +```ini +[SOMETECHNO] ; TechnoType +SeparateWeaponTypes=none ; List of SeparateWeaponType Enumeration (none|deployfireweapon|opentransport|noammo|all) +``` + +```{warning} +Please note that weapons using separate automatic targeting will not perform automatic attacks on certain descending aerial targets if the projectile has `AG=no` and `AA=yes` +``` + ### Shared Ammo - Transports with `OpenTopped=yes` and `Ammo.Shared=yes` will transfer ammo to passengers that have `Ammo.Shared=yes`. diff --git a/src/Ext/TechnoType/Body.cpp b/src/Ext/TechnoType/Body.cpp index cd33d2b069..2ea65d7eb0 100644 --- a/src/Ext/TechnoType/Body.cpp +++ b/src/Ext/TechnoType/Body.cpp @@ -1144,6 +1144,8 @@ void TechnoTypeExt::ExtData::LoadFromINIFile(CCINIClass* const pINI) this->ParadropMission.Read(exINI, pSection, "ParadropMission"); this->AIParadropMission.Read(exINI, pSection, "AIParadropMission"); + this->SeparateWeaponTypes.Read(exINI, pSection, "SeparateWeaponTypes"); + // Ares 0.2 this->RadarJamRadius.Read(exINI, pSection, "RadarJamRadius"); @@ -1845,6 +1847,8 @@ void TechnoTypeExt::ExtData::Serialize(T& Stm) .Process(this->ParadropMission) .Process(this->AIParadropMission) + + .Process(this->SeparateWeaponTypes) ; } void TechnoTypeExt::ExtData::LoadFromStream(PhobosStreamReader& Stm) diff --git a/src/Ext/TechnoType/Body.h b/src/Ext/TechnoType/Body.h index f1afad135f..603ab17dc0 100644 --- a/src/Ext/TechnoType/Body.h +++ b/src/Ext/TechnoType/Body.h @@ -474,7 +474,9 @@ class TechnoTypeExt Nullable ParadropMission; Nullable AIParadropMission; - + + Valueable SeparateWeaponTypes; + ExtData(TechnoTypeClass* OwnerObject) : Extension(OwnerObject) , HealthBar_Hide { false } , HealthBar_HidePips { false } @@ -903,6 +905,8 @@ class TechnoTypeExt , ParadropMission {} , AIParadropMission {} + + , SeparateWeaponTypes { SeparateWeaponType::None } { } virtual ~ExtData() = default; diff --git a/src/Ext/TechnoType/Hooks.MultiWeapon.cpp b/src/Ext/TechnoType/Hooks.MultiWeapon.cpp index 7924fd6dfc..64d308874d 100644 --- a/src/Ext/TechnoType/Hooks.MultiWeapon.cpp +++ b/src/Ext/TechnoType/Hooks.MultiWeapon.cpp @@ -186,44 +186,55 @@ DEFINE_HOOK(0x7431C9, FootClass_SelectAutoTarget_MultiWeapon, 0x7) // UnitClas return UnitGunner; } - const AbstractType rtti = isUnit ? AbstractType::Unit : AbstractType::Infantry; - const int deployFireWeapon = pType->DeployFireWeapon; + const SeparateWeaponType weaponTypes = pTypeExt->SeparateWeaponTypes; - if (IsDeployed(pThis, rtti) && pType->DeployFire && deployFireWeapon >= 0) + if (weaponTypes & SeparateWeaponType::DeployFire) { - ThreatType flags = result; + const AbstractType rtti = isUnit ? AbstractType::Unit : AbstractType::Infantry; + const int deployFireWeapon = pType->DeployFireWeapon; - if (const auto pWeapon = pThis->GetWeapon(deployFireWeapon)->WeaponType) - flags |= pWeapon->AllowedThreats(); + if (IsDeployed(pThis, rtti) && pType->DeployFire && deployFireWeapon >= 0) + { + ThreatType flags = result; - R->EDI(flags); - return isUnit ? UnitReturn : InfantryReturn; - } + if (const auto pWeapon = pThis->GetWeapon(deployFireWeapon)->WeaponType) + flags |= pWeapon->AllowedThreats(); - const int openTransportWeapon = pType->OpenTransportWeapon; + R->EDI(flags); + return isUnit ? UnitReturn : InfantryReturn; + } + } - if (pThis->InOpenToppedTransport && openTransportWeapon >= 0) + if (weaponTypes & SeparateWeaponType::OpenTransport) { - ThreatType flags = result; + const int openTransportWeapon = pType->OpenTransportWeapon; - if (const auto pWeapon = pThis->GetWeapon(openTransportWeapon)->WeaponType) - flags |= pWeapon->AllowedThreats(); + if (pThis->InOpenToppedTransport && openTransportWeapon >= 0) + { + ThreatType flags = result; - R->EDI(flags); - return isUnit ? UnitReturn : InfantryReturn; - } + if (const auto pWeapon = pThis->GetWeapon(openTransportWeapon)->WeaponType) + flags |= pWeapon->AllowedThreats(); - const int noAmmoWeapon = pTypeExt->NoAmmoWeapon; + R->EDI(flags); + return isUnit ? UnitReturn : InfantryReturn; + } + } - if (pType->Ammo >= 0 && noAmmoWeapon >= 0 && pThis->Ammo <= pTypeExt->NoAmmoAmount) + if (weaponTypes & SeparateWeaponType::NoAmmo) { - ThreatType flags = result; + const int noAmmoWeapon = pTypeExt->NoAmmoWeapon; - if (const auto pWeapon = pThis->GetWeapon(noAmmoWeapon)->WeaponType) - flags |= pWeapon->AllowedThreats(); + if (pType->Ammo >= 0 && noAmmoWeapon >= 0 && pThis->Ammo <= pTypeExt->NoAmmoAmount) + { + ThreatType flags = result; - R->EDI(flags); - return isUnit ? UnitReturn : InfantryReturn; + if (const auto pWeapon = pThis->GetWeapon(noAmmoWeapon)->WeaponType) + flags |= pWeapon->AllowedThreats(); + + R->EDI(flags); + return isUnit ? UnitReturn : InfantryReturn; + } } R->EDI(GetThreatType(pThis, pTypeExt, result)); @@ -245,17 +256,21 @@ DEFINE_HOOK(0x445F04, BuildingClass_SelectAutoTarget_MultiWeapon, 0xA) const auto pType = pThis->Type; const auto pTypeExt = TechnoTypeExt::ExtMap.Find(pType); - const int noAmmoWeapon = pTypeExt->NoAmmoWeapon; - if (pType->Ammo >= 0 && noAmmoWeapon >= 0 && pThis->Ammo <= pTypeExt->NoAmmoAmount) + if (pTypeExt->SeparateWeaponTypes & SeparateWeaponType::NoAmmo) { - ThreatType flags = result; + const int noAmmoWeapon = pTypeExt->NoAmmoWeapon; - if (const auto pWeapon = pThis->GetWeapon(noAmmoWeapon)->WeaponType) - flags |= pWeapon->AllowedThreats(); + if (pType->Ammo >= 0 && noAmmoWeapon >= 0 && pThis->Ammo <= pTypeExt->NoAmmoAmount) + { + ThreatType flags = result; + + if (const auto pWeapon = pThis->GetWeapon(noAmmoWeapon)->WeaponType) + flags |= pWeapon->AllowedThreats(); - R->EDI(flags); - return ReturnThreatType; + R->EDI(flags); + return ReturnThreatType; + } } R->EDI(GetThreatType(pThis, pTypeExt, result)); @@ -288,43 +303,54 @@ DEFINE_HOOK(0x6F398E, TechnoClass_CombatDamage_MultiWeapon, 0x7) return GunnerDamage; } - const int deployFireWeapon = pType->DeployFireWeapon; + const SeparateWeaponType weaponTypes = pTypeExt->SeparateWeaponTypes; - if (IsDeployed(pThis, rtti) && pType->DeployFire && deployFireWeapon >= 0) + if (weaponTypes & SeparateWeaponType::DeployFire) { - int damage = 0; + const int deployFireWeapon = pType->DeployFireWeapon; - if (auto const pWeapon = pThis->GetWeapon(deployFireWeapon)->WeaponType) - damage = (pWeapon->Damage + pWeapon->AmbientDamage); + if (IsDeployed(pThis, rtti) && pType->DeployFire && deployFireWeapon >= 0) + { + int damage = 0; - R->EAX(damage); - return ReturnDamage; - } + if (auto const pWeapon = pThis->GetWeapon(deployFireWeapon)->WeaponType) + damage = (pWeapon->Damage + pWeapon->AmbientDamage); - const int openTransportWeapon = pType->OpenTransportWeapon; + R->EAX(damage); + return ReturnDamage; + } + } - if (pThis->InOpenToppedTransport && openTransportWeapon >= 0) + if (weaponTypes & SeparateWeaponType::OpenTransport) { - int damage = 0; + const int openTransportWeapon = pType->OpenTransportWeapon; - if (auto const pWeapon = pThis->GetWeapon(openTransportWeapon)->WeaponType) - damage = (pWeapon->Damage + pWeapon->AmbientDamage); + if (pThis->InOpenToppedTransport && openTransportWeapon >= 0) + { + int damage = 0; - R->EAX(damage); - return ReturnDamage; - } + if (auto const pWeapon = pThis->GetWeapon(openTransportWeapon)->WeaponType) + damage = (pWeapon->Damage + pWeapon->AmbientDamage); - const int noAmmoWeapon = pTypeExt->NoAmmoWeapon; + R->EAX(damage); + return ReturnDamage; + } + } - if (pType->Ammo >= 0 && noAmmoWeapon >= 0 && pThis->Ammo <= pTypeExt->NoAmmoAmount) + if (weaponTypes & SeparateWeaponType::NoAmmo) { - int damage = 0; + const int noAmmoWeapon = pTypeExt->NoAmmoWeapon; + + if (pType->Ammo >= 0 && noAmmoWeapon >= 0 && pThis->Ammo <= pTypeExt->NoAmmoAmount) + { + int damage = 0; - if (auto const pWeapon = pThis->GetWeapon(noAmmoWeapon)->WeaponType) - damage = (pWeapon->Damage + pWeapon->AmbientDamage); + if (auto const pWeapon = pThis->GetWeapon(noAmmoWeapon)->WeaponType) + damage = (pWeapon->Damage + pWeapon->AmbientDamage); - R->EAX(damage); - return ReturnDamage; + R->EAX(damage); + return ReturnDamage; + } } R->EAX(pThis->Veterancy.IsElite() ? pTypeExt->CombatDamages.Y : pTypeExt->CombatDamages.X); @@ -350,34 +376,45 @@ DEFINE_HOOK(0x707ED0, TechnoClass_GetGuardRange_MultiWeapon, 0x6) } const auto pTypeExt = TechnoTypeExt::ExtMap.Find(pType); - const int deployFireWeapon = pType->DeployFireWeapon; + const SeparateWeaponType weaponTypes = pTypeExt->SeparateWeaponTypes; - if (IsDeployed(pThis, rtti) && pType->DeployFire && deployFireWeapon >= 0) + if (weaponTypes & SeparateWeaponType::DeployFire) { - int range = pThis->GetWeaponRange(deployFireWeapon); + const int deployFireWeapon = pType->DeployFireWeapon; - R->EAX(range); - return ReturnRange; - } + if (IsDeployed(pThis, rtti) && pType->DeployFire && deployFireWeapon >= 0) + { + const int range = pThis->GetWeaponRange(deployFireWeapon); - const int openTransportWeapon = pType->OpenTransportWeapon; + R->EAX(range); + return ReturnRange; + } + } - if (pThis->InOpenToppedTransport && openTransportWeapon >= 0) + if (weaponTypes & SeparateWeaponType::OpenTransport) { - int range = pThis->GetWeaponRange(openTransportWeapon); + const int openTransportWeapon = pType->OpenTransportWeapon; - R->EAX(range); - return ReturnRange; - } + if (pThis->InOpenToppedTransport && openTransportWeapon >= 0) + { + const int range = pThis->GetWeaponRange(openTransportWeapon); - const int noAmmoWeapon = pTypeExt->NoAmmoWeapon; + R->EAX(range); + return ReturnRange; + } + } - if (pType->Ammo >= 0 && noAmmoWeapon >= 0 && pThis->Ammo <= pTypeExt->NoAmmoAmount) + if (weaponTypes & SeparateWeaponType::NoAmmo) { - int range = pThis->GetWeaponRange(noAmmoWeapon); + const int noAmmoWeapon = pTypeExt->NoAmmoWeapon; - R->EAX(range); - return ReturnRange; + if (pType->Ammo >= 0 && noAmmoWeapon >= 0 && pThis->Ammo <= pTypeExt->NoAmmoAmount) + { + const int range = pThis->GetWeaponRange(noAmmoWeapon); + + R->EAX(range); + return ReturnRange; + } } if (pTypeExt->MultiWeapon && specialWeapon) diff --git a/src/Utilities/Enum.h b/src/Utilities/Enum.h index 2109fdf943..8c89bf3a7f 100644 --- a/src/Utilities/Enum.h +++ b/src/Utilities/Enum.h @@ -394,3 +394,15 @@ class MouseCursorHotSpotY return false; } }; + +enum class SeparateWeaponType : unsigned char +{ + None = 0x0, + DeployFire = 0x1, + OpenTransport = 0x2, + NoAmmo = 0x4, + + All = DeployFire | OpenTransport | NoAmmo +}; + +MAKE_ENUM_FLAGS(SeparateWeaponType); diff --git a/src/Utilities/TemplateDef.h b/src/Utilities/TemplateDef.h index fa93406465..fbfdabfc8b 100644 --- a/src/Utilities/TemplateDef.h +++ b/src/Utilities/TemplateDef.h @@ -1508,6 +1508,50 @@ if(_strcmpi(parser.value(), #name) == 0){ value = __uuidof(name ## LocomotionCla Debug::INIParseFailed(pSection, pKey, pCur); } } + + template <> + inline bool read(SeparateWeaponType& value, INI_EX& parser, const char* pSection, const char* pKey) + { + if (parser.ReadString(pSection, pKey)) + { + static const std::pair Names[] = + { + {"deployfire", SeparateWeaponType::DeployFire}, + {"opentransport", SeparateWeaponType::OpenTransport}, + {"noammo", SeparateWeaponType::NoAmmo}, + {"all", SeparateWeaponType::All}, + { "none", SeparateWeaponType::None }, + }; + + auto parsed = SeparateWeaponType::None; + for (auto&& part : std::string_view { parser.value() } | std::views::split(',')) + { + std::string_view&& cur { part.begin(), part.end() }; + *const_cast(cur.data() + cur.find_last_not_of(" \t\r") + 1) = 0; + auto pCur = cur.data() + cur.find_first_not_of(" \t\r"); + bool matched = false; + for (auto const& [name, val] : Names) + { + if (_strcmpi(pCur, name) == 0) + { + parsed |= val; + matched = true; + break; + } + } + if (!matched) + { + Debug::INIParseFailed(pSection, pKey, pCur, "Expected an separate weapon type"); + return false; + } + } + + value = parsed; + return true; + } + + return false; + } } From e9d1ff05c50769812d0786a7bf94c6c084cf6d7e Mon Sep 17 00:00:00 2001 From: Fly-Star <100747645+a851903106@users.noreply.github.com> Date: Sat, 7 Feb 2026 15:22:53 +0800 Subject: [PATCH 04/10] Update New-or-Enhanced-Logics.md --- docs/New-or-Enhanced-Logics.md | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/docs/New-or-Enhanced-Logics.md b/docs/New-or-Enhanced-Logics.md index f02e1c73ba..bdb23785b9 100644 --- a/docs/New-or-Enhanced-Logics.md +++ b/docs/New-or-Enhanced-Logics.md @@ -2068,6 +2068,7 @@ SuppressRevengeWeapons.Types= ; List of WeaponTypes ### Separation AutoTarget - `DeployFireWeapon`, `OpenTransportWeapon`, and `NoAmmoWeapon` can use separate auto-targeting instead of all weapons sharing a common decision. + - Please note that weapons using separate automatic targeting will not perform automatic attacks on certain descending aerial targets if the projectile has `AG=no` and `AA=yes`. In `rulesmd.ini`: ```ini @@ -2075,9 +2076,6 @@ In `rulesmd.ini`: SeparateWeaponTypes=none ; List of SeparateWeaponType Enumeration (none|deployfireweapon|opentransport|noammo|all) ``` -```{warning} -Please note that weapons using separate automatic targeting will not perform automatic attacks on certain descending aerial targets if the projectile has `AG=no` and `AA=yes` -``` ### Shared Ammo From 32bdb2a833ad6a47814c3324f332ecb7ab56b2c9 Mon Sep 17 00:00:00 2001 From: Fly-Star <100747645+a851903106@users.noreply.github.com> Date: Sat, 7 Feb 2026 15:52:05 +0800 Subject: [PATCH 05/10] Update New-or-Enhanced-Logics.md --- docs/New-or-Enhanced-Logics.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/New-or-Enhanced-Logics.md b/docs/New-or-Enhanced-Logics.md index bdb23785b9..cdcb594590 100644 --- a/docs/New-or-Enhanced-Logics.md +++ b/docs/New-or-Enhanced-Logics.md @@ -2067,7 +2067,7 @@ SuppressRevengeWeapons.Types= ; List of WeaponTypes ### Separation AutoTarget -- `DeployFireWeapon`, `OpenTransportWeapon`, and `NoAmmoWeapon` can use separate auto-targeting instead of all weapons sharing a common decision. +- In Vanilla, when `TurretCount` is less than or equal to 0, units can only repair/heal targets if the average of all weapons' `Damage + AmbientDamage` is less than 0. This mechanism may prevent units equipped with both healing and lethal weapons from correctly using specific weapons like `DeployFireWeapon`, `OpenTransportWeapon`, or `NoAmmoWeapon`. Now you can use a new flag `SeparateWeaponTypes` to overcome this problem. - Please note that weapons using separate automatic targeting will not perform automatic attacks on certain descending aerial targets if the projectile has `AG=no` and `AA=yes`. In `rulesmd.ini`: From a652aa90d4d128dd71c765de0306083d98699405 Mon Sep 17 00:00:00 2001 From: Fly-Star <100747645+a851903106@users.noreply.github.com> Date: Sat, 7 Feb 2026 16:18:48 +0800 Subject: [PATCH 06/10] update doc --- docs/Fixed-or-Improved-Logics.md | 10 ++++++++++ docs/New-or-Enhanced-Logics.md | 12 ------------ 2 files changed, 10 insertions(+), 12 deletions(-) diff --git a/docs/Fixed-or-Improved-Logics.md b/docs/Fixed-or-Improved-Logics.md index 7779d9a2a5..4d343def97 100644 --- a/docs/Fixed-or-Improved-Logics.md +++ b/docs/Fixed-or-Improved-Logics.md @@ -1798,6 +1798,16 @@ In `rulesmd.ini`: RadarInvisibleToHouse= ; Affected House Enumeration (none|owner/self|allies/ally|team|enemies/enemy|all), default to enemy if RadarInvisible=true, none otherwise ``` +### Separation AutoTarget + +- In Vanilla, when `IsGattling=no` and `TurretCount` is less than or equal to 0, units will only repair/heal targets if the following condition is met: the total `Damage + AmbientDamage` of all weapons divided by the total number of weapons is less than 0. This may cause units equipped with both healing and lethal weapons to fail to properly execute `DeployFireWeapon`, `OpenTransportWeapon`, and `NoAmmoWeapon`. Now you can use a new flag `SeparateWeaponTypes` to overcome this problem. + +In `rulesmd.ini`: +```ini +[SOMETECHNO] ; TechnoType +SeparateWeaponTypes=none ; List of SeparateWeaponType Enumeration (none|deployfireweapon|opentransport|noammo|all) +``` + ### Subterranean unit travel height and speed - It is now possible to control the height at which units with subterranean (Tunnel) `Locomotor` travel, globally or per TechnoType. diff --git a/docs/New-or-Enhanced-Logics.md b/docs/New-or-Enhanced-Logics.md index cdcb594590..0e2c666d66 100644 --- a/docs/New-or-Enhanced-Logics.md +++ b/docs/New-or-Enhanced-Logics.md @@ -2065,18 +2065,6 @@ SuppressRevengeWeapons=false ; boolean SuppressRevengeWeapons.Types= ; List of WeaponTypes ``` -### Separation AutoTarget - -- In Vanilla, when `TurretCount` is less than or equal to 0, units can only repair/heal targets if the average of all weapons' `Damage + AmbientDamage` is less than 0. This mechanism may prevent units equipped with both healing and lethal weapons from correctly using specific weapons like `DeployFireWeapon`, `OpenTransportWeapon`, or `NoAmmoWeapon`. Now you can use a new flag `SeparateWeaponTypes` to overcome this problem. - - Please note that weapons using separate automatic targeting will not perform automatic attacks on certain descending aerial targets if the projectile has `AG=no` and `AA=yes`. - -In `rulesmd.ini`: -```ini -[SOMETECHNO] ; TechnoType -SeparateWeaponTypes=none ; List of SeparateWeaponType Enumeration (none|deployfireweapon|opentransport|noammo|all) -``` - - ### Shared Ammo - Transports with `OpenTopped=yes` and `Ammo.Shared=yes` will transfer ammo to passengers that have `Ammo.Shared=yes`. From 22dea3bd427637fcec0d542bf992e56ae8b614ce Mon Sep 17 00:00:00 2001 From: Fly-Star <100747645+a851903106@users.noreply.github.com> Date: Sat, 7 Feb 2026 16:43:11 +0800 Subject: [PATCH 07/10] Update Fixed-or-Improved-Logics.md --- docs/Fixed-or-Improved-Logics.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/Fixed-or-Improved-Logics.md b/docs/Fixed-or-Improved-Logics.md index 4d343def97..12d7f2f963 100644 --- a/docs/Fixed-or-Improved-Logics.md +++ b/docs/Fixed-or-Improved-Logics.md @@ -1801,6 +1801,7 @@ RadarInvisibleToHouse= ; Affected House Enumeration (none|owner/se ### Separation AutoTarget - In Vanilla, when `IsGattling=no` and `TurretCount` is less than or equal to 0, units will only repair/heal targets if the following condition is met: the total `Damage + AmbientDamage` of all weapons divided by the total number of weapons is less than 0. This may cause units equipped with both healing and lethal weapons to fail to properly execute `DeployFireWeapon`, `OpenTransportWeapon`, and `NoAmmoWeapon`. Now you can use a new flag `SeparateWeaponTypes` to overcome this problem. + - When using a separate auto-aiming device, the effective range will use the current weapon's range rather than the unit's maximum weapon range, `GuardRange` remains effective. Whether ground or air targets can be attacked is also entirely determined by the current weapon. In `rulesmd.ini`: ```ini From 9b5f464f3c9d11bb7f25fe4e8e3ed8df9b59b3f3 Mon Sep 17 00:00:00 2001 From: Noble_Fish <1065703286@qq.com> Date: Sat, 7 Feb 2026 18:09:10 +0800 Subject: [PATCH 08/10] update docs --- docs/Fixed-or-Improved-Logics.md | 4 ++-- docs/Whats-New.md | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/Fixed-or-Improved-Logics.md b/docs/Fixed-or-Improved-Logics.md index 12d7f2f963..5ac3105e9f 100644 --- a/docs/Fixed-or-Improved-Logics.md +++ b/docs/Fixed-or-Improved-Logics.md @@ -1800,8 +1800,8 @@ RadarInvisibleToHouse= ; Affected House Enumeration (none|owner/se ### Separation AutoTarget -- In Vanilla, when `IsGattling=no` and `TurretCount` is less than or equal to 0, units will only repair/heal targets if the following condition is met: the total `Damage + AmbientDamage` of all weapons divided by the total number of weapons is less than 0. This may cause units equipped with both healing and lethal weapons to fail to properly execute `DeployFireWeapon`, `OpenTransportWeapon`, and `NoAmmoWeapon`. Now you can use a new flag `SeparateWeaponTypes` to overcome this problem. - - When using a separate auto-aiming device, the effective range will use the current weapon's range rather than the unit's maximum weapon range, `GuardRange` remains effective. Whether ground or air targets can be attacked is also entirely determined by the current weapon. +- In vanilla, when a unit's TurretCount is not greater than 0 and IsGattling=yes is not set, it calculates the sum of all weapons' Damage and all weapons' AmbientDamage, then divides by the number of weapons (rounding towards zero). If the result is less than 0, the unit is considered to use a repair weapon; otherwise, it is an offensive weapon. This may cause units that have both repair and damage weapons to be unable to properly use DeployFireWeapon, OpenTransportWeapon, and NoAmmoWeapon. Now this issue can be resolved by the newly added SeparateWeaponTypes list. + - When using separation auto target, if GuardRange is not set, the effective range will use the current weapon's own Range, rather than the maximum Range among all the unit's weapons. Functions such as whether it can attack ground or air targets, and whether it uses repair behavior, which were originally based on average calculations, are now entirely determined by the current weapon's own settings. In `rulesmd.ini`: ```ini diff --git a/docs/Whats-New.md b/docs/Whats-New.md index 6411bcf398..89c01484fe 100644 --- a/docs/Whats-New.md +++ b/docs/Whats-New.md @@ -535,7 +535,7 @@ New: - Option to scale `PowerSurplus` setting if enabled to current power drain with `PowerSurplus.ScaleToDrainAmount` (by Starkku) - Global default value for `DefaultToGuardArea` (by TaranDahl) - [Weapon range finding in cylinder](New-or-Enhanced-Logics.md#range-finding-in-cylinder) (by TaranDahl) -- Separation of AutoTarget for `DeployFireWeapon`, `OpenTransportWeapon`, and `NoAmmoWeapon` (by FlyStar) +- [Separation of AutoTarget for `DeployFireWeapon`, `OpenTransportWeapon`, and `NoAmmoWeapon`](Fixed-or-Improved-Logics.md#separation-autotarget) (by FlyStar) Vanilla fixes: - Fixed sidebar not updating queued unit numbers when adding or removing units when the production is on hold (by CrimRecya) From 2d3eefb9d5a8c73a580e0eb2f7496b471975f697 Mon Sep 17 00:00:00 2001 From: Noble_Fish <1065703286@qq.com> Date: Sat, 7 Feb 2026 18:18:30 +0800 Subject: [PATCH 09/10] Lost format --- docs/Fixed-or-Improved-Logics.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/Fixed-or-Improved-Logics.md b/docs/Fixed-or-Improved-Logics.md index 5ac3105e9f..ece5cc53ef 100644 --- a/docs/Fixed-or-Improved-Logics.md +++ b/docs/Fixed-or-Improved-Logics.md @@ -1800,8 +1800,8 @@ RadarInvisibleToHouse= ; Affected House Enumeration (none|owner/se ### Separation AutoTarget -- In vanilla, when a unit's TurretCount is not greater than 0 and IsGattling=yes is not set, it calculates the sum of all weapons' Damage and all weapons' AmbientDamage, then divides by the number of weapons (rounding towards zero). If the result is less than 0, the unit is considered to use a repair weapon; otherwise, it is an offensive weapon. This may cause units that have both repair and damage weapons to be unable to properly use DeployFireWeapon, OpenTransportWeapon, and NoAmmoWeapon. Now this issue can be resolved by the newly added SeparateWeaponTypes list. - - When using separation auto target, if GuardRange is not set, the effective range will use the current weapon's own Range, rather than the maximum Range among all the unit's weapons. Functions such as whether it can attack ground or air targets, and whether it uses repair behavior, which were originally based on average calculations, are now entirely determined by the current weapon's own settings. +- In vanilla, when a unit's `TurretCount` is not greater than 0 and `IsGattling=yes` is not set, it calculates the sum of all weapons' `Damage` and all weapons' `AmbientDamage`, then divides by the number of weapons (rounding towards zero). If the result is less than 0, the unit is considered to use a repair weapon; otherwise, it is an offensive weapon. This may cause units that have both repair and damage weapons to be unable to properly use `DeployFireWeapon`, `OpenTransportWeapon`, and `NoAmmoWeapon`. Now this issue can be resolved by the newly added `SeparateWeaponTypes` list. + - When using separation auto target, if `GuardRange` is not set, the effective range will use the current weapon's own `Range`, rather than the maximum `Range` among all the unit's weapons. Functions such as whether it can attack ground or air targets, and whether it uses repair behavior, which were originally based on average calculations, are now entirely determined by the current weapon's own settings. In `rulesmd.ini`: ```ini From 3efab7c2f78495dfa0b01491a554a2904ef6d6b4 Mon Sep 17 00:00:00 2001 From: Fly-Star <100747645+a851903106@users.noreply.github.com> Date: Tue, 10 Feb 2026 12:44:23 +0800 Subject: [PATCH 10/10] eemove duplicates --- CREDITS.md | 2 - src/Ext/TechnoType/Hooks.MultiWeapon.cpp | 80 ------------------------ 2 files changed, 82 deletions(-) diff --git a/CREDITS.md b/CREDITS.md index f479da8d16..483c4b7773 100644 --- a/CREDITS.md +++ b/CREDITS.md @@ -411,8 +411,6 @@ This page lists all the individual contributions to the project by their author. - Vehicle Deployment Enhancement - Fix an issue where miners affected by `Passengers/DeployFire` were unable to unload minerals - Fix an issue where mining vehicles could not move after leaving a tank bunker - - Fixed an issue where miners affected by `Passengers/DeployFire` were unable to unload minerals - - Fixed an issue where mining vehicles could not move after leaving a tank bunker - Separation of AutoTarget for `DeployFireWeapon`, `OpenTransportWeapon`, and `NoAmmoWeapon` - **NetsuNegi**: - Forbidding parallel AI queues by type diff --git a/src/Ext/TechnoType/Hooks.MultiWeapon.cpp b/src/Ext/TechnoType/Hooks.MultiWeapon.cpp index 64d308874d..4a14a00717 100644 --- a/src/Ext/TechnoType/Hooks.MultiWeapon.cpp +++ b/src/Ext/TechnoType/Hooks.MultiWeapon.cpp @@ -356,83 +356,3 @@ DEFINE_HOOK(0x6F398E, TechnoClass_CombatDamage_MultiWeapon, 0x7) R->EAX(pThis->Veterancy.IsElite() ? pTypeExt->CombatDamages.Y : pTypeExt->CombatDamages.X); return ReturnDamage; } - -DEFINE_HOOK(0x707ED0, TechnoClass_GetGuardRange_MultiWeapon, 0x6) -{ - enum { ReturnRange = 0x707F08 }; - - GET(TechnoClass*, pThis, ESI); - - const auto pType = pThis->GetTechnoType(); - const bool specialWeapon = !pType->IsGattling && (!pType->HasMultipleTurrets() || !pType->Gunner); - const AbstractType rtti = pThis->WhatAmI(); - - if (!pType->IsGattling && pType->TurretCount > 0 - && (pType->Gunner || !specialWeapon) - && rtti == AbstractType::Unit) - { - R->EAX(pThis->GetWeaponRange(pThis->CurrentWeaponNumber)); - return ReturnRange; - } - - const auto pTypeExt = TechnoTypeExt::ExtMap.Find(pType); - const SeparateWeaponType weaponTypes = pTypeExt->SeparateWeaponTypes; - - if (weaponTypes & SeparateWeaponType::DeployFire) - { - const int deployFireWeapon = pType->DeployFireWeapon; - - if (IsDeployed(pThis, rtti) && pType->DeployFire && deployFireWeapon >= 0) - { - const int range = pThis->GetWeaponRange(deployFireWeapon); - - R->EAX(range); - return ReturnRange; - } - } - - if (weaponTypes & SeparateWeaponType::OpenTransport) - { - const int openTransportWeapon = pType->OpenTransportWeapon; - - if (pThis->InOpenToppedTransport && openTransportWeapon >= 0) - { - const int range = pThis->GetWeaponRange(openTransportWeapon); - - R->EAX(range); - return ReturnRange; - } - } - - if (weaponTypes & SeparateWeaponType::NoAmmo) - { - const int noAmmoWeapon = pTypeExt->NoAmmoWeapon; - - if (pType->Ammo >= 0 && noAmmoWeapon >= 0 && pThis->Ammo <= pTypeExt->NoAmmoAmount) - { - const int range = pThis->GetWeaponRange(noAmmoWeapon); - - R->EAX(range); - return ReturnRange; - } - } - - if (pTypeExt->MultiWeapon && specialWeapon) - { - const int selectCount = Math::min(pType->WeaponCount, pTypeExt->MultiWeapon_SelectCount); - int range = 0; - - for (int index = selectCount - 1; index >= 0; --index) - { - const auto weaponRange = pThis->GetWeaponRange(index); - - if (weaponRange > range) - range = weaponRange; - } - - R->EAX(range); - return ReturnRange; - } - - return 0; -}