Line 1: |
Line 1: |
− | {{upcoming|1.6}}
| |
− |
| |
| ← [[Modding:Index|Index]] | | ← [[Modding:Index|Index]] |
| | | |
Line 7: |
Line 5: |
| ==Overview== | | ==Overview== |
| ===Introduction=== | | ===Introduction=== |
− | Each trigger action is comprised of three main parts:
| + | A ''trigger action'' consists of two main parts: |
− | * The '''trigger''' is when to apply the trigger action, either defined by the base game (like <samp>LocationChanged</samp>) or added by C# mods. | + | * 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]]. |
− | * '''Actions''' are what to do (like send mail or start a quest). | + | * 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]]. |
− | * '''Conditions''' are optional [[Modding:Game state queries|game state queries]] to decide whether the trigger action should be applied.
| |
| | | |
− | For example, consider this [[Modding:Content Patcher|Content Patcher]] patch:
| + | ===Argument format=== |
− | {{#tag:syntaxhighlight|<nowiki>
| + | 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>). |
− | {
| |
− | "Format": "</nowiki>{{Content Patcher version}}<nowiki>",
| |
− | "Changes": [
| |
− | {
| |
− | "Action": "EditData",
| |
− | "Target": "Data/TriggerActions",
| |
− | "Entries": {
| |
− | "SomeMod.Id_OnLeoMoved": {
| |
− | "Trigger": "LocationChanged",
| |
− | "Location": "Farm",
| |
− | "Condition": "PLAYER_HAS_FLAG Host leoMoved",
| |
− | "Actions": [
| |
− | "AddMail Current Abigail_LeoMoved Today",
| |
− | "AddConversationTopic LeoMoved 5"
| |
− | ]
| |
− | }
| |
− | }
| |
− | }
| |
− | ]
| |
− | }
| |
− | </nowiki>|lang=js}}
| |
− | | |
− | You can read that like: "''When the player arrives in the Farm location, if Leo has moved to the valley, then [[Modding:Mail data|send a letter]] and start [[Modding:Dialogue#Conversation topics|a conversation topic]]''".
| |
− | | |
− | Actions only run once by default, though you can use the <samp>MarkActionApplied</samp> action to re-enable one.
| |
− | | |
− | ===Action format=== | |
− | An ''action'' consists of an action name with space-delimited arguments. For example, <code>AddMail Current Abigail_LeoMoved Today</code> has action name <samp>AddMail</samp> with three arguments (<samp>Current</samp>, <samp>Abigail_LeoMoved</samp>, and <samp>Today</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 16: |
| 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>. |
| | | |
− | ==Data format== | + | ==Actions== |
− | Trigger actions are stored in the <samp>Data/TriggerActions</samp> asset. This consists of a list of models with these fields:
| + | ===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" |
| |- | | |- |
− | ! field | + | ! action |
− | ! 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 a [[#Triggers|valid trigger type]].
| |
− | |-
| |
− | | <samp>Actions</samp>
| |
− | | The actions to perform. This consists of a list of strings matching the [[#Actions|action format]].
| |
− | |-
| |
− | | <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.
| |
− | |}
| |
− | | |
− | See [[#Overview|example under ''Overview'']].
| |
− | | |
− | ==Valid values==
| |
− | ===Triggers===
| |
− | The game has one built-in trigger which can be used in the <samp>Trigger</samp> field. (Other custom triggers may be [[#For C# mod authors|added by C# mods]].)
| |
− | | |
− | {| class="wikitable"
| |
− | |-
| |
− | ! trigger
| |
| ! effect | | ! effect |
| |- | | |- |
− | | <samp>LocationChanged</samp> | + | | <samp>AddBuff {{t|buff ID}}</samp><br /><samp>RemoveBuff {{t|buff ID}}</samp> |
− | | Raised when the player arrives in a location.
| + | | Apply or remove a buff ID for the current player. |
− | |}
| |
− | | |
− | ===Actions===
| |
− | These are the built-in actions which can be used in the <samp>Actions</samp> field. (Other custom actions may be [[#For C# mod authors|added by C# mods]].)
| |
− | | |
− | {| class="wikitable"
| |
− | |-
| |
− | ! action
| |
− | ! effect
| |
| |- | | |- |
| | <samp>AddConversationTopic {{t|topic ID}} {{t|day duration}}</samp> | | | <samp>AddConversationTopic {{t|topic ID}} {{t|day duration}}</samp> |
Line 102: |
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 115: |
Line 43: |
| | Deduct items by [[Modding:Migrate to Stardew Valley 1.6#Custom items|qualified or unqualified item ID]] from the current player's inventory, up to a max combined stack size of {{o|count}} (default 1). | | | Deduct items by [[Modding:Migrate to Stardew Valley 1.6#Custom items|qualified or unqualified item ID]] from the current player's inventory, up to a max combined stack size of {{o|count}} (default 1). |
| |- | | |- |
− | | <samp>AddMail {{t|player}} {{t|mail ID}} {{t|type}}</samp><br /><samp>RemoveMail {{t|player}} {{t|mail ID}} {{o|type}}</samp> | + | | <samp>AddMail {{t|player}} {{t|mail ID}} {{o|type}}</samp><br /><samp>RemoveMail {{t|player}} {{t|mail ID}} {{o|type}}</samp> |
| | Add or remove a [[Modding:Mail data|mail flag or letter]] for the [[#Target player|specified player(s)]]. | | | Add or remove a [[Modding:Mail data|mail flag or letter]] for the [[#Target player|specified player(s)]]. |
| | | |
Line 134: |
Line 62: |
| |- | | |- |
| | <samp>all</samp> | | | <samp>all</samp> |
− | | (''remove only'') Remove it everywhere (mailbox, tomorrow's mailbox, and received mail). | + | | Add or remove it everywhere (mailbox, tomorrow's mailbox, and received mail). |
| |} | | |} |
| | | |
− | For remove only, {{t|type}} defaults to <samp>all</samp>.
| + | If omitted, the {{t|type}} defaults to <samp>tomorrow</samp> for <samp>AddMail</samp> and <samp>all</samp> for <samp>RemoveMail</samp>. |
| |- | | |- |
| | <samp>AddMoney {{t|amount}}</samp> | | | <samp>AddMoney {{t|amount}}</samp> |
Line 143: |
Line 71: |
| |- | | |- |
| | <samp>AddQuest {{t|quest ID}}</samp><br /><samp>RemoveQuest {{t|quest ID}}</samp> | | | <samp>AddQuest {{t|quest ID}}</samp><br /><samp>RemoveQuest {{t|quest ID}}</samp> |
− | | Add or remove a [[Modding:Quest data|quest]] for the [[#Target player|specified player(s)]]. | + | | Add or remove a [[Modding:Quest data|quest]] for the current player. |
| |- | | |- |
| | <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]] for the [[#Target player|specified player(s)]]. | + | | 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>MarkEventSeen {{t|event ID}} {{o|seen}}</samp> | + | | <samp>IncrementStat {{t|stat key}} {{o|amount}}</samp> |
− | | Mark [[Modding:Event data|an event]] as seen (if {{o|seen}} is <samp>true</samp>) or not seen (if <samp>false</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>MarkQuestionAnswered {{t|answer ID}} {{o|answered}}</samp> | + | | <samp>MarkActionApplied {{t|player}} {{t|answer ID}} {{o|applied}}</samp> |
− | | Mark [[Modding:Dialogue#Response IDs|a dialogue answer]] as selected (if {{o|answered}} is <samp>true</samp>) or not selected (if <samp>false</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. |
| + | |
| + | 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>MarkActionApplied {{t|answer ID}} {{o|applied}}</samp> | + | | <samp>MarkCookingRecipeKnown {{t|player}} {{t|recipe ID}} {{o|known}}</samp><br /><samp>MarkCraftingRecipeKnown {{t|player}} {{t|recipe key}} {{o|known}}</samp> |
− | | Mark another trigger action as applied (if {{o|applied}} is <samp>true</samp>) or not applied (if <samp>false</samp>). This can be used to skip or re-run an action, since actions are only applied once by default. | + | | 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> |
| + | | Mark [[Modding:Event data|an event]] as seen or unseen for the [[#Target player|specified player(s)]], depending on {{o|seen}} (default <samp>true</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>). |
| + | |- |
| + | | <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> |
| + | | ''(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> |
| | 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#Fourteen Hearts|Elliott's 14-heart event]]). | | | 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#Fourteen Hearts|Elliott's 14-heart event]]). |
| + | |
| + | '''TODO: can you call this from the farmhand? Atra doesn't think so.''' |
| |- | | |- |
| | <samp>SetNpcVisible {{t|NPC name}}</samp> | | | <samp>SetNpcVisible {{t|NPC name}}</samp> |
| | End the NPC's invisibility, if applicable. | | | End the NPC's invisibility, if applicable. |
| + | |
| + | '''TODO: check to see if can be called from farmhand. Will probably make the NPC visible again, but the daysUntilNotInvisible is NOT synced.''' |
| |} | | |} |
| | | |
Line 180: |
Line 141: |
| | 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:Common data field types#Unique string ID|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>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>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> |
| + | | ''(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. |
| + | |} |
| + | |
| + | ===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 and a parsnip, don't spend it all at once.#$action AddMoney 10#$action AddItem (O)24" |
| + | </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 and a parsnip.\"/action AddMoney 10/action AddItem (O)24/pause 500/end" |
| + | </syntaxhighlight> |
| + | |
| + | See also the <samp>setSkipActions</samp> command. |
| + | </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 and a parsnip. Take care!^ -Abigail%action AddMoney 10%% %action Additem (O)24%%[#]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== |
Line 188: |
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 204: |
Line 282: |
| | | |
| /// <inheritdoc cref="TriggerActionDelegate" /> | | /// <inheritdoc cref="TriggerActionDelegate" /> |
− | public static bool PlaySound(string[] args, string trigger, string[] 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 214: |
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]] |