diff --git a/CREDITS.md b/CREDITS.md index ecf82be902..a729a79598 100644 --- a/CREDITS.md +++ b/CREDITS.md @@ -692,6 +692,7 @@ This page lists all the individual contributions to the project by their author. - Fix an issue where units recruited by a team with `AreTeamMembersRecruitable=false` cannot be recruited even if they have been liberated by that team - Global default value for `DefaultToGuardArea` - Weapon range finding in cylinder + - Customize the keep-target-range of attackmove - **solar-III (凤九歌)** - Target scanning delay customization (documentation) - Skip target scanning function calling for unarmed technos (documentation) diff --git a/docs/Fixed-or-Improved-Logics.md b/docs/Fixed-or-Improved-Logics.md index 8e683b6ade..8118c82c6c 100644 --- a/docs/Fixed-or-Improved-Logics.md +++ b/docs/Fixed-or-Improved-Logics.md @@ -1562,6 +1562,26 @@ FallingDownDamage= ; integer / percentage FallingDownDamage.Water= ; integer / percentage ``` +### Customize the keep-target-range of attackmove + +- In vanilla, the range of keep target in attackmove is determined by the range of weapon, or the range of the secondary weapon with `NeverUse=yes`. +- Now you can directly specify this distance by setting the following flag to a non-negative value. + - `AttackMove.KeepTargetRange` is used to directly specify this distance. It takes effect when this flag is not less than 0. + - `AttackMove.KeepTargetRangeMultiplier` and `AttackMove.KeepTargetRangeAddend` are used to automatically calculate this distance based on the guard range. It takes effect when the multiplier is not less than 0. + - The final distance is guard range * multiplier + addend. + +In `rulesmd.ini`: +```ini +[General] +AttackMove.KeepTargetRangeMultiplier=-1.0 ; float +AttackMove.KeepTargetRangeAddend=0.0 ; float, range in cell + +[SOMETECHNO] ; TechnoType +AttackMove.KeepTargetRange=-1.0 ; float, range in cell +AttackMove.KeepTargetRangeMultiplier= ; float +AttackMove.KeepTargetRangeAddend= ; float, range in cell +``` + ### Damaged speed customization - In vanilla, units using drive/ship loco will has hardcoded speed multiplier when damaged. Now you can customize it. diff --git a/docs/Whats-New.md b/docs/Whats-New.md index 975aeed572..5287e79b1a 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) +- Customize the keep-target-range of attackmove (by TaranDahl) 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/Rules/Body.cpp b/src/Ext/Rules/Body.cpp index ca47eeb3f8..4acd44e18a 100644 --- a/src/Ext/Rules/Body.cpp +++ b/src/Ext/Rules/Body.cpp @@ -363,6 +363,9 @@ void RulesExt::ExtData::LoadBeforeTypeData(RulesClass* pThis, CCINIClass* pINI) this->AIParadropMission.Read(exINI, GameStrings::General, "AIParadropMission"); this->CylinderRangefinding.Read(exINI, GameStrings::General, "CylinderRangefinding"); + + this->AttackMove_KeepTargetRangeAddend.Read(exINI, GameStrings::General, "AttackMove.KeepTargetRangeAddend"); + this->AttackMove_KeepTargetRangeMultiplier.Read(exINI, GameStrings::General, "AttackMove.KeepTargetRangeMultiplier"); // Section AITargetTypes int itemsCount = pINI->GetKeyCount("AITargetTypes"); @@ -663,6 +666,8 @@ void RulesExt::ExtData::Serialize(T& Stm) .Process(this->AIParadropMission) .Process(this->DefaultToGuardArea) .Process(this->CylinderRangefinding) + .Process(this->AttackMove_KeepTargetRangeAddend) + .Process(this->AttackMove_KeepTargetRangeMultiplier) ; } diff --git a/src/Ext/Rules/Body.h b/src/Ext/Rules/Body.h index 4001f0238b..45a4346bc5 100644 --- a/src/Ext/Rules/Body.h +++ b/src/Ext/Rules/Body.h @@ -1,4 +1,4 @@ -#pragma once +#pragma once #include #include @@ -314,6 +314,9 @@ class RulesExt Valueable CylinderRangefinding; + Valueable AttackMove_KeepTargetRangeAddend; + Valueable AttackMove_KeepTargetRangeMultiplier; + ExtData(RulesClass* OwnerObject) : Extension(OwnerObject) , Storage_TiberiumIndex { -1 } , HarvesterDumpAmount { 0.0f } @@ -570,6 +573,9 @@ class RulesExt , DefaultToGuardArea { false } , CylinderRangefinding { false } + + , AttackMove_KeepTargetRangeAddend { Leptons(0) } + , AttackMove_KeepTargetRangeMultiplier { -1.0 } { } virtual ~ExtData() = default; diff --git a/src/Ext/Techno/Hooks.cpp b/src/Ext/Techno/Hooks.cpp index 49daa58355..7824ece8ea 100644 --- a/src/Ext/Techno/Hooks.cpp +++ b/src/Ext/Techno/Hooks.cpp @@ -1188,6 +1188,35 @@ DEFINE_HOOK(0x4DF3A6, FootClass_UpdateAttackMove_Follow, 0x6) return 0; } +DEFINE_HOOK(0x6F78D0, TechnoClass_InAttackMoveKeepRange_Start, 0x6) +{ + enum { RETN = 0x6F7923 }; + + GET(TechnoClass*, pThis, ECX); + GET_STACK(AbstractClass*, pTarget, 0x4); + + auto pTypeExt = TechnoTypeExt::ExtMap.Find(pThis->GetTechnoType()); + int keepTargetRange = pTypeExt->AttackMove_KeepTargetRange.Get(); + + if (keepTargetRange >= 0) + { + R->AL(pThis->DistanceFrom(pTarget) <= keepTargetRange); + return RETN; + } + + double mult = pTypeExt->AttackMove_KeepTargetRangeMultiplier.Get(RulesExt::Global()->AttackMove_KeepTargetRangeMultiplier); + + if (mult >= 0) + { + auto addend = pTypeExt->AttackMove_KeepTargetRangeAddend.Get(RulesExt::Global()->AttackMove_KeepTargetRangeAddend); + + R->AL(pThis->DistanceFrom(pTarget) <= (int)(pThis->GetGuardRange(0) * mult) + addend); + return RETN; + } + + return 0; +} + #pragma endregion DEFINE_HOOK(0x708FC0, TechnoClass_ResponseMove_Pickup, 0x5) diff --git a/src/Ext/TechnoType/Body.cpp b/src/Ext/TechnoType/Body.cpp index 39560cc224..fc1ef07fe2 100644 --- a/src/Ext/TechnoType/Body.cpp +++ b/src/Ext/TechnoType/Body.cpp @@ -1150,6 +1150,10 @@ void TechnoTypeExt::ExtData::LoadFromINIFile(CCINIClass* const pINI) this->ParadropMission.Read(exINI, pSection, "ParadropMission"); this->AIParadropMission.Read(exINI, pSection, "AIParadropMission"); + this->AttackMove_KeepTargetRange.Read(exINI, pSection, "AttackMove.KeepTargetRange"); + this->AttackMove_KeepTargetRangeAddend.Read(exINI, pSection, "AttackMove.KeepTargetRangeAddend"); + this->AttackMove_KeepTargetRangeMultiplier.Read(exINI, pSection, "AttackMove.KeepTargetRangeMultiplier"); + // Ares 0.2 this->RadarJamRadius.Read(exINI, pSection, "RadarJamRadius"); @@ -1851,6 +1855,10 @@ void TechnoTypeExt::ExtData::Serialize(T& Stm) .Process(this->ParadropMission) .Process(this->AIParadropMission) + + .Process(this->AttackMove_KeepTargetRange) + .Process(this->AttackMove_KeepTargetRangeAddend) + .Process(this->AttackMove_KeepTargetRangeMultiplier) ; } void TechnoTypeExt::ExtData::LoadFromStream(PhobosStreamReader& Stm) diff --git a/src/Ext/TechnoType/Body.h b/src/Ext/TechnoType/Body.h index 7d161c89ca..42f9cc2157 100644 --- a/src/Ext/TechnoType/Body.h +++ b/src/Ext/TechnoType/Body.h @@ -475,6 +475,10 @@ class TechnoTypeExt Nullable ParadropMission; Nullable AIParadropMission; + Valueable AttackMove_KeepTargetRange; + Nullable AttackMove_KeepTargetRangeAddend; + Nullable AttackMove_KeepTargetRangeMultiplier; + ExtData(TechnoTypeClass* OwnerObject) : Extension(OwnerObject) , HealthBar_Hide { false } , HealthBar_HidePips { false } @@ -903,6 +907,10 @@ class TechnoTypeExt , ParadropMission {} , AIParadropMission {} + + , AttackMove_KeepTargetRange { Leptons(-256) } + , AttackMove_KeepTargetRangeAddend {} + , AttackMove_KeepTargetRangeMultiplier {} { } virtual ~ExtData() = default;