Skip to content

Commit

Permalink
Allow detonating weapon warhead on all map objects (#684)
Browse files Browse the repository at this point in the history
* Allow detonating weapon warhead on all map objects

* Simplify loops

* Add DetonateOnAllMapObjects.RequireVerses

* Amend doc

* Post-merge autoformat

Co-authored-by: Meta <[email protected]>
  • Loading branch information
Starkku and Metadorius authored Jul 9, 2022
1 parent 03ad397 commit 391ac19
Show file tree
Hide file tree
Showing 11 changed files with 211 additions and 31 deletions.
1 change: 1 addition & 0 deletions CREDITS.md
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,7 @@ This page lists all the individual contributions to the project by their author.
- Animation damage / weapon improvements
- Warhead self-damaging toggle
- Trailer animation owner inheritance
- Warhead detonation on all objects on map
- **Morton (MortonPL)**:
- `XDrawOffset`
- Shield passthrough & absorption
Expand Down
24 changes: 24 additions & 0 deletions docs/New-or-Enhanced-Logics.md
Original file line number Diff line number Diff line change
Expand Up @@ -732,6 +732,30 @@ In `rulesmd.ini`:
SplashList=<none> ; list of animations
SplashList.PickRandom=false ; boolean

### Detonate Warhead on all objects on map

- Setting `DetonateOnAllMapObjects` to true allows a Warhead that is fully detonated (and not just used to deal damage) and consequently any `Airburst/ShrapnelWeapon` that may follow to detonate on each object currently alive and existing on the map regardless of its actual target, with optional filters. Note that this is done immediately prior Warhead detonation so after `PreImpactAnim` *(Ares feature)* has been displayed.
- `DetonateOnAllMapObjects.AffectTargets` can be used to filter which types of targets (TechnoTypes) are considered valid. Only `all`, `aircraft`, `buildings`, `infantry` and `units` are valid values.
- `DetonateOnAllMapObjects.AffectHouses` can be used to filter which houses targets can belong to be considered valid. Only applicable if the house that fired the projectile is known.
- `DetonateOnAllMapObjects.AffectTypes` can be used to list specific TechnoTypes to be considered as valid targets. If any valid TechnoTypes are listed, then only matching objects will be targeted. Note that `DetonateOnAllMapObjects.AffectTargets` and `DetonateOnAllMapObjects.AffectHouses` take priority over this setting.
- `DetonateOnAllMapObjects.IgnoreTypes` can be used to list specific TechnoTypes to be never considered as valid targets.
- `DetonateOnAllMapObjects.RequireVerses`, if set to true, only considers targets whose armor type the warhead has non-zero `Verses` value against as valid. This is checked after all other filters listed above.

In `rulesmd.ini`:
```ini
[SOMEWARHEAD] ; Warhead
DetonateOnAllMapObjects=false ; boolean
DetonateOnAllMapObjects.AffectTargets=all ; list of Affected Target Enumeration (aircraft|buildings|infantry|units|all)
DetonateOnAllMapObjects.AffectHouses=all ; list of Affected House Enumeration (none|owner/self|allies/ally|team|enemies/enemy|all)
DetonateOnAllMapObjects.AffectTypes= ; list of TechnoType names
DetonateOnAllMapObjects.IgnoreTypes= ; list of TechnoType names
DetonateOnAllMapObjects.RequireVerses=false ; boolean
```

```{warning}
While this feature can provide better performance than a large `CellSpread` value, it still has potential to slow down the game, especially if used in conjunction with things like animations, alpha lights etc. Modder discretion and use of the filter keys is advised.
```

### Generate credits on impact

![image](_static/images/hackerfinallyworks-01.gif)
Expand Down
1 change: 1 addition & 0 deletions docs/Whats-New.md
Original file line number Diff line number Diff line change
Expand Up @@ -313,6 +313,7 @@ New:
- Animation damage / weapon improvements (by Starkku)
- Warhead self-damaging toggle (by Starkku)
- Trailer animations inheriting owner (by Starkku)
- Warhead detonation on all objects on map (by Starkku)

Vanilla fixes:
- Fixed laser drawing code to allow for thicker lasers in house color draw mode (by Kerbiter, ChrisLv_CN)
Expand Down
2 changes: 2 additions & 0 deletions src/Ext/Bullet/Body.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
#include <Ext/WeaponType/Body.h>
#include <Ext/BulletType/Body.h>
#include <Ext/TechnoType/Body.h>
#include <Ext/WarheadType/Body.h>
#include <Utilities/EnumFunctions.h>

template<> const DWORD Extension<BulletClass>::Canary = 0x2A2A2A2A;
BulletExt::ExtContainer BulletExt::ExtMap;
Expand Down
62 changes: 62 additions & 0 deletions src/Ext/Bullet/Hooks.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,10 @@
#include <Ext/BulletType/Body.h>
#include <Misc/CaptureManager.h>

#include <AircraftClass.h>
#include <BuildingClass.h>
#include <InfantryClass.h>
#include <UnitClass.h>
#include <TechnoClass.h>
#include <TacticalClass.h>

Expand Down Expand Up @@ -227,3 +231,61 @@ DEFINE_HOOK(0x469A75, BulletClass_Logics_DamageHouse, 0x7)

return 0;
}

