diff --git a/CREDITS.md b/CREDITS.md index 5ce6300134..a6787a4098 100644 --- a/CREDITS.md +++ b/CREDITS.md @@ -512,6 +512,7 @@ This page lists all the individual contributions to the project by their author. - Fix the bug that the upgrade building's power-enhancing effect depends only on its parent building and is not related to the upgrade building itself - Customize which parasite can remove by warhead - Fix the bug that unit will play crashing voice & sound when dropped by warhead with `IsLocomotor=yes` + - Add toggle of whether shield use ArmorMultiplier or not - **Apollo** - Translucent SHP drawing patches - **ststl**: - Customizable `ShowTimer` priority of superweapons diff --git a/YRpp b/YRpp index 38bf9ecb6b..66e688c83b 160000 --- a/YRpp +++ b/YRpp @@ -1 +1 @@ -Subproject commit 38bf9ecb6bf77e365feac0ec29f453ab9be29527 +Subproject commit 66e688c83b9df8be78b3500ac3563fb1f6cd846f diff --git a/docs/New-or-Enhanced-Logics.md b/docs/New-or-Enhanced-Logics.md index 9152efbd09..5ea6648726 100644 --- a/docs/New-or-Enhanced-Logics.md +++ b/docs/New-or-Enhanced-Logics.md @@ -304,6 +304,9 @@ Laser trails are very resource intensive! Due to the game not utilizing GPU havi In `rulesmd.ini`: ```ini +[CombatDamage] +ShieldApplyArmorMult=false ; boolean + [AudioVisual] Shield.ConditionYellow= ; floating point value, percents or absolute Shield.ConditionRed= ; floating point value, percents or absolute @@ -324,6 +327,7 @@ Armor=none ; ArmorType InheritArmorFromTechno=false ; boolean InheritArmor.Allowed= ; List of TechnoTypes InheritArmor.Disallowed= ; List of TechnoTypes +ApplyArmorMult= ; boolean, default to [CombatDamage] -> ShieldApplyArmorMult Powered=false ; boolean AbsorbOverDamage=false ; boolean SelfHealing=0.0 ; floating point value, percents or absolute @@ -424,6 +428,7 @@ Shield.InheritStateOnReplace=false ; boolean - `InheritArmorFromTechno` can be set to true to override this so that `[TechnoType] -> Armor` is used even if shield is active and `[ShieldType] -> Armor` is ignored. - `InheritArmor.Allowed` lists TechnoTypes whose armor can be overridden. If empty, any TechnoType not listed in `InheritArmor.Disallowed` is okay. - `InheritArmor.Disallowed` lists TechnoTypes whose armor can't be overridden. If empty, any TechnoTypes are okay as long as `InheritArmor.Allowed` is empty or they are listed on it. + - `ApplyArmorMult` can be set to true to allow the shield to benefit from the armor multiplier. - `InitialStrength` can be used to set a different initial strength value from maximum. - `ConditionYellow` and `ConditionRed` can be used to set the thresholds for shield damage states, defaulting to `[AudioVisual] -> Shield.ConditionYellow & Shield.ConditionRed` respectively which in turn default to just `ConditionYellow & ConditionRed`. - When executing `DeploysInto` or `UndeploysInto`, if both of the TechnoTypes have shields, the transformed unit/building would keep relative shield health (in percents), same as with `Strength`. If one of the TechnoTypes doesn't have shields, it's shield's state on conversion will be preserved until converted back. diff --git a/docs/Whats-New.md b/docs/Whats-New.md index 17dc534d58..1841ed9ea1 100644 --- a/docs/Whats-New.md +++ b/docs/Whats-New.md @@ -552,6 +552,7 @@ New: - [SHP turret vehicles support the use of `*tur.shp` files](New-or-Enhanced-Logics.md#independent-shp-vehicle-turret-files) (by FlyStar) - [Implement `CurleyShuffle` for AircraftTypes](Fixed-or-Improved-Logics.md#implement-curleyshuffle-for-aircrafttypes) (ported from Vinifera by Noble_Fish) - Customize which parasite can remove by warhead (by NetsuNegi) +- Add toggle of whether shield use ArmorMultiplier or not (by NetsuNegi) Vanilla fixes: - Fixed sidebar not updating queued unit numbers when adding or removing units when the production is on hold (by CrimRecya) diff --git a/docs/locale/zh_CN/LC_MESSAGES/CREDITS.po b/docs/locale/zh_CN/LC_MESSAGES/CREDITS.po index 65f897808a..3993d8c689 100644 --- a/docs/locale/zh_CN/LC_MESSAGES/CREDITS.po +++ b/docs/locale/zh_CN/LC_MESSAGES/CREDITS.po @@ -1666,6 +1666,11 @@ msgid "Fix the bug that unit will play crashing voice & sound when dropped by " "warhead with `IsLocomotor=yes`" msgstr "修复了载具被 `IsLocomotor=yes` 的弹头丢下时会播放坠毁语音和音效的 Bug" +msgid "" +"Add toggle of whether shield use ArmorMultiplier or not" +msgstr "" +"添加了护盾是否使用护甲倍率的开关" + msgid "**Apollo** - Translucent SHP drawing patches" msgstr "**Apollo** - 半透明 SHP 绘制补丁" diff --git a/docs/locale/zh_CN/LC_MESSAGES/New-or-Enhanced-Logics.po b/docs/locale/zh_CN/LC_MESSAGES/New-or-Enhanced-Logics.po index 260f635c3a..145a9421f6 100644 --- a/docs/locale/zh_CN/LC_MESSAGES/New-or-Enhanced-Logics.po +++ b/docs/locale/zh_CN/LC_MESSAGES/New-or-Enhanced-Logics.po @@ -815,6 +815,12 @@ msgstr "" "`InheritArmor.Disallowed` 列出了其护甲不可被覆盖的科技类型。如果为空,则相当于任何科技类型都可以被覆盖,只要 " "`InheritArmor.Allowed` 为空或者这些科技类型列在该列表中。" +msgid "" +"`ApplyArmorMult` can be set to true to allow the shield to benefit " +"from the armor multiplier." +msgstr "" +"ApplyArmorMult` 可设为 true 以允许护盾享受护甲倍率。" + msgid "" "`InitialStrength` can be used to set a different initial strength value " "from maximum." diff --git a/docs/locale/zh_CN/LC_MESSAGES/Whats-New.po b/docs/locale/zh_CN/LC_MESSAGES/Whats-New.po index 1e71dcdfc5..9e93d848ef 100644 --- a/docs/locale/zh_CN/LC_MESSAGES/Whats-New.po +++ b/docs/locale/zh_CN/LC_MESSAGES/Whats-New.po @@ -1749,6 +1749,8 @@ msgid "" msgstr "" "[实现战机微观 `CurleyShuffle` 设置](Fixed-or-Improved-Logics.md#implement-" "curleyshuffle-for-aircrafttypes)(由 Noble_Fish 移植自 Vinifera)" +msgid "Add toggle of whether shield use ArmorMultiplier or not (by NetsuNegi)" +msgstr "添加了护盾是否使用护甲倍率的开关(by NetsuNegi)" msgid "Customize which parasite can remove by warhead (by NetsuNegi)" msgstr "自定义哪些寄生者可被弹头移除(by NetsuNegi)" diff --git a/src/Ext/Rules/Body.cpp b/src/Ext/Rules/Body.cpp index 6850ce6ee1..8bb4eb9602 100644 --- a/src/Ext/Rules/Body.cpp +++ b/src/Ext/Rules/Body.cpp @@ -104,6 +104,7 @@ void RulesExt::ExtData::LoadBeforeTypeData(RulesClass* pThis, CCINIClass* pINI) this->RadSiteWarhead_Detonate_Full.Read(exINI, GameStrings::Radiation, "RadSiteWarhead.Detonate.Full"); this->RadHasOwner.Read(exINI, GameStrings::Radiation, "RadHasOwner"); this->RadHasInvoker.Read(exINI, GameStrings::Radiation, "RadHasInvoker"); + this->ShieldApplyArmorMult.Read(exINI, GameStrings::CombatDamage, "ShieldApplyArmorMult"); this->VeinholeWarhead.Read(exINI, GameStrings::CombatDamage, "VeinholeWarhead"); this->MissingCameo.Read(pINI, GameStrings::AudioVisual, "MissingCameo"); @@ -468,6 +469,7 @@ void RulesExt::ExtData::Serialize(T& Stm) .Process(this->RadSiteWarhead_Detonate_Full) .Process(this->RadHasOwner) .Process(this->RadHasInvoker) + .Process(this->ShieldApplyArmorMult) .Process(this->JumpjetCrash) .Process(this->JumpjetNoWobbles) .Process(this->VeinholeWarhead) diff --git a/src/Ext/Rules/Body.h b/src/Ext/Rules/Body.h index ca624cd9ae..ee0f33d1ff 100644 --- a/src/Ext/Rules/Body.h +++ b/src/Ext/Rules/Body.h @@ -51,6 +51,7 @@ class RulesExt Valueable RadSiteWarhead_Detonate_Full; Valueable RadHasOwner; Valueable RadHasInvoker; + Valueable ShieldApplyArmorMult; Valueable JumpjetCrash; Valueable JumpjetNoWobbles; @@ -346,6 +347,7 @@ class RulesExt , RadSiteWarhead_Detonate_Full { true } , RadHasOwner { false } , RadHasInvoker { false } + , ShieldApplyArmorMult { false } , JumpjetCrash { 5.0 } , JumpjetNoWobbles { false } , VeinholeWarhead {} diff --git a/src/Ext/Techno/Body.h b/src/Ext/Techno/Body.h index 876a090c86..243545972c 100644 --- a/src/Ext/Techno/Body.h +++ b/src/Ext/Techno/Body.h @@ -267,6 +267,7 @@ class TechnoExt static void UpdateSharedAmmo(TechnoClass* pThis); static double GetCurrentSpeedMultiplier(FootClass* pThis); static double GetCurrentFirepowerMultiplier(TechnoClass* pThis); + static double CalculateArmorMultipliers(TechnoClass* pThis, WarheadTypeClass* pWarhead); static void DrawSelfHealPips(TechnoClass* pThis, Point2D* pLocation, RectangleStruct* pBounds); static void DrawInsignia(TechnoClass* pThis, Point2D* pLocation, RectangleStruct* pBounds); static void ApplyGainedSelfHeal(TechnoClass* pThis); diff --git a/src/Ext/Techno/Hooks.cpp b/src/Ext/Techno/Hooks.cpp index 6b4ed3a50d..0c033b2846 100644 --- a/src/Ext/Techno/Hooks.cpp +++ b/src/Ext/Techno/Hooks.cpp @@ -452,7 +452,7 @@ DEFINE_HOOK(0x4DB218, FootClass_GetMovementSpeed_SpeedMultiplier, 0x6) return 0; } -static int CalculateArmorMultipliers(TechnoClass* pThis, int damage, WarheadTypeClass* pWarhead) +double TechnoExt::CalculateArmorMultipliers(TechnoClass* pThis, WarheadTypeClass* pWarhead) { auto const pExt = TechnoExt::ExtMap.Find(pThis); double mult = pExt->AE.ArmorMultiplier; @@ -476,7 +476,7 @@ static int CalculateArmorMultipliers(TechnoClass* pThis, int damage, WarheadType } } - return static_cast(damage / mult); + return mult; } DEFINE_HOOK(0x6FDC87, TechnoClass_AdjustDamage_ArmorMultiplier, 0x6) @@ -485,7 +485,7 @@ DEFINE_HOOK(0x6FDC87, TechnoClass_AdjustDamage_ArmorMultiplier, 0x6) GET(const int, damage, EAX); GET_STACK(WeaponTypeClass*, pWeapon, STACK_OFFSET(0x18, 0x8)); - R->EAX(CalculateArmorMultipliers(pTarget, damage, pWeapon->Warhead)); + R->EAX(static_cast(damage / TechnoExt::CalculateArmorMultipliers(pTarget, pWeapon->Warhead))); return 0; } @@ -496,7 +496,7 @@ DEFINE_HOOK(0x701966, TechnoClass_ReceiveDamage_ArmorMultiplier, 0x6) GET(const int, damage, EAX); GET_STACK(WarheadTypeClass*, pWarhead, STACK_OFFSET(0xC4, 0xC)); - R->EAX(CalculateArmorMultipliers(pThis, damage, pWarhead)); + R->EAX(static_cast(damage / TechnoExt::CalculateArmorMultipliers(pThis, pWarhead))); return 0; } diff --git a/src/New/Entity/ShieldClass.cpp b/src/New/Entity/ShieldClass.cpp index 3e5e6d56df..b339f256fa 100644 --- a/src/New/Entity/ShieldClass.cpp +++ b/src/New/Entity/ShieldClass.cpp @@ -183,7 +183,7 @@ int ShieldClass::ReceiveDamage(args_ReceiveDamage* args) auto const pWHExt = WarheadTypeExt::ExtMap.Find(pWH); const bool IC = pWHExt->CanAffectInvulnerable(pTechno); - if (!IC || CanBePenetrated(pWH) || TechnoExt::IsTypeImmune(pTechno, args->Attacker)) + if (!IC || this->CanBePenetrated(pWH) || TechnoExt::IsTypeImmune(pTechno, args->Attacker)) return damage; auto const pTechnoType = pTechno->GetTechnoType(); @@ -194,14 +194,32 @@ int ShieldClass::ReceiveDamage(args_ReceiveDamage* args) int nDamage = 0; int shieldDamage = 0; int healthDamage = 0; + double armorMultiplier = 1.0; auto const pType = this->Type; if (pWHExt->CanTargetHouse(args->SourceHouse, pTechno) && !pWH->Temporal) { - if (damage > 0) - nDamage = MapClass::GetTotalDamage(damage, pWH, this->GetArmorType(pTechnoType), args->DistanceToEpicenter); + if (damage >= 0) + { + nDamage = damage; + + if (pType->ApplyArmorMult.Get(RulesExt::Global()->ShieldApplyArmorMult)) + { + armorMultiplier = pTechno->Owner->GetArmorMultiplier(pTechnoType) * pTechno->ArmorMultiplier; + + if (pTechno->HasAbility(Ability::Stronger)) + armorMultiplier *= RulesClass::Instance->VeteranArmor; + + armorMultiplier *= TechnoExt::CalculateArmorMultipliers(pTechno, pWH); + nDamage = Math::max(static_cast(nDamage / armorMultiplier), 0); + } + + nDamage = MapClass::GetTotalDamage(nDamage, pWH, this->GetArmorType(pTechnoType), args->DistanceToEpicenter); + } else + { nDamage = -MapClass::GetTotalDamage(-damage, pWH, this->GetArmorType(pTechnoType), args->DistanceToEpicenter); + } const bool affectsShield = pWHExt->Shield_AffectTypes.size() <= 0 || pWHExt->Shield_AffectTypes.Contains(pType); const double absorbPercent = affectsShield ? pWHExt->Shield_AbsorbPercent.Get(pType->AbsorbPercent) : pType->AbsorbPercent; @@ -253,12 +271,17 @@ int ShieldClass::ReceiveDamage(args_ReceiveDamage* args) if (residueDamage >= 0) { - const int actualResidueDamage = Math::max(0, int((double)(originalShieldDamage - health) / + if (pType->AbsorbOverDamage) + { + this->BreakShield(pWHExt->Shield_BreakAnim, pWHExt->Shield_BreakWeapon.Get(nullptr)); + return healthDamage; + } + + const int actualResidueDamage = Math::max(0, int((double)(originalShieldDamage - health) * armorMultiplier / GeneralUtils::GetWarheadVersusArmor(pWH, this->GetArmorType(pTechnoType)))); //only absord percentage damage this->BreakShield(pWHExt->Shield_BreakAnim, pWHExt->Shield_BreakWeapon.Get(nullptr)); - - return pType->AbsorbOverDamage ? healthDamage : actualResidueDamage + healthDamage; + return actualResidueDamage + healthDamage; } else { diff --git a/src/New/Type/ShieldTypeClass.cpp b/src/New/Type/ShieldTypeClass.cpp index 591e643e4e..0026bef43f 100644 --- a/src/New/Type/ShieldTypeClass.cpp +++ b/src/New/Type/ShieldTypeClass.cpp @@ -23,6 +23,7 @@ void ShieldTypeClass::LoadFromINI(CCINIClass* pINI) this->InheritArmorFromTechno.Read(exINI, pSection, "InheritArmorFromTechno"); this->InheritArmor_Allowed.Read(exINI, pSection, "InheritArmor.Allowed"); this->InheritArmor_Disallowed.Read(exINI, pSection, "InheritArmor.Disallowed"); + this->ApplyArmorMult.Read(exINI, pSection, "ApplyArmorMult"); this->Powered.Read(exINI, pSection, "Powered"); this->Respawn.Read(exINI, pSection, "Respawn"); @@ -99,6 +100,7 @@ void ShieldTypeClass::Serialize(T& Stm) .Process(this->InheritArmorFromTechno) .Process(this->InheritArmor_Allowed) .Process(this->InheritArmor_Disallowed) + .Process(this->ApplyArmorMult) .Process(this->Powered) .Process(this->Respawn) .Process(this->Respawn_Rate) diff --git a/src/New/Type/ShieldTypeClass.h b/src/New/Type/ShieldTypeClass.h index da4574ef35..7f358ecf9e 100644 --- a/src/New/Type/ShieldTypeClass.h +++ b/src/New/Type/ShieldTypeClass.h @@ -15,6 +15,7 @@ class ShieldTypeClass final : public Enumerable Valueable InheritArmorFromTechno; ValueableVector InheritArmor_Allowed; ValueableVector InheritArmor_Disallowed; + Nullable ApplyArmorMult; Valueable Powered; Valueable Respawn; Valueable Respawn_Rate; @@ -72,6 +73,7 @@ class ShieldTypeClass final : public Enumerable , InheritArmorFromTechno { false } , InheritArmor_Allowed { } , InheritArmor_Disallowed { } + , ApplyArmorMult {} , Powered { false } , Respawn { 0.0 } , Respawn_Rate { 0 }