diff --git a/CREDITS.md b/CREDITS.md
index 5bcca208cc..e52c09cf05 100644
--- a/CREDITS.md
+++ b/CREDITS.md
@@ -463,6 +463,7 @@ This page lists all the individual contributions to the project by their author.
- Customize Ares's radar jam logic
- Customize if cloning need power
- Customize type selection for IFV
+ - Customize Inhibitors and Designators
- **Apollo** - Translucent SHP drawing patches
- **ststl**:
- Customizable `ShowTimer` priority of superweapons
diff --git a/Phobos.vcxproj b/Phobos.vcxproj
index 2def0db9a8..ff93548aa9 100644
--- a/Phobos.vcxproj
+++ b/Phobos.vcxproj
@@ -21,6 +21,7 @@
+
@@ -181,6 +182,7 @@
+
@@ -219,6 +221,7 @@
+
@@ -277,6 +280,7 @@
+
diff --git a/docs/Fixed-or-Improved-Logics.md b/docs/Fixed-or-Improved-Logics.md
index b124266b4f..40aef896e2 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 38342ff07d..d737b24182 100644
--- a/docs/New-or-Enhanced-Logics.md
+++ b/docs/New-or-Enhanced-Logics.md
@@ -58,6 +58,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.
@@ -149,6 +151,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
@@ -187,6 +191,39 @@ 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.
+- `StopInTemporal` determines whether or not the effect is rendered inactive if the object is being warped out by a `Temporal=yes` warhead.
+- `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.
+- `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`
+```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
+StopInTemporal=false ; boolean
+
+[SOMESW] ; SuperWeaponType
+SW.InhibitTypes= ; List of SuperWeaponSignalType
+SW.DesignateTypes= ; List of SuperWeaponSignalType
+
+[SOMETECHNO] ; TechnoType
+InhibitTypes= ; List of SuperWeaponSignalType
+DesignateTypes= ; List of SuperWeaponSignalType
+```
+
### Custom Radiation Types

diff --git a/docs/Whats-New.md b/docs/Whats-New.md
index c92dcbc479..8dc894b0de 100644
--- a/docs/Whats-New.md
+++ b/docs/Whats-New.md
@@ -463,6 +463,7 @@ New:
- [Customize if cloning need power](Fixed-or-Improved-Logics.md#customize-if-cloning-need-power) (by NetsuNegi)
- [Added Target Filtering Options to AttachEffect System](New-or-Enhanced-Logics.md#attached-effects) (by Flactine)
- [Customize type selection for IFV](Fixed-or-Improved-Logics.md#customize-type-selection-for-ifv) (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)
diff --git a/src/Ext/SWType/Ares/NewSWType.cpp b/src/Ext/SWType/Ares/NewSWType.cpp
new file mode 100644
index 0000000000..1458916081
--- /dev/null
+++ b/src/Ext/SWType/Ares/NewSWType.cpp
@@ -0,0 +1,167 @@
+#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;
+ const bool hasInhibitType = !pExt->SW_InhibitTypes.empty();
+ const bool hasInhibitor = !pExt->SW_Inhibitors.empty() || pExt->SW_AnyInhibitor;
+
+ if (hasDesignateType || hasDesignator || hasInhibitType || hasInhibitor)
+ {
+ if (hasDesignateType || hasDesignator)
+ data.NeedsDesignator = true;
+
+ for (const auto pTechno : TechnoClass::Array)
+ {
+ if (!pTechno->IsAlive || !pTechno->Health || pTechno->InLimbo)
+ continue;
+
+ const bool deactivated = pTechno->Deactivated;
+
+ if (deactivated && !hasDesignateType && !hasInhibitType)
+ continue;
+
+ const bool isTemporal = pTechno->TemporalTargetingMe || pTechno->IsBeingWarpedOut();
+ bool inactive = deactivated || pTechno->IsUnderEMP();
+ bool buildingOnline = true;
+
+ if (const auto pBuilding = abstract_cast(pTechno))
+ {
+ buildingOnline = pBuilding->IsPowerOnline();
+ inactive |= !buildingOnline;
+ }
+
+ const auto center = pTechno->GetCoords();
+ 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)
+ {
+ for (const auto signal : pExt->SW_DesignateTypes)
+ {
+ if (inactive && signal->Powered)
+ continue;
+
+ if (isTemporal && signal->StopInTemporal)
+ continue;
+
+ 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(sight);
+
+ if (range > 0)
+ data.Designators.emplace_back(range * range, cell);
+ }
+ }
+
+ if (hasDesignator && !deactivated
+ && EnumFunctions::CanTargetHouse(pExt->SW_Designators_Houses, pOwner, pTechnoOwner)
+ && (pExt->SW_AnyDesignator || pExt->SW_Designators.Contains(pTechnoType)))
+ {
+ const int range = pTechnoTypeExt->DesignatorRange.Get(sight);
+
+ if (range > 0)
+ data.Designators.emplace_back(range * range, cell);
+ }
+
+ if (hasInhibitType)
+ {
+ for (const auto signal : pExt->SW_InhibitTypes)
+ {
+ if (inactive && signal->Powered)
+ continue;
+
+ if (isTemporal && signal->StopInTemporal)
+ continue;
+
+ 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(sight);
+
+ if (range > 0)
+ data.Inhibitors.emplace_back(range * range, cell);
+ }
+ }
+
+ if (hasInhibitor && buildingOnline && !deactivated
+ && EnumFunctions::CanTargetHouse(pExt->SW_Inhibitors_Houses, pOwner, pTechnoOwner)
+ && (pExt->SW_AnyInhibitor || pExt->SW_Inhibitors.Contains(pTechnoType)))
+ {
+ const int range = pTechnoTypeExt->InhibitorRange.Get(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 f230746dc7..30f9fc16f4 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)
@@ -45,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_InhibitTypes)
.Process(this->Message_CannotFire)
.Process(this->Message_InsufficientFunds)
.Process(this->Message_ColorScheme)
@@ -118,8 +122,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);
@@ -131,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_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 e4af1c3879..442b4ce603 100644
--- a/src/Ext/SWType/Body.h
+++ b/src/Ext/SWType/Body.h
@@ -8,6 +8,7 @@
#include
#include
+#include
#include
class SWTypeExt
@@ -36,8 +37,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;
@@ -50,6 +53,9 @@ class SWTypeExt
ValueableIdx SW_PostDependent;
Valueable SW_MaxCount;
+ ValueableVector SW_DesignateTypes;
+ ValueableVector SW_InhibitTypes;
+
Valueable Message_CannotFire;
Valueable Message_InsufficientFunds;
ValueableIdx Message_ColorScheme;
@@ -125,8 +131,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 }
@@ -136,6 +144,8 @@ class SWTypeExt
, SW_InitialReady { false }
, SW_PostDependent {}
, SW_MaxCount { -1 }
+ , SW_DesignateTypes {}
+ , SW_InhibitTypes {}
, SW_Shots { -1 }
, Message_CannotFire {}
, Message_InsufficientFunds {}
@@ -190,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 023073853e..7666c1a9ff 100644
--- a/src/Ext/SWType/Hooks.cpp
+++ b/src/Ext/SWType/Hooks.cpp
@@ -61,35 +61,140 @@ 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 hasInhibitType = !pSWExt->SW_InhibitTypes.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 (!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
- {
+ if (!pTechno->IsAlive || !pTechno->Health || pTechno->InLimbo)
continue;
- }
- const auto pTechnoTypeExt = TechnoTypeExt::ExtMap.Find(pCurrentTechnoType);
+ const bool deactivated = pTechno->Deactivated;
- const float radius = pOwner == HouseClass::CurrentPlayer
- ? (float)(pTechnoTypeExt->DesignatorRange.Get(pCurrentTechnoType->Sight))
- : (float)(pTechnoTypeExt->InhibitorRange.Get(pCurrentTechnoType->Sight));
+ if (deactivated && !hasDesignateType && !hasInhibitType)
+ continue;
+
+ const bool isTemporal = pTechno->TemporalTargetingMe || pTechno->IsBeingWarpedOut();
+ bool inactive = deactivated || pTechno->IsUnderEMP();
+ bool buildingOnline = true;
- CoordStruct coords = pCurrentTechno->GetCenterCoords();
+ if (const auto pBuilding = abstract_cast(pTechno))
+ {
+ buildingOnline = pBuilding->IsPowerOnline();
+ inactive |= !buildingOnline;
+ }
+
+ CoordStruct coords = pTechno->GetCenterCoords();
coords.Z = MapClass::Instance.GetCellFloorHeight(coords);
+ const auto pOwner = pTechno->Owner;
const auto color = pOwner->Color;
- Game::DrawRadialIndicator(false, true, coords, color, radius, false, true);
+ const auto pTechnoExt = TechnoExt::ExtMap.Find(pTechno);
+ const auto pTechnoTypeExt = pTechnoExt->TypeExtData;
+ const auto pTechnoType = pTechnoTypeExt->OwnerObject();
+ const int sight = pTechnoType->Sight;
+
+ if (hasDesignateType)
+ {
+ for (const auto signal : pSWExt->SW_DesignateTypes)
+ {
+ if (inactive && signal->Powered)
+ continue;
+
+ if (isTemporal && signal->StopInTemporal)
+ continue;
+
+ if (!EnumFunctions::CanTargetHouse(signal->Affects.Get(AffectedHouse::Owner), HouseClass::CurrentPlayer, pOwner))
+ 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 radius = signal->Range.Get(sight);
+
+ if (radius > 0)
+ Game::DrawRadialIndicator(false, true, coords, color, static_cast(radius), false, true);
+ }
+ }
+
+ if (hasDesignator && !deactivated)
+ {
+ if (EnumFunctions::CanTargetHouse(pSWExt->SW_Designators_Houses, HouseClass::CurrentPlayer, pOwner) && pSWExt->SW_Designators.Contains(pTechnoType))
+ {
+ const int radius = pTechnoTypeExt->DesignatorRange.Get(sight);
+
+ if (radius > 0)
+ Game::DrawRadialIndicator(false, true, coords, color, static_cast(radius), false, true);
+ }
+ }
+
+ if (hasInhibitType)
+ {
+ for (const auto signal : pSWExt->SW_InhibitTypes)
+ {
+ if (inactive && signal->Powered)
+ continue;
+
+ if (isTemporal && signal->StopInTemporal)
+ continue;
+
+ 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(sight);
+
+ if (radius > 0)
+ Game::DrawRadialIndicator(false, true, coords, color, static_cast(radius), false, true);
+ }
+ }
+
+ if (hasInhibitor && buildingOnline && !deactivated)
+ {
+ if (EnumFunctions::CanTargetHouse(pSWExt->SW_Inhibitors_Houses, HouseClass::CurrentPlayer, pOwner) && pSWExt->SW_Inhibitors.Contains(pTechnoType))
+ {
+ const int radius = pTechnoTypeExt->InhibitorRange.Get(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 20e5b6b9a9..15ef97cbb1 100644
--- a/src/Ext/SWType/SWHelpers.cpp
+++ b/src/Ext/SWType/SWHelpers.cpp
@@ -42,37 +42,89 @@ 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 (!pTechno->IsAlive || !pTechno->Health || pTechno->InLimbo)
+ return false;
+
+ const bool deactivated = pTechno->Deactivated;
+
+ if (deactivated && this->SW_InhibitTypes.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 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_InhibitTypes)
{
- if (!pOwner->IsAlliedWith(pTechno))
+ if (inactive && signal->Powered)
+ continue;
+
+ if (isTemporal && signal->StopInTemporal)
+ continue;
+
+ 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)
{
- if (const auto pBld = abstract_cast(pTechno))
+ for (const auto& attachEffect : pTechnoExt->AttachedEffects)
{
- if (!pBld->IsPowerOnline())
- return false;
+ if (signal == attachEffect->GetType()->InhibitType)
+ {
+ findSignal = true;
+ break;
+ }
}
-
- return this->SW_AnyInhibitor || this->SW_Inhibitors.Contains(pTechno->GetTechnoType());
}
- }
- return false;
-}
+ if (!findSignal)
+ continue;
-bool SWTypeExt::ExtData::IsInhibitorEligible(HouseClass* pOwner, const CellStruct& coords, TechnoClass* pTechno) const
-{
- if (this->IsInhibitor(pOwner, pTechno))
- {
- const auto pType = pTechno->GetTechnoType();
- const auto pExt = TechnoTypeExt::ExtMap.Find(pType);
+ const int range = signal->Range.Get(sight);
- // get the inhibitor's center
- const auto center = pTechno->GetCenterCoords();
+ if (distanceSqr <= range * range)
+ return true;
+ }
- // has to be closer than the inhibitor range (which defaults to Sight)
- return coords.DistanceFrom(CellClass::Coord2Cell(center)) <= pExt->InhibitorRange.Get(pType->Sight);
+ if (EnumFunctions::CanTargetHouse(this->SW_Inhibitors_Houses, pOwner, pTechnoOwner) && (this->SW_AnyInhibitor || this->SW_Inhibitors.Contains(pTechnoType)))
+ {
+ const int range = pTechnoTypeExt->InhibitorRange.Get(sight);
+
+ if (distanceSqr <= range * range)
+ return true;
}
return false;
@@ -81,36 +133,91 @@ 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_InhibitTypes.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 (pTechno->Owner == pOwner && 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)
+ return false;
+
+ 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 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)
{
- const auto pType = pTechno->GetTechnoType();
- const auto pExt = TechnoTypeExt::ExtMap.Find(pType);
+ if (inactive && signal->Powered)
+ continue;
+
+ if (isTemporal && signal->StopInTemporal)
+ continue;
- // get the designator's center
- const auto center = pTechno->GetCenterCoords();
+ 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(sight);
+
+ if (distanceSqr <= range * range)
+ return true;
+ }
+
+ if (EnumFunctions::CanTargetHouse(this->SW_Designators_Houses, pOwner, pTechnoOwner) && (this->SW_AnyDesignator || this->SW_Designators.Contains(pTechnoType)))
+ {
+ const int range = pTechnoTypeExt->DesignatorRange.Get(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;
@@ -119,11 +226,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..f642a13211 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->InhibitTypes.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->InhibitTypes.empty())
+ return true;
}
break;
diff --git a/src/Ext/Techno/Body.Update.cpp b/src/Ext/Techno/Body.Update.cpp
index 23728fd023..f855a60f56 100644
--- a/src/Ext/Techno/Body.Update.cpp
+++ b/src/Ext/Techno/Body.Update.cpp
@@ -2006,6 +2006,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)
{
@@ -2031,6 +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 != nullptr;
+ hasDesignator |= type->DesignateType != nullptr;
}
pAE.FirepowerMultiplier = firepower;
@@ -2047,6 +2051,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 d6840dcbf9..4ea9ede1d8 100644
--- a/src/Ext/TechnoType/Body.cpp
+++ b/src/Ext/TechnoType/Body.cpp
@@ -962,6 +962,9 @@ void TechnoTypeExt::ExtData::LoadFromINIFile(CCINIClass* const pINI)
this->Power.Read(exINI, pSection, "Power");
+ this->DesignateTypes.Read(exINI, pSection, "DesignateTypes");
+ this->InhibitTypes.Read(exINI, pSection, "InhibitTypes");
+
this->AllowAirstrike.Read(exINI, pSection, "AllowAirstrike");
this->Image_ConditionYellow.Read(exINI, pSection, "Image.ConditionYellow");
@@ -1603,6 +1606,9 @@ void TechnoTypeExt::ExtData::Serialize(T& Stm)
.Process(this->Power)
+ .Process(this->DesignateTypes)
+ .Process(this->InhibitTypes)
+
.Process(this->AllowAirstrike)
.Process(this->Image_ConditionYellow)
diff --git a/src/Ext/TechnoType/Body.h b/src/Ext/TechnoType/Body.h
index 3ada442893..ca6787a420 100644
--- a/src/Ext/TechnoType/Body.h
+++ b/src/Ext/TechnoType/Body.h
@@ -12,6 +12,7 @@
#include
#include
#include
+#include
#include
#include
#include
@@ -338,6 +339,9 @@ class TechnoTypeExt
Valueable Power;
+ ValueableVector DesignateTypes;
+ ValueableVector InhibitTypes;
+
Nullable AllowAirstrike;
Nullable Image_ConditionYellow;
@@ -750,6 +754,9 @@ class TechnoTypeExt
, Power { }
+ , DesignateTypes { }
+ , InhibitTypes { }
+
, AllowAirstrike { }
, Image_ConditionYellow { }
diff --git a/src/Misc/Hooks.Ares.cpp b/src/Misc/Hooks.Ares.cpp
index 583676d07e..66854a05c9 100644
--- a/src/Misc/Hooks.Ares.cpp
+++ b/src/Misc/Hooks.Ares.cpp
@@ -8,6 +8,8 @@
#include
#include
#include
+#include
+#include
#include
#include
@@ -42,7 +44,6 @@ bool __stdcall ConvertToType(TechnoClass* pThis, TechnoTypeClass* pToType)
TechnoTypeClass* __fastcall ShowPromoteAnim(TechnoClass* pThis)
{
TechnoExt::ShowPromoteAnim(pThis);
-
return pThis->GetTechnoType();
}
@@ -51,6 +52,8 @@ WeaponStruct* __fastcall GetLaserWeapon(BuildingClass* pThis)
return BuildingExt::GetLaserWeapon(pThis);
}
+_GET_FUNCTION_ADDRESS(AresNewSWType::GetTargetingData, AresNewSWType_GetTargetingData_GetAddr)
+
EBolt* __stdcall CreateEBolt(WeaponTypeClass** pWeaponData)
{
return EBoltExt::CreateEBolt(*pWeaponData);
@@ -118,6 +121,9 @@ void Apply_Ares3_0_Patches()
// Redirect Ares's function to our implementation:
Patch::Apply_LJMP(AresHelper::AresBaseAddress + 0x112D0, &BuildingExt::KickOutClone);
+
+ // Redirect Ares' NewSWType::GetTargetingData() to our implementation:
+ Patch::Apply_LJMP(AresHelper::AresBaseAddress + 0x6D1E0, AresNewSWType_GetTargetingData_GetAddr());
}
void Apply_Ares3_0p1_Patches()
@@ -177,4 +183,7 @@ void Apply_Ares3_0p1_Patches()
// Redirect Ares's function to our implementation:
Patch::Apply_LJMP(AresHelper::AresBaseAddress + 0x11860, &BuildingExt::KickOutClone);
+
+ // Redirect Ares' NewSWType::GetTargetingData() to our implementation:
+ Patch::Apply_LJMP(AresHelper::AresBaseAddress + 0x6E1F0, AresNewSWType_GetTargetingData_GetAddr());
}
diff --git a/src/New/Entity/AttachEffectClass.h b/src/New/Entity/AttachEffectClass.h
index fe792c7a3a..d65fe8d717 100644
--- a/src/New/Entity/AttachEffectClass.h
+++ b/src/New/Entity/AttachEffectClass.h
@@ -120,6 +120,8 @@ struct AttachEffectTechnoProperties
bool HasOnFireDiscardables;
bool HasRestrictedArmorMultipliers;
bool HasCritModifiers;
+ bool HasInhibitor;
+ bool HasDesignator;
AttachEffectTechnoProperties() :
FirepowerMultiplier { 1.0 }
@@ -136,5 +138,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 c4a4d0c208..b4ef6238b8 100644
--- a/src/New/Type/AttachEffectTypeClass.cpp
+++ b/src/New/Type/AttachEffectTypeClass.cpp
@@ -170,6 +170,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");
@@ -239,6 +241,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 95a7fa216d..885b16ccb6 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
@@ -101,6 +102,8 @@ class AttachEffectTypeClass final : public Enumerable
Valueable DisableWeapons;
Valueable Unkillable;
ValueableIdx LaserTrail_Type;
+ Valueable InhibitType;
+ Valueable DesignateType;
std::vector Groups;
@@ -164,6 +167,8 @@ class AttachEffectTypeClass final : public Enumerable
, DisableWeapons { false }
, Unkillable { false }
, LaserTrail_Type { -1 }
+ , InhibitType {}
+ , DesignateType {}
, Groups {}
{};
diff --git a/src/New/Type/SWSignalTypeClass.cpp b/src/New/Type/SWSignalTypeClass.cpp
new file mode 100644
index 0000000000..99bdde901c
--- /dev/null
+++ b/src/New/Type/SWSignalTypeClass.cpp
@@ -0,0 +1,46 @@
+#include "SWSignalTypeClass.h"
+
+const char* Enumerable::GetMainSection()
+{
+ return "SuperWeaponSignalTypes";
+}
+
+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");
+ this->Powered.Read(exINI, pSection, "Powered");
+ this->StopInTemporal.Read(exINI, pSection, "StopInTemporal");
+}
+
+// =============================
+// load / save
+
+template
+void SWSignalTypeClass::Serialize(T& stm)
+{
+ stm
+ .Process(this->Range)
+ .Process(this->Affects)
+ .Process(this->Powered)
+ .Process(this->StopInTemporal)
+ ;
+}
+
+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..ae45abb4ab
--- /dev/null
+++ b/src/New/Type/SWSignalTypeClass.h
@@ -0,0 +1,24 @@
+#pragma once
+
+#include
+#include
+
+class SWSignalTypeClass final : public Enumerable
+{
+public:
+ Nullable Range {};
+ Nullable Affects {};
+ Valueable Powered { false };
+ Valueable StopInTemporal { false };
+
+ 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
> ;