From 7fb7dc8a380302db060caff077be88e61e24d8c9 Mon Sep 17 00:00:00 2001 From: Noble_Fish <1065703286@qq.com> Date: Sun, 30 Aug 2026 06:41:05 +0800 Subject: [PATCH 1/2] initial --- CREDITS.md | 1 + docs/Fixed-or-Improved-Logics.md | 10 ++++++++++ docs/Whats-New.md | 1 + src/Ext/Infantry/Hooks.cpp | 13 +++++++++++++ src/Ext/InfantryType/Body.cpp | 2 ++ src/Ext/InfantryType/Body.h | 2 ++ 6 files changed, 29 insertions(+) diff --git a/CREDITS.md b/CREDITS.md index ded5242180..c44de54dee 100644 --- a/CREDITS.md +++ b/CREDITS.md @@ -756,6 +756,7 @@ This page lists all the individual contributions to the project by their author. - Roof production anim - Customize whether the unit exits from the roof - Customize whether the unit can be detected by psychic detector + - Customize `IdleActionFrequency` - **Ollerus**: - Build limit group enhancement - Customizable rocker amplitude diff --git a/docs/Fixed-or-Improved-Logics.md b/docs/Fixed-or-Improved-Logics.md index 96b988df86..fb7cb887b0 100644 --- a/docs/Fixed-or-Improved-Logics.md +++ b/docs/Fixed-or-Improved-Logics.md @@ -2686,6 +2686,16 @@ In `rulesmd.ini`: HarvesterLoadRate= ; integer, default to [General] -> HarvesterLoadRate ``` +### Customize `IdleActionFrequency` + +- Now `IdleActionFrequency` can be customized on each infantry. + +In `rulesmd.ini`: +```ini +[SOMEINFANTRY] ; InfantryType +IdleActionFrequency= ; floating point value, default to [AudioVisual] -> IdleActionFrequency +``` + ### Customize type selection for IFV - In vanilla game, when using type selection command on IFVs, all of them will be selected regardless of their current modes, which is allowed to customize now. diff --git a/docs/Whats-New.md b/docs/Whats-New.md index 2d5542f1be..5f57f67973 100644 --- a/docs/Whats-New.md +++ b/docs/Whats-New.md @@ -433,6 +433,7 @@ HideShakeEffects=false ; boolean - [Customize whether the unit can be detected by psychic detector](Fixed-or-Improved-Logics.md#customize-whether-the-unit-can-be-detected-by-psychic-detector) (by Noble_Fish) - Cloak Enhancement (by NetsuNegi) - [`513` Set mission timer properties](AI-Scripting-and-Mapping.md#set-mission-timer-properties) (by Ollerus) +- [Customize `IdleActionFrequency`](Fixed-or-Improved-Logics.md#customize-idleactionfrequency) (by Noble_Fish) #### Vanilla fixes: - Fixed the bug where a building with `Factory=BuildingType` owned by the AI did not play `ProductionAnim` when placing a produced building (by Noble_Fish) diff --git a/src/Ext/Infantry/Hooks.cpp b/src/Ext/Infantry/Hooks.cpp index c454ac6d56..1dc5801fa4 100644 --- a/src/Ext/Infantry/Hooks.cpp +++ b/src/Ext/Infantry/Hooks.cpp @@ -209,3 +209,16 @@ DEFINE_HOOK(0x51A002, InfantryClass_UpdatePosition_InfiltrateBuilding, 0x6) return 0; } + +DEFINE_HOOK_AGAIN(0x51CDD9, InfantryClass_UpdateIdleAction_IdleActionFrequency, 0x6) +DEFINE_HOOK(0x51CDEF, InfantryClass_UpdateIdleAction_IdleActionFrequency, 0x6) +{ + GET(InfantryClass* const, pThis, ESI); + auto const pTypeExt = InfantryTypeExt::Fetch(pThis->Type); + + double idleActionFrequency = pTypeExt->IdleActionFrequency.Get(RulesClass::Instance->IdleActionFrequency); + + __asm { fld idleActionFrequency } + + return R->Origin() + 0x6; +} diff --git a/src/Ext/InfantryType/Body.cpp b/src/Ext/InfantryType/Body.cpp index 48c94999a1..de476dcf0e 100644 --- a/src/Ext/InfantryType/Body.cpp +++ b/src/Ext/InfantryType/Body.cpp @@ -33,6 +33,7 @@ void InfantryTypeExt::LoadFromINIFile(CCINIClass* const pINI) this->ProneSecondaryFireFLH.Read(exArtINI, pArtSection, "ProneSecondaryFireFLH"); this->DeployedPrimaryFireFLH.Read(exArtINI, pArtSection, "DeployedPrimaryFireFLH"); this->DeployedSecondaryFireFLH.Read(exArtINI, pArtSection, "DeployedSecondaryFireFLH"); + this->IdleActionFrequency.Read(exINI, pSection, "IdleActionFrequency"); } template @@ -55,6 +56,7 @@ void InfantryTypeExt::Serialize(T& Stm) .Process(this->DeployedWeaponBurstFLHs) .Process(this->EliteDeployedWeaponBurstFLHs) .Process(this->InfantryAutoDeploy) + .Process(this->IdleActionFrequency) ; } diff --git a/src/Ext/InfantryType/Body.h b/src/Ext/InfantryType/Body.h index 2c38f7afc3..3a3b4f735e 100644 --- a/src/Ext/InfantryType/Body.h +++ b/src/Ext/InfantryType/Body.h @@ -27,6 +27,7 @@ class InfantryTypeExt final : public TechnoTypeExt std::vector> DeployedWeaponBurstFLHs; std::vector> EliteDeployedWeaponBurstFLHs; Nullable InfantryAutoDeploy; + Nullable IdleActionFrequency; explicit InfantryTypeExt(InfantryTypeClass* const OwnerObject) : TechnoTypeExt(OwnerObject) , Slaved_OwnerWhenMasterKilled { SlaveChangeOwnerType::Killer } @@ -41,6 +42,7 @@ class InfantryTypeExt final : public TechnoTypeExt , DeployedPrimaryFireFLH {} , DeployedSecondaryFireFLH {} , InfantryAutoDeploy {} + , IdleActionFrequency {} { } InfantryTypeClass* OwnerObject() const From 265a20d34070b5f2427ab51798d13de08ed77666 Mon Sep 17 00:00:00 2001 From: Noble_Fish <1065703286@qq.com> Date: Sun, 30 Aug 2026 08:15:26 +0800 Subject: [PATCH 2/2] two value: lower, uppper --- docs/Fixed-or-Improved-Logics.md | 4 +++- src/Ext/Infantry/Hooks.cpp | 24 +++++++++++++++++++++--- src/Ext/InfantryType/Body.h | 2 +- 3 files changed, 25 insertions(+), 5 deletions(-) diff --git a/docs/Fixed-or-Improved-Logics.md b/docs/Fixed-or-Improved-Logics.md index fb7cb887b0..360fdc0c01 100644 --- a/docs/Fixed-or-Improved-Logics.md +++ b/docs/Fixed-or-Improved-Logics.md @@ -2689,11 +2689,13 @@ HarvesterLoadRate= ; integer, default to [General] -> Harvest ### Customize `IdleActionFrequency` - Now `IdleActionFrequency` can be customized on each infantry. + - With a single value, the interval is a random value between `IdleActionFrequency * 450` and `IdleActionFrequency * 1800` frames, which customizes the frequency the same way the global value does. + - With two values, the first one directly sets the lower bound and the second one the upper bound of the random interval in frames. In `rulesmd.ini`: ```ini [SOMEINFANTRY] ; InfantryType -IdleActionFrequency= ; floating point value, default to [AudioVisual] -> IdleActionFrequency +IdleActionFrequency= ; a single floating point value, or a pair of integers defining the random delay range in frames (min, max), defaults to [AudioVisual] -> IdleActionFrequency ``` ### Customize type selection for IFV diff --git a/src/Ext/Infantry/Hooks.cpp b/src/Ext/Infantry/Hooks.cpp index 1dc5801fa4..8d2a708695 100644 --- a/src/Ext/Infantry/Hooks.cpp +++ b/src/Ext/Infantry/Hooks.cpp @@ -216,9 +216,27 @@ DEFINE_HOOK(0x51CDEF, InfantryClass_UpdateIdleAction_IdleActionFrequency, 0x6) GET(InfantryClass* const, pThis, ESI); auto const pTypeExt = InfantryTypeExt::Fetch(pThis->Type); - double idleActionFrequency = pTypeExt->IdleActionFrequency.Get(RulesClass::Instance->IdleActionFrequency); + if (auto const pRange = pTypeExt->IdleActionFrequency.GetEx()) + { + const bool isUpperBound = R->Origin() == 0x51CDD9; + double value; + + if (pRange->ValueCount >= 2) + { + // Two values set the delay range directly in frames, + const double lower = std::min(pRange->X, pRange->Y); + const double upper = std::max(pRange->X, pRange->Y); + value = isUpperBound ? upper / 1800.0 : lower / 450.0; + } + else + { + value = pRange->X; + } - __asm { fld idleActionFrequency } + __asm { fld value } - return R->Origin() + 0x6; + return R->Origin() + 0x6; + } + + return 0; } diff --git a/src/Ext/InfantryType/Body.h b/src/Ext/InfantryType/Body.h index 3a3b4f735e..a2b5094b42 100644 --- a/src/Ext/InfantryType/Body.h +++ b/src/Ext/InfantryType/Body.h @@ -27,7 +27,7 @@ class InfantryTypeExt final : public TechnoTypeExt std::vector> DeployedWeaponBurstFLHs; std::vector> EliteDeployedWeaponBurstFLHs; Nullable InfantryAutoDeploy; - Nullable IdleActionFrequency; + Nullable> IdleActionFrequency; explicit InfantryTypeExt(InfantryTypeClass* const OwnerObject) : TechnoTypeExt(OwnerObject) , Slaved_OwnerWhenMasterKilled { SlaveChangeOwnerType::Killer }