diff --git a/CREDITS.md b/CREDITS.md index 2adb1c7ce4..8d49951175 100644 --- a/CREDITS.md +++ b/CREDITS.md @@ -829,6 +829,7 @@ This page lists all the individual contributions to the project by their author. - Add target filtering options to attacheffect system - Add veterancy-based target filtering for weapons and warheads - Recipient-specific message and EVA on superweapon activation + - Add a new AutoDeath condition based on the owner's power status - **tyuah8**: - Drive/Jumpjet/Ship/Teleport locomotor did not power on when it is un-piggybacked bugfix - Destroyed unit leaves sensors bugfix diff --git a/docs/New-or-Enhanced-Logics.md b/docs/New-or-Enhanced-Logics.md index ec9ae2bdcc..670955844e 100644 --- a/docs/New-or-Enhanced-Logics.md +++ b/docs/New-or-Enhanced-Logics.md @@ -1972,6 +1972,13 @@ Both `InitialStrength` and `InitialStrength.Cloning` never surpass the type's `S - `Technos(Dont)Exist.Any` controls whether or not a single listed TechnoType is enough to satisfy the requirement or if all are required. - `Technos(Dont)Exist.AllowLimboed` controls whether or not limboed TechnoTypes (f.ex those in transports) are counted. - `Technos(Dont)Exist.Houses` controls which houses are checked. + - `PlayerPowerStatus`: The object will die if its owner's power status matches the configured state. + - `low` / `consumer`: Trigger when the owner is in low power. + - `normal`: Trigger when the owner is not in low power. + - `PlayerMoney.Max` / `PlayerMoney.Min`: The object will die based on the owner's available credits. + - If only `PlayerMoney.Max` is set, triggers when money is not above this value. + - If only `PlayerMoney.Min` is set, triggers when money is not below this value. + - If both are set, triggers when money is **inside the range**. - The auto-death behavior can be chosen from the following: - `kill`: The object will be destroyed normally. @@ -1998,6 +2005,9 @@ AutoDeath.TechnosExist= ; List of TechnoTypes AutoDeath.TechnosExist.Any=true ; boolean AutoDeath.TechnosExist.AllowLimboed=false ; boolean AutoDeath.TechnosExist.Houses=owner ; Affected House Enumeration (none|owner/self|allies/ally|team|enemies/enemy|all) +AutoDeath.PlayerPowerStatus=none ; Player Power Enumeration (none|low/consumer|normal) +AutoDeath.PlayerMoneyLessThan=-1 ; integer +AutoDeath.PlayerMoneyMoreThan=-1 ; integer ``` ```{note} diff --git a/docs/Whats-New.md b/docs/Whats-New.md index 2c98a36155..1f3b6b7aa9 100644 --- a/docs/Whats-New.md +++ b/docs/Whats-New.md @@ -606,6 +606,7 @@ HideShakeEffects=false ; boolean - [Customize the step limit of the credits indicator](User-Interface.md#customize-the-step-limit-of-the-credits-indicator) (by Noble_Fish) - [Disable the credits indicator smooth transition](User-Interface.md#disable-the-credits-indicator-smooth-transition) (by Noble_Fish) - Add `selling`, `undeploying` and `harvesting` conditions to `DiscardOn` (by Noble_Fish) +- [AutoDeath based on player power status and player credits](New-or-Enhanced-Logics.md#kill-object-automatically) (by Flactine) #### 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/New-or-Enhanced-Logics.po b/docs/locale/zh_CN/LC_MESSAGES/New-or-Enhanced-Logics.po index c2bee6f0f8..c9b00b223e 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 @@ -4501,6 +4501,27 @@ msgstr "`Technos(Dont)Exist.AllowLimboed` 控制是否计入虚拟的科技类 msgid "`Technos(Dont)Exist.Houses` controls which houses are checked." msgstr "`Technos(Dont)Exist.Houses` 控制检查哪些所属方。" +msgid "`PlayerPowerStatus`: The object will die if its owner's power status matches the configured state." +msgstr "`PlayerPowerStatus`:当对象所属方的电力状态符合设定条件时,则对象死亡。" + +msgid "`low` / `consumer`: Trigger when the owner is in low power." +msgstr "`low` / `consumer`:当对象所属方处于电力不足状态时触发。" + +msgid "`normal`: Trigger when the owner is not in low power." +msgstr "`normal`:当对象所属方未处于电力不足状态时触发。" + +msgid "`PlayerMoney.Max` / `PlayerMoney.Min`: The object will die based on the owner's available credits." +msgstr "`PlayerMoney.Max` / `PlayerMoney.Min`:根据对象所属方的资金决定对象是否死亡。" + +msgid "If only `PlayerMoney.Max` is set, triggers when money is not above this value." +msgstr "仅设置 `PlayerMoney.Max` 时,当资金不高于该值时触发。" + +msgid "If only `PlayerMoney.Min` is set, triggers when money is not below this value." +msgstr "仅设置 `PlayerMoney.Min` 时,当资金不低于该值时触发。" + +msgid "If both are set, triggers when money is **inside the range**." +msgstr "同时设置时,资金处于**区间内**时触发。" + msgid "The auto-death behavior can be chosen from the following:" msgstr "自毁行为有以下选择:" diff --git a/src/Ext/Techno/Body.Update.cpp b/src/Ext/Techno/Body.Update.cpp index f9573e4a58..3fab5fd3ad 100644 --- a/src/Ext/Techno/Body.Update.cpp +++ b/src/Ext/Techno/Body.Update.cpp @@ -332,6 +332,32 @@ bool TechnoExt::ExtData::CheckDeathConditions(bool isInLimbo) : std::all_of(vTypes.begin(), vTypes.end(), existSingleType); }; + if (pTypeExt->AutoDeath_PlayerPowerStatus != PlayerPowerStatus::None) + { + const bool isLowPower = pOwner->HasLowPower(); + const auto status = pTypeExt->AutoDeath_PlayerPowerStatus; + const auto isFirstFrame = (Unsorted::CurrentFrame == 0); + + if ((status == PlayerPowerStatus::Normal && !isLowPower) || (status == PlayerPowerStatus::Low && isLowPower) && !isFirstFrame) + { + TechnoExt::KillSelf(pThis, howToDie, pTypeExt->AutoDeath_VanishAnimation, isInLimbo); + return true; + } + } + + if (pTypeExt->AutoDeath_PlayerMoney_Max != -1 || pTypeExt->AutoDeath_PlayerMoney_Min != -1) + { + const int maxMoney = pTypeExt->AutoDeath_PlayerMoney_Max; + const int minMoney = pTypeExt->AutoDeath_PlayerMoney_Min; + const int currentMoney = pOwner->Available_Money(); + + if ((maxMoney == -1 || currentMoney <= maxMoney) && (minMoney == -1 || currentMoney >= minMoney)) + { + TechnoExt::KillSelf(pThis, howToDie, pTypeExt->AutoDeath_VanishAnimation, isInLimbo); + return true; + } + } + // death if listed technos don't exist if (!pTypeExt->AutoDeath_TechnosDontExist.empty()) { diff --git a/src/Ext/TechnoType/Body.cpp b/src/Ext/TechnoType/Body.cpp index d77b610154..5b2f9c9686 100644 --- a/src/Ext/TechnoType/Body.cpp +++ b/src/Ext/TechnoType/Body.cpp @@ -806,6 +806,14 @@ void TechnoTypeExt::ExtData::LoadFromINIFile(CCINIClass* const pINI) this->AutoDeath_TechnosExist_Any.Read(exINI, pSection, "AutoDeath.TechnosExist.Any"); this->AutoDeath_TechnosExist_AllowLimboed.Read(exINI, pSection, "AutoDeath.TechnosExist.AllowLimboed"); this->AutoDeath_TechnosExist_Houses.Read(exINI, pSection, "AutoDeath.TechnosExist.Houses"); + this->AutoDeath_PlayerPowerStatus.Read(exINI, pSection, "AutoDeath.PlayerPowerStatus"); + this->AutoDeath_PlayerMoney_Max.Read(exINI, pSection, "AutoDeath.PlayerMoney.Max"); + this->AutoDeath_PlayerMoney_Min.Read(exINI, pSection, "AutoDeath.PlayerMoney.Min"); + + if ((this->AutoDeath_PlayerMoney_Max != -1) + && (this->AutoDeath_PlayerMoney_Min != -1) + && (this->AutoDeath_PlayerMoney_Max < this->AutoDeath_PlayerMoney_Min)) + Debug::Log("[Developer warning][%s] AutoDeath.PlayerMoney.Min is bigger than AutoDeath.PlayerMoney.Max, AutoDeath will never activate!\n", pSection); this->Slaved_OwnerWhenMasterKilled.Read(exINI, pSection, "Slaved.OwnerWhenMasterKilled"); this->SlavesFreeSound.Read(exINI, pSection, "SlavesFreeSound"); @@ -1566,6 +1574,9 @@ void TechnoTypeExt::ExtData::Serialize(T& Stm) .Process(this->AutoDeath_TechnosExist_Any) .Process(this->AutoDeath_TechnosExist_AllowLimboed) .Process(this->AutoDeath_TechnosExist_Houses) + .Process(this->AutoDeath_PlayerPowerStatus) + .Process(this->AutoDeath_PlayerMoney_Max) + .Process(this->AutoDeath_PlayerMoney_Min) .Process(this->Slaved_OwnerWhenMasterKilled) .Process(this->SlavesFreeSound) diff --git a/src/Ext/TechnoType/Body.h b/src/Ext/TechnoType/Body.h index 3237832272..0cb8e40930 100644 --- a/src/Ext/TechnoType/Body.h +++ b/src/Ext/TechnoType/Body.h @@ -105,6 +105,9 @@ class TechnoTypeExt Valueable AutoDeath_TechnosExist_Any; Valueable AutoDeath_TechnosExist_AllowLimboed; Valueable AutoDeath_TechnosExist_Houses; + Valueable AutoDeath_PlayerPowerStatus; + Valueable AutoDeath_PlayerMoney_Max; + Valueable AutoDeath_PlayerMoney_Min; Valueable Slaved_OwnerWhenMasterKilled; NullableIdx SlavesFreeSound; @@ -661,6 +664,9 @@ class TechnoTypeExt , AutoDeath_TechnosExist_Any { true } , AutoDeath_TechnosExist_AllowLimboed { true } , AutoDeath_TechnosExist_Houses { AffectedHouse::Owner } + , AutoDeath_PlayerPowerStatus { PlayerPowerStatus::None } + , AutoDeath_PlayerMoney_Max { -1 } + , AutoDeath_PlayerMoney_Min { -1 } , Slaved_OwnerWhenMasterKilled { SlaveChangeOwnerType::Killer } , SlavesFreeSound {} diff --git a/src/Utilities/Enum.h b/src/Utilities/Enum.h index 2e9d9645f4..2e51ee48d1 100644 --- a/src/Utilities/Enum.h +++ b/src/Utilities/Enum.h @@ -188,6 +188,13 @@ enum class AutoDeathBehavior Sell = 2, // buildings only }; +enum class PlayerPowerStatus +{ + None = 0, + Normal = 1, // not low power + Low = 2, // low power +}; + enum class SelfHealGainType { NoHeal = 0, diff --git a/src/Utilities/TemplateDef.h b/src/Utilities/TemplateDef.h index dcac3f3534..b45eb21ce0 100644 --- a/src/Utilities/TemplateDef.h +++ b/src/Utilities/TemplateDef.h @@ -1625,6 +1625,33 @@ if(_strcmpi(parser.value(), #name) == 0){ value = __uuidof(name ## LocomotionCla Debug::INIParseFailed(pSection, pKey, pCur); } } + + template <> + inline bool read(PlayerPowerStatus& value, INI_EX& parser, const char* pSection, const char* pKey) + { + if (parser.ReadString(pSection, pKey)) + { + static const std::pair Names[] = + { + {"none", PlayerPowerStatus::None}, + {"consumer", PlayerPowerStatus::Low}, + {"low", PlayerPowerStatus::Low}, + {"normal", PlayerPowerStatus::Normal}, + }; + + for (auto const& [name, val] : Names) + { + if (_strcmpi(parser.value(), name) == 0) + { + value = val; + return true; + } + } + + Debug::INIParseFailed(pSection, pKey, parser.value(), "Expected a valid PlayerPowerStatus (none, normal, low|consumer"); + } + return false; + } } // Valueable