维护提醒

BWIKI 全站将于 9 月 3 日(全天)进行维护,期间无法编辑任何页面或发布新的评论。

全站通知:

模组:迁移至游戏本体1.7

来自星露谷物语维基
跳到导航 跳到搜索

目录

当前页面编写的内容面向模组的开发者。模组玩家请阅读模组:模组兼容性
Blue Chicken.png
即将到来

星露谷物语的下一个版本为 1.7。
当前页面的内容描述的是 pre-alpha 开发分支中已经进行了的更新。1.7 版本暂无明确的发布日期,正式发布之前,内容可能会发生改动。

此页面帮助模组作者升级模组至下一版本(1.7),并记录了一些更改和新功能。

问答

SMAPI 模组兼容性走势图

该版本有何变化

星露谷物语 1.7 对事件数据作出了重大更改,但除此之外,较于 1.6 和 1.6.9 版本,新版本对于模组而言仅有一些小变化。

这是一次巨变吗

不是。当前模组受到的影响应当是极小的。

某些可能的影响:

  • 事件更改可能影响那些编辑原版事件或使用数值型事件 ID(早于 1.6 版本风格)的模组。Content Patcher 内容包应当大部分不受影响,因为 Content Patcher 会自动重写旧版的内容包,如果可行。
  • 那些使用 Harmony 或反射深度介入游戏内部的模组很脆弱,且可能会被任何游戏更新损坏。然而 1.7 中并不存在特定更改会对此类模组产生超预期影响。

如何升级您的模组

如下是一个推荐的“快速指南”,用于将模组升级到 Stardew Valley 1.7。

对于 C# 模组
  1. 如果还未升级到 1.6.9,请先升级。
  2. 重新构建此解决方案。
  3. 修复出现的构建错误。您可以在此页面以及先前的迁移指南中搜索相关信息。
  4. manifest.json 中更新模组版本号。
    (某些模组可能会因为运行时出错被添加进 SMAPI 兼容性黑名单,更新版本号也能够移出黑名单,如果缺失修复了错误。)
  5. 测试,以确保模组运行正常。
  6. 粗略浏览此页面,查看可能涉及您的模组的章节。
对于 Content Patcher 包;
  1. 如果还未升级到 1.6.9,请先升级。
  2. 粗略浏览此页面,查看可能涉及您的模组的章节。
对于使用其他框架的内容包;
参见提供框架的模组的文档。如果框架本身已经升级,您往往不需要再另行升级内容包。

数据素材更改

Data/Boots

此素材已重构为数据模型,其翻译则迁移至新增的 Strings/Boots。新版素材添加了 ContextTagsCustomFields 等字段,它们在旧版格式中不受支持。

现在此素材为一个“字符串 → 模型”查询,其中:

字段 效果
基本信息
Name 物品内部名称(游戏中不显示)。
DisplayName
Description
一个模板字符串,用于显示游戏内的名称和描述。
ContextTags (可选)添加到此物品的自定义上下文标签(“自定义”是指在自动添加的标签以外,额外添加的标签)。应当指定为数组。
装备效果
AddDefense
AddImmunity
(可选)对玩家的防御免疫的加成。默认为 0。
外观
Texture 靴子贴图所在贴图集的素材名称。若忽略,默认为 Maps/springobjects。对于自定义靴子,此字段不可忽略。
SpriteIndex (可选)贴图在 Texture 中的索引,其中 0 代表左上角的贴图。默认为 0。
ColorTexture (可选)靴子颜色贴图所在贴图集的素材名称。默认为 Characters/Farmer/shoeColors
ColorSpriteIndex (可选)颜色贴图在 ColorTexture 中的贴图索引,其中 0 代表左上角。默认为 0。
高级
CustomFields (可选)此条目的自定义字段

下面代码演示了如何在 1.7 中添加新靴子:

{
    "Format": "2.7.0",
    "Changes": [
        // 添加数据
        {
            "Action": "EditData",
            "Target": "Data/Boots",
            "Entries": {
                "{{ModId}}_FancyBoots": {
                    "Name": "{{ModId}}_FancyBoots",
                    "DisplayName": "{{i18n: fancy-boots.name}}",
                    "Description": "{{i18n: fancy-boots.description}}",
                    "Texture": "Mods/{{ModId}}/Boots",
                    "SpriteIndex": 0,
                    "ColorSpriteIndex": 1
                }
            }
        },

        // 添加贴图
        {
            "Action": "Load",
            "Target": "Mods/{{ModId}}/Boots",
            "FromFile": "assets/boots.png"
        }
    ]
}

Data/Buffs

新增字段:

字段 效果
CustomFields (可选)此条目的自定义字段

Data/ChairTiles

  • 现在地块集素材名称可以包含英文句号(例如,地块集 ExampleAuthor.ModName_Tilesheet 在新版中会被正确解析为数据键,而在旧版中则会被解析为 ExampleAuthor)。

Data/CookingRecipes

重命名了以下配方键名,使得其与产出物品的名称相同(与其他配方保持一致):

旧名称 新名称
Cheese Cauli. Cheese Cauliflower
Cookies Cookie
Cran. Sauce Cranberry Sauce
Dish o' The Sea Dish O' The Sea
Eggplant Parm. Eggplant Parmesan
Vegetable Stew Vegetable Medley

此改动对于显示的文本并无影响,但引用这些配方键名的模组应更新。

