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 @@ -656,6 +656,7 @@ This page lists all the individual contributions to the project by their author.
- CellSpread in cylinder shape
- CellSpread damage check if victim is in air or on floor
- Fix an issue where non-repairer units needed sensors to attack cloaked friendly units
- Toggle per-target warhead effects apply timing
- **solar-III (凤九歌)**
- Target scanning delay customization (documentation)
- Skip target scanning function calling for unarmed technos (documentation)
Expand Down
26 changes: 26 additions & 0 deletions docs/New-or-Enhanced-Logics.md
Original file line number Diff line number Diff line change
Expand Up @@ -2628,6 +2628,32 @@ SpawnsCrate(N).Type= ; Powerup crate type enum (money|unit|healbase|cloak|ex
SpawnsCrate(N).Weight=1 ; integer
```

### Toggle per-target warhead effects apply timing

- Now you can set the following flag to `false` to apply the Phobos warhead effects that take effect on each target when taking damage, rather than when the projectiles detonate.
- This will allow such effects to be applied through damage without projectiles, including but not limited to damage from particles, vanilla radiation, and Ares' `GenericWarhead` superweapon.
- This will also cause all effects that can completely prevent damage to also prevent these warhead effects, including but not limited to `DamageSelf`, `DamageAirThreshold`, `AffectsAllies`, `AffectsAir`.
- If you use a warhead with CellSpread to damage a building multiple times, then these effects will be applied multiple times. If you don't want this to happen, use [`MergeBuildingDamage`](#allow-merging-aoe-damage-to-buildings-into-one).
- The affected effects include:
- [Remove mind-control](#break-mind-control-on-impact)
- [Type convertion](#convert-technotype-on-impact)
- [`BuildingSell` & `BuildingUndeploy`](#sell-or-undeploy-building-on-impact)
- [`RemoveDisguise`](#remove-disguise-on-impact)
- [`ReverseEngineer`](#reverse-engineer-warhead)
- [Modify shield](#shields)
- [Modify attach-effects](#attached-effects)
- [Critical hits](#chance-based-extra-damage-or-warhead-detonation--critical-hits)
- Due to technical reasons, `Crit.SuppressWhenIntercepted=false` and `Crit.ApplyChancePerTarget=true` will forced to be used.

In `rulesmd.ini`:
```ini
[CombatDamage] ; WarheadType
ApplyPerTargetEffectsOnDetonate=true ; boolean

[SOMEWARHEAD] ; WarheadType
ApplyPerTargetEffectsOnDetonate= ; boolean, default to [CombatDamage] -> ApplyPerTargetEffectsOnDetonate
```

### Trigger specific NotHuman infantry Death anim sequence

- Warheads are now able to trigger specific `NotHuman=yes` infantry `Death` anim sequence using the corresponding tag. It's value represents sequences from `Die1` to `Die5`.
Expand Down
1 change: 1 addition & 0 deletions docs/Whats-New.md
Original file line number Diff line number Diff line change
Expand Up @@ -514,6 +514,7 @@ Vanilla fixes:
- Fixed a bug where units can be promoted when created via trigger actions even if they have `Trainable=false` (by NetsuNegi)
- Fixed the bug that ai will try to product aircraft even the airport has no free dock for it (by NetsuNegi)
- Fixed the issue where non-repairer units needed sensors to attack cloaked friendly units (by TaranDahl)
- Toggle per-target warhead effects apply timing (by TaranDahl)

Phobos fixes:
- Fixed the bug that `AllowAirstrike=no` cannot completely prevent air strikes from being launched against it (by NetsuNegi)
Expand Down
3 changes: 3 additions & 0 deletions src/Ext/Rules/Body.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -339,6 +339,8 @@ void RulesExt::ExtData::LoadBeforeTypeData(RulesClass* pThis, CCINIClass* pINI)
this->SortCameoByName.Read(exINI, GameStrings::General, "SortCameoByName");

this->MergeBuildingDamage.Read(exINI, GameStrings::CombatDamage, "MergeBuildingDamage");

this->ApplyPerTargetEffectsOnDetonate.Read(exINI, GameStrings::CombatDamage, "ApplyPerTargetEffectsOnDetonate");

// Section AITargetTypes
int itemsCount = pINI->GetKeyCount("AITargetTypes");
Expand Down Expand Up @@ -617,6 +619,7 @@ void RulesExt::ExtData::Serialize(T& Stm)
.Process(this->AIAirTargetingFix)
.Process(this->SortCameoByName)
.Process(this->MergeBuildingDamage)
.Process(this->ApplyPerTargetEffectsOnDetonate)
;
}

Expand Down
4 changes: 4 additions & 0 deletions src/Ext/Rules/Body.h
Original file line number Diff line number Diff line change
Expand Up @@ -288,6 +288,8 @@ class RulesExt
Valueable<bool> AIAirTargetingFix;

Valueable<bool> SortCameoByName;

Valueable<bool> ApplyPerTargetEffectsOnDetonate;

ExtData(RulesClass* OwnerObject) : Extension<RulesClass>(OwnerObject)
, Storage_TiberiumIndex { -1 }
Expand Down Expand Up @@ -516,6 +518,8 @@ class RulesExt
, SortCameoByName { false }

, MergeBuildingDamage { false }

, ApplyPerTargetEffectsOnDetonate { true }
{ }

virtual ~ExtData() = default;
Expand Down
4 changes: 4 additions & 0 deletions src/Ext/Techno/Hooks.ReceiveDamage.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,10 @@ DEFINE_HOOK(0x701900, TechnoClass_ReceiveDamage_Shield, 0x6)
const auto pSourceHouse = args->SourceHouse;
const auto pTargetHouse = pThis->Owner;

// Apply warhead effects
if (damage && !pWHExt->ApplyPerTargetEffectsOnDetonate.Get(RulesExt::Global()->ApplyPerTargetEffectsOnDetonate))
pWHExt->DetonateOnOneUnit(args->SourceHouse, pThis, args->Attacker);

// Calculate Damage Multiplier
if (!args->IgnoreDefenses && damage)
{
Expand Down
4 changes: 4 additions & 0 deletions src/Ext/WarheadType/Body.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -310,6 +310,8 @@ void WarheadTypeExt::ExtData::LoadFromINIFile(CCINIClass* const pINI)

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

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

// Convert.From & Convert.To
TypeConvertGroup::Parse(this->Convert_Pairs, exINI, pSection, AffectedHouse::All);

Expand Down Expand Up @@ -603,6 +605,8 @@ void WarheadTypeExt::ExtData::Serialize(T& Stm)

.Process(this->AnimZAdjust)

.Process(this->ApplyPerTargetEffectsOnDetonate)

// Ares tags
.Process(this->AffectsEnemies)
.Process(this->AffectsOwner)
Expand Down
6 changes: 5 additions & 1 deletion src/Ext/WarheadType/Body.h
Original file line number Diff line number Diff line change
Expand Up @@ -214,6 +214,8 @@ class WarheadTypeExt

Nullable<int> AnimZAdjust;

Nullable<bool> ApplyPerTargetEffectsOnDetonate;

// Ares tags
// http://ares-developers.github.io/Ares-docs/new/warheads/general.html
Valueable<bool> AffectsEnemies;
Expand Down Expand Up @@ -450,6 +452,8 @@ class WarheadTypeExt
, PlayAnimAboveSurface { false }

, AnimZAdjust {}

, ApplyPerTargetEffectsOnDetonate {}
{ }

void ApplyConvert(HouseClass* pHouse, TechnoClass* pTarget);
Expand All @@ -475,10 +479,10 @@ class WarheadTypeExt
public:
// Detonate.cpp
void Detonate(TechnoClass* pOwner, HouseClass* pHouse, BulletExt::ExtData* pBullet, CoordStruct coords);
void DetonateOnOneUnit(HouseClass* pHouse, TechnoClass* pTarget, TechnoClass* pOwner = nullptr, bool bulletWasIntercepted = false);
void InterceptBullets(TechnoClass* pOwner, BulletClass* pInterceptor, const CoordStruct& coords);
DamageAreaResult DamageAreaWithTarget(const CoordStruct& coords, int damage, TechnoClass* pSource, WarheadTypeClass* pWH, bool affectsTiberium, HouseClass* pSourceHouse, TechnoClass* pTarget);
private:
void DetonateOnOneUnit(HouseClass* pHouse, TechnoClass* pTarget, TechnoClass* pOwner = nullptr, bool bulletWasIntercepted = false);
void ApplyRemoveDisguise(TechnoClass* pTarget);
HouseClass* ApplyRemoveMindControl(HouseClass* pHouse, TechnoClass* pTarget);
void ApplyCrit(HouseClass* pHouse, TechnoClass* pTarget, TechnoClass* Owner);
Expand Down
4 changes: 2 additions & 2 deletions src/Ext/WarheadType/Detonate.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,7 @@ void WarheadTypeExt::ExtData::Detonate(TechnoClass* pOwner, HouseClass* pHouse,
this->Crit_Active = false;
this->Crit_CurrentChance = this->GetCritChance(pOwner);

if (this->PossibleCellSpreadDetonate || this->Crit_CurrentChance > 0.0)
if ((this->PossibleCellSpreadDetonate || this->Crit_CurrentChance > 0.0) && this->ApplyPerTargetEffectsOnDetonate.Get(RulesExt::Global()->ApplyPerTargetEffectsOnDetonate))
{
if (!this->Crit_ApplyChancePerTarget)
this->Crit_RandomBuffer = ScenarioClass::Instance->Random.RandomDouble();
Expand Down Expand Up @@ -471,7 +471,7 @@ HouseClass* WarheadTypeExt::ExtData::ApplyRemoveMindControl(HouseClass* pHouse,

void WarheadTypeExt::ExtData::ApplyCrit(HouseClass* pHouse, TechnoClass* pTarget, TechnoClass* pOwner)
{
const double dice = this->Crit_ApplyChancePerTarget ? ScenarioClass::Instance->Random.RandomDouble() : this->Crit_RandomBuffer;
const double dice = this->Crit_ApplyChancePerTarget || !this->ApplyPerTargetEffectsOnDetonate.Get(RulesExt::Global()->ApplyPerTargetEffectsOnDetonate) ? ScenarioClass::Instance->Random.RandomDouble() : this->Crit_RandomBuffer;

if (this->Crit_CurrentChance < dice)
return;
Expand Down