From 08e9d2d7b5177dcd3bc201a6cee389edd1896185 Mon Sep 17 00:00:00 2001 From: obsidianus Date: Sun, 2 Aug 2026 13:59:05 +0800 Subject: [PATCH 1/7] Automatic conversion based on HP --- CREDITS.md | 2 ++ docs/New-or-Enhanced-Logics.md | 23 +++++++++++++++++++++++ docs/Whats-New.md | 1 + src/Ext/Techno/Body.Update.cpp | 27 +++++++++++++++++++++++++++ src/Ext/Techno/Body.h | 1 + src/Ext/Techno/Hooks.cpp | 1 + src/Ext/TechnoType/Body.cpp | 8 ++++++++ src/Ext/TechnoType/Body.h | 8 ++++++++ 8 files changed, 71 insertions(+) diff --git a/CREDITS.md b/CREDITS.md index 61295f2ce5..d0828150da 100644 --- a/CREDITS.md +++ b/CREDITS.md @@ -917,3 +917,5 @@ This page lists all the individual contributions to the project by their author. - **Chang_zhi**: - Interop export interface for accessing scenario local/global variables - Add `ClampToScreen` tag for `BannerType` to control whether banner position is clamped to the visible area +- **obsidianus** + - Automatic conversion based on HP diff --git a/docs/New-or-Enhanced-Logics.md b/docs/New-or-Enhanced-Logics.md index 1cef4bcfe4..c0131a38b0 100644 --- a/docs/New-or-Enhanced-Logics.md +++ b/docs/New-or-Enhanced-Logics.md @@ -1535,6 +1535,29 @@ This feature has the same limitations as [Ares' Type Conversion](https://ares-de This feature requires Ares 3.0 or higher to function! When Ares 3.0+ is not detected, not all properties of a unit may be updated. ``` +### Automatic conversion based on HP + +- Units can now be converted into another unit by HP. +- When a unit is damaged (health points percentage is lower than `[AudioVisual] -> ConditionYellow` percentage), it now may be converted to a different techno set by `Convert.YellowHP` VehicleType. +- Similar, `Convert.RedHP` is the new techno after the conversion if unit health points percentage is lower than `[AudioVisual] -> ConditionRed` percentage. +- `Convert.GreenHP` is the new techno after the conversion if unit health points percentage is higher than `[AudioVisual] -> ConditionYellow` percentage. + +In `rulesmd.ini`: +```ini +[SOMEVEHICLE] ; TechnoType, before conversion +Convert.GreenHP= ; TechnoType, after conversion +Convert.YellowHP= ; TechnoType, after conversion +Convert.RedHP= ; TechnoType, after conversion +``` + +```{warning} +This feature has the same limitations as [Ares' Type Conversion](https://ares-developers.github.io/Ares-docs/new/typeconversion.html). This feature does not support BuildingTypes. +``` + +```{warning} +This feature requires Ares 3.0 or higher to function! When Ares 3.0+ is not detected, not all properties of a unit may be updated. +``` + ### Automatic passenger deletion - Transports can erase passengers over time. Passengers are deleted in order of entering the transport, from first to last. diff --git a/docs/Whats-New.md b/docs/Whats-New.md index 5562162d1a..d73f1f49c5 100644 --- a/docs/Whats-New.md +++ b/docs/Whats-New.md @@ -646,6 +646,7 @@ HideShakeEffects=false ; boolean - Separately define the global default values of TerrainTypes' `IsPassable` and `CanBeBuiltOn` based on `SpawnsTiberium` (by Noble_Fish) - Customize reveal radius of `RevealToAll` (by NetsuNegi) - [Customize whether aircraft is a cargo plane](Fixed-or-Improved-Logics.md#customize-whether-aircraft-is-a-cargo-plane) (by TaranDahl) +- [Automatic conversion based on HP](New-or-Enhanced-Logics.md#automatic-conversion-based-on-hp) (by obsidianus) #### 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/src/Ext/Techno/Body.Update.cpp b/src/Ext/Techno/Body.Update.cpp index f64b487144..7483af1f0d 100644 --- a/src/Ext/Techno/Body.Update.cpp +++ b/src/Ext/Techno/Body.Update.cpp @@ -160,6 +160,33 @@ void TechnoExt::AmmoAutoConvertActions() } } +void TechnoExt::AutoConvertActions() +{ + const auto pTypeExt = this->TypeExtData; + const auto pFoot = abstract_cast(this->OwnerObject()); + if (pFoot->IsGreenHP()) + { + if (const auto convertType = pTypeExt->Convert_GreenHP) + { + TechnoExt::ConvertToType(pFoot, convertType); + } + } + else if (pFoot->IsYellowHP()) + { + if (const auto convertType = pTypeExt->Convert_YellowHP) + { + TechnoExt::ConvertToType(pFoot, convertType); + } + } + else if (pFoot->IsRedHP()) + { + if (const auto convertType = pTypeExt->Convert_RedHP) + { + TechnoExt::ConvertToType(pFoot, convertType); + } + } +} + // TODO : Merge into new AttachEffects bool TechnoExt::CheckDeathConditions(bool isInLimbo) { diff --git a/src/Ext/Techno/Body.h b/src/Ext/Techno/Body.h index d8aaac7fa7..650772cc93 100644 --- a/src/Ext/Techno/Body.h +++ b/src/Ext/Techno/Body.h @@ -179,6 +179,7 @@ class TechnoExt : public RadioExt, public Detach::Listener void ResetDelayedFireTimer(); void UpdateTintValues(); + void AutoConvertActions(); void AmmoAutoConvertActions(); void UpdateLastTargetCrd(); int GetSight(); diff --git a/src/Ext/Techno/Hooks.cpp b/src/Ext/Techno/Hooks.cpp index 1f0a256ce3..09775cad57 100644 --- a/src/Ext/Techno/Hooks.cpp +++ b/src/Ext/Techno/Hooks.cpp @@ -46,6 +46,7 @@ DEFINE_HOOK(0x4DA54E, FootClass_AI, 0x6) pExt->UpdateWarpInDelay(); pExt->UpdateTiberiumEater(); pExt->AmmoAutoConvertActions(); + pExt->AutoConvertActions(); if (pExt->AttackMoveFollowerTempCount) pExt->AttackMoveFollowerTempCount--; diff --git a/src/Ext/TechnoType/Body.cpp b/src/Ext/TechnoType/Body.cpp index 760b6e7907..ec1f328a7a 100644 --- a/src/Ext/TechnoType/Body.cpp +++ b/src/Ext/TechnoType/Body.cpp @@ -1146,6 +1146,10 @@ void TechnoTypeExt::LoadFromINIFile(CCINIClass* const pINI) // Ares 3.0 this->Unsellable.Read(exINI, pSection, "Unsellable"); + this->Convert_GreenHP.Read(exINI, pSection, "Convert.GreenHP"); + this->Convert_YellowHP.Read(exINI, pSection, "Convert.YellowHP"); + this->Convert_RedHP.Read(exINI, pSection, "Convert.RedHP"); + if (pThis->Gunner) { size_t weaponCount = pThis->WeaponCount; @@ -1739,6 +1743,10 @@ void TechnoTypeExt::Serialize(T& Stm) .Process(this->Unsellable) + .Process(this->Convert_GreenHP) + .Process(this->Convert_YellowHP) + .Process(this->Convert_RedHP) + .Process(this->ExtraThreat_Enabled) .Process(this->ExtraThreat_IsThreat) .Process(this->AlwaysConsideredThreat) diff --git a/src/Ext/TechnoType/Body.h b/src/Ext/TechnoType/Body.h index 01a283b49c..767f658f19 100644 --- a/src/Ext/TechnoType/Body.h +++ b/src/Ext/TechnoType/Body.h @@ -430,6 +430,10 @@ class TechnoTypeExt : public ObjectTypeExt Nullable Unsellable; // Ares 3.0 + Nullable Convert_GreenHP; + Nullable Convert_YellowHP; + Nullable Convert_RedHP; + TechnoTypeExt(TechnoTypeClass* OwnerObject) : ObjectTypeExt(OwnerObject) , HealthBar_Hide { false } , HealthBar_HidePips { false } @@ -799,6 +803,10 @@ class TechnoTypeExt : public ObjectTypeExt , Unsellable {} + , Convert_GreenHP {} + , Convert_YellowHP {} + , Convert_RedHP {} + , ExtraThreat_Enabled { false } , ExtraThreat_IsThreat {} , AlwaysConsideredThreat { false } From d05e179b126b6f1b78a51f253a9c4d3430c50e72 Mon Sep 17 00:00:00 2001 From: obsidianus Date: Sun, 2 Aug 2026 18:20:01 +0800 Subject: [PATCH 2/7] Fix --- docs/New-or-Enhanced-Logics.md | 13 +++++++------ src/Ext/Techno/Body.Update.cpp | 33 ++++++++++++++++++--------------- src/Ext/TechnoType/Body.cpp | 12 ++++++------ src/Ext/TechnoType/Body.h | 12 ++++++------ 4 files changed, 37 insertions(+), 33 deletions(-) diff --git a/docs/New-or-Enhanced-Logics.md b/docs/New-or-Enhanced-Logics.md index c0131a38b0..4448a5c455 100644 --- a/docs/New-or-Enhanced-Logics.md +++ b/docs/New-or-Enhanced-Logics.md @@ -1538,16 +1538,17 @@ This feature requires Ares 3.0 or higher to function! When Ares 3.0+ is not dete ### Automatic conversion based on HP - Units can now be converted into another unit by HP. -- When a unit is damaged (health points percentage is lower than `[AudioVisual] -> ConditionYellow` percentage), it now may be converted to a different techno set by `Convert.YellowHP` VehicleType. -- Similar, `Convert.RedHP` is the new techno after the conversion if unit health points percentage is lower than `[AudioVisual] -> ConditionRed` percentage. -- `Convert.GreenHP` is the new techno after the conversion if unit health points percentage is higher than `[AudioVisual] -> ConditionYellow` percentage. +- `Convert.HP.Min`determines the minimal HP at which a unit converts automatically after the HP update. +- `Convert.HP.Max`determines the maximum HP at which a unit converts automatically after the HP update. +- `Convert.HP` specify the new techno after the conversion. This unit must be of the same type of the original (infantry -> infantry, vehicle -> vehicle or aircraft -> aircraft). +- Setting a negative number will disable the HP check, and when both checks are disabled, conversion will not occur. In `rulesmd.ini`: ```ini [SOMEVEHICLE] ; TechnoType, before conversion -Convert.GreenHP= ; TechnoType, after conversion -Convert.YellowHP= ; TechnoType, after conversion -Convert.RedHP= ; TechnoType, after conversion +Convert.HP.Min= ; floating point value, percents or absolute +Convert.HP.Max= ; floating point value, percents or absolute +Convert.HP= ; TechnoType, after conversion ``` ```{warning} diff --git a/src/Ext/Techno/Body.Update.cpp b/src/Ext/Techno/Body.Update.cpp index 7483af1f0d..1d3cf6b65a 100644 --- a/src/Ext/Techno/Body.Update.cpp +++ b/src/Ext/Techno/Body.Update.cpp @@ -164,26 +164,29 @@ void TechnoExt::AutoConvertActions() { const auto pTypeExt = this->TypeExtData; const auto pFoot = abstract_cast(this->OwnerObject()); - if (pFoot->IsGreenHP()) + + if (!pTypeExt->Convert_HP.isset()) { - if (const auto convertType = pTypeExt->Convert_GreenHP) - { - TechnoExt::ConvertToType(pFoot, convertType); - } + return; } - else if (pFoot->IsYellowHP()) + + const double min = pTypeExt->Convert_HP_Min; + const double max = pTypeExt->Convert_HP_Max; + + if (min < 0.0 && max < 0.0) { - if (const auto convertType = pTypeExt->Convert_YellowHP) - { - TechnoExt::ConvertToType(pFoot, convertType); - } + return; } - else if (pFoot->IsRedHP()) + + const auto hp = pFoot->GetHealthPercentage(); + if (hp <= 0.0) { - if (const auto convertType = pTypeExt->Convert_RedHP) - { - TechnoExt::ConvertToType(pFoot, convertType); - } + return; + } + + if ((min < 0.0 || hp >= min) && (max < 0.0 || hp <= max)) + { + TechnoExt::ConvertToType(pFoot, pTypeExt->Convert_HP); } } diff --git a/src/Ext/TechnoType/Body.cpp b/src/Ext/TechnoType/Body.cpp index ec1f328a7a..0793fb0d18 100644 --- a/src/Ext/TechnoType/Body.cpp +++ b/src/Ext/TechnoType/Body.cpp @@ -1146,9 +1146,9 @@ void TechnoTypeExt::LoadFromINIFile(CCINIClass* const pINI) // Ares 3.0 this->Unsellable.Read(exINI, pSection, "Unsellable"); - this->Convert_GreenHP.Read(exINI, pSection, "Convert.GreenHP"); - this->Convert_YellowHP.Read(exINI, pSection, "Convert.YellowHP"); - this->Convert_RedHP.Read(exINI, pSection, "Convert.RedHP"); + this->Convert_HP_Min.Read(exINI, pSection, "Convert.HP.Min"); + this->Convert_HP_Max.Read(exINI, pSection, "Convert.HP.Max"); + this->Convert_HP.Read(exINI, pSection, "Convert.HP"); if (pThis->Gunner) { @@ -1743,9 +1743,9 @@ void TechnoTypeExt::Serialize(T& Stm) .Process(this->Unsellable) - .Process(this->Convert_GreenHP) - .Process(this->Convert_YellowHP) - .Process(this->Convert_RedHP) + .Process(this->Convert_HP_Min) + .Process(this->Convert_HP_Max) + .Process(this->Convert_HP) .Process(this->ExtraThreat_Enabled) .Process(this->ExtraThreat_IsThreat) diff --git a/src/Ext/TechnoType/Body.h b/src/Ext/TechnoType/Body.h index 767f658f19..f21d1eb233 100644 --- a/src/Ext/TechnoType/Body.h +++ b/src/Ext/TechnoType/Body.h @@ -430,9 +430,9 @@ class TechnoTypeExt : public ObjectTypeExt Nullable Unsellable; // Ares 3.0 - Nullable Convert_GreenHP; - Nullable Convert_YellowHP; - Nullable Convert_RedHP; + Valueable Convert_HP_Min; + Valueable Convert_HP_Max; + Nullable Convert_HP; TechnoTypeExt(TechnoTypeClass* OwnerObject) : ObjectTypeExt(OwnerObject) , HealthBar_Hide { false } @@ -803,9 +803,9 @@ class TechnoTypeExt : public ObjectTypeExt , Unsellable {} - , Convert_GreenHP {} - , Convert_YellowHP {} - , Convert_RedHP {} + , Convert_HP_Min {-1} + , Convert_HP_Max {-1} + , Convert_HP {} , ExtraThreat_Enabled { false } , ExtraThreat_IsThreat {} From 5c283ff1efa480520435398c792684e4f20992af Mon Sep 17 00:00:00 2001 From: Coronia <2217891145@qq.com> Date: Sun, 2 Aug 2026 22:39:28 +0800 Subject: [PATCH 3/7] update --- docs/New-or-Enhanced-Logics.md | 18 +++++------ src/Ext/Foot/Body.cpp | 42 +++++++++++++++++++++++++ src/Ext/Foot/Body.h | 2 ++ src/Ext/Techno/Body.Update.cpp | 56 ---------------------------------- src/Ext/Techno/Body.h | 3 -- src/Ext/Techno/Hooks.cpp | 2 +- src/Ext/TechnoType/Body.cpp | 19 +++++++----- src/Ext/TechnoType/Body.h | 16 +++++----- 8 files changed, 73 insertions(+), 85 deletions(-) diff --git a/docs/New-or-Enhanced-Logics.md b/docs/New-or-Enhanced-Logics.md index 4448a5c455..290f767d9b 100644 --- a/docs/New-or-Enhanced-Logics.md +++ b/docs/New-or-Enhanced-Logics.md @@ -1535,20 +1535,20 @@ This feature has the same limitations as [Ares' Type Conversion](https://ares-de This feature requires Ares 3.0 or higher to function! When Ares 3.0+ is not detected, not all properties of a unit may be updated. ``` -### Automatic conversion based on HP +### Automatic conversion based on health -- Units can now be converted into another unit by HP. -- `Convert.HP.Min`determines the minimal HP at which a unit converts automatically after the HP update. -- `Convert.HP.Max`determines the maximum HP at which a unit converts automatically after the HP update. -- `Convert.HP` specify the new techno after the conversion. This unit must be of the same type of the original (infantry -> infantry, vehicle -> vehicle or aircraft -> aircraft). +- Units can now be converted into another unit by health percentage. +- `Convert.Health.AbovePercent`determines the minimal health percentage at which a unit converts automatically. +- `Convert.Health.BelowPercent`determines the maximum health percentage at which a unit converts automatically. +- `Convert.Health` specify the new techno after the conversion. This unit must be of the same type of the original (infantry -> infantry, vehicle -> vehicle or aircraft -> aircraft). - Setting a negative number will disable the HP check, and when both checks are disabled, conversion will not occur. In `rulesmd.ini`: ```ini -[SOMEVEHICLE] ; TechnoType, before conversion -Convert.HP.Min= ; floating point value, percents or absolute -Convert.HP.Max= ; floating point value, percents or absolute -Convert.HP= ; TechnoType, after conversion +[SOMETECHNO] ; TechnoType, before conversion +Convert.Health.AbovePercent=-1.0 ; floating point value, percents or absolute +Convert.Health.BelowPercent=-1.0 ; floating point value, percents or absolute +Convert.Health= ; TechnoType, after conversion ``` ```{warning} diff --git a/src/Ext/Foot/Body.cpp b/src/Ext/Foot/Body.cpp index 4114bb1abc..5cc7a35959 100644 --- a/src/Ext/Foot/Body.cpp +++ b/src/Ext/Foot/Body.cpp @@ -813,6 +813,48 @@ void FootExt::UpdateTypeData(TechnoTypeClass* pCurrentType) } } +void FootExt::AmmoAutoConvertActions() +{ + const auto pTypeExt = this->TypeExtData; + + if (!pTypeExt->Ammo_AutoConvertType.isset()) + return; + + const int min = pTypeExt->Ammo_AutoConvertMinimumAmount; + const int max = pTypeExt->Ammo_AutoConvertMaximumAmount; + + if (min < 0 && max < 0) + return; + + if (pTypeExt->OwnerObject()->Ammo <= 0) + return; + + const auto pThis = this->OwnerObject(); + const int ammo = pThis->Ammo; + + if ((min < 0 || ammo >= min) && (max < 0 || ammo <= max)) + TechnoExt::ConvertToType(pThis, pTypeExt->Ammo_AutoConvertType); +} + +void FootExt::HealthAutoConvertActions() +{ + const auto pTypeExt = this->TypeExtData; + + if (!pTypeExt->Convert_Health.isset()) + return; + + const int min = pTypeExt->Convert_Health_AbovePercent; + const int max = pTypeExt->Convert_Health_BelowPercent; + + if (min < 0 && max < 0) + return; + + const auto pThis = this->OwnerObject(); + + if (TechnoExt::IsHealthInThreshold(pThis, min, max)) + TechnoExt::ConvertToType(pThis, pTypeExt->Convert_Health); +} + // ============================= // load / save diff --git a/src/Ext/Foot/Body.h b/src/Ext/Foot/Body.h index 0756b3bca9..4d97cfcab7 100644 --- a/src/Ext/Foot/Body.h +++ b/src/Ext/Foot/Body.h @@ -63,6 +63,8 @@ class FootExt : public TechnoExt void UpdateOnTunnelEnter(); void UpdateOnTunnelExit(); void UpdateTypeData(TechnoTypeClass* pCurrentType); + void HealthAutoConvertActions(); + void AmmoAutoConvertActions(); virtual void LoadFromStream(PhobosStreamReader& Stm) override; virtual void SaveToStream(PhobosStreamWriter& Stm) override; diff --git a/src/Ext/Techno/Body.Update.cpp b/src/Ext/Techno/Body.Update.cpp index 1d3cf6b65a..e23b4836ab 100644 --- a/src/Ext/Techno/Body.Update.cpp +++ b/src/Ext/Techno/Body.Update.cpp @@ -134,62 +134,6 @@ void TechnoExt::ApplyInterceptor() } } -void TechnoExt::AmmoAutoConvertActions() -{ - const auto pTypeExt = this->TypeExtData; - - if (!pTypeExt->Ammo_AutoConvertType.isset()) - return; - - const int min = pTypeExt->Ammo_AutoConvertMinimumAmount; - const int max = pTypeExt->Ammo_AutoConvertMaximumAmount; - - if (min < 0 && max < 0) - return; - - if (pTypeExt->OwnerObject()->Ammo <= 0) - return; - - const auto pThis = this->OwnerObject(); - const int ammo = pThis->Ammo; - - if ((min < 0 || ammo >= min) && (max < 0 || ammo <= max)) - { - const auto pFoot = abstract_cast(pThis); - TechnoExt::ConvertToType(pFoot, pTypeExt->Ammo_AutoConvertType); - } -} - -void TechnoExt::AutoConvertActions() -{ - const auto pTypeExt = this->TypeExtData; - const auto pFoot = abstract_cast(this->OwnerObject()); - - if (!pTypeExt->Convert_HP.isset()) - { - return; - } - - const double min = pTypeExt->Convert_HP_Min; - const double max = pTypeExt->Convert_HP_Max; - - if (min < 0.0 && max < 0.0) - { - return; - } - - const auto hp = pFoot->GetHealthPercentage(); - if (hp <= 0.0) - { - return; - } - - if ((min < 0.0 || hp >= min) && (max < 0.0 || hp <= max)) - { - TechnoExt::ConvertToType(pFoot, pTypeExt->Convert_HP); - } -} - // TODO : Merge into new AttachEffects bool TechnoExt::CheckDeathConditions(bool isInLimbo) { diff --git a/src/Ext/Techno/Body.h b/src/Ext/Techno/Body.h index 650772cc93..9fad2304f5 100644 --- a/src/Ext/Techno/Body.h +++ b/src/Ext/Techno/Body.h @@ -178,9 +178,6 @@ class TechnoExt : public RadioExt, public Detach::Listener int ApplyForceWeaponInRange(AbstractClass* pTarget); void ResetDelayedFireTimer(); void UpdateTintValues(); - - void AutoConvertActions(); - void AmmoAutoConvertActions(); void UpdateLastTargetCrd(); int GetSight(); diff --git a/src/Ext/Techno/Hooks.cpp b/src/Ext/Techno/Hooks.cpp index 09775cad57..52c290d1cf 100644 --- a/src/Ext/Techno/Hooks.cpp +++ b/src/Ext/Techno/Hooks.cpp @@ -46,7 +46,7 @@ DEFINE_HOOK(0x4DA54E, FootClass_AI, 0x6) pExt->UpdateWarpInDelay(); pExt->UpdateTiberiumEater(); pExt->AmmoAutoConvertActions(); - pExt->AutoConvertActions(); + pExt->HealthAutoConvertActions(); if (pExt->AttackMoveFollowerTempCount) pExt->AttackMoveFollowerTempCount--; diff --git a/src/Ext/TechnoType/Body.cpp b/src/Ext/TechnoType/Body.cpp index 0793fb0d18..ceedf8c89d 100644 --- a/src/Ext/TechnoType/Body.cpp +++ b/src/Ext/TechnoType/Body.cpp @@ -1124,6 +1124,13 @@ void TechnoTypeExt::LoadFromINIFile(CCINIClass* const pINI) || ExtraThreatCoefficient_Facing.Get(RulesExt::Global()->ExtraThreatCoefficient_Facing) != 0.0 || ExtraThreatCoefficient_DistanceToLastTarget.Get(RulesExt::Global()->ExtraThreatCoefficient_DistanceToLastTarget) != 0.0; + this->Convert_Health_AbovePercent.Read(exINI, pSection, "Convert.Health.AbovePercent"); + this->Convert_Health_BelowPercent.Read(exINI, pSection, "Convert.Health.BelowPercent"); + this->Convert_Health.Read(exINI, pSection, "Convert.Health"); + + if (this->Convert_Health_AbovePercent > this->Convert_Health_BelowPercent) + Debug::Log("[Developer warning][%s] Convert.Health.AbovePercent is greater than Convert.Health.BelowPercent, resulting in no conversion.\n", pSection); + // Ares 0.2 this->RadarJamRadius.Read(exINI, pSection, "RadarJamRadius"); @@ -1146,10 +1153,6 @@ void TechnoTypeExt::LoadFromINIFile(CCINIClass* const pINI) // Ares 3.0 this->Unsellable.Read(exINI, pSection, "Unsellable"); - this->Convert_HP_Min.Read(exINI, pSection, "Convert.HP.Min"); - this->Convert_HP_Max.Read(exINI, pSection, "Convert.HP.Max"); - this->Convert_HP.Read(exINI, pSection, "Convert.HP"); - if (pThis->Gunner) { size_t weaponCount = pThis->WeaponCount; @@ -1743,10 +1746,6 @@ void TechnoTypeExt::Serialize(T& Stm) .Process(this->Unsellable) - .Process(this->Convert_HP_Min) - .Process(this->Convert_HP_Max) - .Process(this->Convert_HP) - .Process(this->ExtraThreat_Enabled) .Process(this->ExtraThreat_IsThreat) .Process(this->AlwaysConsideredThreat) @@ -1754,6 +1753,10 @@ void TechnoTypeExt::Serialize(T& Stm) .Process(this->ExtraThreatCoefficient_InRangeDistance) .Process(this->ExtraThreatCoefficient_Facing) .Process(this->ExtraThreatCoefficient_DistanceToLastTarget) + + .Process(this->Convert_Health_AbovePercent) + .Process(this->Convert_Health_BelowPercent) + .Process(this->Convert_Health) ; } void TechnoTypeExt::LoadFromStream(PhobosStreamReader& Stm) diff --git a/src/Ext/TechnoType/Body.h b/src/Ext/TechnoType/Body.h index f21d1eb233..879e62d6ed 100644 --- a/src/Ext/TechnoType/Body.h +++ b/src/Ext/TechnoType/Body.h @@ -428,11 +428,11 @@ class TechnoTypeExt : public ObjectTypeExt Nullable DropCrate; - Nullable Unsellable; // Ares 3.0 + Valueable Convert_Health_AbovePercent; + Valueable Convert_Health_BelowPercent; + Nullable Convert_Health; - Valueable Convert_HP_Min; - Valueable Convert_HP_Max; - Nullable Convert_HP; + Nullable Unsellable; // Ares 3.0 TechnoTypeExt(TechnoTypeClass* OwnerObject) : ObjectTypeExt(OwnerObject) , HealthBar_Hide { false } @@ -803,10 +803,6 @@ class TechnoTypeExt : public ObjectTypeExt , Unsellable {} - , Convert_HP_Min {-1} - , Convert_HP_Max {-1} - , Convert_HP {} - , ExtraThreat_Enabled { false } , ExtraThreat_IsThreat {} , AlwaysConsideredThreat { false } @@ -816,6 +812,10 @@ class TechnoTypeExt : public ObjectTypeExt , ExtraThreatCoefficient_DistanceToLastTarget {} , DropCrate {} + + , Convert_Health_AbovePercent { -1 } + , Convert_Health_BelowPercent { -1 } + , Convert_Health {} { } virtual ~TechnoTypeExt() = default; From 0494354fa6edee4278fdabe26ceabb29d29ab5ed Mon Sep 17 00:00:00 2001 From: Coronia <2217891145@qq.com> Date: Sun, 2 Aug 2026 22:40:55 +0800 Subject: [PATCH 4/7] doc --- CREDITS.md | 2 +- docs/Whats-New.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CREDITS.md b/CREDITS.md index d0828150da..c09c41304f 100644 --- a/CREDITS.md +++ b/CREDITS.md @@ -918,4 +918,4 @@ This page lists all the individual contributions to the project by their author. - Interop export interface for accessing scenario local/global variables - Add `ClampToScreen` tag for `BannerType` to control whether banner position is clamped to the visible area - **obsidianus** - - Automatic conversion based on HP + - Automatic conversion based on health diff --git a/docs/Whats-New.md b/docs/Whats-New.md index d73f1f49c5..e51544aad2 100644 --- a/docs/Whats-New.md +++ b/docs/Whats-New.md @@ -646,7 +646,7 @@ HideShakeEffects=false ; boolean - Separately define the global default values of TerrainTypes' `IsPassable` and `CanBeBuiltOn` based on `SpawnsTiberium` (by Noble_Fish) - Customize reveal radius of `RevealToAll` (by NetsuNegi) - [Customize whether aircraft is a cargo plane](Fixed-or-Improved-Logics.md#customize-whether-aircraft-is-a-cargo-plane) (by TaranDahl) -- [Automatic conversion based on HP](New-or-Enhanced-Logics.md#automatic-conversion-based-on-hp) (by obsidianus) +- [Automatic conversion based on heallth](New-or-Enhanced-Logics.md#automatic-conversion-based-on-heallth) (by obsidianus) #### Vanilla fixes: - Fixed sidebar not updating queued unit numbers when adding or removing units when the production is on hold (by CrimRecya) From 0cf42323736a95740df378259e9622df1b9e56d9 Mon Sep 17 00:00:00 2001 From: Noble_Fish <1065703286@qq.com> Date: Sun, 2 Aug 2026 22:57:33 +0800 Subject: [PATCH 5/7] fix doc --- CREDITS.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/CREDITS.md b/CREDITS.md index 1b0d341ca8..161bf12d9f 100644 --- a/CREDITS.md +++ b/CREDITS.md @@ -917,5 +917,4 @@ This page lists all the individual contributions to the project by their author. - **Chang_zhi**: - Interop export interface for accessing scenario local/global variables - Add `ClampToScreen` tag for `BannerType` to control whether banner position is clamped to the visible area -- **obsidianus** - - Automatic conversion based on health +- **obsidianus** - Automatic conversion based on health From 3068e1311ec59a3305e710b6e6a28dfa2b84f282 Mon Sep 17 00:00:00 2001 From: obsidianus <143252218+obsidian14@users.noreply.github.com> Date: Mon, 3 Aug 2026 11:37:54 +0800 Subject: [PATCH 6/7] Change health conversion limits to double type --- src/Ext/Foot/Body.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Ext/Foot/Body.cpp b/src/Ext/Foot/Body.cpp index 5cc7a35959..5299bdc7eb 100644 --- a/src/Ext/Foot/Body.cpp +++ b/src/Ext/Foot/Body.cpp @@ -843,8 +843,8 @@ void FootExt::HealthAutoConvertActions() if (!pTypeExt->Convert_Health.isset()) return; - const int min = pTypeExt->Convert_Health_AbovePercent; - const int max = pTypeExt->Convert_Health_BelowPercent; + const double min = pTypeExt->Convert_Health_AbovePercent; + const double max = pTypeExt->Convert_Health_BelowPercent; if (min < 0 && max < 0) return; From e4d1f22de8ad579bce1cb26b83f8d0187cc95e75 Mon Sep 17 00:00:00 2001 From: obsidianus Date: Mon, 3 Aug 2026 17:19:00 +0800 Subject: [PATCH 7/7] Write the Chinese documentation --- docs/New-or-Enhanced-Logics.md | 4 ++-- .../LC_MESSAGES/New-or-Enhanced-Logics.po | 18 ++++++++++++++++++ 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/docs/New-or-Enhanced-Logics.md b/docs/New-or-Enhanced-Logics.md index 04cb3146df..98162c684e 100644 --- a/docs/New-or-Enhanced-Logics.md +++ b/docs/New-or-Enhanced-Logics.md @@ -1536,8 +1536,8 @@ This feature requires Ares 3.0 or higher to function! When Ares 3.0+ is not dete ### Automatic conversion based on health - Units can now be converted into another unit by health percentage. -- `Convert.Health.AbovePercent`determines the minimal health percentage at which a unit converts automatically. -- `Convert.Health.BelowPercent`determines the maximum health percentage at which a unit converts automatically. +- `Convert.Health.AbovePercent` determines the minimal health percentage at which a unit converts automatically. +- `Convert.Health.BelowPercent` determines the maximum health percentage at which a unit converts automatically. - `Convert.Health` specify the new techno after the conversion. This unit must be of the same type of the original (infantry -> infantry, vehicle -> vehicle or aircraft -> aircraft). - Setting a negative number will disable the HP check, and when both checks are disabled, conversion will not occur. 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 b9131b4ba1..65d2b46054 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 @@ -3626,6 +3626,24 @@ msgid "" "both checks are disabled, conversion will not occur." msgstr "设为负数将会禁用弹药数量检查,当两个检查都被禁用时将不会触发变形。" +msgid "Automatic conversion based on health" +msgstr "自动根据血量变形" + +msgid "Units can now be converted into another unit by health percentage." +msgstr "单位可以现在可以基于HP变为其他单位" + +msgid "`Convert.Health.AbovePercent` determines the minimal health percentage at which a unit converts automatically." +msgstr "`Convert.Health.AbovePercent`决定了触发单位自动变身的最小HP值" + +msgid "`Convert.Health.BelowPercent` determines the maximum health percentage at which a unit converts automatically." +msgstr "`Convert.Health.BelowPercent`决定了触发单位自动变身的最大HP值" + +msgid "`Convert.Health` specify the new techno after the conversion. This unit must be of the same type of the original (infantry -> infantry, vehicle -> vehicle or aircraft -> aircraft)." +msgstr "`Convert.Health` 指定变身后的单位. 类型需要和原单位相同 (步兵 → 步兵, 载具 → 载具 或 飞机 → 飞机)" + +msgid "Setting a negative number will disable the HP check, and when both checks are disabled, conversion will not occur." +msgstr "设置为负值会关闭对应的HP检查,当两项检查都被关闭则不会触发变身." + msgid "Automatic passenger deletion" msgstr "自动删除乘客"