DEFINE_HOOK(0x4690C1, BulletClass_Logics_DetonateOnAllMapObjects, 0x8)
{
enum { ReturnFromFunction = 0x46A2FB };

GET(BulletClass*, pThis, ESI);

if (auto const pWHExt = WarheadTypeExt::ExtMap.Find(pThis->WH))
{
if (pWHExt->DetonateOnAllMapObjects && !pWHExt->WasDetonatedOnAllMapObjects)
{
pWHExt->WasDetonatedOnAllMapObjects = true;
auto const pExt = BulletExt::ExtMap.Find(pThis);
auto pOwner = pThis->Owner ? pThis->Owner->Owner : pExt->FirerHouse;

auto tryDetonate = [pThis, pWHExt, pOwner](TechnoClass* pTechno)
{
if (pWHExt->EligibleForFullMapDetonation(pTechno, pOwner))
{
pThis->Target = pTechno;
auto coords = CoordStruct::Empty;
coords = *pTechno->GetCoords(&coords);
pThis->Detonate(coords);
}
};

if ((pWHExt->DetonateOnAllMapObjects_AffectTargets & AffectedTarget::Aircraft) != AffectedTarget::None)
{
for (auto pTechno : *AircraftClass::Array)
tryDetonate(pTechno);
}

if ((pWHExt->DetonateOnAllMapObjects_AffectTargets & AffectedTarget::Building) != AffectedTarget::None)
{
for (auto pTechno : *BuildingClass::Array)
tryDetonate(pTechno);
}

if ((pWHExt->DetonateOnAllMapObjects_AffectTargets & AffectedTarget::Infantry) != AffectedTarget::None)
{
for (auto pTechno : *InfantryClass::Array)
tryDetonate(pTechno);
}

if ((pWHExt->DetonateOnAllMapObjects_AffectTargets & AffectedTarget::Unit) != AffectedTarget::None)
{
for (auto pTechno : *UnitClass::Array)
tryDetonate(pTechno);
}

pWHExt->WasDetonatedOnAllMapObjects = false;

return ReturnFromFunction;
}
}

return 0;
}
42 changes: 42 additions & 0 deletions src/Ext/WarheadType/Body.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
#include <HouseClass.h>

#include <Ext/BulletType/Body.h>
#include <Utilities/EnumFunctions.h>

template<> const DWORD Extension<WarheadTypeClass>::Canary = 0x22222222;
WarheadTypeExt::ExtContainer WarheadTypeExt::ExtMap;
Expand Down Expand Up @@ -59,6 +60,31 @@ void WarheadTypeExt::DetonateAt(WarheadTypeClass* pThis, const CoordStruct& coor
}
}

bool WarheadTypeExt::ExtData::EligibleForFullMapDetonation(TechnoClass* pTechno, HouseClass* pOwner)
{
if (!pTechno)
return false;

if (pOwner && !EnumFunctions::CanTargetHouse(this->DetonateOnAllMapObjects_AffectHouses, pOwner, pTechno->Owner))
return false;

if ((this->DetonateOnAllMapObjects_AffectTypes.size() > 0 &&
!this->DetonateOnAllMapObjects_AffectTypes.Contains(pTechno->GetTechnoType())) ||
this->DetonateOnAllMapObjects_IgnoreTypes.Contains(pTechno->GetTechnoType()))
{
return false;
}

if (this->DetonateOnAllMapObjects_RequireVerses &&
GeneralUtils::GetWarheadVersusArmor(this->OwnerObject(), pTechno->GetTechnoType()->Armor) == 0.0)
{
return false;
}

if (pTechno->IsOnMap && pTechno->IsAlive && !pTechno->InLimbo)
return true;
}

// =============================
// load / save

Expand Down Expand Up @@ -134,6 +160,13 @@ void WarheadTypeExt::ExtData::LoadFromINIFile(CCINIClass* const pINI)
this->LaunchSW_IgnoreInhibitors.Read(exINI, pSection, "LaunchSW.IgnoreInhibitors");
this->AllowDamageOnSelf.Read(exINI, pSection, "AllowDamageOnSelf");

this->DetonateOnAllMapObjects.Read(exINI, pSection, "DetonateOnAllMapObjects");
this->DetonateOnAllMapObjects_RequireVerses.Read(exINI, pSection, "DetonateOnAllMapObjects.RequireVerses");
this->DetonateOnAllMapObjects_AffectTargets.Read(exINI, pSection, "DetonateOnAllMapObjects.AffectTargets");
this->DetonateOnAllMapObjects_AffectHouses.Read(exINI, pSection, "DetonateOnAllMapObjects.AffectHouses");
this->DetonateOnAllMapObjects_AffectTypes.Read(exINI, pSection, "DetonateOnAllMapObjects.AffectTypes");
this->DetonateOnAllMapObjects_IgnoreTypes.Read(exINI, pSection, "DetonateOnAllMapObjects.IgnoreTypes");

