Line 1: |
Line 1: |
− | {{upcoming|1.6}}
| |
− |
| |
| ← [[Modding:Index|Index]] | | ← [[Modding:Index|Index]] |
| | | |
Line 26: |
Line 24: |
| ! action | | ! action |
| ! effect | | ! effect |
| + | |- |
| + | | <samp>AddBuff {{t|buff ID}}</samp><br /><samp>RemoveBuff {{t|buff ID}}</samp> |
| + | | Apply or remove a buff ID for the current player. |
| |- | | |- |
| | <samp>AddConversationTopic {{t|topic ID}} {{t|day duration}}</samp> | | | <samp>AddConversationTopic {{t|topic ID}} {{t|day duration}}</samp> |
Line 32: |
Line 33: |
| | <samp>RemoveConversationTopic {{t|topic ID}}</samp> | | | <samp>RemoveConversationTopic {{t|topic ID}}</samp> |
| | End a [[Modding:Dialogue#Conversation topics|conversation topic]], if it's active. | | | End a [[Modding:Dialogue#Conversation topics|conversation topic]], if it's active. |
− | |-
| |
− | | <samp>AddCookingRecipe {{t|player}} {{t|recipe ID}}</samp><br /><samp>AddCraftingRecipe {{t|player}} {{t|recipe key}}</samp>
| |
− | | Add a [[Modding:Recipe data|cooking or crafting recipe]] to the [[#Target player|specified player(s)]].
| |
| |- | | |- |
| | <samp>AddFriendshipPoints {{t|NPC name}} {{t|count}}</samp> | | | <samp>AddFriendshipPoints {{t|NPC name}} {{t|count}}</samp> |
Line 77: |
Line 75: |
| | <samp>AddSpecialOrder {{t|order ID}}</samp><br /><samp>RemoveSpecialOrder {{t|order ID}}</samp> | | | <samp>AddSpecialOrder {{t|order ID}}</samp><br /><samp>RemoveSpecialOrder {{t|order ID}}</samp> |
| | Add or remove a [[Modding:Special orders|special order]]. | | | Add or remove a [[Modding:Special orders|special order]]. |
| + | |- |
| + | | <samp>If {{t|query}} ## {{t|action if true}}</samp><br /><samp>If {{t|query}} ## {{t|action if true}} ## {{t|action if false}}</samp> |
| + | | Check a [[Modding:Game state queries|game state query]] and perform an action based on the result. |
| + | |
| + | For example, this only sends a mail if the player doesn't have it in their received, mailbox, or queued-for-tomorrow mail: |
| + | <syntaxhighlight lang="js"> |
| + | "ActionsOnPurchase": [ |
| + | "If !PLAYER_HAS_MAIL Current SomeFlag ## AddMail Current SomeFlag" |
| + | ] |
| + | </syntaxhighlight> |
| + | |- |
| + | | <samp>IncrementStat {{t|stat key}} {{o|amount}}</samp> |
| + | | Increment a stat value by the given amount (default 1) for the current player. This can be a vanilla stat key (see the <samp>PLAYER_STAT</samp> [[Modding:Game state queries|game state query]] for a list) or a custom stat key. The amount can be negative to decrement it. |
| |- | | |- |
| | <samp>MarkActionApplied {{t|player}} {{t|answer ID}} {{o|applied}}</samp> | | | <samp>MarkActionApplied {{t|player}} {{t|answer ID}} {{o|applied}}</samp> |
| | Mark a <samp>Data/TriggerActions</samp> entry as applied or non-applied for the [[#Target player|specified player(s)]], depending on {{o|applied}} (default <samp>true</samp>). This can be used to skip or re-run an entry, since <samp>Data/TriggerActions</samp> entries are only applied once by default. | | | Mark a <samp>Data/TriggerActions</samp> entry as applied or non-applied for the [[#Target player|specified player(s)]], depending on {{o|applied}} (default <samp>true</samp>). This can be used to skip or re-run an entry, since <samp>Data/TriggerActions</samp> entries are only applied once by default. |
| | | |
− | Note that an entry can't mark ''itself'' unapplied (but you can add a second entry which marks the first one unapplied). | + | Note that an entry can't use this to mark ''itself'' unapplied; see [[#Make Data/TriggerActions repeat|''Make <samp>Data/TriggerActions</samp> repeat'']] if you want to do that. |
| + | |- |
| + | | <samp>MarkCookingRecipeKnown {{t|player}} {{t|recipe ID}} {{o|known}}</samp><br /><samp>MarkCraftingRecipeKnown {{t|player}} {{t|recipe key}} {{o|known}}</samp> |
| + | | Set whether [[#Target player|specified player(s)]] know a [[Modding:Recipe data|cooking or crafting recipe]], depending on {{o|known}} (default <samp>true</samp>). |
| + | |
| + | Note that forgetting a recipe will also reset its times-cooked/crafted counter to zero. |
| |- | | |- |
| | <samp>MarkEventSeen {{t|player}} {{t|event ID}} {{o|seen}}</samp> | | | <samp>MarkEventSeen {{t|player}} {{t|event ID}} {{o|seen}}</samp> |
Line 88: |
Line 104: |
| | <samp>MarkQuestionAnswered {{t|player}} {{t|answer ID}} {{o|answered}}</samp> | | | <samp>MarkQuestionAnswered {{t|player}} {{t|answer ID}} {{o|answered}}</samp> |
| | Mark [[Modding:Dialogue#Response IDs|a dialogue answer]] as selected or non-selected for the [[#Target player|specified player(s)]], depending on {{o|answered}} (default <samp>true</samp>). | | | Mark [[Modding:Dialogue#Response IDs|a dialogue answer]] as selected or non-selected for the [[#Target player|specified player(s)]], depending on {{o|answered}} (default <samp>true</samp>). |
| + | |- |
| + | | <samp>MarkSongHeard {{t|player}} {{t|song ID}} {{o|heard}}</samp> |
| + | | Mark a song track's cue name heard or non-heard for the [[#Target player|specified player(s)]], depending on {{o|heard}} (default <samp>true</samp>). This affects whether the song appears in the [[jukebox]] selection. |
| |- | | |- |
| | <samp>Null</samp> | | | <samp>Null</samp> |
| | ''(Specialized)'' Does nothing. This is used internally; there's generally no benefit to using it yourself. | | | ''(Specialized)'' Does nothing. This is used internally; there's generally no benefit to using it yourself. |
| + | |- |
| + | | <samp>RemoveTemporaryAnimatedSprites</samp> |
| + | | Remove all temporary animated sprites in the current location. For example, this can be used in the [[Modding:Event data|event]] <samp>setSkipActions</samp> command to clean up the event's temporary sprites. |
| |- | | |- |
| | <samp>SetNpcInvisible {{t|NPC name}} {{t|day duration}}</samp> | | | <samp>SetNpcInvisible {{t|NPC name}} {{t|day duration}}</samp> |
Line 160: |
Line 182: |
| |- | | |- |
| | <samp>Id</samp> | | | <samp>Id</samp> |
− | | The [[Modding:Modder Guide/Game Fundamentals#Unique string IDs|unique string ID]] for this trigger action. | + | | The [[Modding:Common data field types#Unique string ID|unique string ID]] for this trigger action. |
| |- | | |- |
| | <samp>Trigger</samp> | | | <samp>Trigger</samp> |
Line 190: |
Line 212: |
| | | |
| 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. | | 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> | | | <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]]. | | | ''(Optional)'' Whether this trigger action can only run for the main player. If true, the action will be ignored for farmhands in [[multiplayer]]. |
| + | |- |
| + | | <samp>MarkActionApplied</samp> |
| + | | ''(Optional)'' Whether to mark the action applied when it's applied. Default true. |
| + | |
| + | * If true: the action is added to the player's <samp>triggerActionsRun</samp> list, [[Modding:Game state queries|queries]] like <samp>PLAYER_HAS_RUN_TRIGGER_ACTION</samp> will return true, and the action won't run again (unless you use the <samp>MarkActionApplied</samp> action to mark it unapplied). |
| + | * If false: the action can repeat immediately when the same trigger is raised, and [[Modding:Game state queries|queries]] like <samp>PLAYER_HAS_RUN_TRIGGER_ACTION</samp> will return false for it. |
| |- | | |- |
| | <samp>Condition</samp> | | | <samp>Condition</samp> |
Line 210: |
Line 235: |
| <li>A [[Modding:Dialogue|dialogue string]] using the <samp>$action</samp> command. For example: | | <li>A [[Modding:Dialogue|dialogue string]] using the <samp>$action</samp> command. For example: |
| <syntaxhighlight lang="js"> | | <syntaxhighlight lang="js"> |
− | "Mon": "Hi there! Here's 10g, don't spend it all once.#$action AddMoney 10" | + | "Mon": "Hi there! Here's 10g and a parsnip, don't spend it all at once.#$action AddMoney 10#$action AddItem (O)24" |
| </syntaxhighlight></li> | | </syntaxhighlight></li> |
| | | |
| <li>An [[Modding:Event data|event script]] using the <samp>action</samp> command. For example: | | <li>An [[Modding:Event data|event script]] using the <samp>action</samp> command. For example: |
| <syntaxhighlight lang="js"> | | <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" | + | "{{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" |
− | </syntaxhighlight></li> | + | </syntaxhighlight> |
| + | |
| + | See also the <samp>setSkipActions</samp> command. |
| + | </li> |
| | | |
| <li>A [[Modding:Mail data|mail letter]] using the <samp>%action</samp> command. For example: | | <li>A [[Modding:Mail data|mail letter]] using the <samp>%action</samp> command. For example: |
| <syntaxhighlight lang="js"> | | <syntaxhighlight lang="js"> |
− | "{{ModId}}_Letter": "Hey there!^Here's 10g. Take care!^ -Abigail%action AddMoney 10%%[#]A gift from Abigail" | + | "{{ModId}}_Letter": "Hey there!^Here's 10g and a parsnip. Take care!^ -Abigail%action AddMoney 10%% %action Additem (O)24%%[#]A gift from Abigail" |
| </syntaxhighlight></li> | | </syntaxhighlight></li> |
| | | |
| <li>The [[Modding:Console commands|SMAPI console window]] using the <samp>debug action</samp> console command. For example: | | <li>The [[Modding:Console commands|SMAPI console window]] using the <samp>debug action</samp> console command. For example: |
− | <pre>> debug action AddMoney 10 | + | <pre>> debug action "AddMoney 10" |
| | | |
| Applied action 'AddMoney 10'.</pre></li> | | Applied action 'AddMoney 10'.</pre></li> |
Line 236: |
Line 264: |
| C# mods can use the <samp>StardewValley.Triggers.TriggerActionManager</samp> class to interact with trigger actions. | | C# mods can use the <samp>StardewValley.Triggers.TriggerActionManager</samp> class to interact with trigger actions. |
| | | |
− | For example, you can add a new trigger type: | + | For example, you can... |
| + | <ul> |
| + | <li>Add and raise a new trigger type: |
| <syntaxhighlight lang="js"> | | <syntaxhighlight lang="js"> |
| // register custom trigger type | | // register custom trigger type |
| TriggerActionManager.RegisterTrigger("Some.ModId_OnItemReceived"); | | TriggerActionManager.RegisterTrigger("Some.ModId_OnItemReceived"); |
| | | |
− | // run actions for the custom trigger | + | // run actions in Data/TriggerActions for the custom trigger |
| TriggerActionManager.Raise("Some.ModId_OnItemReceived", new[] { item, index }); // trigger can pass optional trigger arguments | | TriggerActionManager.Raise("Some.ModId_OnItemReceived", new[] { item, index }); // trigger can pass optional trigger arguments |
− | </syntaxhighlight> | + | </syntaxhighlight></li> |
| | | |
− | Or you can add a new action handler: | + | <li>Or add a new action: |
| <syntaxhighlight lang="js"> | | <syntaxhighlight lang="js"> |
| TriggerActionManager.RegisterAction("Some.ModId_PlaySound", this.PlaySound); | | TriggerActionManager.RegisterAction("Some.ModId_PlaySound", this.PlaySound); |
Line 252: |
Line 282: |
| | | |
| /// <inheritdoc cref="TriggerActionDelegate" /> | | /// <inheritdoc cref="TriggerActionDelegate" /> |
− | public static bool PlaySound(string[] args, string trigger, object[] triggerArgs, TriggerActionData data) | + | public static bool PlaySound(string[] args, TriggerActionContext context, out string error) |
| { | | { |
| // get args | | // get args |
− | if (!ArgUtility.TryGet(args, 1, out string soundId, out string error, allowBlank: false)) | + | if (!ArgUtility.TryGet(args, 1, out string soundId, out error, allowBlank: false)) |
− | return TriggerActionManager.Helpers.LogActionError(args, trigger, data, error); | + | return false; |
| | | |
| // apply | | // apply |
Line 262: |
Line 292: |
| return true; | | return true; |
| } | | } |
− | </syntaxhighlight> | + | </syntaxhighlight></li> |
| + | |
| + | <li>Or run an action string: |
| + | <syntaxhighlight lang="js"> |
| + | // 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); |
| + | </syntaxhighlight></li> |
| + | </ul> |
| + | |
| + | To avoid conflicts, custom trigger names should be [[Modding:Common data field types#Unique string ID|unique string IDs]]. |
| + | |
| + | ==FAQs== |
| + | ===Trigger actions vs map actions=== |
| + | ''Actions'' can refer to two different systems: |
| + | |
| + | * ''Trigger actions'' (this page) let you perform generic background tasks that can be done anytime, like sending a letter or starting a quest. These can be triggered automatically based on conditions, or via commands in dialogue, events, etc. |
| + | * ''[[Modding:Maps|Map actions]]'' refer to the <samp>Action</samp> and <samp>TouchAction</samp> map properties, which do something when you walk on or interact with a map tile. These can perform a wide array of map- and interaction-specific things like showing a message box, changing the map, opening shop menus, etc. These only work in maps, and generally don't make sense in other contexts. |
| + | |
| + | Aside from the similar names, they're not interchangeable and there's fairly little overlap. |
| + | |
| + | ===Make <samp>Data/TriggerActions</samp> repeat=== |
| + | By default, each entry in <samp>Data/TriggerActions</samp> is only applied once per player. |
| + | |
| + | There are two main ways to repeat actions: |
| + | <ul> |
| + | <li>To make it repeatable immediately, set <samp>"MarkActionApplied": false</samp> on the <samp>Data/TriggerActions</samp> entry.</li> |
| + | <li>To enable repeating at a different time, you can use the <samp>MarkActionApplied</samp> action to forget that it was applied. |
| + | |
| + | For example, this patch will set alternating 'work' or 'weekend' mail flags depending on the day of week: |
| + | {{#tag:syntaxhighlight|<nowiki> |
| + | { |
| + | "Format": "</nowiki>{{Content Patcher version}}<nowiki>", |
| + | "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" |
| + | ] |
| + | }, |
| | | |
− | To avoid conflicts, custom trigger names should be [[Modding:Modder Guide/Game Fundamentals#Unique string IDs|unique string IDs]].
| + | // 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" |
| + | ] |
| + | }, |
| + | } |
| + | } |
| + | ] |
| + | } |
| + | </nowiki>|lang=js}} |
| | | |
| [[Category:Modding]] | | [[Category:Modding]] |