diff --git a/CREDITS.md b/CREDITS.md index e9773e684a..7cf29006b2 100644 --- a/CREDITS.md +++ b/CREDITS.md @@ -690,6 +690,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 + - Allow the unit to stop immediately if the target enters the range during ApproachTarget - **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..f93d695f91 100644 --- a/docs/Fixed-or-Improved-Logics.md +++ b/docs/Fixed-or-Improved-Logics.md @@ -1817,6 +1817,17 @@ SubterraneanSpeed=-1 ; floating point value `SubterraneanHeight` expects negative values to be used and may behave erratically if set to above -50. ``` +### Stop immediately if the target enters the range during ApproachTarget + +- In vanilla, the ApproachTarget will simply exit and do nothing if the target is in range. This will cause your units to approach the target unnecessarily. +- Now you can change this behavior by the following flag. + +In `rulesmd.ini`: +```ini +[General] +ApproachTarget.StopWhenInRange=false ; boolean +``` + ### Target scanning delay optimization - In vanilla, the game used `NormalTargetingDelay` and `GuardAreaTargetingDelay` to globally control the target searching intervals. Increasing these values would make units stupid, while decreasing them would cause game lag. diff --git a/docs/Whats-New.md b/docs/Whats-New.md index 4afcf3f597..9db8c33506 100644 --- a/docs/Whats-New.md +++ b/docs/Whats-New.md @@ -590,6 +590,7 @@ Vanilla fixes: - Fixed the bug where selected technos would lose their selection if their regular mind control was replaced with permanent mind control or with the control from the Psychic Dominator superweapon (by NetsuNegi) - Fixed an issue that retaliation will make the unit keep switching among multiple targets with the same amount of threat (by TaranDahl) - Fixed the issue where units recruited by a team with `AreTeamMembersRecruitable=false` cannot be recruited even if they have been liberated by that team (by TaranDahl) +- Allow the unit to stop immediately if the target enters the range during ApproachTarget (by TaranDahl) Phobos fixes: - Fixed the bug that `AllowAirstrike=no` cannot completely prevent air strikes from being launched against it (by NetsuNegi) diff --git a/src/Ext/Rules/Body.cpp b/src/Ext/Rules/Body.cpp index ca47eeb3f8..5d67f1bd49 100644 --- a/src/Ext/Rules/Body.cpp +++ b/src/Ext/Rules/Body.cpp @@ -314,7 +314,6 @@ void RulesExt::ExtData::LoadBeforeTypeData(RulesClass* pThis, CCINIClass* pINI) this->AllowBerzerkOnAllies.Read(exINI, GameStrings::CombatDamage, "AllowBerzerkOnAllies"); this->AttackMove_IgnoreWeaponCheck.Read(exINI, GameStrings::General, "AttackMove.IgnoreWeaponCheck"); - this->AttackMove_StopWhenTargetAcquired.Read(exINI, GameStrings::General, "AttackMove.StopWhenTargetAcquired"); this->Parasite_GrappleAnim.Read(exINI, GameStrings::AudioVisual, "Parasite.GrappleAnim"); @@ -363,6 +362,8 @@ void RulesExt::ExtData::LoadBeforeTypeData(RulesClass* pThis, CCINIClass* pINI) this->AIParadropMission.Read(exINI, GameStrings::General, "AIParadropMission"); this->CylinderRangefinding.Read(exINI, GameStrings::General, "CylinderRangefinding"); + + this->ApproachTarget_StopWhenInRange.Read(exINI, GameStrings::General, "ApproachTarget.StopWhenInRange"); // Section AITargetTypes int itemsCount = pINI->GetKeyCount("AITargetTypes"); @@ -640,7 +641,6 @@ void RulesExt::ExtData::Serialize(T& Stm) .Process(this->TintColorForceShield) .Process(this->TintColorBerserk) .Process(this->AttackMove_IgnoreWeaponCheck) - .Process(this->AttackMove_StopWhenTargetAcquired) .Process(this->Parasite_GrappleAnim) .Process(this->InfantryAutoDeploy) .Process(this->AdjacentWallDamage) @@ -663,6 +663,7 @@ void RulesExt::ExtData::Serialize(T& Stm) .Process(this->AIParadropMission) .Process(this->DefaultToGuardArea) .Process(this->CylinderRangefinding) + .Process(this->ApproachTarget_StopWhenInRange) ; } diff --git a/src/Ext/Rules/Body.h b/src/Ext/Rules/Body.h index 4001f0238b..b034ed661e 100644 --- a/src/Ext/Rules/Body.h +++ b/src/Ext/Rules/Body.h @@ -1,4 +1,4 @@ -#pragma once +#pragma once #include #include @@ -272,7 +272,6 @@ class RulesExt Valueable AllowBerzerkOnAllies; Valueable AttackMove_IgnoreWeaponCheck; - Nullable AttackMove_StopWhenTargetAcquired; NullableIdx Parasite_GrappleAnim; @@ -314,6 +313,8 @@ class RulesExt Valueable CylinderRangefinding; + Valueable ApproachTarget_StopWhenInRange; + ExtData(RulesClass* OwnerObject) : Extension(OwnerObject) , Storage_TiberiumIndex { -1 } , HarvesterDumpAmount { 0.0f } @@ -534,7 +535,6 @@ class RulesExt , TintColorBerserk { 0 } , AttackMove_IgnoreWeaponCheck { false } - , AttackMove_StopWhenTargetAcquired { } , Parasite_GrappleAnim {} , InfantryAutoDeploy { false } @@ -570,6 +570,8 @@ class RulesExt , DefaultToGuardArea { false } , CylinderRangefinding { false } + + , ApproachTarget_StopWhenInRange { false } { } virtual ~ExtData() = default; diff --git a/src/Ext/Techno/Hooks.Firing.cpp b/src/Ext/Techno/Hooks.Firing.cpp index 300ea0f465..e979386599 100644 --- a/src/Ext/Techno/Hooks.Firing.cpp +++ b/src/Ext/Techno/Hooks.Firing.cpp @@ -1,4 +1,4 @@ -#include "Body.h" +#include "Body.h" #include #include @@ -1149,3 +1149,29 @@ DEFINE_HOOK(0x6F755A, TechnoClass_IsCloseEnough_CylinderRangefinding, 0x7) R->EAX(pCoord->X); return (cylinder || pThis->WhatAmI() == AbstractType::Aircraft) ? 0x6F75B2 : 0x6F7568; } + +DEFINE_HOOK(0x4D5A34, FootClass_ApproachTarget_StopWhenInRange, 0x6) +{ + GET_STACK(bool, closeEnough, STACK_OFFSET(0x158, -0x146)); + + if (RulesExt::Global()->ApproachTarget_StopWhenInRange && closeEnough) + { + GET(FootClass*, pThis, EBX); + if (auto const pJumpjetLoco = locomotion_cast(pThis->Locomotor)) + { + auto const crd = pThis->GetCoords(); + pJumpjetLoco->DestinationCoords.X = crd.X; + pJumpjetLoco->DestinationCoords.Y = crd.Y; + pJumpjetLoco->CurrentSpeed = 0; + pJumpjetLoco->MaxSpeed = 0; + pJumpjetLoco->State = JumpjetLocomotionClass::State::Hovering; + pThis->AbortMotion(); + } + else + { + pThis->SetDestination(nullptr, true); + } + } + + return 0; +} diff --git a/src/Ext/Techno/Hooks.cpp b/src/Ext/Techno/Hooks.cpp index 49daa58355..99a15bad1c 100644 --- a/src/Ext/Techno/Hooks.cpp +++ b/src/Ext/Techno/Hooks.cpp @@ -1039,55 +1039,6 @@ DEFINE_HOOK(0x519FEC, InfantryClass_UpdatePosition_EngineerRepair, 0xA) #pragma region AttackMove -DEFINE_HOOK(0x4DF410, FootClass_UpdateAttackMove_TargetAcquired, 0x6) -{ - GET(FootClass* const, pThis, ESI); - - auto const pTypeExt = TechnoExt::ExtMap.Find(pThis)->TypeExtData; - - if (pThis->IsCloseEnoughToAttack(pThis->Target) - && pTypeExt->AttackMove_StopWhenTargetAcquired.Get(RulesExt::Global()->AttackMove_StopWhenTargetAcquired.Get(!pTypeExt->OwnerObject()->OpportunityFire))) - { - if (auto const pJumpjetLoco = locomotion_cast(pThis->Locomotor)) - { - auto const crd = pThis->GetCoords(); - pJumpjetLoco->DestinationCoords.X = crd.X; - pJumpjetLoco->DestinationCoords.Y = crd.Y; - pJumpjetLoco->CurrentSpeed = 0; - pJumpjetLoco->MaxSpeed = 0; - pJumpjetLoco->State = JumpjetLocomotionClass::State::Hovering; - pThis->AbortMotion(); - } - else - { - pThis->StopMoving(); - pThis->AbortMotion(); - } - } - - if (pTypeExt->AttackMove_PursuitTarget) - pThis->SetDestination(pThis->Target, true); - - return 0; -} - -DEFINE_HOOK(0x4DF4DB, TechnoClass_RefreshMegaMission_CheckMissionFix, 0xA) -{ - enum { ClearMegaMission = 0x4DF4F9, ContinueMegaMission = 0x4DF4CF }; - - GET(FootClass* const, pThis, ESI); - - auto const pTypeExt = TechnoExt::ExtMap.Find(pThis)->TypeExtData; - auto const mission = pThis->GetCurrentMission(); - const bool stopWhenTargetAcquired = pTypeExt->AttackMove_StopWhenTargetAcquired.Get(RulesExt::Global()->AttackMove_StopWhenTargetAcquired.Get(!pTypeExt->OwnerObject()->OpportunityFire)); - bool clearMegaMission = mission != Mission::Guard; - - if (stopWhenTargetAcquired && clearMegaMission) - clearMegaMission = !(mission == Mission::Move && pThis->MegaDestination && pThis->DistanceFrom(pThis->MegaDestination) > 256); - - return clearMegaMission ? ClearMegaMission : ContinueMegaMission; -} - DEFINE_HOOK(0x711E90, TechnoTypeClass_CanAttackMove_IgnoreWeapon, 0x6) { enum { SkipGameCode = 0x711E9A }; diff --git a/src/Ext/TechnoType/Body.cpp b/src/Ext/TechnoType/Body.cpp index 39560cc224..c2d57515ca 100644 --- a/src/Ext/TechnoType/Body.cpp +++ b/src/Ext/TechnoType/Body.cpp @@ -1124,8 +1124,6 @@ void TechnoTypeExt::ExtData::LoadFromINIFile(CCINIClass* const pINI) this->AttackMove_Follow.Read(exINI, pSection, "AttackMove.Follow"); this->AttackMove_Follow_IncludeAir.Read(exINI, pSection, "AttackMove.Follow.IncludeAir"); this->AttackMove_Follow_IfMindControlIsFull.Read(exINI, pSection, "AttackMove.Follow.IfMindControlIsFull"); - this->AttackMove_StopWhenTargetAcquired.Read(exINI, pSection, "AttackMove.StopWhenTargetAcquired"); - this->AttackMove_PursuitTarget.Read(exINI, pSection, "AttackMove.PursuitTarget"); this->Ammo_AutoConvertMinimumAmount.Read(exINI, pSection, "Ammo.AutoConvertMinimumAmount"); this->Ammo_AutoConvertMaximumAmount.Read(exINI, pSection, "Ammo.AutoConvertMaximumAmount"); @@ -1814,8 +1812,6 @@ void TechnoTypeExt::ExtData::Serialize(T& Stm) .Process(this->AttackMove_Follow) .Process(this->AttackMove_Follow_IncludeAir) .Process(this->AttackMove_Follow_IfMindControlIsFull) - .Process(this->AttackMove_StopWhenTargetAcquired) - .Process(this->AttackMove_PursuitTarget) .Process(this->MultiWeapon) .Process(this->MultiWeapon_IsSecondary) diff --git a/src/Ext/TechnoType/Body.h b/src/Ext/TechnoType/Body.h index 7d161c89ca..ba48d2ba5e 100644 --- a/src/Ext/TechnoType/Body.h +++ b/src/Ext/TechnoType/Body.h @@ -437,8 +437,6 @@ class TechnoTypeExt Valueable AttackMove_Follow; Valueable AttackMove_Follow_IncludeAir; Valueable AttackMove_Follow_IfMindControlIsFull; - Nullable AttackMove_StopWhenTargetAcquired; - Valueable AttackMove_PursuitTarget; Valueable MultiWeapon; ValueableVector MultiWeapon_IsSecondary; @@ -866,8 +864,6 @@ class TechnoTypeExt , AttackMove_Follow { false } , AttackMove_Follow_IncludeAir { false } , AttackMove_Follow_IfMindControlIsFull { false } - , AttackMove_StopWhenTargetAcquired { } - , AttackMove_PursuitTarget { false } , MultiWeapon { false } , MultiWeapon_IsSecondary {} diff --git a/src/Utilities/TemplateDef.h b/src/Utilities/TemplateDef.h index fa93406465..78ebac68d7 100644 --- a/src/Utilities/TemplateDef.h +++ b/src/Utilities/TemplateDef.h @@ -57,6 +57,7 @@ #include #include #include +#include #include namespace detail