// Ares tags
// http://ares-developers.github.io/Ares-docs/new/warheads/general.html
this->AffectsEnemies.Read(exINI, pSection, "AffectsEnemies");
Expand Down Expand Up @@ -202,9 +235,18 @@ void WarheadTypeExt::ExtData::Serialize(T& Stm)
.Process(this->LaunchSW_IgnoreInhibitors)
.Process(this->AllowDamageOnSelf)

.Process(this->DetonateOnAllMapObjects)
.Process(this->DetonateOnAllMapObjects_RequireVerses)
.Process(this->DetonateOnAllMapObjects_AffectTargets)
.Process(this->DetonateOnAllMapObjects_AffectHouses)
.Process(this->DetonateOnAllMapObjects_AffectTypes)
.Process(this->DetonateOnAllMapObjects_IgnoreTypes)

// Ares tags
.Process(this->AffectsEnemies)
.Process(this->AffectsOwner)

.Process(this->WasDetonatedOnAllMapObjects)
;
}

Expand Down
24 changes: 21 additions & 3 deletions src/Ext/WarheadType/Body.h
Original file line number Diff line number Diff line change
Expand Up @@ -75,13 +75,21 @@ class WarheadTypeExt
Valueable<bool> LaunchSW_IgnoreInhibitors;
Valueable<bool> AllowDamageOnSelf;

Valueable<bool> DetonateOnAllMapObjects;
Valueable<bool> DetonateOnAllMapObjects_RequireVerses;
Valueable<AffectedTarget> DetonateOnAllMapObjects_AffectTargets;
Valueable<AffectedHouse> DetonateOnAllMapObjects_AffectHouses;
ValueableVector<TechnoTypeClass*> DetonateOnAllMapObjects_AffectTypes;
ValueableVector<TechnoTypeClass*> DetonateOnAllMapObjects_IgnoreTypes;

// Ares tags
// http://ares-developers.github.io/Ares-docs/new/warheads/general.html
Valueable<bool> AffectsEnemies;
Nullable<bool> AffectsOwner;

double RandomBuffer;
bool HasCrit;
bool WasDetonatedOnAllMapObjects;

private:
Valueable<double> Shield_Respawn_Rate_InMinutes;
Expand All @@ -95,7 +103,7 @@ class WarheadTypeExt
, TransactMoney_Display { false }
, TransactMoney_Display_Houses { AffectedHouse::All }
, TransactMoney_Display_AtFirer { false }
, TransactMoney_Display_Offset {{ 0, 0 }}
, TransactMoney_Display_Offset { { 0, 0 } }
, SplashList {}
, SplashList_PickRandom { false }
, RemoveDisguise { false }
Expand All @@ -114,8 +122,6 @@ class WarheadTypeExt
, Crit_AnimOnAffectedTargets { false }
, Crit_AffectBelowPercent { 1.0 }
, Crit_SuppressWhenIntercepted { false }
, RandomBuffer { 0.0 }
, HasCrit { false }

, MindControl_Anim {}

Expand Down Expand Up @@ -151,8 +157,19 @@ class WarheadTypeExt
, LaunchSW_IgnoreInhibitors { false }
, AllowDamageOnSelf { false }

, DetonateOnAllMapObjects { false }
, DetonateOnAllMapObjects_RequireVerses { false }
, DetonateOnAllMapObjects_AffectTargets { AffectedTarget::All }
, DetonateOnAllMapObjects_AffectHouses { AffectedHouse::All }
, DetonateOnAllMapObjects_AffectTypes {}
, DetonateOnAllMapObjects_IgnoreTypes {}

, AffectsEnemies { true }
, AffectsOwner {}

, RandomBuffer { 0.0 }
, HasCrit { false }
, WasDetonatedOnAllMapObjects { false }
{ }

private:
Expand All @@ -167,6 +184,7 @@ class WarheadTypeExt
void Detonate(TechnoClass* pOwner, HouseClass* pHouse, BulletClass* pBullet, CoordStruct coords);
bool CanTargetHouse(HouseClass* pHouse, TechnoClass* pTechno);
void InterceptBullets(TechnoClass* pOwner, WeaponTypeClass* pWeapon, CoordStruct coords);
bool EligibleForFullMapDetonation(TechnoClass* pTechno, HouseClass* pOwner);

virtual ~ExtData() = default;
virtual void LoadFromINIFile(CCINIClass* pINI) override;
Expand Down
Loading

0 comments on commit 391ac19

Please sign in to comment.