diff --git a/CREDITS.md b/CREDITS.md index cb70d9e728..96eed675df 100644 --- a/CREDITS.md +++ b/CREDITS.md @@ -389,6 +389,7 @@ This page lists all the individual contributions to the project by their author. - New Parabola trajectory - Enhanced Bombard trajectory - No turret unit turn to the target + - Damage multiplier for different houses - **Ollerus** - Build limit group enhancement - Customizable rocker amplitude diff --git a/docs/New-or-Enhanced-Logics.md b/docs/New-or-Enhanced-Logics.md index a7823d05c2..60b5ae615a 100644 --- a/docs/New-or-Enhanced-Logics.md +++ b/docs/New-or-Enhanced-Logics.md @@ -1868,6 +1868,23 @@ In `rulesmd.ini`: NotHuman.DeathSequence= ; integer (1 to 5) ``` +### Damage multiplier for different houses + +- Warheads are now able to define the extra damage multiplier for owner house, ally houses and enemy houses. If the warhead's own `DamageXXMultiplier` are not set, these will default to respective `[CombatDamage]` -> `DamageXXMultiplier` which all default to 1.0 .Note that `DamageAlliesMultiplier` won't affect your own units like `AffectsAllies` did, and this function will not affect damage with ignore defenses like `Suicide`.etc . + +In `rulesmd.ini`: +```ini +[CombatDamage] +DamageOwnerMultiplier=1.0 ; floating point value +DamageAlliesMultiplier=1.0 ; floating point value +DamageEnemiesMultiplier=1.0 ; floating point value + +[SOMEWARHEAD] ; Warhead +DamageOwnerMultiplier= ; floating point value +DamageAlliesMultiplier= ; floating point value +DamageEnemiesMultiplier= ; floating point value +``` + ## Weapons ### AreaFire target customization diff --git a/docs/Whats-New.md b/docs/Whats-New.md index de27221e80..9c194da618 100644 --- a/docs/Whats-New.md +++ b/docs/Whats-New.md @@ -324,6 +324,8 @@ New: - Enhanced Bombard trajectory (by CrimRecya & Ollerus, based on knowledge of NaotoYuuki) - Toggle waypoint for building (by TaranDahl) - Bunkerable checks dehardcode (by TaranDahl) +- No turret unit turn to the target (by CrimRecya & TaranDahl) +- Damage multiplier for different houses (by CrimRecya) Vanilla fixes: - Prevent the units with locomotors that cause problems from entering the tank bunker (by TaranDahl) @@ -498,7 +500,6 @@ New: - Allow infantry to use land sequences in water (by Starkku) - `` 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) -- No turret unit turn to the target (by CrimRecya & TaranDahl) - Unit `Speed` setting now accepts floating point values (by Starkku) - Extending `Power` to all TechnoTypes (by Morton) diff --git a/src/Ext/Rules/Body.cpp b/src/Ext/Rules/Body.cpp index 2d44c88b75..b2f4efdddc 100644 --- a/src/Ext/Rules/Body.cpp +++ b/src/Ext/Rules/Body.cpp @@ -194,6 +194,10 @@ void RulesExt::ExtData::LoadBeforeTypeData(RulesClass* pThis, CCINIClass* pINI) this->Vehicles_DefaultDigitalDisplayTypes.Read(exINI, GameStrings::AudioVisual, "Vehicles.DefaultDigitalDisplayTypes"); this->Aircraft_DefaultDigitalDisplayTypes.Read(exINI, GameStrings::AudioVisual, "Aircraft.DefaultDigitalDisplayTypes"); + this->DamageOwnerMultiplier.Read(exINI, GameStrings::CombatDamage, "DamageOwnerMultiplier"); + this->DamageAlliesMultiplier.Read(exINI, GameStrings::CombatDamage, "DamageAlliesMultiplier"); + this->DamageEnemiesMultiplier.Read(exINI, GameStrings::CombatDamage, "DamageEnemiesMultiplier"); + this->AircraftLevelLightMultiplier.Read(exINI, GameStrings::AudioVisual, "AircraftLevelLightMultiplier"); this->JumpjetLevelLightMultiplier.Read(exINI, GameStrings::AudioVisual, "JumpjetLevelLightMultiplier"); @@ -401,6 +405,9 @@ void RulesExt::ExtData::Serialize(T& Stm) .Process(this->ShowDesignatorRange) .Process(this->DropPodTrailer) .Process(this->PodImage) + .Process(this->DamageOwnerMultiplier) + .Process(this->DamageAlliesMultiplier) + .Process(this->DamageEnemiesMultiplier) .Process(this->AircraftLevelLightMultiplier) .Process(this->JumpjetLevelLightMultiplier) .Process(this->VoxelLightSource) diff --git a/src/Ext/Rules/Body.h b/src/Ext/Rules/Body.h index 2cb06e5f33..27178cac50 100644 --- a/src/Ext/Rules/Body.h +++ b/src/Ext/Rules/Body.h @@ -154,6 +154,10 @@ class RulesExt Valueable Promote_VeteranAnimation; Valueable Promote_EliteAnimation; + Valueable DamageOwnerMultiplier; + Valueable DamageAlliesMultiplier; + Valueable DamageEnemiesMultiplier; + Valueable AircraftLevelLightMultiplier; Valueable JumpjetLevelLightMultiplier; @@ -171,7 +175,6 @@ class RulesExt Nullable> VoxelLightSource; // Nullable> VoxelShadowLightSource; Valueable UseFixedVoxelLighting; - Valueable NoTurret_TrackTarget; Valueable GatherWhenMCVDeploy; @@ -298,6 +301,9 @@ class RulesExt , ShowDesignatorRange { true } , DropPodTrailer { } , PodImage { } + , DamageOwnerMultiplier { 1.0 } + , DamageAlliesMultiplier { 1.0 } + , DamageEnemiesMultiplier { 1.0 } , AircraftLevelLightMultiplier { 1.0 } , JumpjetLevelLightMultiplier { 0.0 } , VoxelLightSource { } diff --git a/src/Ext/Techno/Hooks.ReceiveDamage.cpp b/src/Ext/Techno/Hooks.ReceiveDamage.cpp index 301e12faae..144255ee9b 100644 --- a/src/Ext/Techno/Hooks.ReceiveDamage.cpp +++ b/src/Ext/Techno/Hooks.ReceiveDamage.cpp @@ -21,32 +21,47 @@ DEFINE_HOOK(0x701900, TechnoClass_ReceiveDamage_Shield, 0x6) const auto pRules = RulesExt::Global(); const auto pExt = TechnoExt::ExtMap.Find(pThis); + const auto pTypeExt = pExt->TypeExtData; + const auto pType = pTypeExt->OwnerObject(); + const auto pWHExt = WarheadTypeExt::ExtMap.Find(args->WH); + int nDamageLeft = *args->Damage; + const auto pSourceHouse = args->SourceHouse; + const auto pTargetHouse = pThis->Owner; + + // Calculate Damage Multiplier + if (!args->IgnoreDefenses && *args->Damage) + { + double multiplier = 1.0; + + if (!pSourceHouse || !pTargetHouse || !pSourceHouse->IsAlliedWith(pTargetHouse)) + multiplier = pWHExt->DamageEnemiesMultiplier.Get(pRules->DamageEnemiesMultiplier); + else if (pSourceHouse != pTargetHouse) + multiplier = pWHExt->DamageAlliesMultiplier.Get(pRules->DamageAlliesMultiplier); + else + multiplier = pWHExt->DamageOwnerMultiplier.Get(pRules->DamageOwnerMultiplier); + + if (multiplier != 1.0) + { + const auto sgnDamage = *args->Damage > 0 ? 1 : -1; + const auto calculateDamage = static_cast(*args->Damage * multiplier); + *args->Damage = calculateDamage ? calculateDamage : sgnDamage; + } + } // Raise Combat Alert if (pRules->CombatAlert && nDamageLeft > 1) { auto raiseCombatAlert = [&]() { - const auto pHouse = pThis->Owner; - - if (!pHouse->IsControlledByCurrentPlayer() || (pRules->CombatAlert_SuppressIfAllyDamage && pHouse->IsAlliedWith(args->SourceHouse))) + if (!pTargetHouse->IsControlledByCurrentPlayer() || (pRules->CombatAlert_SuppressIfAllyDamage && pTargetHouse->IsAlliedWith(pSourceHouse))) return; - const auto pHouseExt = HouseExt::ExtMap.Find(pHouse); + const auto pHouseExt = HouseExt::ExtMap.Find(pTargetHouse); - if (pHouseExt->CombatAlertTimer.HasTimeLeft()) + if (pHouseExt->CombatAlertTimer.HasTimeLeft() || pWHExt->CombatAlert_Suppress.Get(!pWHExt->Malicious || pWHExt->Nonprovocative)) return; - - const auto pTypeExt = pExt->TypeExtData; - const auto pType = pTypeExt->OwnerObject(); - - if (!pTypeExt->CombatAlert.Get(pRules->CombatAlert_Default.Get(!pType->Insignificant && !pType->Spawned)) || !pThis->IsInPlayfield) - return; - - const auto pWHExt = WarheadTypeExt::ExtMap.Find(args->WH); - - if (pWHExt->CombatAlert_Suppress.Get(!pWHExt->Malicious || pWHExt->Nonprovocative)) + else if (!pTypeExt->CombatAlert.Get(pRules->CombatAlert_Default.Get(!pType->Insignificant && !pType->Spawned)) || !pThis->IsInPlayfield) return; const auto pBuilding = abstract_cast(pThis); diff --git a/src/Ext/WarheadType/Body.cpp b/src/Ext/WarheadType/Body.cpp index 8ba9b9967c..57c0e10a4f 100644 --- a/src/Ext/WarheadType/Body.cpp +++ b/src/Ext/WarheadType/Body.cpp @@ -261,6 +261,10 @@ void WarheadTypeExt::ExtData::LoadFromINIFile(CCINIClass* const pINI) this->CLIsBlack.Read(exINI, pSection, "CLIsBlack"); this->Particle_AlphaImageIsLightFlash.Read(exINI, pSection, "Particle.AlphaImageIsLightFlash"); + this->DamageOwnerMultiplier.Read(exINI, pSection, "DamageOwnerMultiplier"); + this->DamageAlliesMultiplier.Read(exINI, pSection, "DamageAlliesMultiplier"); + this->DamageEnemiesMultiplier.Read(exINI, pSection, "DamageEnemiesMultiplier"); + this->SuppressRevengeWeapons.Read(exINI, pSection, "SuppressRevengeWeapons"); this->SuppressRevengeWeapons_Types.Read(exINI, pSection, "SuppressRevengeWeapons.Types"); this->SuppressReflectDamage.Read(exINI, pSection, "SuppressReflectDamage"); @@ -485,6 +489,10 @@ void WarheadTypeExt::ExtData::Serialize(T& Stm) .Process(this->InflictLocomotor) .Process(this->RemoveInflictedLocomotor) + .Process(this->DamageOwnerMultiplier) + .Process(this->DamageAlliesMultiplier) + .Process(this->DamageEnemiesMultiplier) + .Process(this->Nonprovocative) .Process(this->CombatLightDetailLevel) diff --git a/src/Ext/WarheadType/Body.h b/src/Ext/WarheadType/Body.h index c55b0e1a84..b8c8c50721 100644 --- a/src/Ext/WarheadType/Body.h +++ b/src/Ext/WarheadType/Body.h @@ -145,6 +145,10 @@ class WarheadTypeExt Valueable CLIsBlack; Nullable Particle_AlphaImageIsLightFlash; + Nullable DamageOwnerMultiplier; + Nullable DamageAlliesMultiplier; + Nullable DamageEnemiesMultiplier; + Valueable SuppressRevengeWeapons; ValueableVector SuppressRevengeWeapons_Types; Valueable SuppressReflectDamage; @@ -300,6 +304,10 @@ class WarheadTypeExt , CLIsBlack { false } , Particle_AlphaImageIsLightFlash {} + , DamageOwnerMultiplier {} + , DamageAlliesMultiplier {} + , DamageEnemiesMultiplier {} + , SuppressRevengeWeapons { false } , SuppressRevengeWeapons_Types {} , SuppressReflectDamage { false }