Data/Events/*

参见下文的事件更改

Data/Furniture

此素材已重构为数据模型。新版素材提供了一些在旧版中硬编码的功能,例如自定义物品描述(通过 Description),自定义电视机(通过新增的 Television 家具类型以及 TelevisionScreen 字段),以及自定义字段

现在此素材为一个“字符串 → 模型”查询,其中:

字段 效果
基本信息
Name 物品内部名称(游戏中不显示)。
DisplayName 一个模板字符串,用于显示游戏内的名称。
Description (可选)一个模板字符串,用于显示游戏内的描述。默认为基于物品其他字段生成的通用描述,例如基于 CanPlaceIndoorsCanPlaceOutdoors 字段。
Type (可选)家具类型,影响不同家具的功能和默认值(例如,默认碰撞箱尺寸)。默认为 Other

参见可用的家具类型

Price (可选)从商店购入此家具的价格。默认为 0 。
ContextTags (可选)添加到此物品的自定义上下文标签(“自定义”是指在自动添加的标签以外,额外添加的标签)。应当指定为数组。
行为
CanPlaceIndoors
CanPlaceOutdoors
(可选)玩家是否可以将此家具放置在室内和/或室外。默认为基于 Type 字段生成的通用行为(例如,电视机默认情况下不能放置在户外)。
ExcludeFromRandomSale (可选)是否禁止该家具出现在随机生成的商店存货或家具目录中。默认为 false。
外观
Texture 此家具贴图所在贴图集的素材名称。若忽略,默认为 furniture。对于自定义家具,此字段不可忽略。
SpriteIndex (可选)贴图在 Texture 中的索引,其中 0 代表左上角。默认为 0。
Rotations (可选)家具可能的旋转方式(取 1,2 或 4)。默认为 1。
SpriteSize (可选)Texture 中贴图的尺寸,单位为地块。默认为根据 Type 字段生成的通用尺寸。
BoundingBoxSize (可选)家具在游戏中的碰撞箱大小,单位为地块。默认为根据 Type 字段生成的通用尺寸。

碰撞箱的锚点位于 SpriteSize 的左下角。宽度会使得碰撞箱的右边界向右延展,高度则会使碰撞箱的上边界向上延展。

不同类型的选项
BedType (可选)适用于 Type 字段设为 Bed 的情形。此时此字段指定床的类型,以限制其使用者。默认为 Single

可用取值

床的类型 效果
Single 单人床,仅可供单个玩家或 NPC 使用。
Double 双人床,可供两个玩家或 NPC 使用。
Child 单人床,用于孩子。
TelevisionScreenOffset (可选)适用于 Type 字段设为 Television 的情形。此时此字段指示电视画面贴图相对于电视碰撞箱的 X 和 Y 位移,单位为像素。默认为空。
TelevisionScreenScale (可选)适用于 Type 字段设为 Television 的情形。此时此字段指示对电视画面大小应用的乘数,以使得画面能够恰好贴合电视屏幕。
高级
CustomFields (可选)此条目的自定义字段

Data/Hats

此素材已重构为数据模型,其翻译则迁移至新增的 Strings/Hats 素材。新版素材添加了 ContextTagsCustomFields 等字段,它们在旧版格式中不受支持。

现在此素材为一个“字符串 → 数据模型”查询,其中:

字段 效果
基本信息
Name 物品内部名称(游戏中不显示)。
DisplayName
Description
一个模板字符串,用于显示游戏内的名称和描述。
HairStyle (可选)玩家佩戴此帽子时对其发型的调整。默认为 DrawObscuredHair.

可用的取值为:

  • DrawFullHair:正常绘制头(适用于阿比盖尔的蝴蝶结等不会隐藏头发的帽子)。
  • DrawObscuredHair:帽子下的头发会被隐藏(适用于牛仔帽等大多数帽子)。
  • HideHair:完全隐藏头发(适用于木乃伊头套等完全遮盖头部的帽子)。
SkipHairOffset (可选)是否忽略发型偏移(发型偏移用于使帽子出现在玩家的头发上,而面具等帽子无需发型偏移)。默认为 false。
Texture 此帽子贴图所在贴图集的素材名称。若忽略,默认为 samp>Characters/Farmer/hats。对于自定义帽子,此字段不可忽略。
SpriteIndex (可选)贴图在 Texture 中的索引,其中 0 代表左上角。默认为 0。
ContextTags (可选)添加到此物品的自定义上下文标签(“自定义”是指在自动添加的标签以外,额外添加的标签)。应当指定为数组。
CustomFields (可选)此条目的自定义数据字段

下面的代码演示了如何在 1.7 中添加一顶新帽子:

{
    "Format": "2.7.0",
    "Changes": [
        // 添加数据
        {
            "Action": "EditData",
            "Target": "Data/Hats",
            "Entries": {
                "{{ModId}}_FancyHat": {
                    "Name": "{{ModId}}_FancyHat",
                    "DisplayName": "{{i18n: fancy-hat.name}}",
                    "Description": "{{i18n: fancy-hat.description}}",
                    "HairStyle": "DrawObscuredHair",
                    "Texture": "Mods/{{ModId}}/Hats",
                    "SpriteIndex": 0
                }
            }
        },

        // 添加贴图
        {
            "Action": "Load",
            "Target": "Mods/{{ModId}}/Hats",
            "FromFile": "assets/hats.png"
        }
    ]
}

Data/LostItemsShop

新增了一个字段:

字段 效果
RequireCondition (可选)欲将此物品添加到遗失物品商店,需满足的游戏状态查询。其中 Target 代表待检查的玩家。

一般而言,此字段仅可使用确定性查询。

如果您指定了多个条件字段,则仅会使用其中一个,按如下优先级: RequireMailReceivedRequireEventSeenRequireCondition

Data/PassiveFestivals

新增了一个字段:

字段 效果
InLocations (可选)节日地点。这影响多种游戏逻辑,例如 NPC 对话、帐篷放置限制、天气等。若忽略,默认为 MapReplacements 中的键。

Data/Monsters

星露谷 1.7 版本彻底重构了怪物数据。特别地:

  • 关于怪物通用数据:
    • Data/Monsters 已重构为数据模型素材,其翻译迁移至新增的 Strings/Monsters 素材。新版素材提供了旧版素材不支持的一些重要功能。
    • 引入了“怪物变体”(monster variant)概念,用于使多种具体的怪物共享某些数据(例如,绿色史莱姆 Green Slime 和老虎史莱姆 Tiger Slime 可以视作新增的“史莱姆” Slime 怪物的变体)。这尤适用于处理掉落物。
    • 新增“怪物标签”(monster tag)系统,允许怪物自定义标签,例如 slime_is_prismatic, 可用于筛选怪物掉落物。
  • 关于怪物掉落物数据:
    • 重构了怪物掉落物系统,以支持所有原版功能,例如条件物品查询限定性物品ID(以允许掉落非物体的物品),以及针对不同怪物的概念,例如重复掉落概率和互斥掉落物。
    • 现在所有掉落物都是限定性物品ID。旧版中的“资源ID”(为一个负数,例如 -4)将不再受到支持;物品会根据需要自动转换为等价的资源掉落物。
    • 现在几乎所有怪物掉落物的定义都位于 Data/Monsters 中(几个适用于所有怪物的硬编码掉落物除外)。

现在此素材为一个“字符串 → 数据模型”查询,其中:

字段 效果
基本信息
DisplayName 一个模板字符串,用于显示怪物名称。
IsGlider (可选)此怪物是否飞行(飞行怪物可穿越障碍物,等等)。默认为 false。
IsMineMonster (可选)此怪物是否可以在矿井中生成,以及玩家到达矿井底部后是否受相应加成影响。某些情况下,此字段也适用于其他位置的怪物(例如,农场上的荒野石魔也受到矿井加成)。默认为 false。
ExperiencePoints (可选)击杀此怪物收获的战斗经验值。默认为 1。
数值
Health (可选)基础 HP。默认为 20。
Attack (可选)攻击力(即,每一击减少玩家多少生命值)。默认为 5。
Defense (可选)防御值,用于减轻此怪物受到的伤害。默认为 0。
DodgeChance (可选)此怪物闪避攻击的概率,为 0(从不)到 1(总是)之间的值。默认为 0。
Speed (可选)默认移动速度。默认为 1。
Jitteriness (可选)怪物朝随机非玩家方向移动以绕开障碍物的频率,为 0(从不)到 1(总是)之间的值。默认为 0.1。
DetectionDistance (可选)怪物能探测到玩家并向其移动的距离,或 -1 代表无限制。默认为 4。
掉落物
Drops (可选)击杀怪物所掉落的物品。默认为空。

所有匹配通过的物品都会掉落。如果玩家穿戴了窃贼戒指,则每种掉落物会被判断两次(但 RepeatingChanceSkipIfDropped 等字段不受此影响)。

此字段为掉落物模型所组成的列表。掉落物模型又包含如下字段:

字段 效果
通用字段 参见模组:物品查询#物品生成字段以了解怪物掉落物支持的通用物品字段。

注意:

  • 如果某项掉落物的物品查询返回多组物品,则会从中随机选取一个。
  • Condition 可以包含 %RANDOM_KEY 标记,该标记会被替换为当前时刻此怪物的唯一标识符。
ForTags (可选)此字段指定一系列怪物标签,只有具有相应标签的怪物才可能产出此掉落物。此处的标签可以为上下文标签,例如,可以为!variant_frost_bat, !variant_lava_bat(排除冰冻蝙蝠熔岩蝙蝠)。默认为空,表示无限制。
Chance (可选)掉落此物品的概率,为 0(从不)到 1(总是)之间的值。默认为 1。
RepeatingChance (可选)产出额外掉落物的概率,为 0(从不)到 .95(几乎总是)之间的值。默认为 0。

游戏首先基于其他字段判断是否掉落此物品,如果掉落,之后会反复应用此概率以确定是否额外产出此物品,直到概率判定失败。在产出每个额外物品时,游戏会忽略 ChanceCondition 字段,但会重复应用其他物品生成字段(例如,如果 RandomItemId 字段可用,则产出每个额外物品时会重新进行随机选取)。

RepeatingChanceKey (可选)检查 RepeatingChance 字段时,会使用此字段以产生可预测随机数生成器。故可用于同步每个独立的掉落物。默认为空。

此字段可以设为 %RANDOM_KEY 标记,该标记会被替换为当前时刻此怪物的唯一标识符。

ExplodeStack (可选)是否将包含多个物品的物品堆叠拆分为单个物品。默认为 false。

例如,假设某种怪物会掉落 15 个木材。如果启用此字段,则会掉落 15 个物品堆叠,每个堆叠含 1 个木材,而非掉落 1 个包含 15 个木材的物品堆叠。

SkipIfDropped (可选)为一个物品 ID 数组,如果其中某个 ID 已经掉落,则跳过当前掉落物。默认为空。

示例:

"SkipIfDropped": [ "ExampleDropId", "AnotherDropId" ]
变体
DefaultVariant (可选)如果创建怪物时省略变体,则使用此字段作为默认变体,而非直接使用基础数据创建怪物。默认为 false。
Variants (可选)此怪物可用的变体。默认为空。

每个变体是一系列字段的集合,这些字段用于覆盖基础数据中的相应字段。例如,如下代码创建一个怪物变体,其仅在名称和生命值上与基础怪物有所不同:

"Variants": [
    {
        "DisplayName": "{{i18n: variant-name}}",
        "Health": 50
    }

此字段为包含如下字段的数据模型所组成的列表:

字段 效果
怪物字段 所有怪物字段(除了 DefaultVariantVariants)都可用于此。任何字段都可以被省略,其默认值为基础数据中的对应值。
InheritDrops (可选)是否继承怪物基础数据中的 Drops 字段。默认为 true。

特别地:

  • 如果为 true,则此变体会将基础数据中的 Drops 和变体数据中的 Drops 字段拼接为同一个列表。
  • 如果为 false,则变体数据的 Drops 字段会覆盖基础数据的相应字段。
高级
CustomFields (可选)此条目的自定义字段

例如,下面的 Content Patcher 代码添加了一个“河豚鸡”(Pufferchick)怪物,在被击杀时会掉落河豚。此怪物的贴图会自动从 Monsters/<ID> 中加载。

注意: 此代码仅添加怪物数据。目前为止,仅有怪物数据不会产生任何效果,除非您添加了额外的模组,以生成此怪物的游戏实例。

{
    "Format": "2.7.0",
    "Changes": [
        // 添加数据
        {
            "Action": "EditData",
            "Target": "Data/Monsters",
            "Entries": {
                "{{ModId}}_Pufferchick": {
                    "DisplayName": "{{i18n: pufferchick.name}}",
                    "ExperiencePoints": 3,

                    "Health": 30,
                    "Attack": 2,
                    "Defense": 5,
                    "DodgeChance": 0.3,
                    "Speed": 2,
                    "DetectionDistance": 2,

                    "Drops": [
                        {
                            "Id": "Pufferfish",
                            "ItemId": "(O)128",
                            "Chance": 0.5,
                            "RepeatingChance": 0.1
                        }
                    ]
                }
            }
        },

        // 添加贴图
        {
            "Action": "Load",
            "Target": "Monsters/{{ModId}}_Pufferchick",
            "FromFile": "assets/pufferchick.png"
        }
    ]
}

Data/Objects

新增了一个字段:

字段 效果
Buffs 此字段原先存在,但发生了字段变化:
字段 效果
CustomAttributes 此字段原先存在,但发生了字段变化:
字段 效果
CustomFields (可选)此条目的自定义字段

Data/SpecialOrders

  • 新增了一个字段:
    字段 效果
    CanBeCancelled (可选)是否可以取消此特别任务。在合作模式中,任何玩家取消该任务的同时,也会取消其他玩家的任务。默认为 false。

    优化了一个字段:

    字段 效果
    Duration 此字段现在可以设为 "Indefinite",代表特殊任务永不过期。此特殊任务将永远处于激活状态,直到被完成或取消。如果可以,请启用 CanBeCancelled 字段。

Data/Tools

新增了一个字段:

字段 效果
ContextTags (可选)添加到此物品的自定义上下文标签(“自定义”是指在自动添加的标签以外,额外添加的标签)。应当指定为数组。

Data/Weapons

新增了一个字段:

字段 效果
ContextTags (可选)添加到此物品的自定义上下文标签(“自定义”是指在自动添加的标签以外,额外添加的标签)。应当指定为数组。

针对所有模组作者的更改

上下文标签更改

新增如下上下文标签:

上下文标签 物品类型 效果
axe
error_tool
fishing_rod
generic_tool
hoe
lantern
melee_weapon
milk_pail
pan
pickaxe
raft
shears
slingshot
wand
watering_can
工具武器 实现此工具或近战武器的 C# 类型。

原版中镰刀对应 melee_weapon

fish_skip_minigame 任何 如果此物品在玩家钓鱼时上钩,则会被直接钓起,而无需钓鱼小游戏。这用于游戏中的钓鱼垃圾物品,例如海草(现在其有相应的上下文标签)。
ignore_gift_limits 任何可送礼物品 此物品是否不受礼物数量限制(类似于星之果茶)。具有此标签的物品不会计入日/周送礼数量,且在送礼数量达到极限后仍可送出。
is_galaxy_weapon 武器 将此工具标记为银河武器,例如银河之锤银河剑。原版镰刀通过 Data/Weapons 设置此标签。此字段会影响检查银河武器的逻辑(例如银河之魂附魔)。
is_scythe 工具武器 将此工具标记为镰刀。原版镰刀通过 Data/Weapons 来添加此标签。
spawns_butterflies 家具 蝴蝶是否在此家具周围生成,类似于蝴蝶笼
upgrade_level_* 工具武器 工具升级等级。这些字段是基于工具当前等级自动添加的。例如,铜斧头会同时具有 upgrade_level_0(普通斧头)和 upgrade_level_1(铜斧头)标签。

调试命令更改

改进了现有命令:

命令 描述
jump 修复了 NPC 不存在时发生的问题。
perfection 修复了存档已经部分满足某些要求时,运行会出错的问题。

对话更改

  • 在对话字符串中新增了一个特殊标记
    标记 描述
    ||| 意为 "randomizeDelimiter" 。用于分隔一系列对话变体,以备每天抽取。随机抽取后,任何开头或结尾的空白字符会被删除。抽取的结果是每日确定的(例如,重新加载存档并不会改变抽取到的对话)。

    假设您设置了如下对话:

    "Rainy_Night": "
        我最爱雨天了。$h|||
        我喜欢雨天。|||
        我简直太喜欢雨天了。$h|||
        我讨厌雨天。$s#$b#开玩笑的。我最爱雨天了!$h|||
        我雨天感觉很快活。$h
    "
    

    这个示例创建了五个对话变体,每个变体会被等可能地抽取。

  • 新增对话键:
    描述
    “被动节日对话” 地点对话相同,但可将被动节日 ID 用作地点名称。任何被动节日对话优先于同一地点的地点对话。
  • 优化了部分特殊标记
    标记 变化
    || 现在标记周围的空白字符会被忽略,因此您可以将文本分为多行:
    "Wed8": "
        像你这样经常跑来沙漠不是花费很大吗?#$e#你一定是很喜欢来见我,对吧?嗯…… $h||
        唉……我很怀念星露谷的漂亮花朵……$s
    "
    
  • 使用新增功能合并了某些对话。其先前的对话键现在会被游戏忽略。
    素材 先前的对话键 更改
    Characters/Dialogue/MarriageDialogue
    Characters/Dialogue/MarriageDialogue<NPC name>
    Characters/Dialogue/MarriageDialogue<NPC name>Roommates
    funLeave_<NPC name>
    funReturn_<NPC name>
    jobLeave_<NPC name>
    jobReturn_<NPC name>
    patio_<NPC name>
    spouseRoom_<NPC name>

    spring_<NPC name>
    summer_<NPC name>
    fall_<NPC name>
    winter_<NPC name>
    迁移至 MarriageDialogue<NPC name> 且移除了 NPC 后缀(例如 spouseRoom_<NPC name>spouseRoom)。
    Indoor_Day_0
    Indoor_Day_1
    Indoor_Day_2
    Indoor_Day_3
    Indoor_Day_4
    合并为 Indoor_Day
    Indoor_Night_0
    Indoor_Night_1
    Indoor_Night_2
    Indoor_Night_3
    Indoor_Night_4
    Indoor_Night_<NPC name>
    合并为 Indoor_Night
    NoBed_0
    NoBed_1
    NoBed_2
    NoBed_3
    合并为 NoBed
    Outdoor_0
    Outdoor_1
    Outdoor_2
    Outdoor_3
    Outdoor_4
    Outdoor_<NPC name>
    合并为 Outdoor
    Rainy_Day_0
    Rainy_Day_1
    Rainy_Day_2
    Rainy_Day_3
    Rainy_Day_4
    合并为 Rainy_Day
    Rainy_Night_0
    Rainy_Night_1
    Rainy_Night_2
    Rainy_Night_3
    Rainy_Night_4
    Rainy_Night_5
    Rainy_Night_<NPC name>
    合并为 Rainy_Night
  • 修复了如下问题:在 1.6.0+ 版本中,如果玩家与 NPC 有至少 2 心友谊,则 <location>_<x>_<y><location>_<dayOfWeek> 对话键永远不会触发。
  • 修复了地点对话无法识别 spring 前缀的问题(先前只能识别 summerfallwinter)。
  • 修复了在多个 $r 选项中复用同一个对话键,导致 $r 定义的回答 ID 无法被正确记录的问题。

附魔数据

附魔部分地去硬编码化,其数据迁移至新增的 Data/Enchantments 数据素材。现在模组可以方便地添加新的附魔,包括在锻造台上消耗五彩碎片或自定义物品的附魔。

然而,如下逻辑仍是硬编码的:

  • 龙牙附魔。尽管龙牙附魔位于数据文件中,抽取龙牙附魔的逻辑仍是硬编码的。
  • 使用钻石强化武器,以用尽剩余强化次数
  • 使用 3 个银河之魂将银河武器强化为无限武器(尽管“银河之魂”附魔位于数据文件中,该转化过程仍是硬编码的)。
  • 某些附魔效果(尽管武器增益效果位于数据文件中)。

附魔数据素材文件包含一个“字符串 → 数据模型”查询,其中:

字段 效果
DisplayName 一个模板字符串用于显示附魔名称。可以包含标记 {0} 以显示附魔等级(如适用)。
ForgeWith (可选)此字段表示可以在锻造台上消耗具有指定限定性 ID 的物品来获得此附魔。默认为空,此时代表无法通过锻造台获得此附魔。
AppliesTo (可选)此附魔适用的工具或武器。默认为全部工具/武器。

此字段为一系列上下文标签查询所组成的数组。如果其中至少一个查询匹配成功,则可应用此附魔。

"AppliesTo": [
    "melee_weapon, !is_scythe", // 非镰刀近战武器
    "hoe, upgrade_level_4"      // 铱或更高级锄头
]
IsForge (可选)是否为通过锻造台达成的武器强化。默认为 false。
IsSecondary (可选)是否为龙牙附魔,即,需要在锻造台上消耗龙牙。默认为 false。
IsVisible (可选)是否应当在工具栏中显示此附魔名称。默认为 true。
MaximumLevel (可选)可以在同一件工具上叠加此附魔的次数(例如,此字段可用于武器强化)。取值为 1 代表仅有 1 个附魔等级,也就是只能对同一工具使用此附魔至多一次。默认为 1。
EquipmentEffects (可选)此附魔带来的增益。

此字段为包含如下字段的数据模型所组成的列表。您可以指定任意数量的表项;第一个匹配成功的表项会被采用。

字段 效果
Id 此表项的唯一字符串 ID
MinLevel (可选)此加成生效所需的最小附魔等级。默认为 0(即,任何等级)。
其他字段 参见 Data/Buff 中的 Effects 字段,后者等价于此数据模型。
高级
CustomFields (可选)此条目的自定义字段
ClassName (可选,专用)需要构造的 C# 类,需位于 StardewValley.Enchantments 命名空间下。此类必须为 StardewValley.Enchantments.Enchantment 的子类,且其构造函数不能有任何参数。例如,将此字段设为 BottomlessEnchantment,则游戏会创建 StardewValley.Enchantments.BottomlessEnchantment 的实例。

通常,此字段应当被忽略,此时游戏会创建一个通用的 Enchantment 实例,该实例会使用 Data/Enchantments 中对应 ID 的数据。


事件更改

多语言事件

新版中,原版事件脚本可以使用翻译键来支持所有语言,而无需像旧版那样为每种语言单独设置文件。旧版中各语言的翻译被迁移到了各自的 Strings/Events 文件。

1.6.15 文件 1.7 文件
Data/Events/Beach
Data/Events/Beach.de-DE
Data/Events/Beach.es-ES
Data/Events/Beach.fr-FR
Data/Events/Beach.hu-HU
Data/Events/Beach.it-IT
Data/Events/Beach.ja-JP
Data/Events/Beach.ko-KR
Data/Events/Beach.pt-BR
Data/Events/Beach.ru-RU
Data/Events/Beach.tr-TR
Data/Events/Beach.zh-CN
Data/Events/Beach

Content Patcher 内容包应该大体上不受影响。对于旧版游戏,Content Patcher 会自动编辑事件的语言变体文件;而对于新版游戏,Content Patcher 会自动编辑统一后的事件文件。即,Content Patcher 会自动编辑正确的文件。

在极少数情况下,如果模组直接编辑带本地化后缀的素材名称(例如 Data/Events/Beach.fr-FR),则可能会出错或损坏游戏内容(具体取决于其编辑方式)。这种情况应当罕有发生,因为 Content Patcher 和 SMAPI 的 API 都不鼓励这样做。

弃用分支

旧版中的所有事件分支都将替换为 goto 命令。

为了向后兼容,分支仍能正常工作,但模组事件应当优先考虑 goto 命令,因为:

  • goto 命令与其他功能(例如,跳过事件)更协调,更符合直觉;
  • 游戏的未来版本开发将遵循此路径;
  • 如果使用 EventValidator,弃用的命令会报错;
  • 不保证未来版本总是兼容事件分支。

现在有关分支的事件命令已弃用

数值型事件ID也需要斜杠

在星露谷物语 1.6.0–15 版本中,如果事件键不包含斜杠 /,则其行为取决于 ID 是否为数值型。数值型事件 ID,例如 10040609,会被视为一个无前提条件的事件;而字符串事件 ID,例如 PlayerKilled,则会被视为事件脚本。在 1.7+ 版本中,此行为更加一致:不包含斜杠的事件 ID(例如 10040609)均被视为事件脚本,而包含斜杠的 ID(例如 10040609/)则被视为事件。

换而言之:

事件键格式 1.6.15 行为 1.7 行为
<id> event if numeric, else manual script 手动脚本
<id>/[preconditions] 事件 事件


新增命令

新增了如下命令:

命令 描述
addAchievement <achievement ID> 为当前玩家解锁一项成就。其中 <achievement ID> 可以为平台成就 ID(例如 Achievement_LocalLegend)或内部 ID(例如 17 “美食大厨”)。
addActor <x> <y> <direction> 向事件添加角色或玩家。此命令与角色初始化字段大致相同,不同于后者的是,此命令能够用于脚本中的任何位置,而无需置于脚本开头。例如,您可以将此命令搭配 goto 使用,以用于事件变体。
choose <question> [<answer> <response ID> <go to label>]+ 显示一个对话框,让玩家选择一个回答。您还可以保存回答 ID,并跳转到当前回答对应的一个标签处。

参数列表:

参数 用法
<question> 一个翻译键,或纯文本,用于显示问题。可以留空("")以忽略问题文本。
<answer> 一个翻译键,或纯文本,用于显示一条回答。
<response ID> 如果玩家选择了此条回答,则保存回答 ID,以备随后使用(例如,以备 PLAYER_HAS_DIALOGUE_ANSWER 查询)。可以为 ""_,代表不保存回答 ID。
<go to label> 如果玩家选择了此条回答,则跳转到此标签处(参见 goto 命令以了解更多)。可以为 ""_ 代表不跳转,继续执行下一条命令。

下面的代码只是让玩家选择一条回答,并无其他影响:

choose "你喜欢苹果吗?" "喜欢。" _ _ "不喜欢。" _ _/

也可以像下面这样,让回答影响事件走向:

speak Abigail "你……喜欢我?$l"/
choose "" "当然!" _ happy "不。" _ heartbroken/

label heartbroken/
speak Abigail "哦……我明白了。$s"/
faceDirection Abigail left/
pause 3000/
end/

label happy/
speak Abigail "我们下次应该一起取探索矿井!$h"/
...
completeQuest <id> 标记一个任务为已完成。如果该任务没有待收集的奖励,也将其从游戏内的“日志”中移除。
conditionSpeak <npc> [<dialogue> [condition]]+ 使 NPC 基于特定条件讲话。如果指定了多组对话-条件,则选取第一条条件匹配的对话。如果没有满足条件的对话,则跳过此命令。

参数:

参数 用户
<npc> 讲话的 NPC 的内部名称(可以标记为可选 NPC)。
<dialogue> 对话内容,可以为翻译键或纯文本。如果忽略或为空字符串,则条件匹配时会跳过此命令。
[condition] 下列之一:
  • 一条游戏状态查询
  • ANSWERED <response ID>+,此命令 PLAYER_HAS_DIALOGUE_ANSWER Current 的缩写。
  • 或省略/留空,代表总是匹配此对话(前提是前面所列对话全部匹配失败)。

例如,下面的代码中,玛鲁会根据玩家所选的不同回答作出不同的反应:

conditionSpeak Maru "我不小心摔碎了一份样本……真是对不起。$s" "ANSWERED 38" "@进来后猛地一关门,吓得我打碎了一份样本。$u"
goto [<target> [condition]]+ 跳转到事件脚本的指定位置。其中 <target> 可以是:
target 描述
end 跳转到最后一个 end 事件命令处。
其他 跳转到第一个名称为 <target>label 处。

您可以给出任意多对标签-条件,事件会跳转到第一个满足条件的标签处。若忽略条件,则默认为 true。如果任何条件都不满足,则会继续下一条事件命令。

如下事件脚本使用了 goto 命令,用于重复一个问题,直到玩家选择了指定的回答:

.../
label question/
choose Abigail "嘿!你是不是看上谁了?" "阿比盖尔" correct "潘妮" wrong "亚历克斯" wrong/

label wrong/
speak Abigail "哦?$u"/
pause 500/
goto question/

label correct/
speak Abigail \"我也这么想!$l\"/
pause 500/
end

此命令的 [condition] 参数应当为游戏状态查询。例如,如下代码会在与阿比盖尔离婚的情况下跳转到 divorced 标签,否则继续执行下条命令:

goto divorced "PLAYER_NPC_RELATIONSHIP Current Abigail Divorced"/
label <label> 在事件脚本中设置一个标签,以备 goto 命令调用。

注意:标签名称不能为 end,因为该关键字用于跳转到事件最后。

优化命令

优化了现有命令:

命令 描述
gainSkill 添加了参数验证。
skippable 添加了一个可选的 [skip to label] 参数。若指定此参数,则当玩家点击跳过按钮时,会跳转到指定标签处(参见 goto 以了解更多)。会使用玩家点击“跳过”按钮前最后一条 skippable 命令。

这主要用于在事件结束前做清理或保证解锁事物,例如:

skippable beforeEnd/
.../
label beforeEnd/
gainSkill Fishing 1/
addItem (T)TrainingRod/
end

技术上而言,您可以跳转到事件中的任意位置(例如,用于取消跳过)。然而,跳过操作仍会取消正在进行中的事件行为,例如玩家 / NPC 的移动,因此应当谨慎使用此命令。

splitSpeak 现在您应当将每条对话指定为独立的参数(尽管旧版语法仍可运行):
// 1.6.15
splitSpeak Sam "你也是这样想的?~对……孩子们应该把握这个机会拥有一个快乐的童年。"

// 1.7
splitSpeak Sam "你也是这样想的?" "对……孩子们应该把握这个机会拥有一个快乐的童年。"

此命令现在也可与新增的 choose 一同使用。

spriteText 现在 [text] 参数可以为翻译键

过时命令

如下事件命令已弃用。它们仍正常工作(除了表格末尾列出的命令),但如果使用 EventValidator,则会报错。

事件命令 迁移指南
fork
resetVariable
switchEvent
使用 choosegoto 命令。如果您仍在使用包含 %fork 标记的对话, 则应删除这些标记,并用等价的事件命令取而代之。
question forkX 使用 choose 命令,并用标签取代分支名称。

考虑如下代码

// main event
question fork1 "#I believe in you!#Wow, you're really arrogant."/
fork arrogant/
speak Alex "Thanks, @. I'll remember that."/
...

// 'arrogant' event
emote Alex 12/
speak Alex "Hmmph... I think someone's a little jealous.$a"/

应更新为:

choose "" "I believe in you!" believe "Wow, you're really arrogant." arrogant/

label believe/
speak Alex "Thanks, @. I'll remember that."/
...

label arrogant/
emote Alex 12/
speak Alex "Hmmph... I think someone's a little jealous.$a"/
...

旧版中,即使两个分支结局相同,也必须分别添加代码,造成了重复代码。新版中,可以使用 goto 命令直接跳转到结局处,从而避免了重复代码。

question null 使用 choose,并将标签参数指定为 _ (标签参数 _ 代表顺次执行下一条命令。)

考虑如下旧版代码:

question null "But what am I going to say to Vincent?#It's best to be honest with kids.#You did the right thing. Kids should have hope."/

应当更新为:

choose "But what am I going to say to Vincent?" "It's best to be honest with kids." _ "You did the right thing. Kids should have hope." _/
quickQuestion 使用 choose 命令。其中 <question><answerX> 参数用法相同,而旧版的 <answerX script> 参数变成了标签。

考虑如下旧版代码:

quickQuestion #我愿意帮忙#不,算了……(break)emote Willy 32\speak Willy "好嘞……我知道你会帮忙的,${小伙子^小姑娘}$。$h"\speak Willy "这扇门我就给你开着……你收集好材料之后可以随时来这里摆好。"(break)emote Willy 28\speak Willy "好吧,随你便……$s#$b#如果你改变主意了,可以会来这里帮忙。我还是把这扇门开着。"/

应当更新为:

choose "" "我愿意帮忙" accept "不,算了……" refuse/

label accept/
emote Willy 32/
speak Willy "好嘞……我知道你会帮忙的,$h#$b#这扇门我就给你开着…… 你收集好材料之后可以随时来这里摆好。"/
goto resume/

label refuse/
emote Willy 28/
speak Willy "好吧,随你便……$s#$b#如果你改变主意了,可以会来这里帮忙。我还是把这扇门开着。"/

label resume/
cutscene bandfork
elliottBookTalk
question haleyDarkRoom
question shaneCliffs
question shaneLoan
这些命令已被删除,不再正常工作。它们不太可能被用于模组事件,但如果确有需要,请参见相应的事件代码。

事件键更改

1.7 中,事件基本上得到了统一,并去除了硬编码。特别地:

  • 旧版中某几个事件定义在游戏的 C# 代码中,因此无法被内容包更改。现在,它们中的大部分已迁移至 Data/Events/*,其翻译则迁移至 Strings/Events
    事件 新素材名 新事件ID
    森林浣熊完成事件 Data/Events/Forest RaccoonFinish
    垃圾清理熊完成 Data/Events/Forest 777111
    姜岛饕餮青蛙作物检查 Data/Events/islandFarmCave GourmandInspection
    顶峰完美过场动画 Data/Events/Summit SummitPerfection
    顶峰作弊事件 Data/Events/Summit SummitCheat
  • 其他事件则从非事件数据迁移到了 Data/Events/*:
    事件 旧位置 新素材 新事件ID
    贝啼任务介绍和完成 Strings/Locations:IslandSecret_Event_BirdieIntro
    Strings/Locations:IslandSecret_Event_BirdieFinished
    Strings/Locations:alreadyGotNuts
    Data/Events/IslandWest -888999 (intro)
    -666777 (completed)
    岛屿办事处介绍和完成 Strings/Locations:IslandFieldOffice_Intro_Event
    Strings/Locations:FieldOfficeFinale
    Data/Events/IslandFieldOffice FieldOfficeIntro
    FieldOfficeDone
    雷欧介绍 Strings/Locations:IslandHut_Event_ParrotBoyIntro Data/Events/IslandHut LeoIntro
    彩虹猫之刃事件 Strings/1_6_Strings:ForestPylonEvent Data/Events/WizardHouseBasement ForestPylon
    齐先生骷髅洞穴 100 层 Data/ExtraDialogue:SkullCavern_100_event
    Data/ExtraDialogue:SkullCavern_100_event_honorable
    Data/Events/SkullCave SkullCavern100
    蜗牛教授逃出洞穴 Strings/Locations:IslandNorth_Event_SafariManAppear Data/Events/IslandNorth ProfSnailIntro
  • 其他事件键或者发生更改,或者合并到其他事件:
    素材 1.7 更改
    Data/Events/AbandonedJojaMart missingBundleComplete 事件键改为 192393 以匹配事件 ID。
    Data/Events/Farm 992559/t 600 1130/n clothFound/o Emily/w sunny
    992559/t 600 1130/n clothFound/O Emily/w sunny
    合并为 992559/Time 600 1130/LocalMail clothFound/Weather sunny 事件。
    Data/Events/QiNutRoom 10040609 事件键改为 10040609/ 以配合事件前提的更改
    Data/Events/SamHouse 94/e 93/k 95/t 1800 1950/i 136/y 1
    94/e 93/k 95/t 1800 1950/i 136/y 2
    合并为 95/SawEvent 93/!SawEvent 94/Time 1800 1950/HasItem 136 事件。
    Data/Events/Town 611173/Hn pamHouseUpgrade/o Penny 合并到现有的 611173/Hn pamHouseUpgrade 事件。

对于先前没有 ID 的事件,其新 ID 会在加载存档时按需添加到玩家的已看事件列表中。


其他更改

  • 将所有原版事件的“跳过”逻辑移植到事件脚本中(除了宠物收养逻辑)。
  • 顶峰事件移动到了新增的 Data/Events/Summit 文件中。

游戏状态查询更改

添加了新的游戏状态查询:

条件 效果
IS_DEBRIS_WEATHER
IS_GREEN_RAINING
IS_LIGHTNING
IS_RAINING
IS_SNOWING
目标地点的天气是否设置相应的天气字段。例如,IS_RAININGRainGreenRainStorm 天气时为 true。
LOCATION_MINE_DIFFICULTY <location> <min> [max] 给定地点是否位于矿井骷髅洞穴,且其难度等级介于 <min>[max](默认为无穷) 之间,包含端点值。难度 0 代表默认难度,而挑战之神庙或某些特别任务会使难度加一。
LOCATION_MINE_LEVEL <location> <min> [max] 给定地点是否位于矿井骷髅洞穴,且其层数介于 <min>[max](默认为无穷)之间,包含端点值。骷髅洞穴隐式地开始于 121 层(例如,骷髅洞穴第 10 层实际上是矿井第 130 层)。
PLAYER_HAS_PREVIOUS_CONVERSATION_TOPIC <player> <id>+ 指定玩家先前是否经历过指定的若干对话主题中的任何一个。不包括当前的对话主题(除非曾经经历过当前对话主题)。
PLAYER_QUEST_ACTIVE <player> <id>+
PLAYER_QUEST_COMPLETE <player> <id>+
指定玩家是否有任何一个指定的任务 ID 处于活跃状态(PLAYER_QUEST_ACTIVE)或已完成状态(PLAYER_QUEST_COMPLETE)。

物品查询更改

新增了一个物品查询:

查询 效果
SEASONAL_RACCOON_SEED 获取当季的季节性浣熊种子

其堆叠数量取决于玩家运气。在物品生成字段使用此查询时,也可设置 MinStackMaxStack 以覆盖默认堆叠数量。

物品生成字段更改

  • 新增了物品生成字段:
    字段 效果
    Color (可选)适用于支持颜色的物品类型(例如,物体和衣服)。此字段为生成物品的色调。默认为空。
    Enchantments (可选)适用于工具和武器。此字段为待应用的附魔 ID(与 Data/Enchantments 中的 ID 相同)。此字段应用常规的附魔规则。默认为空。

    此字段应当指定为数组,并且可以重复龙牙附魔以提升其等级。例如,下述代码提供“吸血鬼”和“攻击”(等级 2)附魔:

    "Enchantments": [ "Vampiric", "Attack", "Attack" ]
    
    IsSpecial (可选)是否将产出的物品标记为特殊的永久物品,即,无法被摧毁或丢弃。默认为 false。
    ObjectIsQuestItem (可选)是否将产出的物品标记为任务物品。这会启用一系列规则,例如禁止将物品作为礼物送出,且在物品丢失时自动找回。默认为 false。
    TempData (可选)设置掉落物信息,该信息不会在合作模式中同步,也不会写入存档。某种意义上这是专用的,如果没有处理它的游戏逻辑或 C# 模组逻辑,此字段不会发挥任何作用。默认为空。

    下面的代码添加了一个自定义标识:

    "TempData": {
        "SomeExampleKey": "Example Value"
    }
    

    设置此字段后,可使用如下的 C# 代码读取此临时信息:

    if (item.TryGetTempData("SomeExampleKey", out object value))
        ...;
    
  • ObjectColor 字段已过时,其被 Color 替代。设置该旧版字段的内容包仍能正常运行(因为游戏会自动将其值传入 Color )。

地图属性更改

  • 新增了地图属性:
    动作 效果
    FarmHouseBed <x> <y> [item ID]
    (仅用于农场或农舍)
    创建农舍或联机小屋时,设置床的初始位置。各参数分别为:
    • <x> <y>:用于放置床的地块坐标
    • [item ID]:(可选)床的物品 ID,可以为限定性或非限定性的。此字段仅接受物品类型为 Bed家具物品。默认为 (F)2048单人床)。

    若忽略,则一张单人床会被放置在地块 (9, 8) 处。

  • 改进了地图属性:
    动作 更改
    FarmHouseFlooring
    FarmHouseFurniture
    FarmHouseStarterGift
    FarmHouseStarterSeedsPosition
    FarmHouseWallpaper
    现在可以在农舍地图中设置这些属性,以覆盖农场地图设置的等价属性。
    FarmHouseFurniture 修复了该属性仅接受数值型物品 ID 的问题。

日程更改

  • 新增了日程键:
    语法 概述
    roommate_<festival ID>_<festival day>
    roommate_<festival ID>
    roommate_<season>_<day of month>
    roommate_<day of week>
    roommateJob
    等价于结婚日程的室友版本。

    如果室友 NPC 同时具有 roommate*marriage* 日程,则会优先使用合适的 roommate* 日程。如果不存在适用的室友日程,则会默认使用对应的 marriage* 日程。您可以通过设置 roommate 备用值以免回退到结婚日程。

    marriage
    roommate
    备用值。如果更具体的对话皆不适用,则使用此值。若此备用值被忽略,且没有其他适用的日程,则 NPC 当天不会有任何日程。

触发动作更改

  • 新增触发动作:
    动作 效果
    CompleteQuest <quest ID> 完成玩家日志中所有具有指定 ID 的、活跃中的任务。

其他更改

  • 添加了行程结束动画中 offset 命令的校验。
  • 修复了加载没有建筑内部的存档时的崩溃。
  • 修复了法师以外的 NPC 提出交易烹饪物品的任务时偶尔崩溃的问题。
  • 修复了 RejectItem_* 对话出现后会禁用相应 NPC 的正常对话的问题。
  • 修复了 NPC FlowerDanceCanDance 字段 忽略无对话且不可约会的 NPC 的问题。

C#模组的重要更改

实例化静态不再影响模组程序集

分屏模式中,游戏会在不同分屏之间交换静态字段的值(这称为“实例化静态”,instanced statics)。在旧版中,所有带 [InstancedStatic] 属性的静态字段对应的程序集都会被扫描,除了少数被忽略的程序集,例如 MonoGame。

在 Stardew Valley 1.7 中,游戏仅扫描游戏主程序集以提升性能。如果模组仍在使用 [InstancedStatic] 属性,则应当将其替换为 SMAPI 内建的 PerScreen 工具类。

AssetNameUtility

新增的 AssetNameUtility 类提供了处理素材名称的方法:

方法 用途
Normalize 用于正规化素材名称中的路径分隔符的低阶方法。例如:
string assetName = AssetNameUtility.Normalize("Characters/\\/Abigail"); // 返回 "Characters/Abigail"

请考虑使用 SMAPI 的 PathUtilities.NormalizeAssetName 而非此方法,因为前者更彻底。

TryParseTranslationKey 将一个翻译键拆解其为组成部分。示例:
if (AssetNameUtility.TryParseTranslationKey("Strings/UI:Confirm", out string assetName, out string fieldKey, out string error))
   ...;  // assetName: Strings/UI, fieldKey: Confirm, error: null

此方法不会检查素材或键名是否存在;请使用 Game1.content.IsValidTranslationKey 检查存在性。

DialogueKeyValidator

新增的 DialogueKeyValidator(对话键校验器)用于分析对话条目以排查不符合预定模式的对话键。

这主要用于单元测试。下面的代码展示了如何验证某一数据素材中的所有对话键:

string assetName = "Characters/Dialogues/Abigail";
var dialogues = Game1.content.Load<Dictionary<string, string>>(assetName);

var validator = new DialogueKeyValidator();
foreach ((string key, string dialogue) in dialogues)
{
    if (!validator.IsKnownFormat(assetName, key))
        Assert.Fail($"Validation failed for dialogue '{key}': key doesn't match one of the expected patterns.");
}

您也可以通过设置校验器字段,例如 MarriageDialogueKeyPatterns ,来扩充可用的模式。


EventValidator

概览

新增的 EventValidator 类(事件校验器)可用于分析事件脚本,以检测下列问题:

  • 命令名称不是已注册的命令名或别名;
  • 命令参数不符合预期;
  • 基于 validator.CommandValidators 的自定义规则(例如,默认的校验器会检查 goto 的标签是否合法)。

这主要用于事件的单元测试。例如,下述代码会校验一个数据素材中的所有事件:

string assetName = "Data/Events/Farm";
var events = Game1.content.Load<Dictionary<string, string>>(assetName);

var validator = new EventValidator();
foreach ((string key, string script) in events)
{
    foreach (var issue in validator.Validator(assetName, key, script))
        Assert.Fail($"Validation failed for event '{key}' > command '{issue.CommandText}': {issue.SuggestedError}.");
}

命令参数校验

开启参数校验的方法是,在命令的处理器方法中提供 EventArguments 参数,该参数是一种特殊的表达式,用于检查命令参数是否合法。每条命令可以给出多个参数模式,只要其中一个匹配通过,则认为该参数是合法的。如果模式串是空字符串,则要求命令不能有任何参数。

例如,默认的 showFrame 定义如下:

[EventArguments("int", "actor int bool?")]
public static void ShowFrame(Event @event, string[] args, EventContext context)

一个参数模式串由“标记”(token)组成,由空格分开。其中,每个标记都定义了一个参数的格式。例如,actor int bool? 有三个标记,分别代表三个参数:一个演员名称、一个正整数和一个可选的布尔值。

校验器可识别的标记如下:

标记 含义
通用参数类型
bool 一个布尔类型值(truefalse)。
float 一个正数,可以带小数点(例如 50.5)。
-float 一个数,可以带小数点,也可以带负号(例如 5-5-0.5)。
int 一个正整数(例如 5)。
-int 一个整数,可以带负号(例如 5-5)。
string 一段被引号包围的文本,例如 "some words here"。如果参数不带引号,则该标记等价于 word 标记。
word 一个由字母、数字、句点和/或下划线组成的单词(通常为 ID 或类似值)。虽然命令可以接受引号,但它们是多余的,且会被校验器拒绝。
remainder 一个或多个任何类型的参数。
特殊字符串格式
actor 事件格式中的演员名称(例如 AbigailKent?)。
assetName 素材名称,例如 Data/Achievements
direction 面部朝向,可以使用数值型(0)或字符串型(up)。
goToLabel 一个事件标签(参见 gotolabel 事件命令)。这等价于 word,但用于 EventValidator,以校验标签引用。
itemId 物品ID,可以为限定性或非限定性的(例如 (O)MossySoupMossySoup)。
translationKey 翻译键,例如 Strings/Locations:SomeKey
自定义格式
'...' 单引号中可以使用纯文本或正则表达式进行匹配,例如 'continue''[\w-]+'

此外,您可以使用如下的指示器来扩展标记:

  • + 后缀代表此类型的参数可以重复出现多次。例如, int+ 会允许 55 6 7 通过。
  • ? 后缀代表此可选参数,即,此参数可被省略。此标记后面的所有标记都必须也对应可选参数。(也可指定 int+? 这样的标记,代表可选参数可以重复多次)。
  • | 中缀代表此参数可能是多种候选类型之一。例如,int|bool 允许整数或布尔值通过。

内容管理器更改

游戏本体的“内容管理器”(content manager)API 在星露谷 1.7 中发生了变化。这主要影响 LanguageCodeGame1.content 和其他的内容管理器字段。仅使用 SMAPI 的 Content API 的模组不受影响。

特别地:

  • 现在游戏在大多数地方使用 IContentManager 而非 LocalizedContentManager 。这包括像 Game1.content 的字段,像 Game1.content.CreateTemporary() 的方法,等等。新接口也提供了完整的 IntelliSense 文档。
  • 迁移了三种类型:
    类型 更改
    LocalizedContentManager StardewValley 命名空间迁移至 StardewValley.ContentManagement
    LocalizedContentManager.LanguageCode
    LocalizedContentManager.LanguageChangedHandler
    • StardewValley 命名空间迁移至 StardewValley.ContentManagement
    • 移出了嵌套类型(例如,在模组代码中将 LocalizedContentManager.LanguageCode 更改为 LanguageCode)。
  • 并且更改了某些 LocalizedContentManager 成员:
    类型 成员 更改
    LocalizedContentManager CurrentLanguageCode
    CurrentLanguageLatin
    CurrentLanguageString
    CurrentModLanguage
    GetDefaultLanguageCode()
    OnLanguageChange
    SetModLanguage(…)
    它们不再是静态的,因此必须通过一个实例调用之,例如 Game1.content 。举例而言,在模组代码中将 LocalizedContentManager.GetDefaultLanguageCode() 更改为 Game1.content.GetDefaultLanguageCode()

    其中某些成员已被重命名。

    CurrentCulture 已移除(未被使用)。
    CurrentLanguageCode 重命名为 LanguageCode
    CurrentLanguageLatin 重命名为 LanguageUsesLatinFont
    CurrentLanguageString 重命名为 LanguageString
    CurrentModLanguage 重命名为 LanguageModData
    GetCurrentLanguage() 已移除。请使用 LanguageCode 属性代替之。
    OnLanguageChange 重命名为 OnGlobalLanguageChanged
  • 添加了 SourceCodeContentManager 作为 IContentManager 的一个实现。这主要用于内部单元测试,一般对模组开发者无用,除了可以参考代码写法。


物品更改

  • 新增 IItemDataDefinition.GetContextTags(itemData) 方法,因此自定义 DataDefinition 类可以根据其数据添加上下文标签
  • 修复了 item.CopyFieldsFrom(other) 总将拷贝的堆叠数设为 1 的问题。

怪物更改

  • 怪物数据已大修
  • 新增的 monster.Tags 字段包含了一系列关于怪物的元数据标签,可以在 Data/Monsters 中查看。可以安全地向现有怪物类型的标签列表中添加新标签。
  • 旧版的 monster.objectsToDrop 字段(字符串物品 ID 组成的列表)已被替换为 monster.drops(一个 Inventory 类)。
  • 移除了 monster.getExtraDropItems()。新版中,掉落物应当添加到 Data/Monsters

工具字段和方法

  • 1.6.9 新增了许多工具方法和字段。例如:
    类型 成员 用法
    PassiveFestivalData CoversDate(…) 判断节日是否在指定日期处于活跃状态。
    GetFestivalLocations() 获取被动节日发生的日期(基于 Data/PassiveFestivals 中的 InLocationsMapReplacements 字段)。
    TryGetLocationReplacement(…) 获取被动节日期间用于覆盖常规地点的临时地点。例如,夜市期间 BeachNightMarket(夜市海滩)会覆盖 Beach (海滩)地点。
    Utility TryGetPassiveFestivalDataForDayHere(…) 获取指定地点内指定日期的被动节日(若有)。这等价于 Utility.TryGetPassiveFestivalDataForDay(…),但也会根据被动节日的 InLocationMapReplacements 字段检查地点是否符合条件。

其他破坏性API更改

(本节旨在当您遇到构建错误时为您提供快速参考;否则无需阅读。)

移除或重命名的类型

下列类在 1.7 版本中被移除或重命名:

类型 迁移
BaseEnchantment 重命名为 Enchantment
AxeEnchantment
BaseWeaponEnchantment
FishingRodEnchantment
HoeEnchantment
MilkPailEnchantment
PanEnchantment
PickaxeEnchantment
ShearsEnchantment
WateringCanEnchantment
弃用。现在附魔通过数据绑定到工具。
Events.DiaryEvent 已移除。未被使用。

其他API更改

下列类成员在 1.7 中发生了更改:

类型 成员 迁移方法
BaseEnchantment
(及其子类)
hideEnchantmentName 替换为 EnchantmentManager.HideEnchantmentName
hideSecondaryEnchantName 替换为 EnchantmentManager.HideSecondaryEnchantName
GetEnchantmentFromItem(…) 替换为 EnchantmentManager.GetEnchantmentFromItem
GetAvailableEnchantments() 已移除。
  • 为检查是否可以通过锻造台为某工具添加某附魔,请使用 EnchantmentManager.CanForgeEnchant
  • 尽管在 1.7 不存在直接等价的方法,您仍可模仿旧版逻辑(如有需要)。
    static List<Enchantment> GetAvailableEnchantments()
    {
        var dataAsset = DataLoader.Enchantments(Game1.content);
    
        List<Enchantment> enchantments = [];
        foreach ((string id, EnchantmentData data) in dataAsset)
        {
            if (data.ForgeWith == Object.prismaticShardQID)
                enchantments.Add(EnchantmentManager.CreateEnchantment(dataAsset, id));
        }
    
        return enchantments;
    }
    
GetAvailableEnchantmentsForItem(…) 已移除。
  • 为检查是否可以通过锻造台为某工具添加某附魔,请使用 EnchantmentManager.CanForgeEnchant
  • 尽管在 1.7 不存在直接等价的方法,您仍可模仿旧版逻辑(如有需要)。
    static List<Enchantment> GetAvailableEnchantmentsForItem(Item? tool, Item? item)
    {
        var dataAsset = DataLoader.Enchantments(Game1.content);
        var contextTags = tool?.GetContextTags();
    
        List<Enchantment> enchantments = [];
        foreach ((string id, EnchantmentData data) in dataAsset)
        {
            if (data.ForgeWith == Object.prismaticShardQID && (contextTags is null || EnchantmentManager.MatchesTags(contextTags, data.AppliesTo)))
                enchantments.Add(EnchantmentManager.CreateEnchantment(dataAsset, id));
        }
    
        return enchantments;
    }
    
GetName() 已移除。此方法会根据附魔类型,不一致地返回 ID、显示名称或 "Unknown Enchantment"。请使用新增的 Id 属性,或现有的 GetDisplayName()方法。
GetLevel() 已移除。请使用 Level
GetType() 此方法某些情况下用于识别附魔(例如 enchantment.GetType() == expectedEnchantment.GetType())。这不再可靠,因为 1.7 中引入了基于数据的附魔,这种附魔可能不存在相应的 C# 类型。请使用新的 enchantment.Id 属性。
ResetEnchantments() 已移除。不再需要此方法,因为不再存在附魔实例的缓存列表。
Boots price 已移除。此字段从未被使用过,因为靴子的价格是动态计算的。
Bush draw(SpriteBatch batch, int yDrawOffset) 已移除。请设置 drawOffset 并调用 draw(SpriteBatch) 以实现相同目的。
yDrawOffset drawOffset 取代,新字段是公开的 Point 型对象。
FishingRod lastCatchWasJunk 重命名为 lastCatchSkippedMinigame 以更准确地描述其实际行为。
Furniture armchair
bed
bench
bookcase
chair
couch
decor
dresser
fireplace
lamp
longTable
other
painting
rug
sconce
table
torch
window
已移除。替换为 FurnitureType 枚举(例如,旧版的 Furniture.rug 在新版中为 FurnitureType.Rug)。
placementRestrictions 已移除。替换为 CanPlaceIndoorsCanPlaceOutdoors
Monster getExtraDropItems() 已移除。新版中,掉落物应当添加到 Data/Monsters

Harmony 补丁无法迁移至数据文件,但可以将目标更改至 Monster.RollForDrops

objectsToDrop 已移除。替换为 drops;参见怪物更改以及 Data/Monsters
NPCDialogueResponse
Response
id
friendshipChange
extraArgument
hotkey
responseText
将字段变更为只读。
responseKey
  • 将字段变更为只读。
  • 先前的 NPCDialogueResponse 会在此字段中存储 NPC 的反应对话键。现在应当使用 npcReactionKey 替换之。
SetHotKey(…) 已移除。现在请通过构造函数设置热键。
Tool GetEnchantmentLevel<T>()
GetEnchantmentOfType<T>()
hasEnchantmentOfType<T>()
已移除。分别替换为 GetEnchantmentLevel(id)GetEnchantment(id)HasEnchantment(id)。所有原版附魔的 ID 都有对应的常量,例如 EnchantmentIds.GalaxySoul

其他更改

  • 新增 PlatformAchievementIdsQuestIds 常量。
  • 新增 event.floorSprites 字段用于处理应当绘制在地面上的临时动画贴图(例如,NPC 的影子)。
  • 现在游戏在所有素材名称中均使用正斜杠(例如 Map/Town 而非 Maps\Town)。这应当对大多数模组无影响,因为 SMAPI 已将所有素材名称转换为正斜杠格式。
  • 移除了已损坏的 Lantern 工具,Raft 工具以及相应的逻辑。
  • 修复了 Event.TryGetEventCommandHandler 在其他方法前被调用就会无法加载命令的问题。
  • 修复了机器自动装填第二种原料时,会在箱子中留下空槽位的问题。
  • 修复了将容器型家具(例如梳妆台或鱼缸)放置在桌子上会清空其内容物的问题。

译名更改

中文没有进行任何译名更改。

对XNB的影响

概览

此节概述了星露谷物语 1.7 版本中 XNB 文件的更改。不包含新增文件(因为新增文件不会影响现有的模组)或非英语文件中的文本更改。

XNB 模组会受到不成比例的影响,因为:

  1. 它们会替换整个文件;
  2. 它们通过 MonoGame 内容管道加载,该管道对格式变化的容忍度较低;
  3. 它们无法受益于Content Patcher为其内容包提供的兼容性重写。

Content Patcher 一般不受影响(且 Content Patcher 会尝试自动改写内容包)。然而,如果某个内容包直接替换了整个素材文件而不是编辑它,则可能会受到类似于 XNB 模组的影响。

更改的素材

兼容性可以粗略划分为以下四类:

  • ✘ 已损坏”:旧版模组会删除游戏的新增内容或重大更改,或无法正常运行。坚持使用旧版模组可能带来从显示故障到游戏崩溃在内的各种问题,具体取决于游戏如何使用素材。
  • “✘ 影响更新”:旧版模组会删除 1.7 中的小更改(例如,错别字修复)。
  • “✓ 几乎无影响”:旧版模组一般不受影响,除非它们替换了整个素材文件,或编辑了特殊的条目或字段。
  • 空白:旧版模组一般不受影响。
内容素材 1.7 更改 对早于 1.7 版本模组的影响
XNB 模组 Content Patcher 内容包
Characters/Dialogue/*
  • 移除了新版不再需要的 %fork 标记;
  • 修复了漏洞和错别字。
✘ 影响更新
Data/Boots 格式大修 ✘ 已损坏 ✘ 已损坏
(直到 Content Patcher 添加了运行时迁移)
Data/Buffs 新增数据字段 ✘ 已损坏
Data/CookingRecipes 配方键名更改 ✘ 已损坏 ✓ 几乎无影响
(直到 Content Patcher 添加了运行时迁移)
Data/Events/*
Data/Events/Festivals/*
  • 迁移至多语言事件事件标签
  • 将大部分 awardFestivalPrize 命令替换为 addItem
  • 用于支持上述迁移的重大改动(例如,将对话命令替换为事件命令)。
✓ 几乎无影响 ✘ 影响更新
Data/Events/Farm 将事件 992559(艾米丽介绍裁缝)的变体迁移至新的事件键。 ✓ 几乎无影响 ✘ 影响更新
Data/Events/SamHouse 将事件 95(乔迪的 4 心事件)的变体合并至新的事件键。 ✓ 几乎无影响 ✘ 影响更新
Data/Events/Town 将事件 611173(潘姆的房屋升级)的变体合并至第二个键。 ✓ 几乎无影响 ✘ 影响更新
Data/ExtraDialogues ✓ 几乎无影响 ✓ 几乎无影响
Data/Furniture ✘ 已损坏 ✘ 已损坏
(直到 Content Patcher 添加了运行时迁移)
Data/Hats
  • 格式大修
  • 统一素材名称大小写(Data/hatsData/Hats)。
✘ 已损坏 ✘ 已损坏
(直到 Content Patcher 添加了运行时迁移)
Data/LocationContexts 更改了天气条件以修复重复随机化问题。 ✘ 影响更新 ✓ 几乎无影响
Data/LostItemsShop 新增字段 ✘ 已损坏
Data/Monsters 格式大修 ✘ 已损坏 ✘ 已损坏
(直到 Content Patcher 添加了运行时迁移)
Data/Objects 新增了上下文标签 ✘ 已损坏
Data/SpecialOrders 新增字段 ✘ 已损坏
Data/Tools ✘ 已损坏
Data/Weapons 新增字段 ✘ 已损坏
Data/Weddings 修复了刘易斯跳过婚礼祝词的问题。 ✓ 几乎无影响 ✘ 影响更新
Strings/Events 添加了多语言事件的翻译。 ✘ 已损坏
Maps/Bus(people)
Maps/busPeople
Maps/Island_Secret
已移除(这些字段未被使用)。
Strings/Events 新增了多语言事件的译文。 ✘ 已损坏
Strings/1_6_Strings 位于 ForestPylonEvent 字段,请参见 Data/Events 更改。 ✓ 几乎无影响 ✘ 影响更新
Strings/Furniture 新增物品类别描述的译文(迁移自 Strings/1_6_Strings)。 ✘ 已损坏
Strings/Locations 移除了硬编码事件 ✓ 几乎无影响 ✓ 几乎无影响
Strings/Objects 将某些译文迁至 Strings/Furniture ✓ 几乎无影响 ✓ 几乎无影响
Strings/StringsFromCSFiles
Strings/Tools
移除了某些未使用的翻译。
Strings/UI 合并了 PondQuery_StatusRequestPending_* 的性别变体。 ✓ 几乎无影响 ✘ 已损坏