From ff311379024f62c0d49e42b6b0d520c5d38055c4 Mon Sep 17 00:00:00 2001 From: NetsuNegi39 Date: Fri, 21 Nov 2025 15:31:28 +0800 Subject: [PATCH 01/10] init --- CREDITS.md | 1 + docs/New-or-Enhanced-Logics.md | 11 +++++++++++ docs/Whats-New.md | 1 + src/Ext/SWType/Body.cpp | 4 ++++ src/Ext/SWType/Body.h | 4 ++++ src/Ext/SWType/SWHelpers.cpp | 8 ++++---- src/Misc/Hooks.Ares.cpp | 22 +++++++++++++++++++++- 7 files changed, 46 insertions(+), 5 deletions(-) diff --git a/CREDITS.md b/CREDITS.md index 97fc0789a2..d909f2c361 100644 --- a/CREDITS.md +++ b/CREDITS.md @@ -459,6 +459,7 @@ This page lists all the individual contributions to the project by their author. - Fix the bug that vehicle fall on infantry will make all cell content has been removed - Allow deploy controlled MCV - Fix the bug that naval ship will sink even they destroyed in air + - Customize Inhibitors and Designators - **Apollo** - Translucent SHP drawing patches - **ststl**: - Customizable `ShowTimer` priority of superweapons diff --git a/docs/New-or-Enhanced-Logics.md b/docs/New-or-Enhanced-Logics.md index d04603a742..a695de3316 100644 --- a/docs/New-or-Enhanced-Logics.md +++ b/docs/New-or-Enhanced-Logics.md @@ -1115,6 +1115,17 @@ In `rulesmd.ini`: TabIndex=1 ; integer ``` +### Customize Inhibitors and Designators + +- Theres only enemies inhibitors and selfowned designators are eligible. Now you can customize it. + +In `rulesmd.ini` +```ini +[SOMESW] ; SuperWeaponType +SW.Inhibitors.Houses=enemies ; List of Affected House Enumeration (none|owner/self|allies/ally|team|enemies/enemy|all) +SW.Designators.Houses=owner ; List of Affected House Enumeration (none|owner/self|allies/ally|team|enemies/enemy|all) +``` + ### EMPulse settings - It is possible to customize which weapon a building with `EMPulseCannon=true` fires when an associated `Type=EMPulse` superweapon (**only** if `EMPulse.TargetSelf=false` or omitted) is fired by setting `EMPulse.WeaponIndex`. diff --git a/docs/Whats-New.md b/docs/Whats-New.md index a85f56233d..9c6b8f98f1 100644 --- a/docs/Whats-New.md +++ b/docs/Whats-New.md @@ -526,6 +526,7 @@ Fixes / interactions with other extensions: - Taking over Ares' AlphaImage respawn logic to reduce lags from it (by NetsuNegi) - Fixed an issue that Ares' Type Conversion not resetting barrel's direction by `FireAngle` (by TaranDahl) - Fixed the issue where Ares' `Flash.Duration` cannot override the weapon's repair flash effect (by Sovietianqi, based on knowledge of DeathFish) +- Customize Inhibitors and Designators (by NetsuNegi) ``` ### 0.4 diff --git a/src/Ext/SWType/Body.cpp b/src/Ext/SWType/Body.cpp index f230746dc7..46f72e0595 100644 --- a/src/Ext/SWType/Body.cpp +++ b/src/Ext/SWType/Body.cpp @@ -33,8 +33,10 @@ void SWTypeExt::ExtData::Serialize(T& Stm) .Process(this->SW_Unstoppable) .Process(this->SW_Inhibitors) .Process(this->SW_AnyInhibitor) + .Process(this->SW_Inhibitors_Houses) .Process(this->SW_Designators) .Process(this->SW_AnyDesignator) + .Process(this->SW_Designators_Houses) .Process(this->SW_RangeMinimum) .Process(this->SW_RangeMaximum) .Process(this->SW_RequiredHouses) @@ -118,8 +120,10 @@ void SWTypeExt::ExtData::LoadFromINIFile(CCINIClass* const pINI) this->SW_Unstoppable.Read(exINI, pSection, "SW.Unstoppable"); this->SW_Inhibitors.Read(exINI, pSection, "SW.Inhibitors"); this->SW_AnyInhibitor.Read(exINI, pSection, "SW.AnyInhibitor"); + this->SW_Inhibitors_Houses.Read(exINI, pSection, "SW.Inhibitors.Houses"); this->SW_Designators.Read(exINI, pSection, "SW.Designators"); this->SW_AnyDesignator.Read(exINI, pSection, "SW.AnyDesignator"); + this->SW_Designators_Houses.Read(exINI, pSection, "SW.Designators.Houses"); this->SW_RangeMinimum.Read(exINI, pSection, "SW.RangeMinimum"); this->SW_RangeMaximum.Read(exINI, pSection, "SW.RangeMaximum"); this->SW_RequiredHouses = pINI->ReadHouseTypesList(pSection, "SW.RequiredHouses", this->SW_RequiredHouses); diff --git a/src/Ext/SWType/Body.h b/src/Ext/SWType/Body.h index e4af1c3879..3b1f3eeb2b 100644 --- a/src/Ext/SWType/Body.h +++ b/src/Ext/SWType/Body.h @@ -36,8 +36,10 @@ class SWTypeExt Valueable SW_Unstoppable; ValueableVector SW_Inhibitors; Valueable SW_AnyInhibitor; + Valueable SW_Inhibitors_Houses; ValueableVector SW_Designators; Valueable SW_AnyDesignator; + Valueable SW_Designators_Houses; Valueable SW_RangeMinimum; Valueable SW_RangeMaximum; Valueable SW_Shots; @@ -125,8 +127,10 @@ class SWTypeExt , SW_Unstoppable { false } , SW_Inhibitors {} , SW_AnyInhibitor { false } + , SW_Inhibitors_Houses { AffectedHouse::Enemies } , SW_Designators { } , SW_AnyDesignator { false } + , SW_Designators_Houses { AffectedHouse::Owner } , SW_RangeMinimum { -1.0 } , SW_RangeMaximum { -1.0 } , SW_RequiredHouses { 0xFFFFFFFFu } diff --git a/src/Ext/SWType/SWHelpers.cpp b/src/Ext/SWType/SWHelpers.cpp index 20e5b6b9a9..2fc8933b6b 100644 --- a/src/Ext/SWType/SWHelpers.cpp +++ b/src/Ext/SWType/SWHelpers.cpp @@ -46,11 +46,11 @@ bool SWTypeExt::ExtData::IsInhibitor(HouseClass* pOwner, TechnoClass* pTechno) c { if (pTechno->IsAlive && pTechno->Health && !pTechno->InLimbo && !pTechno->Deactivated) { - if (!pOwner->IsAlliedWith(pTechno)) + if (EnumFunctions::CanTargetHouse(this->SW_Inhibitors_Houses, pOwner, pTechno->Owner)) { - if (const auto pBld = abstract_cast(pTechno)) + if (const auto pBuilding = abstract_cast(pTechno)) { - if (!pBld->IsPowerOnline()) + if (!pBuilding->IsPowerOnline()) return false; } @@ -93,7 +93,7 @@ bool SWTypeExt::ExtData::HasInhibitor(HouseClass* pOwner, const CellStruct& coor // Designators check bool SWTypeExt::ExtData::IsDesignator(HouseClass* pOwner, TechnoClass* pTechno) const { - if (pTechno->Owner == pOwner && pTechno->IsAlive && pTechno->Health && !pTechno->InLimbo && !pTechno->Deactivated) + if (EnumFunctions::CanTargetHouse(this->SW_Designators_Houses, pOwner, pTechno->Owner) && pTechno->IsAlive && pTechno->Health && !pTechno->InLimbo && !pTechno->Deactivated) return this->SW_AnyDesignator || this->SW_Designators.Contains(pTechno->GetTechnoType()); return false; diff --git a/src/Misc/Hooks.Ares.cpp b/src/Misc/Hooks.Ares.cpp index b1883788c6..5170a1068a 100644 --- a/src/Misc/Hooks.Ares.cpp +++ b/src/Misc/Hooks.Ares.cpp @@ -8,6 +8,7 @@ #include #include #include +#include #include // Remember that we still don't fix Ares "issues" a priori. Extensions as well. @@ -40,7 +41,6 @@ bool __stdcall ConvertToType(TechnoClass* pThis, TechnoTypeClass* pToType) TechnoTypeClass* __fastcall ShowPromoteAnim(TechnoClass* pThis) { TechnoExt::ShowPromoteAnim(pThis); - return pThis->GetTechnoType(); } @@ -49,6 +49,18 @@ WeaponStruct* __fastcall GetLaserWeapon(BuildingClass* pThis) return BuildingExt::GetLaserWeapon(pThis); } +bool __fastcall NewSWType_IsInhibitor(void*, void*, SuperWeaponTypeClass** pExt_Ares, HouseClass* pOwner, TechnoClass* pTechno) +{ + const auto pSWExt = SWTypeExt::ExtMap.Find(*pExt_Ares); + return pSWExt->IsInhibitor(pOwner, pTechno); +} + +bool __fastcall NewSWType_IsDesignator(void*, void*, SuperWeaponTypeClass** pExt_Ares, HouseClass* pOwner, TechnoClass* pTechno) +{ + const auto pSWExt = SWTypeExt::ExtMap.Find(*pExt_Ares); + return pSWExt->IsDesignator(pOwner, pTechno); +} + EBolt* __stdcall CreateEBolt(WeaponTypeClass** pWeaponData) { return EBoltExt::CreateEBolt(*pWeaponData); @@ -108,6 +120,10 @@ void Apply_Ares3_0_Patches() // Apply laser weapon selection fix on Ares' laser fire replacement. Patch::Apply_CALL6(AresHelper::AresBaseAddress + 0x56415, &GetLaserWeapon); + + // Redirect Ares' IsInhibitor() and IsDesignator() to our implementation: + Patch::Apply_LJMP(AresHelper::AresBaseAddress + 0x6D900, &NewSWType_IsInhibitor); + Patch::Apply_LJMP(AresHelper::AresBaseAddress + 0x6D880, &NewSWType_IsDesignator); } void Apply_Ares3_0p1_Patches() @@ -161,4 +177,8 @@ void Apply_Ares3_0p1_Patches() // Apply laser weapon selection fix on Ares' laser fire replacement. Patch::Apply_CALL6(AresHelper::AresBaseAddress + 0x570C5, &GetLaserWeapon); + + // Redirect Ares' IsInhibitor() and IsDesignator() to our implementation: + Patch::Apply_LJMP(AresHelper::AresBaseAddress + 0x6E910, &NewSWType_IsInhibitor); + Patch::Apply_LJMP(AresHelper::AresBaseAddress + 0x6E890, &NewSWType_IsDesignator); } From b8a6319b986e069310d2163a5587ab6582517efe Mon Sep 17 00:00:00 2001 From: NetsuNegi39 Date: Fri, 21 Nov 2025 15:47:05 +0800 Subject: [PATCH 02/10] update SWHelpers.cpp --- src/Ext/SWType/SWHelpers.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/Ext/SWType/SWHelpers.cpp b/src/Ext/SWType/SWHelpers.cpp index 2fc8933b6b..0014da638c 100644 --- a/src/Ext/SWType/SWHelpers.cpp +++ b/src/Ext/SWType/SWHelpers.cpp @@ -93,8 +93,11 @@ bool SWTypeExt::ExtData::HasInhibitor(HouseClass* pOwner, const CellStruct& coor // Designators check bool SWTypeExt::ExtData::IsDesignator(HouseClass* pOwner, TechnoClass* pTechno) const { - if (EnumFunctions::CanTargetHouse(this->SW_Designators_Houses, pOwner, pTechno->Owner) && pTechno->IsAlive && pTechno->Health && !pTechno->InLimbo && !pTechno->Deactivated) - return this->SW_AnyDesignator || this->SW_Designators.Contains(pTechno->GetTechnoType()); + if (EnumFunctions::CanTargetHouse(this->SW_Designators_Houses, pOwner, pTechno->Owner)) + { + if (pTechno->IsAlive && pTechno->Health && !pTechno->InLimbo && !pTechno->Deactivated) + return this->SW_AnyDesignator || this->SW_Designators.Contains(pTechno->GetTechnoType()); + } return false; } From 6db54906ef791491157e8293c57e5f4112da943f Mon Sep 17 00:00:00 2001 From: NetsuNegi39 Date: Fri, 21 Nov 2025 15:58:58 +0800 Subject: [PATCH 03/10] Update Hooks.cpp --- src/Ext/SWType/Hooks.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/Ext/SWType/Hooks.cpp b/src/Ext/SWType/Hooks.cpp index 023073853e..f9c6c3a49d 100644 --- a/src/Ext/SWType/Hooks.cpp +++ b/src/Ext/SWType/Hooks.cpp @@ -73,9 +73,8 @@ DEFINE_HOOK(0x6DBE74, Tactical_SuperLinesCircles_ShowDesignatorRange, 0x7) if (!pCurrentTechno->IsAlive || pCurrentTechno->InLimbo - || (pOwner != HouseClass::CurrentPlayer && pOwner->IsAlliedWith(HouseClass::CurrentPlayer)) // Ally objects are never designators or inhibitors - || (pOwner == HouseClass::CurrentPlayer && !pExt->SW_Designators.Contains(pCurrentTechnoType)) // Only owned objects can be designators - || (!pOwner->IsAlliedWith(HouseClass::CurrentPlayer) && !pExt->SW_Inhibitors.Contains(pCurrentTechnoType))) // Only enemy objects can be inhibitors + || (EnumFunctions::CanTargetHouse(pExt->SW_Designators_Houses, HouseClass::CurrentPlayer, pOwner) && !pExt->SW_Designators.Contains(pCurrentTechnoType)) + || (EnumFunctions::CanTargetHouse(pExt->SW_Inhibitors_Houses, HouseClass::CurrentPlayer, pOwner) && !pExt->SW_Inhibitors.Contains(pCurrentTechnoType))) { continue; } From db63a28c39e924c9ffd237a271f1748c45e808f1 Mon Sep 17 00:00:00 2001 From: Noble Fish <89088785+DeathFishAtEase@users.noreply.github.com> Date: Sat, 22 Nov 2025 18:24:37 +0800 Subject: [PATCH 04/10] Move Whats-New message. Avoid forgetting afterwards. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes / interactions with other extensions: ↓ New: --- docs/Whats-New.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/Whats-New.md b/docs/Whats-New.md index c6f8ef214c..eef0aeb590 100644 --- a/docs/Whats-New.md +++ b/docs/Whats-New.md @@ -460,6 +460,7 @@ New: - [Dehardcode the `ZAdjust` of warhead anim](Fixed-or-Improved-Logics.md#dehardcode-the-zadjust-of-warhead-anim) (by TaranDahl) - [Interceptor target scan delay customization](New-or-Enhanced-Logics.md#projectile-interception-logic) (by Starkku) - Allow deploy controlled MCV (by NetsuNegi) +- Customize Inhibitors and Designators (by NetsuNegi) Vanilla fixes: - Fixed sidebar not updating queued unit numbers when adding or removing units when the production is on hold (by CrimRecya) @@ -527,7 +528,6 @@ Fixes / interactions with other extensions: - Fixed an issue that Ares' Type Conversion not resetting barrel's direction by `FireAngle` (by TaranDahl) - Fixed the issue where Ares' `Flash.Duration` cannot override the weapon's repair flash effect (by Sovietianqi, based on knowledge of DeathFish) - Fixed the bug that building with `CloningFacility=true` and `WeaponsFactory=true` may cloning multiple vehicles and then they get stuck (by NetsuNegi) -- Customize Inhibitors and Designators (by NetsuNegi) ``` ### 0.4 From 6b8240c305ab8679052c5949d7e6e6a23d70d79d Mon Sep 17 00:00:00 2001 From: NetsuNegi39 Date: Sun, 23 Nov 2025 19:04:20 +0800 Subject: [PATCH 05/10] sw signal type --- Phobos.vcxproj | 4 + src/Ext/SWType/Ares/NewSWType.cpp | 130 ++++++++++++++++++++++++++++ src/Ext/SWType/Ares/NewSWType.h | 53 ++++++++++++ src/Ext/SWType/Body.cpp | 5 ++ src/Ext/SWType/Body.h | 10 ++- src/Ext/SWType/Hooks.cpp | 82 ++++++++++++++---- src/Ext/SWType/SWHelpers.cpp | 131 +++++++++++++++++++---------- src/Ext/Script/Mission.Attack.cpp | 11 ++- src/Ext/TechnoType/Body.cpp | 6 ++ src/Ext/TechnoType/Body.h | 7 ++ src/Misc/Hooks.Ares.cpp | 23 ++--- src/New/Type/SWSignalTypeClass.cpp | 42 +++++++++ src/New/Type/SWSignalTypeClass.h | 22 +++++ src/Phobos.Ext.cpp | 4 +- 14 files changed, 443 insertions(+), 87 deletions(-) create mode 100644 src/Ext/SWType/Ares/NewSWType.cpp create mode 100644 src/Ext/SWType/Ares/NewSWType.h create mode 100644 src/New/Type/SWSignalTypeClass.cpp create mode 100644 src/New/Type/SWSignalTypeClass.h diff --git a/Phobos.vcxproj b/Phobos.vcxproj index b9b624c99d..ae77b100f6 100644 --- a/Phobos.vcxproj +++ b/Phobos.vcxproj @@ -21,6 +21,7 @@ + @@ -180,6 +181,7 @@ + @@ -217,6 +219,7 @@ + @@ -275,6 +278,7 @@ + diff --git a/src/Ext/SWType/Ares/NewSWType.cpp b/src/Ext/SWType/Ares/NewSWType.cpp new file mode 100644 index 0000000000..b4b390ff21 --- /dev/null +++ b/src/Ext/SWType/Ares/NewSWType.cpp @@ -0,0 +1,130 @@ +#include "NewSWType.h" + +TargetingData& AresNewSWType::GetTargetingData(TargetingData& data, SuperWeaponTypeClass** pExt_Ares, HouseClass* pOwner) const +{ + data.TypeExt_Ares = pExt_Ares; + data.Owner = pOwner; + data.NeedsLaunchSite = false; + data.NeedsDesignator = false; + std::memset(&data.LaunchSites, 0, sizeof(data.LaunchSites)); + std::memset(&data.Designators, 0, sizeof(data.Designators)); + std::memset(&data.Inhibitors, 0, sizeof(data.Inhibitors)); + + // get launchsite data + const auto& [minRange, maxRange] = this->GetLaunchSiteRange(pExt_Ares); + + if (minRange >= 0.0 || maxRange >= 0.0) + { + data.NeedsLaunchSite = true; + + for (const auto pBuilding : pOwner->Buildings) + { + if (this->IsLaunchSite(pExt_Ares, pBuilding)) + { + const auto& [minSiteRange, maxSiteRange] = this->GetLaunchSiteRange(pExt_Ares, pBuilding); + const auto center = pBuilding->GetCoords(); + data.LaunchSites.emplace_back(pBuilding, CellClass::Coord2Cell(center), minSiteRange, maxSiteRange); + } + } + } + + const auto pExt = SWTypeExt::ExtMap.Find(*pExt_Ares); + const bool hasDesignateType = !pExt->SW_DesignateTypes.empty(); + const bool hasDesignator = !pExt->SW_Designators.empty() || pExt->SW_AnyDesignator; + + // get designator data + if (hasDesignateType || hasDesignator) + { + data.NeedsDesignator = true; + + for (const auto pTechno : TechnoClass::Array) + { + if (!pTechno->IsAlive || !pTechno->Health || pTechno->InLimbo || pTechno->Deactivated) + continue; + + // get the designator's center + const auto center = pTechno->GetCoords(); + const auto cell = CellClass::Coord2Cell(center); + + const auto pTechnoType = pTechno->GetTechnoType(); + const auto pTechnoTypeExt = TechnoTypeExt::ExtMap.Find(pTechnoType); + + if (hasDesignateType) + { + for (const auto signal : pExt->SW_DesignateTypes) + { + if (std::ranges::find(pTechnoTypeExt->DesignateTypes, signal) == pTechnoTypeExt->DesignateTypes.cend() + || !EnumFunctions::CanTargetHouse(signal->Affects.Get(AffectedHouse::Owner), pOwner, pTechno->Owner)) + continue; + + const int range = signal->Range.Get(pTechnoType->Sight); + + if (range > 0) + data.Designators.emplace_back(range * range, cell); + } + } + + if (hasDesignator + && EnumFunctions::CanTargetHouse(pExt->SW_Designators_Houses, pOwner, pTechno->Owner) + && (pExt->SW_AnyDesignator || pExt->SW_Designators.Contains(pTechnoType))) + { + const int range = pTechnoTypeExt->DesignatorRange.Get(pTechnoType->Sight); + + if (range > 0) + data.Designators.emplace_back(range * range, cell); + } + } + } + + const bool hasInhibiteType = !pExt->SW_InhibiteTypes.empty(); + const bool hasInhibitor = !pExt->SW_Inhibitors.empty() || pExt->SW_AnyInhibitor; + + // get inhibitor data + if (hasInhibiteType || hasInhibitor) + { + for (const auto pTechno : TechnoClass::Array) + { + if (!pTechno->IsAlive || !pTechno->Health || pTechno->InLimbo || pTechno->Deactivated) + continue; + + const auto pBuilding = abstract_cast(pTechno); + + if (pBuilding && !pBuilding->IsPowerOnline()) + continue; + + // get the inhibitor's center + const auto center = pTechno->GetCoords(); + const auto cell = CellClass::Coord2Cell(center); + + const auto pTechnoType = pTechno->GetTechnoType(); + const auto pTechnoTypeExt = TechnoTypeExt::ExtMap.Find(pTechnoType); + + if (hasInhibiteType) + { + for (const auto signal : pExt->SW_InhibiteTypes) + { + if (std::ranges::find(pTechnoTypeExt->InhibiteTypes, signal) == pTechnoTypeExt->InhibiteTypes.cend() + || !EnumFunctions::CanTargetHouse(signal->Affects.Get(AffectedHouse::Enemies), pOwner, pTechno->Owner)) + continue; + + const int range = signal->Range.Get(pTechnoType->Sight); + + if (range > 0) + data.Inhibitors.emplace_back(range * range, cell); + } + } + + if (hasInhibitor + && EnumFunctions::CanTargetHouse(pExt->SW_Inhibitors_Houses, pOwner, pTechno->Owner) + && (pExt->SW_AnyInhibitor || pExt->SW_Inhibitors.Contains(pTechnoType))) + { + const int range = pTechnoTypeExt->InhibitorRange.Get(pTechnoType->Sight); + + if (range > 0) + data.Inhibitors.emplace_back(range * range, cell); + } + } + } + + return data; +} diff --git a/src/Ext/SWType/Ares/NewSWType.h b/src/Ext/SWType/Ares/NewSWType.h new file mode 100644 index 0000000000..2336ffd51a --- /dev/null +++ b/src/Ext/SWType/Ares/NewSWType.h @@ -0,0 +1,53 @@ +#pragma once +#include "../Body.h" + +struct TargetingData +{ + struct LaunchSite + { + BuildingClass* Building; + CellStruct Center; + double MinRange; + double MaxRange; + }; + + struct RangedItem + { + int RangeSqr; + CellStruct Center; + }; + + SuperWeaponTypeClass** TypeExt_Ares; + HouseClass* Owner; + bool NeedsLaunchSite; + bool NeedsDesignator; + std::vector LaunchSites; + std::vector Designators; + std::vector Inhibitors; +}; + +class AresNewSWType +{ +public: + virtual ~AresNewSWType() = default; + virtual bool CanFireAt(const TargetingData& data, const CellStruct cell, bool manual) const { return false; } + virtual bool AbortFire(SuperClass* pSuper, bool isPlayer) const { return false; } + virtual bool Activate(SuperClass* pSuper, const CellStruct cell, bool isPlayer) { return false; } + virtual void Deactivate(SuperClass* pSuper, const CellStruct cell, bool isPlayer) { } + virtual void Initialize(SuperWeaponTypeClass** pExt_Ares) const { } + virtual void LoadFromINI(SuperWeaponTypeClass** pExt_Ares, CCINIClass* pINI) const { } + virtual WarheadTypeClass* GetWarhead(const SuperWeaponTypeClass** pExt_Ares) const { return nullptr; } + virtual AnimTypeClass* GetAnim(const SuperWeaponTypeClass** pExt_Ares) const { return nullptr; } + virtual int GetSound(const SuperWeaponTypeClass** pExt_Ares) const { return -1; } + virtual int GetDamage(const SuperWeaponTypeClass** pExt_Ares) const { return 0; } + virtual std::pair GetRange(const SuperWeaponTypeClass** pExt_Ares) const { return {}; } + virtual const char* GetTypeString() const { return nullptr; } + virtual bool HandlesType(SuperWeaponType type) const { return false; } + virtual SuperWeaponFlags Flags() const { return SuperWeaponFlags::None; } + virtual bool IsLaunchSite(SuperWeaponTypeClass** pExt_Ares, BuildingClass* pBuilding) const { return false; } + virtual std::pair GetLaunchSiteRange(SuperWeaponTypeClass** pExt_Ares, BuildingClass* pBuilding = nullptr) const { return {}; } + virtual bool IsDesignator(SuperWeaponTypeClass** pExt_Ares, HouseClass* pOwner, TechnoClass* pTechno) const { return false; } + virtual bool IsInhibitor(SuperWeaponTypeClass** pExt_Ares, HouseClass* pOwner, TechnoClass* pTechno) const { return false; } + + TargetingData& GetTargetingData(TargetingData& data, SuperWeaponTypeClass** pExt_Ares, HouseClass* pOwner) const; +}; diff --git a/src/Ext/SWType/Body.cpp b/src/Ext/SWType/Body.cpp index 46f72e0595..27ea30da64 100644 --- a/src/Ext/SWType/Body.cpp +++ b/src/Ext/SWType/Body.cpp @@ -47,6 +47,8 @@ void SWTypeExt::ExtData::Serialize(T& Stm) .Process(this->SW_PostDependent) .Process(this->SW_MaxCount) .Process(this->SW_Shots) + .Process(this->SW_DesignateTypes) + .Process(this->SW_InhibiteTypes) .Process(this->Message_CannotFire) .Process(this->Message_InsufficientFunds) .Process(this->Message_ColorScheme) @@ -135,6 +137,9 @@ void SWTypeExt::ExtData::LoadFromINIFile(CCINIClass* const pINI) this->SW_MaxCount.Read(exINI, pSection, "SW.MaxCount"); this->SW_Shots.Read(exINI, pSection, "SW.Shots"); + this->SW_DesignateTypes.Read(exINI, pSection, "SW.DesignateTypes"); + this->SW_InhibiteTypes.Read(exINI, pSection, "SW.InhibiteTypes"); + this->Message_CannotFire.Read(exINI, pSection, "Message.CannotFire"); this->Message_InsufficientFunds.Read(exINI, pSection, "Message.InsufficientFunds"); diff --git a/src/Ext/SWType/Body.h b/src/Ext/SWType/Body.h index 3b1f3eeb2b..83c1a21360 100644 --- a/src/Ext/SWType/Body.h +++ b/src/Ext/SWType/Body.h @@ -8,6 +8,7 @@ #include #include +#include #include class SWTypeExt @@ -52,6 +53,9 @@ class SWTypeExt ValueableIdx SW_PostDependent; Valueable SW_MaxCount; + ValueableVector SW_DesignateTypes; + ValueableVector SW_InhibiteTypes; + Valueable Message_CannotFire; Valueable Message_InsufficientFunds; ValueableIdx Message_ColorScheme; @@ -140,6 +144,8 @@ class SWTypeExt , SW_InitialReady { false } , SW_PostDependent {} , SW_MaxCount { -1 } + , SW_DesignateTypes {} + , SW_InhibiteTypes {} , SW_Shots { -1 } , Message_CannotFire {} , Message_InsufficientFunds {} @@ -194,10 +200,10 @@ class SWTypeExt { } // Ares 0.A functions - bool IsInhibitor(HouseClass* pOwner, TechnoClass* pTechno) const; + //bool IsInhibitor(HouseClass* pOwner, TechnoClass* pTechno) const; bool HasInhibitor(HouseClass* pOwner, const CellStruct& coords) const; bool IsInhibitorEligible(HouseClass* pOwner, const CellStruct& coords, TechnoClass* pTechno) const; - bool IsDesignator(HouseClass* pOwner, TechnoClass* pTechno) const; + //bool IsDesignator(HouseClass* pOwner, TechnoClass* pTechno) const; bool HasDesignator(HouseClass* pOwner, const CellStruct& coords) const; bool IsDesignatorEligible(HouseClass* pOwner, const CellStruct& coords, TechnoClass* pTechno) const; bool IsLaunchSiteEligible(const CellStruct& Coords, BuildingClass* pBuilding, bool ignoreRange) const; diff --git a/src/Ext/SWType/Hooks.cpp b/src/Ext/SWType/Hooks.cpp index f9c6c3a49d..a62469a121 100644 --- a/src/Ext/SWType/Hooks.cpp +++ b/src/Ext/SWType/Hooks.cpp @@ -61,34 +61,80 @@ DEFINE_HOOK(0x6DBE74, Tactical_SuperLinesCircles_ShowDesignatorRange, 0x7) return 0; const auto pSuperType = SuperWeaponTypeClass::Array.GetItem(Unsorted::CurrentSWType); - const auto pExt = SWTypeExt::ExtMap.Find(pSuperType); + const auto pSWExt = SWTypeExt::ExtMap.Find(pSuperType); - if (!pExt->ShowDesignatorRange) + if (!pSWExt->ShowDesignatorRange) return 0; - for (const auto pCurrentTechno : TechnoClass::Array) + const bool hasDesignateType = !pSWExt->SW_DesignateTypes.empty(); + const bool hasDesignator = !pSWExt->SW_Designators.empty(); + const bool hasInhibiteType = !pSWExt->SW_InhibiteTypes.empty(); + const bool hasInhibitor = !pSWExt->SW_Inhibitors.empty(); + + for (const auto pTechno : TechnoClass::Array) { - const auto pCurrentTechnoType = pCurrentTechno->GetTechnoType(); - const auto pOwner = pCurrentTechno->Owner; + if (!pTechno->IsAlive || !pTechno->Health || pTechno->InLimbo || pTechno->Deactivated) + continue; + + CoordStruct coords = pTechno->GetCenterCoords(); + coords.Z = MapClass::Instance.GetCellFloorHeight(coords); + const auto pOwner = pTechno->Owner; + const auto color = pOwner->Color; + + const auto pTechnoType = pTechno->GetTechnoType(); + const auto pTechnoTypeExt = TechnoTypeExt::ExtMap.Find(pTechnoType); - if (!pCurrentTechno->IsAlive - || pCurrentTechno->InLimbo - || (EnumFunctions::CanTargetHouse(pExt->SW_Designators_Houses, HouseClass::CurrentPlayer, pOwner) && !pExt->SW_Designators.Contains(pCurrentTechnoType)) - || (EnumFunctions::CanTargetHouse(pExt->SW_Inhibitors_Houses, HouseClass::CurrentPlayer, pOwner) && !pExt->SW_Inhibitors.Contains(pCurrentTechnoType))) + if (hasDesignateType) { - continue; + for (const auto signal : pSWExt->SW_DesignateTypes) + { + if (std::ranges::find(pTechnoTypeExt->DesignateTypes, signal) == pTechnoTypeExt->DesignateTypes.cend() + || !EnumFunctions::CanTargetHouse(signal->Affects.Get(AffectedHouse::Owner), pOwner, pTechno->Owner)) + continue; + + const int radius = signal->Range.Get(pTechnoType->Sight); + + if (radius > 0) + Game::DrawRadialIndicator(false, true, coords, color, static_cast(radius), false, true); + } } - const auto pTechnoTypeExt = TechnoTypeExt::ExtMap.Find(pCurrentTechnoType); + if (hasDesignator) + { + if (EnumFunctions::CanTargetHouse(pSWExt->SW_Designators_Houses, HouseClass::CurrentPlayer, pOwner) && pSWExt->SW_Designators.Contains(pTechnoType)) + { + const int radius = pTechnoTypeExt->DesignatorRange.Get(pTechnoType->Sight); - const float radius = pOwner == HouseClass::CurrentPlayer - ? (float)(pTechnoTypeExt->DesignatorRange.Get(pCurrentTechnoType->Sight)) - : (float)(pTechnoTypeExt->InhibitorRange.Get(pCurrentTechnoType->Sight)); + if (radius > 0) + Game::DrawRadialIndicator(false, true, coords, color, static_cast(radius), false, true); + } + } - CoordStruct coords = pCurrentTechno->GetCenterCoords(); - coords.Z = MapClass::Instance.GetCellFloorHeight(coords); - const auto color = pOwner->Color; - Game::DrawRadialIndicator(false, true, coords, color, radius, false, true); + if (hasInhibiteType) + { + for (const auto signal : pSWExt->SW_InhibiteTypes) + { + if (std::ranges::find(pTechnoTypeExt->InhibiteTypes, signal) == pTechnoTypeExt->InhibiteTypes.cend() + || !EnumFunctions::CanTargetHouse(signal->Affects.Get(AffectedHouse::Enemies), pOwner, pTechno->Owner)) + continue; + + const int radius = signal->Range.Get(pTechnoType->Sight); + + if (radius > 0) + Game::DrawRadialIndicator(false, true, coords, color, static_cast(radius), false, true); + } + } + + if (hasInhibitor) + { + if (EnumFunctions::CanTargetHouse(pSWExt->SW_Inhibitors_Houses, HouseClass::CurrentPlayer, pOwner) && pSWExt->SW_Inhibitors.Contains(pTechnoType)) + { + const int radius = pTechnoTypeExt->InhibitorRange.Get(pTechnoType->Sight); + + if (radius > 0) + Game::DrawRadialIndicator(false, true, coords, color, static_cast(radius), false, true); + } + } } return 0; diff --git a/src/Ext/SWType/SWHelpers.cpp b/src/Ext/SWType/SWHelpers.cpp index 0014da638c..edeaea72ba 100644 --- a/src/Ext/SWType/SWHelpers.cpp +++ b/src/Ext/SWType/SWHelpers.cpp @@ -42,37 +42,60 @@ std::vector SWTypeExt::ExtData::WeightedRollsHandler(ValueableVector // ============================= // Ares 0.A helpers // Inhibitors check -bool SWTypeExt::ExtData::IsInhibitor(HouseClass* pOwner, TechnoClass* pTechno) const +//bool SWTypeExt::ExtData::IsInhibitor(HouseClass* pOwner, TechnoClass* pTechno) const +//{ +// if (pTechno->IsAlive && pTechno->Health && !pTechno->InLimbo && !pTechno->Deactivated) +// { +// if (EnumFunctions::CanTargetHouse(this->SW_Inhibitors_Houses, pOwner, pTechno->Owner)) +// { +// if (const auto pBuilding = abstract_cast(pTechno)) +// { +// if (!pBuilding->IsPowerOnline()) +// return false; +// } +// +// return this->SW_AnyInhibitor || this->SW_Inhibitors.Contains(pTechno->GetTechnoType()); +// } +// } +// +// return false; +//} + +bool SWTypeExt::ExtData::IsInhibitorEligible(HouseClass* pOwner, const CellStruct& coords, TechnoClass* pTechno) const { - if (pTechno->IsAlive && pTechno->Health && !pTechno->InLimbo && !pTechno->Deactivated) - { - if (EnumFunctions::CanTargetHouse(this->SW_Inhibitors_Houses, pOwner, pTechno->Owner)) - { - if (const auto pBuilding = abstract_cast(pTechno)) - { - if (!pBuilding->IsPowerOnline()) - return false; - } + if (!pTechno->IsAlive || !pTechno->Health || pTechno->InLimbo || pTechno->Deactivated) + return false; - return this->SW_AnyInhibitor || this->SW_Inhibitors.Contains(pTechno->GetTechnoType()); - } - } + const auto pBuilding = abstract_cast(pTechno); - return false; -} + if (pBuilding && !pBuilding->IsPowerOnline()) + return false; -bool SWTypeExt::ExtData::IsInhibitorEligible(HouseClass* pOwner, const CellStruct& coords, TechnoClass* pTechno) const -{ - if (this->IsInhibitor(pOwner, pTechno)) + // get the inhibitor's center + const auto center = pTechno->GetCenterCoords(); + const double distanceSqr = coords.DistanceFromSquared(CellClass::Coord2Cell(center)); + + const auto pTechnoType = pTechno->GetTechnoType(); + const auto pTechnoTypeExt = TechnoTypeExt::ExtMap.Find(pTechnoType); + + for (const auto signal : this->SW_InhibiteTypes) { - const auto pType = pTechno->GetTechnoType(); - const auto pExt = TechnoTypeExt::ExtMap.Find(pType); + if (std::ranges::find(pTechnoTypeExt->InhibiteTypes, signal) == pTechnoTypeExt->InhibiteTypes.cend() + || !EnumFunctions::CanTargetHouse(signal->Affects.Get(AffectedHouse::Enemies), pOwner, pTechno->Owner)) + continue; + + const int range = signal->Range.Get(pTechnoType->Sight); - // get the inhibitor's center - const auto center = pTechno->GetCenterCoords(); + if (distanceSqr <= range * range) + return true; + } + + if (EnumFunctions::CanTargetHouse(this->SW_Inhibitors_Houses, pOwner, pTechno->Owner) && (this->SW_AnyInhibitor || this->SW_Inhibitors.Contains(pTechnoType))) + { + const int range = pTechnoTypeExt->InhibitorRange.Get(pTechnoType->Sight); - // has to be closer than the inhibitor range (which defaults to Sight) - return coords.DistanceFrom(CellClass::Coord2Cell(center)) <= pExt->InhibitorRange.Get(pType->Sight); + if (distanceSqr <= range * range) + return true; } return false; @@ -81,39 +104,57 @@ bool SWTypeExt::ExtData::IsInhibitorEligible(HouseClass* pOwner, const CellStruc bool SWTypeExt::ExtData::HasInhibitor(HouseClass* pOwner, const CellStruct& coords) const { // does not allow inhibitors - if (this->SW_Inhibitors.empty() && !this->SW_AnyInhibitor) + if (this->SW_InhibiteTypes.empty() && this->SW_Inhibitors.empty() && !this->SW_AnyInhibitor) return false; // a single inhibitor in range suffices - return std::any_of(TechnoClass::Array.begin(), TechnoClass::Array.end(), [=, &coords](TechnoClass* pTechno) + return std::ranges::any_of(TechnoClass::Array, [=, &coords](TechnoClass* pTechno) { return this->IsInhibitorEligible(pOwner, coords, pTechno); } ); } // Designators check -bool SWTypeExt::ExtData::IsDesignator(HouseClass* pOwner, TechnoClass* pTechno) const -{ - if (EnumFunctions::CanTargetHouse(this->SW_Designators_Houses, pOwner, pTechno->Owner)) - { - if (pTechno->IsAlive && pTechno->Health && !pTechno->InLimbo && !pTechno->Deactivated) - return this->SW_AnyDesignator || this->SW_Designators.Contains(pTechno->GetTechnoType()); - } - - return false; -} +//bool SWTypeExt::ExtData::IsDesignator(HouseClass* pOwner, TechnoClass* pTechno) const +//{ +// if (EnumFunctions::CanTargetHouse(this->SW_Designators_Houses, pOwner, pTechno->Owner)) +// { +// if (pTechno->IsAlive && pTechno->Health && !pTechno->InLimbo && !pTechno->Deactivated) +// return this->SW_AnyDesignator || this->SW_Designators.Contains(pTechno->GetTechnoType()); +// } +// +// return false; +//} bool SWTypeExt::ExtData::IsDesignatorEligible(HouseClass* pOwner, const CellStruct& coords, TechnoClass* pTechno) const { - if (this->IsDesignator(pOwner, pTechno)) + if (!pTechno->IsAlive || !pTechno->Health || pTechno->InLimbo || pTechno->Deactivated) + return false; + + // get the designator's center + const auto center = pTechno->GetCenterCoords(); + const double distanceSqr = coords.DistanceFromSquared(CellClass::Coord2Cell(center)); + + const auto pTechnoType = pTechno->GetTechnoType(); + const auto pTechnoTypeExt = TechnoTypeExt::ExtMap.Find(pTechnoType); + + for (const auto signal : this->SW_DesignateTypes) { - const auto pType = pTechno->GetTechnoType(); - const auto pExt = TechnoTypeExt::ExtMap.Find(pType); + if (std::ranges::find(pTechnoTypeExt->DesignateTypes, signal) == pTechnoTypeExt->DesignateTypes.cend() + || !EnumFunctions::CanTargetHouse(signal->Affects.Get(AffectedHouse::Owner), pOwner, pTechno->Owner)) + continue; - // get the designator's center - const auto center = pTechno->GetCenterCoords(); + const int range = signal->Range.Get(pTechnoType->Sight); + + if (distanceSqr <= range * range) + return true; + } + + if (EnumFunctions::CanTargetHouse(this->SW_Designators_Houses, pOwner, pTechno->Owner) && (this->SW_AnyDesignator || this->SW_Designators.Contains(pTechnoType))) + { + const int range = pTechnoTypeExt->DesignatorRange.Get(pTechnoType->Sight); - // has to be closer than the designator range (which defaults to Sight) - return coords.DistanceFrom(CellClass::Coord2Cell(center)) <= pExt->DesignatorRange.Get(pType->Sight); + if (distanceSqr <= range * range) + return true; } return false; @@ -122,11 +163,11 @@ bool SWTypeExt::ExtData::IsDesignatorEligible(HouseClass* pOwner, const CellStru bool SWTypeExt::ExtData::HasDesignator(HouseClass* pOwner, const CellStruct& coords) const { // does not require designators - if (this->SW_Designators.empty() && !this->SW_AnyDesignator) + if (this->SW_DesignateTypes.empty() && this->SW_Designators.empty() && !this->SW_AnyDesignator) return true; // a single designator in range suffices - return std::any_of(TechnoClass::Array.begin(), TechnoClass::Array.end(), [=, &coords](TechnoClass* pTechno) + return std::ranges::any_of(TechnoClass::Array, [=, &coords](TechnoClass* pTechno) { return this->IsDesignatorEligible(pOwner, coords, pTechno); }); } diff --git a/src/Ext/Script/Mission.Attack.cpp b/src/Ext/Script/Mission.Attack.cpp index 536a26f77a..44919da709 100644 --- a/src/Ext/Script/Mission.Attack.cpp +++ b/src/Ext/Script/Mission.Attack.cpp @@ -976,7 +976,8 @@ bool ScriptExt::EvaluateObjectWithMask(TechnoClass* pTechno, int mask, int attac const auto pTechnoTypeExt = TechnoTypeExt::ExtMap.Find(pTechnoType); if (pTechnoTypeExt->RadarJamRadius > 0 - || pTechnoTypeExt->InhibitorRange.isset()) + || pTechnoTypeExt->InhibitorRange.isset() + || !pTechnoTypeExt->InhibiteTypes.empty()) { return true; } @@ -1250,10 +1251,12 @@ bool ScriptExt::EvaluateObjectWithMask(TechnoClass* pTechno, int mask, int attac case 30: // Inhibitor - if (!pTechno->Owner->IsNeutral() - && TechnoTypeExt::ExtMap.Find(pTechnoType)->InhibitorRange.isset()) + if (!pTechno->Owner->IsNeutral()) { - return true; + const auto pTechnoTypeExt = TechnoTypeExt::ExtMap.Find(pTechnoType); + + if (pTechnoTypeExt->InhibitorRange.isset() || !pTechnoTypeExt->InhibiteTypes.empty()) + return true; } break; diff --git a/src/Ext/TechnoType/Body.cpp b/src/Ext/TechnoType/Body.cpp index f0ce44e17c..af36b82203 100644 --- a/src/Ext/TechnoType/Body.cpp +++ b/src/Ext/TechnoType/Body.cpp @@ -943,6 +943,9 @@ void TechnoTypeExt::ExtData::LoadFromINIFile(CCINIClass* const pINI) this->Power.Read(exINI, pSection, "Power"); + this->DesignateTypes.Read(exINI, pSection, "DesignateTypes"); + this->InhibiteTypes.Read(exINI, pSection, "InhibiteTypes"); + this->AllowAirstrike.Read(exINI, pSection, "AllowAirstrike"); this->Image_ConditionYellow.Read(exINI, pSection, "Image.ConditionYellow"); @@ -1580,6 +1583,9 @@ void TechnoTypeExt::ExtData::Serialize(T& Stm) .Process(this->Power) + .Process(this->DesignateTypes) + .Process(this->InhibiteTypes) + .Process(this->AllowAirstrike) .Process(this->Image_ConditionYellow) diff --git a/src/Ext/TechnoType/Body.h b/src/Ext/TechnoType/Body.h index efe25a53e1..1b77469ef5 100644 --- a/src/Ext/TechnoType/Body.h +++ b/src/Ext/TechnoType/Body.h @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include @@ -332,6 +333,9 @@ class TechnoTypeExt Valueable Power; + ValueableVector DesignateTypes; + ValueableVector InhibiteTypes; + Nullable AllowAirstrike; Nullable Image_ConditionYellow; @@ -738,6 +742,9 @@ class TechnoTypeExt , Power { } + , DesignateTypes { } + , InhibiteTypes { } + , AllowAirstrike { } , Image_ConditionYellow { } diff --git a/src/Misc/Hooks.Ares.cpp b/src/Misc/Hooks.Ares.cpp index 5170a1068a..7a957d61b5 100644 --- a/src/Misc/Hooks.Ares.cpp +++ b/src/Misc/Hooks.Ares.cpp @@ -9,6 +9,7 @@ #include #include #include +#include #include // Remember that we still don't fix Ares "issues" a priori. Extensions as well. @@ -49,17 +50,7 @@ WeaponStruct* __fastcall GetLaserWeapon(BuildingClass* pThis) return BuildingExt::GetLaserWeapon(pThis); } -bool __fastcall NewSWType_IsInhibitor(void*, void*, SuperWeaponTypeClass** pExt_Ares, HouseClass* pOwner, TechnoClass* pTechno) -{ - const auto pSWExt = SWTypeExt::ExtMap.Find(*pExt_Ares); - return pSWExt->IsInhibitor(pOwner, pTechno); -} - -bool __fastcall NewSWType_IsDesignator(void*, void*, SuperWeaponTypeClass** pExt_Ares, HouseClass* pOwner, TechnoClass* pTechno) -{ - const auto pSWExt = SWTypeExt::ExtMap.Find(*pExt_Ares); - return pSWExt->IsDesignator(pOwner, pTechno); -} +_GET_FUNCTION_ADDRESS(AresNewSWType::GetTargetingData, AresNewSWType_GetTargetingData_GetAddr) EBolt* __stdcall CreateEBolt(WeaponTypeClass** pWeaponData) { @@ -121,9 +112,8 @@ void Apply_Ares3_0_Patches() // Apply laser weapon selection fix on Ares' laser fire replacement. Patch::Apply_CALL6(AresHelper::AresBaseAddress + 0x56415, &GetLaserWeapon); - // Redirect Ares' IsInhibitor() and IsDesignator() to our implementation: - Patch::Apply_LJMP(AresHelper::AresBaseAddress + 0x6D900, &NewSWType_IsInhibitor); - Patch::Apply_LJMP(AresHelper::AresBaseAddress + 0x6D880, &NewSWType_IsDesignator); + // Redirect Ares' NewSWType::GetTargetingData() to our implementation: + Patch::Apply_LJMP(AresHelper::AresBaseAddress + 0x6D1E0, AresNewSWType_GetTargetingData_GetAddr()); } void Apply_Ares3_0p1_Patches() @@ -178,7 +168,6 @@ void Apply_Ares3_0p1_Patches() // Apply laser weapon selection fix on Ares' laser fire replacement. Patch::Apply_CALL6(AresHelper::AresBaseAddress + 0x570C5, &GetLaserWeapon); - // Redirect Ares' IsInhibitor() and IsDesignator() to our implementation: - Patch::Apply_LJMP(AresHelper::AresBaseAddress + 0x6E910, &NewSWType_IsInhibitor); - Patch::Apply_LJMP(AresHelper::AresBaseAddress + 0x6E890, &NewSWType_IsDesignator); + // Redirect Ares' NewSWType::GetTargetingData() to our implementation: + Patch::Apply_LJMP(AresHelper::AresBaseAddress + 0x6E1F0, AresNewSWType_GetTargetingData_GetAddr()); } diff --git a/src/New/Type/SWSignalTypeClass.cpp b/src/New/Type/SWSignalTypeClass.cpp new file mode 100644 index 0000000000..a4c94f76a2 --- /dev/null +++ b/src/New/Type/SWSignalTypeClass.cpp @@ -0,0 +1,42 @@ +#include "SWSignalTypeClass.h" + +const char* Enumerable::GetMainSection() +{ + return "SWSignalTypes"; +} + +void SWSignalTypeClass::LoadFromINI(CCINIClass* pINI) +{ + const char* pSection = this->Name; + + if (!pINI->GetSection(pSection)) + return; + + INI_EX exINI(pINI); + //char tempBuffer[0x20]; + + this->Range.Read(exINI, pSection, "Range"); + this->Affects.Read(exINI, pSection, "Affects"); +} + +// ============================= +// load / save + +template +void SWSignalTypeClass::Serialize(T& stm) +{ + stm + .Process(this->Range) + .Process(this->Affects) + ; +} + +void SWSignalTypeClass::LoadFromStream(PhobosStreamReader& stm) +{ + this->Serialize(stm); +} + +void SWSignalTypeClass::SaveToStream(PhobosStreamWriter& stm) +{ + this->Serialize(stm); +} diff --git a/src/New/Type/SWSignalTypeClass.h b/src/New/Type/SWSignalTypeClass.h new file mode 100644 index 0000000000..5d773b86dc --- /dev/null +++ b/src/New/Type/SWSignalTypeClass.h @@ -0,0 +1,22 @@ +#pragma once + +#include +#include + +class SWSignalTypeClass final : public Enumerable +{ +public: + Nullable Range {}; + Nullable Affects {}; + + SWSignalTypeClass(const char* pTitle = NONE_STR) : Enumerable(pTitle) + { } + + void LoadFromINI(CCINIClass* pINI); + void LoadFromStream(PhobosStreamReader& stm); + void SaveToStream(PhobosStreamWriter& stm); + +private: + template + void Serialize(T& stm); +}; diff --git a/src/Phobos.Ext.cpp b/src/Phobos.Ext.cpp index ac02d779bf..7ff52ac63d 100644 --- a/src/Phobos.Ext.cpp +++ b/src/Phobos.Ext.cpp @@ -36,6 +36,7 @@ #include #include #include +#include #include #include @@ -242,7 +243,8 @@ using PhobosTypeRegistry = TypeRegistry < AttachEffectTypeClass, AttachEffectClass, NewSWType, - SelectBoxTypeClass + SelectBoxTypeClass, + SWSignalTypeClass // other classes > ; From 9b0c60249b1f095be3521b5ad874a987c74cc25c Mon Sep 17 00:00:00 2001 From: NetsuNegi39 Date: Sun, 23 Nov 2025 19:11:41 +0800 Subject: [PATCH 06/10] Update New-or-Enhanced-Logics.md --- docs/New-or-Enhanced-Logics.md | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/docs/New-or-Enhanced-Logics.md b/docs/New-or-Enhanced-Logics.md index 60e622f0b7..473ebf4acd 100644 --- a/docs/New-or-Enhanced-Logics.md +++ b/docs/New-or-Enhanced-Logics.md @@ -1121,9 +1121,22 @@ TabIndex=1 ; integer In `rulesmd.ini` ```ini +[SWSignalTypes] +0=SOMESWSIGNAL + +[SOMESWSIGNAL] +Range= ; integer +Affects= ; List of Affected House Enumeration (none|owner/self|allies/ally|team|enemies/enemy|all) + [SOMESW] ; SuperWeaponType SW.Inhibitors.Houses=enemies ; List of Affected House Enumeration (none|owner/self|allies/ally|team|enemies/enemy|all) SW.Designators.Houses=owner ; List of Affected House Enumeration (none|owner/self|allies/ally|team|enemies/enemy|all) +SW.InhibiteTypes= ; List of sw signal types +SW.DesignateTypes= ; List of sw signal types + +[SOMETECHNO] ; TechnoType +InhibiteTypes= ; List of sw signal types +DesignateTypes= ; List of sw signal types ``` ### EMPulse settings From 2c60c690bf19c6bbeeb32cf61b17f247d9ae3d24 Mon Sep 17 00:00:00 2001 From: Coronia <2217891145@qq.com> Date: Fri, 28 Nov 2025 12:27:13 +0800 Subject: [PATCH 07/10] update doc and Powered --- docs/Fixed-or-Improved-Logics.md | 14 ++++++++ docs/New-or-Enhanced-Logics.md | 55 +++++++++++++++++------------- src/Ext/SWType/Ares/NewSWType.cpp | 53 ++++++++++++---------------- src/Ext/SWType/Hooks.cpp | 18 ++++++++-- src/Ext/SWType/SWHelpers.cpp | 23 +++++++++---- src/New/Type/SWSignalTypeClass.cpp | 4 ++- src/New/Type/SWSignalTypeClass.h | 1 + 7 files changed, 103 insertions(+), 65 deletions(-) diff --git a/docs/Fixed-or-Improved-Logics.md b/docs/Fixed-or-Improved-Logics.md index 521c090bf4..1405136e02 100644 --- a/docs/Fixed-or-Improved-Logics.md +++ b/docs/Fixed-or-Improved-Logics.md @@ -948,6 +948,20 @@ Shrapnel.AffectsBuildings=false ; boolean Shrapnel.UseWeaponTargeting=false ; boolean ``` +## Super Weapons + +### Custom affected houses for Ares' Inhibitor and Designator + +- In Ares, only enemies inhibitors and selfowned designators are eligible. Now you can customize it. +- This is independent from [Custom Inhibitor and Designator Type](New-or-Enhanced-Logics.md#custom-inhibitor-and-designator-type) introduced by Phobos. + +In `rulesmd.ini`: +```ini +[SOMESW] ; SuperWeaponType +SW.Inhibitors.Houses=enemies ; List of Affected House Enumeration (none|owner/self|allies/ally|team|enemies/enemy|all) +SW.Designators.Houses=owner ; List of Affected House Enumeration (none|owner/self|allies/ally|team|enemies/enemy|all) +``` + ## Technos ### Airstrike flare visual customizations diff --git a/docs/New-or-Enhanced-Logics.md b/docs/New-or-Enhanced-Logics.md index d35bb9f198..faf59e1e28 100644 --- a/docs/New-or-Enhanced-Logics.md +++ b/docs/New-or-Enhanced-Logics.md @@ -181,6 +181,37 @@ SuppressReflectDamage.Types= ; List of AttachEffectTypes SuppressReflectDamage.Groups= ; comma-separated list of strings (group IDs) ``` +### Custom Super Weapon Signal Type + +- It's now possible to define Inhibitor and Designator properties in a Super Weapon Signal Type, which allows more customization than [Ares' Inibitors and Designators](https://ares-developers.github.io/Ares-docs/new/superweapons/range.html). +- `Range` determines the radius of the Inhibitor and Designator effects. Default to the attached techno's `Sight` if not set. +- `Affects` determines the affected house of the Inhibitor and Designator effects. Default to `enemies` if it's used as an Inhibitor, and `owner` if it's Designator. +- `Powered` determines whether or not the effect is rendered inactive if the object it is attached to is deactivated (`PoweredUnit` or affected by EMP) or on low power. + - Notice that it's different from Ares' behavior, which always checks if the building is on low power for Inhibitor, and doesn't check EMP. +- `SW.InhibiteTypes` determines the Super Weapon Signals that'll act as an Inhibitor for this super weapon, which prevent it to be launched in this area. +- `SW.DesignateTypes` determines the Super Weapon Signals that'll act as an Designator for this super weapon, which only allow it to be launched in this area. +- `InhibiteTypes` and `DesignateTypes` determine the Super Weapon Signals a techno owned, which make it an Inhibitor/Designator to super weapons with corresponding `SW.Inhibite/DesignateTypes`. +- This allow a techno to own multiple Inhibitor and Designator effects towards different super weapons, rather than limited to one for all super weapons. + +In `rulesmd.ini` +```ini +[SuperWeaponSignalTypes] +0=SOMESWSIGNAL + +[SOMESWSIGNAL] ; SuperWeaponSignalType +Range= ; integer, default to [SOMETECHNO] -> Sight +Affects= ; List of Affected House Enumeration (none|owner/self|allies/ally|team|enemies/enemy|all), default to enemies for Inhibitor and owner for Designator +Powered=false ; boolean + +[SOMESW] ; SuperWeaponType +SW.InhibiteTypes= ; List of SuperWeaponSignalType +SW.DesignateTypes= ; List of SuperWeaponSignalType + +[SOMETECHNO] ; TechnoType +InhibiteTypes= ; List of SuperWeaponSignalType +DesignateTypes= ; List of SuperWeaponSignalType +``` + ### Custom Radiation Types ![image](_static/images/radtype-01.png) @@ -1117,30 +1148,6 @@ In `rulesmd.ini`: TabIndex=1 ; integer ``` -### Customize Inhibitors and Designators - -- Theres only enemies inhibitors and selfowned designators are eligible. Now you can customize it. - -In `rulesmd.ini` -```ini -[SWSignalTypes] -0=SOMESWSIGNAL - -[SOMESWSIGNAL] -Range= ; integer -Affects= ; List of Affected House Enumeration (none|owner/self|allies/ally|team|enemies/enemy|all) - -[SOMESW] ; SuperWeaponType -SW.Inhibitors.Houses=enemies ; List of Affected House Enumeration (none|owner/self|allies/ally|team|enemies/enemy|all) -SW.Designators.Houses=owner ; List of Affected House Enumeration (none|owner/self|allies/ally|team|enemies/enemy|all) -SW.InhibiteTypes= ; List of sw signal types -SW.DesignateTypes= ; List of sw signal types - -[SOMETECHNO] ; TechnoType -InhibiteTypes= ; List of sw signal types -DesignateTypes= ; List of sw signal types -``` - ### EMPulse settings - It is possible to customize which weapon a building with `EMPulseCannon=true` fires when an associated `Type=EMPulse` superweapon (**only** if `EMPulse.TargetSelf=false` or omitted) is fired by setting `EMPulse.WeaponIndex`. diff --git a/src/Ext/SWType/Ares/NewSWType.cpp b/src/Ext/SWType/Ares/NewSWType.cpp index b4b390ff21..6e33e86ee3 100644 --- a/src/Ext/SWType/Ares/NewSWType.cpp +++ b/src/Ext/SWType/Ares/NewSWType.cpp @@ -31,28 +31,41 @@ TargetingData& AresNewSWType::GetTargetingData(TargetingData& data, SuperWeaponT const auto pExt = SWTypeExt::ExtMap.Find(*pExt_Ares); const bool hasDesignateType = !pExt->SW_DesignateTypes.empty(); const bool hasDesignator = !pExt->SW_Designators.empty() || pExt->SW_AnyDesignator; + const bool hasInhibiteType = !pExt->SW_InhibiteTypes.empty(); + const bool hasInhibitor = !pExt->SW_Inhibitors.empty() || pExt->SW_AnyInhibitor; - // get designator data - if (hasDesignateType || hasDesignator) + if (hasDesignateType || hasDesignator || hasInhibiteType || hasInhibitor) { - data.NeedsDesignator = true; + if (hasDesignateType || hasDesignator) + data.NeedsDesignator = true; for (const auto pTechno : TechnoClass::Array) { - if (!pTechno->IsAlive || !pTechno->Health || pTechno->InLimbo || pTechno->Deactivated) + if (!pTechno->IsAlive || !pTechno->Health || pTechno->InLimbo) continue; // get the designator's center const auto center = pTechno->GetCoords(); const auto cell = CellClass::Coord2Cell(center); + bool inactive = pTechno->Deactivated || pTechno->IsUnderEMP(); + bool buildingOnline = true; + + if (const auto pBuilding = abstract_cast(pTechno)) + { + buildingOnline = pBuilding->IsPowerOnline(); + inactive |= !buildingOnline; + } const auto pTechnoType = pTechno->GetTechnoType(); - const auto pTechnoTypeExt = TechnoTypeExt::ExtMap.Find(pTechnoType); + const auto pTechnoTypeExt = TechnoTypeExt::ExtMap.Find(pTechnoType); if (hasDesignateType) { for (const auto signal : pExt->SW_DesignateTypes) { + if (inactive && signal->Powered) + continue; + if (std::ranges::find(pTechnoTypeExt->DesignateTypes, signal) == pTechnoTypeExt->DesignateTypes.cend() || !EnumFunctions::CanTargetHouse(signal->Affects.Get(AffectedHouse::Owner), pOwner, pTechno->Owner)) continue; @@ -73,36 +86,14 @@ TargetingData& AresNewSWType::GetTargetingData(TargetingData& data, SuperWeaponT if (range > 0) data.Designators.emplace_back(range * range, cell); } - } - } - - const bool hasInhibiteType = !pExt->SW_InhibiteTypes.empty(); - const bool hasInhibitor = !pExt->SW_Inhibitors.empty() || pExt->SW_AnyInhibitor; - - // get inhibitor data - if (hasInhibiteType || hasInhibitor) - { - for (const auto pTechno : TechnoClass::Array) - { - if (!pTechno->IsAlive || !pTechno->Health || pTechno->InLimbo || pTechno->Deactivated) - continue; - - const auto pBuilding = abstract_cast(pTechno); - - if (pBuilding && !pBuilding->IsPowerOnline()) - continue; - - // get the inhibitor's center - const auto center = pTechno->GetCoords(); - const auto cell = CellClass::Coord2Cell(center); - - const auto pTechnoType = pTechno->GetTechnoType(); - const auto pTechnoTypeExt = TechnoTypeExt::ExtMap.Find(pTechnoType); if (hasInhibiteType) { for (const auto signal : pExt->SW_InhibiteTypes) { + if (inactive && signal->Powered) + continue; + if (std::ranges::find(pTechnoTypeExt->InhibiteTypes, signal) == pTechnoTypeExt->InhibiteTypes.cend() || !EnumFunctions::CanTargetHouse(signal->Affects.Get(AffectedHouse::Enemies), pOwner, pTechno->Owner)) continue; @@ -114,7 +105,7 @@ TargetingData& AresNewSWType::GetTargetingData(TargetingData& data, SuperWeaponT } } - if (hasInhibitor + if (hasInhibitor && buildingOnline && EnumFunctions::CanTargetHouse(pExt->SW_Inhibitors_Houses, pOwner, pTechno->Owner) && (pExt->SW_AnyInhibitor || pExt->SW_Inhibitors.Contains(pTechnoType))) { diff --git a/src/Ext/SWType/Hooks.cpp b/src/Ext/SWType/Hooks.cpp index a62469a121..b473de9ec8 100644 --- a/src/Ext/SWType/Hooks.cpp +++ b/src/Ext/SWType/Hooks.cpp @@ -73,13 +73,21 @@ DEFINE_HOOK(0x6DBE74, Tactical_SuperLinesCircles_ShowDesignatorRange, 0x7) for (const auto pTechno : TechnoClass::Array) { - if (!pTechno->IsAlive || !pTechno->Health || pTechno->InLimbo || pTechno->Deactivated) + if (!pTechno->IsAlive || !pTechno->Health || pTechno->InLimbo) continue; CoordStruct coords = pTechno->GetCenterCoords(); coords.Z = MapClass::Instance.GetCellFloorHeight(coords); const auto pOwner = pTechno->Owner; const auto color = pOwner->Color; + bool inactive = pTechno->Deactivated || pTechno->IsUnderEMP(); + bool buildingOnline = true; + + if (const auto pBuilding = abstract_cast(pTechno)) + { + buildingOnline = pBuilding->IsPowerOnline(); + inactive |= !buildingOnline; + } const auto pTechnoType = pTechno->GetTechnoType(); const auto pTechnoTypeExt = TechnoTypeExt::ExtMap.Find(pTechnoType); @@ -88,6 +96,9 @@ DEFINE_HOOK(0x6DBE74, Tactical_SuperLinesCircles_ShowDesignatorRange, 0x7) { for (const auto signal : pSWExt->SW_DesignateTypes) { + if (inactive && signal->Powered) + continue; + if (std::ranges::find(pTechnoTypeExt->DesignateTypes, signal) == pTechnoTypeExt->DesignateTypes.cend() || !EnumFunctions::CanTargetHouse(signal->Affects.Get(AffectedHouse::Owner), pOwner, pTechno->Owner)) continue; @@ -114,6 +125,9 @@ DEFINE_HOOK(0x6DBE74, Tactical_SuperLinesCircles_ShowDesignatorRange, 0x7) { for (const auto signal : pSWExt->SW_InhibiteTypes) { + if (inactive && signal->Powered) + continue; + if (std::ranges::find(pTechnoTypeExt->InhibiteTypes, signal) == pTechnoTypeExt->InhibiteTypes.cend() || !EnumFunctions::CanTargetHouse(signal->Affects.Get(AffectedHouse::Enemies), pOwner, pTechno->Owner)) continue; @@ -125,7 +139,7 @@ DEFINE_HOOK(0x6DBE74, Tactical_SuperLinesCircles_ShowDesignatorRange, 0x7) } } - if (hasInhibitor) + if (hasInhibitor && buildingOnline) { if (EnumFunctions::CanTargetHouse(pSWExt->SW_Inhibitors_Houses, HouseClass::CurrentPlayer, pOwner) && pSWExt->SW_Inhibitors.Contains(pTechnoType)) { diff --git a/src/Ext/SWType/SWHelpers.cpp b/src/Ext/SWType/SWHelpers.cpp index edeaea72ba..e105f0fb85 100644 --- a/src/Ext/SWType/SWHelpers.cpp +++ b/src/Ext/SWType/SWHelpers.cpp @@ -63,23 +63,25 @@ std::vector SWTypeExt::ExtData::WeightedRollsHandler(ValueableVector bool SWTypeExt::ExtData::IsInhibitorEligible(HouseClass* pOwner, const CellStruct& coords, TechnoClass* pTechno) const { - if (!pTechno->IsAlive || !pTechno->Health || pTechno->InLimbo || pTechno->Deactivated) - return false; - - const auto pBuilding = abstract_cast(pTechno); - - if (pBuilding && !pBuilding->IsPowerOnline()) + if (!pTechno->IsAlive || !pTechno->Health || pTechno->InLimbo) return false; // get the inhibitor's center const auto center = pTechno->GetCenterCoords(); const double distanceSqr = coords.DistanceFromSquared(CellClass::Coord2Cell(center)); + bool inactive = pTechno->Deactivated || pTechno->IsUnderEMP(); + + if (const auto pBuilding = abstract_cast(pTechno)) + inactive |= !pBuilding->IsPowerOnline(); const auto pTechnoType = pTechno->GetTechnoType(); const auto pTechnoTypeExt = TechnoTypeExt::ExtMap.Find(pTechnoType); for (const auto signal : this->SW_InhibiteTypes) { + if (inactive && signal->Powered) + continue; + if (std::ranges::find(pTechnoTypeExt->InhibiteTypes, signal) == pTechnoTypeExt->InhibiteTypes.cend() || !EnumFunctions::CanTargetHouse(signal->Affects.Get(AffectedHouse::Enemies), pOwner, pTechno->Owner)) continue; @@ -127,18 +129,25 @@ bool SWTypeExt::ExtData::HasInhibitor(HouseClass* pOwner, const CellStruct& coor bool SWTypeExt::ExtData::IsDesignatorEligible(HouseClass* pOwner, const CellStruct& coords, TechnoClass* pTechno) const { - if (!pTechno->IsAlive || !pTechno->Health || pTechno->InLimbo || pTechno->Deactivated) + if (!pTechno->IsAlive || !pTechno->Health || pTechno->InLimbo) return false; // get the designator's center const auto center = pTechno->GetCenterCoords(); const double distanceSqr = coords.DistanceFromSquared(CellClass::Coord2Cell(center)); + bool inactive = pTechno->Deactivated || pTechno->IsUnderEMP(); + + if (const auto pBuilding = abstract_cast(pTechno)) + inactive |= !pBuilding->IsPowerOnline(); const auto pTechnoType = pTechno->GetTechnoType(); const auto pTechnoTypeExt = TechnoTypeExt::ExtMap.Find(pTechnoType); for (const auto signal : this->SW_DesignateTypes) { + if (inactive && signal->Powered) + continue; + if (std::ranges::find(pTechnoTypeExt->DesignateTypes, signal) == pTechnoTypeExt->DesignateTypes.cend() || !EnumFunctions::CanTargetHouse(signal->Affects.Get(AffectedHouse::Owner), pOwner, pTechno->Owner)) continue; diff --git a/src/New/Type/SWSignalTypeClass.cpp b/src/New/Type/SWSignalTypeClass.cpp index a4c94f76a2..9a982f7988 100644 --- a/src/New/Type/SWSignalTypeClass.cpp +++ b/src/New/Type/SWSignalTypeClass.cpp @@ -2,7 +2,7 @@ const char* Enumerable::GetMainSection() { - return "SWSignalTypes"; + return "SuperWeaponSignalTypes"; } void SWSignalTypeClass::LoadFromINI(CCINIClass* pINI) @@ -17,6 +17,7 @@ void SWSignalTypeClass::LoadFromINI(CCINIClass* pINI) this->Range.Read(exINI, pSection, "Range"); this->Affects.Read(exINI, pSection, "Affects"); + this->Powered.Read(exINI, pSection, "Powered"); } // ============================= @@ -28,6 +29,7 @@ void SWSignalTypeClass::Serialize(T& stm) stm .Process(this->Range) .Process(this->Affects) + .Process(this->Powered) ; } diff --git a/src/New/Type/SWSignalTypeClass.h b/src/New/Type/SWSignalTypeClass.h index 5d773b86dc..7aa4469444 100644 --- a/src/New/Type/SWSignalTypeClass.h +++ b/src/New/Type/SWSignalTypeClass.h @@ -8,6 +8,7 @@ class SWSignalTypeClass final : public Enumerable public: Nullable Range {}; Nullable Affects {}; + Valueable Powered { false }; SWSignalTypeClass(const char* pTitle = NONE_STR) : Enumerable(pTitle) { } From 4ce0a804cbeeca168592b40547d7ae3940f4cd54 Mon Sep 17 00:00:00 2001 From: Coronia <2217891145@qq.com> Date: Fri, 28 Nov 2025 13:13:05 +0800 Subject: [PATCH 08/10] fix and add check for Temporal --- docs/New-or-Enhanced-Logics.md | 2 ++ src/Ext/SWType/Ares/NewSWType.cpp | 23 ++++++++++++++----- src/Ext/SWType/Hooks.cpp | 26 +++++++++++++++------ src/Ext/SWType/SWHelpers.cpp | 36 +++++++++++++++++++++--------- src/New/Type/SWSignalTypeClass.cpp | 2 ++ src/New/Type/SWSignalTypeClass.h | 1 + 6 files changed, 67 insertions(+), 23 deletions(-) diff --git a/docs/New-or-Enhanced-Logics.md b/docs/New-or-Enhanced-Logics.md index faf59e1e28..f77140f14c 100644 --- a/docs/New-or-Enhanced-Logics.md +++ b/docs/New-or-Enhanced-Logics.md @@ -188,6 +188,7 @@ SuppressReflectDamage.Groups= ; comma-separated list of str - `Affects` determines the affected house of the Inhibitor and Designator effects. Default to `enemies` if it's used as an Inhibitor, and `owner` if it's Designator. - `Powered` determines whether or not the effect is rendered inactive if the object it is attached to is deactivated (`PoweredUnit` or affected by EMP) or on low power. - Notice that it's different from Ares' behavior, which always checks if the building is on low power for Inhibitor, and doesn't check EMP. +- `StopInTemporal` determines whether or not the effect is rendered inactive if the object is being warped out by a `Temporal=yes` warhead. - `SW.InhibiteTypes` determines the Super Weapon Signals that'll act as an Inhibitor for this super weapon, which prevent it to be launched in this area. - `SW.DesignateTypes` determines the Super Weapon Signals that'll act as an Designator for this super weapon, which only allow it to be launched in this area. - `InhibiteTypes` and `DesignateTypes` determine the Super Weapon Signals a techno owned, which make it an Inhibitor/Designator to super weapons with corresponding `SW.Inhibite/DesignateTypes`. @@ -202,6 +203,7 @@ In `rulesmd.ini` Range= ; integer, default to [SOMETECHNO] -> Sight Affects= ; List of Affected House Enumeration (none|owner/self|allies/ally|team|enemies/enemy|all), default to enemies for Inhibitor and owner for Designator Powered=false ; boolean +StopInTemporal=false ; boolean [SOMESW] ; SuperWeaponType SW.InhibiteTypes= ; List of SuperWeaponSignalType diff --git a/src/Ext/SWType/Ares/NewSWType.cpp b/src/Ext/SWType/Ares/NewSWType.cpp index 6e33e86ee3..aba81b1ed7 100644 --- a/src/Ext/SWType/Ares/NewSWType.cpp +++ b/src/Ext/SWType/Ares/NewSWType.cpp @@ -44,10 +44,13 @@ TargetingData& AresNewSWType::GetTargetingData(TargetingData& data, SuperWeaponT if (!pTechno->IsAlive || !pTechno->Health || pTechno->InLimbo) continue; - // get the designator's center - const auto center = pTechno->GetCoords(); - const auto cell = CellClass::Coord2Cell(center); - bool inactive = pTechno->Deactivated || pTechno->IsUnderEMP(); + const bool deactivated = pTechno->Deactivated; + + if (deactivated && !hasDesignateType && !hasInhibiteType) + continue; + + const bool isTemporal = pTechno->TemporalTargetingMe || pTechno->IsBeingWarpedOut(); + bool inactive = deactivated || pTechno->IsUnderEMP(); bool buildingOnline = true; if (const auto pBuilding = abstract_cast(pTechno)) @@ -56,6 +59,8 @@ TargetingData& AresNewSWType::GetTargetingData(TargetingData& data, SuperWeaponT inactive |= !buildingOnline; } + const auto center = pTechno->GetCoords(); + const auto cell = CellClass::Coord2Cell(center); const auto pTechnoType = pTechno->GetTechnoType(); const auto pTechnoTypeExt = TechnoTypeExt::ExtMap.Find(pTechnoType); @@ -66,6 +71,9 @@ TargetingData& AresNewSWType::GetTargetingData(TargetingData& data, SuperWeaponT if (inactive && signal->Powered) continue; + if (isTemporal && signal->StopInTemporal) + continue; + if (std::ranges::find(pTechnoTypeExt->DesignateTypes, signal) == pTechnoTypeExt->DesignateTypes.cend() || !EnumFunctions::CanTargetHouse(signal->Affects.Get(AffectedHouse::Owner), pOwner, pTechno->Owner)) continue; @@ -77,7 +85,7 @@ TargetingData& AresNewSWType::GetTargetingData(TargetingData& data, SuperWeaponT } } - if (hasDesignator + if (hasDesignator && !deactivated && EnumFunctions::CanTargetHouse(pExt->SW_Designators_Houses, pOwner, pTechno->Owner) && (pExt->SW_AnyDesignator || pExt->SW_Designators.Contains(pTechnoType))) { @@ -94,6 +102,9 @@ TargetingData& AresNewSWType::GetTargetingData(TargetingData& data, SuperWeaponT if (inactive && signal->Powered) continue; + if (isTemporal && signal->StopInTemporal) + continue; + if (std::ranges::find(pTechnoTypeExt->InhibiteTypes, signal) == pTechnoTypeExt->InhibiteTypes.cend() || !EnumFunctions::CanTargetHouse(signal->Affects.Get(AffectedHouse::Enemies), pOwner, pTechno->Owner)) continue; @@ -105,7 +116,7 @@ TargetingData& AresNewSWType::GetTargetingData(TargetingData& data, SuperWeaponT } } - if (hasInhibitor && buildingOnline + if (hasInhibitor && buildingOnline && !deactivated && EnumFunctions::CanTargetHouse(pExt->SW_Inhibitors_Houses, pOwner, pTechno->Owner) && (pExt->SW_AnyInhibitor || pExt->SW_Inhibitors.Contains(pTechnoType))) { diff --git a/src/Ext/SWType/Hooks.cpp b/src/Ext/SWType/Hooks.cpp index b473de9ec8..e33a5b0dcd 100644 --- a/src/Ext/SWType/Hooks.cpp +++ b/src/Ext/SWType/Hooks.cpp @@ -76,11 +76,13 @@ DEFINE_HOOK(0x6DBE74, Tactical_SuperLinesCircles_ShowDesignatorRange, 0x7) if (!pTechno->IsAlive || !pTechno->Health || pTechno->InLimbo) continue; - CoordStruct coords = pTechno->GetCenterCoords(); - coords.Z = MapClass::Instance.GetCellFloorHeight(coords); - const auto pOwner = pTechno->Owner; - const auto color = pOwner->Color; - bool inactive = pTechno->Deactivated || pTechno->IsUnderEMP(); + const bool deactivated = pTechno->Deactivated; + + if (deactivated && !hasDesignateType && !hasInhibiteType) + continue; + + const bool isTemporal = pTechno->TemporalTargetingMe || pTechno->IsBeingWarpedOut(); + bool inactive = deactivated || pTechno->IsUnderEMP(); bool buildingOnline = true; if (const auto pBuilding = abstract_cast(pTechno)) @@ -89,6 +91,10 @@ DEFINE_HOOK(0x6DBE74, Tactical_SuperLinesCircles_ShowDesignatorRange, 0x7) inactive |= !buildingOnline; } + CoordStruct coords = pTechno->GetCenterCoords(); + coords.Z = MapClass::Instance.GetCellFloorHeight(coords); + const auto pOwner = pTechno->Owner; + const auto color = pOwner->Color; const auto pTechnoType = pTechno->GetTechnoType(); const auto pTechnoTypeExt = TechnoTypeExt::ExtMap.Find(pTechnoType); @@ -99,6 +105,9 @@ DEFINE_HOOK(0x6DBE74, Tactical_SuperLinesCircles_ShowDesignatorRange, 0x7) if (inactive && signal->Powered) continue; + if (isTemporal && signal->StopInTemporal) + continue; + if (std::ranges::find(pTechnoTypeExt->DesignateTypes, signal) == pTechnoTypeExt->DesignateTypes.cend() || !EnumFunctions::CanTargetHouse(signal->Affects.Get(AffectedHouse::Owner), pOwner, pTechno->Owner)) continue; @@ -110,7 +119,7 @@ DEFINE_HOOK(0x6DBE74, Tactical_SuperLinesCircles_ShowDesignatorRange, 0x7) } } - if (hasDesignator) + if (hasDesignator && !deactivated) { if (EnumFunctions::CanTargetHouse(pSWExt->SW_Designators_Houses, HouseClass::CurrentPlayer, pOwner) && pSWExt->SW_Designators.Contains(pTechnoType)) { @@ -128,6 +137,9 @@ DEFINE_HOOK(0x6DBE74, Tactical_SuperLinesCircles_ShowDesignatorRange, 0x7) if (inactive && signal->Powered) continue; + if (isTemporal && signal->StopInTemporal) + continue; + if (std::ranges::find(pTechnoTypeExt->InhibiteTypes, signal) == pTechnoTypeExt->InhibiteTypes.cend() || !EnumFunctions::CanTargetHouse(signal->Affects.Get(AffectedHouse::Enemies), pOwner, pTechno->Owner)) continue; @@ -139,7 +151,7 @@ DEFINE_HOOK(0x6DBE74, Tactical_SuperLinesCircles_ShowDesignatorRange, 0x7) } } - if (hasInhibitor && buildingOnline) + if (hasInhibitor && buildingOnline && !deactivated) { if (EnumFunctions::CanTargetHouse(pSWExt->SW_Inhibitors_Houses, HouseClass::CurrentPlayer, pOwner) && pSWExt->SW_Inhibitors.Contains(pTechnoType)) { diff --git a/src/Ext/SWType/SWHelpers.cpp b/src/Ext/SWType/SWHelpers.cpp index e105f0fb85..a65de15761 100644 --- a/src/Ext/SWType/SWHelpers.cpp +++ b/src/Ext/SWType/SWHelpers.cpp @@ -66,14 +66,19 @@ bool SWTypeExt::ExtData::IsInhibitorEligible(HouseClass* pOwner, const CellStruc if (!pTechno->IsAlive || !pTechno->Health || pTechno->InLimbo) return false; - // get the inhibitor's center - const auto center = pTechno->GetCenterCoords(); - const double distanceSqr = coords.DistanceFromSquared(CellClass::Coord2Cell(center)); - bool inactive = pTechno->Deactivated || pTechno->IsUnderEMP(); + const bool deactivated = pTechno->Deactivated; + + if (deactivated && this->SW_InhibiteTypes.empty()) + return false; + + const bool isTemporal = pTechno->TemporalTargetingMe || pTechno->IsBeingWarpedOut(); + bool inactive = deactivated || pTechno->IsUnderEMP(); if (const auto pBuilding = abstract_cast(pTechno)) inactive |= !pBuilding->IsPowerOnline(); + const auto center = pTechno->GetCenterCoords(); + const double distanceSqr = coords.DistanceFromSquared(CellClass::Coord2Cell(center)); const auto pTechnoType = pTechno->GetTechnoType(); const auto pTechnoTypeExt = TechnoTypeExt::ExtMap.Find(pTechnoType); @@ -82,6 +87,9 @@ bool SWTypeExt::ExtData::IsInhibitorEligible(HouseClass* pOwner, const CellStruc if (inactive && signal->Powered) continue; + if (isTemporal && signal->StopInTemporal) + continue; + if (std::ranges::find(pTechnoTypeExt->InhibiteTypes, signal) == pTechnoTypeExt->InhibiteTypes.cend() || !EnumFunctions::CanTargetHouse(signal->Affects.Get(AffectedHouse::Enemies), pOwner, pTechno->Owner)) continue; @@ -92,7 +100,7 @@ bool SWTypeExt::ExtData::IsInhibitorEligible(HouseClass* pOwner, const CellStruc return true; } - if (EnumFunctions::CanTargetHouse(this->SW_Inhibitors_Houses, pOwner, pTechno->Owner) && (this->SW_AnyInhibitor || this->SW_Inhibitors.Contains(pTechnoType))) + if (!deactivated && EnumFunctions::CanTargetHouse(this->SW_Inhibitors_Houses, pOwner, pTechno->Owner) && (this->SW_AnyInhibitor || this->SW_Inhibitors.Contains(pTechnoType))) { const int range = pTechnoTypeExt->InhibitorRange.Get(pTechnoType->Sight); @@ -132,14 +140,19 @@ bool SWTypeExt::ExtData::IsDesignatorEligible(HouseClass* pOwner, const CellStru if (!pTechno->IsAlive || !pTechno->Health || pTechno->InLimbo) return false; - // get the designator's center - const auto center = pTechno->GetCenterCoords(); - const double distanceSqr = coords.DistanceFromSquared(CellClass::Coord2Cell(center)); - bool inactive = pTechno->Deactivated || pTechno->IsUnderEMP(); + const bool deactivated = pTechno->Deactivated; + + if (deactivated && this->SW_DesignateTypes.empty()) + return false; + + const bool isTemporal = pTechno->TemporalTargetingMe || pTechno->IsBeingWarpedOut(); + bool inactive = deactivated || pTechno->IsUnderEMP(); if (const auto pBuilding = abstract_cast(pTechno)) inactive |= !pBuilding->IsPowerOnline(); + const auto center = pTechno->GetCenterCoords(); + const double distanceSqr = coords.DistanceFromSquared(CellClass::Coord2Cell(center)); const auto pTechnoType = pTechno->GetTechnoType(); const auto pTechnoTypeExt = TechnoTypeExt::ExtMap.Find(pTechnoType); @@ -148,6 +161,9 @@ bool SWTypeExt::ExtData::IsDesignatorEligible(HouseClass* pOwner, const CellStru if (inactive && signal->Powered) continue; + if (isTemporal && signal->StopInTemporal) + continue; + if (std::ranges::find(pTechnoTypeExt->DesignateTypes, signal) == pTechnoTypeExt->DesignateTypes.cend() || !EnumFunctions::CanTargetHouse(signal->Affects.Get(AffectedHouse::Owner), pOwner, pTechno->Owner)) continue; @@ -158,7 +174,7 @@ bool SWTypeExt::ExtData::IsDesignatorEligible(HouseClass* pOwner, const CellStru return true; } - if (EnumFunctions::CanTargetHouse(this->SW_Designators_Houses, pOwner, pTechno->Owner) && (this->SW_AnyDesignator || this->SW_Designators.Contains(pTechnoType))) + if (!deactivated && EnumFunctions::CanTargetHouse(this->SW_Designators_Houses, pOwner, pTechno->Owner) && (this->SW_AnyDesignator || this->SW_Designators.Contains(pTechnoType))) { const int range = pTechnoTypeExt->DesignatorRange.Get(pTechnoType->Sight); diff --git a/src/New/Type/SWSignalTypeClass.cpp b/src/New/Type/SWSignalTypeClass.cpp index 9a982f7988..99bdde901c 100644 --- a/src/New/Type/SWSignalTypeClass.cpp +++ b/src/New/Type/SWSignalTypeClass.cpp @@ -18,6 +18,7 @@ void SWSignalTypeClass::LoadFromINI(CCINIClass* pINI) this->Range.Read(exINI, pSection, "Range"); this->Affects.Read(exINI, pSection, "Affects"); this->Powered.Read(exINI, pSection, "Powered"); + this->StopInTemporal.Read(exINI, pSection, "StopInTemporal"); } // ============================= @@ -30,6 +31,7 @@ void SWSignalTypeClass::Serialize(T& stm) .Process(this->Range) .Process(this->Affects) .Process(this->Powered) + .Process(this->StopInTemporal) ; } diff --git a/src/New/Type/SWSignalTypeClass.h b/src/New/Type/SWSignalTypeClass.h index 7aa4469444..ae45abb4ab 100644 --- a/src/New/Type/SWSignalTypeClass.h +++ b/src/New/Type/SWSignalTypeClass.h @@ -9,6 +9,7 @@ class SWSignalTypeClass final : public Enumerable Nullable Range {}; Nullable Affects {}; Valueable Powered { false }; + Valueable StopInTemporal { false }; SWSignalTypeClass(const char* pTitle = NONE_STR) : Enumerable(pTitle) { } From fc8410c288a786652f9b43afd63b2a059fb955fa Mon Sep 17 00:00:00 2001 From: Coronia <2217891145@qq.com> Date: Fri, 28 Nov 2025 15:19:09 +0800 Subject: [PATCH 09/10] add signal to AE and fix to typo and alliance settings --- docs/New-or-Enhanced-Logics.md | 12 +++-- src/Ext/SWType/Ares/NewSWType.cpp | 71 ++++++++++++++++++------- src/Ext/SWType/Body.cpp | 4 +- src/Ext/SWType/Body.h | 4 +- src/Ext/SWType/Hooks.cpp | 62 +++++++++++++++++----- src/Ext/SWType/SWHelpers.cpp | 72 ++++++++++++++++++++------ src/Ext/Script/Mission.Attack.cpp | 4 +- src/Ext/Techno/Body.Update.cpp | 6 +++ src/Ext/TechnoType/Body.cpp | 4 +- src/Ext/TechnoType/Body.h | 4 +- src/New/Entity/AttachEffectClass.h | 4 ++ src/New/Type/AttachEffectTypeClass.cpp | 4 ++ src/New/Type/AttachEffectTypeClass.h | 5 ++ 13 files changed, 193 insertions(+), 63 deletions(-) diff --git a/docs/New-or-Enhanced-Logics.md b/docs/New-or-Enhanced-Logics.md index f77140f14c..60b5be0889 100644 --- a/docs/New-or-Enhanced-Logics.md +++ b/docs/New-or-Enhanced-Logics.md @@ -55,6 +55,8 @@ This page describes all the engine features that are either new and introduced b - `DisableWeapons` can be used to disable ability to fire any and all weapons. - On TechnoTypes with `OpenTopped=true`, `OpenTopped.CheckTransportDisableWeapons` can be set to true to make passengers not be able to fire out if transport's weapons are disabled by `DisableWeapons`. - `Unkillable` can be used to prevent the techno from being killed by taken damage (minimum health will be 1). + - `LaserTrail.Type` can be used to grant a [laser trail](#laser-trails) for the attached object. + - `InhibitType` and `DesignateType` can be used to grant a [super weapon signal](#custom-super-weapon-signal-type) which can act as Inhibitor and Designator for the attached object. - It is possible to set groups for attach effect types by defining strings in `Groups`. - Groups can be used instead of types for removing effects and weapon filters. @@ -143,6 +145,8 @@ ReflectDamage.UseInvokerAsOwner=false ; boolean DisableWeapons=false ; boolean Unkillable=false ; boolean LaserTrail.Type= ; LaserTrailType +InhibitType= ; SuperWeaponSignalType +DesignateType= ; SuperWeaponSignalType Groups= ; comma-separated list of strings (group IDs) [SOMETECHNO] ; TechnoType @@ -189,9 +193,9 @@ SuppressReflectDamage.Groups= ; comma-separated list of str - `Powered` determines whether or not the effect is rendered inactive if the object it is attached to is deactivated (`PoweredUnit` or affected by EMP) or on low power. - Notice that it's different from Ares' behavior, which always checks if the building is on low power for Inhibitor, and doesn't check EMP. - `StopInTemporal` determines whether or not the effect is rendered inactive if the object is being warped out by a `Temporal=yes` warhead. -- `SW.InhibiteTypes` determines the Super Weapon Signals that'll act as an Inhibitor for this super weapon, which prevent it to be launched in this area. +- `SW.InhibitTypes` determines the Super Weapon Signals that'll act as an Inhibitor for this super weapon, which prevent it to be launched in this area. - `SW.DesignateTypes` determines the Super Weapon Signals that'll act as an Designator for this super weapon, which only allow it to be launched in this area. -- `InhibiteTypes` and `DesignateTypes` determine the Super Weapon Signals a techno owned, which make it an Inhibitor/Designator to super weapons with corresponding `SW.Inhibite/DesignateTypes`. +- `InhibitTypes` and `DesignateTypes` determine the Super Weapon Signals a techno owned, which make it an Inhibitor/Designator to super weapons with corresponding `SW.Inhibit/DesignateTypes`. - This allow a techno to own multiple Inhibitor and Designator effects towards different super weapons, rather than limited to one for all super weapons. In `rulesmd.ini` @@ -206,11 +210,11 @@ Powered=false ; boolean StopInTemporal=false ; boolean [SOMESW] ; SuperWeaponType -SW.InhibiteTypes= ; List of SuperWeaponSignalType +SW.InhibitTypes= ; List of SuperWeaponSignalType SW.DesignateTypes= ; List of SuperWeaponSignalType [SOMETECHNO] ; TechnoType -InhibiteTypes= ; List of SuperWeaponSignalType +InhibitTypes= ; List of SuperWeaponSignalType DesignateTypes= ; List of SuperWeaponSignalType ``` diff --git a/src/Ext/SWType/Ares/NewSWType.cpp b/src/Ext/SWType/Ares/NewSWType.cpp index aba81b1ed7..1458916081 100644 --- a/src/Ext/SWType/Ares/NewSWType.cpp +++ b/src/Ext/SWType/Ares/NewSWType.cpp @@ -31,10 +31,10 @@ TargetingData& AresNewSWType::GetTargetingData(TargetingData& data, SuperWeaponT const auto pExt = SWTypeExt::ExtMap.Find(*pExt_Ares); const bool hasDesignateType = !pExt->SW_DesignateTypes.empty(); const bool hasDesignator = !pExt->SW_Designators.empty() || pExt->SW_AnyDesignator; - const bool hasInhibiteType = !pExt->SW_InhibiteTypes.empty(); + const bool hasInhibitType = !pExt->SW_InhibitTypes.empty(); const bool hasInhibitor = !pExt->SW_Inhibitors.empty() || pExt->SW_AnyInhibitor; - if (hasDesignateType || hasDesignator || hasInhibiteType || hasInhibitor) + if (hasDesignateType || hasDesignator || hasInhibitType || hasInhibitor) { if (hasDesignateType || hasDesignator) data.NeedsDesignator = true; @@ -46,7 +46,7 @@ TargetingData& AresNewSWType::GetTargetingData(TargetingData& data, SuperWeaponT const bool deactivated = pTechno->Deactivated; - if (deactivated && !hasDesignateType && !hasInhibiteType) + if (deactivated && !hasDesignateType && !hasInhibitType) continue; const bool isTemporal = pTechno->TemporalTargetingMe || pTechno->IsBeingWarpedOut(); @@ -60,9 +60,12 @@ TargetingData& AresNewSWType::GetTargetingData(TargetingData& data, SuperWeaponT } const auto center = pTechno->GetCoords(); - const auto cell = CellClass::Coord2Cell(center); - const auto pTechnoType = pTechno->GetTechnoType(); - const auto pTechnoTypeExt = TechnoTypeExt::ExtMap.Find(pTechnoType); + const auto cell = CellClass::Coord2Cell(center); + const auto pTechnoExt = TechnoExt::ExtMap.Find(pTechno); + const auto pTechnoTypeExt = pTechnoExt->TypeExtData; + const auto pTechnoType = pTechnoTypeExt->OwnerObject(); + const auto pTechnoOwner = pTechno->Owner; + const int sight = pTechnoType->Sight; if (hasDesignateType) { @@ -74,11 +77,27 @@ TargetingData& AresNewSWType::GetTargetingData(TargetingData& data, SuperWeaponT if (isTemporal && signal->StopInTemporal) continue; - if (std::ranges::find(pTechnoTypeExt->DesignateTypes, signal) == pTechnoTypeExt->DesignateTypes.cend() - || !EnumFunctions::CanTargetHouse(signal->Affects.Get(AffectedHouse::Owner), pOwner, pTechno->Owner)) + if (!EnumFunctions::CanTargetHouse(signal->Affects.Get(AffectedHouse::Owner), pOwner, pTechnoOwner)) continue; - const int range = signal->Range.Get(pTechnoType->Sight); + bool findSignal = std::ranges::find(pTechnoTypeExt->DesignateTypes, signal) == pTechnoTypeExt->DesignateTypes.cend(); + + if (!findSignal && pTechnoExt->AE.HasDesignator) + { + for (const auto& attachEffect : pTechnoExt->AttachedEffects) + { + if (signal == attachEffect->GetType()->DesignateType) + { + findSignal = true; + break; + } + } + } + + if (!findSignal) + continue; + + const int range = signal->Range.Get(sight); if (range > 0) data.Designators.emplace_back(range * range, cell); @@ -86,18 +105,18 @@ TargetingData& AresNewSWType::GetTargetingData(TargetingData& data, SuperWeaponT } if (hasDesignator && !deactivated - && EnumFunctions::CanTargetHouse(pExt->SW_Designators_Houses, pOwner, pTechno->Owner) + && EnumFunctions::CanTargetHouse(pExt->SW_Designators_Houses, pOwner, pTechnoOwner) && (pExt->SW_AnyDesignator || pExt->SW_Designators.Contains(pTechnoType))) { - const int range = pTechnoTypeExt->DesignatorRange.Get(pTechnoType->Sight); + const int range = pTechnoTypeExt->DesignatorRange.Get(sight); if (range > 0) data.Designators.emplace_back(range * range, cell); } - if (hasInhibiteType) + if (hasInhibitType) { - for (const auto signal : pExt->SW_InhibiteTypes) + for (const auto signal : pExt->SW_InhibitTypes) { if (inactive && signal->Powered) continue; @@ -105,11 +124,27 @@ TargetingData& AresNewSWType::GetTargetingData(TargetingData& data, SuperWeaponT if (isTemporal && signal->StopInTemporal) continue; - if (std::ranges::find(pTechnoTypeExt->InhibiteTypes, signal) == pTechnoTypeExt->InhibiteTypes.cend() - || !EnumFunctions::CanTargetHouse(signal->Affects.Get(AffectedHouse::Enemies), pOwner, pTechno->Owner)) + if (!EnumFunctions::CanTargetHouse(signal->Affects.Get(AffectedHouse::Enemies), pOwner, pTechnoOwner)) + continue; + + bool findSignal = std::ranges::find(pTechnoTypeExt->InhibitTypes, signal) == pTechnoTypeExt->InhibitTypes.cend(); + + if (!findSignal && pTechnoExt->AE.HasInhibitor) + { + for (const auto& attachEffect : pTechnoExt->AttachedEffects) + { + if (signal == attachEffect->GetType()->InhibitType) + { + findSignal = true; + break; + } + } + } + + if (!findSignal) continue; - const int range = signal->Range.Get(pTechnoType->Sight); + const int range = signal->Range.Get(sight); if (range > 0) data.Inhibitors.emplace_back(range * range, cell); @@ -117,10 +152,10 @@ TargetingData& AresNewSWType::GetTargetingData(TargetingData& data, SuperWeaponT } if (hasInhibitor && buildingOnline && !deactivated - && EnumFunctions::CanTargetHouse(pExt->SW_Inhibitors_Houses, pOwner, pTechno->Owner) + && EnumFunctions::CanTargetHouse(pExt->SW_Inhibitors_Houses, pOwner, pTechnoOwner) && (pExt->SW_AnyInhibitor || pExt->SW_Inhibitors.Contains(pTechnoType))) { - const int range = pTechnoTypeExt->InhibitorRange.Get(pTechnoType->Sight); + const int range = pTechnoTypeExt->InhibitorRange.Get(sight); if (range > 0) data.Inhibitors.emplace_back(range * range, cell); diff --git a/src/Ext/SWType/Body.cpp b/src/Ext/SWType/Body.cpp index 27ea30da64..30f9fc16f4 100644 --- a/src/Ext/SWType/Body.cpp +++ b/src/Ext/SWType/Body.cpp @@ -48,7 +48,7 @@ void SWTypeExt::ExtData::Serialize(T& Stm) .Process(this->SW_MaxCount) .Process(this->SW_Shots) .Process(this->SW_DesignateTypes) - .Process(this->SW_InhibiteTypes) + .Process(this->SW_InhibitTypes) .Process(this->Message_CannotFire) .Process(this->Message_InsufficientFunds) .Process(this->Message_ColorScheme) @@ -138,7 +138,7 @@ void SWTypeExt::ExtData::LoadFromINIFile(CCINIClass* const pINI) this->SW_Shots.Read(exINI, pSection, "SW.Shots"); this->SW_DesignateTypes.Read(exINI, pSection, "SW.DesignateTypes"); - this->SW_InhibiteTypes.Read(exINI, pSection, "SW.InhibiteTypes"); + this->SW_InhibitTypes.Read(exINI, pSection, "SW.InhibitTypes"); this->Message_CannotFire.Read(exINI, pSection, "Message.CannotFire"); this->Message_InsufficientFunds.Read(exINI, pSection, "Message.InsufficientFunds"); diff --git a/src/Ext/SWType/Body.h b/src/Ext/SWType/Body.h index 83c1a21360..442b4ce603 100644 --- a/src/Ext/SWType/Body.h +++ b/src/Ext/SWType/Body.h @@ -54,7 +54,7 @@ class SWTypeExt Valueable SW_MaxCount; ValueableVector SW_DesignateTypes; - ValueableVector SW_InhibiteTypes; + ValueableVector SW_InhibitTypes; Valueable Message_CannotFire; Valueable Message_InsufficientFunds; @@ -145,7 +145,7 @@ class SWTypeExt , SW_PostDependent {} , SW_MaxCount { -1 } , SW_DesignateTypes {} - , SW_InhibiteTypes {} + , SW_InhibitTypes {} , SW_Shots { -1 } , Message_CannotFire {} , Message_InsufficientFunds {} diff --git a/src/Ext/SWType/Hooks.cpp b/src/Ext/SWType/Hooks.cpp index e33a5b0dcd..7666c1a9ff 100644 --- a/src/Ext/SWType/Hooks.cpp +++ b/src/Ext/SWType/Hooks.cpp @@ -68,7 +68,7 @@ DEFINE_HOOK(0x6DBE74, Tactical_SuperLinesCircles_ShowDesignatorRange, 0x7) const bool hasDesignateType = !pSWExt->SW_DesignateTypes.empty(); const bool hasDesignator = !pSWExt->SW_Designators.empty(); - const bool hasInhibiteType = !pSWExt->SW_InhibiteTypes.empty(); + const bool hasInhibitType = !pSWExt->SW_InhibitTypes.empty(); const bool hasInhibitor = !pSWExt->SW_Inhibitors.empty(); for (const auto pTechno : TechnoClass::Array) @@ -78,7 +78,7 @@ DEFINE_HOOK(0x6DBE74, Tactical_SuperLinesCircles_ShowDesignatorRange, 0x7) const bool deactivated = pTechno->Deactivated; - if (deactivated && !hasDesignateType && !hasInhibiteType) + if (deactivated && !hasDesignateType && !hasInhibitType) continue; const bool isTemporal = pTechno->TemporalTargetingMe || pTechno->IsBeingWarpedOut(); @@ -95,8 +95,10 @@ DEFINE_HOOK(0x6DBE74, Tactical_SuperLinesCircles_ShowDesignatorRange, 0x7) coords.Z = MapClass::Instance.GetCellFloorHeight(coords); const auto pOwner = pTechno->Owner; const auto color = pOwner->Color; - const auto pTechnoType = pTechno->GetTechnoType(); - const auto pTechnoTypeExt = TechnoTypeExt::ExtMap.Find(pTechnoType); + const auto pTechnoExt = TechnoExt::ExtMap.Find(pTechno); + const auto pTechnoTypeExt = pTechnoExt->TypeExtData; + const auto pTechnoType = pTechnoTypeExt->OwnerObject(); + const int sight = pTechnoType->Sight; if (hasDesignateType) { @@ -108,11 +110,27 @@ DEFINE_HOOK(0x6DBE74, Tactical_SuperLinesCircles_ShowDesignatorRange, 0x7) if (isTemporal && signal->StopInTemporal) continue; - if (std::ranges::find(pTechnoTypeExt->DesignateTypes, signal) == pTechnoTypeExt->DesignateTypes.cend() - || !EnumFunctions::CanTargetHouse(signal->Affects.Get(AffectedHouse::Owner), pOwner, pTechno->Owner)) + if (!EnumFunctions::CanTargetHouse(signal->Affects.Get(AffectedHouse::Owner), HouseClass::CurrentPlayer, pOwner)) continue; - const int radius = signal->Range.Get(pTechnoType->Sight); + bool findSignal = std::ranges::find(pTechnoTypeExt->DesignateTypes, signal) == pTechnoTypeExt->DesignateTypes.cend(); + + if (!findSignal && pTechnoExt->AE.HasDesignator) + { + for (const auto& attachEffect : pTechnoExt->AttachedEffects) + { + if (signal == attachEffect->GetType()->DesignateType) + { + findSignal = true; + break; + } + } + } + + if (!findSignal) + continue; + + const int radius = signal->Range.Get(sight); if (radius > 0) Game::DrawRadialIndicator(false, true, coords, color, static_cast(radius), false, true); @@ -123,16 +141,16 @@ DEFINE_HOOK(0x6DBE74, Tactical_SuperLinesCircles_ShowDesignatorRange, 0x7) { if (EnumFunctions::CanTargetHouse(pSWExt->SW_Designators_Houses, HouseClass::CurrentPlayer, pOwner) && pSWExt->SW_Designators.Contains(pTechnoType)) { - const int radius = pTechnoTypeExt->DesignatorRange.Get(pTechnoType->Sight); + const int radius = pTechnoTypeExt->DesignatorRange.Get(sight); if (radius > 0) Game::DrawRadialIndicator(false, true, coords, color, static_cast(radius), false, true); } } - if (hasInhibiteType) + if (hasInhibitType) { - for (const auto signal : pSWExt->SW_InhibiteTypes) + for (const auto signal : pSWExt->SW_InhibitTypes) { if (inactive && signal->Powered) continue; @@ -140,11 +158,27 @@ DEFINE_HOOK(0x6DBE74, Tactical_SuperLinesCircles_ShowDesignatorRange, 0x7) if (isTemporal && signal->StopInTemporal) continue; - if (std::ranges::find(pTechnoTypeExt->InhibiteTypes, signal) == pTechnoTypeExt->InhibiteTypes.cend() - || !EnumFunctions::CanTargetHouse(signal->Affects.Get(AffectedHouse::Enemies), pOwner, pTechno->Owner)) + if (!EnumFunctions::CanTargetHouse(signal->Affects.Get(AffectedHouse::Enemies), HouseClass::CurrentPlayer, pOwner)) + continue; + + bool findSignal = std::ranges::find(pTechnoTypeExt->InhibitTypes, signal) == pTechnoTypeExt->InhibitTypes.cend(); + + if (!findSignal && pTechnoExt->AE.HasInhibitor) + { + for (const auto& attachEffect : pTechnoExt->AttachedEffects) + { + if (signal == attachEffect->GetType()->InhibitType) + { + findSignal = true; + break; + } + } + } + + if (!findSignal) continue; - const int radius = signal->Range.Get(pTechnoType->Sight); + const int radius = signal->Range.Get(sight); if (radius > 0) Game::DrawRadialIndicator(false, true, coords, color, static_cast(radius), false, true); @@ -155,7 +189,7 @@ DEFINE_HOOK(0x6DBE74, Tactical_SuperLinesCircles_ShowDesignatorRange, 0x7) { if (EnumFunctions::CanTargetHouse(pSWExt->SW_Inhibitors_Houses, HouseClass::CurrentPlayer, pOwner) && pSWExt->SW_Inhibitors.Contains(pTechnoType)) { - const int radius = pTechnoTypeExt->InhibitorRange.Get(pTechnoType->Sight); + const int radius = pTechnoTypeExt->InhibitorRange.Get(sight); if (radius > 0) Game::DrawRadialIndicator(false, true, coords, color, static_cast(radius), false, true); diff --git a/src/Ext/SWType/SWHelpers.cpp b/src/Ext/SWType/SWHelpers.cpp index a65de15761..15ef97cbb1 100644 --- a/src/Ext/SWType/SWHelpers.cpp +++ b/src/Ext/SWType/SWHelpers.cpp @@ -68,7 +68,7 @@ bool SWTypeExt::ExtData::IsInhibitorEligible(HouseClass* pOwner, const CellStruc const bool deactivated = pTechno->Deactivated; - if (deactivated && this->SW_InhibiteTypes.empty()) + if (deactivated && this->SW_InhibitTypes.empty()) return false; const bool isTemporal = pTechno->TemporalTargetingMe || pTechno->IsBeingWarpedOut(); @@ -79,10 +79,13 @@ bool SWTypeExt::ExtData::IsInhibitorEligible(HouseClass* pOwner, const CellStruc const auto center = pTechno->GetCenterCoords(); const double distanceSqr = coords.DistanceFromSquared(CellClass::Coord2Cell(center)); - const auto pTechnoType = pTechno->GetTechnoType(); - const auto pTechnoTypeExt = TechnoTypeExt::ExtMap.Find(pTechnoType); + const auto pTechnoExt = TechnoExt::ExtMap.Find(pTechno); + const auto pTechnoTypeExt = pTechnoExt->TypeExtData; + const auto pTechnoType = pTechnoTypeExt->OwnerObject(); + const auto pTechnoOwner = pTechno->Owner; + const int sight = pTechnoType->Sight; - for (const auto signal : this->SW_InhibiteTypes) + for (const auto signal : this->SW_InhibitTypes) { if (inactive && signal->Powered) continue; @@ -90,19 +93,35 @@ bool SWTypeExt::ExtData::IsInhibitorEligible(HouseClass* pOwner, const CellStruc if (isTemporal && signal->StopInTemporal) continue; - if (std::ranges::find(pTechnoTypeExt->InhibiteTypes, signal) == pTechnoTypeExt->InhibiteTypes.cend() - || !EnumFunctions::CanTargetHouse(signal->Affects.Get(AffectedHouse::Enemies), pOwner, pTechno->Owner)) + if (!EnumFunctions::CanTargetHouse(signal->Affects.Get(AffectedHouse::Enemies), pOwner, pTechnoOwner)) continue; - const int range = signal->Range.Get(pTechnoType->Sight); + bool findSignal = std::ranges::find(pTechnoTypeExt->InhibitTypes, signal) == pTechnoTypeExt->InhibitTypes.cend(); + + if (!findSignal && pTechnoExt->AE.HasInhibitor) + { + for (const auto& attachEffect : pTechnoExt->AttachedEffects) + { + if (signal == attachEffect->GetType()->InhibitType) + { + findSignal = true; + break; + } + } + } + + if (!findSignal) + continue; + + const int range = signal->Range.Get(sight); if (distanceSqr <= range * range) return true; } - if (!deactivated && EnumFunctions::CanTargetHouse(this->SW_Inhibitors_Houses, pOwner, pTechno->Owner) && (this->SW_AnyInhibitor || this->SW_Inhibitors.Contains(pTechnoType))) + if (EnumFunctions::CanTargetHouse(this->SW_Inhibitors_Houses, pOwner, pTechnoOwner) && (this->SW_AnyInhibitor || this->SW_Inhibitors.Contains(pTechnoType))) { - const int range = pTechnoTypeExt->InhibitorRange.Get(pTechnoType->Sight); + const int range = pTechnoTypeExt->InhibitorRange.Get(sight); if (distanceSqr <= range * range) return true; @@ -114,7 +133,7 @@ bool SWTypeExt::ExtData::IsInhibitorEligible(HouseClass* pOwner, const CellStruc bool SWTypeExt::ExtData::HasInhibitor(HouseClass* pOwner, const CellStruct& coords) const { // does not allow inhibitors - if (this->SW_InhibiteTypes.empty() && this->SW_Inhibitors.empty() && !this->SW_AnyInhibitor) + if (this->SW_InhibitTypes.empty() && this->SW_Inhibitors.empty() && !this->SW_AnyInhibitor) return false; // a single inhibitor in range suffices @@ -153,8 +172,11 @@ bool SWTypeExt::ExtData::IsDesignatorEligible(HouseClass* pOwner, const CellStru const auto center = pTechno->GetCenterCoords(); const double distanceSqr = coords.DistanceFromSquared(CellClass::Coord2Cell(center)); - const auto pTechnoType = pTechno->GetTechnoType(); - const auto pTechnoTypeExt = TechnoTypeExt::ExtMap.Find(pTechnoType); + const auto pTechnoExt = TechnoExt::ExtMap.Find(pTechno); + const auto pTechnoTypeExt = pTechnoExt->TypeExtData; + const auto pTechnoType = pTechnoTypeExt->OwnerObject(); + const auto pTechnoOwner = pTechno->Owner; + const int sight = pTechnoType->Sight; for (const auto signal : this->SW_DesignateTypes) { @@ -164,19 +186,35 @@ bool SWTypeExt::ExtData::IsDesignatorEligible(HouseClass* pOwner, const CellStru if (isTemporal && signal->StopInTemporal) continue; - if (std::ranges::find(pTechnoTypeExt->DesignateTypes, signal) == pTechnoTypeExt->DesignateTypes.cend() - || !EnumFunctions::CanTargetHouse(signal->Affects.Get(AffectedHouse::Owner), pOwner, pTechno->Owner)) + if (!EnumFunctions::CanTargetHouse(signal->Affects.Get(AffectedHouse::Owner), pOwner, pTechnoOwner)) + continue; + + bool findSignal = std::ranges::find(pTechnoTypeExt->DesignateTypes, signal) == pTechnoTypeExt->DesignateTypes.cend(); + + if (!findSignal && pTechnoExt->AE.HasDesignator) + { + for (const auto& attachEffect : pTechnoExt->AttachedEffects) + { + if (signal == attachEffect->GetType()->DesignateType) + { + findSignal = true; + break; + } + } + } + + if (!findSignal) continue; - const int range = signal->Range.Get(pTechnoType->Sight); + const int range = signal->Range.Get(sight); if (distanceSqr <= range * range) return true; } - if (!deactivated && EnumFunctions::CanTargetHouse(this->SW_Designators_Houses, pOwner, pTechno->Owner) && (this->SW_AnyDesignator || this->SW_Designators.Contains(pTechnoType))) + if (EnumFunctions::CanTargetHouse(this->SW_Designators_Houses, pOwner, pTechnoOwner) && (this->SW_AnyDesignator || this->SW_Designators.Contains(pTechnoType))) { - const int range = pTechnoTypeExt->DesignatorRange.Get(pTechnoType->Sight); + const int range = pTechnoTypeExt->DesignatorRange.Get(sight); if (distanceSqr <= range * range) return true; diff --git a/src/Ext/Script/Mission.Attack.cpp b/src/Ext/Script/Mission.Attack.cpp index 44919da709..f642a13211 100644 --- a/src/Ext/Script/Mission.Attack.cpp +++ b/src/Ext/Script/Mission.Attack.cpp @@ -977,7 +977,7 @@ bool ScriptExt::EvaluateObjectWithMask(TechnoClass* pTechno, int mask, int attac if (pTechnoTypeExt->RadarJamRadius > 0 || pTechnoTypeExt->InhibitorRange.isset() - || !pTechnoTypeExt->InhibiteTypes.empty()) + || !pTechnoTypeExt->InhibitTypes.empty()) { return true; } @@ -1255,7 +1255,7 @@ bool ScriptExt::EvaluateObjectWithMask(TechnoClass* pTechno, int mask, int attac { const auto pTechnoTypeExt = TechnoTypeExt::ExtMap.Find(pTechnoType); - if (pTechnoTypeExt->InhibitorRange.isset() || !pTechnoTypeExt->InhibiteTypes.empty()) + if (pTechnoTypeExt->InhibitorRange.isset() || !pTechnoTypeExt->InhibitTypes.empty()) return true; } diff --git a/src/Ext/Techno/Body.Update.cpp b/src/Ext/Techno/Body.Update.cpp index bf0b62ccaa..35960c777c 100644 --- a/src/Ext/Techno/Body.Update.cpp +++ b/src/Ext/Techno/Body.Update.cpp @@ -1999,6 +1999,8 @@ void TechnoExt::ExtData::RecalculateStatMultipliers() bool hasOnFireDiscardables = false; bool hasRestrictedArmorMultipliers = false; bool hasCritModifiers = false; + bool hasInibitor = false; + bool hasDesignator = false; for (const auto& attachEffect : this->AttachedEffects) { @@ -2024,6 +2026,8 @@ void TechnoExt::ExtData::RecalculateStatMultipliers() reflectsDamage |= type->ReflectDamage; hasOnFireDiscardables |= (type->DiscardOn & DiscardCondition::Firing) != DiscardCondition::None; hasCritModifiers |= (type->Crit_Multiplier != 1.0 || type->Crit_ExtraChance != 0.0); + hasInibitor |= type->InhibitType; + hasDesignator |= type->DesignateType; } pAE.FirepowerMultiplier = firepower; @@ -2040,6 +2044,8 @@ void TechnoExt::ExtData::RecalculateStatMultipliers() pAE.HasOnFireDiscardables = hasOnFireDiscardables; pAE.HasRestrictedArmorMultipliers = hasRestrictedArmorMultipliers; pAE.HasCritModifiers = hasCritModifiers; + pAE.HasInhibitor = hasInibitor; + pAE.HasDesignator = hasDesignator; if (forceDecloak && pThis->CloakState == CloakState::Cloaked) pThis->Uncloak(true); diff --git a/src/Ext/TechnoType/Body.cpp b/src/Ext/TechnoType/Body.cpp index 740ad2cdec..245e9c6529 100644 --- a/src/Ext/TechnoType/Body.cpp +++ b/src/Ext/TechnoType/Body.cpp @@ -948,7 +948,7 @@ void TechnoTypeExt::ExtData::LoadFromINIFile(CCINIClass* const pINI) this->Power.Read(exINI, pSection, "Power"); this->DesignateTypes.Read(exINI, pSection, "DesignateTypes"); - this->InhibiteTypes.Read(exINI, pSection, "InhibiteTypes"); + this->InhibitTypes.Read(exINI, pSection, "InhibitTypes"); this->AllowAirstrike.Read(exINI, pSection, "AllowAirstrike"); @@ -1592,7 +1592,7 @@ void TechnoTypeExt::ExtData::Serialize(T& Stm) .Process(this->Power) .Process(this->DesignateTypes) - .Process(this->InhibiteTypes) + .Process(this->InhibitTypes) .Process(this->AllowAirstrike) diff --git a/src/Ext/TechnoType/Body.h b/src/Ext/TechnoType/Body.h index 059a68bf91..2029d363d5 100644 --- a/src/Ext/TechnoType/Body.h +++ b/src/Ext/TechnoType/Body.h @@ -338,7 +338,7 @@ class TechnoTypeExt Valueable Power; ValueableVector DesignateTypes; - ValueableVector InhibiteTypes; + ValueableVector InhibitTypes; Nullable AllowAirstrike; @@ -751,7 +751,7 @@ class TechnoTypeExt , Power { } , DesignateTypes { } - , InhibiteTypes { } + , InhibitTypes { } , AllowAirstrike { } diff --git a/src/New/Entity/AttachEffectClass.h b/src/New/Entity/AttachEffectClass.h index ada71251bc..ef172c90d6 100644 --- a/src/New/Entity/AttachEffectClass.h +++ b/src/New/Entity/AttachEffectClass.h @@ -106,6 +106,8 @@ struct AttachEffectTechnoProperties bool HasOnFireDiscardables; bool HasRestrictedArmorMultipliers; bool HasCritModifiers; + bool HasInhibitor; + bool HasDesignator; AttachEffectTechnoProperties() : FirepowerMultiplier { 1.0 } @@ -122,5 +124,7 @@ struct AttachEffectTechnoProperties , HasOnFireDiscardables { false } , HasRestrictedArmorMultipliers { false } , HasCritModifiers { false } + , HasInhibitor { false } + , HasDesignator { false } { } }; diff --git a/src/New/Type/AttachEffectTypeClass.cpp b/src/New/Type/AttachEffectTypeClass.cpp index 47719b7268..b81793dc1f 100644 --- a/src/New/Type/AttachEffectTypeClass.cpp +++ b/src/New/Type/AttachEffectTypeClass.cpp @@ -167,6 +167,8 @@ void AttachEffectTypeClass::LoadFromINI(CCINIClass* pINI) this->DisableWeapons.Read(exINI, pSection, "DisableWeapons"); this->Unkillable.Read(exINI, pSection, "Unkillable"); this->LaserTrail_Type.Read(exINI, pSection, "LaserTrail.Type"); + this->InhibitType.Read(exINI, pSection, "InhibitType"); + this->DesignateType.Read(exINI, pSection, "DesignateType"); // Groups exINI.ParseStringList(this->Groups, pSection, "Groups"); @@ -233,6 +235,8 @@ void AttachEffectTypeClass::Serialize(T& Stm) .Process(this->DisableWeapons) .Process(this->Unkillable) .Process(this->LaserTrail_Type) + .Process(this->InhibitType) + .Process(this->DesignateType) .Process(this->Groups) ; } diff --git a/src/New/Type/AttachEffectTypeClass.h b/src/New/Type/AttachEffectTypeClass.h index 373a144a10..9c0078910f 100644 --- a/src/New/Type/AttachEffectTypeClass.h +++ b/src/New/Type/AttachEffectTypeClass.h @@ -7,6 +7,7 @@ #include #include #include "LaserTrailTypeClass.h" +#include "SWSignalTypeClass.h" // AE discard condition enum class DiscardCondition : unsigned char @@ -98,6 +99,8 @@ class AttachEffectTypeClass final : public Enumerable Valueable DisableWeapons; Valueable Unkillable; ValueableIdx LaserTrail_Type; + Valueable InhibitType; + Valueable DesignateType; std::vector Groups; @@ -158,6 +161,8 @@ class AttachEffectTypeClass final : public Enumerable , DisableWeapons { false } , Unkillable { false } , LaserTrail_Type { -1 } + , InhibitType {} + , DesignateType {} , Groups {} {}; From 43c8621dcc6e24b904ad46188d65b0d567d0ddb4 Mon Sep 17 00:00:00 2001 From: NetsuNegi39 Date: Wed, 3 Dec 2025 06:06:12 +0800 Subject: [PATCH 10/10] fix --- src/Ext/Techno/Body.Update.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Ext/Techno/Body.Update.cpp b/src/Ext/Techno/Body.Update.cpp index faf7e44407..f855a60f56 100644 --- a/src/Ext/Techno/Body.Update.cpp +++ b/src/Ext/Techno/Body.Update.cpp @@ -2033,8 +2033,8 @@ void TechnoExt::ExtData::RecalculateStatMultipliers() reflectsDamage |= type->ReflectDamage; hasOnFireDiscardables |= (type->DiscardOn & DiscardCondition::Firing) != DiscardCondition::None; hasCritModifiers |= (type->Crit_Multiplier != 1.0 || type->Crit_ExtraChance != 0.0); - hasInibitor |= type->InhibitType; - hasDesignator |= type->DesignateType; + hasInibitor |= type->InhibitType != nullptr; + hasDesignator |= type->DesignateType != nullptr; } pAE.FirepowerMultiplier = firepower;