Card Dynamic Variables
Add A Variable
Use ModCardVars when a card needs values in its description that can change at runtime.
using MegaCrit.Sts2.Core.Localization.DynamicVars;
using STS2RitsuLib.Cards.DynamicVars;
public sealed class MyStrike : ModCardTemplate(1, CardType.Attack, CardRarity.Common, TargetType.SingleEnemy)
{
public override DynamicVarSet DynamicVars => new()
{
ModCardVars.Int("damage", Damage),
ModCardVars.Computed("block", 3, card => card?.Upgraded == true ? 5 : 3),
};
}Then use those variable names in cards.json, for example Deal {damage} damage. Gain {block} block.
Use a normal IntVar for values that already live on the card. Use ComputedDynamicVar when the display value depends on target, upgrade state, or preview mode.
添加变量
当卡牌描述中需要显示运行时变化的数值时,使用 ModCardVars。
using MegaCrit.Sts2.Core.Localization.DynamicVars;
using STS2RitsuLib.Cards.DynamicVars;
public sealed class MyStrike : ModCardTemplate(1, CardType.Attack, CardRarity.Common, TargetType.SingleEnemy)
{
public override DynamicVarSet DynamicVars => new()
{
ModCardVars.Int("damage", Damage),
ModCardVars.Computed("block", 3, card => card?.Upgraded == true ? 5 : 3),
};
}然后在 cards.json 中使用这些变量名,例如 造成 {damage} 点伤害。获得 {block} 点格挡。
值已经存在于卡牌上时,用普通 IntVar。显示值依赖目标、升级状态或预览模式时,用 ComputedDynamicVar。
Damage And Block Wrappers
Use ComputedDamage and ComputedBlock for computed values that should still match normal card preview rules for Strength, Dexterity, Vulnerable, Frail, and card enchantments:
public override DynamicVarSet DynamicVars => new()
{
ModCardVars.ComputedDamage("damage", 6, (card, target) => BaseDamage + BonusDamage(card, target)),
ModCardVars.ComputedBlock("block", 5, card => card?.IsUpgraded == true ? 8 : 5),
};For Osty attacks, use ComputedOstyDamage so damage preview modifiers see Osty as the dealer:
ModCardVars.ComputedOstyDamage("damage", 7, (card, target) => ResolveOstyDamage(card, target));When the preview base amount differs from the live amount, pass a preview base factory. The result still goes through normal damage or block hooks:
ModCardVars.ComputedDamage(
"damage",
6,
(card, target) => ResolveDamage(card, target),
(card, mode, target, runGlobalHooks) => ResolvePreviewDamageBase(card, mode, target));Use plain Computed when the value should not pass through damage or block hooks.
伤害与格挡包装
当计算值仍需要符合普通卡牌预览规则时,使用 ComputedDamage 和 ComputedBlock,这样力量、敏捷、易伤、脆弱和卡牌附魔都会参与预览计算:
public override DynamicVarSet DynamicVars => new()
{
ModCardVars.ComputedDamage("damage", 6, (card, target) => BaseDamage + BonusDamage(card, target)),
ModCardVars.ComputedBlock("block", 5, card => card?.IsUpgraded == true ? 8 : 5),
};奥斯蒂攻击使用 ComputedOstyDamage,这样伤害预览修正会把奥斯蒂视为伤害来源:
ModCardVars.ComputedOstyDamage("damage", 7, (card, target) => ResolveOstyDamage(card, target));当预览基础值和实卡当前值不同时,传入 preview base factory。它返回的结果仍会继续经过普通伤害或格挡 hook:
ModCardVars.ComputedDamage(
"damage",
6,
(card, target) => ResolveDamage(card, target),
(card, mode, target, runGlobalHooks) => ResolvePreviewDamageBase(card, mode, target));如果数值不应该经过伤害或格挡 hook,继续使用普通 Computed。
Energy, Star, And Power Icon Counts
Use the concrete icon variable helpers when a description needs a dynamic amount rendered through the game’s icon formatters:
public override DynamicVarSet DynamicVars => new()
{
ModCardVars.ComputedEnergy("EnergyGain", 1, card => ResolveEnergyGain(card)),
ModCardVars.ComputedStars("StarGain", 1, card => ResolveStarGain(card)),
ModCardVars.ComputedPower<StrengthPower>("StrengthPower", 2, card => ResolveStrength(card)),
};ComputedPower<T> keeps the typed PowerVar<T> shape for naming and display, and does not run power-amount hooks by default. For a computed amount that represents power being applied by the card and should use the same preview hook path as vanilla PowerVar<T>, use ComputedPowerAmountGiven<T>.
Then keep the formatter in localization:
{
"MY_CARD.description": "Gain {EnergyGain:energyIcons()}.\nGain {StarGain:starIcons()}.\nGain {StrengthPower:diff()} Strength."
}For a literal single energy icon that follows the card pool color, use the vanilla extra argument:
{
"MY_CARD.description": "The next card costs 0{energyPrefix:energyIcons(1)}."
}能量、星星与能力层数图标数量
当描述中需要通过游戏原生图标 formatter 显示动态数量时,使用具体图标变量辅助方法:
public override DynamicVarSet DynamicVars => new()
{
ModCardVars.ComputedEnergy("EnergyGain", 1, card => ResolveEnergyGain(card)),
ModCardVars.ComputedStars("StarGain", 1, card => ResolveStarGain(card)),
ModCardVars.ComputedPower<StrengthPower>("StrengthPower", 2, card => ResolveStrength(card)),
};ComputedPower<T> 保留类型化的 PowerVar<T> 形状,用于命名和显示,默认不跑能力层数 hook。如果这个计算值表示卡牌将要施加的能力层数,并且需要走和原版 PowerVar<T> 相同的预览修正路径,使用 ComputedPowerAmountGiven<T>。
本地化里继续保留 formatter:
{
"MY_CARD.description": "获得{EnergyGain:energyIcons()}。\n获得{StarGain:starIcons()}。\n获得{StrengthPower:diff()}点力量。"
}如果只是需要一个跟随卡池颜色的固定单个能量图标,使用原版额外参数:
{
"MY_CARD.description": "下一张牌耗能变为0{energyPrefix:energyIcons(1)}。"
}Add A Tooltip
Attach hover tips directly to a dynamic variable.
ModCardVars.Int("heat", Heat)
.WithSharedTooltip("MY_MOD_HEAT", "res://MyMod/images/ui/heat.png");This reads static_hover_tips keys:
{
"MY_MOD_HEAT.title": "Heat",
"MY_MOD_HEAT.description": "Some cards care about the current Heat value."
}For custom layouts, pass a factory to .WithTooltip(var => new HoverTip(...)).
添加 Tooltip
可以直接给动态变量挂 hover tip。
ModCardVars.Int("heat", Heat)
.WithSharedTooltip("MY_MOD_HEAT", "res://MyMod/images/ui/heat.png");它读取 static_hover_tips 中的 key:
{
"MY_MOD_HEAT.title": "热量",
"MY_MOD_HEAT.description": "部分卡牌会根据当前热量改变效果。"
}需要自定义布局时,传入 .WithTooltip(var => new HoverTip(...)) 工厂。
Read Values Safely
Use extension helpers when a card or effect reads dynamic variables from another card:
var amount = card.DynamicVars.GetIntOrDefault("damage");
var hasHeat = card.DynamicVars.HasPositiveValue("heat");The helpers return defaults when the key is missing, which is usually better than assuming every card has your variable.
安全读取
当卡牌或效果需要读取另一张牌的动态变量时,使用扩展方法:
var amount = card.DynamicVars.GetIntOrDefault("damage");
var hasHeat = card.DynamicVars.HasPositiveValue("heat");变量不存在时这些方法会返回默认值,通常比假定每张牌都有你的变量更稳。
Preview Logic
ComputedDynamicVar accepts a preview factory:
ModCardVars.Computed(
"damage",
Damage,
(card, target) => ResolveDamage(card, target),
(card, mode, target, runGlobalHooks) => ResolvePreviewDamage(card, mode, target));Use preview logic when card preview, target preview, or upgrade preview should show a value different from the current live card value.
预览逻辑
ComputedDynamicVar 可以传入 preview factory:
ModCardVars.Computed(
"damage",
Damage,
(card, target) => ResolveDamage(card, target),
(card, mode, target, runGlobalHooks) => ResolvePreviewDamage(card, mode, target));当卡牌预览、目标预览或升级预览需要显示不同于当前实卡的值时,再写 preview 逻辑。