diff --git a/CREDITS.md b/CREDITS.md index 953abc3a28..65cc9f9412 100644 --- a/CREDITS.md +++ b/CREDITS.md @@ -403,6 +403,7 @@ This page lists all the individual contributions to the project by their author. - Reactivate unused trigger events 2, 53, and 54 - Map Action 511, 609, 610 - Weapons now support `AttackFriendlies` and `AttackCursorOnFriendlies` + - Attack non-threatening structures extensions - **NetsuNegi**: - Forbidding parallel AI queues by type - Jumpjet crash speed fix when crashing onto building diff --git a/docs/New-or-Enhanced-Logics.md b/docs/New-or-Enhanced-Logics.md index 57b4a0db63..03d52b9ff9 100644 --- a/docs/New-or-Enhanced-Logics.md +++ b/docs/New-or-Enhanced-Logics.md @@ -1322,6 +1322,18 @@ In `rulesmd.ini`: AttackMove.IgnoreWeaponCheck=false ; boolean ``` +### Attack non-threatening structures + +- You can now freely configure whether units can automatically target non-threatening structures. + - `AutoTarget.NoThreatBuildings` affects player-controlled units, `AutoTargetAI.NoThreatBuildings` affects other units. + +In `rulesmd.ini`: +```ini +[General] +AutoTarget.NoThreatBuildings=false ; boolean +AutoTargetAI.NoThreatBuildings=true ; boolean +``` + ### Aircraft spawner customizations ![image](_static/images/spawnrange-01.gif) @@ -2727,15 +2739,14 @@ In `rulesmd.ini`: AreaFire.Target=base ; AreaFire Target Enumeration (base|self|random) ``` -### Can attack allies +### Attack non-threatening structures -- Weapons now support `AttackFriendlies` and `AttackCursorOnFriendlies`, They override the firer's `AttackFriendlies` and `AttackCursorOnFriendlies`. +- `AttackNoThreatBuildings` permits shooters to attack non-threatening structures. This setting overrides other configurations. In `rulesmd.ini`: ```ini [SOMEWEAPON] ; WeaponType -AttackFriendlies= ; boolean -AttackCursorOnFriendlies= ; boolean +AttackNoThreatBuildings= ; boolean ``` ### Burst delay customizations @@ -2770,6 +2781,17 @@ Burst.NoDelay=false ; boolean - This will ignore `Burst.Delays` setting. ``` +### Can attack allies + +- Weapons now support `AttackFriendlies` and `AttackCursorOnFriendlies`, They override the firer's `AttackFriendlies` and `AttackCursorOnFriendlies`. + +In `rulesmd.ini`: +```ini +[SOMEWEAPON] ; WeaponType +AttackFriendlies= ; boolean +AttackCursorOnFriendlies= ; boolean +``` + ### Delayed firing - It is possible to have any weapon fire with a delay by setting `DelayedFire.Duration` on a WeaponType - it supports a single integer or two comma-separated ones for a random range to pick value from. diff --git a/docs/Whats-New.md b/docs/Whats-New.md index cdace56832..5785b1622b 100644 --- a/docs/Whats-New.md +++ b/docs/Whats-New.md @@ -481,6 +481,7 @@ New: - Map Action [`511` Undeploy Building to Waypoint](AI-Scripting-and-Mapping.md#undeploy-building-to-waypoint), [`609` Set Radar Mode](AI-Scripting-and-Mapping.md#set-radar-mode), [`610` Set house's `TeamDelays` value](AI-Scripting-and-Mapping.md#set-house-s-teamdelays-value) (by FlyStar) - [Toggle to exclude technos from base center calculations](New-or-Enhanced-Logics.md#exclusion-from-base-center-calculations) (by Starkku) - Weapons now support `AttackFriendlies` and `AttackCursorOnFriendlies` (by FlyStar) +- Attack non-threatening structures extensions (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/Rules/Body.cpp b/src/Ext/Rules/Body.cpp index 31dc3b749d..b373daa3fb 100644 --- a/src/Ext/Rules/Body.cpp +++ b/src/Ext/Rules/Body.cpp @@ -343,6 +343,9 @@ void RulesExt::ExtData::LoadBeforeTypeData(RulesClass* pThis, CCINIClass* pINI) this->ExtraRange_Prefiring.Read(exINI, GameStrings::General, "ExtraRange.Prefiring"); this->ExtraRange_Prefiring_IncludeBurst.Read(exINI, GameStrings::General, "ExtraRange.Prefiring.IncludeBurst"); + this->AutoTarget_NoThreatBuildings.Read(exINI, GameStrings::General, "AutoTarget.NoThreatBuildings"); + this->AutoTargetAI_NoThreatBuildings.Read(exINI, GameStrings::General, "AutoTargetAI.NoThreatBuildings"); + // Section AITargetTypes int itemsCount = pINI->GetKeyCount("AITargetTypes"); for (int i = 0; i < itemsCount; ++i) @@ -627,6 +630,8 @@ void RulesExt::ExtData::Serialize(T& Stm) .Process(this->ExtraRange_FirerMoving) .Process(this->ExtraRange_Prefiring) .Process(this->ExtraRange_Prefiring_IncludeBurst) + .Process(this->AutoTarget_NoThreatBuildings) + .Process(this->AutoTargetAI_NoThreatBuildings) ; } diff --git a/src/Ext/Rules/Body.h b/src/Ext/Rules/Body.h index 26c11f7f7f..008da33838 100644 --- a/src/Ext/Rules/Body.h +++ b/src/Ext/Rules/Body.h @@ -293,6 +293,9 @@ class RulesExt Valueable ApplyPerTargetEffectsOnDetonate; + Valueable AutoTarget_NoThreatBuildings; + Valueable AutoTargetAI_NoThreatBuildings; + ExtData(RulesClass* OwnerObject) : Extension(OwnerObject) , Storage_TiberiumIndex { -1 } , HarvesterDumpAmount { 0.0f } @@ -530,6 +533,9 @@ class RulesExt , ExtraRange_FirerMoving { Leptons(0) } , ExtraRange_Prefiring { Leptons(0) } , ExtraRange_Prefiring_IncludeBurst { true } + + , AutoTarget_NoThreatBuildings { false } + , AutoTargetAI_NoThreatBuildings { true } { } virtual ~ExtData() = default; diff --git a/src/Ext/Techno/Hooks.TargetEvaluation.cpp b/src/Ext/Techno/Hooks.TargetEvaluation.cpp index d8c9d1f3e7..c6cbafa419 100644 --- a/src/Ext/Techno/Hooks.TargetEvaluation.cpp +++ b/src/Ext/Techno/Hooks.TargetEvaluation.cpp @@ -203,8 +203,10 @@ DEFINE_HOOK(0x6F85AB, TechnoClass_CanAutoTargetObject_AggressiveAttackMove, 0x6) GET(TechnoClass* const, pThis, EDI); - if (!pThis->Owner->IsControlledByHuman()) - return CanTarget; + // Now, it is possible to customize which types of national active attacks on non-threatening buildings, so this part has been commented out. + // The new judgment code is in TechnoClass_CanAutoTarget_AttackNoThreatBuildings of Hook.cpp. + // if (!pThis->Owner->IsControlledByHuman()) + // return CanTarget; if (!pThis->MegaMissionIsAttackMove()) return ContinueCheck; diff --git a/src/Ext/Techno/Hooks.cpp b/src/Ext/Techno/Hooks.cpp index 3a45f56a53..480c922963 100644 --- a/src/Ext/Techno/Hooks.cpp +++ b/src/Ext/Techno/Hooks.cpp @@ -1542,13 +1542,16 @@ DEFINE_HOOK(0x6F8A92, TechnoClass_CheckAutoTarget_AttackFriendlies, 0xA) namespace CanAutoTargetTemp { - WeaponTypeExt::ExtData* WeaponExt; + TechnoTypeExt::ExtData* TypeExtData = nullptr; + WeaponTypeExt::ExtData* WeaponExt = nullptr; } DEFINE_HOOK(0x6F7E30, TechnoClass_CanAutoTarget_SetContent, 0x6) { + GET(TechnoClass*, pThis, EDI); GET(WeaponTypeClass*, pWeapon, EBP); + CanAutoTargetTemp::TypeExtData = TechnoExt::ExtMap.Find(pThis)->TypeExtData; CanAutoTargetTemp::WeaponExt = WeaponTypeExt::ExtMap.TryFind(pWeapon); return 0; @@ -1569,4 +1572,23 @@ DEFINE_HOOK(0x6F7EF4, TechnoClass_CanAutoTarget_AttackFriendlies, 0xA) return SkipGameCode; } +DEFINE_HOOK(0x6F85CF, TechnoClass_CanAutoTarget_AttackNoThreatBuildings, 0xA) +{ + enum { CanAttack = 0x6F8604, Continue = 0x6F85D9 }; + + GET(TechnoClass*, pThis, EDI); + GET(BuildingClass*, pTarget, ESI); + + bool canAttack = pThis->Owner->IsControlledByHuman() ? RulesExt::Global()->AutoTarget_NoThreatBuildings : RulesExt::Global()->AutoTargetAI_NoThreatBuildings; + + if (const auto pWeaponExt = CanAutoTargetTemp::WeaponExt) + canAttack = pWeaponExt->AttackNoThreatBuildings.Get(canAttack); + + if (canAttack) + return CanAttack; + + R->EAX(pTarget->GetTurretWeapon()); + return Continue; +} + #pragma endregion diff --git a/src/Ext/WeaponType/Body.cpp b/src/Ext/WeaponType/Body.cpp index dd2ecdd2bb..5e06ff4722 100644 --- a/src/Ext/WeaponType/Body.cpp +++ b/src/Ext/WeaponType/Body.cpp @@ -158,6 +158,7 @@ void WeaponTypeExt::ExtData::LoadFromINIFile(CCINIClass* const pINI) this->ExtraRange_Prefiring_IncludeBurst.Read(exINI, GameStrings::General, "ExtraRange.Prefiring.IncludeBurst"); this->AttackFriendlies.Read(exINI, pSection, "AttackFriendlies"); this->AttackCursorOnFriendlies.Read(exINI, pSection, "AttackCursorOnFriendlies"); + this->AttackNoThreatBuildings.Read(exINI, pSection, "AttackNoThreatBuildings"); // handle SkipWeaponPicking if (this->CanTarget != AffectedTarget::All || this->CanTargetHouses != AffectedHouse::All @@ -248,6 +249,7 @@ void WeaponTypeExt::ExtData::Serialize(T& Stm) .Process(this->ExtraRange_Prefiring_IncludeBurst) .Process(this->AttackFriendlies) .Process(this->AttackCursorOnFriendlies) + .Process(this->AttackNoThreatBuildings) ; }; diff --git a/src/Ext/WeaponType/Body.h b/src/Ext/WeaponType/Body.h index f59c0f71fb..f784b74d22 100644 --- a/src/Ext/WeaponType/Body.h +++ b/src/Ext/WeaponType/Body.h @@ -91,6 +91,7 @@ class WeaponTypeExt Nullable ExtraRange_Prefiring_IncludeBurst; Nullable AttackFriendlies; Nullable AttackCursorOnFriendlies; + Nullable AttackNoThreatBuildings; bool SkipWeaponPicking; @@ -170,6 +171,7 @@ class WeaponTypeExt , ExtraRange_Prefiring_IncludeBurst {} , AttackFriendlies {} , AttackCursorOnFriendlies {} + , AttackNoThreatBuildings {} { } int GetBurstDelay(int burstIndex) const;