Difference between revisions of "Modding:Trigger actions"
Lumisteria (talk | contribs) m (→Triggers) |
Pathoschild (talk | contribs) (reorganize and expand for expanded scope (can now be triggered in multiple ways)) |
||
Line 7: | Line 7: | ||
==Overview== | ==Overview== | ||
===Introduction=== | ===Introduction=== | ||
− | + | A ''trigger action'' consists of two main parts: | |
− | * The | + | * The ''trigger'' is what causes the action to happen. This can be an entry in <samp>Data/TriggerActions</samp>, an event command, etc. See [[#Triggers|built-in triggers]]. |
− | * ''' | + | * The ''action'' is a space-delimited string which defines what to do. For example, <code>AddMail Current Robin</code> adds the <samp>Robin</samp> letter to the player's [[Modding:Mail data|mailbox]] tomorrow. See [[#Argument format|argument format]] and [[#Actions|built-in actions]]. |
− | |||
− | + | ===Argument format=== | |
− | + | Arguments are space-delimited. For example, <code>AddMail Current Abigail_LeoMoved Now</code> calls the <samp>AddMail</samp> action with three arguments (player: <samp>Current</samp>, mail ID: <samp>Abigail_LeoMoved</samp>, and mail type: <samp>Now</samp>). | |
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | === | ||
− | |||
If you have spaces within an argument, you can surround it with quotes to keep it together. For example, <code>AddFriendshipPoints "Mister Qi" 10</code> has two arguments (<samp>Mister Qi</samp> and <samp>10</samp>). You can escape inner quotes with backslashes, like <code>AddFriendshipPoints "Mister \"Qi\"" 10</code>. | If you have spaces within an argument, you can surround it with quotes to keep it together. For example, <code>AddFriendshipPoints "Mister Qi" 10</code> has two arguments (<samp>Mister Qi</samp> and <samp>10</samp>). You can escape inner quotes with backslashes, like <code>AddFriendshipPoints "Mister \"Qi\"" 10</code>. | ||
Line 47: | Line 18: | ||
Remember that quotes and backslashes inside JSON strings need to be escaped too. For example, <code>"AddFriendshipPoints \"Mister Qi\" 10"</code> will send <code>AddFriendshipPoints "Mister Qi" 10</code> to the game code. Alternatively, you can use single-quotes for the JSON string instead, like <code>'AddFriendshipPoints "Mister Qi" 10'</code>. | Remember that quotes and backslashes inside JSON strings need to be escaped too. For example, <code>"AddFriendshipPoints \"Mister Qi\" 10"</code> will send <code>AddFriendshipPoints "Mister Qi" 10</code> to the game code. Alternatively, you can use single-quotes for the JSON string instead, like <code>'AddFriendshipPoints "Mister Qi" 10'</code>. | ||
− | == | + | ==Actions== |
− | + | ===Built-in actions=== | |
− | + | These are the built-in actions which can be used by any [[#Triggers|trigger]]. (Other custom actions may be [[#For C# mod authors|added by C# mods]].) | |
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | === | ||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
{| class="wikitable" | {| class="wikitable" | ||
Line 194: | Line 110: | ||
| Apply to the main player. | | Apply to the main player. | ||
|} | |} | ||
+ | |||
+ | ==Triggers== | ||
+ | ===<samp>Data/TriggerActions</samp>=== | ||
+ | <samp>Data/TriggerActions</samp> is a data asset which lets you dynamically perform actions when the conditions are met. | ||
+ | |||
+ | For example, consider this [[Modding:Content Patcher|Content Patcher]] patch: | ||
+ | {{#tag:syntaxhighlight|<nowiki> | ||
+ | { | ||
+ | "Format": "</nowiki>{{Content Patcher version}}<nowiki>", | ||
+ | "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" | ||
+ | ] | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | ] | ||
+ | } | ||
+ | </nowiki>|lang=js}} | ||
+ | |||
+ | You can read that like: "''When the player is going to sleep, if Leo has moved to the valley, then [[Modding:Mail data|send a letter]] and start [[Modding:Dialogue#Conversation topics|a conversation topic]]''". | ||
+ | |||
+ | Each entry in <samp>Data/TriggerActions</samp> only runs once by default, though you can use the <samp>MarkActionApplied</samp> action to re-enable one. | ||
+ | |||
+ | <samp>Data/TriggerActions</samp> consists of a list of models with these fields: | ||
+ | |||
+ | {| class="wikitable" | ||
+ | |- | ||
+ | ! field | ||
+ | ! effect | ||
+ | |- | ||
+ | | <samp>Id</samp> | ||
+ | | The [[Modding:Modder Guide/Game Fundamentals#Unique string IDs|unique string ID]] for this trigger action. | ||
+ | |- | ||
+ | | <samp>Trigger</samp> | ||
+ | | When to apply the trigger action. This must be one or more of these values (space-delimited): | ||
+ | |||
+ | {| class="wikitable" | ||
+ | |- | ||
+ | ! trigger | ||
+ | ! effect | ||
+ | |- | ||
+ | | <samp>DayStarted</samp> | ||
+ | | Raised when the player starts a day, after either sleeping or loading. | ||
+ | |- | ||
+ | | <samp>DayEnding</samp> | ||
+ | | Raised when the player is going to sleep. This happens immediately before the game changes the date, sets up the new day, and saves. | ||
+ | |- | ||
+ | | <samp>LocationChanged</samp> | ||
+ | | Raised when the player arrives in a location. | ||
+ | |- | ||
+ | | ''other'' | ||
+ | | Other custom triggers may be [[#For C# mod authors|added by C# mods]]. | ||
+ | |} | ||
+ | |- | ||
+ | | <samp>Actions</samp> | ||
+ | | ''(Optional)'' The actions to perform, as a list of strings matching the [[#Actions|action format]]. | ||
+ | |- | ||
+ | | <samp>Action</samp> | ||
+ | | ''(Optional)'' A single action to perform, matching the [[#Actions|action format]]. | ||
+ | |||
+ | This is just a shortcut for <samp>Actions</samp> with one action. Technically you can use both together, but usually you should just pick one property to set. | ||
+ | |- | ||
+ | | <samp>Location</samp> | ||
+ | | ''(Optional)'' If set, the internal location name where this action should be applied. This is a shortcut for (and more efficient than) using a <samp>LOCATION_NAME</samp> game state query. Default none. | ||
+ | |- | ||
+ | | <samp>HostOnly</samp> | ||
+ | | ''(Optional)'' Whether this trigger action can only run for the main player. If true, the action will be ignored for farmhands in [[multiplayer]]. | ||
+ | |- | ||
+ | | <samp>Condition</samp> | ||
+ | | ''(Optional)'' A [[Modding:Game state queries|game state query]] which indicates whether this action can be applied currently. Defaults to always true. | ||
+ | |- | ||
+ | | <samp>CustomFields</samp> | ||
+ | | ''(Optional)'' The [[Modding:Migrate to Stardew Valley 1.6#Custom data fields|custom fields]] for this entry. | ||
+ | |} | ||
+ | |||
+ | See [[#Overview|example under ''Overview'']]. | ||
+ | |||
+ | ===Elsewhere=== | ||
+ | You can also run an action directly from... | ||
+ | |||
+ | <ul> | ||
+ | <li>A [[Modding:Dialogue|dialogue string]] using the <samp>$action</samp> command. For example: | ||
+ | <syntaxhighlight lang="js"> | ||
+ | "Mon": "Hi there! Here's 10g, don't spend it all once.#$action AddMoney 10" | ||
+ | </syntaxhighlight></li> | ||
+ | |||
+ | <li>An [[Modding:Event data|event script]] using the <samp>action</samp> command. For example: | ||
+ | <syntaxhighlight lang="js"> | ||
+ | "{{ModId}}_Event": "continue/64 15/farmer 64 16 2 Abigail 64 18 0/pause 1500/speak Abigail \"Hi. Here's 10g.\"/action AddMoney 10/pause 500/end" | ||
+ | </syntaxhighlight></li> | ||
+ | |||
+ | <li>A [[Modding:Mail data|mail letter]] using the <samp>%action</samp> command. For example: | ||
+ | <syntaxhighlight lang="js"> | ||
+ | "{{ModId}}_Letter": "Hey there!^Here's 10g. Take care!^ -Abigail%action AddMoney 10%%[#]A gift from Abigail" | ||
+ | </syntaxhighlight></li> | ||
+ | |||
+ | <li>The [[Modding:Console commands|SMAPI console window]] using the <samp>debug action</samp> console command. For example: | ||
+ | <pre>> debug action AddMoney 10 | ||
+ | |||
+ | Applied action 'AddMoney 10'.</pre></li> | ||
+ | </ul> | ||
==For C# mod authors== | ==For C# mod authors== |
Revision as of 07:25, 2 January 2024
← Index
This page documents trigger actions, which let content packs perform an action when something happens. (C# mods should usually use SMAPI events instead.)
Overview
Introduction
A trigger action consists of two main parts:
- The trigger is what causes the action to happen. This can be an entry in Data/TriggerActions, an event command, etc. See built-in triggers.
- The action is a space-delimited string which defines what to do. For example,
AddMail Current Robin
adds the Robin letter to the player's mailbox tomorrow. See argument format and built-in actions.
Argument format
Arguments are space-delimited. For example, AddMail Current Abigail_LeoMoved Now
calls the AddMail action with three arguments (player: Current, mail ID: Abigail_LeoMoved, and mail type: Now).
If you have spaces within an argument, you can surround it with quotes to keep it together. For example, AddFriendshipPoints "Mister Qi" 10
has two arguments (Mister Qi and 10). You can escape inner quotes with backslashes, like AddFriendshipPoints "Mister \"Qi\"" 10
.
Remember that quotes and backslashes inside JSON strings need to be escaped too. For example, "AddFriendshipPoints \"Mister Qi\" 10"
will send AddFriendshipPoints "Mister Qi" 10
to the game code. Alternatively, you can use single-quotes for the JSON string instead, like 'AddFriendshipPoints "Mister Qi" 10'
.
Actions
Built-in actions
These are the built-in actions which can be used by any trigger. (Other custom actions may be added by C# mods.)
action | effect | ||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|
AddConversationTopic <topic ID> <day duration>
|
Start a conversation topic for the given number of days. If the topic is already active, this resets its duration to the given number. | ||||||||||
RemoveConversationTopic <topic ID>
|
End a conversation topic, if it's active. | ||||||||||
AddCookingRecipe <player> <recipe ID> AddCraftingRecipe <player> <recipe key>
|
Add a cooking or crafting recipe to the specified player(s). | ||||||||||
AddFriendshipPoints <NPC name> <count>
|
Add <count> friendship points between the current player and specified NPC. The <count> can be negative to reduce friendship points.
| ||||||||||
AddItem <item ID> [count] [quality]
|
Add an item by its qualified or unqualified item ID to the current player's inventory, with an optional count (default 1) and quality (default 0). | ||||||||||
RemoveItem <item ID> [count]
|
Deduct items by qualified or unqualified item ID from the current player's inventory, up to a max combined stack size of [count] (default 1).
| ||||||||||
AddMail <player> <mail ID> [type] RemoveMail <player> <mail ID> [type]
|
Add or remove a mail flag or letter for the specified player(s).
The
If omitted, the | ||||||||||
AddMoney <amount>
|
Add the given <amount> of money for the current player. The <amount> can be negative to deduct money.
| ||||||||||
AddQuest <quest ID> RemoveQuest <quest ID>
|
Add or remove a quest for the specified player(s). | ||||||||||
AddSpecialOrder <order ID> RemoveSpecialOrder <order ID>
|
Add or remove a special order for the specified player(s). | ||||||||||
MarkEventSeen <event ID> [seen]
|
Mark an event as seen (if [seen] is true) or not seen (if false).
| ||||||||||
MarkQuestionAnswered <answer ID> [answered]
|
Mark a dialogue answer as selected (if [answered] is true) or not selected (if false).
| ||||||||||
MarkActionApplied <answer ID> [applied]
|
Mark another trigger action as applied (if [applied] is true) or not applied (if false). This can be used to skip or re-run an action, since actions are only applied once by default.
| ||||||||||
SetNpcInvisible <NPC name> <day duration>
|
Hide an NPC so they disappear and can't be interacted with for the given number of days. This is used when NPCs go away for a while (e.g. Elliott's 14-heart event). | ||||||||||
SetNpcVisible <NPC name>
|
End the NPC's invisibility, if applicable. |
Target player
Some conditions have a <player>
argument. This can be one of...
value | result |
---|---|
All | Apply the action to all players (regardless of whether they're online). |
Current | Apply to the local player. |
Host | Apply to the main player. |
Triggers
Data/TriggerActions
Data/TriggerActions is a data asset which lets you dynamically perform actions when the conditions are met.
For example, consider this 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"
]
}
}
}
]
}
You can read that like: "When the player is going to sleep, if Leo has moved to the valley, then send a letter and start a conversation topic".
Each entry in Data/TriggerActions only runs once by default, though you can use the MarkActionApplied action to re-enable one.
Data/TriggerActions consists of a list of models with these fields:
field | effect | ||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|
Id | The unique string ID for this trigger action. | ||||||||||
Trigger | When to apply the trigger action. This must be one or more of these values (space-delimited):
| ||||||||||
Actions | (Optional) The actions to perform, as a list of strings matching the action format. | ||||||||||
Action | (Optional) A single action to perform, matching the action format.
This is just a shortcut for Actions with one action. Technically you can use both together, but usually you should just pick one property to set. | ||||||||||
Location | (Optional) If set, the internal location name where this action should be applied. This is a shortcut for (and more efficient than) using a LOCATION_NAME game state query. Default none. | ||||||||||
HostOnly | (Optional) Whether this trigger action can only run for the main player. If true, the action will be ignored for farmhands in multiplayer. | ||||||||||
Condition | (Optional) A game state query which indicates whether this action can be applied currently. Defaults to always true. | ||||||||||
CustomFields | (Optional) The custom fields for this entry. |
Elsewhere
You can also run an action directly from...
- A dialogue string using the $action command. For example:
"Mon": "Hi there! Here's 10g, don't spend it all once.#$action AddMoney 10"
- An event script using the action command. For example:
"{{ModId}}_Event": "continue/64 15/farmer 64 16 2 Abigail 64 18 0/pause 1500/speak Abigail \"Hi. Here's 10g.\"/action AddMoney 10/pause 500/end"
- A mail letter using the %action command. For example:
"{{ModId}}_Letter": "Hey there!^Here's 10g. Take care!^ -Abigail%action AddMoney 10%%[#]A gift from Abigail"
- The SMAPI console window using the debug action console command. For example:
> debug action AddMoney 10 Applied action 'AddMoney 10'.
For C# mod authors
Using trigger actions in C# data
Trigger actions are mainly meant for Content Patcher packs. C# mod can use SMAPI's events instead, which are much more flexible and efficient (unless you want to let content packs edit your trigger actions).
Extensibility
C# mods can use the StardewValley.Triggers.TriggerActionManager class to interact with trigger actions.
For example, you can add a new trigger type:
// register custom trigger type
TriggerActionManager.RegisterTrigger("Some.ModId_OnItemReceived");
// run actions for the custom trigger
TriggerActionManager.Raise("Some.ModId_OnItemReceived", new[] { item, index }); // trigger can pass optional trigger arguments
Or you can add a new action handler:
TriggerActionManager.RegisterAction("Some.ModId_PlaySound", this.PlaySound);
...
/// <inheritdoc cref="TriggerActionDelegate" />
public static bool PlaySound(string[] args, string trigger, object[] triggerArgs, TriggerActionData data)
{
// get args
if (!ArgUtility.TryGet(args, 1, out string soundId, out string error, allowBlank: false))
return TriggerActionManager.Helpers.LogActionError(args, trigger, data, error);
// apply
Game1.playSound(soundId);
return true;
}
To avoid conflicts, custom trigger names should be unique string IDs.