Jump to content

Modding:Migrate to Stardew Valley 1.7: Difference between revisions

From Stardew Valley Wiki
imported>Pathoschild
imported>Pathoschild
backport event overhaul to 1.6.16
Line 123: Line 123:
| ''(Optional)'' The [[Modding:Common data field types#Custom fields|custom fields]] for this entry.
| ''(Optional)'' The [[Modding:Common data field types#Custom fields|custom fields]] for this entry.
|}
|}
===[[Modding:Event data|<samp>Data/Events/*</samp>]]===
See ''[[#Event changes|event changes]]'' below.


===[[Modding:Furniture|<samp>Data/Furniture</samp>]]===
===[[Modding:Furniture|<samp>Data/Furniture</samp>]]===
Line 851: Line 848:


===[[Modding:Event data|Event]] changes===
===[[Modding:Event data|Event]] changes===
====Multilingual events====
Added new event commands:
All vanilla events are now multilingual, with a single copy of each event script which uses translation keys. Translations from the old per-language event files were moved into a per-language <samp>Strings/Events</samp> file.
 
For example:
{| class="wikitable"
{| class="wikitable"
|-
|-
! files in 1.6.16
! command
! files in 1.7
! description
|-
|-
| <pre>
| <samp>setDrawDepthModifier {{t|npc}} {{t|amountInTiles}}
Data/Events/Beach
| Modify the draw depth of {{t|npc}} for this event, by {{t|amountInTiles}}.
Data/Events/Beach.de-DE
|-
Data/Events/Beach.es-ES
| <samp>setDrawDepthModifier {{t|npc}} reset
Data/Events/Beach.fr-FR
| Reset the draw depth modifier of {{t|npc}} for this event.
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
</pre>
|valign="top"| <pre>
Data/Events/Beach
</pre>
|}
 
[[Modding:Content Patcher|Content Patcher]] content packs should generally be unaffected, since their edits were applied to the active version of the file automatically (which will just become the base file in all languages).
 
In rare cases, a mod which directly targets a specific localized asset name like <code>Data/Events/Beach.fr-FR</code> may no longer work or break vanilla events (depending on how it edits them). That should be a very rare case, since the APIs for both Content Patcher and SMAPI were designed to discourage doing that.
 
====Forking deprecated====
All vanilla events which used forking now use [[#New event commands|goto labels]] instead.
 
'''Forking still works like before''' for backwards compatibility, but mod events should prefer goto labels since...
* they work more consistently and intuitively with other features like skip labels;
* it's the approach that the game will be applying and developing in future versions;
* deprecated commands will be reported as an error if you use the [[#EventValidator|<samp>EventValidator</samp>]];
* and there's no guarantee forking will always work in future versions.
 
The [[#Deprecated commands|fork-related event commands are deprecated]].
 
====Precondition slash now required for numeric event IDs====
In Stardew Valley 1.6.0–16, the behavior of an event key with no <code>/</code> depended on whether the ID was numeric. A numeric event ID like <code>10040609</code> was treated as an event with no precondition, while a string event ID like <code>PlayerKilled</code> was treated as a manual script. In 1.7+, the behavior is now consistent: any event ID without a slash (like <code>10040609</code>) is treated as a manual script, and any with a slash (like <code>10040609/</code>) is treated as an event.
 
In other words:
 
{| class="wikitable"
|-
|-
! event key format
| <samp>ForceBreathing {{t|npc}} false
! behavior in 1.6.16
| Prevent {{t|npc}} from showing a breathing animation for this event.
! &rarr;
! behavior in 1.7
|-
|-
| <samp>{{t|id}}</samp>
| <samp>ForceBreathing {{t|npc}} true {{o|breathPosX}} {{o|breathPosY}} {{o|breathRectX}} {{o|breathRectY}} {{o|breathRectWidth}} {{o|breathRectHeight}}
| event if numeric, else manual script
| Force {{t|npc}} to show a breathing animation for this event. You can optionally override the data used for the breathing rect, with the values following the same behavior as they would if specified in the <samp>Data/Characters</samp> character data.
| &rarr;
| manual script
|-
|-
| <samp>{{t|id}}/{{o|preconditions}}</samp>
| <samp>ForceBreathing {{t|npc}} reset
| event
| Reset the forced breathing modifier of {{t|npc}} for this event.
| &rarr;
| event
|}
|}


====New event commands====
===[[Modding:Fish ponds|Fish pond]] changes===
<ul>
<li>Added new fish pond translation keys:
{| class="wikitable"
{| class="wikitable"
|-
|-
! command
! asset
! description
! key
! usage
|-
|-
| <samp>choose {{t|question}} [{{t|answer}} {{t|go to label}}]+</samp>
| <samp>Strings/UI</samp>
| Show a dialogue box to choose from a list of responses, then optionally skip to a label based on the selected answer.
| <samp>PondQuery_{{t|key}}_{{t|item ID}}</samp><br /><samp>PondQuery_{{t|key}}_{{t|attitude}}</samp>
| All <samp>PondQuery_*</samp> translation keys can now be suffixed with either the qualified item ID of the fish, or the fish's general attitude based on their <samp>fish_talk_*</samp> [[Modding:Context tags|context tag]].


Arguments:
For example, the 'fish are OK' message for an [[anchovy]] pond will be loaded from the first key which exists in this order: <samp>PondQuery_StatusOk_(O)129</samp>, <samp>PondQuery_StatusOk_Rude</samp>, or <samp>PondQuery_StatusOk</samp>.
|}</li>
<li>Merged some fish pond translation keys:
{| class="wikitable"
{| class="wikitable"
|-
|-
! argument
! asset
! usage
! former key
! changes
|-
|-
| {{t|question}}
| <samp>Strings/UI</samp>
| The [[Modding:Common data field types#Translation key|translation key]] or literal text to show above the choices. This can be empty (<code>""</code>) to omit the question line.
| <samp>PondQuery_Status{{t|status}}{{t|number (0–6)}}</samp><br /><samp>PondQuery_StatusRequestComplete_{{t|fish disposition}}{{t|number (0–2)}}</samp><br /><samp>PondQuery_StatusRequestPending_{{t|fish disposition}}{{t|number (0–2)}}</samp><br />
|-
| Removed the number key suffixes using [[#Switch blocks|switch blocks]] (e.g. merged <samp>PondQuery_StatusOk{{t|number}}</samp> into <samp>PondQuery_StatusOk</samp>).
| {{t|answer}}
| The [[Modding:Common data field types#Translation key|translation key]] or literal text for an answer to show.
|-
| {{t|go to label}}
| If the player chooses this answer, jump to this label in the event (see the <samp>goto</samp> command for more info). This can be <code>""</code> or <code>_</code> to continue to the next command instead.
|}
|}
</li>
<li>[[Coral]] and [[Sea Urchin|Sea urchin]] now have the <samp>fish_talk_coral</samp> [[Modding:Context tags|context tag]] instead of a hardcoded <samp>_Coral</samp> translation key suffixes.</li>
</ul>


For example, here's a simple choice which doesn't affect anything:
===[[Modding:Item queries|Item query]] changes===
<pre>choose "Do you like apples?" "I love them." _ "I hate them." _/</pre>
Added one new item query:
 
Or you can change the course of the event based on the choice:
<pre>
speak Abigail "Do you... like me?$l"/
choose "" "Yes!" happy "No." heartbroken/
 
label heartbroken/
speak Abigail "Oh. I understand.$s"/
faceDirection Abigail left/
pause 3000/
end/
 
label happy/
speak Abigail "We should explore the mines together next time!$h"/
...
</pre>
|-
| <samp>conditionSpeak {{t|npc}} [{{t|dialogue}} {{o|condition}}]+</samp>
| Make an NPC say a dialogue based on arbitrary conditions. The first dialogue with a matching dialogue is spoken; if none match, the command is skipped.
 
Arguments:
{| class="wikitable"
{| class="wikitable"
|-
|-
! argument
! query
! usage
! effect
|-
|-
| {{t|npc}}
| <samp>SEASONAL_RACCOON_SEED</samp>
| The internal name of the NPC who should speak (which can be [[Modding:Event data#Optional NPCs|marked optional]]).
| Get a [[Giant Stump#Note|seasonal raccoon seed]] for the current season.
|-
 
| {{t|dialogue}}
This sets the stack size to the recommended amount based on the player's luck. When used in item spawn fields, you can set <samp>MinStack</samp> and <samp>MaxStack</samp> to override the stack size.
| The [[Modding:Common data field types#Translation key|translation key]] or literal text for the dialogue to speak. If omitted or empty, the command is skipped when the condition is matched.
|-
| {{o|condition}}
| One of:
* a [[Modding:Game state queries|game state query]];
* or <samp>ANSWERED {{t|response ID}}+</samp> as a shortcut for the <samp>PLAYER_HAS_DIALOGUE_ANSWER Current</samp> query;
* or omitted/blank to always match this dialogue if no previous one matched.
|}
|}


For example, here Maru says a different line if the player suggested she tell the truth:
===[[Modding:Item queries#Item spawn fields|Item spawn field]] changes===
<pre>conditionSpeak Maru "I accidentally dropped one of the samples... I'm so sorry.$s" "ANSWERED 38" "@ came in and slammed the door so loud I dropped this sample.$u"</pre>
<ul>
|-
<li>Added new item spawn fields:
| <samp>goto [{{t|target}} {{o|condition}}]+</samp>
| Skip forward or backward to a specific position in the event script. Each {{t|target}} can be:
 
{| class="wikitable"
{| class="wikitable"
|-
|-
! target
! field
! description
! effect
|-
|-
| <samp>end</samp>
| <samp>Enchantments</samp>
| Jump to the last <samp>end</samp> event command in the script.
| ''(Optional)'' For tools and weapons, the [[Enchantments|enchantment]] IDs to apply (matching their IDs in <samp>Data/Enchantments</samp>). This field applies the normal enchantment rules. Default none.
|-
 
| ''any other value''
This is specified as an array, and you can repeat secondary enchantments to boost their level. For example, this applies Vampiric and Attack (level 2):
| Jump to the first <samp>label</samp> command with this name.
<syntaxhighlight lang="js">
"Enchantments": [ "Vampiric", "Attack", "Attack" ]
</syntaxhighlight>
|}
|}
</li>
</ul>


You can list any number of label/[[Modding:Game state queries|condition]] pairs, and it will go to the first label with a matching condition. If a condition is omitted, it defaults to always true. If none of the conditions match, it continues to the next command normally.
===[[Modding:Game state queries|Game state query]] changes===
 
Added game state queries:
For example, this event script uses <samp>goto</samp> to repeat a question until a specific answer is selected:
{| class="wikitable"
<pre>
|-
.../
! query
label question/
! effect
choose Abigail "Hey! Did you have your eye on someone?" "Abigail" correct "Penny" wrong "Alex" wrong/
 
label wrong/
speak Abigail "Oh?$u"/
pause 500/
goto question/
 
label correct/
speak Abigail \"I thought so!$l\"/
pause 500/
end
</pre>
 
You can make <samp>goto</samp> conditional using [[Modding:Game state queries|game state queries]]. For example, this will go to the <samp>divorced</samp> label if you divorced Abigail, and continue to the next command if not:
<pre>goto divorced "PLAYER_NPC_RELATIONSHIP Current Abigail Divorced"/</pre>
|-
|-
| <samp>label {{t|label}}</samp>
| <samp>PLAYER_INVENTORY_SIZE {{t|player}} {{t|minSize}} {{o|maxSize}}</samp>
| Set a named position in the event script, which you can go to using the <samp>goto</samp> command.
| Whether ''any one'' of the [[Modding:Game state queries#Target player|specified player(s)]] inventory has at least {{t|minSize}} slots unlocked, and (if specified) less than or equal to {{o|maxSize}} slots unlocked.
|}


'''Note:''' you can't use <samp>end</samp> as a label name, since that automatically matches the <samp>end</samp> event command.
===[[Modding:Trigger actions|Trigger action]] changes===
Added new trigger actions:
{| class="wikitable"
|-
|-
| <samp>setDrawDepthModifier {{t|npc}} {{t|amountInTiles}}
! action
| Modify the draw depth of {{t|npc}} for this event, by {{t|amountInTiles}}.
! effect
|-
| <samp>AddHealth {{t|amount}}</samp>
| Heals the local player by {{t|amount}} and plays the appropriate sound effect.
|-
| <samp>IncreaseBackpackSize {{t|amount}}</samp>
| Increase the backpack size of the local player by {{t|amount}}.
|-
|-
| <samp>setDrawDepthModifier {{t|npc}} reset
| <samp>HoldUpItem {{t|itemId}} {{o|message}}</samp>
| Reset the draw depth modifier of {{t|npc}} for this event.
| Start animation to hold up the specified item above the player's head. If {{o||message}} is specified, it will show that message as well.
|-
|-
| <samp>ForceBreathing {{t|npc}} false
| <samp>MultiplayerGlobalMessage {{t|translationKey}} {{o|arg1}} {{o|arg2}} {{o|arg3}}...</samp>
| Prevent {{t|npc}} from showing a breathing animation for this event.
| Show a global chat message in multiplayer. The translation key needs to exist in <samp>Strings/UI</samp> and must be prefixed with <samp>Chat_</samp> within that file (meaning you would use <samp>"SomeMessage"</samp> in <samp>MultiplayerGlobalMessage</samp> and <samp>"Chat_SomeMessage"</samp> in <samp>Strings/UI</samp>). Any additional arguments after the translation key (which are parsed as tokenizable strings) will be used as substitution values using the normal notation. (ex. <samp>MultiplayerGlobalMessage "SomeMessage" "meow" "kitty cat"</samp> and <samp>"Chat_SomeMessage": "{1} goes {0}"</samp> would result in the message <samp>"kitty cat goes meow"</samp>)
|-
|-
| <samp>ForceBreathing {{t|npc}} true {{o|breathPosX}} {{o|breathPosY}} {{o|breathRectX}} {{o|breathRectY}} {{o|breathRectWidth}} {{o|breathRectHeight}}
| <samp>SetVariable {{t|variableStoreId}} {{t|name}} {{t|value}}</samp>
| Force {{t|npc}} to show a breathing animation for this event. You can optionally override the data used for the breathing rect, with the values following the same behavior as they would if specified in the <samp>Data/Characters</samp> character data.
| Sets the value of the variable {{t|name}} in the {{t|variableStoreId}} store to {{t|value}}, if that variable store is writable. (For more on variables, see the relevant section in tokenizable string changes on this page.)
|-
|-
| <samp>ForceBreathing {{t|npc}} reset
| <samp>RemoveVariable {{t|variableStoreId}} {{t|name}}</samp>
| Reset the forced breathing modifier of {{t|npc}} for this event.
| Removes the variable {{t|name}} in the {{t|variableStoreId}} store, if that variable store is writable. (For more on variables, see the relevant section in tokenizable string changes on this page.)
|}
|}


====Improved existing commands====
===[[Modding:Tokenizable strings|Tokenizable string]] changes===
{| class="wikitable"
====Usable in more places====
|-
Tokenizable strings are now usable in more places.
! command
<ul>
! description
<li>Game state queries</li>
|-
<li>Trigger actions (for <samp>If</samp>, token evaluation is delayed until which value to use is checked)</li>
| <samp>skippable</samp>
<li>A few specific event commands:
| Added an optional {{o|skip to label}} argument. If set, the event will jump to that label when the player clicks the skip button (see <samp>goto</samp> for more info). The last <samp>skippable</samp> command run before the player skips is applied.
<ul>
<li><samp>action</samp></li>
<li><samp>goto</samp>, specifically for the label(s)</li>
<li><samp>setSkipActions</samp> (token evaluation is delayed until the actions are actually run, meaning any changes that occur during the event but before the player has actually pressed "skip" will be reflected in the variables used here)</li>
</ul></li>
</ul>


This is meant to clean up or grant unlocks before the event ends. For example:
Tokens are evaluated immediately, unless otherwise specified.
<pre>
skippable beforeEnd/
.../
 
label beforeEnd/
gainSkill Fishing 1/
addItem (T)TrainingRod/
end
</pre>
 
Technically you can jump to any point in the event (e.g. to cancel the skip). However, the skip action will still cancel any ongoing event behavior like ongoing player/NPC movements, so you should be careful doing this.
|-
| <samp>splitSpeak</samp>
| You should now specify each dialogue as a separate argument (though the old syntax will still work):
<pre>// in 1.6.16
splitSpeak Sam "You think so?~Yeah... kids should play and have fun while they still have the chance."
 
// in 1.7
splitSpeak Sam "You think so?" "Yeah... kids should play and have fun while they still have the chance."
</pre>
 
This also now works with the new <samp>choose</samp> command too.
|}
 
====Deprecated commands====
These event commands are deprecated. '''They still work just like before''' (except the ones at the bottom of the table), but if you use the [[#EventValidator|<samp>EventValidator</samp>]] it'll report them as an error.


====New tokens====
The following tokens have been added:
{| class="wikitable"
{| class="wikitable"
|-
|-
! event command
! token format
! migration
! output
|-
|-
| <samp>fork</samp><br /><samp>resetVariable</samp><br /><samp>switchEvent</samp>
| <samp>InputArgument {{t|argumentName}}</samp>
| Use the <samp>choose</samp> or <samp>goto</samp> commands instead. If you used dialogue containing the <samp>%fork</samp> token, it should be removed and replaced with equivalent event commands.
| Tokenizable strings can now accept input arguments, depending on where they were called. If the input argument {{t|argumentName}} does not exist, then token evaluation fails.
|-
|}
| <samp>question forkX</samp>
| Use the <samp>choose</samp> command instead, and replace the event fork with a label.


For example, this script:
====Token expressions====
<pre>
Additionally, a new type of tokens now exists (called "expressions"), which are only usable in certain contexts. If one of these tokens is used in a place where it is not allowed, it will fail and say the token was not found. The places where expressions tokens are usable are:
// main event
<ul>
question fork1 "#I believe in you!#Wow, you're really arrogant."/
<li>Game state queries</li>
fork arrogant/
<li>Trigger actions</li>
speak Alex "Thanks, @. I'll remember that."/
<li>A few specific event commands:
...
<ul>
<li><samp>action</samp></li>
<li><samp>goto</samp>, specifically for the label(s)</li>
<li><samp>setSkipActions</samp></li>
</ul></li>
</ul>


// 'arrogant' event
{| class="wikitable"
emote Alex 12/
speak Alex "Hmmph... I think someone's a little jealous.$a"/
</pre>
 
Becomes this script:
<pre>
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"/
...
</pre>
 
Forks often duplicated the end of the script. In that case, you can have both variants just <samp>goto</samp> the common ending instead.
|-
|-
| <samp>question null</samp>
! token format
| Use <samp>choose</samp> with <samp>_</samp> labels instead. (Setting a label argument to <samp>_</samp> means it'll just continue to the next command instead.)
! output
 
For example, this command:
<pre>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."/</pre>
 
Would become this command:
<pre>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." _/</pre>
|-
|-
| <samp>quickQuestion</samp>
| <samp>Math Integer {{t|expression}}</samp> <br/>
| Use the <samp>choose</samp> command instead. The {{t|question}} and {{t|answerX}} have matching <samp>choose</samp> arguments, while the {{t|answerX script}} arguments become labels.
<samp>Math Decimal {{t|expression}}</samp>
 
| Calculates the given expression as math, using either integers (when <samp>Integer</samp> is specified) or floating point numbers (when <samp>Decimal</samp> is specified).
For example, this command:
<ul>
<pre>quickQuestion #I'd like to help#Nah, I'll pass...(break)emote Willy 32\speak Willy "Aye... I thought you would.$h#$b#I'll leave this door unlocked for ya... you can come drop off the materials whenever you like."(break)emote Willy 28\speak Willy "Alright, suit yourself...$s#$b#If you have a change of heart, you can always come back and help out. I'll leave this door unlocked, anyhow."/</pre>
<li>For example, <samp>[Math Integer 3 / 2]</samp> will result in <samp>1</samp>, while <samp>[Math Decimal 3 / 2]</samp> will result in <samp>1.5</samp>. This is because with <samp>Integer</samp> specified, each operation will remove everything after the decimal point before proceeding.</li>
 
<li>Valid operators include, in order of precedence:
Becomes this script:
<ul>
<pre>
<li>Parenthesis (meaning "<samp>(</samp>" and "<samp>)</samp>") can be used to group parts of the epxression to be processed first, similar to how one would expect in a real math expression.</li>
choose "" "I'd like to help" accept "Nah, I'll pass..." refuse/
<li><samp>*</samp> (multiplication), <samp>/</samp> (division), and <samp>%</samp> (modulus)</li>
 
<li><samp>+</samp> (addition) and <samp>-</samp> (subtraction)</li>
label accept/
</ul></li>
emote Willy 32/
</ul>
speak Willy "Aye... I thought you would.$h#$b#I'll leave this door unlocked for ya... you can come drop off the materials whenever you like."/
goto resume/
 
label refuse/
emote Willy 28/
speak Willy "Alright, suit yourself...$s#$b#If you have a change of heart, you can always come back and help out. I'll leave this door unlocked, anyhow."/
 
label resume/
</pre>
|-
|-
| <samp>cutscene bandfork</samp><br /><samp>elliottBookTalk</samp><br /><samp>question haleyDarkRoom</samp><br /><samp>question shaneCliffs</samp><br /><samp>question shaneLoan</samp>
| <samp>Comparison {{t|expression}}</samp>
| These commands are '''deleted''' and will no longer work. They're unlikely to be used by mod events, but see their relevant events for the new equivalents if needed.
| Evaluates the given expression, resulting in <samp>TRUE</samp> if the expression is true, and <samp>FALSE</samp> otherwise.
|}
 
====Changed event keys====
Events were generally unified and de-hardcoded in 1.7. In particular...
 
<ul>
<ul>
<li>Several events were previously defined in the game's C# code, where they couldn't be changed by content packs. Most of these were moved into <samp>Data/Events/*</samp> with translations in <samp>Strings/Events</samp>:
<li>The expression can compare numbers (whether integer or decimal), or strings.</li>
{| class="wikitable"
<li>Valid operators include, in order of precedence:
! event
<ul>
! new asset name
<li>Parenthesis (meaning "<samp>(</samp>" and "<samp>)</samp>") can be used to group parts of the expression to be processed first, similar to how one would expect in a real math expression.</li>
! new event ID
<li><samp>!</samp> - negation, meaning <samp>[Comparison !TRUE]</samp> becomes <samp>FALSE</samp>, <samp>[Comparison !FALSE]</samp> becomes <samp>TRUE</samp>, and something like <samp>[Comparison !(3 >= 5)]</samp> becomes <samp>TRUE</samp></li>
|-
<li><samp>&lt;</samp> (less than), <samp>&lt;=</samp> (less than or equal to), <samp>&lg;</samp> (greater than), <samp>&gt;=</samp> (greater than or equal to)</li>
| [[Giant Stump|forest raccoon]] finished event
<li><samp>==</samp> (equal to) and <samp>!=</samp> (not equal to)</li>
| <samp>Data/Events/Forest</samp>
<li><samp>&&</samp> ("and"), meaning <samp>[Comparison 2 > 1 && 3 == 3]</samp> becomes <samp>FALSE</samp></li>
| <samp>RaccoonFinish</code>
<li><samp>||</samp> ("or"), meaning <samp>[Comparison 2 > 1 || 3 == 3]</samp> becomes <samp>TRUE</samp></li>
<li>(For those who know what "logical comparison short circuiting" is, please be aware that that is currently not implemented.)</li>
</ul></li>
</ul>
|-
|-
| [[Trash Bear|forest trash bear]] cleanup
| <samp>If {{t|condition}} {{t|trueValue}} {{o|falseValue}}</samp>
| <samp>Data/Events/Forest</samp>
| If {{t|condition}} evalautes to <samp>TRUE</samp>, then {{t|trueValue}} is evaluated and returned. If {{t|condition}} evalutes to <samp>FALSE</samp>, then {{o|falseValue}} is evaluated and returned (if it was specified - otherwise, nothing is returned).
| <samp>777111</samp>
|-
|-
| [[Ginger Island#Gourmand Frog|island Gourmand crop inspection]]
| <samp>GameStateQuery {{t|gsq}}</samp>
| <samp>Data/Events/islandFarmCave</samp>
| Evaluates the given game state query, allowing GSQ usage inside <samp>[If]</samp>.
| <samp>GourmandInspection</samp>
|-
|-
| [[The Summit#Cutscene|summit perfection cutscene]]
| <samp>VariableExists {{t|variableStore}} {{t|variableName}}</samp>
| <samp>Data/Events/Summit</samp>
| Evaluates to <samp>TRUE</samp> if {{t|variableStore}} has a variable named {{t|variableName}}, and <samp>FALSE</samp> otherwise. (For more on variable stores, see later section.)
| <samp>SummitPerfection</samp>
|-
|-
| [[The_Summit#Illegitimate access|summit cheat event]]
| <samp>GetVariable {{t|variableStore}} {{t|variableName}}</samp>
| <samp>Data/Events/Summit</samp>
| Evaluates to the value of {{t|variableName}} in the variable store {{t|variableStore}}. If the variable does not exist, evaluation of the tokenizable string will fail. (For more on variable stores, see later section.)
| <samp>SummitCheat</samp>
|}</li>
<li>Others were moved from non-event data into <samp>Data/Events/*</samp>:
{| class="wikitable"
! event
! old location
! new asset
! new event ID
|-
|-
| [[Birdie]] quest intro & completed
| <samp>GetVariableWithDefault {{t|variableStore}} {{t|variableName}} {{t|defaultValue}}</samp>
| <samp>Strings/Locations:IslandSecret_Event_BirdieIntro</samp><br /><samp>Strings/Locations:IslandSecret_Event_BirdieFinished</samp><br /><samp><samp>Strings/Locations:alreadyGotNuts</samp>
| Evaluates to the value of {{t|variableName}} in the variable store {{t|variableStore}}. If the variable does not exist, {{t|defaultValue}} will be returned instead. (For more on variable stores, see later section.)
| <samp>Data/Events/IslandWest</samp>
|}
| <samp>-888999</samp> (intro)<br /><samp>-666777</samp> (completed)
 
|-
====Variable stores====
| [[Ginger Island#Field Office|field office]] intro & completed
Variables stores are a set of named variables stored in a particular location. The current available locations used as variable stores are:
| <samp>Strings/Locations:IslandFieldOffice_Intro_Event</samp><br /><samp>Strings/Locations:FieldOfficeFinale</samp>
| <samp>Data/Events/IslandFieldOffice</samp>
| <samp>FieldOfficeIntro</samp><br /><samp>FieldOfficeDone</samp>
|-
| [[Leo]] intro
| <samp>Strings/Locations:IslandHut_Event_ParrotBoyIntro</samp>
| <samp>Data/Events/IslandHut</samp>
| <samp>LeoIntro</samp>
|-
| [[Meowmere]] event
| <samp>Strings/1_6_Strings:ForestPylonEvent</samp>
| <samp>Data/Events/WizardHouseBasement</samp>
| <samp>ForestPylon</samp>
|-
| [[Mr. Qi#Secrets|Mr. Qi Skull Cavern level 100]]
| <samp>Data/ExtraDialogue:SkullCavern_100_event</samp><br /><samp>Data/ExtraDialogue:SkullCavern_100_event_honorable</samp>
| <samp>Data/Events/SkullCave</samp>
| <samp>SkullCavern100</samp>
|-
| [[Professor Snail]] exits cave
| <samp>Strings/Locations:IslandNorth_Event_SafariManAppear</samp>
| <samp>Data/Events/IslandNorth</samp>
| <samp>ProfSnailIntro</samp>
|}</li>
<li>Other event keys were changed or merged as part of the other event changes:
{| class="wikitable"
{| class="wikitable"
|-
|-
! asset
! variable store ID
! entry key
! description
! change in 1.7
|-
|-
| <samp>Data/Events/AbandonedJojaMart</samp>
| <samp>Global</samp>
| <code>missingBundleComplete</code>
| A variable store attached to the save itself.
| Event key changed to <code>192393</code> to match the event ID.
<ul>
<li>Any player can read and write from this.</li>
<li>This variable store will be saved into the save file at the end of the day.</li>
</ul>
|-
|-
| <samp>Data/Events/Farm</samp>
| <samp>Player/{{t|playerSpecifier}}</samp>
| <code>992559/t 600 1130/n clothFound/o Emily/w sunny</code><br /><code>992559/t 600 1130/n clothFound/O Emily/w sunny</code>
| A variable store attached to a particular player.
| Merged into a single <code>992559/Time 600 1130/LocalMail clothFound/Weather sunny</code> event.
<ul>
<li>{{t|playerSpecifier}} uses the same format as [[Modding:Game state queries#Target player|game state query target players]], except specifiers that work for check multiple players (such as <samp>Any</samp> or <samp>All</samp>) may not be used.</li>
<li>Any player can read from this, however only the owning player can write to their variable store.</li>
<li>If a player is disconnected, their variables are saved, and will be resynced when they reconnect.</li>
<li>This variable store will be saved into the save file at the end of the day.</li>
</ul>
|-
|-
| <samp>Data/Events/QiNutRoom</samp>
| <samp>Local</samp>
| <code>10040609</code>
| A variable store attached to a "calling context". Generally, this means it will always be reset between uses unless specifically kept, such as in the following contexts:
| Event key changed to <code>10040609/</code> per the [[#Precondition slash now required for numeric event IDs|precondition change]].
<ul>
|-
<li>Events - A variable set in the <samp>Local</samp> variable store using the <samp>action</samp> event command will be usable later during that event.</li>
| <samp>Data/Events/SamHouse</samp>
<li><samp>Data/TriggerActions</samp> - When a trigger action has multiple actions to run, all actions will be using the same <samp>Local</samp> variable store, meaning earlier trigger actions can save data for use by later trigger actions in the same sequence.</samp></li>
| <code>94/e 93/k 95/t 1800 1950/i 136/y 1</code><br /><code>94/e 93/k 95/t 1800 1950/i 136/y 2</code>
| Merged into a single <code>95/SawEvent 93/!SawEvent 94/Time 1800 1950/HasItem 136</code> event.
|-
| <samp>Data/Events/Town</samp>
| <code>611173/Hn pamHouseUpgrade/o Penny</code>
| Merged into the existing <code>611173/Hn pamHouseUpgrade</code> event.
|}</li>
</ul>
</ul>
|}


For events that didn't previously have an event ID, their new IDs will be added to the player's seen-events list automatically if needed when the save is loaded.
===Debug command changes===
 
This only details some debug command changes - mainly, ones that might be useful for mod authors.
====Other event changes====
* Moved all vanilla events' on-skip behavior into their event scripts (except the pet adoption logic).


===[[Modding:Fish ponds|Fish pond]] changes===
<ul>
<li>Added new fish pond translation keys:
{| class="wikitable"
{| class="wikitable"
|-
|-
! asset
! command
! key
! changes
! usage
|-
| <samp>/tokens</samp>
| A new required parameter has been introduced as the first argument, {{t|type}}. If {{t|type}} is <samp>Text</samp> the string will be evaluated using non-expression tokens. If {{t|type}} is <samp>Expression</samp>, expression tokens will be allowed as well.
|-
|-
| <samp>Strings/UI</samp>
| <samp>/runmacro</samp>
| <samp>PondQuery_{{t|key}}_{{t|item ID}}</samp><br /><samp>PondQuery_{{t|key}}_{{t|attitude}}</samp>
| Commented lines are now allowed - if <samp>--</samp> is the beginning of a line, it will be ignored.
| All <samp>PondQuery_*</samp> translation keys can now be suffixed with either the qualified item ID of the fish, or the fish's general attitude based on their <samp>fish_talk_*</samp> [[Modding:Context tags|context tag]].
 
For example, the 'fish are OK' message for an [[anchovy]] pond will be loaded from the first key which exists in this order: <samp>PondQuery_StatusOk_(O)129</samp>, <samp>PondQuery_StatusOk_Rude</samp>, or <samp>PondQuery_StatusOk</samp>.
|}</li>
<li>Merged some fish pond translation keys:
{| class="wikitable"
|-
|-
! asset
| <samp>/debugaction</samp> (new)
! former key
| A new command for trying out tokenizable string input arguments, tokenizable string local variables, and trigger actions using them. This command maintains its own set of input arguments and a local variable store, which can be manipulated using the subcommands.
! changes
|-
| <samp>Strings/UI</samp>
| <samp>PondQuery_Status{{t|status}}{{t|number (0–6)}}</samp><br /><samp>PondQuery_StatusRequestComplete_{{t|fish disposition}}{{t|number (0–2)}}</samp><br /><samp>PondQuery_StatusRequestPending_{{t|fish disposition}}{{t|number (0–2)}}</samp><br />
| Removed the number key suffixes using [[#Switch blocks|switch blocks]] (e.g. merged <samp>PondQuery_StatusOk{{t|number}}</samp> into <samp>PondQuery_StatusOk</samp>).
|}
</li>
<li>[[Coral]] and [[Sea Urchin|Sea urchin]] now have the <samp>fish_talk_coral</samp> [[Modding:Context tags|context tag]] instead of a hardcoded <samp>_Coral</samp> translation key suffixes.</li>
</ul>
 
===[[Modding:Item queries|Item query]] changes===
Added one new item query:
{| class="wikitable"
{| class="wikitable"
|-
|-
! query
! subcommand
! effect
! effect
|-
|-
| <samp>SEASONAL_RACCOON_SEED</samp>
| <samp>/debugaction argument {{t|name}} {{t|value}}</samp>
| Get a [[Giant Stump#Note|seasonal raccoon seed]] for the current season.
| Sets the input argument {{t|name}} to {{t|value}}, which can be later used in <samp>/debugaction run</samp> and <samp>/debugaction evaluate</samp>.
 
|-
This sets the stack size to the recommended amount based on the player's luck. When used in item spawn fields, you can set <samp>MinStack</samp> and <samp>MaxStack</samp> to override the stack size.
| <samp>/debugaction evaluate {{t|expression}}</samp>
|}
| Evaluates {{t|expression}} as a tokenizable string, using input arguments and local variables previously set from this command.
 
===[[Modding:Item queries#Item spawn fields|Item spawn field]] changes===
<ul>
<li>Added new item spawn fields:
{| class="wikitable"
|-
|-
! field
| <samp>/debugaction run {{t|action}}</samp>
! effect
| Runs {{t|action}} as a trigger action, using input arguments and local variables previously set from this command.
|-
|-
| <samp>Enchantments</samp>
| <samp>/debugaction clear</samp>
| ''(Optional)'' For tools and weapons, the [[Enchantments|enchantment]] IDs to apply (matching their IDs in <samp>Data/Enchantments</samp>). This field applies the normal enchantment rules. Default none.
| Clears all previously set input arguments and local variables for <samp>/debugaction</samp>.
|}
Some examples of using this command alongside <samp>/runmacro</samp>, at least at the time of writing, can be found here: https://gist.github.com/spacechase0/3ca7b2e195619a17ef9039c894cc60e4
|}


This is specified as an array, and you can repeat secondary enchantments to boost their level. For example, this applies Vampiric and Attack (level 2):
==Changes for C# mod authors==
<syntaxhighlight lang="js">
 
"Enchantments": [ "Vampiric", "Attack", "Attack" ]
===DialogueKeyValidator===
</syntaxhighlight>
The new <samp>DialogueKeyValidator</samp> class analyses [[Modding:Dialogue|dialogue entries]] to detect dialogue keys which don't match one of the predefined patterns.
|}
</li>
</ul>


===[[Modding:Game state queries|Game state query]] changes===
This is mainly meant to implement unit tests. For example, to validate all dialogue keys in a data asset:
Added game state queries:
<syntaxhighlight lang="c#">
{| class="wikitable"
string assetName = "Characters/Dialogues/Abigail";
|-
var dialogues = Game1.content.Load<Dictionary<string, string>>(assetName);
! query
! effect
|-
| <samp>PLAYER_INVENTORY_SIZE {{t|player}} {{t|minSize}} {{o|maxSize}}</samp>
| Whether ''any one'' of the [[Modding:Game state queries#Target player|specified player(s)]] inventory has at least {{t|minSize}} slots unlocked, and (if specified) less than or equal to {{o|maxSize}} slots unlocked.
|}


===[[Modding:Trigger actions|Trigger action]] changes===
var validator = new DialogueKeyValidator();
Added new trigger actions:
foreach ((string key, string dialogue) in dialogues)
{| class="wikitable"
{
|-
    if (!validator.IsKnownFormat(assetName, key))
! action
        Assert.Fail($"Validation failed for dialogue '{key}': key doesn't match one of the expected patterns.");
! effect
}
|-
</syntaxhighlight>
| <samp>AddHealth {{t|amount}}</samp>
 
| Heals the local player by {{t|amount}} and plays the appropriate sound effect.
You can optionally extend the valid patterns by setting validator fields like <samp>MarriageDialogueKeyPatterns</samp>.
|-
 
| <samp>IncreaseBackpackSize {{t|amount}}</samp>
===Content manager changes===
| Increase the backpack size of the local player by {{t|amount}}.
1.7 adds a <samp>SourceCodeContentManager</samp> implementation of <samp>IContentManager</samp>. This is meant for internal unit tests, and isn't relevant for mod authors except as an example.
|-
 
| <samp>HoldUpItem {{t|itemId}} {{o|message}}</samp>
===Monster changes===
| Start animation to hold up the specified item above the player's head. If {{o||message}} is specified, it will show that message as well.
* The [[#Data/Monsters|monster data has been overhauled]].
|-
* The new <samp>monster.Tags</samp> field contains a set of metadata tags about the monster which can be checked in [[#Data/Monsters|<samp>Data/Monsters</samp>]]. It's safe to add new tags to the list for existing monster types.
| <samp>MultiplayerGlobalMessage {{t|translationKey}} {{o|arg1}} {{o|arg2}} {{o|arg3}}...</samp>
* The former <samp>monster.objectsToDrop</samp> field (a list of string object IDs) has been replaced by <samp>monster.drops</samp> (an [[Modding:Migrate to Stardew Valley 1.6#Inventory class|item inventory]]).
| Show a global chat message in multiplayer. The translation key needs to exist in <samp>Strings/UI</samp> and must be prefixed with <samp>Chat_</samp> within that file (meaning you would use <samp>"SomeMessage"</samp> in <samp>MultiplayerGlobalMessage</samp> and <samp>"Chat_SomeMessage"</samp> in <samp>Strings/UI</samp>). Any additional arguments after the translation key (which are parsed as tokenizable strings) will be used as substitution values using the normal notation. (ex. <samp>MultiplayerGlobalMessage "SomeMessage" "meow" "kitty cat"</samp> and <samp>"Chat_SomeMessage": "{1} goes {0}"</samp> would result in the message <samp>"kitty cat goes meow"</samp>)
* Removed <samp>monster.getExtraDropItems()</samp>. Drops should be added in [[#Data/Monsters|<samp>Data/Monsters</samp>]] instead.
|-
| <samp>SetVariable {{t|variableStoreId}} {{t|name}} {{t|value}}</samp>
| Sets the value of the variable {{t|name}} in the {{t|variableStoreId}} store to {{t|value}}, if that variable store is writable. (For more on variables, see the relevant section in tokenizable string changes on this page.)
|-
| <samp>RemoveVariable {{t|variableStoreId}} {{t|name}}</samp>
| Removes the variable {{t|name}} in the {{t|variableStoreId}} store, if that variable store is writable. (For more on variables, see the relevant section in tokenizable string changes on this page.)
|}


===[[Modding:Tokenizable strings|Tokenizable string]] changes===
===<samp>SpecialItem</samp> deprecation===
====Usable in more places====
<samp>SpecialItem</samp> is now deprecated, and is only kept for save compatibility. All existing uses of it have been migrated to use <samp>Object</samp> instead, with the following new objects being available:
Tokenizable strings are now usable in more places.
<ul>
<ul>
<li>Game state queries</li>
<li><samp>(O)BackpackUpgrade1</samp></li>
<li>Trigger actions (for <samp>If</samp>, token evaluation is delayed until which value to use is checked)</li>
<li><samp>(O)BackpackUpgrade2</samp></li>
<li>A few specific event commands:
<li><samp>(O)ClubCard</samp></li>
<ul>
<li><samp>(O)SpecialCharm</samp></li>
<li><samp>action</samp></li>
<li><samp>(O)SkullKey</samp></li>
<li><samp>goto</samp>, specifically for the label(s)</li>
<li><samp>(O)MagnifyingGlass</samp></li>
<li><samp>setSkipActions</samp> (token evaluation is delayed until the actions are actually run, meaning any changes that occur during the event but before the player has actually pressed "skip" will be reflected in the variables used here)</li>
<li><samp>(O)DarkTalisman</samp></li>
</ul></li>
<li><samp>(O)MagicInk</samp></li>
</ul>
</ul>


Tokens are evaluated immediately, unless otherwise specified.
===Tokenizable string changes===
Tokenizable string parsing and evaluation has been separated into two separate stages. As a result, several places that use them now cache the parsed version (which is called <samp>ParsedStringSegment</samp>.
 
Any custom trigger actions or tokenizable string tokens that want to delay tokenizable string evaluation so they can handle it themself (such as for only evaluating portions that should be used based on a condition) can attach the <samp>[DelayArgumentTokenEvaluation]</samp> attribute to their handler method. This will prevent the arguments from being evaluated before they reach your handler. (However, the handlers themselves currently still use <samp>string[]</samp> as their arguments, so this could be slightly off depending on how quotes were used.)


====New tokens====
<samp>TokenParser.ParseText(string text, Random random, TokenParserDelegate customParser, Farmer player)</samp> is now deprecated, and <samp>TokenParser.EvaluateText(string text, TokenParserContext context)</samp> should be used instead.
The following tokens have been added:
{| class="wikitable"
|-
! token format
! output
|-
| <samp>InputArgument {{t|argumentName}}</samp>
| Tokenizable strings can now accept input arguments, depending on where they were called. If the input argument {{t|argumentName}} does not exist, then token evaluation fails.
|}


====Token expressions====
===Netfield changes===
Additionally, a new type of tokens now exists (called "expressions"), which are only usable in certain contexts. If one of these tokens is used in a place where it is not allowed, it will fail and say the token was not found. The places where expressions tokens are usable are:
The following changes must now all be registered with <samp>ProtocolSummary</samp> before usage:
<ul>
<ul>
<li>Game state queries</li>
<li>Additional net fields</li>
<li>Trigger actions</li>
<li>Additional net types</li>
<li>A few specific event commands:
<li>Subclasses of any synced type</li>
<ul>
<li><samp>action</samp></li>
<li><samp>goto</samp>, specifically for the label(s)</li>
<li><samp>setSkipActions</samp></li>
</ul></li>
</ul>
</ul>
If this is not done, an exception will be thrown when adding netfields, or setting values of unknown types.
Instead of manually registering with <samp>ProtocolSummary</samp> or manually adding net fields using a harmony patch, everything should be registered through a new SMAPI API (coming soon) which will handle these details for you. This will ensure that if mods load in a different order on one player's computer compared to other connected players, it will not break anything.


If a farmhand's <samp>ProtocolSummary</samp> does not match the host's, they will get a protocol mismatch error upon connecting (rather than "No cabins available", or other obscure and unclear issues).
===Other breaking API changes===
''(This section is meant as a quick reference if you have build errors; there's no need to read through it otherwise.)''
====Removed or renamed types====
These classes renamed in 1.7:
{| class="wikitable"
{| class="wikitable"
|-
|-
! token format
! type
! output
! migration
|-
|-
| <samp>Math Integer {{t|expression}}</samp> <br/>
| <samp>BaseEnchantment</samp>
<samp>Math Decimal {{t|expression}}</samp>
| Renamed to <samp>Enchantment</samp>.
| Calculates the given expression as math, using either integers (when <samp>Integer</samp> is specified) or floating point numbers (when <samp>Decimal</samp> is specified).
<ul>
<li>For example, <samp>[Math Integer 3 / 2]</samp> will result in <samp>1</samp>, while <samp>[Math Decimal 3 / 2]</samp> will result in <samp>1.5</samp>. This is because with <samp>Integer</samp> specified, each operation will remove everything after the decimal point before proceeding.</li>
<li>Valid operators include, in order of precedence:
<ul>
<li>Parenthesis (meaning "<samp>(</samp>" and "<samp>)</samp>") can be used to group parts of the epxression to be processed first, similar to how one would expect in a real math expression.</li>
<li><samp>*</samp> (multiplication), <samp>/</samp> (division), and <samp>%</samp> (modulus)</li>
<li><samp>+</samp> (addition) and <samp>-</samp> (subtraction)</li>
</ul></li>
</ul>
|-
|-
| <samp>Comparison {{t|expression}}</samp>
| <samp>AxeEnchantment</samp><br /><samp>BaseWeaponEnchantment</samp><br /><samp>FishingRodEnchantment</samp><br /><samp>HoeEnchantment</samp><br /><samp>MilkPailEnchantment</samp><br /><samp>PanEnchantment</samp><br /><samp>PickaxeEnchantment</samp><br /><samp>ShearsEnchantment</samp><br /><samp>WateringCanEnchantment</samp>
| Evaluates the given expression, resulting in <samp>TRUE</samp> if the expression is true, and <samp>FALSE</samp> otherwise.
| Obsolete. Enchantments now [[#Enchantment data|target tools via data]] instead.
<ul>
|}
<li>The expression can compare numbers (whether integer or decimal), or strings.</li>
 
<li>Valid operators include, in order of precedence:
====Other API changes====
<ul>
These class members changed in 1.7:
<li>Parenthesis (meaning "<samp>(</samp>" and "<samp>)</samp>") can be used to group parts of the expression to be processed first, similar to how one would expect in a real math expression.</li>
 
<li><samp>!</samp> - negation, meaning <samp>[Comparison !TRUE]</samp> becomes <samp>FALSE</samp>, <samp>[Comparison !FALSE]</samp> becomes <samp>TRUE</samp>, and something like <samp>[Comparison !(3 >= 5)]</samp> becomes <samp>TRUE</samp></li>
{| class="wikitable"
<li><samp>&lt;</samp> (less than), <samp>&lt;=</samp> (less than or equal to), <samp>&lg;</samp> (greater than), <samp>&gt;=</samp> (greater than or equal to)</li>
<li><samp>==</samp> (equal to) and <samp>!=</samp> (not equal to)</li>
<li><samp>&&</samp> ("and"), meaning <samp>[Comparison 2 > 1 && 3 == 3]</samp> becomes <samp>FALSE</samp></li>
<li><samp>||</samp> ("or"), meaning <samp>[Comparison 2 > 1 || 3 == 3]</samp> becomes <samp>TRUE</samp></li>
<li>(For those who know what "logical comparison short circuiting" is, please be aware that that is currently not implemented.)</li>
</ul></li>
</ul>
|-
|-
| <samp>If {{t|condition}} {{t|trueValue}} {{o|falseValue}}</samp>
! type
| If {{t|condition}} evalautes to <samp>TRUE</samp>, then {{t|trueValue}} is evaluated and returned. If {{t|condition}} evalutes to <samp>FALSE</samp>, then {{o|falseValue}} is evaluated and returned (if it was specified - otherwise, nothing is returned).
! member
! migration
|-
|-
| <samp>GameStateQuery {{t|gsq}}</samp>
|rowspan="9"| <samp>BaseEnchantment</samp><br /><small>(and its subclasses)</small>
| Evaluates the given game state query, allowing GSQ usage inside <samp>[If]</samp>.
| <samp>hideEnchantmentName</samp>
| Replaced by <samp>EnchantmentManager.HideEnchantmentName</samp>.
|-
|-
| <samp>VariableExists {{t|variableStore}} {{t|variableName}}</samp>
| <samp>hideSecondaryEnchantName</samp>
| Evaluates to <samp>TRUE</samp> if {{t|variableStore}} has a variable named {{t|variableName}}, and <samp>FALSE</samp> otherwise. (For more on variable stores, see later section.)
| Replaced by <samp>EnchantmentManager.HideSecondaryEnchantName</samp>.
|-
|-
| <samp>GetVariable {{t|variableStore}} {{t|variableName}}</samp>
| <samp>GetEnchantmentFromItem(…)</samp>
| Evaluates to the value of {{t|variableName}} in the variable store {{t|variableStore}}. If the variable does not exist, evaluation of the tokenizable string will fail. (For more on variable stores, see later section.)
| Replaced by <samp>EnchantmentManager.GetEnchantmentFromItem</samp>.
|-
|-
| <samp>GetVariableWithDefault {{t|variableStore}} {{t|variableName}} {{t|defaultValue}}</samp>
| <samp>GetAvailableEnchantments()</samp>
| Evaluates to the value of {{t|variableName}} in the variable store {{t|variableStore}}. If the variable does not exist, {{t|defaultValue}} will be returned instead. (For more on variable stores, see later section.)
| Removed.
|}
<ul>
<li>To check whether any enchantments can be applied to a tool through the [[forge]], use <samp>EnchantmentManager.CanForgeEnchant</samp>.</li>
<li>There's no directly equivalent method in 1.7, but you can mimic the former logic if needed.
<syntaxhighlight lang="c#">
static List<Enchantment> GetAvailableEnchantments()
{
    var dataAsset = DataLoader.Enchantments(Game1.content);


====Variable stores====
    List<Enchantment> enchantments = [];
Variables stores are a set of named variables stored in a particular location. The current available locations used as variable stores are:
    foreach ((string id, EnchantmentData data) in dataAsset)
{| class="wikitable"
    {
|-
        if (data.ForgeWith == Object.prismaticShardQID)
! variable store ID
            enchantments.Add(EnchantmentManager.CreateEnchantment(dataAsset, id));
! description
    }
|-
 
| <samp>Global</samp>
    return enchantments;
| A variable store attached to the save itself.
}
<ul>
</syntaxhighlight></li>
<li>Any player can read and write from this.</li>
<li>This variable store will be saved into the save file at the end of the day.</li>
</ul>
</ul>
|-
|-
| <samp>Player/{{t|playerSpecifier}}</samp>
| <samp>GetAvailableEnchantmentsForItem(…)</samp>
| A variable store attached to a particular player.
| Removed.
<ul>
<ul>
<li>{{t|playerSpecifier}} uses the same format as [[Modding:Game state queries#Target player|game state query target players]], except specifiers that work for check multiple players (such as <samp>Any</samp> or <samp>All</samp>) may not be used.</li>
<li>To check whether any enchantments can be applied to a tool through the [[forge]], use <samp>EnchantmentManager.CanForgeEnchant</samp>.</li>
<li>Any player can read from this, however only the owning player can write to their variable store.</li>
<li>There's no directly equivalent method in 1.7, but you can mimic the former logic if needed.
<li>If a player is disconnected, their variables are saved, and will be resynced when they reconnect.</li>
<syntaxhighlight lang="c#">
<li>This variable store will be saved into the save file at the end of the day.</li>
static List<Enchantment> GetAvailableEnchantmentsForItem(Item? tool, Item? item)
</ul>
{
|-
    var dataAsset = DataLoader.Enchantments(Game1.content);
| <samp>Local</samp>
    var contextTags = tool?.GetContextTags();
| A variable store attached to a "calling context". Generally, this means it will always be reset between uses unless specifically kept, such as in the following contexts:
<ul>
<li>Events - A variable set in the <samp>Local</samp> variable store using the <samp>action</samp> event command will be usable later during that event.</li>
<li><samp>Data/TriggerActions</samp> - When a trigger action has multiple actions to run, all actions will be using the same <samp>Local</samp> variable store, meaning earlier trigger actions can save data for use by later trigger actions in the same sequence.</samp></li>
</ul>
|}


===Debug command changes===
    List<Enchantment> enchantments = [];
This only details some debug command changes - mainly, ones that might be useful for mod authors.
    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));
    }


{| class="wikitable"
    return enchantments;
}
</syntaxhighlight></li>
</ul>
|-
|-
! command
| <samp>GetName()</samp>
! changes
| Removed. This inconsistently returned an ID, a display name, or <samp>"Unknown Enchantment"</samp> depending on the enchantment type. Use the new <samp>Id</samp> property or the pre-existing <samp>GetDisplayName()</samp> method instead.
|-
|-
| <samp>/tokens</samp>
| <samp>GetLevel()</samp>
| A new required parameter has been introduced as the first argument, {{t|type}}. If {{t|type}} is <samp>Text</samp> the string will be evaluated using non-expression tokens. If {{t|type}} is <samp>Expression</samp>, expression tokens will be allowed as well.
| Removed. Use <samp>Level</samp> instead.
|-
|-
| <samp>/runmacro</samp>
| <samp>GetType()</samp>
| Commented lines are now allowed - if <samp>--</samp> is the beginning of a line, it will be ignored.
| This was sometimes to identify enchantments (like <code>enchantment.GetType() == expectedEnchantment.GetType()</code>). That's no longer reliable, since 1.7 introduces data-based enchantments which may not have their own C# type. You should use the new <samp>enchantment.Id</samp> property instead.
|-
|-
| <samp>/debugaction</samp> (new)
| <samp>ResetEnchantments()</samp>
| A new command for trying out tokenizable string input arguments, tokenizable string local variables, and trigger actions using them. This command maintains its own set of input arguments and a local variable store, which can be manipulated using the subcommands.
| Removed. This is no longer needed since it no longer has a cached list of enchantment instances.
{| class="wikitable"
|-
|-
! subcommand
|rowspan="2"| <samp>Furniture</samp>
! effect
| <samp>armchair</samp><br /><samp>bed</samp><br /><samp>bench</samp><br /><samp>bookcase</samp><br /><samp>chair</samp><br /><samp>couch</samp><br /><samp>decor</samp><br /><samp>dresser</samp><br /><samp>fireplace</samp><br /><samp>lamp</samp><br /><samp>longTable</samp><br /><samp>other</samp><br /><samp>painting</samp><br /><samp>rug</samp><br /><samp>sconce</samp><br /><samp>table</samp><br /><samp>torch</samp><br /><samp>window</samp>
| Removed. Replaced by the <samp>FurnitureType</samp> enum (e.g. <code>Furniture.rug</code> is now <code>FurnitureType.Rug</code>).
|-
|-
| <samp>/debugaction argument {{t|name}} {{t|value}}</samp>
| <samp>placementRestrictions</samp>
| Sets the input argument {{t|name}} to {{t|value}}, which can be later used in <samp>/debugaction run</samp> and <samp>/debugaction evaluate</samp>.
| Removed. Replaced by <samp>CanPlaceIndoors</samp> and <samp>CanPlaceOutdoors</samp>.
|-
|-
| <samp>/debugaction evaluate {{t|expression}}</samp>
|rowspan="2"| <samp>Monster</samp>
| Evaluates {{t|expression}} as a tokenizable string, using input arguments and local variables previously set from this command.
| <samp>getExtraDropItems()</samp>
| Removed. Drops should be added to [[#Data/Monsters|<samp>Data/Monsters</samp>]] instead.
 
[[Modding:Modder Guide/APIs/Harmony|Harmony patches]] which can't be moved into data can target <samp>Monster.RollForDrops</samp> instead.
|-
|-
| <samp>/debugaction run {{t|action}}</samp>
| <samp>objectsToDrop</samp>
| Runs {{t|action}} as a trigger action, using input arguments and local variables previously set from this command.
| Removed. Replaced by <samp>drops</samp>; see [[#Monster changes|''monster changes'']] and [[#Data/Monsters|''<samp>Data/Monsters</samp>'']].
|-
|-
| <samp>/debugaction clear</samp>
| <samp>Tool</samp>
| Clears all previously set input arguments and local variables for <samp>/debugaction</samp>.
| <samp>GetEnchantmentLevel&lt;T&gt;()</samp><br /><samp>GetEnchantmentOfType&lt;T&gt;()</samp><br /><samp>hasEnchantmentOfType&lt;T&gt;()</samp>
|}
| Removed. Replaced by <samp>GetEnchantmentLevel(id)</samp>, <samp>GetEnchantment(id)</samp>, and <samp>HasEnchantment(id)</samp> respectively. All vanilla enchantments have a constant for the ID like <samp>EnchantmentIds.GalaxySoul</samp>.
Some examples of using this command alongside <samp>/runmacro</samp>, at least at the time of writing, can be found here: https://gist.github.com/spacechase0/3ca7b2e195619a17ef9039c894cc60e4
|}
|}


==Changes for C# mod authors==
==Name translation changes for wiki maintainers==
Some in-game item and monster names were retranslated in some languages for clarity or correctness.
 
This list is mostly provided to help wiki maintainers update pages, so it doesn't include names which only changed capitalization, changed <code>'</code> (straight apostrophe) to <code>’</code> (curly) in French, or aren't visible to vanilla players (like mine rocks).


===DialogueKeyValidator===
''None yet.''
The new <samp>DialogueKeyValidator</samp> class analyses [[Modding:Dialogue|dialogue entries]] to detect dialogue keys which don't match one of the predefined patterns.


This is mainly meant to implement unit tests. For example, to validate all dialogue keys in a data asset:
==XNB impact==
<syntaxhighlight lang="c#">
<!--
string assetName = "Characters/Dialogues/Abigail";
var dialogues = Game1.content.Load<Dictionary<string, string>>(assetName);


var validator = new DialogueKeyValidator();
Updated up to 1.7 alpha 2025-09-13.
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.");
}
</syntaxhighlight>


You can optionally extend the valid patterns by setting validator fields like <samp>MarriageDialogueKeyPatterns</samp>.
-->
===Overview===
This section provides a summary of the XNB files which changed in Stardew Valley 1.7. This doesn't include new files (since they won't impact existing mods) or text changes in non-English files.


===EventValidator changes===
[[Modding:Using XNB mods|XNB mods]] are disproportionately affected, since...
The [[Modding:Migrate to Stardew Valley 1.6.16|<samp>EventValidator</samp> class added in 1.6.16]] lets you detect issues in [[Modding:Event data|event scripts]] (mainly meant for unit tests).
# they replace the entire file;
# they're loaded through the MonoGame content pipeline which is less tolerant of format changes;
# they don't benefit from the compatibility rewrites [[Modding:Content Patcher|Content Patcher]] provides for its content packs.


Stardew Valley 1.7 adds one token recognized by the <samp>EventArguments</samp> attribute:
Content Patcher packs are typically unaffected (and Content Patcher will try to rewrite content packs automatically). However if a content pack replaces an entire asset instead of editing, it's more likely to be affected like an XNB mod.
{| class="wikitable"
|-
! token
! meaning
|-
| <samp>goToLabel</samp>
| An event label (see the <samp>goto</samp> and <samp>label</samp> event commands). This is equivalent to <samp>word</samp>, but is used by <samp>EventValidator</samp> to validate label references.
|}


===Content manager changes===
===Changed assets===
1.7 adds a <samp>SourceCodeContentManager</samp> implementation of <samp>IContentManager</samp>. This is meant for internal unit tests, and isn't relevant for mod authors except as an example.
Compatibility is broadly grouped into four categories:
* "'''✘ broken'''": mods will remove new content or significant changes, or the mod's intended changes will no longer work. Effects may range from display bugs to crashes, depending how the game uses that specific content.
* "✘ will remove changes": mods will remove minor changes in 1.7 (e.g. typo fixes).
* "✓ mostly unaffected": mods will only be affected if they edit specific entries or fields.
* Blank: no expected impact for the vast majority of mods.


===Monster changes===
{| class="wikitable"
* The [[#Data/Monsters|monster data has been overhauled]].
|-
* The new <samp>monster.Tags</samp> field contains a set of metadata tags about the monster which can be checked in [[#Data/Monsters|<samp>Data/Monsters</samp>]]. It's safe to add new tags to the list for existing monster types.
!rowspan="2"| content asset
* The former <samp>monster.objectsToDrop</samp> field (a list of string object IDs) has been replaced by <samp>monster.drops</samp> (an [[Modding:Migrate to Stardew Valley 1.6#Inventory class|item inventory]]).
!rowspan="2"| changes in 1.7
* Removed <samp>monster.getExtraDropItems()</samp>. Drops should be added in [[#Data/Monsters|<samp>Data/Monsters</samp>]] instead.
!colspan="2"| compatibility for pre-1.7 mods
 
|-
===<samp>SpecialItem</samp> deprecation===
! XNB mods
<samp>SpecialItem</samp> is now deprecated, and is only kept for save compatibility. All existing uses of it have been migrated to use <samp>Object</samp> instead, with the following new objects being available:
! Content Patcher packs
<ul>
|-
<li><samp>(O)BackpackUpgrade1</samp></li>
| <samp>Characters/Dialogue/Abigail</samp>
<li><samp>(O)BackpackUpgrade2</samp></li>
| &#32;
<li><samp>(O)ClubCard</samp></li>
* [[#Dialogue changes|Merged resort dialogue keys]].
<li><samp>(O)SpecialCharm</samp></li>
* Fixed invalid dialogue keys.
<li><samp>(O)SkullKey</samp></li>
| '''✘ broken'''
<li><samp>(O)MagnifyingGlass</samp></li>
| ✓ mostly unaffected
<li><samp>(O)DarkTalisman</samp></li>
|-
<li><samp>(O)MagicInk</samp></li>
| <samp>Characters/Dialogue/Alex</samp><br /><samp>Characters/Dialogue/Clint</samp>
</ul>
| [[#Dialogue changes|Merged resort dialogue keys]].
 
| '''✘ broken'''
===Tokenizable string changes===
| ✓ mostly unaffected
Tokenizable string parsing and evaluation has been separated into two separate stages. As a result, several places that use them now cache the parsed version (which is called <samp>ParsedStringSegment</samp>.
|-
 
| <samp>Characters/Dialogue/Dwarf</samp>
Any custom trigger actions or tokenizable string tokens that want to delay tokenizable string evaluation so they can handle it themself (such as for only evaluating portions that should be used based on a condition) can attach the <samp>[DelayArgumentTokenEvaluation]</samp> attribute to their handler method. This will prevent the arguments from being evaluated before they reach your handler. (However, the handlers themselves currently still use <samp>string[]</samp> as their arguments, so this could be slightly off depending on how quotes were used.)
| Fixed invalid dialogue keys.
 
| '''✘ broken'''
<samp>TokenParser.ParseText(string text, Random random, TokenParserDelegate customParser, Farmer player)</samp> is now deprecated, and <samp>TokenParser.EvaluateText(string text, TokenParserContext context)</samp> should be used instead.
| ✓ mostly unaffected
 
===Netfield changes===
The following changes must now all be registered with <samp>ProtocolSummary</samp> before usage:
<ul>
<li>Additional net fields</li>
<li>Additional net types</li>
<li>Subclasses of any synced type</li>
</ul>
If this is not done, an exception will be thrown when adding netfields, or setting values of unknown types.
 
Instead of manually registering with <samp>ProtocolSummary</samp> or manually adding net fields using a harmony patch, everything should be registered through a new SMAPI API (coming soon) which will handle these details for you. This will ensure that if mods load in a different order on one player's computer compared to other connected players, it will not break anything.
 
If a farmhand's <samp>ProtocolSummary</samp> does not match the host's, they will get a protocol mismatch error upon connecting (rather than "No cabins available", or other obscure and unclear issues).
 
===Other breaking API changes===
''(This section is meant as a quick reference if you have build errors; there's no need to read through it otherwise.)''
 
====Removed or renamed types====
These classes renamed in 1.7:
{| class="wikitable"
|-
|-
! type
| <samp>Characters/Dialogue/Elliott</samp>
! migration
| &#32;
* [[#Dialogue changes|Merged resort dialogue keys]].
* Fixed invalid dialogue key.
| '''✘ broken'''
| ✓ mostly unaffected
|-
|-
| <samp>BaseEnchantment</samp>
| <samp>Characters/Dialogue/Evelyn</samp>
| Renamed to <samp>Enchantment</samp>.
| Fixed invalid dialogue key.
| '''✘ broken'''
| ✓ mostly unaffected
|-
|-
| <samp>AxeEnchantment</samp><br /><samp>BaseWeaponEnchantment</samp><br /><samp>FishingRodEnchantment</samp><br /><samp>HoeEnchantment</samp><br /><samp>MilkPailEnchantment</samp><br /><samp>PanEnchantment</samp><br /><samp>PickaxeEnchantment</samp><br /><samp>ShearsEnchantment</samp><br /><samp>WateringCanEnchantment</samp>
| <samp>Characters/Dialogue/Haley</samp>
| Obsolete. Enchantments now [[#Enchantment data|target tools via data]] instead.
| [[#Dialogue changes|Merged resort dialogue keys]].
|}
| '''✘ broken'''
 
| ✓ mostly unaffected
====Other API changes====
These class members changed in 1.7:
 
{| class="wikitable"
|-
|-
! type
| <samp>Characters/Dialogue/Harvey</samp>
! member
| Fixed invalid dialogue key.
! migration
| '''✘ broken'''
| ✓ mostly unaffected
|-
|-
|rowspan="9"| <samp>BaseEnchantment</samp><br /><small>(and its subclasses)</small>
| <samp>Characters/Dialogue/Jodi</samp>
| <samp>hideEnchantmentName</samp>
| Fixed invalid dialogue key.
| Replaced by <samp>EnchantmentManager.HideEnchantmentName</samp>.
| '''✘ broken'''
| ✓ mostly unaffected
|-
|-
| <samp>hideSecondaryEnchantName</samp>
| <samp>Characters/Dialogue/Leah</samp>
| Replaced by <samp>EnchantmentManager.HideSecondaryEnchantName</samp>.
| [[#Dialogue changes|Merged resort dialogue keys]].
| '''✘ broken'''
| ✓ mostly unaffected
|-
|-
| <samp>GetEnchantmentFromItem(…)</samp>
| <samp>Characters/Dialogue/Lewis</samp>
| Replaced by <samp>EnchantmentManager.GetEnchantmentFromItem</samp>.
| Fixed invalid dialogue key.
| '''✘ broken'''
| ✓ mostly unaffected
|-
|-
| <samp>GetAvailableEnchantments()</samp>
| <samp>Characters/Dialogue/MarriageDialogue</samp><br /><samp>Characters/Dialogue/MarriageDialogue*</samp>
| Removed.
| &#32;
<ul>
* [[#Dialogue changes|Merged some dialogue keys]].
<li>To check whether any enchantments can be applied to a tool through the [[forge]], use <samp>EnchantmentManager.CanForgeEnchant</samp>.</li>
* [[#Dialogue changes|Merged some keys from the base asset into NPC-specific assets]].
<li>There's no directly equivalent method in 1.7, but you can mimic the former logic if needed.
| '''✘ broken'''
<syntaxhighlight lang="c#">
| ✓ mostly unaffected
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;
}
</syntaxhighlight></li>
</ul>
|-
|-
| <samp>GetAvailableEnchantmentsForItem(…)</samp>
| <samp>Characters/Dialogue/Maru</samp><br /><samp>Characters/Dialogue/Penny</samp><br /><samp>Characters/Dialogue/Sam</samp>
| Removed.
| [[#Dialogue changes|Merged resort dialogue keys]].
<ul>
| '''✘ broken'''
<li>To check whether any enchantments can be applied to a tool through the [[forge]], use <samp>EnchantmentManager.CanForgeEnchant</samp>.</li>
| ✓ mostly unaffected
<li>There's no directly equivalent method in 1.7, but you can mimic the former logic if needed.
<syntaxhighlight lang="c#">
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;
}
</syntaxhighlight></li>
</ul>
|-
|-
| <samp>GetName()</samp>
| <samp>Characters/Dialogue/Sebastian</samp>
| Removed. This inconsistently returned an ID, a display name, or <samp>"Unknown Enchantment"</samp> depending on the enchantment type. Use the new <samp>Id</samp> property or the pre-existing <samp>GetDisplayName()</samp> method instead.
| &#32;
* [[#Dialogue changes|Merged resort dialogue keys]].
* Fixed invalid dialogue key.
| '''✘ broken'''
| ✓ mostly unaffected
|-
|-
| <samp>GetLevel()</samp>
| <samp>Data/Boots</samp>
| Removed. Use <samp>Level</samp> instead.
| [[#Data/Boots|Overhauled format]].
| '''✘ broken'''
| '''✘ broken'''<br /><small>(until Content Patcher adds runtime migrations)</small>
|-
|-
| <samp>GetType()</samp>
| <samp>Data/Buffs</samp>
| This was sometimes to identify enchantments (like <code>enchantment.GetType() == expectedEnchantment.GetType()</code>). That's no longer reliable, since 1.7 introduces data-based enchantments which may not have their own C# type. You should use the new <samp>enchantment.Id</samp> property instead.
| [[#Data/Buffs|Added new data field to data model]].
| '''✘ broken'''
|
|-
|-
| <samp>ResetEnchantments()</samp>
| <samp>Data/Buildings</samp><br /><samp>Data/Characters</samp>
| Removed. This is no longer needed since it no longer has a cached list of enchantment instances.
| [[#Item spawn field changes|Added new item spawn field]].
| '''✘ broken'''
|
|-
|-
|rowspan="2"| <samp>Furniture</samp>
| <samp>Data/FishPondData</samp><br /><samp>Data/FruitTrees</samp>
| <samp>armchair</samp><br /><samp>bed</samp><br /><samp>bench</samp><br /><samp>bookcase</samp><br /><samp>chair</samp><br /><samp>couch</samp><br /><samp>decor</samp><br /><samp>dresser</samp><br /><samp>fireplace</samp><br /><samp>lamp</samp><br /><samp>longTable</samp><br /><samp>other</samp><br /><samp>painting</samp><br /><samp>rug</samp><br /><samp>sconce</samp><br /><samp>table</samp><br /><samp>torch</samp><br /><samp>window</samp>
| [[#Item spawn field changes|Added new item spawn field]].
| Removed. Replaced by the <samp>FurnitureType</samp> enum (e.g. <code>Furniture.rug</code> is now <code>FurnitureType.Rug</code>).
| '''✘ broken'''
|
|-
|-
| <samp>placementRestrictions</samp>
| <samp>Data/Furniture</samp>
| Removed. Replaced by <samp>CanPlaceIndoors</samp> and <samp>CanPlaceOutdoors</samp>.
| [[#Data/Furniture|Overhauled format]].
| '''✘ broken'''
| '''✘ broken'''<br /><small>(until Content Patcher adds runtime migrations)</small>
|-
|-
|rowspan="2"| <samp>Monster</samp>
| <samp>Data/GarbageCans</samp><br /><samp>Data/GiantCrops</samp>
| <samp>getExtraDropItems()</samp>
| [[#Item spawn field changes|Added new item spawn field]].
| Removed. Drops should be added to [[#Data/Monsters|<samp>Data/Monsters</samp>]] instead.
| '''✘ broken'''
 
|
[[Modding:Modder Guide/APIs/Harmony|Harmony patches]] which can't be moved into data can target <samp>Monster.RollForDrops</samp> instead.
|-
|-
| <samp>objectsToDrop</samp>
| <samp>Data/Hats</samp>
| Removed. Replaced by <samp>drops</samp>; see [[#Monster changes|''monster changes'']] and [[#Data/Monsters|''<samp>Data/Monsters</samp>'']].
| [[#Data/Hats|Overhauled format]].
| '''✘ broken'''
| '''✘ broken'''<br /><small>(until Content Patcher adds runtime migrations)</small>
|-
|-
| <samp>Tool</samp>
| <samp>Data/Locations</samp>
| <samp>GetEnchantmentLevel&lt;T&gt;()</samp><br /><samp>GetEnchantmentOfType&lt;T&gt;()</samp><br /><samp>hasEnchantmentOfType&lt;T&gt;()</samp>
| [[#Item spawn field changes|Added new item spawn field]].
| Removed. Replaced by <samp>GetEnchantmentLevel(id)</samp>, <samp>GetEnchantment(id)</samp>, and <samp>HasEnchantment(id)</samp> respectively. All vanilla enchantments have a constant for the ID like <samp>EnchantmentIds.GalaxySoul</samp>.
| '''✘ broken'''
|}
|
 
|-
==Name translation changes for wiki maintainers==
| <samp>Data/Machines</samp>
Some in-game item and monster names were retranslated in some languages for clarity or correctness.
| [[#Item spawn field changes|Added new item spawn field]].
 
| '''✘ broken'''
This list is mostly provided to help wiki maintainers update pages, so it doesn't include names which only changed capitalization, changed <code>'</code> (straight apostrophe) to <code>’</code> (curly) in French, or aren't visible to vanilla players (like mine rocks).
|
 
|-
''None yet.''
| <samp>Data/Monsters</samp>
 
| [[#Data/Monsters|Overhauled format]].
==XNB impact==
| '''✘ broken'''
<!--
| '''✘ broken'''<br /><small>(until Content Patcher adds runtime migrations)</small>
 
Updated up to 1.7 alpha 2025-09-13.
 
-->
===Overview===
This section provides a summary of the XNB files which changed in Stardew Valley 1.7. This doesn't include new files (since they won't impact existing mods) or text changes in non-English files.
 
[[Modding:Using XNB mods|XNB mods]] are disproportionately affected, since...
# they replace the entire file;
# they're loaded through the MonoGame content pipeline which is less tolerant of format changes;
# they don't benefit from the compatibility rewrites [[Modding:Content Patcher|Content Patcher]] provides for its content packs.
 
Content Patcher packs are typically unaffected (and Content Patcher will try to rewrite content packs automatically). However if a content pack replaces an entire asset instead of editing, it's more likely to be affected like an XNB mod.
 
===Changed assets===
Compatibility is broadly grouped into four categories:
* "'''✘ broken'''": mods will remove new content or significant changes, or the mod's intended changes will no longer work. Effects may range from display bugs to crashes, depending how the game uses that specific content.
* "✘ will remove changes": mods will remove minor changes in 1.7 (e.g. typo fixes).
* "✓ mostly unaffected": mods will only be affected if they edit specific entries or fields.
* Blank: no expected impact for the vast majority of mods.
 
{| class="wikitable"
|-
|-
!rowspan="2"| content asset
| <samp>Data/Movies</samp>
!rowspan="2"| changes in 1.7
| [[#Item spawn field changes|Added new item spawn field]].
!colspan="2"| compatibility for pre-1.7 mods
| '''✘ broken'''
|
|-
|-
! XNB mods
| <samp>Data/Objects</samp>
! Content Patcher packs
|-
| <samp>Characters/Dialogue/Abigail</samp>
| &#32;
| &#32;
* [[#Dialogue changes|Merged resort dialogue keys]].
* [[#Data/Objects|Added new data field to data model]] and [[#Item spawn field changes|new item spawn fields]].
* Removed event dialogues moved into <samp>Strings/Events</samp>.
* Added <samp>fish_talk_coral</samp> [[#New context tags|context tag]] for [[coral]] and [[Sea Urchin|sea urchin]].
* Fixed invalid dialogue keys.
| '''✘ broken'''
| '''✘ broken'''
| ✓ mostly unaffected
| ✓ mostly unaffected
|-
|-
| <samp>Characters/Dialogue/Alex</samp><br /><samp>Characters/Dialogue/Clint</samp>
| <samp>Data/Pets</samp><br /><samp>Data/Shops</samp>
| [[#Item spawn field changes|Added new item spawn field]].
| '''✘ broken'''
|
|-
| <samp>Data/Weapons</samp>
| &#32;
| &#32;
* [[#Dialogue changes|Merged resort dialogue keys]].
* [[#Item spawn field changes|Added new item spawn field]].
* Removed event dialogues moved into <samp>Strings/Events</samp>.
* Added <samp>is_galaxy_weapon</samp> [[#New context tags|context tag]] for galaxy weapons.
| '''✘ broken'''
| '''✘ broken'''
| ✓ mostly unaffected
| ✓ mostly unaffected
|-
|-
| <samp>Characters/Dialogue/Demetrius</samp>
| <samp>Data/WildTrees</samp>
| Removed event dialogues moved into <samp>Strings/Events</samp>.
| [[#Item spawn field changes|Added new item spawn field]].
|
| '''✘ broken'''
|
|
|-
|-
| <samp>Characters/Dialogue/Dwarf</samp>
| <samp>Strings/1_6_Strings</samp>
| Fixed invalid dialogue keys.
| Moved some translations into <samp>Strings/EnchanmentNames</samp> and <samp>Strings/Furniture</samp>.
| '''✘ broken'''
| ✓ mostly unaffected
|-
| <samp>Characters/Dialogue/Elliott</samp>
| &#32;
* [[#Dialogue changes|Merged resort dialogue keys]].
* Removed event dialogues moved into <samp>Strings/Events</samp>.
* Fixed invalid dialogue key.
| '''✘ broken'''
| ✓ mostly unaffected
|-
| <samp>Characters/Dialogue/Emily</samp>
| Removed event dialogues moved into <samp>Strings/Events</samp>.
|
|
|-
| <samp>Characters/Dialogue/Evelyn</samp>
| &#32;
* Removed event dialogues moved into <samp>Strings/Events</samp>.
* Fixed invalid dialogue key.
| '''✘ broken'''
| ✓ mostly unaffected
|-
| <samp>Characters/Dialogue/Haley</samp>
| &#32;
* [[#Dialogue changes|Merged resort dialogue keys]].
* Removed event dialogues moved into <samp>Strings/Events</samp>.
| '''✘ broken'''
| ✓ mostly unaffected
|-
| <samp>Characters/Dialogue/Harvey</samp>
| &#32;
* Removed event dialogues moved into <samp>Strings/Events</samp>.
* Fixed invalid dialogue key.
| '''✘ broken'''
| ✓ mostly unaffected
|-
| <samp>Characters/Dialogue/Jodi</samp>
| Fixed invalid dialogue key.
| '''✘ broken'''
| ✓ mostly unaffected
|-
| <samp>Characters/Dialogue/Kent</samp>
| Removed event dialogues moved into <samp>Strings/Events</samp>.
|
|
|-
| <samp>Characters/Dialogue/Leah</samp>
| &#32;
* [[#Dialogue changes|Merged resort dialogue keys]].
* Removed event dialogues moved into <samp>Strings/Events</samp>.
| '''✘ broken'''
| ✓ mostly unaffected
|-
| <samp>Characters/Dialogue/Lewis</samp>
| &#32;
* Removed event dialogues moved into <samp>Strings/Events</samp>.
* Fixed invalid dialogue key.
| '''✘ broken'''
| ✓ mostly unaffected
|-
| <samp>Characters/Dialogue/MarriageDialogue</samp><br /><samp>Characters/Dialogue/MarriageDialogue*</samp>
| &#32;
* [[#Dialogue changes|Merged some dialogue keys]].
* [[#Dialogue changes|Merged some keys from the base asset into NPC-specific assets]].
| '''✘ broken'''
| ✓ mostly unaffected
|-
| <samp>Characters/Dialogue/Maru</samp>
| &#32;
* [[#Dialogue changes|Merged resort dialogue keys]].
* Removed event dialogues moved into <samp>Strings/Events</samp>.
| '''✘ broken'''
| ✓ mostly unaffected
|-
| <samp>Characters/Dialogue/Pam</samp>
| Removed event dialogues moved into <samp>Strings/Events</samp>.
|
|
|-
| <samp>Characters/Dialogue/Penny</samp>
| &#32;
* [[#Dialogue changes|Merged resort dialogue keys]].
* Removed event dialogues moved into <samp>Strings/Events</samp>.
| '''✘ broken'''
| ✓ mostly unaffected
|-
| <samp>Characters/Dialogue/Pierre</samp><br /><samp>Characters/Dialogue/Robin</samp>
| Removed event dialogues moved into <samp>Strings/Events</samp>.
|
|
|-
| <samp>Characters/Dialogue/Sam</samp>
| &#32;
* [[#Dialogue changes|Merged resort dialogue keys]].
* Removed event dialogues moved into <samp>Strings/Events</samp>.
| '''✘ broken'''
| ✓ mostly unaffected
|-
| <samp>Characters/Dialogue/Sebastian</samp>
| &#32;
* [[#Dialogue changes|Merged resort dialogue keys]].
* Removed event dialogues moved into <samp>Strings/Events</samp>.
* Fixed invalid dialogue key.
| '''✘ broken'''
| ✓ mostly unaffected
|-
| <samp>Characters/Dialogue/Shane</samp>
| Removed event dialogues moved into <samp>Strings/Events</samp>.
|
|
|-
| <samp>Data/Boots</samp>
| [[#Data/Boots|Overhauled format]].
| '''✘ broken'''
| '''✘ broken'''<br /><small>(until Content Patcher adds runtime migrations)</small>
|-
| <samp>Data/Buffs</samp>
| [[#Data/Buffs|Added new data field to data model]].
| '''✘ broken'''
|
|-
| <samp>Data/Buildings</samp><br /><samp>Data/Characters</samp>
| [[#Item spawn field changes|Added new item spawn field]].
| '''✘ broken'''
|
|-
| <samp>Data/Events/*</samp><br /><samp>Data/Events/Festivals/*</samp>
| [[#Event changes|Major changes]] including [[#Multilingual events|multilingual events]], [[#Forking deprecated|event labels]], [[#Changed event keys|event key changes]], replacing dialogue commands with event commands, etc.
| '''✘ broken'''
| ✓ mostly unaffected
|-
| <samp>Data/ExtraDialogues</samp>
| &#32;
* [[#Event changes|Moved hardcoded events into <samp>Data/Events/*</samp>]].
* Moved <samp>SummitEvent_*</samp> translations into <samp>Strings/Events</samp> (with a new name & format).
| ✓ mostly unaffected
| ✓ mostly unaffected
|-
| <samp>Data/FishPondData</samp><br /><samp>Data/FruitTrees</samp>
| [[#Item spawn field changes|Added new item spawn field]].
| '''✘ broken'''
|
|-
| <samp>Data/Furniture</samp>
| [[#Data/Furniture|Overhauled format]].
| '''✘ broken'''
| '''✘ broken'''<br /><small>(until Content Patcher adds runtime migrations)</small>
|-
| <samp>Data/GarbageCans</samp><br /><samp>Data/GiantCrops</samp>
| [[#Item spawn field changes|Added new item spawn field]].
| '''✘ broken'''
|
|-
| <samp>Data/Hats</samp>
| [[#Data/Hats|Overhauled format]].
| '''✘ broken'''
| '''✘ broken'''<br /><small>(until Content Patcher adds runtime migrations)</small>
|-
| <samp>Data/Locations</samp>
| [[#Item spawn field changes|Added new item spawn field]].
| '''✘ broken'''
|
|-
| <samp>Data/Machines</samp>
| [[#Item spawn field changes|Added new item spawn field]].
| '''✘ broken'''
|
|-
| <samp>Data/Monsters</samp>
| [[#Data/Monsters|Overhauled format]].
| '''✘ broken'''
| '''✘ broken'''<br /><small>(until Content Patcher adds runtime migrations)</small>
|-
| <samp>Data/Movies</samp>
| [[#Item spawn field changes|Added new item spawn field]].
| '''✘ broken'''
|
|-
| <samp>Data/Objects</samp>
| &#32;
* [[#Data/Objects|Added new data field to data model]] and [[#Item spawn field changes|new item spawn fields]].
* Added <samp>fish_talk_coral</samp> [[#New context tags|context tag]] for [[coral]] and [[Sea Urchin|sea urchin]].
| '''✘ broken'''
| ✓ mostly unaffected
|-
| <samp>Data/Pets</samp><br /><samp>Data/Shops</samp>
| [[#Item spawn field changes|Added new item spawn field]].
| '''✘ broken'''
|
|
|-
| <samp>Data/Weapons</samp>
| &#32;
* [[#Item spawn field changes|Added new item spawn field]].
* Added <samp>is_galaxy_weapon</samp> [[#New context tags|context tag]] for galaxy weapons.
| '''✘ broken'''
| ✓ mostly unaffected
|-
| <samp>Data/WildTrees</samp>
| [[#Item spawn field changes|Added new item spawn field]].
| '''✘ broken'''
|
|
|-
| <samp>Strings/1_6_Strings</samp>
| &#32;
* [[#Event changes|Moved hardcoded events into <samp>Data/Events/*</samp>]].
* Moved some translations into <samp>Strings/EnchanmentNames</samp>, <samp>Strings/Events</samp>, and <samp>Strings/Furniture</samp>.
| ✓ mostly unaffected
| ✓ mostly unaffected
|-
|-
| <samp>Strings/EnchantmentNames</samp>
| <samp>Strings/EnchantmentNames</samp>
Line 1,979: Line 1,504:
| '''✘ broken'''
| '''✘ broken'''
| ✓ mostly unaffected
| ✓ mostly unaffected
|-
| <samp>Strings/Events</samp>
| &#32;
* Added translations for [[#Multilingual events|multilingual events]].
* Added translations moved from NPC dialogue assets.
| '''✘ broken'''
|
|-
|-
| <samp>Strings/Furniture</samp>
| <samp>Strings/Furniture</samp>
Line 1,991: Line 1,509:
| '''✘ broken'''
| '''✘ broken'''
|
|
|-
| <samp>Strings/Locations</samp>
| &#32;
* [[#Event changes|Moved hardcoded events into <samp>Data/Events/*</samp>]].
* Moved some event translations into <samp>Strings/Events</samp>.
| ✓ mostly unaffected
| ✓ mostly unaffected
|-
|-
| <samp>Strings/Objects</samp>
| <samp>Strings/Objects</samp>

Revision as of 04:40, 16 January 2026

←Index

This page is for mod authors. Players: see the mod compatibility list instead.

⚠ Stardew Valley 1.7 was announced, but has no planned release date.
There's no estimate for when the update will be released, so don't plan mod updates around the 1.7 release. Things will change before it's released!

This page helps mod authors prepare their mods for the upcoming Stardew Valley 1.7, and documents some of the changes and new functionality.

FAQs

SMAPI mod compatibility over time.

What's changing?

Stardew Valley 1.7 makes significant changes to many data assets to enable new game features and mod extensibility. See the sections below for more details.

Is this the modapocalypse?

Probably not. SMAPI and Content Patcher will automatically rewrite older mods for many of the changes, so they should still work as-is. Some mods may need an update.

How to update your mod

Here's a suggested 'quick start' guide to update a mod for Stardew Valley 1.7.

For C# mods:
  1. Update for Stardew Valley 1.6.16 if you haven't already.
  2. Rebuild the solution.
  3. Fix any build errors and review any build warnings. You can search this page and previous migration guides for relevant info as needed.
  4. Increment your mod version in manifest.json.
    (Some mods may be added to SMAPI's compatibility blacklist due to runtime errors. Incrementing the mod version will fix that if so.)
  5. Test to make sure the mod works.
  6. Skim through this page, and check any section that might be relevant to the mod.
For Content Patcher packs:
  1. Update for Stardew Valley 1.6.16 if you haven't already.
  2. Skim through this page, and check any section that might be relevant to the mod.
For content packs which use another framework:
See the documentation for the framework mod. Often you won't need to update the content pack if the framework mod itself was updated.

Data asset changes

Data/Boots

This has been overhauled into a data model asset, with translations moved into a new Strings/Boots asset. This also includes new fields like ContextTags and CustomFields which weren't available in the old format.

The data asset now consists of a string → model lookup, where...

field effect
basic info
Name The internal item name (not shown in-game).
DisplayName
Description
A tokenizable string for the item's in-game display name and description.
ContextTags (Optional) The custom context tags to add for this item (in addition to the tags added automatically based on the other item data), specified as an array.
equipment effects
AddDefense
AddImmunity
(Optional) A bonus applied to the player's defense or immunity stats when the boots are equipped. Default 0.
appearance
Texture The asset name for the texture containing the boots sprite. Defaults to Maps/springobjects if omitted, but should always be specified for custom boots.
SpriteIndex (Optional) The sprite's index within the Texture, where 0 is the top-left sprite. Default 0.
ColorTexture (Optional) The asset name for the texture containing the boots color sprite. Defaults to Characters/Farmer/shoeColors if omitted.
ColorSpriteIndex (Optional) The color sprite's index within the ColorTexture, where 0 is the top-left sprite. Default 0.
advanced
CustomFields (Optional) The custom fields for this entry.

For example, here's how to add new boots in 1.7:

{
    "Format": "2.8.0",
    "Changes": [
        // add data
        {
            "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
                }
            }
        },

        // add texture
        {
            "Action": "Load",
            "Target": "Mods/{{ModId}}/Boots",
            "FromFile": "assets/boots.png"
        }
    ]
}

Data/Buffs

Added one new field to buff attributes, contained in the Effects field:

field effect
CustomFields (Optional) The custom fields for this entry.

Data/Furniture

This has been overhauled into a data model asset. The overhaul also adds support for previously-hardcoded features like custom item descriptions (via Description), custom TVs (via the new Television furniture type and TelevisionScreen* fields), and custom fields.

The data asset now consists of a string → model lookup, where...

field effect
basic info
Name The internal item name (not shown in-game).
DisplayName A tokenizable string for the item's in-game display name.
Description (Optional) A tokenizable string for the item's in-game description. Defaults to a generic description based on the other fields like CanPlaceIndoors and CanPlaceOutdoors.
Type (Optional) The furniture type, which affects various furniture functionality and default values (e.g. default bounding box size). Defaults to Other.

See table of valid types.

Price (Optional) The price for this furniture when purchased from a shop. Default 0.
ContextTags (Optional) The custom context tags to add for this item (in addition to the tags added automatically based on the other item data), specified as an array.
behavior
CanPlaceIndoors
CanPlaceOutdoors
(Optional) Whether the player can place this furniture indoors and/or outdoors. Defaults to generic behavior based on the Type field (e.g. TVs can't be placed outdoors by default).
ExcludeFromRandomSale (Optional) Whether to prevent this furniture from being shown in randomly generated shop stock or furniture catalogues. Default false.
appearance
Texture The asset name for the texture containing the furniture sprite. Defaults to TileSheets/furniture if omitted, but should always be specified for custom furniture.
SpriteIndex (Optional) The sprite's index within the Texture, where 0 is the top-left sprite. Default 0.
Rotations (Optional) The number of rotations possible (1, 2, or 4). Default 1.
SpriteSize (Optional) The sprite's size in the Texture, measured in tiles. Defaults to a generic size depending on the Type field.
BoundingBoxSize (Optional) The collision box size when the furniture is placed in-game, measured in tiles. Defaults to a generic size depending on the Type field.

The bounding box is anchored to the bottom-left corner of the SpriteSize. Width will push the right side of the box to the right, height will push the top of the box upwards.

type-specific options
BedType (Optional) When the Type field is set to Bed, the bed type which affects who can sleep in it. Default Single.

Valid values:

bed type effect
Single A single-sized bed with room for one player or NPC.
Double A double-sized bed with room for two players or NPCs.
Child A single bed for a child NPC.
TelevisionScreenOffset (Optional) When the Type field is set to Television, the X and Y pixel offset relative to the TV's bounding box to apply when drawing the screen image onto the TV. Default none.
TelevisionScreenScale (Optional) When the Type field is set to Television, the zoom multiplier to apply to the screen image so it fits onto the TV's screen.
advanced
CustomFields (Optional) The custom fields for this entry.

Data/Hats

This has been overhauled into a data model asset, with translations moved into a new Strings/Hats asset. This also includes new fields like ContextTags and CustomFields which weren't available in the old format.

The data asset now consists of a string → model lookup, where...

field effect
basic info
Name The internal item name (not shown in-game).
DisplayName
Description
A tokenizable string for the item's in-game display name and description.
HairStyle (Optional) What to do about the player's hair when they wear this hat. Default DrawObscuredHair.

The possible values are:

  • DrawFullHair: the hair is drawn like usual (e.g. for hats that don't hide the hair like Abigail's bow).
  • DrawObscuredHair: the hair is partly obscured under the hat (e.g. for most hats like the cowboy hat).
  • HideHair: the hair is fully hidden (e.g. for hats which fully cover the head like the mummy mask).
SkipHairOffset (Optional) Whether to skip offsetting the hat to sit 'on top' of the player's current hairstyle (e.g. for masks). Default false.
Texture The asset name for the texture containing the hat sprite. Defaults to Characters/Farmer/hats if omitted, but should always be specified for custom hats.
SpriteIndex (Optional) The sprite's index within the Texture, where 0 is the top-left sprite. Default 0.
ContextTags (Optional) The custom context tags to add for this item (in addition to the tags added automatically based on the other item data), specified as an array.
CustomFields (Optional) The custom fields for this entry.

For example, here's how to add a new hat in 1.7:

{
    "Format": "2.8.0",
    "Changes": [
        // add data
        {
            "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
                }
            }
        },

        // add texture
        {
            "Action": "Load",
            "Target": "Mods/{{ModId}}/Hats",
            "FromFile": "assets/hats.png"
        }
    ]
}

Data/Monsters

Monster data has been completely rethought in Stardew Valley 1.7. In particular...

  • For monster data in general:
    • Data/Monsters has been been overhauled into a data model asset, with translations moved into a new Strings/Monsters asset. This includes significant new features which weren't supported with the old format.
    • A new 'monster variant' concept lets multiple specific monsters share common data (e.g. Green Slime and Tiger Slime are variants of the new base Slime monster). This is particularly used for common drops.
    • A new 'monster tag' system lets monster define custom tags like slime_is_prismatic, which can be used to filter monster drops.
  • For monster drops:
    • A rethought monster drop system supports the full range of vanilla features like conditions, item queries, qualified item IDs for non-object drops, and monster-specific concepts like repeating drop chance and mutually-exclusive drops.
    • All drops are now qualified item IDs. The former 'resource IDs' (formatted as negative numbers like -4) are no longer supported; items are converted into their equivalent resource debris automatically where needed.
    • Nearly all monster drops are now defined in Data/Monsters (with just a few hardcoded drops common to all monsters left).

The data asset now consists of a string → model lookup, where...

  • The key is the unique string ID.
  • The value is a model with the fields listed below.
field effect
basic info
DisplayName A tokenizable string for the monster's display name.
IsGlider (Optional) Whether the monster is flying (e.g. so they glide over obstacles). Default false.
IsMineMonster (Optional) Whether this monster spawns in the mines, and should be buffed after the player reaches the bottom. This sometimes applies to monsters that can appear elsewhere too (e.g. wilderness golems on the farm receive mine buffs too). Default false.
ExperiencePoints (Optional) The combat experience points received for defeating the monster. Default 1.
stats
Health (Optional) The initial hit points. Default 20.
Attack (Optional) The attack power (i.e. how much damage its hits inflict on players). Default 5.
Defense (Optional) The defense which reduces damage received by this monster. Default 0.
DodgeChance (Optional) The percentage chance that the monster dodges an attack, as a value between 0 (never) and 1 (always). Default 0.
Speed (Optional) The default movement speed. Default 1.
Jitteriness (Optional) How often the monster will move in random non-player directions to try to get around objects, as a value between 0 (never) and 1 (always). Default 0.1.
DetectionDistance (Optional) The distance at which the monster detects a player and begins moving towards them, or -1 for unlimited. Default 4.
drops
Drops (Optional) The items which can drop when the monster is defeated. Default none.

All matching entries are dropped. If the player has a burglar's ring equipped, each entry will make two attempts to drop (but fields like RepeatingChance and SkipIfDropped are independent between the two attempts).

This consists of a list of models with these fields:

field effect
common fields See item spawn fields for the generic item fields supported for monster drops.

Notes:

  • If a drop has an item query which returns multiple item stacks, one of them will be selected at random.
  • The Condition field can optionally contain the %RANDOM_KEY token, which is set to a unique identifier for this monster during the current tick.
ForTags (Optional) The monster tags for which this drop applies. This can be a context tag-like query string like !variant_frost_bat, !variant_lava_bat (not frost bat or lava bat). Default none, meaning it applies to all monsters with this data.
Chance (Optional) A probability that this item will be found, as a value between 0 (never) and 1 (always). Default 1.
RepeatingChance (Optional) A compounding probability of an extra drop, as a value between 0 (never) and .95 (nearly always). Default 0.

This applies after an item has been dropped based on the other fields. This chance is repeatedly checked to produce an extra drop until it fails. Each repeat drop will ignore the Chance and Condition fields, but reapply all other item spawn fields (e.g. re-selecting RandomItemId if applicable).

RepeatingChanceKey (Optional) When checking the RepeatingChance field, use this to seed a predictable RNG. This can be used to synchronize separate drops. Default none.

This can optionally contain the %RANDOM_KEY token, which is set to a unique identifier for this monster during the current tick.

ExplodeStack (Optional) Whether to split multi-item stacks into single-item stacks. Default false.

For example, let's say a monster would drop a stack of 15 wood. With this option enabled, it would instead drop 15 stacks of one wood each.

SkipIfDropped (Optional) Skip the current entry if one of these drop IDs have already been dropped. Default none.

This is specified as an array. For example:

"SkipIfDropped": [ "ExampleDropId", "AnotherDropId" ]
variants
DefaultVariant (Optional) When the game creates a monster of this type without specifying a variant, use the given variant instead of creating it from only the base data. Default false.
Variants (Optional) The possible variations of this monster. Default none.

Each variant is simply a set of fields which override the base data when set. For example, this creates a variant which only differs from the base monster by name and health points:

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

This consists of a list of models with these fields:

field effect
monster fields All monster fields (except DefaultVariant and Variants) can be set on the variant. All fields are optional, and default to the value set in the monster's base data.
InheritDrops (Optional) Whether to inherit drops defined in the monster's base Drops field. Default true.

Specifically:

  • If true, the variant will combine the base Drops and variant Drops into one list.
  • If false, only drops in the variant Drops field are applied.
advanced
CustomFields (Optional) The custom fields for this entry.

For example, this Content Patcher code adds a new 'Pufferchick' monster which drops pufferfish when defeated. The monster's spritesheet is automatically loaded from Monsters/<ID>.

Note: this only adds the monster data. Currently this does nothing unless you have another mod which spawns instances of the monster in-game.

{
    "Format": "2.8.0",
    "Changes": [
        // add data
        {
            "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
                        }
                    ]
                }
            }
        },

        // add texture
        {
            "Action": "Load",
            "Target": "Monsters/{{ModId}}_Pufferchick",
            "FromFile": "assets/pufferchick.png"
        }
    ]
}

Data/Objects

Added new fields:

field effect
Buffs This field already existed, but has a field change:
field effect
CustomAttributes This field already existed, but has one new field:
field effect
CustomFields (Optional) The custom fields for this entry.
UseCondition A game state query for determining if the object is usable on right click. If not specified, equivalent to "TRUE".
UseConditionFailedMessage A tokenizable string for what message to show when UseCondition is not met. If an empty string, no message will be shown. If not specified, equivalent to "[LocalizedText Strings/UI:CantUseHere]".
UseActions A list of actions to run upon using the item. These trigger actions will have an input argument called StackSize, which will be the size of the stack obtained if triggered via ConsumeOnObtain, or 1 otherwise. (For more information on trigger action input arguments, see the relevant section on this page.)
ConsumeOnUse true if the item should be consumed on use, false otherwise. Default true.
ObtainActions A list of actions to run upon obtaining the item. These trigger actions will have an input argument called StackSize, which will be the size of the stack obtained. (For more information on trigger action input arguments, see the relevant section on this page.)
ConsumeOnObtain If the item should be automatically used *and* consumed when obtained. Items with this enabled:
  • Will not actually enter the inventory (since they are consumed immediately).
  • Can be collected even with a full inventory (since they are consumed immediately).
  • Will not have their UseCondition checked before their UseActions are run.
  • Will have their ObtainActions (if any) run before their UseActions are run.
ShowNotificationOnObtain true if the item should show a notification in the bottom left corner of the screen upon receiving the item, false otherwise. Default true.

Display shops

This section has is currently out of date. Display shops have been merged with normal shops. This will be updated once that merge is complete.

In addition to being able to add or change what is sold on Pierre's counter, you can also create your own.

Display shops are similar to normal shops, except they show their stocked items in-world. They have a fixed size which is filled from the item pool until it is full (or there is nothing left to add).

Display shops are stocked at the beginning of the day, and not restocked until the next day. They are stocked per-farmhand so that they can be different for everyone (such as with backpack upgrades), however a LimitedStockMode of Player will sync the stock between players, just like a normal shop.

Display shop items are always purchased one at a time - a higher stack size means it can be bought multiple times.

The data asset, located at Data/DisplayShops, consists of a string -> model lookup, where...

  • The key is the ID of the display shop.
  • The value is a model with the fields listed below.
field effect
basic info
OpenCondition (Optional) A Game State Query for determining if the display shop if is open (that is, if the items shown are purchasable or not). If not specified, it will always be open.
ClosedMessage (Optional) A Tokenizable String for what message to show if the shop is closed. Defaults to (after token parsing) "Closed.".
Currency (Optional) The currency to use for the price, with the same options as in Data/Shops. Defaults to 0 (standard gold).
cosmetic
PurchaseSound (Optional) A sound to play upon making a successful purchase. Defaults to "purchaseClick".
ItemWorldOffset (Optional) A Vector2 of how far to move the display item from the tile that has the purchase tile action. For example, Pierre's shop counter has a value of 0 -72 so that the items show on top of the counter. Defaults to 0.
stocked products
ApplyProfitMargins (Optional) Whether or not to apply profit margins by default for items in this shop. Defaults to null.
PriceModifiers (Optional) Price modifiers to apply to items in this shop. Behaves the same way as Data/Shops PriceModifiers.
PriceModifierMode (Optional) Price modifier mod for applying price modifiers to items in this shop. Behaves the same way as Data/Shops PriceModifierMode.
ItemCountToSell (Optional) The amount of items that can be sold each day.
ItemPool (Optional) The items to use when populating the shop. This list is sorted by Precedence before being used, with entries of the same precedence being shuffled together. This list consist of values with these fields:
field effect
common fields See Items for Shops for the item fields supported by display shop items.

Notes:

  • If set to an item query which returns multiple items, all of them will be valid choices for the shop.
  • Unlike other item spawn fields, you don't have to have a valid item spawn from each entry. This can be useful when used in conjunction with other fields for purchases that do other things (via ActionsOnPurchased).
  • Unlike other item spawn fields, ObjectDisplayName is supported for any entry (not just Object items).
DisplayTextureOverride (Optional) The path to the texture to use instead of the item texture. *Required when there is no valid item for this entry.*
DisplayTextureRegionOverride (Optional) The region of the texture to display when using DisplayTextureOverride. *Required when there is no valid item for this entry.*
DisplayOffset (Optional) The amount to offset drawing this item when shown in the display shop. This is useful for non-standard-sized items.
DisplayScale (Optional) How much to scale the item when it is shown. Defaults to 4 (just like most things in the game).
ItemBlurb (Optional) Text to show in a dialogue box before the item prompt appears.
ItemBlurbSpeaker (Optional) The NPC that will "speak" the ItemBlurb, if desired.
Precedence (Optional) The precedence for this item to be checked, with higher being sooner. Defaults to 0.

To make the display shop show in world, you need to use a new tile action: DisplayShop <displayShopId> <itemIndex>, with displayShopId being the ID of the entry in Data/DisplayShops and itemIndex being which index of the stocked items to make available (based on the corresponding ItemCountToSell value).

For example, here's how to add a new entry to Pierre's counter (TODO: change to content patcher format instead of XML):

          <Item>
            <ItemId>(O)0</ItemId>
            <Price>123</Price>
            <AvailableStock>3</AvailableStock>
            <ItemBlurb>wow some weeds. perfect for honey</ItemBlurb>
            <ItemBlurbSpeaker>Penny</ItemBlurbSpeaker>
            <Precedence>-100</Precedence>
          </Item>

Changes for all mod authors

Switch blocks

'Switch blocks' are a new ${…}$ syntax which can be used in nearly all game text (not just dialogue). This extends the former 'gender-switch blocks' added in 1.6.0.

These are applied before most other commands or parsing, so you can safely use them in cases where characters like ^ have a different meaning (e.g. mail text).

The supported switch blocks are:

type syntax description
gender ${male^female}
${male^female^non-binary}
Switch between text for male, female, and non-binary players. The non-binary value is only used if a mod overrides the player's gender, since the in-game UI only allows male or female.

You can also use ¦ instead of ^, in which case any ^ characters are left as-is.

For example:

"Mon": "Hey ${lad^lass^kiddo}$!"
randomize ${variant A ||| …}$ Defines an arbitrary number of variants from which to choose each day. After randomization, any leading or trailing whitespace is trimmed. This randomization is deterministic per day (e.g. reloading the save won't change which one is shown).

For example, let's say you did this:

"Rainy_Night": "I ${love ||| like ||| adore ||| somewhat enjoy ||| enjoy}$ rain.$h"

That would create five variants which each have an equal probability of being selected.

Switch blocks can be arbitrary combined and nested. For example:

"Rainy_Night": "${Hello there ||| Hey ${lad^lass^kiddo}$ }$!"

Context tag changes

Added new context tags:

context tag item types effect
is_galaxy_weapon weapons Marks the tool as a galaxy weapon like the galaxy hammer or galaxy sword. This is set for vanilla scythes through Data/Weapons. This affects logic which checks for galaxy weapons (e.g. galaxy soul enchantments).

Dialogue changes

  • Added a new special token in dialogue strings:
    token description
    ||| This is a shortcut for the randomize switch block.

    Delimits an arbitrary number of dialogue variants from which to choose each day. After randomization, any leading or trailing whitespace is trimmed. This randomization is deterministic per day (e.g. reloading the save won't change which one is shown).

    For example, let's say you did this:

    "Rainy_Night": "
        I love rain.$h|||
        I like rain.$h|||
        I adore rain.$h|||
        I hate rain.$s#$b#Just kidding. I love it!$h|||
        I enjoy rain.$h
    "
    

    That would create five variants of the dialogue which each have an equal probability of being selected.

  • Improved some special tokens:
    token changes
    || Whitespace around the token is now ignored, so you can split text into multiple lines:
    "Wed8": "
        Isn't it expensive, coming to the desert so often like you do?#$e#You must really like to see me, huh? Hmmm... $h||
        *sigh*... I do miss the beautiful flowers of Stardew Valley...$s
    "
    
  • Some dialogues were merged or renamed using the new features. The previous dialogue keys are now ignored by the game.
    asset former key changes
    Characters/Dialogue/<NPC name> Resort_<number>
    Resort_Bar_<number>
    Resort_Chair_<number>
    Resort_Dance_<number>
    Resort_Shore_<number>
    Resort_Towel_<number>
    Resort_Umbrella_<number>
    Resort_Wander_<number>
    Merged into their base key (e.g. Resort_<random> into Resort) using the new ||| random-variant token.
    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>
    Moved into MarriageDialogue<NPC name> and removed the NPC suffix (like spouseRoom_<NPC name> → spouseRoom).
    Indoor_Day_0
    Indoor_Day_1
    Indoor_Day_2
    Indoor_Day_3
    Indoor_Day_4
    Merged into Indoor_Day.
    Indoor_Night_0
    Indoor_Night_1
    Indoor_Night_2
    Indoor_Night_3
    Indoor_Night_4
    Indoor_Night_<NPC name>
    Merged into Indoor_Night.
    NoBed_0
    NoBed_1
    NoBed_2
    NoBed_3
    Merged into NoBed.
    Outdoor_0
    Outdoor_1
    Outdoor_2
    Outdoor_3
    Outdoor_4
    Outdoor_<NPC name>
    Merged into Outdoor.
    Rainy_Day_0
    Rainy_Day_1
    Rainy_Day_2
    Rainy_Day_3
    Rainy_Day_4
    Merged into Rainy_Day.
    Rainy_Night_0
    Rainy_Night_1
    Rainy_Night_2
    Rainy_Night_3
    Rainy_Night_4
    Rainy_Night_5
    Rainy_Night_<NPC name>
    Merged into Rainy_Night.

Enchantment data

Enchantments have been partly de-hardcoded into a new Data/Enchantments data asset. Mods can now easily add new enchantments, including enchantments applied through the forge using a prismatic shard or a custom item ID.

However, this logic is still hardcoded:

  • Forging innate enchantments. The innate enchantments are in data, but the logic to choose which to apply is still hardcoded.
  • Forging diamonds into a weapon to fill all its weapon stat slots.
  • Forging three galaxy souls into galaxy weapons to transform them into infinity weapons. (The 'Galaxy Soul' enchantment is in data, but the transformation is hardcoded.)
  • Several enchantments' effects when applied (though weapon buff effects are in data).

This consists of a string → model lookup, where...

  • The key is the unique string ID for the enchantment.
  • The value is a model with the fields listed below.
field effect
DisplayName A tokenizable string for the enchantment's display name, shown in tooltips. This can contain {0} for the enchantment level, if applicable.
ForgeWith (Optional) If set, this enchantment is applied to tools by forging an item with this qualified ID into it. Default none, in which case it won't be applicable through the forge.
AppliesTo (Optional) The tools or weapons to which this enchantment can be applied. Defaults to all tools/weapons.

This is specified as an array of context tag queries. The enchantment can be applied if at least one query matches.

"AppliesTo": [
    "melee_weapon, !is_scythe", // any non-scythe melee weapon
    "hoe, upgrade_level_4"      // any hoe upgraded to iridium or higher
]
IsForge (Optional) Whether this is a weapon stat enchantment applied through the forge. Default false.
IsSecondary (Optional) Whether this is an innate enchantment applied through the forge using a dragon tooth. Default false.
IsVisible (Optional) Whether the enchantment should be shown in the tool/weapon's tooltip. Default true.
MaximumLevel (Optional) The number of times this enchantment can be applied to the same tool to upgrade the enchantment level (e.g. for weapon stat enchantments). A value of 1 means there's only one enchantment level, so it can't be upgraded by applying the enchantment again. Default 1.
EquipmentEffects (Optional) The buffs applied to the weapon when this enchantment is applied.

This consists of a list of models with the fields below. You can specify any number of entries; the first one which matches the tool will be applied.

field effect
Id A unique string ID for this entry.
MinLevel (Optional) The minimum enchantment level for which these stats apply. Default 0 (i.e. any level).
other fields See the Effects field in Data/Buffs, which is equivalent to this model.
advanced
CustomFields (Optional) The custom fields for this entry.
ClassName (Optional, specialized) The name of the C# class to construct within the StardewValley.Enchantments namespace. The class must be a subclass of StardewValley.Enchantments.Enchantment, and have a constructor with no arguments. For example, given a value of BottomlessEnchantment, the game will create StardewValley.Enchantments.BottomlessEnchantment instances.

This should usually be omitted, in which case the game will create a generic Enchantment instance which uses the data in Data/Enchantments for its ID.

Event changes

Added new event commands:

command description
setDrawDepthModifier <npc> <amountInTiles> Modify the draw depth of <npc> for this event, by <amountInTiles>.
setDrawDepthModifier <npc> reset Reset the draw depth modifier of <npc> for this event.
ForceBreathing <npc> false Prevent <npc> from showing a breathing animation for this event.
ForceBreathing <npc> true [breathPosX] [breathPosY] [breathRectX] [breathRectY] [breathRectWidth] [breathRectHeight] Force <npc> to show a breathing animation for this event. You can optionally override the data used for the breathing rect, with the values following the same behavior as they would if specified in the Data/Characters character data.
ForceBreathing <npc> reset Reset the forced breathing modifier of <npc> for this event.

Fish pond changes

  • Added new fish pond translation keys:
    asset key usage
    Strings/UI PondQuery_<key>_<item ID>
    PondQuery_<key>_<attitude>
    All PondQuery_* translation keys can now be suffixed with either the qualified item ID of the fish, or the fish's general attitude based on their fish_talk_* context tag.

    For example, the 'fish are OK' message for an anchovy pond will be loaded from the first key which exists in this order: PondQuery_StatusOk_(O)129, PondQuery_StatusOk_Rude, or PondQuery_StatusOk.

  • Merged some fish pond translation keys:
    asset former key changes
    Strings/UI PondQuery_Status<status><number (0–6)>
    PondQuery_StatusRequestComplete_<fish disposition><number (0–2)>
    PondQuery_StatusRequestPending_<fish disposition><number (0–2)>
    Removed the number key suffixes using switch blocks (e.g. merged PondQuery_StatusOk<number> into PondQuery_StatusOk).
  • Coral and Sea urchin now have the fish_talk_coral context tag instead of a hardcoded _Coral translation key suffixes.

Item query changes

Added one new item query:

query effect
SEASONAL_RACCOON_SEED Get a seasonal raccoon seed for the current season.

This sets the stack size to the recommended amount based on the player's luck. When used in item spawn fields, you can set MinStack and MaxStack to override the stack size.

Item spawn field changes

  • Added new item spawn fields:
    field effect
    Enchantments (Optional) For tools and weapons, the enchantment IDs to apply (matching their IDs in Data/Enchantments). This field applies the normal enchantment rules. Default none.

    This is specified as an array, and you can repeat secondary enchantments to boost their level. For example, this applies Vampiric and Attack (level 2):

    "Enchantments": [ "Vampiric", "Attack", "Attack" ]
    

Game state query changes

Added game state queries:

query effect
PLAYER_INVENTORY_SIZE <player> <minSize> [maxSize] Whether any one of the specified player(s) inventory has at least <minSize> slots unlocked, and (if specified) less than or equal to [maxSize] slots unlocked.

Trigger action changes

Added new trigger actions:

action effect
AddHealth <amount> Heals the local player by <amount> and plays the appropriate sound effect.
IncreaseBackpackSize <amount> Increase the backpack size of the local player by <amount>.
HoldUpItem <itemId> [message] Start animation to hold up the specified item above the player's head. If [|message] is specified, it will show that message as well.
MultiplayerGlobalMessage <translationKey> [arg1] [arg2] [arg3]... Show a global chat message in multiplayer. The translation key needs to exist in Strings/UI and must be prefixed with Chat_ within that file (meaning you would use "SomeMessage" in MultiplayerGlobalMessage and "Chat_SomeMessage" in Strings/UI). Any additional arguments after the translation key (which are parsed as tokenizable strings) will be used as substitution values using the normal notation. (ex. MultiplayerGlobalMessage "SomeMessage" "meow" "kitty cat" and "Chat_SomeMessage": "{1} goes {0}" would result in the message "kitty cat goes meow")
SetVariable <variableStoreId> <name> <value> Sets the value of the variable <name> in the <variableStoreId> store to <value>, if that variable store is writable. (For more on variables, see the relevant section in tokenizable string changes on this page.)
RemoveVariable <variableStoreId> <name> Removes the variable <name> in the <variableStoreId> store, if that variable store is writable. (For more on variables, see the relevant section in tokenizable string changes on this page.)

Tokenizable string changes

Usable in more places

Tokenizable strings are now usable in more places.

  • Game state queries
  • Trigger actions (for If, token evaluation is delayed until which value to use is checked)
  • A few specific event commands:
    • action
    • goto, specifically for the label(s)
    • setSkipActions (token evaluation is delayed until the actions are actually run, meaning any changes that occur during the event but before the player has actually pressed "skip" will be reflected in the variables used here)

Tokens are evaluated immediately, unless otherwise specified.

New tokens

The following tokens have been added:

token format output
InputArgument <argumentName> Tokenizable strings can now accept input arguments, depending on where they were called. If the input argument <argumentName> does not exist, then token evaluation fails.

Token expressions

Additionally, a new type of tokens now exists (called "expressions"), which are only usable in certain contexts. If one of these tokens is used in a place where it is not allowed, it will fail and say the token was not found. The places where expressions tokens are usable are:

  • Game state queries
  • Trigger actions
  • A few specific event commands:
    • action
    • goto, specifically for the label(s)
    • setSkipActions
token format output
Math Integer <expression>

Math Decimal <expression>

Calculates the given expression as math, using either integers (when Integer is specified) or floating point numbers (when Decimal is specified).
  • For example, [Math Integer 3 / 2] will result in 1, while [Math Decimal 3 / 2] will result in 1.5. This is because with Integer specified, each operation will remove everything after the decimal point before proceeding.
  • Valid operators include, in order of precedence:
    • Parenthesis (meaning "(" and ")") can be used to group parts of the epxression to be processed first, similar to how one would expect in a real math expression.
    • * (multiplication), / (division), and % (modulus)
    • + (addition) and - (subtraction)
Comparison <expression> Evaluates the given expression, resulting in TRUE if the expression is true, and FALSE otherwise.
  • The expression can compare numbers (whether integer or decimal), or strings.
  • Valid operators include, in order of precedence:
    • Parenthesis (meaning "(" and ")") can be used to group parts of the expression to be processed first, similar to how one would expect in a real math expression.
    • ! - negation, meaning [Comparison !TRUE] becomes FALSE, [Comparison !FALSE] becomes TRUE, and something like [Comparison !(3 >= 5)] becomes TRUE
    • < (less than), <= (less than or equal to), ≶ (greater than), >= (greater than or equal to)
    • == (equal to) and != (not equal to)
    • && ("and"), meaning [Comparison 2 > 1 && 3 == 3] becomes FALSE
    • || ("or"), meaning [Comparison 2 > 1 || 3 == 3] becomes TRUE
    • (For those who know what "logical comparison short circuiting" is, please be aware that that is currently not implemented.)
If <condition> <trueValue> [falseValue] If <condition> evalautes to TRUE, then <trueValue> is evaluated and returned. If <condition> evalutes to FALSE, then [falseValue] is evaluated and returned (if it was specified - otherwise, nothing is returned).
GameStateQuery <gsq> Evaluates the given game state query, allowing GSQ usage inside [If].
VariableExists <variableStore> <variableName> Evaluates to TRUE if <variableStore> has a variable named <variableName>, and FALSE otherwise. (For more on variable stores, see later section.)
GetVariable <variableStore> <variableName> Evaluates to the value of <variableName> in the variable store <variableStore>. If the variable does not exist, evaluation of the tokenizable string will fail. (For more on variable stores, see later section.)
GetVariableWithDefault <variableStore> <variableName> <defaultValue> Evaluates to the value of <variableName> in the variable store <variableStore>. If the variable does not exist, <defaultValue> will be returned instead. (For more on variable stores, see later section.)

Variable stores

Variables stores are a set of named variables stored in a particular location. The current available locations used as variable stores are:

variable store ID description
Global A variable store attached to the save itself.
  • Any player can read and write from this.
  • This variable store will be saved into the save file at the end of the day.
Player/<playerSpecifier> A variable store attached to a particular player.
  • <playerSpecifier> uses the same format as game state query target players, except specifiers that work for check multiple players (such as Any or All) may not be used.
  • Any player can read from this, however only the owning player can write to their variable store.
  • If a player is disconnected, their variables are saved, and will be resynced when they reconnect.
  • This variable store will be saved into the save file at the end of the day.
Local A variable store attached to a "calling context". Generally, this means it will always be reset between uses unless specifically kept, such as in the following contexts:
  • Events - A variable set in the Local variable store using the action event command will be usable later during that event.
  • Data/TriggerActions - When a trigger action has multiple actions to run, all actions will be using the same Local variable store, meaning earlier trigger actions can save data for use by later trigger actions in the same sequence.

Debug command changes

This only details some debug command changes - mainly, ones that might be useful for mod authors.

command changes
/tokens A new required parameter has been introduced as the first argument, <type>. If <type> is Text the string will be evaluated using non-expression tokens. If <type> is Expression, expression tokens will be allowed as well.
/runmacro Commented lines are now allowed - if -- is the beginning of a line, it will be ignored.
/debugaction (new) A new command for trying out tokenizable string input arguments, tokenizable string local variables, and trigger actions using them. This command maintains its own set of input arguments and a local variable store, which can be manipulated using the subcommands.
subcommand effect
/debugaction argument <name> <value> Sets the input argument <name> to <value>, which can be later used in /debugaction run and /debugaction evaluate.
/debugaction evaluate <expression> Evaluates <expression> as a tokenizable string, using input arguments and local variables previously set from this command.
/debugaction run <action> Runs <action> as a trigger action, using input arguments and local variables previously set from this command.
/debugaction clear Clears all previously set input arguments and local variables for /debugaction.

Some examples of using this command alongside /runmacro, at least at the time of writing, can be found here: https://gist.github.com/spacechase0/3ca7b2e195619a17ef9039c894cc60e4

Changes for C# mod authors

DialogueKeyValidator

The new DialogueKeyValidator class analyses dialogue entries to detect dialogue keys which don't match one of the predefined patterns.

This is mainly meant to implement unit tests. For example, to validate all dialogue keys in a data asset:

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.");
}

You can optionally extend the valid patterns by setting validator fields like MarriageDialogueKeyPatterns.

Content manager changes

1.7 adds a SourceCodeContentManager implementation of IContentManager. This is meant for internal unit tests, and isn't relevant for mod authors except as an example.

Monster changes

  • The monster data has been overhauled.
  • The new monster.Tags field contains a set of metadata tags about the monster which can be checked in Data/Monsters. It's safe to add new tags to the list for existing monster types.
  • The former monster.objectsToDrop field (a list of string object IDs) has been replaced by monster.drops (an item inventory).
  • Removed monster.getExtraDropItems(). Drops should be added in Data/Monsters instead.

SpecialItem deprecation

SpecialItem is now deprecated, and is only kept for save compatibility. All existing uses of it have been migrated to use Object instead, with the following new objects being available:

  • (O)BackpackUpgrade1
  • (O)BackpackUpgrade2
  • (O)ClubCard
  • (O)SpecialCharm
  • (O)SkullKey
  • (O)MagnifyingGlass
  • (O)DarkTalisman
  • (O)MagicInk

Tokenizable string changes

Tokenizable string parsing and evaluation has been separated into two separate stages. As a result, several places that use them now cache the parsed version (which is called ParsedStringSegment.

Any custom trigger actions or tokenizable string tokens that want to delay tokenizable string evaluation so they can handle it themself (such as for only evaluating portions that should be used based on a condition) can attach the [DelayArgumentTokenEvaluation] attribute to their handler method. This will prevent the arguments from being evaluated before they reach your handler. (However, the handlers themselves currently still use string[] as their arguments, so this could be slightly off depending on how quotes were used.)

TokenParser.ParseText(string text, Random random, TokenParserDelegate customParser, Farmer player) is now deprecated, and TokenParser.EvaluateText(string text, TokenParserContext context) should be used instead.

Netfield changes

The following changes must now all be registered with ProtocolSummary before usage:

  • Additional net fields
  • Additional net types
  • Subclasses of any synced type

If this is not done, an exception will be thrown when adding netfields, or setting values of unknown types.

Instead of manually registering with ProtocolSummary or manually adding net fields using a harmony patch, everything should be registered through a new SMAPI API (coming soon) which will handle these details for you. This will ensure that if mods load in a different order on one player's computer compared to other connected players, it will not break anything.

If a farmhand's ProtocolSummary does not match the host's, they will get a protocol mismatch error upon connecting (rather than "No cabins available", or other obscure and unclear issues).

Other breaking API changes

(This section is meant as a quick reference if you have build errors; there's no need to read through it otherwise.)

Removed or renamed types

These classes renamed in 1.7:

type migration
BaseEnchantment Renamed to Enchantment.
AxeEnchantment
BaseWeaponEnchantment
FishingRodEnchantment
HoeEnchantment
MilkPailEnchantment
PanEnchantment
PickaxeEnchantment
ShearsEnchantment
WateringCanEnchantment
Obsolete. Enchantments now target tools via data instead.

Other API changes

These class members changed in 1.7:

type member migration
BaseEnchantment
(and its subclasses)
hideEnchantmentName Replaced by EnchantmentManager.HideEnchantmentName.
hideSecondaryEnchantName Replaced by EnchantmentManager.HideSecondaryEnchantName.
GetEnchantmentFromItem(…) Replaced by EnchantmentManager.GetEnchantmentFromItem.
GetAvailableEnchantments() Removed.
  • To check whether any enchantments can be applied to a tool through the forge, use EnchantmentManager.CanForgeEnchant.
  • There's no directly equivalent method in 1.7, but you can mimic the former logic if needed.
    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(…) Removed.
  • To check whether any enchantments can be applied to a tool through the forge, use EnchantmentManager.CanForgeEnchant.
  • There's no directly equivalent method in 1.7, but you can mimic the former logic if needed.
    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() Removed. This inconsistently returned an ID, a display name, or "Unknown Enchantment" depending on the enchantment type. Use the new Id property or the pre-existing GetDisplayName() method instead.
GetLevel() Removed. Use Level instead.
GetType() This was sometimes to identify enchantments (like enchantment.GetType() == expectedEnchantment.GetType()). That's no longer reliable, since 1.7 introduces data-based enchantments which may not have their own C# type. You should use the new enchantment.Id property instead.
ResetEnchantments() Removed. This is no longer needed since it no longer has a cached list of enchantment instances.
Furniture armchair
bed
bench
bookcase
chair
couch
decor
dresser
fireplace
lamp
longTable
other
painting
rug
sconce
table
torch
window
Removed. Replaced by the FurnitureType enum (e.g. Furniture.rug is now FurnitureType.Rug).
placementRestrictions Removed. Replaced by CanPlaceIndoors and CanPlaceOutdoors.
Monster getExtraDropItems() Removed. Drops should be added to Data/Monsters instead.

Harmony patches which can't be moved into data can target Monster.RollForDrops instead.

objectsToDrop Removed. Replaced by drops; see monster changes and Data/Monsters.
Tool GetEnchantmentLevel<T>()
GetEnchantmentOfType<T>()
hasEnchantmentOfType<T>()
Removed. Replaced by GetEnchantmentLevel(id), GetEnchantment(id), and HasEnchantment(id) respectively. All vanilla enchantments have a constant for the ID like EnchantmentIds.GalaxySoul.

Name translation changes for wiki maintainers

Some in-game item and monster names were retranslated in some languages for clarity or correctness.

This list is mostly provided to help wiki maintainers update pages, so it doesn't include names which only changed capitalization, changed ' (straight apostrophe) to ’ (curly) in French, or aren't visible to vanilla players (like mine rocks).

None yet.

XNB impact

Overview

This section provides a summary of the XNB files which changed in Stardew Valley 1.7. This doesn't include new files (since they won't impact existing mods) or text changes in non-English files.

XNB mods are disproportionately affected, since...

  1. they replace the entire file;
  2. they're loaded through the MonoGame content pipeline which is less tolerant of format changes;
  3. they don't benefit from the compatibility rewrites Content Patcher provides for its content packs.

Content Patcher packs are typically unaffected (and Content Patcher will try to rewrite content packs automatically). However if a content pack replaces an entire asset instead of editing, it's more likely to be affected like an XNB mod.

Changed assets

Compatibility is broadly grouped into four categories:

  • "✘ broken": mods will remove new content or significant changes, or the mod's intended changes will no longer work. Effects may range from display bugs to crashes, depending how the game uses that specific content.
  • "✘ will remove changes": mods will remove minor changes in 1.7 (e.g. typo fixes).
  • "✓ mostly unaffected": mods will only be affected if they edit specific entries or fields.
  • Blank: no expected impact for the vast majority of mods.
content asset changes in 1.7 compatibility for pre-1.7 mods
XNB mods Content Patcher packs
Characters/Dialogue/Abigail ✘ broken ✓ mostly unaffected
Characters/Dialogue/Alex
Characters/Dialogue/Clint
Merged resort dialogue keys. ✘ broken ✓ mostly unaffected
Characters/Dialogue/Dwarf Fixed invalid dialogue keys. ✘ broken ✓ mostly unaffected
Characters/Dialogue/Elliott ✘ broken ✓ mostly unaffected
Characters/Dialogue/Evelyn Fixed invalid dialogue key. ✘ broken ✓ mostly unaffected
Characters/Dialogue/Haley Merged resort dialogue keys. ✘ broken ✓ mostly unaffected
Characters/Dialogue/Harvey Fixed invalid dialogue key. ✘ broken ✓ mostly unaffected
Characters/Dialogue/Jodi Fixed invalid dialogue key. ✘ broken ✓ mostly unaffected
Characters/Dialogue/Leah Merged resort dialogue keys. ✘ broken ✓ mostly unaffected
Characters/Dialogue/Lewis Fixed invalid dialogue key. ✘ broken ✓ mostly unaffected
Characters/Dialogue/MarriageDialogue
Characters/Dialogue/MarriageDialogue*
✘ broken ✓ mostly unaffected
Characters/Dialogue/Maru
Characters/Dialogue/Penny
Characters/Dialogue/Sam
Merged resort dialogue keys. ✘ broken ✓ mostly unaffected
Characters/Dialogue/Sebastian ✘ broken ✓ mostly unaffected
Data/Boots Overhauled format. ✘ broken ✘ broken
(until Content Patcher adds runtime migrations)
Data/Buffs Added new data field to data model. ✘ broken
Data/Buildings
Data/Characters
Added new item spawn field. ✘ broken
Data/FishPondData
Data/FruitTrees
Added new item spawn field. ✘ broken
Data/Furniture Overhauled format. ✘ broken ✘ broken
(until Content Patcher adds runtime migrations)
Data/GarbageCans
Data/GiantCrops
Added new item spawn field. ✘ broken
Data/Hats Overhauled format. ✘ broken ✘ broken
(until Content Patcher adds runtime migrations)
Data/Locations Added new item spawn field. ✘ broken
Data/Machines Added new item spawn field. ✘ broken
Data/Monsters Overhauled format. ✘ broken ✘ broken
(until Content Patcher adds runtime migrations)
Data/Movies Added new item spawn field. ✘ broken
Data/Objects ✘ broken ✓ mostly unaffected
Data/Pets
Data/Shops
Added new item spawn field. ✘ broken
Data/Weapons ✘ broken ✓ mostly unaffected
Data/WildTrees Added new item spawn field. ✘ broken
Strings/1_6_Strings Moved some translations into Strings/EnchanmentNames and Strings/Furniture.
Strings/EnchantmentNames
  • Added translations moved from Strings/1_6_Strings.
  • Renamed two keys (Auto-Hook → <samp.AutoHook, Bug Killer → BugKiller).
✘ broken ✓ mostly unaffected
Strings/Furniture Added translations for catalogue descriptions (moved from Strings/1_6_Strings). ✘ broken
Strings/Objects Moved catalogue descriptions into Strings/Furniture. ✓ mostly unaffected ✓ mostly unaffected
Strings/UI Merged some fish pond translation keys. ✘ broken ✓ mostly unaffected

Removed or moved translation keys

These translation keys were moved or removed in 1.6.16. (For changes to the content, see changed assets above.)

asset key changes
Strings/Locations SeedShop_BuyBackpack_ResponseNo Moved to Strings/UI, with the key GenericPurchase_Decline.