Skip to content
Open
1 change: 1 addition & 0 deletions CREDITS.md
Original file line number Diff line number Diff line change
Expand Up @@ -766,6 +766,7 @@ This page lists all the individual contributions to the project by their author.
- Drive/Jumpjet/Ship/Teleport locomotor did not power on when it is un-piggybacked bugfix
- Destroyed unit leaves sensors bugfix
- **FrozenFog** - Hotkey for deselect object from current selection
- **WingHwy** - Radar / Power Outage warhead
- **Aephiex** - initial fix for Ares academy not working on the initial payloads of vehicles built from a war factory
- **Multfinite** - Allow to toggle main exception handler via command line argument `-ExceptionHandler=boolean`
- **hejiajun107, Xkein** - Fix a jumpjet crash related to voxel shadow drawing
Expand Down
21 changes: 21 additions & 0 deletions docs/New-or-Enhanced-Logics.md
Original file line number Diff line number Diff line change
Expand Up @@ -2962,6 +2962,27 @@ UnlimboDetonate.KeepSelected=false ; boolean
`UnlimboDetonate` cannot be used in conjunction with `Parasite`.
```

### Radar / Power Outage warhead

- Now you can use the following tags to make the warhead cause a radar or power outage to the affected houses for a specified duration.
- `RadarOutage` disables the radar display (identical to a Lightning Storm), while `PowerOutage` causes a blackout (identical to spy infiltration on a Power Plant).
- If `Duration` is **positive**, it stacks onto the current outage timer, unless `Cap` is **negative** — then the effect does not stack and only the longest single duration is kept.
- If `Duration` is **negative**, it reduces the current outage timer.
- When `Cap` is **positive**, it acts as a ceiling for stacking or a floor for reduction.
- Setting `Cap` to **0** with a negative `Duration` removes the outage entirely.
- The final duration never goes below zero.

In `rulesmd.ini`:
```ini
[SOMEWARHEAD] ; WarheadType
RadarOutage.Duration=0 ; integer, game frames
RadarOutage.Cap=0 ; integer
RadarOutage.AffectsHouse=enemies ; Affected House Enumeration (none|owner/self|allies/ally|team|enemies/enemy|all)
PowerOutage.Duration=0 ; integer, game frames
PowerOutage.Cap=0 ; integer
PowerOutage.AffectsHouse=enemies ; Affected House Enumeration (none|owner/self|allies/ally|team|enemies/enemy|all)
```

## Weapons

### AreaFire target customization
Expand Down
1 change: 1 addition & 0 deletions docs/Whats-New.md
Original file line number Diff line number Diff line change
Expand Up @@ -576,6 +576,7 @@ New:
- [Customize `HarvesterLoadRate`](Fixed-or-Improved-Logics.md#customize-harvesterloadrate) (by Noble_Fish)
- [Toggle to prevent `ShrapnelWeapon` from targeting buildings multiple times](Fixed-or-Improved-Logics.md#shrapnel-enhancements) (by Starkku)
- [Laser drawing Z-adjust customization](Fixed-or-Improved-Logics.md#laser-z-adjust) (by Starkku)
- [Radar / Power Outage warhead](New-or-Enhanced-Logics.md#radar--power-outage-warhead) (by WingHwy)
- Customize `HarvesterDumpRate` (by Noble_Fish)
- Allow users to define the time interval of `DisplayIncome` (by Noble_Fish)

Expand Down
14 changes: 14 additions & 0 deletions src/Ext/WarheadType/Body.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -308,6 +308,13 @@ void WarheadTypeExt::ExtData::LoadFromINIFile(CCINIClass* const pINI)
this->JumpjetNoWobbles.Read(exINI, pSection, "JumpjetNoWobbles");
this->JumpjetDeviation.Read(exINI, pSection, "JumpjetDeviation");

this->RadarOutage_Duration.Read(exINI, pSection, "RadarOutage.Duration");
this->RadarOutage_Cap.Read(exINI, pSection, "RadarOutage.Cap");
this->RadarOutage_AffectsHouse.Read(exINI, pSection, "RadarOutage.AffectsHouse");
this->PowerOutage_Duration.Read(exINI, pSection, "PowerOutage.Duration");
this->PowerOutage_Cap.Read(exINI, pSection, "PowerOutage.Cap");
this->PowerOutage_AffectsHouse.Read(exINI, pSection, "PowerOutage.AffectsHouse");
Comment thread
WingHwy marked this conversation as resolved.

this->Nonprovocative.Read(exINI, pSection, "Nonprovocative");

this->MergeBuildingDamage.Read(exINI, pSection, "MergeBuildingDamage");
Expand Down Expand Up @@ -695,6 +702,13 @@ void WarheadTypeExt::ExtData::Serialize(T& Stm)
.Process(this->JumpjetNoWobbles)
.Process(this->JumpjetDeviation)

.Process(this->RadarOutage_Duration)
.Process(this->RadarOutage_Cap)
.Process(this->RadarOutage_AffectsHouse)
.Process(this->PowerOutage_Duration)
.Process(this->PowerOutage_Cap)
.Process(this->PowerOutage_AffectsHouse)

.Process(this->Nonprovocative)

.Process(this->MergeBuildingDamage)
Expand Down
14 changes: 14 additions & 0 deletions src/Ext/WarheadType/Body.h
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,13 @@ class WarheadTypeExt
Nullable<bool> JumpjetNoWobbles;
Nullable<int> JumpjetDeviation;

Valueable<int> RadarOutage_Duration;
Valueable<int> RadarOutage_Cap;
Valueable<AffectedHouse> RadarOutage_AffectsHouse;
Valueable<int> PowerOutage_Duration;
Valueable<int> PowerOutage_Cap;
Valueable<AffectedHouse> PowerOutage_AffectsHouse;

Valueable<bool> Nonprovocative;

Nullable<bool> MergeBuildingDamage;
Expand Down Expand Up @@ -426,6 +433,13 @@ class WarheadTypeExt
, JumpjetNoWobbles {}
, JumpjetDeviation {}

, RadarOutage_Duration { 0 }
, RadarOutage_Cap { 0 }
, RadarOutage_AffectsHouse { AffectedHouse::Enemies }
, PowerOutage_Duration { 0 }
, PowerOutage_Cap { 0 }
, PowerOutage_AffectsHouse { AffectedHouse::Enemies }

, Nonprovocative { false }

, MergeBuildingDamage {}
Expand Down
40 changes: 40 additions & 0 deletions src/Ext/WarheadType/Detonate.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,46 @@ void WarheadTypeExt::ExtData::Detonate(TechnoClass* pOwner, HouseClass* pHouse,
MapClass::Instance.PlacePowerupCrate(CellClass::Coord2Cell(coords), this->SpawnsCrate_Types.at(index));
}

if (this->RadarOutage_Duration)
{
for (const auto pTargetHouse : HouseClass::Array)
{
if (!pTargetHouse->Defeated && !pTargetHouse->IsObserver()
&& !pTargetHouse->Type->MultiplayPassive
&& EnumFunctions::CanTargetHouse(this->RadarOutage_AffectsHouse, pHouse, pTargetHouse))
{
int newLeft = Helpers::Alex::getCappedDuration(
pTargetHouse->RadarBlackoutTimer.GetTimeLeft(),
this->RadarOutage_Duration,
this->RadarOutage_Cap
);
newLeft = Math::max(newLeft, 0);
pTargetHouse->RadarBlackoutTimer.Start(newLeft);
pTargetHouse->RecheckRadar = true;
}
}
}

if (this->PowerOutage_Duration)
{
for (const auto pTargetHouse : HouseClass::Array)
{
if (!pTargetHouse->Defeated && !pTargetHouse->IsObserver()
&& !pTargetHouse->Type->MultiplayPassive
&& EnumFunctions::CanTargetHouse(this->PowerOutage_AffectsHouse, pHouse, pTargetHouse))
{
int newLeft = Helpers::Alex::getCappedDuration(
pTargetHouse->PowerBlackoutTimer.GetTimeLeft(),
this->PowerOutage_Duration,
this->PowerOutage_Cap
);
newLeft = Math::max(newLeft, 0);
pTargetHouse->PowerBlackoutTimer.Start(newLeft);
pTargetHouse->RecheckPower = true;
}
}
}

for (const int swIdx : this->LaunchSW)
{
if (const auto pSuper = pHouse->Supers.GetItem(swIdx))
Expand Down
Loading