Skip to content

自定义效果、特质与属性

复制人的数值系统主要由三层组成:

  • Attribute:属性,比如运动、力量、学习、免疫。
  • Effect:临时或永久效果,可以给属性加减值。
  • Trait:特质,通常是角色长期拥有的标签和修正。

入门时先做 Effect。它最安全,也最容易测试:注册一个效果,加到复制人身上,看属性有没有变化。

注册 Effect

效果要注册进 Db.Get().effects。常见时机是 Db.Initialize 后:

csharp
using HarmonyLib;
using Klei.AI;

namespace MyEffects
{
    [HarmonyPatch(typeof(Db), "Initialize")]
    public static class Db_Initialize_Patch
    {
        public static void Postfix(Db __instance)
        {
            ModEffects.RegisterAll(__instance.effects);
        }
    }
}

Db.Get().effects 的类型是 ResourceSet<Effect>

建议集中写一个 ModEffects.RegisterAll(),后面维护会清楚很多。

创建一个效果

最直接的写法:

csharp
using System.Collections.Generic;
using Klei.AI;

namespace MyEffects
{
    public static class ModEffects
    {
        public const string QUICK_LEARNER = "MyQuickLearner";

        public static void RegisterAll(ResourceSet<Effect> effects)
        {
            Effect effect = new Effect(
                QUICK_LEARNER,
                "快速学习",
                "学习能力提高。",
                600f,
                true,
                true,
                false);

            effect.SelfModifiers = new List<AttributeModifier>
            {
                new AttributeModifier(
                    Db.Get().Attributes.Learning.Id,
                    3f,
                    "快速学习")
            };

            effects.Add(effect);
        }
    }
}

600f 是持续时间,单位是游戏秒。持续时间写 0f 或负数时,要根据具体构造和调用方式测试,不要默认它一定永久。

给复制人添加效果

csharp
Effects effects = minion.GetComponent<Effects>();
if (effects != null)
{
    effects.Add(ModEffects.QUICK_LEARNER, true);
}

移除:

csharp
effects.Remove(ModEffects.QUICK_LEARNER);

检查:

csharp
bool hasEffect = effects.HasEffect(ModEffects.QUICK_LEARNER);

常用属性

属性 ID 建议从 Db.Get().Attributes 拿:

csharp
Db.Get().Attributes.Athletics.Id
Db.Get().Attributes.Strength.Id
Db.Get().Attributes.Learning.Id
Db.Get().Attributes.Construction.Id
Db.Get().Attributes.Machinery.Id
Db.Get().Attributes.Digging.Id
Db.Get().Attributes.Cooking.Id
Db.Get().Attributes.Caring.Id
Db.Get().Attributes.Immunity.Id

不要硬写字符串,除非源码里确认过这个 ID。游戏更新后,直接用 Db 至少更好查。

负面效果

负面效果的构造参数里 isBadtrue

csharp
Effect tired = new Effect(
    "MyHeavyBody",
    "身体沉重",
    "运动和力量下降。",
    1200f,
    true,
    true,
    true);

然后加负数修正:

csharp
tired.SelfModifiers = new List<AttributeModifier>
{
    new AttributeModifier(Db.Get().Attributes.Athletics.Id, -4f, "身体沉重"),
    new AttributeModifier(Db.Get().Attributes.Strength.Id, -2f, "身体沉重")
};

负面效果最好有清晰的移除条件。只加不移除,玩家会觉得像坏档。

自定义特质

特质适合长期身份,比如“耐寒”“神经敏锐”“不擅长挖掘”。基础写法:

csharp
Trait trait = new Trait(
    "MyColdResistant",
    "耐寒体质",
    "这个复制人更适合寒冷环境。",
    0f,
    false,
    null,
    true,
    true);

trait.SelfModifiers.Add(new AttributeModifier(
    Db.Get().Attributes.Immunity.Id,
    2f,
    "耐寒体质"));

Db.Get().traits.Add(trait);

给复制人添加:

csharp
Traits traits = minion.GetComponent<Traits>();
Trait trait = Db.Get().traits.Get("MyColdResistant");
if (traits != null && trait != null && !traits.HasTrait(trait))
{
    traits.Add(trait);
}

特质会进入角色资料,存档影响更长。测试时要多开新档,不要只在旧档里热加载。

自定义属性

自定义 Attribute 可以做,但不建议作为第一步。因为 UI、等级、经验、显示文本、保存读取都要跟上。

如果只是想让某个组件有数值,优先自己写字段:

csharp
[Serialize]
private float heatAffinity;

只有这个数值需要进入复制人属性面板、被多个系统引用、被效果修正时,再考虑注册新属性。

文字路径

效果文本常见路径:

csharp
STRINGS.DUPLICANTS.MODIFIERS.MYQUICKLEARNER.NAME
STRINGS.DUPLICANTS.MODIFIERS.MYQUICKLEARNER.TOOLTIP

特质文本常见路径:

csharp
STRINGS.DUPLICANTS.TRAITS.MYCOLDRESISTANT.NAME
STRINGS.DUPLICANTS.TRAITS.MYCOLDRESISTANT.DESC

路径不统一时,效果能生效,但 UI 显示会很别扭。先把文本整理好,再写大量效果。

常见坑

效果注册太早会找不到 Db.Get().Attributes。放在 Db.Initialize 后最稳。

效果 ID 改名会影响存档。发布后尽量不要改 ID,只改显示名。

属性修正来源名不要空着。属性面板里会显示这条修正从哪里来,空名字很难排查。

永久效果要谨慎。优先用长时间效果加刷新逻辑,确认没问题后再做真正永久。