Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CREDITS.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
4 changes: 4 additions & 0 deletions Phobos.vcxproj
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
<ClCompile Include="src\Ext\Cell\Hooks.cpp" />
<ClCompile Include="src\Ext\Infantry\Hooks.cpp" />
<ClCompile Include="src\Ext\Infantry\Hooks.Firing.cpp" />
<ClCompile Include="src\Ext\SWType\Ares\NewSWType.cpp" />
<ClCompile Include="src\Ext\TechnoType\Hooks.MultiWeapon.cpp" />
<ClCompile Include="src\Ext\Techno\Hooks.Targeting.cpp" />
<ClCompile Include="src\Ext\Unit\Hooks.DrawIt.cpp" />
Expand Down Expand Up @@ -181,6 +182,7 @@
<ClCompile Include="src\Ext\WeaponType\Hooks.DiskLaserRadius.cpp" />
<ClCompile Include="src\Misc\BlittersFix.cpp" />
<ClCompile Include="src\Misc\Selection.cpp" />
<ClCompile Include="src\New\Type\SWSignalTypeClass.cpp" />
<ClCompile Include="src\Utilities\Anchor.cpp" />
<ClCompile Include="src\Utilities\Debug.cpp" />
<ClCompile Include="src\Ext\BuildingType\Body.cpp" />
Expand Down Expand Up @@ -219,6 +221,7 @@
<ItemGroup>
<ClInclude Include="src\Ext\EBolt\Body.h" />
<ClInclude Include="src\New\Entity\Ares\RadarJammerClass.h" />
<ClInclude Include="src\Ext\SWType\Ares\NewSWType.h" />
<ClInclude Include="src\New\Type\Affiliated\CreateUnitTypeClass.h" />
<ClInclude Include="src\Blowfish\blowfish.h" />
<ClInclude Include="src\Ext\Cell\Body.h" />
Expand Down Expand Up @@ -277,6 +280,7 @@
<ClInclude Include="src\New\Type\Affiliated\PassengerDeletionTypeClass.h" />
<ClInclude Include="src\New\Entity\LaserTrailClass.h" />
<ClInclude Include="src\New\Entity\ShieldClass.h" />
<ClInclude Include="src\New\Type\SWSignalTypeClass.h" />
<ClInclude Include="src\Utilities\Anchor.h" />
<ClInclude Include="src\Utilities\Enumerable.h" />
<ClInclude Include="src\Ext\Aircraft\Body.h" />
Expand Down
14 changes: 14 additions & 0 deletions docs/Fixed-or-Improved-Logics.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
37 changes: 37 additions & 0 deletions docs/New-or-Enhanced-Logics.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.

Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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

![image](_static/images/radtype-01.png)
Expand Down
1 change: 1 addition & 0 deletions docs/Whats-New.md
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
167 changes: 167 additions & 0 deletions src/Ext/SWType/Ares/NewSWType.cpp
Original file line number Diff line number Diff line change
@@ -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<BuildingClass*>(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;
}
53 changes: 53 additions & 0 deletions src/Ext/SWType/Ares/NewSWType.h
Original file line number Diff line number Diff line change
@@ -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<LaunchSite> LaunchSites;
std::vector<RangedItem> Designators;
std::vector<RangedItem> 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<float, int> 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<double, double> 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;
};
9 changes: 9 additions & 0 deletions src/Ext/SWType/Body.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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)
Expand Down Expand Up @@ -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);
Expand All @@ -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");

Expand Down
Loading