diff --git a/CREDITS.md b/CREDITS.md index 1d410c0135..5dd5691572 100644 --- a/CREDITS.md +++ b/CREDITS.md @@ -689,6 +689,7 @@ This page lists all the individual contributions to the project by their author. - Fixed an issue that retaliation will make the unit keep switching among multiple targets with the same amount of threat - 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` + - Customize several behavior of mission area guard - **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 4193783447..8975046314 100644 --- a/docs/Fixed-or-Improved-Logics.md +++ b/docs/Fixed-or-Improved-Logics.md @@ -1560,6 +1560,27 @@ FallingDownDamage= ; integer / percentage FallingDownDamage.Water= ; integer / percentage ``` +### Customize several behavior of mission area guard + +- In vanilla, technos in area guard mission will use the focus as the center of targeting and stray. + - Now you can change the center to itself by using `AreaGuard.UseSelfAsCenter=true`. (For stray, what is checked is the distance between the techno and the current target) +- In vanilla, technos in area guard mission will do targeting in an extended range (roughly 2 times of the guard range). + - Now you can change the range to the guard range by using `AreaGuard.TargetingInRange=true`. +- In vanilla, technos in area guard mission will not stray unless it has no destination. + - Now you can change the behavior by using `AreaGuard.StrayIgnoreDestination=true`. + +In `rulesmd.ini`: +```ini +[General] +AreaGuard.UseSelfAsCenter= ; boolean +AreaGuard.TargetingInRange= ; boolean +AreaGuard.StrayIgnoreDestination= ; boolean +``` + +```{note} +In vanilla, if `GuardRange` is not set, then the guard range will be automatically deduced based on the weapon range. +``` + ### 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 e8d0b5cde9..484079c288 100644 --- a/docs/Whats-New.md +++ b/docs/Whats-New.md @@ -534,6 +534,7 @@ New: - [Customizable paradropped unit missions](Fixed-or-Improved-Logics.md#customizable-paradrop-missions) (by Starkku) - Option to scale `PowerSurplus` setting if enabled to current power drain with `PowerSurplus.ScaleToDrainAmount` (by Starkku) - Global default value for `DefaultToGuardArea` (by TaranDahl) +- [Customize several behavior of mission area guard](Fixed-or-Improved-Logics.md#customize-several-behavior-of-mission-area-guard) (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 a8fc44b19b..8eb53eac32 100644 --- a/src/Ext/Rules/Body.cpp +++ b/src/Ext/Rules/Body.cpp @@ -362,6 +362,10 @@ void RulesExt::ExtData::LoadBeforeTypeData(RulesClass* pThis, CCINIClass* pINI) this->ParadropMission.Read(exINI, GameStrings::General, "ParadropMission"); this->AIParadropMission.Read(exINI, GameStrings::General, "AIParadropMission"); + this->AreaGuard_UseSelfAsCenter.Read(exINI, GameStrings::General, "AreaGuard.UseSelfAsCenter"); + this->AreaGuard_TargetingInRange.Read(exINI, GameStrings::General, "AreaGuard.TargetingInRange"); + this->AreaGuard_StrayIgnoreDestination.Read(exINI, GameStrings::General, "AreaGuard.StrayIgnoreDestination"); + // Section AITargetTypes int itemsCount = pINI->GetKeyCount("AITargetTypes"); for (int i = 0; i < itemsCount; ++i) @@ -660,6 +664,9 @@ void RulesExt::ExtData::Serialize(T& Stm) .Process(this->ParadropMission) .Process(this->AIParadropMission) .Process(this->DefaultToGuardArea) + .Process(this->AreaGuard_UseSelfAsCenter) + .Process(this->AreaGuard_TargetingInRange) + .Process(this->AreaGuard_StrayIgnoreDestination) ; } diff --git a/src/Ext/Rules/Body.h b/src/Ext/Rules/Body.h index 1d3e6603e2..7452c2e13f 100644 --- a/src/Ext/Rules/Body.h +++ b/src/Ext/Rules/Body.h @@ -1,4 +1,4 @@ -#pragma once +#pragma once #include #include @@ -311,6 +311,9 @@ class RulesExt Valueable AIParadropMission; Valueable DefaultToGuardArea; + Valueable AreaGuard_UseSelfAsCenter; + Valueable AreaGuard_TargetingInRange; + Valueable AreaGuard_StrayIgnoreDestination; ExtData(RulesClass* OwnerObject) : Extension(OwnerObject) , Storage_TiberiumIndex { -1 } @@ -566,6 +569,9 @@ class RulesExt , AIParadropMission { Mission::Hunt } , DefaultToGuardArea { false } + , AreaGuard_UseSelfAsCenter { false } + , AreaGuard_TargetingInRange { false } + , AreaGuard_StrayIgnoreDestination { false } { } virtual ~ExtData() = default; diff --git a/src/Ext/Techno/Hooks.Targeting.cpp b/src/Ext/Techno/Hooks.Targeting.cpp index ff1da00c3d..6622d9b652 100644 --- a/src/Ext/Techno/Hooks.Targeting.cpp +++ b/src/Ext/Techno/Hooks.Targeting.cpp @@ -69,3 +69,36 @@ DEFINE_HOOK(0x6F7CE2, TechnoClass_CanAutoTargetObject_IronCurtain, 0x6) return 0; } + +#pragma region AreaGuard + +DEFINE_HOOK(0x4D6E9F, FootClass_MissionAreaGuard_UseSelfAsCenter, 0x6) +{ + enum { CheckDist = 0x4D6EAF, ResetTarget = 0x4D6ED1 }; + + GET(FootClass*, pThis, ESI); + + if (!RulesExt::Global()->AreaGuard_StrayIgnoreDestination && pThis->Destination) + return ResetTarget; + + R->EAX(pThis->DistanceFrom(RulesExt::Global()->AreaGuard_UseSelfAsCenter ? pThis->Target : pThis->ArchiveTarget)); + return CheckDist; +} + +namespace AreaGuard_UseSelfAsCenterContext +{ + CoordStruct crd; +} + +DEFINE_HOOK(0x4D6EFD, FootClass_MissionAreaGuard_Extend, 0x6) +{ + enum { SkipGameCode = 0x4D6F03 }; + + GET(FootClass*, pThis, ESI); + AreaGuard_UseSelfAsCenterContext::crd = (RulesExt::Global()->AreaGuard_UseSelfAsCenter ? pThis : pThis->ArchiveTarget)->GetCoords(); + R->EAX(&AreaGuard_UseSelfAsCenterContext::crd); + R->Stack(0, RulesExt::Global()->AreaGuard_TargetingInRange ? ThreatType::Range : ThreatType::Area); + return 0; +} + +#pragma endregion