模组:触发动作

来自Stardew Valley Wiki
跳到导航 跳到搜索

目录

此页面解释了触发动作,后者负责在某些事情发生时让内容包完成特定动作。(C#模组则通常应当使用SMAPI Events API。)

概览

简介

一个触发动作包括两个主要部分:

  • 触发条件是导致此动作发生的条件。它可以是一个Data/TriggerActions列表项、一条事件命令之类的东西。参见内建触发条件
  • 动作是由空格分隔的字符串,它定义了触发后执行的动作。例如,AddMail Current Robin会在第二天将标识为Robin的信件添加到玩家的邮箱中。参见参数格式内建动作


参数格式

参数之间使用空格分隔。例如,AddMail Current Abigail_LeoMoved Now 调用samp>AddMail动作并传入如下三个参数:Current(玩家)、Abigail_LeoMoved(信件ID)、Now(信件类型)。

若某个参数内部需要包括空格,则需使用半角双引号括起来。例如AddFriendshipPoints "Mister Qi" 10有两个参数(Mister Qi10)。如需在双引号内部使用空格,则应使用反斜杠 \ 转义,例如AddFriendshipPoints "Mister \"Qi\"" 10

请记住,JSON字符串内部的引号和反斜杠也需要转义。例如 "AddFriendshipPoints \"Mister Qi\" 10" 会向游戏代码发送。您也可以使用单引号表示JSON字符串,例如 'AddFriendshipPoints "Mister Qi" 10'

动作

内建动作

如下是任何触发条件都能使用的内建动作(其他自定义动作可以通过C#添加)。

动作 效果
AddBuff <buff ID> [milliseconds duration]
RemoveBuff <buff ID>
为当前玩家赋予或清除指定ID的效果。对于AddBuff,持续时间默认为此效果的默认持续时间;该值可以是 -2,以使效果持续一整天。
AddConversationTopic <topic ID> <day duration> 启动一个持续指定天数的对话主题。若已激活,则重置其持续时间为给定的天数。
RemoveConversationTopic <topic ID> 结束一个进行中的对话主题
AddFriendshipPoints <NPC name> <count> count}点友谊值<count>可以为负数,以减少友谊值。
AddItem <item ID> [count] [quality] 根据限定性或非限定性物品ID将物品添加到当前玩家的背包中,还可以选择数量(默认为 1)和[模组:物品数据#品质|品质]](默认为 0)。
RemoveItem <item ID> [count] 根据限定性或非限定性物品ID从玩家背包中删除物品,最大数量为 [count](默认为 1)。
AddMail <player> <mail ID> [type]
RemoveMail <player> <mail ID> [type]
添加或移除指定玩家信件标识或信件

其中<type>必须为下列取值之一:

<type> 效果
now 当前在玩家的邮箱中。
tomorrow 明天送达玩家邮箱。
received 已读(通过邮箱)。
all 从所有地方添加/移除(包括上面全部三种)。

若省略,则AddMail<type>默认为tomorrow,而RemoveMail<type>默认为all

AddMoney <amount> 为当前玩家增加指定的 <amount> 金钱。<amount> 可以为负数,用于扣除金钱。
AddQuest <quest ID>
RemoveQuest <quest ID>
添加/移除当前玩家的任务
AddSpecialOrder <order ID>
RemoveSpecialOrder <order ID>
添加/移除当前玩家的特别任务
If <query> ## <action if true>
If <query> ## <action if true> ## <action if false>
检查给定游戏状态查询,并根据返回值执行特定动作。

下面的例子会送给玩家一封信,如果玩家未收到过此信、邮箱暂无此信且明日没有此信:

"ActionsOnPurchase": [
    "If !PLAYER_HAS_MAIL Current SomeFlag ## AddMail Current SomeFlag"
]
IncrementStat <stat key> [amount] 将当前玩家的指定统计值增加指定值(默认为 1)。<stat key>可以为原版统计量(参见 PLAYER_STAT 游戏状态查询 以获取列表),也可以是一个自定义统计量。数值可以是负数,表示减少。
MarkActionApplied <player> <answer ID> [applied] 根据 [applied](默认true),将相应触发事件标记为已触发或未触发。<player>指定了此命令的目标玩家 。这可以用来跳过或重新运行一个触发事件(注意Data/TriggerActions中的触发事件默认只能触发一次。)

需要注意的是,一个触发事件不能以此标记“‘自身’”未应用;如果要这样做,参见使Data/TriggerActions重复发生

MarkCookingRecipeKnown <player> <recipe ID> [known]
MarkCraftingRecipeKnown <player> <recipe key> [known]
根据[known](默认为true),设置目标玩家是否已学会烹饪或打造配方 。(默认为true)。

请注意,忘记配方也会将其烹饪/打造次数计数器重置为零。

MarkEventSeen <player> <event ID> [seen] 根据[seen](默认true),设置目标玩家是否已看过指定事件
MarkQuestionAnswered <player> <answer ID> [answered] 根据[answered](默认true),设置目标玩家是否已选择过<answer ID>对应的对话回答
MarkSongHeard <player> <song ID> [heard] 根据 [heard](默认true),设置目标玩家是否已听过指定的音乐提示。这将影响歌曲是否出现在迷你点唱机歌单中。
Null (专用) 什么也不做。主要用于内部;一般情况下对您没有什么用。
RemoveTemporaryAnimatedSprites 移除当前位置的所有临时动画贴图。例如,这可以在setSkipActions事件中使用,以清理事件的临时贴图。
SetNpcInvisible <NPC name> <day duration> 隐藏某个村民,使之消失且持续<day duration>多天不能交互。这用于村民离开一段事件的场景(例如艾利欧特的14心事件)。

TODO: 是否可以对农场帮手使用?Atra不这样认为。

SetNpcVisible <NPC name> 解除村民的隐藏状态(若可用)。

TODO: 是否可以对农场帮手使用?可能会解除NPC的隐藏状态,但daysUntilNotInvisible 不会 同步。

目标玩家

某些触发条件具有<player>参数。可以有下列取值:

结果
All 用于所有玩家(无论是否在线)。
Current 用于本地玩家。
Host 用于房主。

触发条件

Data/TriggerActions

Data/TriggerActions 是一种数据素材,可让您在条件满足时动态执行操作。

例如,请参见如下Content Patcher补丁(patch):

{
    "Format": "2.3.0",
    "Changes": [
        {
            "Action": "EditData",
            "Target": "Data/TriggerActions",
            "Entries": {
                "{{ModId}}_OnLeoMoved": {
                    "Id": "{{ModId}}_OnLeoMoved",
                    "Trigger": "DayEnding",
                    "Condition": "PLAYER_HAS_MAIL Host leoMoved",
                    "Actions": [
                        "AddMail Current {{ModId}}_Abigail_LeoMoved",
                        "AddConversationTopic {{ModId}}_LeoMoved 5"
                    ]
                }
            }
        }
    ]
}

上述代码大意为:“当玩家准备睡觉时,若雷欧搬到了星露谷,则发送一封信件并开启一个对话主题。”

默认情况下Data/TriggerActions的每个触发事件仅能触发以此,尽管您可以使用MarkActionApplied动作来重复触发。

Data/TriggerActions为包含如下字段的数据模型所组成的列表。

字段 效果
Id 此触发动作的唯一字符串ID
Trigger 触发条件。此字段必须为如下取值中的一到多个(若有多个,则使用空格分隔):
触发条件 效果
DayStarted 玩家开始新的一天时触发,即,在睡觉或读档后触发。
DayEnding 在玩家准备睡觉时触发。它会在游戏更改日期、初始化新的一天、存档之前立即触发。
LocationChanged 在玩家到达指定地点时触发。
其他 C#模组可以添加其他的自定义触发条件。
Actions (可选) 欲执行的动作,为合乎动作格式的字符串列表。
Action (可选) 欲执行的单个动作,须合乎动作格式

此命令为Actions只有单个动作的简写。技术上而言您可以同时使用这两个字段,但实际上您应当仅使用其中一个。

HostOnly (可选) 触发动作是否仅适用于房主。若为true,则合作模式下此动作不会对农场帮手执行。
MarkActionApplied (可选) 当事件触发时,是否将其标记为已触发。默认为true。
  • 若为true:此动作会被加进玩家的triggerActionsRun列表,而PLAYER_HAS_RUN_TRIGGER_ACTION游戏状态查询会返回ture,且此触发动作不会再次触发(除非使用MarkActionApplied将其重新设为未触发)。
  • 若为false:只要满足此动作的触发条件,就会触发此动作,不限次数。而PLAYER_HAS_RUN_TRIGGER_ACTION游戏状态查询会返回false。
Condition (可选) 一个游戏状态查询,表示当前是否可以应用此动作。默认为始终为 “true”。
CustomFields (可选) 此条目的自定义字段

其他位置

您也可以直接从如下位置加载动作:

  • 使用$action命令的对话字符串。例如:
    "Mon": "Hi there! Here's 10g and a parsnip, don't spend it all at once.#$action AddMoney 10#$action AddItem (O)24"
    
  • 使用action命令的事件脚本。例如:
    "{{ModId}}_Event": "continue/64 15/farmer 64 16 2 Abigail 64 18 0/pause 1500/speak Abigail \"Hi. Here's 10g and a parsnip.\"/action AddMoney 10/action AddItem (O)24/pause 500/end"
    

    另请参阅setSkipActions命令。

  • 使用%action命令的信件数据。例如:
    "{{ModId}}_Letter": "Hey there!^Here's 10g and a parsnip. Take care!^   -Abigail%action AddMoney 10%% %action Additem (O)24%%[#]A gift from Abigail"
    
  • 使用debug action控制台命令的SMAPI 控制台窗口。例如:
    > debug action "AddMoney 10"
    
    Applied action 'AddMoney 10'.

针对C#模组作者

在C#中使用触发事件

触发动作主要用于Content Patcher内容包。C# mod 可以使用SMAPI的Events API代替,这样会更加灵活和高效(除非您希望内容包编辑您的触发动作)。

扩展性

C# mods 可以使用 StardewValley.Triggers.TriggerActionManager 类与触发动作进行交互。

例如,您可以...

  • 注册/调用自定义动作
    // register custom trigger type
    TriggerActionManager.RegisterTrigger("Some.ModId_OnItemReceived");
    
    // run actions in Data/TriggerActions for the custom trigger
    TriggerActionManager.Raise("Some.ModId_OnItemReceived", new[] { item, index }); // trigger can pass optional trigger arguments
    
  • 添加新动作
    TriggerActionManager.RegisterAction("Some.ModId_PlaySound", this.PlaySound);
    
    ...
    
    /// <inheritdoc cref="TriggerActionDelegate" />
    public static bool PlaySound(string[] args, TriggerActionContext context, out string error)
    {
        // get args
        if (!ArgUtility.TryGet(args, 1, out string soundId, out error, allowBlank: false))
            return false;
    
        // apply
        Game1.playSound(soundId);
        return true;
    }
    
  • 或运行动作字符串:
    // NOTE: this is just an example of how to run an action. This is meant to support actions specified in data or content
    // packs. If you want to send mail (or perform other actions) in C#, it's better to call the C# APIs directly instead.
    string action = "AddMail Current Robin Now";
    if (!TriggerActionManager.TryRunAction(action, out string error, out Exception ex))
        Game1.log.Error($"Failed running action '{action}': {error}", ex);
    

为避免冲突,自定义触发条件的名称应当为唯一字符串ID

常见问题

触发动作 vs 地图动作

动作可能指如下两个不同的概念:

  • 触发的动作(本页)可让您执行随时可行的一般背景任务,如发送信件或开始任务。这些操作可以根据条件自动触发,也可以通过对话、事件等中的命令触发。
  • 地图动作指的是 ActionTouchAction 地图属性,当您在地图上行走或与地图地块互动时,这些属性会执行某些操作。这些属性可以执行一系列特定于地图和交互的操作,如显示消息框、更改地图、打开商店菜单等。这些功能只在地图中起作用,在其他情况下一般没有意义。

除了名称相似外,这两个概念完全不同。

使Data/TriggerActions重复发生

默认情况下,Data/TriggerActions 中的每个触发动作对每个玩家只触发一次。 重复触发有两种主要方式:

  • 立即使其能够重复触发,为此,需要为Data/TriggerActions中的列表项设置"MarkActionApplied": false
  • 稍后使其能够重复触发,可以使用MarkActionApplied动作来忘记此事件已触发。 在下面的例子中,Content Patcher补丁(patch)会根据一周的不同日期交替设置"work"或"weekend"信件标识:
    {
        "Format": "2.3.0",
        "Changes": [
            {
                "Action": "EditData",
                "Target": "Data/TriggerActions",
                "Entries": {
                    // set 'work' flag on weekdays, and reset weekend action
                    "{{ModId}}_Work": {
                        "Id": "{{ModId}}_Work",
                        "Trigger": "DayStarted",
                        "Condition": "!DAY_OF_WEEK Saturday Sunday",
                        "Actions": [
                            "AddMail Current {{ModId}}_Work Received",
                            "RemoveMail Current {{ModId}}_Weekend",
                            "MarkActionApplied Current {{ModId}}_Weekend false"
                        ]
                    },
    
                    // set 'weekend' flag on weekends, and reset work action
                    "{{ModId}}_Weekend": {
                        "Id": "{{ModId}}_Weekend",
                        "Trigger": "DayStarted",
                        "Condition": "DAY_OF_WEEK Saturday Sunday",
                        "Actions": [
                            "AddMail Current {{ModId}}_Weekend Received",
                            "RemoveMail Current {{ModId}}_Work",
                            "MarkActionApplied Current {{ModId}}_Work false"
                        ]
                    },
                }
            }
        ]
    }