diff --git a/CREDITS.md b/CREDITS.md index 8b942bf16b..58f638956e 100644 --- a/CREDITS.md +++ b/CREDITS.md @@ -373,6 +373,7 @@ This page lists all the individual contributions to the project by their author. - **Ollerus** - Build limit group enhancement - Customizable rocker amplitude + - Fire weapon when kill - **handama** - AI script action to jump back to previous script - **TaranDahl (航味麻酱)** - Skirmish AI "sell all buildings and set all technos to hunt" behavior dehardcode diff --git a/docs/New-or-Enhanced-Logics.md b/docs/New-or-Enhanced-Logics.md index 2e8c80f3fd..278498e703 100644 --- a/docs/New-or-Enhanced-Logics.md +++ b/docs/New-or-Enhanced-Logics.md @@ -1518,6 +1518,29 @@ DetonateOnAllMapObjects.IgnoreTypes= ; list of TechnoType names DetonateOnAllMapObjects.RequireVerses=false ; boolean ``` +### Fire weapon when kill + +- `KillWeapon` will be fired at the target TechnoType's location once it's been killed by this Warhead. + - `KillWeapon.AffectTargets` is used to filter which types of targets (TechnoTypes) are considered valid for KillWeapon. Only `none`, `all`, `aircraft`, `buildings`, `infantry` and `units` are valid values. + - `KillWeapon.AffectHouses` is used to filter which houses targets can belong to be considered valid for KillWeapon. + - `KillWeapon.AffectTypes` can be used to list specific TechnoTypes to be considered as valid targets for KillWeapon. If any valid TechnoTypes are listed, then only matching objects will be targeted. + - `KillWeapon.IgnoreTypes` can be used to list specific TechnoTypes to be never considered as valid targets for KillWeapon. +- Ìf a TechnoType has `SuppressKillWeapons` set to true, it will not trigger KillWeapon upon being killed. `SuppressKillWeapons.Types` can be used to list WeaponTypes affected by this, if none are listed all WeaponTypes are affected. + + In `rulesmd.ini`: +```ini +[SOMEWARHEAD] ; Warhead +KillWeapon= ; WeaponType +KillWeapon.AffectTargets=all ; list of Affected Target Enumeration (none|aircraft|buildings|infantry|units|all) +KillWeapon.AffectHouses=all ; list of Affected House Enumeration (none|owner/self|allies/ally|team|enemies/enemy|all) +KillWeapon.AffectTypes= ; list of TechnoTypes +KillWeapon.IgnoreTypes= ; list of TechnoTypes + +[SOMETECHNO] ; TechnoType +SuppressKillWeapons=false ; boolean +SuppressKillWeapons.Types= ; list of WeaponTypes +``` + ### Generate credits on impact ![image](_static/images/hackerfinallyworks-01.gif) diff --git a/docs/Whats-New.md b/docs/Whats-New.md index 7966e80312..b29407d1c3 100644 --- a/docs/Whats-New.md +++ b/docs/Whats-New.md @@ -469,6 +469,7 @@ New: - `` can now be used as owner for pre-placed objects on skirmish and multiplayer maps (by Starkku) - Allow customizing charge turret delays per burst on a weapon (by Starkku) - Unit `Speed` setting now accepts floating point values (by Starkku) +- Fire weapon when kill (by Ollerus) Vanilla fixes: - Allow AI to repair structures built from base nodes/trigger action 125/SW delivery in single player missions (by Trsdy) diff --git a/src/Ext/Techno/Body.h b/src/Ext/Techno/Body.h index dd958380bd..e9e47503e6 100644 --- a/src/Ext/Techno/Body.h +++ b/src/Ext/Techno/Body.h @@ -183,4 +183,5 @@ class TechnoExt static WeaponTypeClass* GetCurrentWeapon(TechnoClass* pThis, int& weaponIndex, bool getSecondary = false); static WeaponTypeClass* GetCurrentWeapon(TechnoClass* pThis, bool getSecondary = false); static int GetWeaponIndexAgainstWall(TechnoClass* pThis, OverlayTypeClass* pWallOverlayType); + static void ApplyKillWeapon(TechnoClass* pThis, TechnoClass* pSource, WarheadTypeClass* pWH); }; diff --git a/src/Ext/Techno/Hooks.ReceiveDamage.cpp b/src/Ext/Techno/Hooks.ReceiveDamage.cpp index 8084a0b18f..ef7317c132 100644 --- a/src/Ext/Techno/Hooks.ReceiveDamage.cpp +++ b/src/Ext/Techno/Hooks.ReceiveDamage.cpp @@ -112,6 +112,8 @@ DEFINE_HOOK(0x702672, TechnoClass_ReceiveDamage_RevengeWeapon, 0x5) GET_STACK(TechnoClass*, pSource, STACK_OFFSET(0xC4, 0x10)); GET_STACK(WarheadTypeClass*, pWarhead, STACK_OFFSET(0xC4, 0xC)); + TechnoExt::ApplyKillWeapon(pThis, pSource, pWarhead); + if (pSource) { auto const pExt = TechnoExt::ExtMap.Find(pThis); diff --git a/src/Ext/Techno/WeaponHelpers.cpp b/src/Ext/Techno/WeaponHelpers.cpp index 5310fdf18c..9821b83e9f 100644 --- a/src/Ext/Techno/WeaponHelpers.cpp +++ b/src/Ext/Techno/WeaponHelpers.cpp @@ -3,6 +3,7 @@ #include #include +#include #include // Compares two weapons and returns index of which one is eligible to fire against current target (0 = first, 1 = second), or -1 if neither works. @@ -198,3 +199,25 @@ int TechnoExt::GetWeaponIndexAgainstWall(TechnoClass* pThis, OverlayTypeClass* p return weaponIndex; } + +void TechnoExt::ApplyKillWeapon(TechnoClass* pThis, TechnoClass* pSource, WarheadTypeClass* pWH) +{ + auto const pType = pThis->GetTechnoType(); + auto const pTypeExt = TechnoTypeExt::ExtMap.Find(pType); + auto const pWHExt = WarheadTypeExt::ExtMap.Find(pWH); + + if (!pWHExt->KillWeapon || pTypeExt->SuppressKillWeapons || !EnumFunctions::CanTargetHouse(pWHExt->KillWeapon_AffectHouses, pSource->Owner, pThis->Owner)) + return; + + if (pWHExt->KillWeapon_AffectTypes.size() > 0 && !pWHExt->KillWeapon_AffectTypes.Contains(pType)) + return; + + if (pWHExt->KillWeapon_IgnoreTypes.size() > 0 && pWHExt->KillWeapon_IgnoreTypes.Contains(pType)) + return; + + if (pTypeExt->SuppressKillWeapons_Types.size() > 0 && pTypeExt->SuppressKillWeapons_Types.Contains(pWHExt->KillWeapon)) + return; + + if (EnumFunctions::IsTechnoEligible(pThis, pWHExt->KillWeapon_AffectTargets)) + WeaponTypeExt::DetonateAt(pWHExt->KillWeapon, pThis, pSource); +} diff --git a/src/Ext/TechnoType/Body.cpp b/src/Ext/TechnoType/Body.cpp index 06d15d6242..a200b0cc72 100644 --- a/src/Ext/TechnoType/Body.cpp +++ b/src/Ext/TechnoType/Body.cpp @@ -457,6 +457,9 @@ void TechnoTypeExt::ExtData::LoadFromINIFile(CCINIClass* const pINI) this->Wake_Grapple.Read(exINI, pSection, "Wake.Grapple"); this->Wake_Sinking.Read(exINI, pSection, "Wake.Sinking"); + this->SuppressKillWeapons.Read(exINI, pSection, "SuppressKillWeapons"); + this->SuppressKillWeapons_Types.Read(exINI, pSection, "SuppressKillWeapons.Types"); + // Ares 0.2 this->RadarJamRadius.Read(exINI, pSection, "RadarJamRadius"); @@ -827,6 +830,9 @@ void TechnoTypeExt::ExtData::Serialize(T& Stm) .Process(this->Wake) .Process(this->Wake_Grapple) .Process(this->Wake_Sinking) + + .Process(this->SuppressKillWeapons) + .Process(this->SuppressKillWeapons_Types) ; } void TechnoTypeExt::ExtData::LoadFromStream(PhobosStreamReader& Stm) diff --git a/src/Ext/TechnoType/Body.h b/src/Ext/TechnoType/Body.h index f6caad6729..3965d75e26 100644 --- a/src/Ext/TechnoType/Body.h +++ b/src/Ext/TechnoType/Body.h @@ -249,6 +249,9 @@ class TechnoTypeExt std::vector> DeployedWeaponBurstFLHs; std::vector> EliteDeployedWeaponBurstFLHs; + Valueable SuppressKillWeapons; + ValueableVector SuppressKillWeapons_Types; + ExtData(TechnoTypeClass* OwnerObject) : Extension(OwnerObject) , HealthBar_Hide { false } @@ -452,6 +455,9 @@ class TechnoTypeExt , Wake { } , Wake_Grapple { } , Wake_Sinking { } + + , SuppressKillWeapons { false } + , SuppressKillWeapons_Types {} { } virtual ~ExtData() = default; diff --git a/src/Ext/WarheadType/Body.cpp b/src/Ext/WarheadType/Body.cpp index 5a5e2febef..a5b58d1862 100644 --- a/src/Ext/WarheadType/Body.cpp +++ b/src/Ext/WarheadType/Body.cpp @@ -266,6 +266,12 @@ void WarheadTypeExt::ExtData::LoadFromINIFile(CCINIClass* const pINI) this->SuppressReflectDamage.Read(exINI, pSection, "SuppressReflectDamage"); this->SuppressReflectDamage_Types.Read(exINI, pSection, "SuppressReflectDamage.Types"); + this->KillWeapon.Read(exINI, pSection, "KillWeapon"); + this->KillWeapon_AffectTargets.Read(exINI, pSection, "KillWeapon.AffectTargets"); + this->KillWeapon_AffectHouses.Read(exINI, pSection, "KillWeapon.AffectHouses"); + this->KillWeapon_AffectTypes.Read(exINI, pSection, "KillWeapon.AffectTypes"); + this->KillWeapon_IgnoreTypes.Read(exINI, pSection, "KillWeapon.IgnoreTypes"); + // Convert.From & Convert.To TypeConvertGroup::Parse(this->Convert_Pairs, exINI, pSection, AffectedHouse::All); @@ -489,6 +495,12 @@ void WarheadTypeExt::ExtData::Serialize(T& Stm) .Process(this->CLIsBlack) .Process(this->Particle_AlphaImageIsLightFlash) + .Process(this->KillWeapon) + .Process(this->KillWeapon_AffectTargets) + .Process(this->KillWeapon_AffectHouses) + .Process(this->KillWeapon_AffectTypes) + .Process(this->KillWeapon_IgnoreTypes) + // Ares tags .Process(this->AffectsEnemies) .Process(this->AffectsOwner) diff --git a/src/Ext/WarheadType/Body.h b/src/Ext/WarheadType/Body.h index b5331a9ada..8d2edf0e4a 100644 --- a/src/Ext/WarheadType/Body.h +++ b/src/Ext/WarheadType/Body.h @@ -150,6 +150,12 @@ class WarheadTypeExt Valueable SuppressReflectDamage; ValueableVector SuppressReflectDamage_Types; + Valueable KillWeapon; + Valueable KillWeapon_AffectTargets; + Valueable KillWeapon_AffectHouses; + ValueableVector KillWeapon_AffectTypes; + ValueableVector KillWeapon_IgnoreTypes; + // Ares tags // http://ares-developers.github.io/Ares-docs/new/warheads/general.html Valueable AffectsEnemies; @@ -316,6 +322,12 @@ class WarheadTypeExt , RemainingAnimCreationInterval { 0 } , PossibleCellSpreadDetonate { false } , DamageAreaTarget {} + + , KillWeapon {} + , KillWeapon_AffectTargets { AffectedTarget::All } + , KillWeapon_AffectHouses { AffectedHouse::All } + , KillWeapon_AffectTypes {} + , KillWeapon_IgnoreTypes {} { } void ApplyConvert(HouseClass* pHouse, TechnoClass* pTarget);